Merge branch 'bf-blender' into mb-0001-operator-repeat

This commit is contained in:
Jaume Bellet 2024-04-04 20:04:14 +02:00
commit 2c66749a9e
1775 changed files with 43045 additions and 24692 deletions

View File

@ -30,7 +30,7 @@ CHECKER_EXCLUDE_SOURCE_FILES = set(os.path.join(*f.split("/")) for f in (
"source/blender/draw/engines/eevee_next/eevee_lut.cc",
))
CHECKER_ARGS = [
CHECKER_ARGS = (
# Speed up execution.
# As Blender has many defines, the total number of configurations is large making execution unreasonably slow.
# This could be increased but do so with care.
@ -39,9 +39,15 @@ CHECKER_ARGS = [
# Enable this when includes are missing.
# "--check-config",
# This is slower, for a comprehensive output it is needed.
"--check-level=exhaustive",
# Shows many pedantic issues, some are quite useful.
"--enable=all",
# Generates many warnings, CPPCHECK known about system includes without resolving them.
"--suppress=missingIncludeSystem",
# Also shows useful messages, even if some are false-positives.
"--inconclusive",
@ -50,7 +56,15 @@ CHECKER_ARGS = [
*(() if USE_VERBOSE else ("--quiet",))
# NOTE: `--cppcheck-build-dir=<dir>` is added later as a temporary directory.
]
)
CHECKER_ARGS_C = (
"--std=c11",
)
CHECKER_ARGS_CXX = (
"--std=c++17",
)
def source_info_filter(
@ -74,22 +88,50 @@ def source_info_filter(
return source_info_result
def cppcheck() -> None:
def cppcheck(temp_dir: str) -> None:
temp_build_dir = os.path.join(temp_dir, "build")
temp_source_dir = os.path.join(temp_dir, "source")
del temp_dir
os.mkdir(temp_build_dir)
os.mkdir(temp_source_dir)
source_info = project_source_info.build_info(ignore_prefix_list=CHECKER_IGNORE_PREFIX)
source_defines = project_source_info.build_defines_as_args()
cppcheck_compiler_h = os.path.join(temp_source_dir, "cppcheck_compiler.h")
with open(cppcheck_compiler_h, "w", encoding="utf-8") as fh:
fh.write(project_source_info.build_defines_as_source())
# Add additional defines.
fh.write("\n")
# Python's `pyport.h` errors without this.
fh.write("#define UCHAR_MAX 255\n")
# `intern/atomic/intern/atomic_ops_utils.h` errors with `Cannot find int size` without this.
fh.write("#define UINT_MAX 0xFFFFFFFF\n")
# Apply exclusion.
source_info = source_info_filter(source_info)
check_commands = []
for c, inc_dirs, defs in source_info:
if c.endswith(".c"):
checker_args_extra = CHECKER_ARGS_C
else:
checker_args_extra = CHECKER_ARGS_CXX
cmd = (
[CHECKER_BIN] +
CHECKER_ARGS +
[c] +
[("-I%s" % i) for i in inc_dirs] +
[("-D%s" % d) for d in defs] +
source_defines
CHECKER_BIN,
*CHECKER_ARGS,
*checker_args_extra,
"--cppcheck-build-dir=" + temp_build_dir,
"--include=" + cppcheck_compiler_h,
# NOTE: for some reason failing to include this crease a large number of syntax errors
# from `intern/guardedalloc/MEM_guardedalloc.h`. Include directly to resolve.
"--include=" + os.path.join(
project_source_info.SOURCE_DIR, "source", "blender", "blenlib", "BLI_compiler_attrs.h",
),
c,
*[("-I%s" % i) for i in inc_dirs],
*[("-D%s" % d) for d in defs],
)
check_commands.append((c, cmd))
@ -119,8 +161,7 @@ def cppcheck() -> None:
def main() -> None:
with tempfile.TemporaryDirectory() as temp_dir:
CHECKER_ARGS.append("--cppcheck-build-dir=" + temp_dir)
cppcheck()
cppcheck(temp_dir)
if __name__ == "__main__":

View File

@ -24,12 +24,12 @@ from typing import (
Any,
Callable,
Generator,
IO,
List,
Optional,
Sequence,
Tuple,
Union,
cast,
)
import shlex
@ -120,12 +120,13 @@ def makefile_log() -> List[str]:
time.sleep(1)
# We know this is always true based on the input arguments to `Popen`.
stdout: IO[bytes] = process.stdout # type: ignore
assert process.stdout is not None
stdout: IO[bytes] = process.stdout
out = stdout.read()
stdout.close()
print("done!", len(out), "bytes")
return cast(List[str], out.decode("utf-8", errors="ignore").split("\n"))
return out.decode("utf-8", errors="ignore").split("\n")
def build_info(
@ -211,9 +212,10 @@ def build_defines_as_source() -> str:
)
# We know this is always true based on the input arguments to `Popen`.
stdout: IO[bytes] = process.stdout # type: ignore
assert process.stdout is not None
stdout: IO[bytes] = process.stdout
return cast(str, stdout.read().strip().decode('ascii'))
return stdout.read().strip().decode('ascii')
def build_defines_as_args() -> List[str]:

View File

@ -33,7 +33,7 @@ def main() -> None:
blender_srcdir = Path(__file__).absolute().parent.parent.parent
cli_parser = argparse.ArgumentParser(
description=f"Create a tarball of the Blender sources, optionally including sources of dependencies.",
description="Create a tarball of the Blender sources, optionally including sources of dependencies.",
epilog="This script is intended to be run by `make source_archive_complete`.",
)
cli_parser.add_argument(

View File

@ -393,7 +393,7 @@ def floating_checkout_add_origin_if_needed(
upstream_url = make_utils.git_get_remote_url(args.git_command, "upstream")
call((args.git_command, "remote", "rename", "upstream", "origin"))
make_utils.git_set_config(args.git_command, f"remote.origin.url", origin_external_url)
make_utils.git_set_config(args.git_command, "remote.origin.url", origin_external_url)
call((args.git_command, "remote", "add", "upstream", upstream_url))
finally:

View File

@ -115,7 +115,8 @@ def git_branch(git_command: str) -> str:
try:
branch = subprocess.check_output([git_command, "rev-parse", "--abbrev-ref", "HEAD"])
except subprocess.CalledProcessError as e:
except subprocess.CalledProcessError:
# No need to print the exception, error text is written to the output already.
sys.stderr.write("Failed to get Blender git branch\n")
sys.exit(1)

134
doc/python_api/conf.py Normal file
View File

@ -0,0 +1,134 @@
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
import time
def has_module(module_name):
found = False
try:
__import__(module_name)
found = True
except ModuleNotFoundError as ex:
if ex.name != module_name:
raise ex
return found
# These are substituted when this file is copied to the build directory.
BLENDER_VERSION_STRING = "${BLENDER_VERSION_STRING}"
BLENDER_VERSION_DOTS = "${BLENDER_VERSION_DOTS}"
BLENDER_REVISION = "${BLENDER_REVISION}"
BLENDER_REVISION_TIMESTAMP = "${BLENDER_REVISION_TIMESTAMP}"
BLENDER_VERSION_DATE = time.strftime(
"%d/%m/%Y",
time.localtime(int(BLENDER_REVISION_TIMESTAMP) if BLENDER_REVISION_TIMESTAMP != "0" else None),
)
if BLENDER_REVISION != "Unknown":
# SHA1 GIT hash.
BLENDER_VERSION_HASH = BLENDER_REVISION
BLENDER_VERSION_HASH_HTML_LINK = "<a href=https://projects.blender.org/blender/blender/commit/%s>%s</a>" % (
BLENDER_VERSION_HASH, BLENDER_VERSION_HASH)
else:
# Fallback: Should not be used.
BLENDER_VERSION_HASH = "Hash Unknown"
BLENDER_VERSION_HASH_HTML_LINK = BLENDER_VERSION_HASH
extensions = ["sphinx.ext.intersphinx"]
intersphinx_mapping = {"blender_manual": ("https://docs.blender.org/manual/en/dev/", None)}
# Provides copy button next to code-blocks (nice to have but not essential).
if has_module("sphinx_copybutton"):
extensions.append("sphinx_copybutton")
# Exclude line numbers, prompts, and console text.
copybutton_exclude = ".linenos, .gp, .go"
project = "Blender %s Python API" % BLENDER_VERSION_STRING
root_doc = "index"
copyright = "Blender Authors"
version = BLENDER_VERSION_DOTS
release = BLENDER_VERSION_DOTS
# Set this as the default is a super-set of Python3.
highlight_language = "python3"
# No need to detect encoding.
highlight_options = {"default": {"encoding": "utf-8"}}
# Quiet file not in table-of-contents warnings.
exclude_patterns = [
"include__bmesh.rst",
]
html_title = "Blender Python API"
# The fallback to a built-in theme when `furo` is not found.
html_theme = "default"
if has_module("furo"):
html_theme = "furo"
html_theme_options = {
"light_css_variables": {
"color-brand-primary": "#265787",
"color-brand-content": "#265787",
},
}
html_sidebars = {
"**": [
"sidebar/brand.html",
"sidebar/search.html",
"sidebar/scroll-start.html",
"sidebar/navigation.html",
"sidebar/scroll-end.html",
"sidebar/variant-selector.html",
]
}
# Not helpful since the source is generated, adds to upload size.
html_copy_source = False
html_show_sphinx = False
html_baseurl = "https://docs.blender.org/api/current/"
html_use_opensearch = "https://docs.blender.org/api/current"
html_show_search_summary = True
html_split_index = True
html_static_path = ["static"]
templates_path = ["templates"]
html_context = {"commit": "%s - %s" % (BLENDER_VERSION_HASH_HTML_LINK, BLENDER_VERSION_DATE)}
html_extra_path = ["static"]
html_favicon = "static/favicon.ico"
html_logo = "static/blender_logo.svg"
# Disable default `last_updated` value, since this is the date of doc generation, not the one of the source commit.
html_last_updated_fmt = None
if html_theme == "furo":
html_css_files = ["css/theme_overrides.css", "css/version_switch.css"]
html_js_files = ["js/version_switch.js"]
# Needed for latex, PDF generation.
latex_elements = {
"papersize": "a4paper",
}
latex_documents = [
("contents", "contents.tex", "Blender Index", "Blender Foundation", "manual"),
]
# Workaround for useless links leading to compile errors
# See https://github.com/sphinx-doc/sphinx/issues/3866
from sphinx.domains.python import PythonDomain
class PatchedPythonDomain(PythonDomain):
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
if "refspecific" in node:
del node["refspecific"]
return super(PatchedPythonDomain, self).resolve_xref(
env, fromdocname, builder, typ, target, node, contnode)
def setup(app):
app.add_domain(PatchedPythonDomain, override=True)

View File

@ -17,10 +17,10 @@ animation or modifiers into account:
When is used on evaluated object all modifiers are taken into account.
.. note:: The result mesh is owned by the object. It can be freed by calling `object.to_mesh_clear()`.
.. note:: The result mesh is owned by the object. It can be freed by calling :meth:`~Object.to_mesh_clear`.
.. note::
The result mesh must be treated as temporary, and cannot be referenced from objects in the main
database. If the mesh intended to be used in a persistent manner use bpy.data.meshes.new_from_object()
database. If the mesh intended to be used in a persistent manner use :meth:`~BlendDataMeshes.new_from_object`
instead.
.. note:: If object does not have geometry (i.e. camera) the functions returns None.
"""

View File

@ -15,7 +15,7 @@ If the object is a text object. The text will be converted into a 3D curve and r
never applied on text objects and apply_modifiers will be ignored. If the object is neither a curve nor
a text object, an error will be reported.
.. note:: The resulting curve is owned by the object. It can be freed by calling `object.to_curve_clear()`.
.. note:: The resulting curve is owned by the object. It can be freed by calling :meth:`~Object.to_curve_clear`.
.. note::
The resulting curve must be treated as temporary, and cannot be referenced from objects in the main
database.

View File

@ -16,10 +16,11 @@ This ``directory`` and ``files`` properties now will be used by the
"""
import bpy
from bpy_extras.io_utils import ImportHelper
from mathutils import Vector
class ShaderScriptImport(bpy.types.Operator):
class ShaderScriptImport(bpy.types.Operator, ImportHelper):
"""Test importer that creates scripts nodes from .txt files"""
bl_idname = "shader.script_import"
bl_label = "Import a text file as a script node"
@ -28,8 +29,11 @@ class ShaderScriptImport(bpy.types.Operator):
This Operator can import multiple .txt files, we need following directory and files
properties that the file handler will use to set files path data
"""
directory: bpy.props.StringProperty(subtype='FILE_PATH', options={'SKIP_SAVE'})
files: bpy.props.CollectionProperty(type=bpy.types.OperatorFileListElement, options={'SKIP_SAVE'})
directory: bpy.props.StringProperty(subtype='FILE_PATH', options={'SKIP_SAVE', 'HIDDEN'})
files: bpy.props.CollectionProperty(type=bpy.types.OperatorFileListElement, options={'SKIP_SAVE', 'HIDDEN'})
"""Allow the user to select if the node's label is set or not"""
set_label: bpy.props.BoolProperty(name="Set Label", default=False)
@classmethod
def poll(cls, context):
@ -57,23 +61,26 @@ class ShaderScriptImport(bpy.types.Operator):
filepath = os.path.join(self.directory, file.name)
text_node.filepath = filepath
text_node.location = Vector((x, y))
# Set the node's title to the file name
if self.set_label:
text_node.label = file.name
x += 20.0
y -= 20.0
return {'FINISHED'}
"""
By default the file handler invokes the operator with the directory and files properties set.
In this example if this properties are set the operator is executed, if not the
file select window is invoked.
This depends on setting ``options={'SKIP_SAVE'}`` to the properties options to avoid
to reuse filepath data between operator calls.
Use ImportHelper's invoke_popup() to handle the invocation so that this operator's properties
are shown in a popup. This allows the user to configure additional settings on the operator like
the `set_label` property. Consider having a draw() method on the operator in order to layout the
properties in the UI appropriately.
If filepath information is not provided the file select window will be invoked instead.
"""
def invoke(self, context, event):
if self.directory:
return self.execute(context)
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
return self.invoke_popup(context)
class SHADER_FH_script_import(bpy.types.FileHandler):

View File

@ -136,8 +136,9 @@ class MESH_UL_vgroups_slow(bpy.types.UIList):
def filter_items(self, context, data, propname):
# This function gets the collection property (as the usual tuple (data, propname)), and must return two lists:
# * The first one is for filtering, it must contain 32bit integers were self.bitflag_filter_item marks the
# matching item as filtered (i.e. to be shown), and 31 other bits are free for custom needs. Here we use the
# first one to mark VGROUP_EMPTY.
# matching item as filtered (i.e. to be shown). The upper 16 bits (including self.bitflag_filter_item) are
# reserved for internal use, the lower 16 bits are free for custom use. Here we use the first bit to mark
# VGROUP_EMPTY.
# * The second one is for reordering, it must return a list containing the new indices of the items (which
# gives us a mapping org_idx -> new_idx).
# Please note that the default UI_UL_list defines helper functions for common tasks (see its doc for more info).

View File

@ -1,9 +1,9 @@
sphinx==7.1.2
sphinx==7.2.6
# Sphinx dependencies that are important
Jinja2==3.1.2
Pygments==2.16.1
docutils==0.18.1
Jinja2==3.1.3
Pygments==2.17.2
docutils==0.20.1
snowballstemmer==2.2.0
requests==2.31.0
@ -11,3 +11,6 @@ requests==2.31.0
# Without this theme, the default theme will be used.
furo==2024.1.29
sphinx-basic-ng==1.0.0b2
# Show a copy button (convenience only).
sphinx-copybutton==0.5.2

View File

@ -61,7 +61,6 @@ import os
import sys
import inspect
import shutil
import time
import logging
import warnings
@ -486,19 +485,6 @@ BLENDER_REVISION_TIMESTAMP = bpy.app.build_commit_timestamp
BLENDER_VERSION_STRING = bpy.app.version_string
BLENDER_VERSION_DOTS = "%d.%d" % (bpy.app.version[0], bpy.app.version[1])
if BLENDER_REVISION != "Unknown":
# SHA1 Git hash
BLENDER_VERSION_HASH = BLENDER_REVISION
BLENDER_VERSION_HASH_HTML_LINK = "<a href=https://projects.blender.org/blender/blender/commit/%s>%s</a>" % (
BLENDER_VERSION_HASH, BLENDER_VERSION_HASH,
)
BLENDER_VERSION_DATE = time.strftime("%d/%m/%Y", time.localtime(BLENDER_REVISION_TIMESTAMP))
else:
# Fallback: Should not be used
BLENDER_VERSION_HASH = "Hash Unknown"
BLENDER_VERSION_HASH_HTML_LINK = BLENDER_VERSION_HASH
BLENDER_VERSION_DATE = time.strftime("%Y-%m-%d")
# Example: `2_83`.
BLENDER_VERSION_PATH = "%d_%d" % (bpy.app.version[0], bpy.app.version[1])
@ -1712,7 +1698,7 @@ def pyrna2sphinx(basepath):
lines.append(" * :class:`%s.%s`\n" % (base.identifier, identifier))
if lines:
fw(".. rubric:: Inherited Properties\n\n")
fw(title_string("Inherited Properties", "-"))
fw(".. hlist::\n")
fw(" :columns: 2\n\n")
@ -1738,7 +1724,7 @@ def pyrna2sphinx(basepath):
lines.append(" * :class:`%s.%s`\n" % (base.identifier, identifier))
if lines:
fw(".. rubric:: Inherited Functions\n\n")
fw(title_string("Inherited Functions", "-"))
fw(".. hlist::\n")
fw(" :columns: 2\n\n")
@ -1750,8 +1736,7 @@ def pyrna2sphinx(basepath):
del lines[:]
if struct.references:
# use this otherwise it gets in the index for a normal heading.
fw(".. rubric:: References\n\n")
fw(title_string("References", "-"))
fw(".. hlist::\n")
fw(" :columns: 2\n\n")
@ -1896,111 +1881,6 @@ def pyrna2sphinx(basepath):
write_ops()
def write_sphinx_conf_py(basepath):
"""
Write sphinx's ``conf.py``.
"""
filepath = os.path.join(basepath, "conf.py")
file = open(filepath, "w", encoding="utf-8")
fw = file.write
fw("import sys, os\n\n")
fw("extensions = ['sphinx.ext.intersphinx']\n\n")
fw("intersphinx_mapping = {'blender_manual': ('https://docs.blender.org/manual/en/dev/', None)}\n\n")
fw("project = 'Blender %s Python API'\n" % BLENDER_VERSION_STRING)
fw("root_doc = 'index'\n")
fw("copyright = 'Blender Authors'\n")
fw("version = '%s'\n" % BLENDER_VERSION_DOTS)
fw("release = '%s'\n" % BLENDER_VERSION_DOTS)
# Set this as the default is a super-set of Python3.
fw("highlight_language = 'python3'\n")
# No need to detect encoding.
fw("highlight_options = {'default': {'encoding': 'utf-8'}}\n\n")
# Quiet file not in table-of-contents warnings.
fw("exclude_patterns = [\n")
fw(" 'include__bmesh.rst',\n")
fw("]\n\n")
fw("html_title = 'Blender Python API'\n")
fw("html_theme = 'default'\n")
# The theme 'sphinx_rtd_theme' is no longer distributed with sphinx by default, only use when available.
fw(r"""
try:
import furo
html_theme = "furo"
del furo
except ModuleNotFoundError:
pass
if html_theme == "furo":
html_theme_options = {
"light_css_variables": {
"color-brand-primary": "#265787",
"color-brand-content": "#265787",
},
}
html_sidebars = {
"**": [
"sidebar/brand.html",
"sidebar/search.html",
"sidebar/scroll-start.html",
"sidebar/navigation.html",
"sidebar/scroll-end.html",
# "sidebar/variant-selector.html",
]
}
""")
# not helpful since the source is generated, adds to upload size.
fw("html_copy_source = False\n")
fw("html_show_sphinx = False\n")
fw("html_baseurl = 'https://docs.blender.org/api/current/'\n")
fw("html_use_opensearch = 'https://docs.blender.org/api/current'\n")
fw("html_show_search_summary = True\n")
fw("html_split_index = True\n")
fw("html_static_path = ['static']\n")
fw("templates_path = ['templates']\n")
fw("html_context = {'commit': '%s - %s'}\n" % (BLENDER_VERSION_HASH_HTML_LINK, BLENDER_VERSION_DATE))
fw("html_extra_path = ['static/favicon.ico', 'static/blender_logo.svg']\n")
fw("html_favicon = 'static/favicon.ico'\n")
fw("html_logo = 'static/blender_logo.svg'\n")
# Disable default `last_updated` value, since this is the date of doc generation, not the one of the source commit.
fw("html_last_updated_fmt = None\n\n")
fw("if html_theme == 'furo':\n")
fw(" html_css_files = ['css/version_switch.css']\n")
fw(" html_js_files = ['js/version_switch.js']\n")
# needed for latex, pdf gen
fw("latex_elements = {\n")
fw(" 'papersize': 'a4paper',\n")
fw("}\n\n")
fw("latex_documents = [ ('contents', 'contents.tex', 'Blender Index', 'Blender Foundation', 'manual'), ]\n")
# Workaround for useless links leading to compile errors
# See https://github.com/sphinx-doc/sphinx/issues/3866
fw(r"""
from sphinx.domains.python import PythonDomain
class PatchedPythonDomain(PythonDomain):
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
if 'refspecific' in node:
del node['refspecific']
return super(PatchedPythonDomain, self).resolve_xref(
env, fromdocname, builder, typ, target, node, contnode)
""")
# end workaround
fw("def setup(app):\n")
fw(" app.add_css_file('css/theme_overrides.css')\n")
fw(" app.add_domain(PatchedPythonDomain, override=True)\n\n")
file.close()
def write_rst_index(basepath):
"""
Write the RST file of the main page, needed for sphinx: ``index.html``.
@ -2239,7 +2119,6 @@ def write_rst_enum_items(basepath, key, key_no_prefix, enum_items):
fw(".. _%s:\n\n" % key)
fw(title_string(key_no_prefix.replace("_", " ").title(), "#"))
# fw(".. rubric:: %s\n\n" % key_no_prefix.replace("_", " ").title())
for item in enum_items:
identifier = item.identifier
@ -2414,7 +2293,7 @@ def copy_handwritten_extra(basepath):
shutil.copy2(f_src, f_dst)
def copy_theme_assets(basepath):
def copy_sphinx_files(basepath):
shutil.copytree(
os.path.join(SCRIPT_DIR, "static"),
os.path.join(basepath, "static"),
@ -2426,17 +2305,38 @@ def copy_theme_assets(basepath):
copy_function=shutil.copy,
)
shutil.copy2(os.path.join(SCRIPT_DIR, "conf.py"), basepath, )
def format_config(basepath):
"""
Updates ``conf.py`` with context information from Blender.
"""
from string import Template
# Ensure the string literals can contain any characters by closing the surrounding quotes
# and declare a separate literal via `repr()`.
def declare_in_quotes(string):
return "\" %r \"" % (string)
substitutions = {
"BLENDER_VERSION_STRING": declare_in_quotes(BLENDER_VERSION_STRING),
"BLENDER_VERSION_DOTS": declare_in_quotes(BLENDER_VERSION_DOTS),
"BLENDER_REVISION_TIMESTAMP": declare_in_quotes(str(BLENDER_REVISION_TIMESTAMP)),
"BLENDER_REVISION": declare_in_quotes(BLENDER_REVISION),
}
filepath = os.path.join(basepath, "conf.py")
# Read the template string from the template file.
with open(filepath, 'r', encoding="utf-8") as fh:
template_file = fh.read()
with open(filepath, 'w', encoding="utf-8") as fh:
fh.write(Template(template_file).substitute(substitutions))
def rna2sphinx(basepath):
try:
os.mkdir(basepath)
except:
pass
# sphinx setup
write_sphinx_conf_py(basepath)
# main page
write_rst_index(basepath)
@ -2463,9 +2363,6 @@ def rna2sphinx(basepath):
# copy source files referenced
copy_handwritten_extra(basepath)
# copy extra files needed for theme
copy_theme_assets(basepath)
def align_sphinx_in_to_sphinx_in_tmp(dir_src, dir_dst):
"""
@ -2586,10 +2483,22 @@ def main():
copy_function=shutil.copy,
)
# Dump the API in RST files.
# start from a clean directory everytime
if os.path.exists(SPHINX_IN_TMP):
shutil.rmtree(SPHINX_IN_TMP, True)
try:
os.mkdir(SPHINX_IN_TMP)
except:
pass
# copy extra files needed for theme
copy_sphinx_files(SPHINX_IN_TMP)
# write infromation needed for 'conf.py'
format_config(SPHINX_IN_TMP)
# Dump the API in RST files.
rna2sphinx(SPHINX_IN_TMP)
if ARGS.changelog:

View File

@ -67,10 +67,16 @@ dl dt {
dl.field-list {
display: grid;
grid-template-columns: auto minmax(80%, 95%);
}
p {
margin-bottom: 0;
}
dl.field-list > dd > p:last-child {
margin-bottom: 0;
}
@media (max-width: calc(67em / 2)) {
dl.field-list {
grid-template-columns: unset;
}
}
/* TABLE & FIGURE */
@ -94,6 +100,12 @@ figcaption {
}
}
/* Allow horizontal lists to collapse on narrow screens */
.hlist tr {
display: flex;
flex-flow: row wrap;
}
/* End TABLE & FIGURE. */
/* Force admonition to span the full width if close to a figure */
@ -141,6 +153,11 @@ a {
text-decoration: none;
}
/* Break long code references onto a second line */
a > code.docutils {
overflow-wrap: anywhere;
}
/* Quotes for Fig. "link". */
a[href^="#fig-"]::before {
content: "\201c";

View File

@ -32,6 +32,7 @@ endif()
add_subdirectory(rangetree)
add_subdirectory(nanosvg)
add_subdirectory(wcwidth)
add_subdirectory(xxhash)
if(WITH_BULLET)
if(NOT WITH_SYSTEM_BULLET)
@ -104,10 +105,6 @@ if(WITH_MOD_FLUID)
add_subdirectory(mantaflow)
endif()
if(WITH_COMPOSITOR_CPU)
add_subdirectory(smaa_areatex)
endif()
if(WITH_VULKAN_BACKEND)
add_subdirectory(vulkan_memory_allocator)
endif()

View File

@ -124,13 +124,12 @@ void PulseAudioDevice::playing(bool playing)
AUD_pa_threaded_mainloop_lock(m_mainloop);
AUD_pa_stream_cork(m_stream, playing ? 0 : 1, nullptr, nullptr);
AUD_pa_threaded_mainloop_unlock(m_mainloop);
if(!playing)
{
AUD_pa_stream_flush(m_stream, nullptr, nullptr);
m_clear = true;
}
AUD_pa_threaded_mainloop_unlock(m_mainloop);
}
PulseAudioDevice::PulseAudioDevice(const std::string &name, DeviceSpecs specs, int buffersize) :

View File

@ -1,5 +0,0 @@
# SPDX-FileCopyrightText: 2017 Blender Foundation
#
# SPDX-License-Identifier: GPL-2.0-or-later
add_executable(smaa_areatex smaa_areatex.cpp)

View File

@ -1,5 +0,0 @@
Project: smaa-cpp
URL: https://github.com/iRi-E/smaa-cpp
License: MIT
Upstream version: 0.4.0
Local modifications:

File diff suppressed because it is too large Load Diff

21
extern/xxhash/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
PUBLIC .
)
set(INC_SYS
)
set(SRC
xxhash.c
xxhash.h
)
set(LIB
)
blender_add_lib(extern_xxhash "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
add_library(bf::extern::xxhash ALIAS extern_xxhash)

26
extern/xxhash/LICENSE vendored Normal file
View File

@ -0,0 +1,26 @@
xxHash Library
Copyright (c) 2012-2021 Yann Collet
All rights reserved.
BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

6
extern/xxhash/README.blender vendored Normal file
View File

@ -0,0 +1,6 @@
Project: xxHash
URL: https://xxhash.com/
License: BSD 2-Clause
Upstream version: v0.8.2 (2023-07-21)
Local modifications:
* None

43
extern/xxhash/xxhash.c vendored Normal file
View File

@ -0,0 +1,43 @@
/*
* xxHash - Extremely Fast Hash algorithm
* Copyright (C) 2012-2021 Yann Collet
*
* BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You can contact the author at:
* - xxHash homepage: https://www.xxhash.com
* - xxHash source repository: https://github.com/Cyan4973/xxHash
*/
/*
* xxhash.c instantiates functions defined in xxhash.h
*/
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
#define XXH_IMPLEMENTATION /* access definitions */
#include "xxhash.h"

6773
extern/xxhash/xxhash.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -109,12 +109,12 @@ typedef struct CLG_LogRef {
struct CLG_LogRef *next;
} CLG_LogRef;
void CLG_log_str(CLG_LogType *lg,
void CLG_log_str(const CLG_LogType *lg,
enum CLG_Severity severity,
const char *file_line,
const char *fn,
const char *message) _CLOG_ATTR_NONNULL(1, 3, 4, 5);
void CLG_logf(CLG_LogType *lg,
void CLG_logf(const CLG_LogType *lg,
enum CLG_Severity severity,
const char *file_line,
const char *fn,
@ -156,7 +156,7 @@ int CLG_color_support_get(CLG_LogRef *clg_ref);
#define CLOG_AT_SEVERITY(clg_ref, severity, verbose_level, ...) \
{ \
CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
const CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || \
(severity >= CLG_SEVERITY_WARN)) \
{ \
@ -167,7 +167,7 @@ int CLG_color_support_get(CLG_LogRef *clg_ref);
#define CLOG_STR_AT_SEVERITY(clg_ref, severity, verbose_level, str) \
{ \
CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
const CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || \
(severity >= CLG_SEVERITY_WARN)) \
{ \

View File

@ -175,9 +175,8 @@ static void clg_str_vappendf(CLogStringBuf *cstr, const char *fmt, va_list args)
{
/* Use limit because windows may use '-1' for a formatting error. */
const uint len_max = 65535;
uint len_avail = cstr->len_alloc - cstr->len;
while (true) {
uint len_avail = cstr->len_alloc - cstr->len;
va_list args_cpy;
va_copy(args_cpy, args);
int retval = vsnprintf(cstr->data + cstr->len, len_avail, fmt, args_cpy);
@ -188,22 +187,23 @@ static void clg_str_vappendf(CLogStringBuf *cstr, const char *fmt, va_list args)
* message. */
break;
}
else if ((uint)retval <= len_avail) {
if ((uint)retval <= len_avail) {
/* Copy was successful. */
cstr->len += (uint)retval;
break;
}
else {
/* vsnprintf was not successful, due to lack of allocated space, retval contains expected
* length of the formatted string, use it to allocate required amount of memory. */
uint len_alloc = cstr->len + (uint)retval;
if (len_alloc >= len_max) {
/* Safe upper-limit, just in case... */
break;
}
clg_str_reserve(cstr, len_alloc);
len_avail = cstr->len_alloc - cstr->len;
/* `vsnprintf` was not successful, due to lack of allocated space, `retval` contains expected
* length of the formatted string, use it to allocate required amount of memory. */
uint len_alloc = cstr->len + (uint)retval;
if (len_alloc >= len_max) {
/* Safe upper-limit, just in case... */
break;
}
clg_str_reserve(cstr, len_alloc);
len_avail = cstr->len_alloc - cstr->len;
}
}
@ -429,7 +429,7 @@ static void write_severity(CLogStringBuf *cstr, enum CLG_Severity severity, bool
}
}
static void write_type(CLogStringBuf *cstr, CLG_LogType *lg)
static void write_type(CLogStringBuf *cstr, const CLG_LogType *lg)
{
clg_str_append(cstr, " (");
clg_str_append(cstr, lg->identifier);
@ -460,7 +460,7 @@ static void write_file_line_fn(CLogStringBuf *cstr,
clg_str_append(cstr, ": ");
}
void CLG_log_str(CLG_LogType *lg,
void CLG_log_str(const CLG_LogType *lg,
enum CLG_Severity severity,
const char *file_line,
const char *fn,
@ -498,7 +498,7 @@ void CLG_log_str(CLG_LogType *lg,
}
}
void CLG_logf(CLG_LogType *lg,
void CLG_logf(const CLG_LogType *lg,
enum CLG_Severity severity,
const char *file_line,
const char *fn,

View File

@ -219,10 +219,6 @@ endif()
if(WITH_CYCLES_OSL)
add_definitions(-DWITH_OSL)
# osl 1.9.x
add_definitions(-DOSL_STATIC_BUILD)
# pre 1.9
add_definitions(-DOSL_STATIC_LIBRARY)
include_directories(
SYSTEM
${OSL_INCLUDE_DIR}

View File

@ -142,6 +142,12 @@ if(WITH_OPENIMAGEDENOISE)
)
endif()
if(WITH_CYCLES_OSL)
list(APPEND LIB
${OSL_LIBRARIES}
)
endif()
blender_add_lib(bf_intern_cycles "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
add_dependencies(bf_intern_cycles bf_rna)

View File

@ -235,8 +235,8 @@ def enum_preview_denoiser(self, context):
items = [
('AUTO',
"Automatic",
("Use the fastest available denoiser for viewport rendering "
"(OptiX if available, OpenImageDenoise otherwise)"),
("Use GPU accelerated denoising if supported, for the best performance. "
"Prefer OpenImageDenoise over OptiX"),
0)]
else:
items = [('AUTO', "None", "Blender was compiled without a viewport denoiser", 0)]

View File

@ -2,11 +2,11 @@
*
* SPDX-License-Identifier: Apache-2.0 */
#include "GPU_context.h"
#include "GPU_immediate.h"
#include "GPU_shader.h"
#include "GPU_state.h"
#include "GPU_texture.h"
#include "GPU_context.hh"
#include "GPU_immediate.hh"
#include "GPU_shader.hh"
#include "GPU_state.hh"
#include "GPU_texture.hh"
#include "RE_engine.h"

View File

@ -26,7 +26,7 @@
#include "util/tbb.h"
#include "util/types.h"
#include "GPU_state.h"
#include "GPU_state.hh"
#ifdef WITH_OSL
# include "scene/osl.h"

View File

@ -203,6 +203,13 @@ if(WITH_OPENIMAGEDENOISE)
)
endif()
if(WITH_CYCLES_OSL)
list(APPEND LIB
${OSL_LIBRARIES}
)
endif()
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})

View File

@ -124,7 +124,8 @@ class DeviceInfo {
/* Multiple Devices with the same ID would be very bad. */
assert(id != info.id ||
(type == info.type && num == info.num && description == info.description));
return id == info.id;
return id == info.id && use_hardware_raytracing == info.use_hardware_raytracing &&
kernel_optimization_level == info.kernel_optimization_level;
}
};

View File

@ -106,7 +106,7 @@ struct ShaderCache {
friend ShaderCache *get_shader_cache(id<MTLDevice> mtlDevice);
void compile_thread_func(int thread_index);
void compile_thread_func();
using PipelineCollection = std::vector<unique_ptr<MetalKernelPipeline>>;
@ -174,7 +174,7 @@ void ShaderCache::wait_for_all()
}
}
void ShaderCache::compile_thread_func(int /*thread_index*/)
void ShaderCache::compile_thread_func()
{
while (running) {
@ -309,7 +309,7 @@ void ShaderCache::load_kernel(DeviceKernel device_kernel,
metal_printf("Spawning %d Cycles kernel compilation threads\n", max_mtlcompiler_threads);
for (int i = 0; i < max_mtlcompiler_threads; i++) {
compile_threads.push_back(std::thread([&] { compile_thread_func(i); }));
compile_threads.push_back(std::thread([this] { this->compile_thread_func(); }));
}
}
}

View File

@ -773,8 +773,9 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
size_t &kernel_local_size)
{
assert(queue);
const static size_t preferred_work_group_size_intersect_shading = 32;
const static size_t preferred_work_group_size_intersect = 128;
const static size_t preferred_work_group_size_shading = 256;
const static size_t preferred_work_group_size_shading_simd8 = 64;
/* Shader evaluation kernels seems to use some amount of shared memory, so better
* to avoid usage of maximum work group sizes for them. */
const static size_t preferred_work_group_size_shader_evaluation = 256;
@ -783,6 +784,9 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
const static size_t preferred_work_group_size_cryptomatte = 512;
const static size_t preferred_work_group_size_default = 1024;
const sycl::device &device = reinterpret_cast<sycl::queue *>(queue)->get_device();
const size_t max_work_group_size = device.get_info<sycl::info::device::max_work_group_size>();
size_t preferred_work_group_size = 0;
switch (kernel) {
case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_CAMERA:
@ -792,6 +796,9 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK:
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_DEDICATED_LIGHT:
preferred_work_group_size = preferred_work_group_size_intersect;
break;
case DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND:
case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT:
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE:
@ -799,9 +806,13 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE:
case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME:
case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
case DEVICE_KERNEL_INTEGRATOR_SHADE_DEDICATED_LIGHT:
preferred_work_group_size = preferred_work_group_size_intersect_shading;
break;
case DEVICE_KERNEL_INTEGRATOR_SHADE_DEDICATED_LIGHT: {
const bool device_is_simd8 =
(device.has(sycl::aspect::ext_intel_gpu_eu_simd_width) &&
device.get_info<sycl::ext::intel::info::device::gpu_eu_simd_width>() == 8);
preferred_work_group_size = (device_is_simd8) ? preferred_work_group_size_shading_simd8 :
preferred_work_group_size_shading;
} break;
case DEVICE_KERNEL_CRYPTOMATTE_POSTPROCESS:
preferred_work_group_size = preferred_work_group_size_cryptomatte;
@ -829,11 +840,7 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
preferred_work_group_size = preferred_work_group_size_default;
}
const size_t limit_work_group_size = reinterpret_cast<sycl::queue *>(queue)
->get_device()
.get_info<sycl::info::device::max_work_group_size>();
kernel_local_size = std::min(limit_work_group_size, preferred_work_group_size);
kernel_local_size = std::min(max_work_group_size, preferred_work_group_size);
/* NOTE(@nsirgien): As for now non-uniform work-groups don't work on most oneAPI devices,
* we extend work size to fit uniformity requirements. */

View File

@ -46,7 +46,7 @@ static const char *oidn_device_type_to_string(const OIDNDeviceType type)
return "HIP";
# endif
/* The Metal support was added in OIDN 2.2.*/
/* The Metal support was added in OIDN 2.2. */
# if (OIDN_VERSION_MAJOR > 2) || ((OIDN_VERSION_MAJOR == 2) && (OIDN_VERSION_MINOR >= 2))
case OIDN_DEVICE_TYPE_METAL:
return "METAL";

View File

@ -224,18 +224,24 @@ ccl_device void camera_sample_orthographic(KernelGlobals kg,
/* Panorama Camera */
ccl_device_inline float3 camera_panorama_direction(ccl_constant KernelCamera *cam,
float x,
float y)
{
const ProjectionTransform rastertocamera = cam->rastertocamera;
float3 Pcamera = transform_perspective(&rastertocamera, make_float3(x, y, 0.0f));
return panorama_to_direction(cam, Pcamera.x, Pcamera.y);
}
ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
ccl_global const DecomposedTransform *cam_motion,
const float2 raster,
const float2 rand_lens,
ccl_private Ray *ray)
{
ProjectionTransform rastertocamera = cam->rastertocamera;
float3 Pcamera = transform_perspective(&rastertocamera, float2_to_float3(raster));
/* create ray form raster position */
float3 P = zero_float3();
float3 D = panorama_to_direction(cam, Pcamera.x, Pcamera.y);
float3 D = camera_panorama_direction(cam, raster.x, raster.y);
/* indicates ray should not receive any light, outside of the lens */
if (is_zero(D)) {
@ -246,6 +252,11 @@ ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
/* modify ray for depth of field */
float aperturesize = cam->aperturesize;
#ifdef __RAY_DIFFERENTIALS__
/* keep pre-DoF value for differentials later */
float3 Dcenter = D;
#endif
if (aperturesize > 0.0f) {
/* sample point on aperture */
float2 lens_uv = camera_sample_aperture(cam, rand_lens) * aperturesize;
@ -289,38 +300,32 @@ ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
* because we don't want to be affected by depth of field. We compute
* ray origin and direction for the center and two neighboring pixels
* and simply take their differences. */
float3 Pcenter = Pcamera;
float3 Dcenter = panorama_to_direction(cam, Pcenter.x, Pcenter.y);
float3 Dx = camera_panorama_direction(cam, raster.x + 1.0f, raster.y);
float3 Dy = camera_panorama_direction(cam, raster.x, raster.y + 1.0f);
if (use_stereo) {
float3 Pcenter = zero_float3();
float3 Px = zero_float3();
float3 Py = zero_float3();
spherical_stereo_transform(cam, &Pcenter, &Dcenter);
}
Pcenter = transform_point(&cameratoworld, Pcenter);
Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
float3 Px = transform_perspective(&rastertocamera, make_float3(raster.x + 1.0f, raster.y, 0.0f));
float3 Dx = panorama_to_direction(cam, Px.x, Px.y);
if (use_stereo) {
spherical_stereo_transform(cam, &Px, &Dx);
}
Px = transform_point(&cameratoworld, Px);
Dx = normalize(transform_direction(&cameratoworld, Dx));
differential3 dP, dD;
dP.dx = Px - Pcenter;
dD.dx = Dx - Dcenter;
float3 Py = transform_perspective(&rastertocamera, make_float3(raster.x, raster.y + 1.0f, 0.0f));
float3 Dy = panorama_to_direction(cam, Py.x, Py.y);
if (use_stereo) {
spherical_stereo_transform(cam, &Py, &Dy);
}
Py = transform_point(&cameratoworld, Py);
Dy = normalize(transform_direction(&cameratoworld, Dy));
dP.dy = Py - Pcenter;
dD.dy = Dy - Dcenter;
differential3 dP;
Pcenter = transform_point(&cameratoworld, Pcenter);
dP.dx = transform_point(&cameratoworld, Px) - Pcenter;
dP.dy = transform_point(&cameratoworld, Py) - Pcenter;
ray->dP = differential_make_compact(dP);
}
else {
ray->dP = differential_zero_compact();
}
differential3 dD;
Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
dD.dx = normalize(transform_direction(&cameratoworld, Dx)) - Dcenter;
dD.dy = normalize(transform_direction(&cameratoworld, Dy)) - Dcenter;
ray->dD = differential_make_compact(dD);
ray->dP = differential_make_compact(dP);
#endif
/* clipping */

View File

@ -18,7 +18,7 @@ typedef struct HuangHairExtra {
/* Optional modulation factors. */
float R, TT, TRT;
/* Local coordinate system. X is stored as `bsdf->N`.*/
/* Local coordinate system. X is stored as `bsdf->N`. */
float3 Y, Z;
/* Incident direction in local coordinate system. */

View File

@ -18,15 +18,20 @@ typedef struct ToonBsdf {
static_assert(sizeof(ShaderClosure) >= sizeof(ToonBsdf), "ToonBsdf is too large!");
ccl_device_inline int bsdf_toon_setup_common(ccl_private ToonBsdf *bsdf)
{
bsdf->size = clamp(bsdf->size, 1e-5f, 1.0f) * M_PI_2_F;
bsdf->smooth = saturatef(bsdf->smooth) * M_PI_2_F;
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
/* DIFFUSE TOON */
ccl_device int bsdf_diffuse_toon_setup(ccl_private ToonBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_DIFFUSE_TOON_ID;
bsdf->size = saturatef(bsdf->size);
bsdf->smooth = saturatef(bsdf->smooth);
return SD_BSDF | SD_BSDF_HAS_EVAL;
return bsdf_toon_setup_common(bsdf);
}
ccl_device float bsdf_toon_get_intensity(float max_angle, float smooth, float angle)
@ -57,19 +62,17 @@ ccl_device Spectrum bsdf_diffuse_toon_eval(ccl_private const ShaderClosure *sc,
ccl_private float *pdf)
{
ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
float max_angle = bsdf->size;
float smooth = bsdf->smooth;
float cosNO = dot(bsdf->N, wo);
if (cosNO >= 0.0f) {
float max_angle = bsdf->size * M_PI_2_F;
float smooth = bsdf->smooth * M_PI_2_F;
float angle = safe_acosf(fmaxf(cosNO, 0.0f));
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
float eval = bsdf_toon_get_intensity(max_angle, smooth, angle);
if (eval > 0.0f) {
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
*pdf = 0.5f * M_1_PI_F / (1.0f - cosf(sample_angle));
if (angle < sample_angle) {
float eval = bsdf_toon_get_intensity(max_angle, smooth, angle);
*pdf = M_1_2PI_F / one_minus_cos(sample_angle);
return make_spectrum(*pdf * eval);
}
}
@ -87,29 +90,22 @@ ccl_device int bsdf_diffuse_toon_sample(ccl_private const ShaderClosure *sc,
ccl_private float *pdf)
{
ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
float max_angle = bsdf->size * M_PI_2_F;
float smooth = bsdf->smooth * M_PI_2_F;
float max_angle = bsdf->size;
float smooth = bsdf->smooth;
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
float angle = sample_angle * rand.x;
if (sample_angle > 0.0f) {
float unused;
*wo = sample_uniform_cone(bsdf->N, one_minus_cos(sample_angle), rand, &unused, pdf);
float cosNO;
*wo = sample_uniform_cone(bsdf->N, one_minus_cos(sample_angle), rand, &cosNO, pdf);
if (dot(Ng, *wo) > 0.0f) {
*eval = make_spectrum(*pdf * bsdf_toon_get_intensity(max_angle, smooth, angle));
}
else {
*eval = zero_spectrum();
*pdf = 0.0f;
}
}
else {
*eval = zero_spectrum();
*pdf = 0.0f;
if (dot(Ng, *wo) > 0.0f) {
float angle = acosf(cosNO);
*eval = make_spectrum(*pdf * bsdf_toon_get_intensity(max_angle, smooth, angle));
return LABEL_REFLECT | LABEL_DIFFUSE;
}
return LABEL_REFLECT | LABEL_DIFFUSE;
*pdf = 0.0f;
*eval = zero_spectrum();
return LABEL_NONE;
}
/* GLOSSY TOON */
@ -117,10 +113,7 @@ ccl_device int bsdf_diffuse_toon_sample(ccl_private const ShaderClosure *sc,
ccl_device int bsdf_glossy_toon_setup(ccl_private ToonBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_GLOSSY_TOON_ID;
bsdf->size = saturatef(bsdf->size);
bsdf->smooth = saturatef(bsdf->smooth);
return SD_BSDF | SD_BSDF_HAS_EVAL;
return bsdf_toon_setup_common(bsdf);
}
ccl_device Spectrum bsdf_glossy_toon_eval(ccl_private const ShaderClosure *sc,
@ -129,8 +122,8 @@ ccl_device Spectrum bsdf_glossy_toon_eval(ccl_private const ShaderClosure *sc,
ccl_private float *pdf)
{
ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
float max_angle = bsdf->size * M_PI_2_F;
float smooth = bsdf->smooth * M_PI_2_F;
float max_angle = bsdf->size;
float smooth = bsdf->smooth;
float cosNI = dot(bsdf->N, wi);
float cosNO = dot(bsdf->N, wo);
@ -140,12 +133,13 @@ ccl_device Spectrum bsdf_glossy_toon_eval(ccl_private const ShaderClosure *sc,
float cosRO = dot(R, wo);
float angle = safe_acosf(fmaxf(cosRO, 0.0f));
float eval = bsdf_toon_get_intensity(max_angle, smooth, angle);
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
*pdf = 0.5f * M_1_PI_F / (1.0f - cosf(sample_angle));
return make_spectrum(*pdf * eval);
if (angle < sample_angle) {
float eval = bsdf_toon_get_intensity(max_angle, smooth, angle);
*pdf = M_1_2PI_F / one_minus_cos(sample_angle);
return make_spectrum(*pdf * eval);
}
}
*pdf = 0.0f;
return zero_spectrum();
@ -160,8 +154,8 @@ ccl_device int bsdf_glossy_toon_sample(ccl_private const ShaderClosure *sc,
ccl_private float *pdf)
{
ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
float max_angle = bsdf->size * M_PI_2_F;
float smooth = bsdf->smooth * M_PI_2_F;
float max_angle = bsdf->size;
float smooth = bsdf->smooth;
float cosNI = dot(bsdf->N, wi);
if (cosNI > 0) {
@ -169,30 +163,21 @@ ccl_device int bsdf_glossy_toon_sample(ccl_private const ShaderClosure *sc,
float3 R = (2 * cosNI) * bsdf->N - wi;
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
float angle = sample_angle * rand.x;
float unused;
*wo = sample_uniform_cone(R, one_minus_cos(sample_angle), rand, &unused, pdf);
float cosRO;
*wo = sample_uniform_cone(R, one_minus_cos(sample_angle), rand, &cosRO, pdf);
if (dot(Ng, *wo) > 0.0f) {
float cosNO = dot(bsdf->N, *wo);
/* make sure the direction we chose is still in the right hemisphere */
if (cosNO > 0) {
*eval = make_spectrum(*pdf * bsdf_toon_get_intensity(max_angle, smooth, angle));
}
else {
*pdf = 0.0f;
*eval = zero_spectrum();
}
}
else {
*pdf = 0.0f;
*eval = zero_spectrum();
/* make sure the direction we chose is still in the right hemisphere */
if (dot(Ng, *wo) > 0.0f && dot(bsdf->N, *wo) > 0.0f) {
float angle = acosf(cosRO);
*eval = make_spectrum(*pdf * bsdf_toon_get_intensity(max_angle, smooth, angle));
return LABEL_GLOSSY | LABEL_REFLECT;
}
}
return LABEL_GLOSSY | LABEL_REFLECT;
*pdf = 0.0f;
*eval = zero_spectrum();
return LABEL_NONE;
}
CCL_NAMESPACE_END

View File

@ -18,9 +18,8 @@
#include "util/texture.h"
#include "util/types.h"
/* On x86_64, versions of glibc < 2.16 have an issue where expf is
* much slower than the double version. This was fixed in glibc 2.16.
*/
/* On x86_64, versions of GLIBC < 2.16 have an issue where `expf` is
* much slower than the double version. This was fixed in GLIBC 2.16. */
#if !defined(__KERNEL_GPU__) && defined(__x86_64__) && defined(__x86_64__) && \
defined(__GNU_LIBRARY__) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) && \
(__GLIBC__ <= 2 && __GLIBC_MINOR__ < 16)

View File

@ -38,7 +38,7 @@
#define ccl_global
#define ccl_always_inline __attribute__((always_inline))
#define ccl_device_inline inline
#define ccl_noinline __attribute__((noinline))
#define ccl_noinline
#define ccl_inline_constant const constexpr
#define ccl_device_constant static constexpr
#define ccl_static_constexpr static constexpr

View File

@ -64,6 +64,11 @@ typedef struct VolumeShaderCoefficients {
Spectrum emission;
} VolumeShaderCoefficients;
typedef struct EquiangularCoefficients {
float3 P;
float2 t_range;
} EquiangularCoefficients;
/* Evaluate shader to get extinction coefficient at P. */
ccl_device_inline bool shadow_volume_shader_sample(KernelGlobals kg,
IntegratorShadowState state,
@ -264,18 +269,18 @@ ccl_device void volume_shadow_heterogeneous(KernelGlobals kg,
# define VOLUME_SAMPLE_PDF_CUTOFF 1e-8f
ccl_device float volume_equiangular_sample(ccl_private const Ray *ccl_restrict ray,
const float3 light_P,
ccl_private const EquiangularCoefficients &coeffs,
const float xi,
ccl_private float *pdf)
{
const float tmin = ray->tmin;
const float tmax = ray->tmax;
const float delta = dot((light_P - ray->P), ray->D);
const float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta);
const float delta = dot((coeffs.P - ray->P), ray->D);
const float D = safe_sqrtf(len_squared(coeffs.P - ray->P) - delta * delta);
if (UNLIKELY(D == 0.0f)) {
*pdf = 0.0f;
return 0.0f;
}
const float tmin = coeffs.t_range.x;
const float tmax = coeffs.t_range.y;
const float theta_a = atan2f(tmin - delta, D);
const float theta_b = atan2f(tmax - delta, D);
const float t_ = D * tanf((xi * theta_b) + (1 - xi) * theta_a);
@ -289,17 +294,17 @@ ccl_device float volume_equiangular_sample(ccl_private const Ray *ccl_restrict r
}
ccl_device float volume_equiangular_pdf(ccl_private const Ray *ccl_restrict ray,
const float3 light_P,
ccl_private const EquiangularCoefficients &coeffs,
const float sample_t)
{
const float delta = dot((light_P - ray->P), ray->D);
const float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta);
const float delta = dot((coeffs.P - ray->P), ray->D);
const float D = safe_sqrtf(len_squared(coeffs.P - ray->P) - delta * delta);
if (UNLIKELY(D == 0.0f)) {
return 0.0f;
}
const float tmin = ray->tmin;
const float tmax = ray->tmax;
const float tmin = coeffs.t_range.x;
const float tmax = coeffs.t_range.y;
const float t_ = sample_t - delta;
const float theta_a = atan2f(tmin - delta, D);
@ -313,6 +318,29 @@ ccl_device float volume_equiangular_pdf(ccl_private const Ray *ccl_restrict ray,
return pdf;
}
ccl_device_inline bool volume_equiangular_valid_ray_segment(KernelGlobals kg,
const float3 ray_P,
const float3 ray_D,
ccl_private float2 *t_range,
const ccl_private LightSample *ls)
{
if (ls->type == LIGHT_SPOT) {
ccl_global const KernelLight *klight = &kernel_data_fetch(lights, ls->lamp);
return spot_light_valid_ray_segment(klight, ray_P, ray_D, t_range);
}
if (ls->type == LIGHT_AREA) {
ccl_global const KernelLight *klight = &kernel_data_fetch(lights, ls->lamp);
return area_light_valid_ray_segment(&klight->area, ray_P - klight->co, ray_D, t_range);
}
if (ls->type == LIGHT_TRIANGLE) {
return triangle_light_valid_ray_segment(kg, ray_P - ls->P, ray_D, t_range, ls);
}
/* Point light, the whole range of the ray is visible. */
kernel_assert(ls->type == LIGHT_POINT);
return true;
}
/* Distance sampling */
ccl_device float volume_distance_sample(float max_t,
@ -403,7 +431,7 @@ typedef struct VolumeIntegrateState {
ccl_device_forceinline void volume_integrate_step_scattering(
ccl_private const ShaderData *sd,
ccl_private const Ray *ray,
const float3 equiangular_light_P,
ccl_private const EquiangularCoefficients &equiangular_coeffs,
ccl_private const VolumeShaderCoefficients &ccl_restrict coeff,
const Spectrum transmittance,
ccl_private VolumeIntegrateState &ccl_restrict vstate,
@ -474,7 +502,7 @@ ccl_device_forceinline void volume_integrate_step_scattering(
/* Multiple importance sampling. */
if (vstate.use_mis) {
const float equiangular_pdf = volume_equiangular_pdf(ray, equiangular_light_P, new_t);
const float equiangular_pdf = volume_equiangular_pdf(ray, equiangular_coeffs, new_t);
const float mis_weight = power_heuristic(vstate.distance_pdf * distance_pdf,
equiangular_pdf);
result.direct_throughput *= 2.0f * mis_weight;
@ -509,7 +537,7 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
ccl_global float *ccl_restrict render_buffer,
const float object_step_size,
const VolumeSampleMethod direct_sample_method,
const float3 equiangular_light_P,
ccl_private const EquiangularCoefficients &equiangular_coeffs,
ccl_private VolumeIntegrateResult &result)
{
PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_INTEGRATE);
@ -560,7 +588,7 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
/* Equiangular sampling: compute distance and PDF in advance. */
if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
result.direct_t = volume_equiangular_sample(
ray, equiangular_light_P, vstate.rscatter, &vstate.equiangular_pdf);
ray, equiangular_coeffs, vstate.rscatter, &vstate.equiangular_pdf);
}
# ifdef __PATH_GUIDING__
result.direct_sample_method = vstate.direct_sample_method;
@ -614,7 +642,7 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
/* Scattering and absorption. */
volume_integrate_step_scattering(
sd, ray, equiangular_light_P, coeff, transmittance, vstate, result);
sd, ray, equiangular_coeffs, coeff, transmittance, vstate, result);
}
else {
/* Absorption only. */
@ -673,7 +701,8 @@ ccl_device_forceinline bool integrate_volume_equiangular_sample_light(
ccl_private const Ray *ccl_restrict ray,
ccl_private const ShaderData *ccl_restrict sd,
ccl_private const RNGState *ccl_restrict rng_state,
ccl_private float3 *ccl_restrict P)
ccl_private EquiangularCoefficients *ccl_restrict equiangular_coeffs,
ccl_private LightSample &ccl_restrict ls)
{
/* Test if there is a light or BSDF that needs direct light. */
if (!kernel_data.integrator.use_direct_light) {
@ -685,7 +714,6 @@ ccl_device_forceinline bool integrate_volume_equiangular_sample_light(
const uint bounce = INTEGRATOR_STATE(state, path, bounce);
const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
LightSample ls ccl_optional_struct_init;
if (!light_sample_from_volume_segment(kg,
rand_light,
sd->time,
@ -708,9 +736,10 @@ ccl_device_forceinline bool integrate_volume_equiangular_sample_light(
return false;
}
*P = ls.P;
equiangular_coeffs->P = ls.P;
return true;
return volume_equiangular_valid_ray_segment(
kg, ray->P, ray->D, &equiangular_coeffs->t_range, &ls);
}
/* Path tracing: sample point on light and evaluate light shader, then
@ -725,41 +754,26 @@ ccl_device_forceinline void integrate_volume_direct_light(
# ifdef __PATH_GUIDING__
ccl_private const Spectrum unlit_throughput,
# endif
ccl_private const Spectrum throughput)
ccl_private const Spectrum throughput,
ccl_private LightSample &ccl_restrict ls)
{
PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_DIRECT_LIGHT);
if (!kernel_data.integrator.use_direct_light) {
if (!kernel_data.integrator.use_direct_light || ls.emitter_id == EMITTER_NONE) {
return;
}
/* Sample position on the same light again, now from the shading point where we scattered.
*
* Note that this means we sample the light tree twice when equiangular sampling is used.
* We could consider sampling the light tree just once and use the same light position again.
*
* This would make the PDFs for MIS weights more complicated due to having to account for
* both distance/equiangular and direct/indirect light sampling, but could be more accurate.
* Additionally we could end up behind the light or outside a spot light cone, which might
* waste a sample. Though on the other hand it would be possible to prevent that with
* equiangular sampling restricted to a smaller sub-segment where the light has influence. */
LightSample ls ccl_optional_struct_init;
/* Sample position on the same light again, now from the shading point where we scattered. */
{
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
const uint bounce = INTEGRATOR_STATE(state, path, bounce);
const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
const float3 N = zero_float3();
const int object_receiver = light_link_receiver_nee(kg, sd);
const int shader_flags = SD_BSDF_HAS_TRANSMISSION;
if (!light_sample_from_position(kg,
rng_state,
rand_light,
sd->time,
P,
zero_float3(),
light_link_receiver_nee(kg, sd),
SD_BSDF_HAS_TRANSMISSION,
bounce,
path_flag,
&ls))
if (!light_sample<false>(
kg, rand_light, sd->time, P, N, object_receiver, shader_flags, bounce, path_flag, &ls))
{
return;
}
@ -877,6 +891,7 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
KernelGlobals kg,
IntegratorState state,
ccl_private ShaderData *sd,
ccl_private const Ray *ray,
ccl_private const RNGState *rng_state,
ccl_private const ShaderVolumePhases *phases)
{
@ -929,6 +944,9 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(phase_wo);
INTEGRATOR_STATE_WRITE(state, ray, tmin) = 0.0f;
# ifdef __LIGHT_TREE__
INTEGRATOR_STATE_WRITE(state, ray, previous_dt) = ray->tmax - ray->tmin;
# endif
INTEGRATOR_STATE_WRITE(state, ray, tmax) = FLT_MAX;
# ifdef __RAY_DIFFERENTIALS__
INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
@ -957,7 +975,8 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
/* Update path state */
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = phase_pdf;
INTEGRATOR_STATE_WRITE(state, path, mis_origin_n) = zero_float3();
const float3 previous_P = ray->P + ray->D * ray->tmin;
INTEGRATOR_STATE_WRITE(state, path, mis_origin_n) = sd->P - previous_P;
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
unguided_phase_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
@ -989,11 +1008,15 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
/* Sample light ahead of volume stepping, for equiangular sampling. */
/* TODO: distant lights are ignored now, but could instead use even distribution. */
LightSample ls ccl_optional_struct_init;
ls.emitter_id = EMITTER_NONE;
const bool need_light_sample = !(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_TERMINATE);
float3 equiangular_P = zero_float3();
const bool have_equiangular_sample = need_light_sample &&
integrate_volume_equiangular_sample_light(
kg, state, ray, &sd, &rng_state, &equiangular_P);
EquiangularCoefficients equiangular_coeffs = {zero_float3(), make_float2(ray->tmin, ray->tmax)};
const bool have_equiangular_sample =
need_light_sample && integrate_volume_equiangular_sample_light(
kg, state, ray, &sd, &rng_state, &equiangular_coeffs, ls);
VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ?
volume_stack_sample_method(kg, state) :
@ -1023,7 +1046,7 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
render_buffer,
step_size,
direct_sample_method,
equiangular_P,
equiangular_coeffs,
result);
/* Perform path termination. The intersect_closest will have already marked this path
@ -1091,7 +1114,8 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
# ifdef __PATH_GUIDING__
unlit_throughput,
# endif
result.direct_throughput);
result.direct_throughput,
ls);
}
/* Indirect light.
@ -1130,7 +1154,7 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
# endif
# endif
if (integrate_volume_phase_scatter(kg, state, &sd, &rng_state, &result.indirect_phases)) {
if (integrate_volume_phase_scatter(kg, state, &sd, ray, &rng_state, &result.indirect_phases)) {
return VOLUME_PATH_SCATTERED;
}
else {

View File

@ -75,6 +75,9 @@ KERNEL_STRUCT_MEMBER(ray, float, tmax, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(ray, float, time, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(ray, float, dD, KERNEL_FEATURE_PATH_TRACING)
#ifdef __LIGHT_TREE__
KERNEL_STRUCT_MEMBER(ray, float, previous_dt, KERNEL_FEATURE_PATH_TRACING)
#endif
KERNEL_STRUCT_END(ray)
/*************************** Intersection result ******************************/

View File

@ -233,6 +233,11 @@ ccl_device bool area_light_spread_clamp_light(const float3 P,
return true;
}
ccl_device_forceinline bool area_light_is_ellipse(const ccl_global KernelAreaLight *light)
{
return light->invarea < 0.0f;
}
/* Common API. */
/* Compute `eval_fac` and `pdf`. Also sample a new position on the light if `sample_coord`. */
template<bool in_volume_segment>
@ -338,7 +343,7 @@ ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight,
const float light_v = dot(inplane, klight->area.axis_v) / klight->area.len_v;
if (!in_volume_segment) {
const bool is_ellipse = (klight->area.invarea < 0.0f);
const bool is_ellipse = area_light_is_ellipse(&klight->area);
/* Sampled point lies outside of the area light. */
if (is_ellipse && (sqr(light_u) + sqr(light_v) > 0.25f)) {
@ -380,7 +385,7 @@ ccl_device_inline bool area_light_intersect(const ccl_global KernelLight *klight
{
/* Area light. */
const float invarea = fabsf(klight->area.invarea);
const bool is_ellipse = (klight->area.invarea < 0.0f);
const bool is_ellipse = area_light_is_ellipse(&klight->area);
if (invarea == 0.0f) {
return false;
}
@ -428,6 +433,55 @@ ccl_device_inline bool area_light_sample_from_intersection(
return area_light_eval<false>(klight, ray_P, &light_P, ls, zero_float2(), false);
}
/* Returns the maximal distance between the light center and the boundary. */
ccl_device_forceinline float area_light_max_extent(const ccl_global KernelAreaLight *light)
{
return 0.5f * (area_light_is_ellipse(light) ? fmaxf(light->len_u, light->len_v) :
len(make_float2(light->len_u, light->len_v)));
}
/* Find the ray segment lit by the area light. */
ccl_device_inline bool area_light_valid_ray_segment(const ccl_global KernelAreaLight *light,
float3 P,
float3 D,
ccl_private float2 *t_range)
{
bool valid;
const float tan_half_spread = light->tan_half_spread;
float3 axis = light->dir;
const bool angle_almost_zero = (tan_half_spread < 1e-5f);
if (angle_almost_zero) {
/* Map to local coordinate of the light. Do not use `itfm` in `KernelLight` as there might be
* additional scaling in the light size. */
const Transform tfm = make_transform(light->axis_u, light->axis_v, axis);
P = transform_point(&tfm, P);
D = transform_direction(&tfm, D);
axis = make_float3(0.0f, 0.0f, 1.0f);
const float half_len_u = 0.5f * light->len_u;
const float half_len_v = 0.5f * light->len_v;
if (area_light_is_ellipse(light)) {
valid = ray_infinite_cylinder_intersect(P, D, half_len_u, half_len_v, t_range);
}
else {
const float3 bbox_min = make_float3(-half_len_u, -half_len_v, 0.0f);
const float3 bbox_max = make_float3(half_len_u, half_len_v, FLT_MAX);
valid = ray_aabb_intersect(bbox_min, bbox_max, P, D, t_range);
}
}
else {
/* Conservative estimation with the smallest possible cone covering the whole spread. */
const float3 apex_to_point = P + area_light_max_extent(light) / tan_half_spread * axis;
const float cos_angle_sq = 1.0f / (1.0f + sqr(tan_half_spread));
valid = ray_cone_intersect(axis, apex_to_point, D, cos_angle_sq, t_range);
}
/* Limit the range to the positive side of the area light. */
return valid && ray_plane_intersect(axis, P, D, t_range);
}
template<bool in_volume_segment>
ccl_device_forceinline bool area_light_tree_parameters(const ccl_global KernelLight *klight,
const float3 centroid,
@ -438,13 +492,11 @@ ccl_device_forceinline bool area_light_tree_parameters(const ccl_global KernelLi
ccl_private float2 &distance,
ccl_private float3 &point_to_centroid)
{
if (!in_volume_segment) {
/* TODO: a cheap substitute for minimal distance between point and primitive. Does it
* worth the overhead to compute the accurate minimal distance? */
float min_distance;
point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
distance = make_float2(min_distance, min_distance);
}
/* TODO: a cheap substitute for minimal distance between point and primitive. Does it worth the
* overhead to compute the accurate minimal distance? */
float min_distance;
point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
distance = make_float2(min_distance, min_distance);
cos_theta_u = FLT_MAX;
@ -464,9 +516,8 @@ ccl_device_forceinline bool area_light_tree_parameters(const ccl_global KernelLi
const bool shape_above_surface = dot(N, centroid - P) + fabsf(dot(N, extentu)) +
fabsf(dot(N, extentv)) >
0;
const bool in_volume = is_zero(N);
return (front_facing && shape_above_surface) || in_volume;
return front_facing && shape_above_surface;
}
CCL_NAMESPACE_END

View File

@ -12,9 +12,9 @@ CCL_NAMESPACE_BEGIN
typedef struct LightSample {
float3 P; /* position on light, or direction for distant light */
float3 Ng; /* normal on light */
float3 D; /* direction from shading point to light */
packed_float3 Ng; /* normal on light */
float t; /* distance to light (FLT_MAX for distant light) */
float3 D; /* direction from shading point to light */
float u, v; /* parametric coordinate on primitive */
float pdf; /* pdf for selecting light and point on light */
float pdf_selection; /* pdf for selecting light */
@ -25,6 +25,7 @@ typedef struct LightSample {
int lamp; /* lamp id */
int group; /* lightgroup */
LightType type; /* type of light */
int emitter_id; /* index in the emitter array */
} LightSample;
/* Utilities */

View File

@ -41,36 +41,14 @@ ccl_device int light_distribution_sample(KernelGlobals kg, const float rand)
return index;
}
template<bool in_volume_segment>
ccl_device_noinline bool light_distribution_sample(KernelGlobals kg,
const float3 rand,
const float time,
const float3 P,
const float3 N,
const int object_receiver,
const int shader_flags,
const int bounce,
const uint32_t path_flag,
const float rand,
ccl_private LightSample *ls)
{
/* Sample light index from distribution. */
/* The first two dimensions of the Sobol sequence have better stratification. */
const int index = light_distribution_sample(kg, rand.z);
const float pdf_selection = kernel_data.integrator.distribution_pdf_lights;
const float2 rand_uv = float3_to_float2(rand);
return light_sample<in_volume_segment>(kg,
rand_uv,
time,
P,
N,
object_receiver,
shader_flags,
bounce,
path_flag,
index,
0,
pdf_selection,
ls);
ls->emitter_id = light_distribution_sample(kg, rand);
ls->pdf_selection = kernel_data.integrator.distribution_pdf_lights;
return true;
}
ccl_device_inline float light_distribution_pdf_lamp(KernelGlobals kg)

View File

@ -177,7 +177,7 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
template<bool in_volume_segment>
ccl_device_noinline bool light_sample(KernelGlobals kg,
const float2 rand,
const float3 rand_light,
const float time,
const float3 P,
const float3 N,
@ -185,33 +185,31 @@ ccl_device_noinline bool light_sample(KernelGlobals kg,
const int shader_flags,
const int bounce,
const uint32_t path_flag,
const int emitter_index,
const int object_id,
const float pdf_selection,
ccl_private LightSample *ls)
{
/* The first two dimensions of the Sobol sequence have better stratification, use them to sample
* position on the light. */
const float2 rand = float3_to_float2(rand_light);
int prim;
MeshLight mesh_light;
#ifdef __LIGHT_TREE__
if (kernel_data.integrator.use_light_tree) {
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
emitter_index);
ls->emitter_id);
prim = kemitter->light.id;
mesh_light.shader_flag = kemitter->mesh_light.shader_flag;
mesh_light.object_id = object_id;
mesh_light.object_id = ls->object;
}
else
#endif
{
ccl_global const KernelLightDistribution *kdistribution = &kernel_data_fetch(
light_distribution, emitter_index);
light_distribution, ls->emitter_id);
prim = kdistribution->prim;
mesh_light = kdistribution->mesh_light;
}
/* A different value would be assigned in `triangle_light_sample()` if `!use_light_tree`. */
ls->pdf_selection = pdf_selection;
if (prim >= 0) {
/* Mesh light. */
const int object = mesh_light.object_id;

View File

@ -196,21 +196,22 @@ ccl_device_forceinline bool point_light_tree_parameters(const ccl_global KernelL
ccl_private float2 &distance,
ccl_private float3 &point_to_centroid)
{
float min_distance;
point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
distance = min_distance * one_float2();
if (in_volume_segment) {
cos_theta_u = 1.0f; /* Any value in [-1, 1], irrelevant since theta = 0 */
return true;
}
float dist_point_to_centroid;
point_to_centroid = safe_normalize_len(centroid - P, &dist_point_to_centroid);
const float radius = klight->spot.radius;
if (klight->spot.is_sphere) {
if (dist_point_to_centroid > radius) {
if (min_distance > radius) {
/* Equivalent to a disk light with the same angular span. */
cos_theta_u = cos_from_sin(radius / dist_point_to_centroid);
distance = dist_point_to_centroid * make_float2(1.0f / cos_theta_u, 1.0f);
cos_theta_u = cos_from_sin(radius / min_distance);
distance.x = min_distance / cos_theta_u;
}
else {
/* Similar to background light. */
@ -220,10 +221,10 @@ ccl_device_forceinline bool point_light_tree_parameters(const ccl_global KernelL
}
}
else {
const float hypotenus = sqrtf(sqr(radius) + sqr(dist_point_to_centroid));
cos_theta_u = dist_point_to_centroid / hypotenus;
const float hypotenus = sqrtf(sqr(radius) + sqr(min_distance));
cos_theta_u = min_distance / hypotenus;
distance = make_float2(hypotenus, dist_point_to_centroid);
distance.x = hypotenus;
}
return true;

View File

@ -329,17 +329,25 @@ ccl_device_inline bool light_sample_from_volume_segment(KernelGlobals kg,
const uint32_t path_flag,
ccl_private LightSample *ls)
{
const int shader_flags = SD_BSDF_HAS_TRANSMISSION;
#ifdef __LIGHT_TREE__
if (kernel_data.integrator.use_light_tree) {
return light_tree_sample<true>(
kg, rand, time, P, D, t, object_receiver, SD_BSDF_HAS_TRANSMISSION, bounce, path_flag, ls);
if (!light_tree_sample<true>(kg, rand.z, P, D, t, object_receiver, shader_flags, ls)) {
return false;
}
}
else
#endif
{
return light_distribution_sample<true>(
kg, rand, time, P, D, object_receiver, SD_BSDF_HAS_TRANSMISSION, bounce, path_flag, ls);
if (!light_distribution_sample(kg, rand.z, ls)) {
return false;
}
}
/* Sample position on the selected light. */
return light_sample<true>(
kg, rand, time, P, D, object_receiver, shader_flags, bounce, path_flag, ls);
}
ccl_device bool light_sample_from_position(KernelGlobals kg,
@ -354,17 +362,24 @@ ccl_device bool light_sample_from_position(KernelGlobals kg,
const uint32_t path_flag,
ccl_private LightSample *ls)
{
/* Randomly select a light. */
#ifdef __LIGHT_TREE__
if (kernel_data.integrator.use_light_tree) {
return light_tree_sample<false>(
kg, rand, time, P, N, 0.0f, object_receiver, shader_flags, bounce, path_flag, ls);
if (!light_tree_sample<false>(kg, rand.z, P, N, 0.0f, object_receiver, shader_flags, ls)) {
return false;
}
}
else
#endif
{
return light_distribution_sample<false>(
kg, rand, time, P, N, object_receiver, shader_flags, bounce, path_flag, ls);
if (!light_distribution_sample(kg, rand.z, ls)) {
return false;
}
}
/* Sample position on the selected light. */
return light_sample<false>(
kg, rand, time, P, N, object_receiver, shader_flags, bounce, path_flag, ls);
}
/* Update light sample with new shading point position for MNEE. The position on the light is fixed
@ -415,13 +430,15 @@ ccl_device_inline float light_sample_mis_weight_forward_surface(KernelGlobals kg
#ifdef __LIGHT_TREE__
if (kernel_data.integrator.use_light_tree) {
float3 ray_P = INTEGRATOR_STATE(state, ray, P);
const float dt = INTEGRATOR_STATE(state, ray, previous_dt);
const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
uint lookup_offset = kernel_data_fetch(object_lookup_offset, sd->object);
uint prim_offset = kernel_data_fetch(object_prim_offset, sd->object);
uint triangle = kernel_data_fetch(triangle_to_tree, sd->prim - prim_offset + lookup_offset);
pdf *= light_tree_pdf(
kg, ray_P, N, path_flag, sd->object, triangle, light_link_receiver_forward(kg, state));
kg, ray_P, N, dt, path_flag, sd->object, triangle, light_link_receiver_forward(kg, state));
}
else
#endif
@ -445,9 +462,11 @@ ccl_device_inline float light_sample_mis_weight_forward_lamp(KernelGlobals kg,
#ifdef __LIGHT_TREE__
if (kernel_data.integrator.use_light_tree) {
const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
const float dt = INTEGRATOR_STATE(state, ray, previous_dt);
pdf *= light_tree_pdf(kg,
P,
N,
dt,
path_flag,
0,
kernel_data_fetch(light_to_tree, ls->lamp),
@ -485,9 +504,10 @@ ccl_device_inline float light_sample_mis_weight_forward_background(KernelGlobals
#ifdef __LIGHT_TREE__
if (kernel_data.integrator.use_light_tree) {
const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
const float dt = INTEGRATOR_STATE(state, ray, previous_dt);
uint light = kernel_data_fetch(light_to_tree, kernel_data.background.light_index);
pdf *= light_tree_pdf(
kg, ray_P, N, path_flag, 0, light, light_link_receiver_forward(kg, state));
kg, ray_P, N, dt, path_flag, 0, light, light_link_receiver_forward(kg, state));
}
else
#endif

View File

@ -265,6 +265,24 @@ ccl_device_inline bool spot_light_sample_from_intersection(
return true;
}
/* Find the ray segment lit by the spot light. */
ccl_device_inline bool spot_light_valid_ray_segment(const ccl_global KernelLight *klight,
const float3 P,
const float3 D,
ccl_private float2 *t_range)
{
/* Convert to local space of the spot light. */
const Transform itfm = klight->itfm;
float3 local_P = P + klight->spot.dir * klight->spot.ray_segment_dp;
local_P = transform_point(&itfm, local_P);
const float3 local_D = transform_direction(&itfm, D);
const float3 axis = make_float3(0.0f, 0.0f, -1.0f);
/* Intersect the ray with the smallest enclosing cone of the light spread. */
return ray_cone_intersect(
axis, local_P, local_D, sqr(klight->spot.cos_half_spot_angle), t_range);
}
template<bool in_volume_segment>
ccl_device_forceinline bool spot_light_tree_parameters(const ccl_global KernelLight *klight,
const float3 centroid,
@ -273,35 +291,32 @@ ccl_device_forceinline bool spot_light_tree_parameters(const ccl_global KernelLi
ccl_private float2 &distance,
ccl_private float3 &point_to_centroid)
{
float dist_point_to_centroid;
const float3 point_to_centroid_ = safe_normalize_len(centroid - P, &dist_point_to_centroid);
float min_distance;
point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
distance = min_distance * one_float2();
const float radius = klight->spot.radius;
if (klight->spot.is_sphere) {
cos_theta_u = (dist_point_to_centroid > radius) ?
cos_from_sin(radius / dist_point_to_centroid) :
-1.0f;
cos_theta_u = (min_distance > radius) ? cos_from_sin(radius / min_distance) : -1.0f;
if (in_volume_segment) {
return true;
}
distance = (dist_point_to_centroid > radius) ?
dist_point_to_centroid * make_float2(1.0f / cos_theta_u, 1.0f) :
one_float2() * radius / M_SQRT2_F;
distance = (min_distance > radius) ? min_distance * make_float2(1.0f / cos_theta_u, 1.0f) :
one_float2() * radius / M_SQRT2_F;
}
else {
const float hypotenus = sqrtf(sqr(radius) + sqr(dist_point_to_centroid));
cos_theta_u = dist_point_to_centroid / hypotenus;
const float hypotenus = sqrtf(sqr(radius) + sqr(min_distance));
cos_theta_u = min_distance / hypotenus;
if (in_volume_segment) {
return true;
}
distance = make_float2(hypotenus, dist_point_to_centroid);
distance.x = hypotenus;
}
point_to_centroid = point_to_centroid_;
return true;
}

View File

@ -148,10 +148,7 @@ ccl_device void light_tree_importance(const float3 N_or_D,
float cos_min_incidence_angle = 1.0f;
float cos_max_incidence_angle = 1.0f;
/* When sampling the light tree for the second time in `shade_volume.h` and when query the pdf in
* `sample.h`. */
const bool in_volume = is_zero(N_or_D);
if (!in_volume_segment && !in_volume) {
if (!in_volume_segment) {
const float3 N = N_or_D;
const float cos_theta_i = has_transmission ? fabsf(dot(point_to_centroid, N)) :
dot(point_to_centroid, N);
@ -197,7 +194,7 @@ ccl_device void light_tree_importance(const float3 N_or_D,
float cos_min_outgoing_angle;
if ((cos_theta >= cos_theta_u) || (cos_theta_minus_theta_u >= cos_theta_o)) {
/* theta - theta_o - theta_u <= 0 */
kernel_assert((fast_acosf(cos_theta) - bcone.theta_o - fast_acosf(cos_theta_u)) < 5e-4f);
kernel_assert((fast_acosf(cos_theta) - bcone.theta_o - fast_acosf(cos_theta_u)) < 1e-3f);
cos_min_outgoing_angle = 1.0f;
}
else if ((bcone.theta_o + bcone.theta_e > M_PI_F) ||
@ -221,9 +218,9 @@ ccl_device void light_tree_importance(const float3 N_or_D,
max_importance = fabsf(f_a * cos_min_incidence_angle * energy * cos_min_outgoing_angle /
(in_volume_segment ? min_distance : sqr(min_distance)));
/* TODO: also min importance for volume? */
/* TODO: compute proper min importance for volume. */
if (in_volume_segment) {
min_importance = max_importance;
min_importance = 0.0f;
return;
}
@ -270,10 +267,10 @@ ccl_device bool compute_emitter_centroid_and_dir(KernelGlobals kg,
/* Arbitrary centroid and direction. */
centroid = make_float3(0.0f, 0.0f, 1.0f);
dir = make_float3(0.0f, 0.0f, -1.0f);
return !in_volume_segment;
break;
case LIGHT_DISTANT:
dir = centroid;
return !in_volume_segment;
break;
default:
return false;
}
@ -323,23 +320,27 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
float cos_theta_u;
float distance;
if (knode->type == LIGHT_TREE_DISTANT) {
if (in_volume_segment) {
return;
}
point_to_centroid = -bcone.axis;
cos_theta_u = fast_cosf(bcone.theta_o + bcone.theta_e);
distance = 1.0f;
if (t == FLT_MAX) {
/* In world volume, distant light has no contribution. */
return;
}
}
else {
const float3 centroid = 0.5f * (bbox.min + bbox.max);
if (in_volume_segment) {
const float3 D = N_or_D;
const float3 closest_point = P + dot(centroid - P, D) * D;
const float closest_t = clamp(dot(centroid - P, D), 0.0f, t);
const float3 closest_point = P + D * closest_t;
/* Minimal distance of the ray to the cluster. */
distance = len(centroid - closest_point);
/* Vector that forms a minimal angle with the emitter centroid. */
point_to_centroid = -compute_v(centroid, P, D, bcone.axis, t);
cos_theta_u = light_tree_cos_bounding_box_angle(bbox, closest_point, point_to_centroid);
cos_theta_u = light_tree_cos_bounding_box_angle(
bbox, closest_point, normalize(centroid - closest_point));
}
else {
const float3 N = N_or_D;
@ -404,8 +405,8 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
bcone.theta_o = kemitter->theta_o;
bcone.theta_e = kemitter->theta_e;
float cos_theta_u;
float2 distance; /* distance.x = max_distance, distance.y = mix_distance */
float3 centroid, point_to_centroid, P_c;
float2 distance; /* distance.x = max_distance, distance.y = min_distance */
float3 centroid, point_to_centroid, P_c = P;
if (!compute_emitter_centroid_and_dir<in_volume_segment>(kg, kemitter, P, centroid, bcone.axis))
{
@ -414,15 +415,9 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
if (in_volume_segment) {
const float3 D = N_or_D;
/* Closest point. */
P_c = P + dot(centroid - P, D) * D;
/* Minimal distance of the ray to the cluster. */
distance.x = len(centroid - P_c);
distance.y = distance.x;
point_to_centroid = -compute_v(centroid, P, D, bcone.axis, t);
}
else {
P_c = P;
/* Closest point from ray to the emitter centroid. */
const float closest_t = clamp(dot(centroid - P, D), 0.0f, t);
P_c += D * closest_t;
}
/* Early out if the emitter is guaranteed to be invisible. */
@ -456,6 +451,9 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
case LIGHT_DISTANT:
is_visible = distant_light_tree_parameters(
centroid, bcone.theta_e, cos_theta_u, distance, point_to_centroid);
if (in_volume_segment) {
centroid = P - bcone.axis;
}
break;
default:
return;
@ -467,6 +465,11 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
return;
}
if (in_volume_segment) {
/* Vector that forms a minimal angle with the emitter centroid. */
point_to_centroid = -compute_v(centroid, P, N_or_D, bcone.axis, t);
}
light_tree_importance<in_volume_segment>(N_or_D,
has_transmission,
point_to_centroid,
@ -697,17 +700,16 @@ ccl_device int light_tree_root_node_index(KernelGlobals kg, const int object_rec
return 0;
}
/* Pick a random light from the light tree from a given shading point P, write to the picked light
* index and the probability of picking the light. */
template<bool in_volume_segment>
ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
const float3 rand,
const float time,
const float rand,
const float3 P,
float3 N_or_D,
float t,
const int object_receiver,
const int shader_flags,
const int bounce,
const uint32_t path_flag,
ccl_private LightSample *ls)
{
if (!kernel_data.integrator.use_direct_light) {
@ -718,10 +720,8 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
float pdf_leaf = 1.0f;
float pdf_selection = 1.0f;
int selected_emitter = -1;
int object_emitter = 0;
int node_index = light_tree_root_node_index(kg, object_receiver);
/* The first two dimensions of the Sobol sequence have better stratification. */
float rand_selection = rand.z;
float rand_selection = rand;
float3 local_P = P;
@ -743,7 +743,7 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
}
/* Continue with the picked mesh light. */
object_emitter = kernel_data_fetch(light_tree_emitters, selected_emitter).mesh.object_id;
ls->object = kernel_data_fetch(light_tree_emitters, selected_emitter).mesh.object_id;
continue;
}
@ -766,27 +766,18 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
pdf_leaf *= (node_index == left_index) ? left_prob : (1.0f - left_prob);
}
pdf_selection *= pdf_leaf;
ls->emitter_id = selected_emitter;
ls->pdf_selection = pdf_selection * pdf_leaf;
return light_sample<in_volume_segment>(kg,
float3_to_float2(rand),
time,
P,
N_or_D,
object_receiver,
shader_flags,
bounce,
path_flag,
selected_emitter,
object_emitter,
pdf_selection,
ls);
return true;
}
/* We need to be able to find the probability of selecting a given light for MIS. */
template<bool in_volume_segment>
ccl_device float light_tree_pdf(KernelGlobals kg,
float3 P,
float3 N,
const float dt,
const int path_flag,
const int object_emitter,
const uint index_emitter,
@ -796,7 +787,7 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
index_emitter);
int root_index;
int subtree_root_index;
uint bit_trail, target_emitter;
if (is_triangle(kemitter)) {
@ -805,16 +796,17 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
target_emitter = kernel_data_fetch(object_to_tree, object_emitter);
ccl_global const KernelLightTreeEmitter *kmesh = &kernel_data_fetch(light_tree_emitters,
target_emitter);
root_index = kmesh->mesh.node_id;
ccl_global const KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, root_index);
subtree_root_index = kmesh->mesh.node_id;
ccl_global const KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes,
subtree_root_index);
bit_trail = kroot->bit_trail;
if (kroot->type == LIGHT_TREE_INSTANCE) {
root_index = kroot->instance.reference;
subtree_root_index = kroot->instance.reference;
}
}
else {
root_index = 0;
subtree_root_index = -1;
bit_trail = kemitter->bit_trail;
target_emitter = index_emitter;
}
@ -836,8 +828,8 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
for (int i = 0; i < knode->num_emitters; i++) {
const int emitter = knode->leaf.first_emitter + i;
float max_importance, min_importance;
light_tree_emitter_importance<false>(
kg, P, N, 0, has_transmission, emitter, max_importance, min_importance);
light_tree_emitter_importance<in_volume_segment>(
kg, P, N, dt, has_transmission, emitter, max_importance, min_importance);
num_has_importance += (max_importance > 0);
if (emitter == target_emitter) {
target_max_importance = max_importance;
@ -856,13 +848,13 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
return 0.0f;
}
if (root_index) {
if (subtree_root_index != -1) {
/* Arrived at the mesh light. Continue with the subtree. */
float unused;
light_tree_to_local_space<false>(kg, object_emitter, P, N, unused);
light_tree_to_local_space<in_volume_segment>(kg, object_emitter, P, N, unused);
node_index = root_index;
root_index = 0;
node_index = subtree_root_index;
subtree_root_index = -1;
target_emitter = index_emitter;
bit_trail = kemitter->bit_trail;
continue;
@ -877,8 +869,8 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
const int right_index = knode->inner.right_child;
float left_prob;
if (!get_left_probability<false>(
kg, P, N, 0, has_transmission, left_index, right_index, left_prob))
if (!get_left_probability<in_volume_segment>(
kg, P, N, dt, has_transmission, left_index, right_index, left_prob))
{
return 0.0f;
}
@ -896,4 +888,27 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
}
}
/* If the function is called in volume, retrieve the previous point in volume segment, and compute
* pdf from there. Otherwise compute from the current shading point. */
ccl_device_inline float light_tree_pdf(KernelGlobals kg,
float3 P,
float3 N,
const float dt,
const int path_flag,
const int emitter_object,
const uint emitter_id,
const int object_receiver)
{
if (path_flag & PATH_RAY_VOLUME_SCATTER) {
const float3 D_times_t = N;
const float3 D = normalize(D_times_t);
P = P - D_times_t;
return light_tree_pdf<true>(
kg, P, D, dt, path_flag, emitter_object, emitter_id, object_receiver);
}
return light_tree_pdf<false>(
kg, P, N, 0.0f, path_flag, emitter_object, emitter_id, object_receiver);
}
CCL_NAMESPACE_END

View File

@ -269,6 +269,26 @@ ccl_device_forceinline bool triangle_light_sample(KernelGlobals kg,
return (ls->pdf > 0.0f);
}
/* Find the ray segment lit by the triangle light. */
ccl_device_inline bool triangle_light_valid_ray_segment(KernelGlobals kg,
const float3 P,
const float3 D,
ccl_private float2 *t_range,
const ccl_private LightSample *ls)
{
const int shader_flag = kernel_data_fetch(shaders, ls->shader & SHADER_MASK).flags;
const int SD_MIS_BOTH = SD_MIS_BACK | SD_MIS_FRONT;
if ((shader_flag & SD_MIS_BOTH) == SD_MIS_BOTH) {
/* Both sides are sampled, the complete ray segment is visible. */
return true;
}
/* Only one side is sampled, intersect the ray and the triangle light plane to find the visible
* ray segment. Flip normal if Emission Sampling is set to back. */
const float3 N = ls->Ng;
return ray_plane_intersect((shader_flag & SD_MIS_BACK) ? -N : N, P, D, t_range);
}
template<bool in_volume_segment>
ccl_device_forceinline bool triangle_light_tree_parameters(
KernelGlobals kg,
@ -281,13 +301,11 @@ ccl_device_forceinline bool triangle_light_tree_parameters(
ccl_private float2 &distance,
ccl_private float3 &point_to_centroid)
{
if (!in_volume_segment) {
/* TODO: a cheap substitute for minimal distance between point and primitive. Does it
* worth the overhead to compute the accurate minimal distance? */
float min_distance;
point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
distance = make_float2(min_distance, min_distance);
}
/* TODO: a cheap substitute for minimal distance between point and primitive. Does it worth the
* overhead to compute the accurate minimal distance? */
float min_distance;
point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
distance = make_float2(min_distance, min_distance);
cos_theta_u = FLT_MAX;
@ -307,9 +325,8 @@ ccl_device_forceinline bool triangle_light_tree_parameters(
}
const bool front_facing = bcone.theta_o != 0.0f || dot(bcone.axis, point_to_centroid) < 0;
const bool in_volume = is_zero(N);
return (front_facing && shape_above_surface) || in_volume;
return front_facing && shape_above_surface;
}
CCL_NAMESPACE_END

View File

@ -7,76 +7,82 @@
#define vector3 point
float safe_noise(float p)
float safe_noise(float co)
{
float f = noise("noise", p);
if (isinf(f)) {
return 0.5;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. */
float p = fmod(co, 100000.0);
return noise("noise", p);
}
float safe_noise(vector2 p)
float safe_noise(vector2 co)
{
float f = noise("noise", p.x, p.y);
if (isinf(f)) {
return 0.5;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector2 p = fmod(co, 100000.0);
return noise("noise", p.x, p.y);
}
float safe_noise(vector3 p)
float safe_noise(vector3 co)
{
float f = noise("noise", p);
if (isinf(f)) {
return 0.5;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector3 p = fmod(co, 100000.0);
return noise("noise", p);
}
float safe_noise(vector4 p)
float safe_noise(vector4 co)
{
float f = noise("noise", vector3(p.x, p.y, p.z), p.w);
if (isinf(f)) {
return 0.5;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector4 p = fmod(co, 100000.0);
return noise("noise", vector3(p.x, p.y, p.z), p.w);
}
float safe_snoise(float p)
float safe_snoise(float co)
{
float f = noise("snoise", p);
if (isinf(f)) {
return 0.0;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. */
float p = fmod(co, 100000.0);
return noise("snoise", p);
}
float safe_snoise(vector2 p)
float safe_snoise(vector2 co)
{
float f = noise("snoise", p.x, p.y);
if (isinf(f)) {
return 0.0;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector2 p = fmod(co, 100000.0);
return noise("snoise", p.x, p.y);
}
float safe_snoise(vector3 p)
float safe_snoise(vector3 co)
{
float f = noise("snoise", p);
if (isinf(f)) {
return 0.0;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector3 p = fmod(co, 100000.0);
return noise("snoise", p);
}
float safe_snoise(vector4 p)
float safe_snoise(vector4 co)
{
float f = noise("snoise", vector3(p.x, p.y, p.z), p.w);
if (isinf(f)) {
return 0.0;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector4 p = fmod(co, 100000.0);
return noise("snoise", vector3(p.x, p.y, p.z), p.w);
}
#define NOISE_FBM(T) \

View File

@ -684,7 +684,12 @@ ccl_device_inline float noise_scale4(float result)
ccl_device_inline float snoise_1d(float p)
{
return noise_scale1(ensure_finite(perlin_1d(p)));
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. */
/* The 1D variant of fmod is called fmodf. */
p = fmodf(p, 100000.0f);
return noise_scale1(perlin_1d(p));
}
ccl_device_inline float noise_1d(float p)
@ -694,7 +699,12 @@ ccl_device_inline float noise_1d(float p)
ccl_device_inline float snoise_2d(float2 p)
{
return noise_scale2(ensure_finite(perlin_2d(p.x, p.y)));
/* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0f, however at such scales
* this usually shouldn't be noticeable. */
p = fmod(p, 100000.0f);
return noise_scale2(perlin_2d(p.x, p.y));
}
ccl_device_inline float noise_2d(float2 p)
@ -704,7 +714,12 @@ ccl_device_inline float noise_2d(float2 p)
ccl_device_inline float snoise_3d(float3 p)
{
return noise_scale3(ensure_finite(perlin_3d(p.x, p.y, p.z)));
/* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0f, however at such scales
* this usually shouldn't be noticeable. */
p = fmod(p, 100000.0f);
return noise_scale3(perlin_3d(p.x, p.y, p.z));
}
ccl_device_inline float noise_3d(float3 p)
@ -714,7 +729,12 @@ ccl_device_inline float noise_3d(float3 p)
ccl_device_inline float snoise_4d(float4 p)
{
return noise_scale4(ensure_finite(perlin_4d(p.x, p.y, p.z, p.w)));
/* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0f, however at such scales
* this usually shouldn't be noticeable. */
p = fmod(p, 100000.0f);
return noise_scale4(perlin_4d(p.x, p.y, p.z, p.w));
}
ccl_device_inline float noise_4d(float4 p)

View File

@ -45,6 +45,7 @@ CCL_NAMESPACE_BEGIN
#define OBJECT_NONE (~0)
#define PRIM_NONE (~0)
#define LAMP_NONE (~0)
#define EMITTER_NONE (~0)
#define ID_NONE (0.0f)
#define PASS_UNUSED (~0)
#define LIGHTGROUP_NONE (~0)
@ -1376,6 +1377,8 @@ typedef struct KernelSpotLight {
int is_sphere;
/* For non-uniform object scaling, the actual spread might be different. */
float cos_half_larger_spread;
/* Distance from the apex of the smallest enclosing cone of the light spread to light center. */
float ray_segment_dp;
} KernelSpotLight;
/* PointLight is SpotLight with only radius and invarea being used. */

View File

@ -107,6 +107,7 @@ endif()
if(WITH_CYCLES_OSL)
list(APPEND LIB
cycles_kernel_osl
${OSL_LIBRARIES}
)
endif()

View File

@ -903,14 +903,14 @@ static void background_cdf(
for (int i = start; i < end; i++) {
float sin_theta = sinf(M_PI_F * (i + 0.5f) / res_y);
float3 env_color = (*pixels)[i * res_x];
float ave_luminance = average(env_color);
float ave_luminance = average(fabs(env_color));
cond_cdf[i * cdf_width].x = ave_luminance * sin_theta;
cond_cdf[i * cdf_width].y = 0.0f;
for (int j = 1; j < res_x; j++) {
env_color = (*pixels)[i * res_x + j];
ave_luminance = average(env_color);
ave_luminance = average(fabs(env_color));
cond_cdf[i * cdf_width + j].x = ave_luminance * sin_theta;
cond_cdf[i * cdf_width + j].y = cond_cdf[i * cdf_width + j - 1].y +
@ -1362,6 +1362,9 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce
/* Choose the angle which spans a larger cone. */
klights[light_index].spot.cos_half_larger_spread = inversesqrtf(
1.0f + tan_sq * fmaxf(len_u_sq, len_v_sq) / len_w_sq);
/* radius / sin(half_angle_small) */
klights[light_index].spot.ray_segment_dp =
light->size * sqrtf(1.0f + len_w_sq / (tan_sq * fminf(len_u_sq, len_v_sq)));
}
klights[light_index].shader_id = shader_id;

View File

@ -39,7 +39,7 @@ static std::atomic<uint64_t> g_instance_index = 0;
/* Construct names of EXR channels which will ensure order of all channels to match exact offsets
* in render buffers corresponding to the given passes.
*
* Returns `std` datatypes so that it can be assigned directly to the OIIO's `ImageSpec`. */
* Returns `std` data-types so that it can be assigned directly to the OIIO's `ImageSpec`. */
static std::vector<std::string> exr_channel_names_for_passes(const BufferParams &buffer_params)
{
static const char *component_suffixes[] = {"R", "G", "B", "A"};

View File

@ -275,8 +275,8 @@ ccl_device_inline float4 improve_5throot_solution_sse2(const float4 &old_result,
/* Calculate powf(x, 2.4). Working domain: 1e-10 < x < 1e+10 */
ccl_device_inline float4 fastpow24_sse2(const float4 &arg)
{
/* max, avg and |avg| errors were calculated in gcc without FMA instructions
* The final precision should be better than powf in glibc */
/* `max`, `avg` and |avg| errors were calculated in GCC without FMA instructions.
* The final precision should be better than `powf` in GLIBC. */
/* Calculate x^4/5, coefficient 0.994 was constructed manually to minimize avg error */
/* 0x3F4CCCCD = 4/5 */

View File

@ -1030,6 +1030,46 @@ ccl_device_inline uint32_t reverse_integer_bits(uint32_t x)
#endif
}
/* Check if intervals (first->x, first->y) and (second.x, second.y) intersect, and replace the
* first interval with their intersection. */
ccl_device_inline bool intervals_intersect(ccl_private float2 *first, const float2 second)
{
first->x = fmaxf(first->x, second.x);
first->y = fminf(first->y, second.y);
return first->x < first->y;
}
/* Solve quadratic equation a*x^2 + b*x + c = 0, adapted from Mitsuba 3
* The solution is ordered so that x1 <= x2.
* Returns true if at least one solution is found. */
ccl_device_inline bool solve_quadratic(
const float a, const float b, const float c, ccl_private float &x1, ccl_private float &x2)
{
/* If the equation is linear, the solution is -c/b, but b has to be non-zero. */
const bool valid_linear = (a == 0.0f) && (b != 0.0f);
x1 = x2 = -c / b;
const float discriminant = sqr(b) - 4.0f * a * c;
/* Allow slightly negative discriminant in case of numerical precision issues. */
const bool valid_quadratic = (a != 0.0f) && (discriminant > -1e-5f);
if (valid_quadratic) {
/* Numerically stable version of (-b ± sqrt(discriminant)) / (2 * a), avoiding catastrophic
* cancellation when `b` is very close to `sqrt(discriminant)`, by finding the solution of
* greater magnitude which does not suffer from loss of precision, then using the identity
* x1 * x2 = c / a. */
const float temp = -0.5f * (b + copysignf(safe_sqrtf(discriminant), b));
const float r1 = temp / a;
const float r2 = c / temp;
x1 = fminf(r1, r2);
x2 = fmaxf(r1, r2);
}
return (valid_linear || valid_quadratic);
}
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_H__ */

View File

@ -198,6 +198,11 @@ ccl_device_inline float2 clamp(const float2 a, const float2 mn, const float2 mx)
return min(max(a, mn), mx);
}
ccl_device_inline float2 fmod(const float2 a, const float b)
{
return make_float2(fmodf(a.x, b), fmodf(a.y, b));
}
ccl_device_inline float2 fabs(const float2 a)
{
return make_float2(fabsf(a.x), fabsf(a.y));

View File

@ -309,6 +309,11 @@ ccl_device_inline float3 fabs(const float3 a)
# endif
}
ccl_device_inline float3 fmod(const float3 a, const float b)
{
return make_float3(fmodf(a.x, b), fmodf(a.y, b), fmodf(a.z, b));
}
ccl_device_inline float3 sqrt(const float3 a)
{
# ifdef __KERNEL_SSE__

View File

@ -465,6 +465,11 @@ ccl_device_inline float4 fabs(const float4 a)
# endif
}
ccl_device_inline float4 fmod(const float4 a, const float b)
{
return make_float4(fmodf(a.x, b), fmodf(a.y, b), fmodf(a.z, b), fmodf(a.w, b));
}
ccl_device_inline float4 floor(const float4 a)
{
# ifdef __KERNEL_SSE__

View File

@ -302,6 +302,140 @@ ccl_device bool ray_quad_intersect(float3 ray_P,
return true;
}
/* Find the ray segment that lies in the same side as the normal `N` of the plane.
* `P` is the vector pointing from any point on the plane to the ray origin. */
ccl_device bool ray_plane_intersect(const float3 N,
const float3 P,
const float3 ray_D,
ccl_private float2 *t_range)
{
const float DN = dot(ray_D, N);
/* Distance from P to the plane. */
const float t = -dot(P, N) / DN;
/* Limit the range to the positive side. */
if (DN > 0.0f) {
t_range->x = fmaxf(t_range->x, t);
}
else {
t_range->y = fminf(t_range->y, t);
}
return t_range->x < t_range->y;
}
/* Find the ray segment inside an axis-aligned bounding box. */
ccl_device bool ray_aabb_intersect(const float3 bbox_min,
const float3 bbox_max,
const float3 ray_P,
const float3 ray_D,
ccl_private float2 *t_range)
{
const float3 inv_ray_D = rcp(ray_D);
/* Absolute distances to lower and upper box coordinates; */
const float3 t_lower = (bbox_min - ray_P) * inv_ray_D;
const float3 t_upper = (bbox_max - ray_P) * inv_ray_D;
/* The four t-intervals (for x-/y-/z-slabs, and ray p(t)). */
const float4 tmins = float3_to_float4(min(t_lower, t_upper), t_range->x);
const float4 tmaxes = float3_to_float4(max(t_lower, t_upper), t_range->y);
/* Max of mins and min of maxes. */
const float tmin = reduce_max(tmins);
const float tmax = reduce_min(tmaxes);
*t_range = make_float2(tmin, tmax);
return tmin < tmax;
}
/* Find the segment of a ray defined by P + D * t that lies inside a cylinder defined by
* (x / len_u)^2 + (y / len_v)^2 = 1. */
ccl_device_inline bool ray_infinite_cylinder_intersect(const float3 P,
const float3 D,
const float len_u,
const float len_v,
ccl_private float2 *t_range)
{
/* Convert to a 2D problem. */
const float2 inv_len = 1.0f / make_float2(len_u, len_v);
float2 P_proj = float3_to_float2(P) * inv_len;
const float2 D_proj = float3_to_float2(D) * inv_len;
/* Solve quadratic equation a*t^2 + 2b*t + c = 0. */
const float a = dot(D_proj, D_proj);
float b = dot(P_proj, D_proj);
/* Move ray origin closer to the cylinder to prevent precision issue when the ray is far away. */
const float t_mid = -b / a;
P_proj += D_proj * t_mid;
/* Recompute b from the shifted origin. */
b = dot(P_proj, D_proj);
const float c = dot(P_proj, P_proj) - 1.0f;
float tmin, tmax;
const bool valid = solve_quadratic(a, 2.0f * b, c, tmin, tmax);
return valid && intervals_intersect(t_range, make_float2(tmin, tmax) + t_mid);
}
/* *
* Find the ray segment inside a single-sided cone.
*
* \param axis: a unit-length direction around which the cone has a circular symmetry
* \param P: the vector pointing from the cone apex to the ray origin
* \param D: the direction of the ray, does not need to have unit-length
* \param cos_angle_sq: `sqr(cos(half_aperture_of_the_cone))`
* \param t_range: the lower and upper bounds between which the ray lies inside the cone
* \return whether the intersection exists and is in the provided range
*
* See https://www.geometrictools.com/Documentation/IntersectionLineCone.pdf for illustration
*/
ccl_device_inline bool ray_cone_intersect(const float3 axis,
const float3 P,
float3 D,
const float cos_angle_sq,
ccl_private float2 *t_range)
{
if (cos_angle_sq < 1e-4f) {
/* The cone is nearly a plane. */
return ray_plane_intersect(axis, P, D, t_range);
}
const float inv_len = inversesqrtf(len_squared(D));
D *= inv_len;
const float AD = dot(axis, D);
const float AP = dot(axis, P);
const float a = sqr(AD) - cos_angle_sq;
const float b = 2.0f * (AD * AP - cos_angle_sq * dot(D, P));
const float c = sqr(AP) - cos_angle_sq * dot(P, P);
float tmin = 0.0f, tmax = FLT_MAX;
bool valid = solve_quadratic(a, b, c, tmin, tmax);
/* Check if the intersections are in the same hemisphere as the cone. */
const bool tmin_valid = AP + tmin * AD > 0.0f;
const bool tmax_valid = AP + tmax * AD > 0.0f;
valid &= (tmin_valid || tmax_valid);
if (!tmax_valid) {
tmax = tmin;
tmin = 0.0f;
}
else if (!tmin_valid) {
tmin = tmax;
tmax = FLT_MAX;
}
return valid && intervals_intersect(t_range, make_float2(tmin, tmax) * inv_len);
}
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_INTERSECT_H__ */

View File

@ -14,7 +14,7 @@ CCL_NAMESPACE_BEGIN
thread::thread(function<void()> run_cb) : run_cb_(run_cb), joined_(false)
{
#if defined(__APPLE__) || defined(__linux__) && !defined(__GLIBC__)
/* Set the stack size to 2MB to match glibc. The default 512KB on macOS is
/* Set the stack size to 2MB to match GLIBC. The default 512KB on macOS is
* too small for Embree, and consistent stack size also makes things more
* predictable in general. */
pthread_attr_t attribute;

View File

@ -161,6 +161,17 @@ ccl_device_inline Transform make_transform(float a,
return t;
}
ccl_device_inline Transform make_transform(const float3 x, const float3 y, const float3 z)
{
Transform t;
t.x = float3_to_float4(x, 0.0f);
t.y = float3_to_float4(y, 0.0f);
t.z = float3_to_float4(z, 0.0f);
return t;
}
ccl_device_inline Transform euler_to_transform(const float3 euler)
{
float cx = cosf(euler.x);

View File

@ -10,10 +10,6 @@
#include "GHOST_Types.h"
#ifdef __cplusplus
extern "C" {
#endif
GHOST_DECLARE_HANDLE(GHOST_SystemPathsHandle);
/**
@ -63,7 +59,3 @@ extern const char *GHOST_getBinaryDir();
* Add the file to the operating system most recently used files
*/
extern void GHOST_addToSystemRecentFiles(const char *filepath);
#ifdef __cplusplus
}
#endif

View File

@ -427,7 +427,7 @@ struct GWL_Cursor {
/**
* The name of the theme (set by an environment variable).
* When disabled, leave as an empty string and the default theme will be used.
* When disabled, leave as an empty string and pass in nullptr to use the default theme.
*/
std::string theme_name;
/**
@ -2507,7 +2507,9 @@ static const wl_cursor *gwl_seat_cursor_find_from_shape(GWL_Seat *seat,
if (!cursor->wl.theme) {
/* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */
cursor->wl.theme = wl_cursor_theme_load(
cursor->theme_name.c_str(), cursor->theme_size, seat->system->wl_shm_get());
(cursor->theme_name.empty() ? nullptr : cursor->theme_name.c_str()),
cursor->theme_size,
seat->system->wl_shm_get());
}
if (cursor->wl.theme) {
@ -3521,7 +3523,9 @@ static bool update_cursor_scale(GWL_Cursor &cursor,
}
wl_cursor_theme_destroy(cursor.wl.theme);
cursor.wl.theme = wl_cursor_theme_load(
cursor.theme_name.c_str(), scale * cursor.theme_size, shm);
(cursor.theme_name.empty() ? nullptr : cursor.theme_name.c_str()),
scale * cursor.theme_size,
shm);
if (cursor.wl.theme_cursor) {
cursor.wl.theme_cursor = wl_cursor_theme_get_cursor(cursor.wl.theme,
cursor.wl.theme_cursor_name);

View File

@ -8,15 +8,13 @@
#pragma once
#ifdef __cplusplus
# undef wl_array_for_each
#undef wl_array_for_each
/**
* This macro causes a warning for C++ code, define our own.
* See: https://gitlab.freedesktop.org/wayland/wayland/-/issues/34
*/
# define WL_ARRAY_FOR_EACH(pos, array) \
for (pos = (decltype(pos))((array)->data); \
reinterpret_cast<const char *>(pos) < \
(reinterpret_cast<const char *>((array)->data) + (array)->size); \
(pos)++)
#endif
#define WL_ARRAY_FOR_EACH(pos, array) \
for (pos = (decltype(pos))((array)->data); \
reinterpret_cast<const char *>(pos) < \
(reinterpret_cast<const char *>((array)->data) + (array)->size); \
(pos)++)

View File

@ -1879,6 +1879,23 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
xdg_toplevel *toplevel = libdecor_frame_get_xdg_toplevel(decor.frame);
gwl_window_state_set_for_xdg(toplevel, state, gwl_window_state_get(window_));
/* NOTE(@ideasman42): Round trips are necessary with LIBDECOR on GNOME
* because resizing later on and redrawing does *not* update as it should, see #119871.
*
* Without the round-trip here:
* - The window will be created and this function will return using the requested buffer size,
* instead of the window size which ends up being used (causing a visible flicker).
* This has the down side that Blender's internal window state has the outdated size
* which then gets immediately resized, causing a noticeable glitch.
* - The window decorations will be displayed at the wrong size before refreshing
* at the new size.
* - On GNOME-Shell 46 shows the previous buffer-size under some conditions.
*
* In principle this could be used with XDG too however it causes problems with KDE
* and some WLROOTS based compositors.
*/
wl_display_roundtrip(system_->wl_display_get());
}
else
#endif /* WITH_GHOST_WAYLAND_LIBDECOR */

View File

@ -40,9 +40,9 @@
#include "WindowData.h"
/* GPU API. */
#include "GPU_context.h"
#include "GPU_immediate.h"
#include "GPU_init_exit.h"
#include "GPU_context.hh"
#include "GPU_immediate.hh"
#include "GPU_init_exit.hh"
extern int datatoc_bfont_ttf_size;
extern char const datatoc_bfont_ttf[];

View File

@ -115,10 +115,10 @@ void *MEM_lockfree_dupallocN(const void *vmemh)
{
void *newp = NULL;
if (vmemh) {
MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
const MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
const size_t prev_size = MEM_lockfree_allocN_len(vmemh);
if (UNLIKELY(MEMHEAD_IS_ALIGNED(memh))) {
MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
const MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
newp = MEM_lockfree_mallocN_aligned(
prev_size, (size_t)memh_aligned->alignment, "dupli_malloc");
}
@ -135,14 +135,14 @@ void *MEM_lockfree_reallocN_id(void *vmemh, size_t len, const char *str)
void *newp = NULL;
if (vmemh) {
MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
size_t old_len = MEM_lockfree_allocN_len(vmemh);
const MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
const size_t old_len = MEM_lockfree_allocN_len(vmemh);
if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) {
newp = MEM_lockfree_mallocN(len, "realloc");
}
else {
MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
const MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
newp = MEM_lockfree_mallocN_aligned(len, (size_t)memh_aligned->alignment, "realloc");
}
@ -171,14 +171,14 @@ void *MEM_lockfree_recallocN_id(void *vmemh, size_t len, const char *str)
void *newp = NULL;
if (vmemh) {
MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
size_t old_len = MEM_lockfree_allocN_len(vmemh);
const MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
const size_t old_len = MEM_lockfree_allocN_len(vmemh);
if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) {
newp = MEM_lockfree_mallocN(len, "recalloc");
}
else {
MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
const MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
newp = MEM_lockfree_mallocN_aligned(len, (size_t)memh_aligned->alignment, "recalloc");
}

View File

@ -19,8 +19,8 @@
# pragma warning(pop)
#endif
#include "GPU_immediate.h"
#include "GPU_shader.h"
#include "GPU_immediate.hh"
#include "GPU_shader.hh"
#include "GPU_uniform_buffer.hh"
#include "gpu_shader_create_info.hh"
@ -512,8 +512,8 @@ static void updateGPUCurveMapping(OCIO_GPUCurveMappping &curvemap,
curvemap.cache_id = curve_mapping_settings->cache_id;
/* Update texture. */
int offset[3] = {0, 0, 0};
int extent[3] = {curve_mapping_settings->lut_size, 0, 0};
const int offset[3] = {0, 0, 0};
const int extent[3] = {curve_mapping_settings->lut_size, 0, 0};
const float *pixels = curve_mapping_settings->lut;
GPU_texture_update_sub(
curvemap.texture, GPU_DATA_FLOAT, pixels, UNPACK3(offset), UNPACK3(extent));

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef GPU_SHADER
# include "GPU_shader_shared_utils.h"
# include "GPU_shader_shared_utils.hh"
#endif
struct OCIO_GPUCurveMappingParameters {

View File

@ -60,17 +60,17 @@ TEST(MeshTopology, TrivialFaceTopology)
EXPECT_EQ(mesh_topology.getNumFaceVertices(2), 5);
{
int vertex_indices[] = {0, 1, 2, 3};
const int vertex_indices[] = {0, 1, 2, 3};
mesh_topology.setFaceVertexIndices(0, 4, vertex_indices);
}
{
int vertex_indices[] = {4, 5, 6};
const int vertex_indices[] = {4, 5, 6};
mesh_topology.setFaceVertexIndices(1, 3, vertex_indices);
}
{
int vertex_indices[] = {7, 8, 9, 10, 11};
const int vertex_indices[] = {7, 8, 9, 10, 11};
mesh_topology.setFaceVertexIndices(2, 5, vertex_indices);
}

View File

@ -18,7 +18,7 @@ extern "C" {
* Currently, this API is optimized for Bullet RigidBodies, and doesn't
* take into account other Physics Engines. Some tweaking may be necessary
* to allow other systems to be used, in particular there may be references
* to datatypes that aren't used here...
* to data-types that aren't used here...
*
* -- Joshua Leung (22 June 2010)
*/
@ -210,7 +210,7 @@ rbCollisionShape *RB_shape_new_cylinder(float radius, float height);
/* Setup (Convex Hull) ------------ */
rbCollisionShape *RB_shape_new_convex_hull(
float *verts, int stride, int count, float margin, bool *can_embed);
const float *verts, int stride, int count, float margin, bool *can_embed);
/* Setup (Triangle Mesh) ---------- */
@ -244,7 +244,7 @@ float RB_shape_get_margin(rbCollisionShape *shape);
void RB_shape_set_margin(rbCollisionShape *shape, float value);
void RB_shape_trimesh_update(rbCollisionShape *shape,
float *vertices,
const float *vertices,
int num_verts,
int vert_stride,
const float min[3],

View File

@ -712,7 +712,7 @@ rbCollisionShape *RB_shape_new_cylinder(float radius, float height)
/* Setup (Convex Hull) ------------ */
rbCollisionShape *RB_shape_new_convex_hull(
float *verts, int stride, int count, float margin, bool *can_embed)
const float *verts, int stride, int count, float margin, bool *can_embed)
{
btConvexHullComputer hull_computer = btConvexHullComputer();
@ -800,7 +800,7 @@ rbCollisionShape *RB_shape_new_trimesh(rbMeshData *mesh)
}
void RB_shape_trimesh_update(rbCollisionShape *shape,
float *vertices,
const float *vertices,
int num_verts,
int vert_stride,
const float min[3],

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"\"POT-Creation-Date: 2019-02-25 20:41:30\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2016-04-23 22:41+0300\n"
@ -2023,18 +2023,6 @@ msgid "Vertex Color"
msgstr "ﺔﻄﻘﻨﻟﺍ ﻥﻮﻟ"
msgid "Direction"
msgstr "ﻩﺎﺠﺗﺇ"
msgid "Add effect of brush"
msgstr "ﺓﺎﺷﺮﻔﻟﺍ ﺮﺛﺆﻣ ﻒﺿﺍ"
msgid "Subtract effect of brush"
msgstr "ﺓﺎﺷﺮﻔﻟﺍ ﺮﻴﺛﺄﺗ ﺡﺮﻃﺍ"
msgid "Dissolve"
msgstr "ﻞﻠﺤﺘﻟﺍ"
@ -2043,6 +2031,10 @@ msgid "Stroke"
msgstr "ﺔﺒﻄﺷ"
msgid "Direction"
msgstr "ﻩﺎﺠﺗﺇ"
msgid "Normal"
msgstr "ﻢﻇﺎﻧ"
@ -9276,6 +9268,14 @@ msgid "Editable falloff curve"
msgstr "ﺮﻳﺮﺤﺘﻠﻟ ﻞﺑﺎﻗ ﻁﻮﻘﺳ ﻰﻨﺤﻨﻣ"
msgid "Add effect of brush"
msgstr "ﺓﺎﺷﺮﻔﻟﺍ ﺮﺛﺆﻣ ﻒﺿﺍ"
msgid "Subtract effect of brush"
msgstr "ﺓﺎﺷﺮﻔﻟﺍ ﺮﻴﺛﺄﺗ ﺡﺮﻃﺍ"
msgid "Fill Threshold"
msgstr "ﺔﺌﺒﻌﺘﻟﺍ ﺔﺒﺘﻋ"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-02-23 23:56+0000\n"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2023-09-26 10:37+0000\n"

View File

@ -1,10 +1,10 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-03-12 05:27+0000\n"
"PO-Revision-Date: 2024-03-24 20:56+0000\n"
"Last-Translator: Joan Pujolar <joan.pujolar@gmail.com>\n"
"Language-Team: Catalan <https://translate.blender.org/projects/blender-ui/ui/ca/>\n"
"Language: ca\n"
@ -403,6 +403,10 @@ msgid "Displays glTF UI to manage material variants"
msgstr "Mostra la IU de glTF per gestionar variants de materials"
msgid "Allow glTF Embedded format"
msgstr "Permetre format incrustat gITF"
msgid "Display glTF UI to manage animations"
msgstr "Mostrar la IU de glTF per gestionar animacions"
@ -4464,18 +4468,6 @@ msgid "Number of pixels to expand or contract fill area"
msgstr "[Dilate/Contract]: Nombre de píxels per expandir o contraure l'àrea d'emplenament"
msgid "Direction"
msgstr "Direcció"
msgid "Add effect of brush"
msgstr "Sumar efecte de pinzell"
msgid "Subtract effect of brush"
msgstr "Restar efecte de pinzell"
msgid "Eraser Mode"
msgstr "Mode esborrar"
@ -4524,6 +4516,10 @@ msgid "Strokes end extension for closing gaps, use zero to disable"
msgstr "[Closure Size]: Extensió final dels traços per a tancar buits, posar zero per a desactivar"
msgid "Direction"
msgstr "Direcció"
msgid "Direction of the fill"
msgstr "Direcció de l'emplenat"
@ -20581,6 +20577,14 @@ msgid "Amount of random elements that are going to be affected by the brush"
msgstr "Quantitat d'elements aleatoris que es veuran afectats pel pinzell"
msgid "Add effect of brush"
msgstr "Sumar efecte de pinzell"
msgid "Subtract effect of brush"
msgstr "Restar efecte de pinzell"
msgid "Max Element Distance"
msgstr "Distància màxima d'element"
@ -21921,7 +21925,7 @@ msgstr "Usar pressió per a mescla d'impregnació"
msgid "Use pressure to modulate wet mix"
msgstr "[Use Pressure for Wet Mix]: Utilitza la pressió per a modular la mescla humida"
msgstr "[Use Pressure for Wet Mix]: Utilitza la pressió per a modular la mescla d'impregnació"
msgid "Use Pressure for Wet Persistence"
@ -33889,7 +33893,7 @@ msgstr "[Keying set paths]: Col·lecció de camins de jocs d'atributs de fites"
msgid "Active Keying Set"
msgstr "Jocs de fitoatributs actiu"
msgstr "Joc de fitoatributs actiu"
msgid "Active Keying Set used to insert/delete keyframes"
@ -35481,7 +35485,7 @@ msgstr "Especials de rastreig de translació"
msgid "Rotation Track Specials"
msgstr "Especials de rastreig de rotacació"
msgstr "Especials de rastreig de rotació"
msgid "Track"
@ -53481,7 +53485,7 @@ msgstr "Aplica escala de solució"
msgid "Apply scale on solution itself to make distance between selected tracks equals to desired"
msgstr "[Apply Solution Scale]: Aplica l'escala sobre la solució mateixa per fer que la distància entre les rastres seleccionats sigui igual a la desitjada"
msgstr "[Apply Solution Scale]: Aplica l'escala sobre la solució mateixa per fer que la distància entre els rastres seleccionats sigui igual a la desitjada"
msgid "Distance between selected tracks"
@ -57346,7 +57350,7 @@ msgstr "Restablir morfofites entre accions"
msgid "Reset shape keys between each action exported. This is needed when some SK channels are not keyed on some animations"
msgstr "Reestableix la morfofites entre cada acció exportada. Es fa necessari quan alguns canals SK no tenen fites en algunes animacions"
msgstr "Reestableix la morfofites entre cada acció exportada. Es fa necessari quan alguns canals de MF no tinguin fites en algunes animacions"
msgid "Shape Key Tangents"
@ -90670,6 +90674,10 @@ msgid "Temporary Directory"
msgstr "Directori temporal"
msgid "The directory for storing temporary save files. The path must reference an existing directory or it will be ignored"
msgstr "Directori per emmagatzamar documents guardats temporals. La ruta ha de referir-se a un directori concret o s'ignorarà"
msgid ""
"Command to launch the text editor, either a full path or a command in $PATH.\n"
"Use the internal editor when left blank"
@ -106021,7 +106029,7 @@ msgstr "Ganxo USD"
msgid "Defines callback functions to extend USD IO"
msgstr "Defineix les funcions de reinvocació per estendre a E/E d'USD"
msgstr "Defineix les funcions de reinvocació per estendre a IE d'USD"
msgid "A short description of the USD hook"
@ -111250,6 +111258,11 @@ msgid "Mesh Filter Modal Map"
msgstr "Mapa modal de filtre de malla"
msgctxt "Operator"
msgid "DEM data (.hgt) as Mesh and/or Image"
msgstr "Dades DEM (.hgt) as com a malla i/o imatge"
msgid "You have been logged out"
msgstr "Ha expirat la teva sessió d'usuari"
@ -111842,6 +111855,10 @@ msgid "Path to gltfpack"
msgstr "Ruta a gltfpack"
msgid "This is the least efficient of the available forms, and should only be used when required."
msgstr "Aquesta és la forma menys eficient de les disponibles, i només s'hauria d'emprar quan cal."
msgid "Export only deformation bones is not possible when not sampling animation"
msgstr "Exportar només ossos de deformació no és possible quan no es mostreja l'animació"
@ -114606,14 +114623,6 @@ msgid "Caps Type"
msgstr "Tipus d'extrems"
msgid "CCW"
msgstr "SAH"
msgid "CW"
msgstr "SH"
msgid "Invert to Fill"
msgstr "Invertir per emplenar"
@ -120848,6 +120857,18 @@ msgid "armatures"
msgstr "esquelets"
msgid "Unable to create builtin attribute in edit mode"
msgstr "No s'ha pogut crear atribut de fàbrica en mode edició"
msgid "Domain unsupported for \"id\" attribute"
msgstr "Domini no admès com a atribut \"id\""
msgid "Type unsupported for \"id\" attribute"
msgstr "Tipus no admès per a atribut \"id\""
msgid "Attribute name cannot be empty"
msgstr "El nom de l'atribut no pot quedar buit"
@ -121362,18 +121383,6 @@ msgid "Auto Smooth"
msgstr "Autosuavitzar"
msgid "Socket_1"
msgstr "Born_1"
msgid "Input_1_use_attribute"
msgstr "Input_1_use_attribute"
msgid "Input_1_attribute_name"
msgstr "Input_1_attribute_name"
msgid "Tangent space can only be computed for tris/quads, aborting"
msgstr "L'espai tangencial només es pot calcular per a tris/quads, avortant"
@ -122455,6 +122464,10 @@ msgid "Cannot create the Animation Context"
msgstr "No es pot crear el Context d'animació"
msgid "One or more F-Curves are not visible due to filter settings"
msgstr "Una o més corbes-F no són visibles degut al filtre"
msgid "F-Curves have no valid size"
msgstr "Les corbes-F no tenen una dimensió vàlida"
@ -122793,10 +122806,6 @@ msgid "No object found to operate on"
msgstr "No s'ha trobat cap objecte amb què operar"
msgid "Bone collections can only be added to an Armature"
msgstr "Les col·leccions d'ossos només es poden afegir a un esquelet"
msgid "Cannot add bone collections to a linked Armature without an override"
msgstr "No es poden afegir col·leccions d'ossos a una esquelet vinculat sense un sobreseïment"
@ -122805,10 +122814,6 @@ msgid "Cannot add bone collections to a linked Armature with a system override;
msgstr "No es poden afegir col·leccions d'ossos a un esquelet enllaçat amb un sobreseïment de sistema; creeu explícitament un sobreseïment en l'esquelet"
msgid "Bone collections can only be edited on an Armature"
msgstr "Les col·leccions d'ossos només es poden editar en un esquelet"
msgid "Cannot update a linked Armature with a system override; explicitly create an override on the Armature"
msgstr "No es pot actualitzar un esquelet enllaçat amb un sobreseïment de sistema; creeu explícitament un sobreseïment en l'esquelket"
@ -122821,6 +122826,10 @@ msgid "Cannot edit bone collections that are linked from another blend file"
msgstr "No es poden editar col·leccions d'ossos vinculades a un altre document blend"
msgid "Bone collections can only be edited on an Armature"
msgstr "Les col·leccions d'ossos només es poden editar en un esquelet"
msgid "Cannot edit bone collections on linked Armatures without override"
msgstr "No es poden editar les col·leccions d'ossos d'esquelets vinculats sense sobreseure"
@ -123398,6 +123407,10 @@ msgid "Data-block inputs are unsupported"
msgstr "Ingressions de blocs de dades no compatibles"
msgid "Node group's first output must be a geometry"
msgstr "La primera egressió del grup de nodes ha de ser una geometria"
msgid "Annotation Create Poly: LMB click to place next stroke vertex | ESC/Enter to end (or click outside this area)"
msgstr "Anotació - Crear polígons: clicar BER per a col·locar el vèrtex següent del traç | ESC/Retorn per a finalitzar (o clicar fora de l'àrea)"
@ -133389,10 +133402,6 @@ msgid "Node group must have an output socket"
msgstr "El grup de nodes ha de tenir un born de sortida"
msgid "Node group's first output must be a geometry"
msgstr "La primera egressió del grup de nodes ha de ser una geometria"
msgid "NormalEdit"
msgstr "Edició de normals (NormalEdit)"
@ -137344,7 +137353,7 @@ msgstr "Format FBX"
msgid "FBX IO meshes, UVs, vertex colors, materials, textures, cameras, lamps and actions"
msgstr "Malles IO FBX, UV's, colors de vèrtex, materials, textures, càmeres, llums i accions"
msgstr "Malles IE FBX, UV's, colors de vèrtex, materials, textures, càmeres, llums i accions"
msgid "Import Images as Planes"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2023-12-12 02:28+0000\n"
@ -2887,18 +2887,6 @@ msgid "Curve used for the strength"
msgstr "Křivka použitá pro pevnost"
msgid "Direction"
msgstr "Směr"
msgid "Add effect of brush"
msgstr "Přidat efekt štětce"
msgid "Subtract effect of brush"
msgstr "Odečtení efektu štětce"
msgid "Eraser Mode"
msgstr "Režim gumy"
@ -2923,6 +2911,10 @@ msgid "Affect Stroke Thickness"
msgstr "Ovlivnit Tloušťku Tahu"
msgid "Direction"
msgstr "Směr"
msgid "Normal"
msgstr "Normála"
@ -8840,6 +8832,14 @@ msgid "Editable falloff curve"
msgstr "Křivka útlumu"
msgid "Add effect of brush"
msgstr "Přidat efekt štětce"
msgid "Subtract effect of brush"
msgstr "Odečtení efektu štětce"
msgid "Falloff Angle"
msgstr "Úhel Poklesu"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2023-11-06 03:54+0000\n"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: \n"
@ -3603,18 +3603,6 @@ msgid "Curve used for the strength"
msgstr "Kurve verwendet für die Stärke"
msgid "Direction"
msgstr "Richtung"
msgid "Add effect of brush"
msgstr "Hinzufügen-Effekt des Pinsels"
msgid "Subtract effect of brush"
msgstr "Abziehen-Effekt des Pinsels"
msgid "Eraser Mode"
msgstr "Radiermodus"
@ -3659,6 +3647,10 @@ msgid "Strokes end extension for closing gaps, use zero to disable"
msgstr "Striche Enderweiterung zum Schließen von Lücken, verwenden Sie Null zum deaktivieren"
msgid "Direction"
msgstr "Richtung"
msgid "Direction of the fill"
msgstr "Richtung der Füllung"
@ -12965,6 +12957,14 @@ msgid "Brush deforms the mesh by deforming the constraints of a cloth simulation
msgstr "Pinsel deformiert die Schleife indem eine Deformation, der Bedingung, einer Gewebesimulation durchgeführt wird"
msgid "Add effect of brush"
msgstr "Hinzufügen-Effekt des Pinsels"
msgid "Subtract effect of brush"
msgstr "Abziehen-Effekt des Pinsels"
msgid "Max Element Distance"
msgstr "Max. Elementabstand"
@ -54328,14 +54328,6 @@ msgid "Mask Value"
msgstr "Maskiere Wert"
msgid "CCW"
msgstr "CCW"
msgid "CW"
msgstr "CW"
msgid "Invert to Fill"
msgstr "Zum füllen invertieren"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2008-03-23 12:20+0200\n"

View File

@ -1,18 +1,50 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-03-25 00:51+0000\n"
"Last-Translator: william sélifet <williamselifet@live.be>\n"
"Language-Team: Esperanto <https://translate.blender.org/projects/blender-ui/ui/eo/>\n"
"Language: eo\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.0.1"
msgid "Name"
msgstr "Nomo"
msgid "Select"
msgstr "Elektas"
msgstr "Elektu"
msgid "Add"
msgstr "Aldonia"
msgid "Cache Files"
msgstr "Kaŝdosiero"
msgid "Deflectors"
msgstr "Deflekta"
msgid "Angular"
msgstr "Angula"
msgid "View"
msgstr "Rigardi"
msgid "Render"
msgstr "Por Kapitulacigi"
msgstr "Redoni"
msgid "Window"
@ -23,6 +55,14 @@ msgid "Edit Mode"
msgstr "Prilaborado Modo"
msgid "F-Curves"
msgstr "F-Kurbecoj"
msgid "B-Bone"
msgstr "B-osto"
msgid "Links"
msgstr "Ligiloj"
@ -35,6 +75,10 @@ msgid "Sculpt Mode"
msgstr "Skulptaĵo Modo"
msgid "Attribute"
msgstr "Atributo"
msgid "File"
msgstr "Dosiero"
@ -49,7 +93,11 @@ msgstr "Nova"
msgctxt "Operator"
msgid "Select"
msgstr "Elektas"
msgstr "Elektu"
msgid "Handles"
msgstr "Manpreni"
msgid "View Z Axis"
@ -62,7 +110,7 @@ msgstr "Montri X Axis"
msgctxt "Operator"
msgid "Render"
msgstr "Por Kapitulacigi"
msgstr "Redoni"
msgctxt "Operator"

View File

@ -1,10 +1,10 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-03-12 05:27+0000\n"
"PO-Revision-Date: 2024-03-24 20:56+0000\n"
"Last-Translator: Gabriel Gazzán <gabcorreo@gmail.com>\n"
"Language-Team: Spanish <https://translate.blender.org/projects/blender-ui/ui/es/>\n"
"Language: es\n"
@ -403,6 +403,10 @@ msgid "Displays glTF UI to manage material variants"
msgstr "Muestra la interfaz de glTF para administrar variantes de materiales"
msgid "Allow glTF Embedded format"
msgstr "Permitir formato glTF incorporado"
msgid "Display glTF UI to manage animations"
msgstr "Muestra la interfaz de glTF para administrar animaciones"
@ -4464,18 +4468,6 @@ msgid "Number of pixels to expand or contract fill area"
msgstr "Cantidad de píxeles a expandir o contraer el relleno del área"
msgid "Direction"
msgstr "Dirección"
msgid "Add effect of brush"
msgstr "Adiciona el efecto del pincel"
msgid "Subtract effect of brush"
msgstr "Sustrae el efecto del pincel"
msgid "Eraser Mode"
msgstr "Modo de borrar"
@ -4524,6 +4516,10 @@ msgid "Strokes end extension for closing gaps, use zero to disable"
msgstr "Extensión del extremo de los trazos para cerrar huecos, 0 para deshabilitar"
msgid "Direction"
msgstr "Dirección"
msgid "Direction of the fill"
msgstr "Dirección del relleno"
@ -6465,11 +6461,11 @@ msgstr "Codificación de imagen básica de AgX para un dispositivo sRGB"
msgid "AgX Log"
msgstr "AgX logarítmico"
msgstr "AgX logarítmica"
msgid "Log Encoding with Chroma inset and rotation, and with 25 Stops of Dynamic Range"
msgstr "Codificación logarítmica con inserción y rotación de croma, con un rango dinámico de 25 paradas"
msgstr "Codificación logarítmica con desplazamiento y rotación de croma, con un rango dinámico de 25 paradas"
msgid "Display P3"
@ -6621,7 +6617,7 @@ msgstr "Transformación adicional aplicada con fines artísticos, antes de la tr
msgid "Do not modify image in an artistic manner"
msgstr "No modifica las imágenes"
msgstr "No modifica las imágenes"
msgid "Use Curves"
@ -19717,7 +19713,7 @@ msgstr "Rango de fotogramas de curvas"
msgid "The combined frame range of all F-Curves within this action"
msgstr "El rango combinado de fotogramas de todas las Curvas-F en esta acción"
msgstr "El rango combinado de fotogramas de todas las curvas-f en esta acción"
msgid "F-Curves"
@ -20581,6 +20577,14 @@ msgid "Amount of random elements that are going to be affected by the brush"
msgstr "Cantidad de elementos aleatorios que serán afectados por el pincel"
msgid "Add effect of brush"
msgstr "Adiciona el efecto del pincel"
msgid "Subtract effect of brush"
msgstr "Sustrae el efecto del pincel"
msgid "Max Element Distance"
msgstr "Distancia máx. elementos"
@ -20783,7 +20787,7 @@ msgstr "Espaciado gradiente"
msgid "Spacing before brush gradient goes full circle"
msgstr "Espacio antes de que el gradiente del pincel de la vuelta completa"
msgstr "Espacio antes de que el gradiente del pincel de una revolución completa"
msgid "Gradient Fill Mode"
@ -28538,7 +28542,7 @@ msgstr "Torsionar"
msgid "Number of turns around parent along the strand"
msgstr "Cantidad de vueltas a lo largo de la hebra"
msgstr "Cantidad de revoluciones a lo largo de la hebra"
msgid "Twist Curve"
@ -31381,7 +31385,7 @@ msgstr "Qué opciones de administración de color usar al guardar archivos"
msgid "Follow Scene"
msgstr "Igual que la escena"
msgstr "De la escena"
msgid "Choose BW for saving grayscale images, RGB for saving red, green and blue channels, and RGBA for saving red, green, blue and alpha channels"
@ -31925,7 +31929,7 @@ msgstr "ID del elemento"
msgid "Identifier of operator to call on input event"
msgstr "Identificador del operador a invocar en un evento de entrada"
msgstr "Identificador del operador a ser invocado por el evento de entrada"
msgid "Is this keymap item user defined (doesn't just replace a builtin item)"
@ -36105,7 +36109,7 @@ msgstr "Controles de puntos de referencia"
msgid "Lightgroup Sync"
msgstr "Sincronizar grupo de luces"
msgstr "Sincronizar grupos de luces"
msgid "Operator Presets"
@ -39256,7 +39260,7 @@ msgstr "Invierte las coordenadas de texturizado V alrededor del punto de desplaz
msgid "Mirror vertex groups (e.g. .R->.L)"
msgstr "Simetrizar grupos de vértices (p.ej. .D -> .I)"
msgstr "Simetrizar grupos de vértices (p.ej. .R -> .L)"
msgid "Multires Modifier"
@ -41585,7 +41589,7 @@ msgstr "Mostrar la previsualización usando la resolución completa o distintas
msgid "None, full render"
msgstr "No reemplazar, procesar clip original"
msgstr "No reemplazar (clip original)"
msgid "Render Undistorted"
@ -42478,7 +42482,7 @@ msgstr "Interpolación de píxeles de alta calidad"
msgid "Location Influence"
msgstr "Influencia de la posición"
msgstr "Influencia en posición"
msgid "Influence of stabilization algorithm on footage location"
@ -42486,7 +42490,7 @@ msgstr "Influencia del algoritmo de estabilización sobre la posición de la ima
msgid "Rotation Influence"
msgstr "Influencia rotación"
msgstr "Influencia en rotación"
msgid "Influence of stabilization algorithm on footage rotation"
@ -42494,7 +42498,7 @@ msgstr "Influencia del algoritmo de estabilización sobre la rotación de la pel
msgid "Scale Influence"
msgstr "Escalar Influencia"
msgstr "Influencia en escala"
msgid "Influence of stabilization algorithm on footage scale"
@ -43348,11 +43352,11 @@ msgstr "Algoritmo a usar para limitar canal"
msgid "Single"
msgstr "Único"
msgstr "Individual"
msgid "Limit by single channel"
msgstr "Limitar en base a un solo canal"
msgstr "Limitar en base a un único canal"
msgid "Limit by maximum of other channels"
@ -66400,7 +66404,7 @@ msgstr "Extruye los vértices seleccionados con una rotación en espiral alreded
msgid "Turns"
msgstr "Vueltas"
msgstr "Revoluciones"
msgid "(De)select all vertices, edges or faces"
@ -68846,7 +68850,7 @@ msgstr "Qué algoritmo usar para generar el margen"
msgid "Filter to combined, diffuse, glossy, transmission and subsurface passes"
msgstr "Filtrar a las pasadas combinada, de difusión, reflectividad, transmisión y transluminiscencia"
msgstr "Filtrar las pasadas combinada, de difusión, reflectividad, transmisión y transluminiscencia"
msgid "Type of pass to bake, some of them may not be supported by the current render engine"
@ -69766,11 +69770,11 @@ msgstr "Excluir a los bloqueadores seleccionados de la proyección sombras desde
msgctxt "Operator"
msgid "Select Light Linking Blockers"
msgstr "Seleccionar bloqueadores vinculados"
msgstr "Seleccionar bloqueadores de iluminación"
msgid "Select all objects which block light from this emitter"
msgstr "Selecciona todos los objetos que bloquean la iluminación de este emisor"
msgstr "Selecciona todos los objetos que bloquean la luz de este emisor"
msgctxt "Operator"
@ -69787,20 +69791,20 @@ msgstr "Estado de la vinculación de iluminación"
msgid "Include selected receivers to receive light from the active emitter"
msgstr "Incluir a los receptores seleccionados para que reciban iluminación desde el emisor activo"
msgstr "Incluir a los receptores seleccionados para la recepción de luz desde el emisor activo"
msgid "Exclude selected receivers from receiving light from the active emitter"
msgstr "Excluir a los receptores seleccionados de la recepción de iluminación desde el emisor activo"
msgstr "Excluir a los receptores seleccionados de la recepción de luz desde el emisor activo"
msgctxt "Operator"
msgid "Select Light Linking Receivers"
msgstr "Seleccionar receptores vinculados a iluminación"
msgstr "Seleccionar receptores de iluminación"
msgid "Select all objects which receive light from this emitter"
msgstr "Seleccionar todos los objetos que reciben iluminación desde este emisor"
msgstr "Selecciona todos los objetos que reciben luz de este emisor"
msgctxt "Operator"
@ -69809,7 +69813,7 @@ msgstr "Eliminar de colección de vinculación de iluminación"
msgid "Remove this object or collection from the light linking collection"
msgstr "Eliminar este objeto o colección de la colección de vinculación de iluminación"
msgstr "Elimina este objeto o colección de la colección de vinculación de iluminación"
msgctxt "Operator"
@ -71072,7 +71076,7 @@ msgstr "Tipo de luz"
msgid "Matching light types"
msgstr "Tipos de luces coincidentes"
msgstr "Luces del mismo tipo"
msgid "Select object relative to the active object's position in the hierarchy"
@ -71104,7 +71108,7 @@ msgstr "Biblioteca (datos de objeto)"
msgid "Select the mirror objects of the selected object e.g. \"L.sword\" and \"R.sword\""
msgstr "Selecciona el objeto simétrico del objeto seleccionado, p.ej: \"D.espada\" -> \"I.espada\""
msgstr "Selecciona el objeto simétrico del objeto seleccionado, p.ej: \"L.espada\" -> \"R.espada\""
msgid "Select connected parent/child objects"
@ -71606,7 +71610,7 @@ msgstr "Eliminar rastreo"
msgid "Clear and Keep Transformation (Clear Track)"
msgstr "Eliminar y mantener transformaciones (Eliminar rastreo)"
msgstr "Eliminar rastreo y mantener transformaciones"
msgctxt "Operator"
@ -74913,11 +74917,11 @@ msgstr "Exporta la configuración del teclado a un script Python"
msgid "All Keymaps"
msgstr "Todos los mapas de teclado"
msgstr "Mapa de teclado completo"
msgid "Write all keymaps (not just user modified)"
msgstr "Guarda todos los mapas de teclado (no sólo los modificados por el usuario)"
msgstr "Guardará el mapa de teclado completo (no sólo las teclas modificadas por el usuario)"
msgctxt "Operator"
@ -74926,7 +74930,7 @@ msgstr "Importar mapa de teclado..."
msgid "Import key configuration from a Python script"
msgstr "Importa la configuración del teclado desde un script Python"
msgstr "Importa la configuración del teclado desde un script de Python"
msgid "Keep Original"
@ -74934,7 +74938,7 @@ msgstr "Mantener original"
msgid "Keep original file after copying to configuration folder"
msgstr "Mantiene el archivo original luego de copiar hacia la carpeta de configuración"
msgstr "Mantendrá el archivo original luego de copiar hacia la carpeta de configuración"
msgctxt "Operator"
@ -74943,7 +74947,7 @@ msgstr "Eliminar configuración de teclado"
msgid "Remove key config"
msgstr "Elimina configuración de teclado"
msgstr "Eliminará la configuración de teclado actual"
msgctxt "Operator"
@ -74952,7 +74956,7 @@ msgstr "Comprobar conflictos en teclado"
msgid "Test key configuration for conflicts"
msgstr "Comprobar conflictos en teclado"
msgstr "Comprobará conflictos en el mapa de teclado"
msgctxt "Operator"
@ -74961,7 +74965,7 @@ msgstr "Agregar elemento a mapa de teclado"
msgid "Add key map item"
msgstr "Agrega un elemento al mapa de teclado"
msgstr "Agrega un elemento al mapa de teclado actual"
msgctxt "Operator"
@ -74970,7 +74974,7 @@ msgstr "Eliminar elemento del mapa de teclado"
msgid "Remove key map item"
msgstr "Elimina un elemento del mapa de teclado"
msgstr "Elimina un elemento del mapa de teclado actual"
msgid "Item Identifier"
@ -74987,7 +74991,7 @@ msgstr "Restablecer elemento de teclado"
msgid "Restore key map item"
msgstr "Restablece un elemento del mapa de teclado"
msgstr "Restablece un elemento del mapa de teclado"
msgid "Identifier of the item to restore"
@ -75000,11 +75004,11 @@ msgstr "Restablecer mapa de teclado"
msgid "Restore key map(s)"
msgstr "Restablece el mapa del teclado"
msgstr "Restablece el mapa del teclado"
msgid "Restore all keymaps to default"
msgstr "Restablece todos los mapas de teclado a su estado predefinido"
msgstr "Restablece todos los mapas de teclado a su estado predefinido"
msgctxt "Operator"
@ -75994,7 +75998,7 @@ msgstr "Agregar AOV"
msgid "Add a Shader AOV"
msgstr "Agregar AOV de sombreado"
msgstr "Agrega una AOV de sombreado"
msgctxt "Operator"
@ -76003,7 +76007,7 @@ msgstr "Agregar grupo de luces"
msgid "Add a Light Group"
msgstr "Agrega un grupo de luces"
msgstr "Agrega un nuevo grupo de luces a la capa de visualización actual"
msgid "Name of newly created lightgroup"
@ -76012,11 +76016,11 @@ msgstr "Nombre del grupo de luces recientemente creado"
msgctxt "Operator"
msgid "Add Used Lightgroups"
msgstr "Agregar grupos de luces usados"
msgstr "Agregar grupos de luces en uso"
msgid "Add all used Light Groups"
msgstr "Agrega todos los grupos de luces usados"
msgstr "Agrega (a la capa de visualización actual) todos los grupos de luces que se encuentren en uso en otras capas de visualización"
msgctxt "Operator"
@ -76025,7 +76029,7 @@ msgstr "Eliminar capa de visualización"
msgid "Remove the selected view layer"
msgstr "Elimina la capa de visualización seleccionada"
msgstr "Elimina la capa de visualización actual"
msgctxt "Operator"
@ -76034,7 +76038,7 @@ msgstr "Eliminar AOV"
msgid "Remove Active AOV"
msgstr "Eliminar AOV activa"
msgstr "Elimina la AOV activa"
msgctxt "Operator"
@ -76043,7 +76047,7 @@ msgstr "Eliminar grupo de luces"
msgid "Remove Active Lightgroup"
msgstr "Eliminar grupo de luces activo"
msgstr "Elimina el grupo de luces activo de la capa de visualización actual"
msgctxt "Operator"
@ -76052,7 +76056,7 @@ msgstr "Eliminar grupos de luces no usados"
msgid "Remove all unused Light Groups"
msgstr "Elimina todos los grupos de luces no usados"
msgstr "Elimina (de la capa de visualización actual) todos los grupos de luces no usados"
msgctxt "Operator"
@ -84964,7 +84968,7 @@ msgstr "Abre un archivo guardado automáticamente para recuperarlo"
msgctxt "Operator"
msgid "Recover Last Session"
msgstr "Recuperar la última sesión"
msgstr "Recuperar última sesión"
msgid "Open the last closed file (\"quit.blend\")"
@ -87768,7 +87772,7 @@ msgstr "Menús"
msgid "Open on Mouse Over"
msgstr "Abrir al posar ratón"
msgstr "Abrir al posar el ratón"
msgid "Pie Menus"
@ -88074,7 +88078,7 @@ msgstr "Máscara de esténcil"
msgctxt "Operator"
msgid "Scale Cage"
msgstr "Escalar jaula"
msgstr "Escalar (Jaula)"
msgctxt "Operator"
@ -90670,6 +90674,10 @@ msgid "Temporary Directory"
msgstr "Directorio temporal"
msgid "The directory for storing temporary save files. The path must reference an existing directory or it will be ignored"
msgstr "Directorio para almacenar archivos temporales. La ruta deberá referenciar a un directorio existente, de lo contrario será ignorado"
msgid ""
"Command to launch the text editor, either a full path or a command in $PATH.\n"
"Use the internal editor when left blank"
@ -92461,7 +92469,7 @@ msgstr "Verdadero cuando no sea posible establecer este valor en Ninguno"
msgid "Return"
msgstr "Devuelta"
msgstr "Resultante"
msgid "True when this property is an output value from an RNA function"
@ -100306,11 +100314,11 @@ msgstr "Si existieran, los marcadores serán mostrados en una fila separada en l
msgid "Show Pose Markers"
msgstr "Mostrar marcadores de posición"
msgstr "Mostrar marcadores de la pose"
msgid "Show markers belonging to the active action instead of Scene markers (Action and Shape Key Editors only)"
msgstr "Muestra los marcadores pertenecientes a la acción activa, en vez de los de la escena (sólo en editores de acciones y Formas clave)"
msgstr "Mostrará los marcadores pertenecientes a la acción activa, en vez de los marcadores de la escena (sólo para el Editor de acciones y el Editor de Formas clave)"
msgid "Show Sliders"
@ -100334,7 +100342,7 @@ msgstr "Sincronizar marcadores"
msgid "Sync Markers with keyframe edits"
msgstr "Sincroniza los marcadores al editar fotogramas clave"
msgstr "Sincronizar los marcadores al editar fotogramas clave"
msgid "Realtime Updates"
@ -104442,7 +104450,7 @@ msgstr "Estilo de control"
msgid "Widget Label Style"
msgstr "Estilo etiqueta del control"
msgstr "Estilo Control etiqueta"
msgid "Theme Text Editor"
@ -104622,7 +104630,7 @@ msgstr "Colores Elementos lista"
msgid "Menu Widget Colors"
msgstr "Colores Controles menú"
msgstr "Colores Control menú"
msgid "Menu Backdrop Colors"
@ -104899,7 +104907,7 @@ msgstr "Color de la estructura en modo Edición, cuando la selección de bordes
msgid "Theme Widget Color Set"
msgstr "Conjunto de colores de controles"
msgstr "Conjunto de colores Control"
msgid "Theme settings for widget color sets"
@ -104931,7 +104939,7 @@ msgstr "Sombreado Arriba"
msgid "Theme Widget State Color"
msgstr "Color de estado de controles"
msgstr "Color de estado de Control"
msgid "Theme settings for widget state colors"
@ -105071,7 +105079,7 @@ msgstr "Esculpido de curvas"
msgid "Curve Profile Widget"
msgstr "Control de curva de perfil"
msgstr "Control curva de perfil"
msgid "Used for defining a profile's path"
@ -108131,7 +108139,7 @@ msgstr "Nombre del elemento del mapa de acción"
msgid "Identifier of operator to call on action event"
msgstr "Identificador del operador a invocar en un evento de la acción"
msgstr "Identificador del operador a ser invocado por el evento de la acción"
msgid "Operator Mode"
@ -111250,6 +111258,11 @@ msgid "Mesh Filter Modal Map"
msgstr "Mapa modal - Filtro de malla"
msgctxt "Operator"
msgid "DEM data (.hgt) as Mesh and/or Image"
msgstr "Datos DEM (.hgt) como malla y/o imagen"
msgid "You have been logged out"
msgstr "Se ha cerrado la sesión"
@ -111842,6 +111855,10 @@ msgid "Path to gltfpack"
msgstr "Ruta a gltfpack"
msgid "This is the least efficient of the available forms, and should only be used when required."
msgstr "Este es el formato menos eficiente de todos, sólo debería ser usado cuando sea necesario."
msgid "Export only deformation bones is not possible when not sampling animation"
msgstr "La exportación tan sólo de huesos deformantes no es posible cuando no se está muestreando la animación"
@ -114606,14 +114623,6 @@ msgid "Caps Type"
msgstr "Tipo de extremos"
msgid "CCW"
msgstr "Antihorario"
msgid "CW"
msgstr "Horario"
msgid "Invert to Fill"
msgstr "Invertir a Rellenar"
@ -117182,7 +117191,7 @@ msgstr "Ajustar previsualización a ventana"
msgctxt "Operator"
msgid "Sequence Render Image"
msgstr "Procesar fotograma"
msgstr "Procesar imagen"
msgctxt "Operator"
@ -117926,7 +117935,7 @@ msgstr "STL (.stl)"
msgctxt "Operator"
msgid "Render Image"
msgstr "Procesar fotograma"
msgstr "Procesar imagen"
msgctxt "Operator"
@ -118060,7 +118069,7 @@ msgstr "Nivel superior"
msgid "Sub Level"
msgstr "Sub nivel"
msgstr "Nivel inferior"
msgid "Link Materials To"
@ -118230,7 +118239,7 @@ msgstr "Título del panel"
msgid "Widget Label"
msgstr "Etiqueta de control"
msgstr "Etiqueta control"
msgid "Temporary Files"
@ -118481,7 +118490,7 @@ msgstr "Perspectiva / Ortogonal"
msgctxt "Operator"
msgid "Viewport Render Image"
msgstr "Procesar fotograma"
msgstr "Procesar imagen"
msgctxt "Operator"
@ -120848,6 +120857,18 @@ msgid "armatures"
msgstr "esqueletos"
msgid "Unable to create builtin attribute in edit mode"
msgstr "No es posible crear un atributo interno en modo Edición"
msgid "Domain unsupported for \"id\" attribute"
msgstr "Dominio no soportado para el atributo \"id\""
msgid "Type unsupported for \"id\" attribute"
msgstr "Tipo no soportado para el atributo \"id\""
msgid "Attribute name cannot be empty"
msgstr "El nombre del atributo no puede estar vacío"
@ -121315,11 +121336,11 @@ msgstr "luces"
msgid "Light Linking for %s"
msgstr "Vinculación de iluminación para %s"
msgstr "Vinculación_iluminación %s"
msgid "Shadow Linking for %s"
msgstr "Vinculación de sombras para %s"
msgstr "Vinculación_sombras %s"
msgid "Cannot unlink unsupported '%s' from light linking collection '%s'"
@ -121362,18 +121383,6 @@ msgid "Auto Smooth"
msgstr "Suavizado automático"
msgid "Socket_1"
msgstr "Conector_1"
msgid "Input_1_use_attribute"
msgstr "Entrada_1_usar_atributo"
msgid "Input_1_attribute_name"
msgstr "Entrada_1_nombre_atributo"
msgid "Tangent space can only be computed for tris/quads, aborting"
msgstr "El espacio tangencial sólo puede ser calculado en triángulos o cuadriláteros, abortando"
@ -122455,6 +122464,10 @@ msgid "Cannot create the Animation Context"
msgstr "No es posible crear el contexto de animación"
msgid "One or more F-Curves are not visible due to filter settings"
msgstr "Una o más curvas-f no se encuentran visibles debido a las opciones de filtrado"
msgid "F-Curves have no valid size"
msgstr "Las curvas-f tienen un tamaño inválido"
@ -122793,10 +122806,6 @@ msgid "No object found to operate on"
msgstr "No se encontraron objetos sobre los cuales operar"
msgid "Bone collections can only be added to an Armature"
msgstr "Las colecciones de huesos sólo pueden ser agregadas a un esqueleto"
msgid "Cannot add bone collections to a linked Armature without an override"
msgstr "No es posible agregar colecciones de huesos a un esqueleto vinculado sin una redefinición"
@ -122805,10 +122814,6 @@ msgid "Cannot add bone collections to a linked Armature with a system override;
msgstr "No es posible agregar colecciones de huesos a un esqueleto vinculado con una redefinición del sistema; crear de forma explícita una redefinición en el esqueleto"
msgid "Bone collections can only be edited on an Armature"
msgstr "Las colecciones de huesos sólo pueden ser editadas en un esqueleto"
msgid "Cannot update a linked Armature with a system override; explicitly create an override on the Armature"
msgstr "No es posible actualizar un esqueleto vinculado con una redefinición del sistema; crear de forma explícita una redefinición en el esqueleto"
@ -122821,6 +122826,10 @@ msgid "Cannot edit bone collections that are linked from another blend file"
msgstr "No es posible editar colecciones de huesos que se encuentren vinculadas desde otro archivo .blend"
msgid "Bone collections can only be edited on an Armature"
msgstr "Las colecciones de huesos sólo pueden ser editadas en un esqueleto"
msgid "Cannot edit bone collections on linked Armatures without override"
msgstr "No es posible editar colecciones de huesos en esqueletos vinculados, sin una redefinición"
@ -123398,6 +123407,10 @@ msgid "Data-block inputs are unsupported"
msgstr "Entradas del bloque de datos no soportadas"
msgid "Node group's first output must be a geometry"
msgstr "La primera salida del grupo de nodos debe ser una geometría"
msgid "Annotation Create Poly: LMB click to place next stroke vertex | ESC/Enter to end (or click outside this area)"
msgstr "Anotación - Línea poligonal: Clic Izq. para ubicar los puntos del trazo | Esc/Intro para finalizar (o clic fuera de este área)"
@ -127692,7 +127705,7 @@ msgstr "Y:"
msgid "Pattern Area:"
msgstr "Área patrón:"
msgstr "Área del patrón:"
msgid "Width:"
@ -133389,10 +133402,6 @@ msgid "Node group must have an output socket"
msgstr "El grupo de nodos debe contener un conector de salida"
msgid "Node group's first output must be a geometry"
msgstr "La primera salida del grupo de nodos debe ser una geometría"
msgid "NormalEdit"
msgstr "Editar_normales"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
@ -305,14 +305,14 @@ msgid "Material"
msgstr "Materiala"
msgid "Direction"
msgstr "Norabidea"
msgid "Stroke"
msgstr "Trazua"
msgid "Direction"
msgstr "Norabidea"
msgid "Normal"
msgstr "Normala"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2023-11-30 20:00+0000\n"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: \n"
@ -2134,14 +2134,14 @@ msgid "Curve Strength"
msgstr "Käyrän vahvuus"
msgid "Direction"
msgstr "Suunta"
msgid "Stroke"
msgstr "Piirto"
msgid "Direction"
msgstr "Suunta"
msgid "Normal"
msgstr "Normaali"

View File

@ -1,10 +1,10 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-03-12 05:27+0000\n"
"PO-Revision-Date: 2024-03-19 07:58+0000\n"
"Last-Translator: Damien Picard <dam.pic@free.fr>\n"
"Language-Team: French <https://translate.blender.org/projects/blender-ui/ui/fr/>\n"
"Language: fr\n"
@ -403,6 +403,10 @@ msgid "Displays glTF UI to manage material variants"
msgstr "Afficher linterface glTF pour gérer les variantes de matériaux"
msgid "Allow glTF Embedded format"
msgstr "Permettre le format gtTF embarqué"
msgid "Display glTF UI to manage animations"
msgstr "Afficher linterface glTF pour gérer les animations"
@ -4464,18 +4468,6 @@ msgid "Number of pixels to expand or contract fill area"
msgstr "Nombre de pixels à utiliser pour dilater ou contracter la zone remplie"
msgid "Direction"
msgstr "Direction"
msgid "Add effect of brush"
msgstr "Effet daddition de la brosse"
msgid "Subtract effect of brush"
msgstr "Effet de soustraction de la brosse"
msgid "Eraser Mode"
msgstr "Mode gomme"
@ -4524,6 +4516,10 @@ msgid "Strokes end extension for closing gaps, use zero to disable"
msgstr "Extension de lextrémité des traits pour fermer les interstices, 0 pour désactiver"
msgid "Direction"
msgstr "Direction"
msgid "Direction of the fill"
msgstr "Direction du remplissage"
@ -20581,6 +20577,14 @@ msgid "Amount of random elements that are going to be affected by the brush"
msgstr "Quantité déléments aléatoires qui seront affectés par la brosse"
msgid "Add effect of brush"
msgstr "Effet daddition de la brosse"
msgid "Subtract effect of brush"
msgstr "Effet de soustraction de la brosse"
msgid "Max Element Distance"
msgstr "Distance max déléments"
@ -63164,11 +63168,11 @@ msgstr "Hauteur du plan créé"
msgid "Animate Image Sequences"
msgstr "Animer la séquence dimages"
msgstr "Séquences dimages"
msgid "Import sequentially numbered images as an animated image sequence instead of separate planes"
msgstr "Importer les images numérotées séquentiellement en tant que séquence dimages animée, plutôt que des plans séparés"
msgstr "Importer les images numérotées séquentiellement en tant que séquences dimages, plutôt que comme plans séparés"
msgid "Offset Planes"
@ -80673,7 +80677,7 @@ msgstr "Mettre à jour le dépôt de travail di18n (fichiers po)"
msgid "Skip POT"
msgstr "Ignorer POT"
msgstr "Ignorer le POT"
msgid "Skip POT file generation"
@ -90672,6 +90676,10 @@ msgid "Temporary Directory"
msgstr "Dossier temporaire"
msgid "The directory for storing temporary save files. The path must reference an existing directory or it will be ignored"
msgstr "Le dossier où stocker les fichiers temporaires. Le chemin doit pointer vers un dossier existant, sans quoi il sera ignoré"
msgid ""
"Command to launch the text editor, either a full path or a command in $PATH.\n"
"Use the internal editor when left blank"
@ -111844,6 +111852,10 @@ msgid "Path to gltfpack"
msgstr "Chemin de gltfpack"
msgid "This is the least efficient of the available forms, and should only be used when required."
msgstr "Il sagit de la moins efficace des formes disponibles, et ne devrait être utilisée que si nécessaire."
msgid "Export only deformation bones is not possible when not sampling animation"
msgstr "Impossible de nexporter que les os de déformation si lanimation nest pas échantillonnée"
@ -114608,14 +114620,6 @@ msgid "Caps Type"
msgstr "Type dextrémités"
msgid "CCW"
msgstr "Antihoraire"
msgid "CW"
msgstr "Horaire"
msgid "Invert to Fill"
msgstr "Inverser pour remplir"
@ -120850,6 +120854,18 @@ msgid "armatures"
msgstr "armatures"
msgid "Unable to create builtin attribute in edit mode"
msgstr "Impossible de créer un attribut prédéfini en mode édition"
msgid "Domain unsupported for \"id\" attribute"
msgstr "Domaine non pris en charge pour lattribut « id »"
msgid "Type unsupported for \"id\" attribute"
msgstr "Type non pris en charge pour lattribut « id »"
msgid "Attribute name cannot be empty"
msgstr "Le nom dattribut ne peut pas être vide"
@ -121364,18 +121380,6 @@ msgid "Auto Smooth"
msgstr "Lissage auto"
msgid "Socket_1"
msgstr "Prise_1"
msgid "Input_1_use_attribute"
msgstr "Entrée_1_utiliser_l_attribut"
msgid "Input_1_attribute_name"
msgstr "Entrée_1_nom_d_attribut"
msgid "Tangent space can only be computed for tris/quads, aborting"
msgstr "Lespace tangent peut seulement être calculé pour des triangles ou quadrangles, abandon"
@ -122457,6 +122461,10 @@ msgid "Cannot create the Animation Context"
msgstr "Impossible de créer le contexte danimation"
msgid "One or more F-Curves are not visible due to filter settings"
msgstr "Une F-courbe ou plus ne sont pas visibles à cause des réglages de filtrage"
msgid "F-Curves have no valid size"
msgstr "Les F-courbes nont pas de taille valide"
@ -122795,10 +122803,6 @@ msgid "No object found to operate on"
msgstr "Aucun objet trouvé sur lequel agir"
msgid "Bone collections can only be added to an Armature"
msgstr "Les collections dos ne peuvent être ajoutées que sur une armature"
msgid "Cannot add bone collections to a linked Armature without an override"
msgstr "Impossible dajouter des collections dos à une armature liée sans redéfinition"
@ -122807,10 +122811,6 @@ msgid "Cannot add bone collections to a linked Armature with a system override;
msgstr "Impossible dajouter des collections dos à une armature liée ayant une redéfinition système ; créer une redéfinition explicite sur larmature"
msgid "Bone collections can only be edited on an Armature"
msgstr "Les collections dos ne peuvent être éditées que sur une armature"
msgid "Cannot update a linked Armature with a system override; explicitly create an override on the Armature"
msgstr "Impossible de mettre à jour une armature liée ayant une redéfinition système ; créer une redéfinition explicite sur larmature"
@ -122823,6 +122823,10 @@ msgid "Cannot edit bone collections that are linked from another blend file"
msgstr "Impossible déditer des collections dos liées depuis un autre fichier blend"
msgid "Bone collections can only be edited on an Armature"
msgstr "Les collections dos ne peuvent être éditées que sur une armature"
msgid "Cannot edit bone collections on linked Armatures without override"
msgstr "Impossible déditer des collections dos dune armature liée sans redéfinition"
@ -123400,6 +123404,10 @@ msgid "Data-block inputs are unsupported"
msgstr "Les entrées blocs de données ne sont pas prises en charge"
msgid "Node group's first output must be a geometry"
msgstr "La première sortie du groupe de nœuds doit être une géométrie"
msgid "Annotation Create Poly: LMB click to place next stroke vertex | ESC/Enter to end (or click outside this area)"
msgstr "Création de poly dannotation : clic gauche pour placer le prochain sommet du trait | Échap/Entrée pour finaliser (ou cliquer en dehors de cette zone)"
@ -133391,10 +133399,6 @@ msgid "Node group must have an output socket"
msgstr "Le groupe de nœuds doit avoir une prise de sortie"
msgid "Node group's first output must be a geometry"
msgstr "La première sortie du groupe de nœuds doit être une géométrie"
msgid "NormalEdit"
msgstr "ÉditionNormales"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2017-12-25 14:01+0100\n"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2023-10-06 09:54+0000\n"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2015-03-03 16:21+0530\n"
@ -655,14 +655,14 @@ msgid "Vertex Color"
msgstr "शिरोबिन्दु रंग"
msgid "Direction"
msgstr "दिशा"
msgid "Dissolve"
msgstr "भंग"
msgid "Direction"
msgstr "दिशा"
msgid "Radius"
msgstr "त्रिज्या"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-01-11 03:55+0000\n"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2023-12-04 11:07+0000\n"
@ -3276,18 +3276,6 @@ msgid "Curve used for the strength"
msgstr "Kurva digunakan untuk kekuatan"
msgid "Direction"
msgstr "Arah"
msgid "Add effect of brush"
msgstr "Tambah efek kuas"
msgid "Subtract effect of brush"
msgstr "Kurangi efek kuas"
msgid "Eraser Mode"
msgstr "Mode Penghapus"
@ -3332,6 +3320,10 @@ msgid "Strokes end extension for closing gaps, use zero to disable"
msgstr "Garis luar dan ekstensi untuk menutup celah, gunakan nol untuk dinonaktifkan"
msgid "Direction"
msgstr "Arah"
msgid "Direction of the fill"
msgstr "Arah isi"
@ -9238,6 +9230,14 @@ msgid "Cloth Simulation"
msgstr "Simulasi Kain"
msgid "Add effect of brush"
msgstr "Tambah efek kuas"
msgid "Subtract effect of brush"
msgstr "Kurangi efek kuas"
msgid "Projected"
msgstr "Terproyeksi"
@ -22960,14 +22960,6 @@ msgid "Thickness Profile"
msgstr "Profil Ketebalan"
msgid "CCW"
msgstr "CCW"
msgid "CW"
msgstr "CW"
msgid "Quality Steps"
msgstr "Step Kualitas"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-03-01 16:11+0000\n"
@ -3928,18 +3928,6 @@ msgid "Curve used for the strength"
msgstr "Curva usata per la forza"
msgid "Direction"
msgstr "Direzione"
msgid "Add effect of brush"
msgstr "Aggiunge l'effetto del pennello"
msgid "Subtract effect of brush"
msgstr "Sottrae l'effetto del pennello"
msgid "Dissolve"
msgstr "Dissolvi"
@ -3968,6 +3956,10 @@ msgid "Closure Size"
msgstr "Dimensione della Chiusura"
msgid "Direction"
msgstr "Direzione"
msgid "Direction of the fill"
msgstr "Direzione del riempimento"
@ -13247,6 +13239,14 @@ msgid "Color of cursor when subtracting"
msgstr "Colore del cursore quando sottrae"
msgid "Add effect of brush"
msgstr "Aggiunge l'effetto del pennello"
msgid "Subtract effect of brush"
msgstr "Sottrae l'effetto del pennello"
msgid "Falloff Angle"
msgstr "Angolo Decadimento"
@ -54252,14 +54252,6 @@ msgid "Mask Value"
msgstr "Valore Maschera"
msgid "CCW"
msgstr "Senso Antiorario"
msgid "CW"
msgstr "Senso Orario"
msgctxt "Operator"
msgid "Copy Active to Selected Objects"
msgstr "Copia Attivo a Oggetti Selezionati"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-03-12 05:27+0000\n"
@ -4487,18 +4487,6 @@ msgid "Number of pixels to expand or contract fill area"
msgstr "フィルエリアを拡大,または縮小するピクセル数"
msgid "Direction"
msgstr "方向"
msgid "Add effect of brush"
msgstr "ブラシにエフェクトを追加"
msgid "Subtract effect of brush"
msgstr "ブラシの効果を差し引きます"
msgid "Eraser Mode"
msgstr "消しゴムモード"
@ -4547,6 +4535,10 @@ msgid "Strokes end extension for closing gaps, use zero to disable"
msgstr "ストロークの端を延長し,隙間を埋めます(0で無効)"
msgid "Direction"
msgstr "方向"
msgid "Direction of the fill"
msgstr "フィルの方向"
@ -20833,6 +20825,14 @@ msgid "Amount of random elements that are going to be affected by the brush"
msgstr "このブラシにより影響を受けるランダム要素の量"
msgid "Add effect of brush"
msgstr "ブラシにエフェクトを追加"
msgid "Subtract effect of brush"
msgstr "ブラシの効果を差し引きます"
msgid "Max Element Distance"
msgstr "要素の最大距離"
@ -115570,14 +115570,6 @@ msgid "Caps Type"
msgstr "端のタイプ"
msgid "CCW"
msgstr "反時計回り"
msgid "CW"
msgstr "時計回り"
msgid "Invert to Fill"
msgstr "反転をフィルに"
@ -122326,18 +122318,6 @@ msgid "Auto Smooth"
msgstr "自動スムーズ"
msgid "Socket_1"
msgstr "ソケット_1"
msgid "Input_1_use_attribute"
msgstr "入力_1_属性使用"
msgid "Input_1_attribute_name"
msgstr "入力_1_属性名"
msgid "Tangent space can only be computed for tris/quads, aborting"
msgstr "タンジェント空間は三角面/四角面のみ計算可能です.中止します"
@ -123759,10 +123739,6 @@ msgid "No object found to operate on"
msgstr "操作するオブジェクトがありません"
msgid "Bone collections can only be added to an Armature"
msgstr "ボーンコレクションはアーマチュアにのみ追加可能です"
msgid "Cannot add bone collections to a linked Armature without an override"
msgstr "オーバーライドのないリンク中のアーマチュアにはボーンコレクションを追加できません"
@ -123771,10 +123747,6 @@ msgid "Cannot add bone collections to a linked Armature with a system override;
msgstr "システムオーバーライドのあるリンク中のアーマチュアにボーンコレクションを追加できません.アーマチュアにオーバーライドを明示的に作成してください"
msgid "Bone collections can only be edited on an Armature"
msgstr "ボーンコレクションはアーマチュアでのみ編集できます"
msgid "Cannot update a linked Armature with a system override; explicitly create an override on the Armature"
msgstr "システムオーバーライドのあるリンク中アーマチュアは更新できません.アーマチュアにオーバーライドを明示的に作成してください"
@ -123787,6 +123759,10 @@ msgid "Cannot edit bone collections that are linked from another blend file"
msgstr "他の blend ファイルからリンク中のボーンコレクションの編集はできません"
msgid "Bone collections can only be edited on an Armature"
msgstr "ボーンコレクションはアーマチュアでのみ編集できます"
msgid "Cannot edit bone collections on linked Armatures without override"
msgstr "オーバーライドのない,リンク中のアーマチュアのボーンコレクションは編集できません"
@ -124366,6 +124342,10 @@ msgid "Data-block inputs are unsupported"
msgstr "データブロック入力は未対応です"
msgid "Node group's first output must be a geometry"
msgstr "ノードグループの最初の出力はジオメトリにしてください"
msgid "Annotation Create Poly: LMB click to place next stroke vertex | ESC/Enter to end (or click outside this area)"
msgstr "アノテーションポリ作成:左クリックで次のストローク頂点配置 | Esc/Enterまたはエリア外をクリックで終了"
@ -134365,10 +134345,6 @@ msgid "Node group must have an output socket"
msgstr "ノードグループに出力ソケットが必要です"
msgid "Node group's first output must be a geometry"
msgstr "ノードグループの最初の出力はジオメトリにしてください"
msgid "NormalEdit"
msgstr "法線編集"

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Beta (b'4b7cc5b6608a')\n"
"Project-Id-Version: Blender 4.1.0 Release Candidate (b'64bfe491645f')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-01 00:00+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"

Some files were not shown because too many files have changed in this diff Show More