From 65d40b3eeb8bd92ec74a2c3c03c73a331dccf668 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 26 Jan 2018 11:52:01 +1100 Subject: [PATCH 01/16] Docs: invoke_search_popup uses bl_property Also add code example in docs. --- .../examples/bpy.types.Operator.6.py | 38 +++++++++++++++++++ source/blender/makesrna/intern/rna_wm_api.c | 7 +++- 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 doc/python_api/examples/bpy.types.Operator.6.py diff --git a/doc/python_api/examples/bpy.types.Operator.6.py b/doc/python_api/examples/bpy.types.Operator.6.py new file mode 100644 index 00000000000..d32a7d5fd4a --- /dev/null +++ b/doc/python_api/examples/bpy.types.Operator.6.py @@ -0,0 +1,38 @@ +""" +Enum Search Popup ++++++++++++++++++ + +You may want to have an operator prompt the user to select an item +from a search field, this can be done using :class:`bpy.types.Operator.invoke_search_popup`. +""" +import bpy +from bpy.props import EnumProperty + + +class SearchEnumOperator(bpy.types.Operator): + bl_idname = "object.search_enum_operator" + bl_label = "Search Enum Operator" + bl_property = "my_search" + + my_search = EnumProperty( + name="My Search", + items=( + ('FOO', "Foo", ""), + ('BAR', "Bar", ""), + ('BAZ', "Baz", ""), + ), + ) + + def execute(self, context): + self.report({'INFO'}, "Selected:" + self.my_search) + return {'FINISHED'} + + def invoke(self, context, event): + context.window_manager.invoke_search_popup(self) + return {'RUNNING_MODAL'} + + +bpy.utils.register_class(SearchEnumOperator) + +# test call +bpy.ops.object.search_enum_operator('INVOKE_DEFAULT') diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index 089504e342a..cbbe50ccf03 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -459,8 +459,11 @@ void RNA_api_wm(StructRNA *srna) /* invoke enum */ func = RNA_def_function(srna, "invoke_search_popup", "rna_Operator_enum_search_invoke"); - RNA_def_function_ui_description(func, "Operator search popup invoke (search in values of " - "operator's type 'prop' EnumProperty, and execute it on confirmation)"); + RNA_def_function_ui_description( + func, + "Operator search popup invoke which " + "searches values of the operator's :class:`bpy.types.Operator.bl_property` " + "(which must be an EnumProperty), executing it on confirmation"); rna_generic_op_invoke(func, 0); /* invoke functions, for use with python */ From 7980265e7e509f5d9c9ed0f281c67d0662d4f464 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 26 Jan 2018 12:23:15 +1100 Subject: [PATCH 02/16] Tests: replace os.system w/ subprocess.call Saves on process creation and avoids being tripped up by command line parsing. Based on D2967 by @ldo with edits. --- tests/python/pep8.py | 148 +++++++++++++++++++++++++------------------ 1 file changed, 87 insertions(+), 61 deletions(-) diff --git a/tests/python/pep8.py b/tests/python/pep8.py index dde4250f6aa..ebf2c5eabb7 100644 --- a/tests/python/pep8.py +++ b/tests/python/pep8.py @@ -19,6 +19,8 @@ # import os +import subprocess +import shutil # depends on pep8, frosted, pylint # for Ubuntu @@ -71,6 +73,79 @@ def is_pep8(path): return 0 +def check_files_flake8(files): + print("\n\n\n# running flake8...") + + # these are very picky and often hard to follow + # while keeping common script formatting. + ignore = ( + "E122", + "E123", + "E124", + "E125", + "E126", + "E127", + "E128", + # "imports not at top of file." + # prefer to load as needed (lazy load addons etc). + "E402", + # "do not compare types, use 'isinstance()'" + # times types are compared, + # I rather keep them specific + "E721", + ) + + for f, pep8_type in files: + + if pep8_type == 1: + # E501:80 line length + ignore_tmp = ignore + ("E501", ) + else: + ignore_tmp = ignore + + subprocess.call(( + "flake8", + "--isolated", + "--ignore=%s" % ",".join(ignore_tmp), + f, + )) + + +def check_files_frosted(files): + print("\n\n\n# running frosted...") + for f, pep8_type in files: + subprocess.call(("frosted", f)) + + +def check_files_pylint(files): + print("\n\n\n# running pylint...") + for f, pep8_type in files: + # let pep8 complain about line length + subprocess.call(( + "pylint", + "--disable=" + "C0111," # missing doc string + "C0103," # invalid name + "C0413," # import should be placed at the top + "W0613," # unused argument, may add this back + # but happens a lot for 'context' for eg. + "W0232," # class has no __init__, Operator/Panel/Menu etc + "W0142," # Used * or ** magic + # even needed in some cases + "R0902," # Too many instance attributes + "R0903," # Too many statements + "R0911," # Too many return statements + "R0912," # Too many branches + "R0913," # Too many arguments + "R0914," # Too many local variables + "R0915,", # Too many statements + "--output-format=parseable", + "--reports=n", + "--max-line-length=1000", + f, + )) + + def main(): files = [] files_skip = [] @@ -113,70 +188,21 @@ def main(): print("%s:%d:0: empty class (), remove" % (f, i + 1)) del re, class_check - print("\n\n\n# running flake8...") + if shutil.which("flake8"): + check_files_flake8(files) + else: + print("Skipping flake8 checks (command not found)") - # these are very picky and often hard to follow - # while keeping common script formatting. - ignore = ( - "E122", - "E123", - "E124", - "E125", - "E126", - "E127", - "E128", - # "imports not at top of file." - # prefer to load as needed (lazy load addons etc). - "E402", - # "do not compare types, use 'isinstance()'" - # times types are compared, - # I rather keep them specific - "E721", - ) + if shutil.which("frosted"): + check_files_frosted(files) + else: + print("Skipping frosted checks (command not found)") - for f, pep8_type in files: + if shutil.which("pylint"): + check_files_pylint(files) + else: + print("Skipping pylint checks (command not found)") - if pep8_type == 1: - # E501:80 line length - ignore_tmp = ignore + ("E501", ) - else: - ignore_tmp = ignore - - os.system("flake8 " - "--isolated " - "--ignore=%s '%s'" % - (",".join(ignore_tmp), f)) - - # frosted - print("\n\n\n# running frosted...") - for f, pep8_type in files: - os.system("frosted '%s'" % f) - - print("\n\n\n# running pylint...") - for f, pep8_type in files: - # let pep8 complain about line length - os.system("pylint " - "--disable=" - "C0111," # missing doc string - "C0103," # invalid name - "C0413," # import should be placed at the top - "W0613," # unused argument, may add this back - # but happens a lot for 'context' for eg. - "W0232," # class has no __init__, Operator/Panel/Menu etc - "W0142," # Used * or ** magic - # even needed in some cases - "R0902," # Too many instance attributes - "R0903," # Too many statements - "R0911," # Too many return statements - "R0912," # Too many branches - "R0913," # Too many arguments - "R0914," # Too many local variables - "R0915," # Too many statements - " " - "--output-format=parseable " - "--reports=n " - "--max-line-length=1000" - " '%s'" % f) if __name__ == "__main__": From 0f14c72c29c9478056f92f102ca9f94ad9f60a5c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 26 Jan 2018 12:29:55 +1100 Subject: [PATCH 03/16] project_info: replace os.system w/ subprocess.check_call --- build_files/cmake/project_info.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/build_files/cmake/project_info.py b/build_files/cmake/project_info.py index 9b0905da030..ad205cc228c 100755 --- a/build_files/cmake/project_info.py +++ b/build_files/cmake/project_info.py @@ -28,6 +28,9 @@ Module for accessing project file data for Blender. Before use, call init(cmake_build_dir). """ +# TODO: Use CMAKE_EXPORT_COMPILE_COMMANDS (compile_commands.json) +# Instead of Eclipse project format. + __all__ = ( "SIMPLE_PROJECTFILE", "SOURCE_DIR", @@ -45,14 +48,22 @@ __all__ = ( import sys -if not sys.version.startswith("3"): +if sys.version_info.major < 3: print("\nPython3.x needed, found %s.\nAborting!\n" % sys.version.partition(" ")[0]) sys.exit(1) +import subprocess import os -from os.path import join, dirname, normpath, abspath, splitext, exists +from os.path import ( + abspath, + dirname, + exists, + join, + normpath, + splitext, +) SOURCE_DIR = join(dirname(__file__), "..", "..") SOURCE_DIR = normpath(SOURCE_DIR) @@ -146,13 +157,13 @@ def cmake_advanced_info(): raise Exception("Error: win32 is not supported") else: if make_exe_basename.startswith(("make", "gmake")): - cmd = 'cmake "%s" -G"Eclipse CDT4 - Unix Makefiles"' % CMAKE_DIR + cmd = ("cmake", CMAKE_DIR, "-GEclipse CDT4 - Unix Makefiles") elif make_exe_basename.startswith("ninja"): - cmd = 'cmake "%s" -G"Eclipse CDT4 - Ninja"' % CMAKE_DIR + cmd = ("cmake", CMAKE_DIR, "-GEclipse CDT4 - Ninja") else: raise Exception("Unknown make program %r" % make_exe) - os.system(cmd) + subprocess.check_call(cmd) return join(CMAKE_DIR, ".cproject") includes = [] From 9b96dd0f6157fabf0f267ece54fa604094ba303c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 26 Jan 2018 12:46:10 +1100 Subject: [PATCH 04/16] icon update: replace os.system w/ subprocess.check_call --- release/datafiles/blender_icons_update.py | 78 +++++++++++++---------- release/datafiles/prvicons_update.py | 12 +++- 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/release/datafiles/blender_icons_update.py b/release/datafiles/blender_icons_update.py index d342df0a6f9..664915cc10b 100755 --- a/release/datafiles/blender_icons_update.py +++ b/release/datafiles/blender_icons_update.py @@ -2,13 +2,14 @@ # This script updates icons from the SVG file import os +import subprocess import sys def run(cmd): - print(" ", cmd) - os.system(cmd) + print(" ", " ".join(cmd)) + subprocess.check_call(cmd) -BASEDIR = os.path.abspath(os.path.dirname(__file__)) + os.sep +BASEDIR = os.path.abspath(os.path.dirname(__file__)) inkscape_bin = "inkscape" blender_bin = "blender" @@ -18,9 +19,24 @@ if sys.platform == 'darwin': if os.path.exists(inkscape_app_path): inkscape_bin = inkscape_app_path -cmd = inkscape_bin + ' "%sblender_icons.svg" --export-width=602 --export-height=640 --without-gui --export-png="%sblender_icons16.png"' % (BASEDIR, BASEDIR) +cmd = ( + inkscape_bin, + os.path.join(BASEDIR, "blender_icons.svg"), + "--export-width=602", + "--export-height=640", + "--without-gui", + "--export-png=" + os.path.join(BASEDIR, "blender_icons16.png"), +) run(cmd) -cmd = inkscape_bin + ' "%sblender_icons.svg" --export-width=1204 --export-height=1280 --without-gui --export-png="%sblender_icons32.png"' % (BASEDIR, BASEDIR) + +cmd = ( + inkscape_bin, + os.path.join(BASEDIR, "blender_icons.svg"), + "--export-width=1204", + "--export-height=1280", + "--without-gui", + "--export-png=" + os.path.join(BASEDIR, "blender_icons32.png"), +) run(cmd) @@ -32,40 +48,36 @@ datatoc_icon_split_py = os.path.join(BASEDIR, "..", "..", "source", "blender", " # create .dat pixmaps (which are stored in git) cmd = ( - blender_bin + " " - "--background -noaudio " - "--python " + datatoc_icon_split_py + " -- " - "--image=" + BASEDIR + "blender_icons16.png " - "--output=" + BASEDIR + "blender_icons16 " - "--output_prefix=icon16_ " - "--name_style=UI_ICONS " - "--parts_x 26 --parts_y 30 " - "--minx 3 --maxx 53 --miny 3 --maxy 8 " - "--minx_icon 2 --maxx_icon 2 --miny_icon 2 --maxy_icon 2 " - "--spacex_icon 1 --spacey_icon 1" - ) + blender_bin, "--background", "-noaudio", + "--python", datatoc_icon_split_py, "--", + "--image=" + os.path.join(BASEDIR, "blender_icons16.png"), + "--output=" + os.path.join(BASEDIR, "blender_icons16"), + "--output_prefix=icon16_", + "--name_style=UI_ICONS", + "--parts_x", "26", "--parts_y", "30", + "--minx", "3", "--maxx", "53", "--miny", "3", "--maxy", "8", + "--minx_icon", "2", "--maxx_icon", "2", "--miny_icon", "2", "--maxy_icon", "2", + "--spacex_icon", "1", "--spacey_icon", "1", +) run(cmd) cmd = ( - blender_bin + " " - "--background -noaudio " - "--python " + datatoc_icon_split_py + " -- " - "--image=" + BASEDIR + "blender_icons32.png " - "--output=" + BASEDIR + "blender_icons32 " - "--output_prefix=icon32_ " - "--name_style=UI_ICONS " - "--parts_x 26 --parts_y 30 " - "--minx 6 --maxx 106 --miny 6 --maxy 16 " - "--minx_icon 4 --maxx_icon 4 --miny_icon 4 --maxy_icon 4 " - "--spacex_icon 2 --spacey_icon 2" - - ) + blender_bin, "--background", "-noaudio", + "--python", datatoc_icon_split_py, "--", + "--image=" + os.path.join(BASEDIR, "blender_icons32.png"), + "--output=" + os.path.join(BASEDIR, "blender_icons32"), + "--output_prefix=icon32_", + "--name_style=UI_ICONS", + "--parts_x", "26", "--parts_y", "30", + "--minx", "6", "--maxx", "106", "--miny", "6", "--maxy", "16", + "--minx_icon", "4", "--maxx_icon", "4", "--miny_icon", "4", "--maxy_icon", "4", + "--spacex_icon", "2", "--spacey_icon", "2", +) run(cmd) -os.remove(BASEDIR + "blender_icons16.png") -os.remove(BASEDIR + "blender_icons32.png") +os.remove(os.path.join(BASEDIR, "blender_icons16.png")) +os.remove(os.path.join(BASEDIR, "blender_icons32.png")) # For testing, if we want the PNG of each image # ./datatoc_icon_split_to_png.py ./blender_icons16/*.dat # ./datatoc_icon_split_to_png.py ./blender_icons32/*.dat - diff --git a/release/datafiles/prvicons_update.py b/release/datafiles/prvicons_update.py index 448a43df9ce..bc170b98545 100755 --- a/release/datafiles/prvicons_update.py +++ b/release/datafiles/prvicons_update.py @@ -2,9 +2,10 @@ # This script updates icons from the SVG file import os +import subprocess import sys -BASEDIR = os.path.abspath(os.path.dirname(__file__)) + os.sep +BASEDIR = os.path.abspath(os.path.dirname(__file__)) inkscape_path = 'inkscape' @@ -13,5 +14,10 @@ if sys.platform == 'darwin': if os.path.exists(inkscape_app_path): inkscape_path = inkscape_app_path -cmd = inkscape_path + ' "%sprvicons.svg" --without-gui --export-png="%sprvicons.png"' % (BASEDIR, BASEDIR) -os.system(cmd) +cmd = ( + inkscape_path, + os.path.join(BASEDIR, "prvicons.svg"), + "--without-gui", + "--export-png=" + os.path.join(BASEDIR, "prvicons.png"), +) +subprocess.check_call(cmd) From 19b1b45d715e9c9bb20df77b02dd2943f28cd157 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 26 Jan 2018 12:53:42 +1100 Subject: [PATCH 05/16] make_quickie: replace os.system w/ subprocess.call --- build_files/cmake/example_scripts/make_quicky.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build_files/cmake/example_scripts/make_quicky.py b/build_files/cmake/example_scripts/make_quicky.py index 49c284e354d..a1334d6fc83 100755 --- a/build_files/cmake/example_scripts/make_quicky.py +++ b/build_files/cmake/example_scripts/make_quicky.py @@ -107,12 +107,12 @@ def main(): return # execute - cmd = "make %s %s blender/fast" % (" ".join(args), " ".join(targets_new)) + cmd = ["make"] + args + targets_new + ["blender/fast"] print("cmake building with targets: %s" % " ".join(targets_new)) - print("executing: %s" % cmd) + print("executing: %s" % " ".join(cmd)) - import os - os.system(cmd) + import subprocess + subprocess.call(cmd) if __name__ == "__main__": main() From 22afe88882e88b15df06a2b5ce3c596d31dd6365 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 26 Jan 2018 13:10:02 +1100 Subject: [PATCH 06/16] Fix navmesh creation w/ multiple objects D2976 by @dertom --- source/blender/editors/mesh/mesh_navmesh.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index b95921964eb..740d18951dc 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -72,7 +72,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, LinkNode *oblink, *dmlink; DerivedMesh *dm; Scene *scene = CTX_data_scene(C); - LinkNode *dms = NULL; + LinkNodePair dms_pair = {NULL,NULL}; int nverts, ntris, *tris; float *verts; @@ -85,7 +85,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, ob = (Object *) oblink->link; dm = mesh_create_derived_no_virtual(scene, ob, NULL, CD_MASK_MESH); DM_ensure_tessface(dm); - BLI_linklist_prepend(&dms, dm); + BLI_linklist_append(&dms_pair, dm); nverts += dm->getNumVerts(dm); nfaces = dm->getNumTessFaces(dm); @@ -101,6 +101,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, *r_lay |= ob->lay; } + LinkNode *dms = dms_pair.list; /* create data */ verts = MEM_mallocN(sizeof(float) * 3 * nverts, "createVertsTrisData verts"); From 848f0c5b5b3ca4d747e00a66182c3d0edd8cc99b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 25 Jan 2018 16:11:06 +0100 Subject: [PATCH 07/16] Code cleanup: simpler and faster detection of BVH refit. --- intern/cycles/blender/blender_mesh.cpp | 40 ++++++++++---------------- intern/cycles/util/util_vector.h | 5 ++++ 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index cfbc868938e..3b07464cd96 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -1138,12 +1138,19 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, mesh_synced.insert(mesh); /* create derived mesh */ - array oldtriangle = mesh->triangles; + array oldtriangles; + array oldsubd_faces; + array oldsubd_face_corners; + oldtriangles.steal_data(mesh->triangles); + oldsubd_faces.steal_data(mesh->subd_faces); + oldsubd_face_corners.steal_data(mesh->subd_face_corners); /* compares curve_keys rather than strands in order to handle quick hair * adjustments in dynamic BVH - other methods could probably do this better*/ - array oldcurve_keys = mesh->curve_keys; - array oldcurve_radius = mesh->curve_radius; + array oldcurve_keys; + array oldcurve_radius; + oldcurve_keys.steal_data(mesh->curve_keys); + oldcurve_radius.steal_data(mesh->curve_radius); mesh->clear(); mesh->used_shaders = used_shaders; @@ -1206,28 +1213,11 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, sync_mesh_fluid_motion(b_ob, scene, mesh); /* tag update */ - bool rebuild = false; - - if(oldtriangle.size() != mesh->triangles.size()) - rebuild = true; - else if(oldtriangle.size()) { - if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(int)*oldtriangle.size()) != 0) - rebuild = true; - } - - if(oldcurve_keys.size() != mesh->curve_keys.size()) - rebuild = true; - else if(oldcurve_keys.size()) { - if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float3)*oldcurve_keys.size()) != 0) - rebuild = true; - } - - if(oldcurve_radius.size() != mesh->curve_radius.size()) - rebuild = true; - else if(oldcurve_radius.size()) { - if(memcmp(&oldcurve_radius[0], &mesh->curve_radius[0], sizeof(float)*oldcurve_radius.size()) != 0) - rebuild = true; - } + bool rebuild = (oldtriangles != mesh->triangles) || + (oldsubd_faces != mesh->subd_faces) || + (oldsubd_face_corners != mesh->subd_face_corners) || + (oldcurve_keys != mesh->curve_keys) || + (oldcurve_radius != mesh->curve_radius); mesh->tag_update(scene, rebuild); diff --git a/intern/cycles/util/util_vector.h b/intern/cycles/util/util_vector.h index 67bf82b47a5..625c19c7c46 100644 --- a/intern/cycles/util/util_vector.h +++ b/intern/cycles/util/util_vector.h @@ -162,6 +162,11 @@ public: return memcmp(data_, other.data_, datasize_*sizeof(T)) == 0; } + bool operator!=(const array& other) const + { + return !(*this == other); + } + void steal_data(array& from) { if(this != &from) { From c4a4d20d3ddc9e1791fca89f76f14b0ee94b827b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 26 Jan 2018 07:54:09 +0100 Subject: [PATCH 08/16] Fix part of T53080: all material previews re-rendering after undo. This reverts commit dc2617130b2e1d7d2b9892fbd7c6e7b60caafb66, which disabled writing of previews for undo. While this uses some memory, re-rendering all previews is very expensive, especially if for example you have lots of materials using high-res image textures. --- source/blender/blenloader/intern/writefile.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index d7d2dd529f9..c2820ac6e30 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -679,8 +679,10 @@ static void write_iddata(void *wd, const ID *id) static void write_previews(WriteData *wd, const PreviewImage *prv_orig) { - /* Never write previews when doing memsave (i.e. undo/redo)! */ - if (prv_orig && !wd->current) { + /* Note we write previews also for undo steps. It takes up some memory, + * but not doing so would causes all previews to be re-rendered after + * undo which is too expensive. */ + if (prv_orig) { PreviewImage prv = *prv_orig; /* don't write out large previews if not requested */ From 009ce8f3f411f4d9de4f0287f8aaba34fa4fc718 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 26 Jan 2018 08:39:38 +0100 Subject: [PATCH 09/16] Fix harmlness RNA warning in image texture node drawing. --- source/blender/editors/space_node/drawnode.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 2d1a2de9b2d..bcf06f117aa 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -683,7 +683,8 @@ static void node_common_set_butfunc(bNodeType *ntype) /* ****************** BUTTON CALLBACKS FOR SHADER NODES ***************** */ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr, - PointerRNA *imaptr, PointerRNA *iuserptr) + PointerRNA *imaptr, PointerRNA *iuserptr, + bool compositor) { uiLayout *col; int source; @@ -718,7 +719,8 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr, uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE); } - if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER && + if (compositor && + RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER && RNA_boolean_get(ptr, "has_layers")) { col = uiLayoutColumn(layout, false); @@ -842,7 +844,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA /* note: image user properties used directly here, unlike compositor image node, * which redefines them in the node struct RNA to get proper updates. */ - node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); + node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); } static void node_shader_buts_tex_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -861,7 +863,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); - node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); + node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); @@ -1311,7 +1313,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA * imaptr = RNA_pointer_get(ptr, "image"); - node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr); + node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true); node_buts_image_views(layout, C, ptr, &imaptr); } From c528b9b7777322c2b714aaa0bec40a1f3997ad06 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 26 Jan 2018 14:59:16 +0100 Subject: [PATCH 10/16] Fix T53003: IMB: Invalid framerate handling due to short integer overflow. FFMPEG uses int for the numerator, while Blender uses a short. So in cases people gave weird exotic framerate values and we cannot reduce enough the numerator, we'd get totally weird values (even negative frame rates sometimes!) Now we add checks for short overflow and approximate as best as possible in that case (error should not matter unless you have shots of at least several hundreds of hours ;) ). --- source/blender/imbuf/intern/IMB_anim.h | 4 ++-- source/blender/imbuf/intern/anim_movie.c | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index b10ae4f6fe9..c4c4f4405a5 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -99,8 +99,8 @@ struct anim { int curtype; int curposition; /* index 0 = 1e, 1 = 2e, enz. */ int duration; - short frs_sec; - float frs_sec_base; + int frs_sec; + double frs_sec_base; int x, y; /* for number */ diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 25b0c0d7b1a..4f535a26c3b 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -55,6 +55,7 @@ #include #include #include +#include #ifndef _WIN32 #include #else @@ -1365,15 +1366,28 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc) bool IMB_anim_get_fps(struct anim *anim, short *frs_sec, float *frs_sec_base, bool no_av_base) { + double frs_sec_base_double; if (anim->frs_sec) { - *frs_sec = anim->frs_sec; - *frs_sec_base = anim->frs_sec_base; + if (anim->frs_sec > SHRT_MAX) { + /* We cannot store original rational in our short/float format, + * we need to approximate it as best as we can... */ + *frs_sec = SHRT_MAX; + frs_sec_base_double = anim->frs_sec_base * (double)SHRT_MAX / (double)anim->frs_sec; + } + else { + *frs_sec = anim->frs_sec; + frs_sec_base_double = anim->frs_sec_base; + } #ifdef WITH_FFMPEG if (no_av_base) { - *frs_sec_base /= AV_TIME_BASE; + *frs_sec_base = (float)(frs_sec_base_double / AV_TIME_BASE); + } + else { + *frs_sec_base = (float)frs_sec_base_double; } #else UNUSED_VARS(no_av_base); + *frs_sec_base = (float)frs_sec_base_double; #endif return true; } From 567afcca20215770a7eaefa04052b0a41c682fcb Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 26 Jan 2018 15:08:58 +0100 Subject: [PATCH 11/16] Related to T53003: tweak scene fps range. Move restricted 'reasonable' range to ui_range, and allow wider values for manual settings. --- source/blender/makesrna/intern/rna_scene.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index fda92ff7c0d..e6ba459a406 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5889,14 +5889,16 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "fps", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "frs_sec"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 1, 120); + RNA_def_property_range(prop, 1, SHRT_MAX); + RNA_def_property_ui_range(prop, 1, 120, 1, -1); RNA_def_property_ui_text(prop, "FPS", "Framerate, expressed in frames per second"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update"); prop = RNA_def_property(srna, "fps_base", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "frs_sec_base"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 0.1f, 120.0f); + RNA_def_property_range(prop, 1e-5f, 1e6f); + RNA_def_property_ui_range(prop, 0.1f, 120.0f, 2, -1); RNA_def_property_ui_text(prop, "FPS Base", "Framerate base"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update"); From 47a3bbcc34185684813ba21d808f124c584a93ae Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 26 Jan 2018 15:13:35 +0100 Subject: [PATCH 12/16] IMB: Add asserts that returned fps and fps base are strictly positives. Forgot to add that in previous commit, also related to T53003. --- source/blender/imbuf/intern/anim_movie.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 4f535a26c3b..5472cae3ef2 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -1389,6 +1389,9 @@ bool IMB_anim_get_fps(struct anim *anim, UNUSED_VARS(no_av_base); *frs_sec_base = (float)frs_sec_base_double; #endif + BLI_assert(*frs_sec > 0); + BLI_assert(*frs_sec_base > 0.0f); + return true; } return false; From ce4915cddb08860f06ccc6a8ce7a7118441674ec Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 26 Jan 2018 14:09:55 +0100 Subject: [PATCH 13/16] Code refactor: store RGB BSSRDF in a single closure. Previously we stored each color channel in a single closure, which was convenient for sampling a closure and channel together. But this doesn't work so well for algorithms where we want to render multiple color channels together. --- intern/cycles/kernel/closure/bssrdf.h | 83 +++++++++++++------ intern/cycles/kernel/kernel_path_branched.h | 2 +- intern/cycles/kernel/kernel_subsurface.h | 48 +++++------ intern/cycles/kernel/osl/osl_bssrdf.cpp | 32 +------ .../kernel/split/kernel_subsurface_scatter.h | 2 +- intern/cycles/kernel/svm/svm_closure.h | 66 ++------------- 6 files changed, 93 insertions(+), 140 deletions(-) diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h index ec10e452148..383c168463b 100644 --- a/intern/cycles/kernel/closure/bssrdf.h +++ b/intern/cycles/kernel/closure/bssrdf.h @@ -22,11 +22,10 @@ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct Bssrdf { SHADER_CLOSURE_BASE; - float radius; + float3 radius; + float3 albedo; float sharpness; - float d; float texture_blur; - float albedo; float roughness; } Bssrdf; @@ -200,7 +199,7 @@ ccl_device_inline float bssrdf_burley_fitting(float A) /* Scale mean free path length so it gives similar looking result * to Cubic and Gaussian models. */ -ccl_device_inline float bssrdf_burley_compatible_mfp(float r) +ccl_device_inline float3 bssrdf_burley_compatible_mfp(float3 r) { return 0.25f * M_1_PI_F * r; } @@ -208,13 +207,14 @@ ccl_device_inline float bssrdf_burley_compatible_mfp(float r) ccl_device void bssrdf_burley_setup(Bssrdf *bssrdf) { /* Mean free path length. */ - const float l = bssrdf_burley_compatible_mfp(bssrdf->radius); + const float3 l = bssrdf_burley_compatible_mfp(bssrdf->radius); /* Surface albedo. */ - const float A = bssrdf->albedo; - const float s = bssrdf_burley_fitting(A); - const float d = l / s; + const float3 A = bssrdf->albedo; + const float3 s = make_float3(bssrdf_burley_fitting(A.x), + bssrdf_burley_fitting(A.y), + bssrdf_burley_fitting(A.z)); - bssrdf->d = d; + bssrdf->radius = l / s; } ccl_device float bssrdf_burley_eval(const float d, float r) @@ -345,7 +345,7 @@ ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight) ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type) { - if(bssrdf->radius < BSSRDF_MIN_RADIUS) { + if(max3(bssrdf->radius) < BSSRDF_MIN_RADIUS) { /* revert to diffuse BSDF if radius too small */ int flag; #ifdef __PRINCIPLED__ @@ -393,25 +393,60 @@ ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type) ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float *h) { const Bssrdf *bssrdf = (const Bssrdf*)sc; + float radius; - if(sc->type == CLOSURE_BSSRDF_CUBIC_ID) - bssrdf_cubic_sample(bssrdf->radius, bssrdf->sharpness, xi, r, h); - else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID) - bssrdf_gaussian_sample(bssrdf->radius, xi, r, h); - else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID || sc->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ - bssrdf_burley_sample(bssrdf->d, xi, r, h); + /* Sample color channel and reuse random number. */ + if(xi < 1.0f/3.0f) { + xi *= 3.0f; + radius = bssrdf->radius.x; + } + else if(xi < 2.0f/3.0f) { + xi = (xi - 1.0f/3.0f)*3.0f; + radius = bssrdf->radius.y; + } + else { + xi = (xi - 2.0f/3.0f)*3.0f; + radius = bssrdf->radius.z; + } + + /* Sample BSSRDF. */ + if(bssrdf->type == CLOSURE_BSSRDF_CUBIC_ID) { + bssrdf_cubic_sample(radius, bssrdf->sharpness, xi, r, h); + } + else if(bssrdf->type == CLOSURE_BSSRDF_GAUSSIAN_ID){ + bssrdf_gaussian_sample(radius, xi, r, h); + } + else { /*if(bssrdf->type == CLOSURE_BSSRDF_BURLEY_ID || bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ + bssrdf_burley_sample(radius, xi, r, h); + } +} + +ccl_device float bssrdf_channel_pdf(const Bssrdf *bssrdf, float radius, float r) +{ + if(bssrdf->type == CLOSURE_BSSRDF_CUBIC_ID) { + return bssrdf_cubic_pdf(radius, bssrdf->sharpness, r); + } + else if(bssrdf->type == CLOSURE_BSSRDF_GAUSSIAN_ID) { + return bssrdf_gaussian_pdf(radius, r); + } + else { /*if(bssrdf->type == CLOSURE_BSSRDF_BURLEY_ID || bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ + return bssrdf_burley_pdf(radius, r); + } +} + +ccl_device_forceinline float3 bssrdf_eval(const ShaderClosure *sc, float r) +{ + const Bssrdf *bssrdf = (const Bssrdf*)sc; + + return make_float3( + bssrdf_channel_pdf(bssrdf, bssrdf->radius.x, r), + bssrdf_channel_pdf(bssrdf, bssrdf->radius.y, r), + bssrdf_channel_pdf(bssrdf, bssrdf->radius.z, r)); } ccl_device_forceinline float bssrdf_pdf(const ShaderClosure *sc, float r) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - - if(sc->type == CLOSURE_BSSRDF_CUBIC_ID) - return bssrdf_cubic_pdf(bssrdf->radius, bssrdf->sharpness, r); - else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID) - return bssrdf_gaussian_pdf(bssrdf->radius, r); - else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID || sc->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ - return bssrdf_burley_pdf(bssrdf->d, r); + return average(bssrdf_eval(sc, r)); } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index 63fe7822e2a..fe2a7d179a4 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -333,7 +333,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, /* set up random number generator */ uint lcg_state = lcg_state_init(state, 0x68bc21eb); - int num_samples = kernel_data.integrator.subsurface_samples; + int num_samples = kernel_data.integrator.subsurface_samples * 3; float num_samples_inv = 1.0f/num_samples; uint bssrdf_rng_hash = cmj_hash(state->rng_hash, i); diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index c79992ee99b..582a20704d3 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -23,11 +23,6 @@ CCL_NAMESPACE_BEGIN * */ -/* TODO: - * - test using power heuristic for combing bssrdfs - * - try to reduce one sample model variance - */ - ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd, const ShaderClosure *sc, float disk_r, @@ -63,12 +58,11 @@ ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd, float sample_weight = (all)? 1.0f: sc->sample_weight * sample_weight_inv; /* compute pdf */ - float pdf = bssrdf_pdf(sc, r); - float disk_pdf = bssrdf_pdf(sc, disk_r); + float3 eval = bssrdf_eval(sc, r); + float pdf = bssrdf_pdf(sc, disk_r); - /* TODO power heuristic is not working correct here */ - eval_sum += sc->weight*pdf; //*sample_weight*disk_pdf; - pdf_sum += sample_weight*disk_pdf; //*sample_weight*disk_pdf; + eval_sum += sc->weight * eval; + pdf_sum += sample_weight * pdf; } } @@ -190,20 +184,20 @@ ccl_device_inline int subsurface_scatter_multi_intersect( disk_N = sd->Ng; make_orthonormals(disk_N, &disk_T, &disk_B); - if(disk_u < 0.5f) { + if(disk_v < 0.5f) { pick_pdf_N = 0.5f; pick_pdf_T = 0.25f; pick_pdf_B = 0.25f; - disk_u *= 2.0f; + disk_v *= 2.0f; } - else if(disk_u < 0.75f) { + else if(disk_v < 0.75f) { float3 tmp = disk_N; disk_N = disk_T; disk_T = tmp; pick_pdf_N = 0.25f; pick_pdf_T = 0.5f; pick_pdf_B = 0.25f; - disk_u = (disk_u - 0.5f)*4.0f; + disk_v = (disk_v - 0.5f)*4.0f; } else { float3 tmp = disk_N; @@ -212,15 +206,14 @@ ccl_device_inline int subsurface_scatter_multi_intersect( pick_pdf_N = 0.25f; pick_pdf_T = 0.25f; pick_pdf_B = 0.5f; - disk_u = (disk_u - 0.75f)*4.0f; + disk_v = (disk_v - 0.75f)*4.0f; } /* sample point on disk */ - float phi = M_2PI_F * disk_u; - float disk_r = disk_v; - float disk_height; + float phi = M_2PI_F * disk_v; + float disk_height, disk_r; - bssrdf_sample(sc, disk_r, &disk_r, &disk_height); + bssrdf_sample(sc, disk_u, &disk_r, &disk_height); float3 disk_P = (disk_r*cosf(phi)) * disk_T + (disk_r*sinf(phi)) * disk_B; @@ -359,20 +352,20 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, ccl_a disk_N = sd->Ng; make_orthonormals(disk_N, &disk_T, &disk_B); - if(disk_u < 0.5f) { + if(disk_v < 0.5f) { pick_pdf_N = 0.5f; pick_pdf_T = 0.25f; pick_pdf_B = 0.25f; - disk_u *= 2.0f; + disk_v *= 2.0f; } - else if(disk_u < 0.75f) { + else if(disk_v < 0.75f) { float3 tmp = disk_N; disk_N = disk_T; disk_T = tmp; pick_pdf_N = 0.25f; pick_pdf_T = 0.5f; pick_pdf_B = 0.25f; - disk_u = (disk_u - 0.5f)*4.0f; + disk_v = (disk_v - 0.5f)*4.0f; } else { float3 tmp = disk_N; @@ -381,15 +374,14 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, ccl_a pick_pdf_N = 0.25f; pick_pdf_T = 0.25f; pick_pdf_B = 0.5f; - disk_u = (disk_u - 0.75f)*4.0f; + disk_v = (disk_v - 0.75f)*4.0f; } /* sample point on disk */ - float phi = M_2PI_F * disk_u; - float disk_r = disk_v; - float disk_height; + float phi = M_2PI_F * disk_v; + float disk_height, disk_r; - bssrdf_sample(sc, disk_r, &disk_r, &disk_height); + bssrdf_sample(sc, disk_u, &disk_r, &disk_height); float3 disk_P = (disk_r*cosf(phi)) * disk_T + (disk_r*sinf(phi)) * disk_B; diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp index 27a96720c1e..b79cef244a0 100644 --- a/intern/cycles/kernel/osl/osl_bssrdf.cpp +++ b/intern/cycles/kernel/osl/osl_bssrdf.cpp @@ -72,36 +72,12 @@ public: float texture_blur = params.texture_blur; /* create one closure per color channel */ - Bssrdf *bssrdf = bssrdf_alloc(sd, make_float3(weight.x, 0.0f, 0.0f)); + Bssrdf *bssrdf = bssrdf_alloc(sd, weight); if(bssrdf) { - bssrdf->sample_weight = sample_weight; - bssrdf->radius = radius.x; + bssrdf->sample_weight = sample_weight * 3.0f; + bssrdf->radius = radius; + bssrdf->albedo = albedo; bssrdf->texture_blur = texture_blur; - bssrdf->albedo = albedo.x; - bssrdf->sharpness = sharpness; - bssrdf->N = params.N; - bssrdf->roughness = params.roughness; - sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type); - } - - bssrdf = bssrdf_alloc(sd, make_float3(0.0f, weight.y, 0.0f)); - if(bssrdf) { - bssrdf->sample_weight = sample_weight; - bssrdf->radius = radius.y; - bssrdf->texture_blur = texture_blur; - bssrdf->albedo = albedo.y; - bssrdf->sharpness = sharpness; - bssrdf->N = params.N; - bssrdf->roughness = params.roughness; - sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type); - } - - bssrdf = bssrdf_alloc(sd, make_float3(0.0f, 0.0f, weight.z)); - if(bssrdf) { - bssrdf->sample_weight = sample_weight; - bssrdf->radius = radius.z; - bssrdf->texture_blur = texture_blur; - bssrdf->albedo = albedo.z; bssrdf->sharpness = sharpness; bssrdf->N = params.N; bssrdf->roughness = params.roughness; diff --git a/intern/cycles/kernel/split/kernel_subsurface_scatter.h b/intern/cycles/kernel/split/kernel_subsurface_scatter.h index 5bf7483e9a2..38dd1dc5654 100644 --- a/intern/cycles/kernel/split/kernel_subsurface_scatter.h +++ b/intern/cycles/kernel/split/kernel_subsurface_scatter.h @@ -54,7 +54,7 @@ ccl_device_noinline bool kernel_split_branched_path_subsurface_indirect_light_it branched_state->lcg_state = lcg_state_init_addrspace(&branched_state->path_state, 0x68bc21eb); } - int num_samples = kernel_data.integrator.subsurface_samples; + int num_samples = kernel_data.integrator.subsurface_samples * 3; float num_samples_inv = 1.0f/num_samples; uint bssrdf_rng_hash = cmj_hash(branched_state->path_state.rng_hash, i); diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index 47ebe4288e3..b2fc01f617e 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -191,40 +191,12 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * float texture_blur = 0.0f; /* create one closure per color channel */ - Bssrdf *bssrdf = bssrdf_alloc(sd, make_float3(subsurf_weight.x, 0.0f, 0.0f)); + Bssrdf *bssrdf = bssrdf_alloc(sd, subsurf_weight); if(bssrdf) { - bssrdf->sample_weight = subsurf_sample_weight; - bssrdf->radius = radius.x; + bssrdf->sample_weight = subsurf_sample_weight * 3.0f; + bssrdf->radius = radius; + bssrdf->albedo = subsurface_color; bssrdf->texture_blur = texture_blur; - bssrdf->albedo = subsurface_color.x; - bssrdf->sharpness = sharpness; - bssrdf->N = N; - bssrdf->roughness = roughness; - - /* setup bsdf */ - sd->flag |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_PRINCIPLED_ID); - } - - bssrdf = bssrdf_alloc(sd, make_float3(0.0f, subsurf_weight.y, 0.0f)); - if(bssrdf) { - bssrdf->sample_weight = subsurf_sample_weight; - bssrdf->radius = radius.y; - bssrdf->texture_blur = texture_blur; - bssrdf->albedo = subsurface_color.y; - bssrdf->sharpness = sharpness; - bssrdf->N = N; - bssrdf->roughness = roughness; - - /* setup bsdf */ - sd->flag |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_PRINCIPLED_ID); - } - - bssrdf = bssrdf_alloc(sd, make_float3(0.0f, 0.0f, subsurf_weight.z)); - if(bssrdf) { - bssrdf->sample_weight = subsurf_sample_weight; - bssrdf->radius = radius.z; - bssrdf->texture_blur = texture_blur; - bssrdf->albedo = subsurface_color.z; bssrdf->sharpness = sharpness; bssrdf->N = N; bssrdf->roughness = roughness; @@ -803,34 +775,12 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * float texture_blur = param2; /* create one closure per color channel */ - Bssrdf *bssrdf = bssrdf_alloc(sd, make_float3(weight.x, 0.0f, 0.0f)); + Bssrdf *bssrdf = bssrdf_alloc(sd, weight); if(bssrdf) { - bssrdf->sample_weight = sample_weight; - bssrdf->radius = radius.x; + bssrdf->sample_weight = sample_weight * 3.0f; + bssrdf->radius = radius; + bssrdf->albedo = albedo; bssrdf->texture_blur = texture_blur; - bssrdf->albedo = albedo.x; - bssrdf->sharpness = sharpness; - bssrdf->N = N; - sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type); - } - - bssrdf = bssrdf_alloc(sd, make_float3(0.0f, weight.y, 0.0f)); - if(bssrdf) { - bssrdf->sample_weight = sample_weight; - bssrdf->radius = radius.y; - bssrdf->texture_blur = texture_blur; - bssrdf->albedo = albedo.y; - bssrdf->sharpness = sharpness; - bssrdf->N = N; - sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type); - } - - bssrdf = bssrdf_alloc(sd, make_float3(0.0f, 0.0f, weight.z)); - if(bssrdf) { - bssrdf->sample_weight = sample_weight; - bssrdf->radius = radius.z; - bssrdf->texture_blur = texture_blur; - bssrdf->albedo = albedo.z; bssrdf->sharpness = sharpness; bssrdf->N = N; sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type); From d611cf9233583a04b9168850ddbf708236de44b3 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 26 Jan 2018 18:31:36 +0100 Subject: [PATCH 14/16] Fix mixed BSDF + BSSRDF sampling bug in path tracing, after 095a01a73a35. Spotted by Ha Hyung-jin, thanks! --- intern/cycles/kernel/kernel_shader.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 26d3fcf15b2..5f2f00c5ceb 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -611,6 +611,8 @@ void shader_bsdf_eval(KernelGlobals *kg, ccl_device_inline const ShaderClosure *shader_bsdf_pick(ShaderData *sd, float *randu) { + /* Note the sampling here must match shader_bssrdf_pick, + * since we reuse the same random number. */ int sampled = 0; if(sd->num_closure > 1) { @@ -620,7 +622,7 @@ ccl_device_inline const ShaderClosure *shader_bsdf_pick(ShaderData *sd, for(int i = 0; i < sd->num_closure; i++) { const ShaderClosure *sc = &sd->closure[i]; - if(CLOSURE_IS_BSDF(sc->type)) { + if(CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { sum += sc->sample_weight; } } @@ -631,7 +633,7 @@ ccl_device_inline const ShaderClosure *shader_bsdf_pick(ShaderData *sd, for(int i = 0; i < sd->num_closure; i++) { const ShaderClosure *sc = &sd->closure[i]; - if(CLOSURE_IS_BSDF(sc->type)) { + if(CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { float next_sum = partial_sum + sc->sample_weight; if(r < next_sum) { @@ -648,13 +650,16 @@ ccl_device_inline const ShaderClosure *shader_bsdf_pick(ShaderData *sd, } } - return &sd->closure[sampled]; + const ShaderClosure *sc = &sd->closure[sampled]; + return CLOSURE_IS_BSDF(sc->type)? sc: NULL; } ccl_device_inline const ShaderClosure *shader_bssrdf_pick(ShaderData *sd, ccl_addr_space float3 *throughput, float *randu) { + /* Note the sampling here must match shader_bsdf_pick, + * since we reuse the same random number. */ int sampled = 0; if(sd->num_closure > 1) { @@ -703,7 +708,8 @@ ccl_device_inline const ShaderClosure *shader_bssrdf_pick(ShaderData *sd, } } - return &sd->closure[sampled]; + const ShaderClosure *sc = &sd->closure[sampled]; + return CLOSURE_IS_BSSRDF(sc->type)? sc: NULL; } ccl_device_inline int shader_bsdf_sample(KernelGlobals *kg, From 7b29e917118ffdeb39de5c942dd652d40914dbc3 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 26 Jan 2018 22:11:28 +0100 Subject: [PATCH 15/16] Code refactor: make mixed small/large BSSRDF radii more robust. --- intern/cycles/kernel/closure/bssrdf.h | 108 +++++++++++++++++------- intern/cycles/kernel/osl/osl_bssrdf.cpp | 53 +++++------- intern/cycles/kernel/svm/svm_closure.h | 60 +++++-------- 3 files changed, 116 insertions(+), 105 deletions(-) diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h index 383c168463b..c8f505e8418 100644 --- a/intern/cycles/kernel/closure/bssrdf.h +++ b/intern/cycles/kernel/closure/bssrdf.h @@ -27,6 +27,7 @@ typedef ccl_addr_space struct Bssrdf { float sharpness; float texture_blur; float roughness; + float channels; } Bssrdf; /* Planar Truncated Gaussian @@ -343,42 +344,68 @@ ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight) return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? bssrdf : NULL; } -ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type) +ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type) { - if(max3(bssrdf->radius) < BSSRDF_MIN_RADIUS) { - /* revert to diffuse BSDF if radius too small */ - int flag; + int flag = 0; + int bssrdf_channels = 3; + float3 diffuse_weight = make_float3(0.0f, 0.0f, 0.0f); + + /* Verify if the radii are large enough to sample without precision issues. */ + if(bssrdf->radius.x < BSSRDF_MIN_RADIUS) { + diffuse_weight.x = bssrdf->weight.x; + bssrdf->weight.x = 0.0f; + bssrdf->radius.x = 0.0f; + bssrdf_channels--; + } + if(bssrdf->radius.y < BSSRDF_MIN_RADIUS) { + diffuse_weight.y = bssrdf->weight.y; + bssrdf->weight.y = 0.0f; + bssrdf->radius.y = 0.0f; + bssrdf_channels--; + } + if(bssrdf->radius.z < BSSRDF_MIN_RADIUS) { + diffuse_weight.z = bssrdf->weight.z; + bssrdf->weight.z = 0.0f; + bssrdf->radius.z = 0.0f; + bssrdf_channels--; + } + + if(bssrdf_channels < 3) { + /* Add diffuse BSDF if any radius too small. */ #ifdef __PRINCIPLED__ if(type == CLOSURE_BSSRDF_PRINCIPLED_ID) { float roughness = bssrdf->roughness; float3 N = bssrdf->N; - float3 weight = bssrdf->weight; - float sample_weight = bssrdf->sample_weight; - PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bssrdf; + PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), diffuse_weight); - bsdf->N = N; - bsdf->roughness = roughness; - bsdf->weight = weight; - bsdf->sample_weight = sample_weight; - flag = bsdf_principled_diffuse_setup(bsdf); - bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID; + if(bsdf) { + bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID; + bsdf->N = N; + bsdf->roughness = roughness; + flag |= bsdf_principled_diffuse_setup(bsdf); + } } else #endif /* __PRINCIPLED__ */ { - DiffuseBsdf *bsdf = (DiffuseBsdf*)bssrdf; - bsdf->N = bssrdf->N; - flag = bsdf_diffuse_setup(bsdf); - bsdf->type = CLOSURE_BSDF_BSSRDF_ID; + DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), diffuse_weight); + + if(bsdf) { + bsdf->type = CLOSURE_BSDF_BSSRDF_ID; + bsdf->N = bssrdf->N; + flag |= bsdf_diffuse_setup(bsdf); + } } - - return flag; } - else { + + /* Setup BSSRDF if radius is large enough. */ + if(bssrdf_channels > 0) { + bssrdf->type = type; + bssrdf->channels = bssrdf_channels; + bssrdf->sample_weight = fabsf(average(bssrdf->weight)) * bssrdf->channels; bssrdf->texture_blur = saturate(bssrdf->texture_blur); bssrdf->sharpness = saturate(bssrdf->sharpness); - bssrdf->type = type; if(type == CLOSURE_BSSRDF_BURLEY_ID || type == CLOSURE_BSSRDF_PRINCIPLED_ID) @@ -386,8 +413,14 @@ ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type) bssrdf_burley_setup(bssrdf); } - return SD_BSSRDF; + flag |= SD_BSSRDF; } + else { + bssrdf->type = type; + bssrdf->sample_weight = 0.0f; + } + + return flag; } ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float *h) @@ -395,17 +428,22 @@ ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float const Bssrdf *bssrdf = (const Bssrdf*)sc; float radius; - /* Sample color channel and reuse random number. */ - if(xi < 1.0f/3.0f) { - xi *= 3.0f; - radius = bssrdf->radius.x; + /* Sample color channel and reuse random number. Only a subset of channels + * may be used if their radius was too small to handle as BSSRDF. */ + xi *= bssrdf->channels; + + if(xi < 1.0f) { + radius = (bssrdf->radius.x > 0.0f)? bssrdf->radius.x: + (bssrdf->radius.y > 0.0f)? bssrdf->radius.y: + bssrdf->radius.z; } - else if(xi < 2.0f/3.0f) { - xi = (xi - 1.0f/3.0f)*3.0f; - radius = bssrdf->radius.y; + else if(xi < 2.0f) { + xi -= 1.0f; + radius = (bssrdf->radius.x > 0.0f)? bssrdf->radius.y: + bssrdf->radius.z; } else { - xi = (xi - 2.0f/3.0f)*3.0f; + xi -= 2.0f; radius = bssrdf->radius.z; } @@ -423,7 +461,10 @@ ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float ccl_device float bssrdf_channel_pdf(const Bssrdf *bssrdf, float radius, float r) { - if(bssrdf->type == CLOSURE_BSSRDF_CUBIC_ID) { + if(radius == 0.0f) { + return 0.0f; + } + else if(bssrdf->type == CLOSURE_BSSRDF_CUBIC_ID) { return bssrdf_cubic_pdf(radius, bssrdf->sharpness, r); } else if(bssrdf->type == CLOSURE_BSSRDF_GAUSSIAN_ID) { @@ -446,7 +487,10 @@ ccl_device_forceinline float3 bssrdf_eval(const ShaderClosure *sc, float r) ccl_device_forceinline float bssrdf_pdf(const ShaderClosure *sc, float r) { - return average(bssrdf_eval(sc, r)); + const Bssrdf *bssrdf = (const Bssrdf*)sc; + float3 pdf = bssrdf_eval(sc, r); + + return (pdf.x + pdf.y + pdf.z) / bssrdf->channels; } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp index b79cef244a0..3e7905f26df 100644 --- a/intern/cycles/kernel/osl/osl_bssrdf.cpp +++ b/intern/cycles/kernel/osl/osl_bssrdf.cpp @@ -51,38 +51,27 @@ using namespace OSL; class CBSSRDFClosure : public CClosurePrimitive { public: Bssrdf params; - float3 radius; - float3 albedo; void alloc(ShaderData *sd, int path_flag, float3 weight, ClosureType type) { - float sample_weight = fabsf(average(weight)); + Bssrdf *bssrdf = bssrdf_alloc(sd, weight); - /* disable in case of diffuse ancestor, can't see it well then and - * adds considerably noise due to probabilities of continuing path - * getting lower and lower */ - if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR) { - radius = make_float3(0.0f, 0.0f, 0.0f); - } - - if(sample_weight > CLOSURE_WEIGHT_CUTOFF) { - /* sharpness */ - float sharpness = params.sharpness; - /* texture color blur */ - float texture_blur = params.texture_blur; + if(bssrdf) { + /* disable in case of diffuse ancestor, can't see it well then and + * adds considerably noise due to probabilities of continuing path + * getting lower and lower */ + if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR) { + params.radius = make_float3(0.0f, 0.0f, 0.0f); + } /* create one closure per color channel */ - Bssrdf *bssrdf = bssrdf_alloc(sd, weight); - if(bssrdf) { - bssrdf->sample_weight = sample_weight * 3.0f; - bssrdf->radius = radius; - bssrdf->albedo = albedo; - bssrdf->texture_blur = texture_blur; - bssrdf->sharpness = sharpness; - bssrdf->N = params.N; - bssrdf->roughness = params.roughness; - sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type); - } + bssrdf->radius = params.radius; + bssrdf->albedo = params.albedo; + bssrdf->texture_blur = params.texture_blur; + bssrdf->sharpness = params.sharpness; + bssrdf->N = params.N; + bssrdf->roughness = params.roughness; + sd->flag |= bssrdf_setup(sd, bssrdf, (ClosureType)type); } } }; @@ -101,7 +90,7 @@ ClosureParam *closure_bssrdf_cubic_params() { static ClosureParam params[] = { CLOSURE_FLOAT3_PARAM(CubicBSSRDFClosure, params.N), - CLOSURE_FLOAT3_PARAM(CubicBSSRDFClosure, radius), + CLOSURE_FLOAT3_PARAM(CubicBSSRDFClosure, params.radius), CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, params.texture_blur), CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, params.sharpness), CLOSURE_STRING_KEYPARAM(CubicBSSRDFClosure, label, "label"), @@ -126,7 +115,7 @@ ClosureParam *closure_bssrdf_gaussian_params() { static ClosureParam params[] = { CLOSURE_FLOAT3_PARAM(GaussianBSSRDFClosure, params.N), - CLOSURE_FLOAT3_PARAM(GaussianBSSRDFClosure, radius), + CLOSURE_FLOAT3_PARAM(GaussianBSSRDFClosure, params.radius), CLOSURE_FLOAT_PARAM(GaussianBSSRDFClosure, params.texture_blur), CLOSURE_STRING_KEYPARAM(GaussianBSSRDFClosure, label, "label"), CLOSURE_FINISH_PARAM(GaussianBSSRDFClosure) @@ -150,9 +139,9 @@ ClosureParam *closure_bssrdf_burley_params() { static ClosureParam params[] = { CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, params.N), - CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, radius), + CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, params.radius), CLOSURE_FLOAT_PARAM(BurleyBSSRDFClosure, params.texture_blur), - CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, albedo), + CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, params.albedo), CLOSURE_STRING_KEYPARAM(BurleyBSSRDFClosure, label, "label"), CLOSURE_FINISH_PARAM(BurleyBSSRDFClosure) }; @@ -175,9 +164,9 @@ ClosureParam *closure_bssrdf_principled_params() { static ClosureParam params[] = { CLOSURE_FLOAT3_PARAM(PrincipledBSSRDFClosure, params.N), - CLOSURE_FLOAT3_PARAM(PrincipledBSSRDFClosure, radius), + CLOSURE_FLOAT3_PARAM(PrincipledBSSRDFClosure, params.radius), CLOSURE_FLOAT_PARAM(PrincipledBSSRDFClosure, params.texture_blur), - CLOSURE_FLOAT3_PARAM(PrincipledBSSRDFClosure, albedo), + CLOSURE_FLOAT3_PARAM(PrincipledBSSRDFClosure, params.albedo), CLOSURE_FLOAT_PARAM(PrincipledBSSRDFClosure, params.roughness), CLOSURE_STRING_KEYPARAM(PrincipledBSSRDFClosure, label, "label"), CLOSURE_FINISH_PARAM(PrincipledBSSRDFClosure) diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index b2fc01f617e..5a5cf2db401 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -153,7 +153,6 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * #ifdef __SUBSURFACE__ float3 mixed_ss_base_color = subsurface_color * subsurface + base_color * (1.0f - subsurface); float3 subsurf_weight = weight * mixed_ss_base_color * diffuse_weight; - float subsurf_sample_weight = fabsf(average(subsurf_weight)); /* disable in case of diffuse ancestor, can't see it well then and * adds considerably noise due to probabilities of continuing path @@ -182,27 +181,19 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * sd->flag |= bsdf_principled_diffuse_setup(bsdf); } } - else if(subsurface > CLOSURE_WEIGHT_CUTOFF && subsurf_sample_weight > CLOSURE_WEIGHT_CUTOFF) { - /* radius * scale */ - float3 radius = subsurface_radius * subsurface; - /* sharpness */ - float sharpness = 0.0f; - /* texture color blur */ - float texture_blur = 0.0f; - - /* create one closure per color channel */ + else if(subsurface > CLOSURE_WEIGHT_CUTOFF) { Bssrdf *bssrdf = bssrdf_alloc(sd, subsurf_weight); + if(bssrdf) { - bssrdf->sample_weight = subsurf_sample_weight * 3.0f; - bssrdf->radius = radius; + bssrdf->radius = subsurface_radius * subsurface; bssrdf->albedo = subsurface_color; - bssrdf->texture_blur = texture_blur; - bssrdf->sharpness = sharpness; + bssrdf->texture_blur = 0.0f; + bssrdf->sharpness = 0.0f; bssrdf->N = N; bssrdf->roughness = roughness; /* setup bsdf */ - sd->flag |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_PRINCIPLED_ID); + sd->flag |= bssrdf_setup(sd, bssrdf, (ClosureType)CLOSURE_BSSRDF_PRINCIPLED_ID); } } } @@ -756,35 +747,22 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * case CLOSURE_BSSRDF_CUBIC_ID: case CLOSURE_BSSRDF_GAUSSIAN_ID: case CLOSURE_BSSRDF_BURLEY_ID: { - float3 albedo = sd->svm_closure_weight; float3 weight = sd->svm_closure_weight * mix_weight; - float sample_weight = fabsf(average(weight)); - - /* disable in case of diffuse ancestor, can't see it well then and - * adds considerably noise due to probabilities of continuing path - * getting lower and lower */ - if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR) - param1 = 0.0f; + Bssrdf *bssrdf = bssrdf_alloc(sd, weight); - if(sample_weight > CLOSURE_WEIGHT_CUTOFF) { - /* radius * scale */ - float3 radius = stack_load_float3(stack, data_node.z)*param1; - /* sharpness */ - float sharpness = stack_load_float(stack, data_node.w); - /* texture color blur */ - float texture_blur = param2; + if(bssrdf) { + /* disable in case of diffuse ancestor, can't see it well then and + * adds considerably noise due to probabilities of continuing path + * getting lower and lower */ + if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR) + param1 = 0.0f; - /* create one closure per color channel */ - Bssrdf *bssrdf = bssrdf_alloc(sd, weight); - if(bssrdf) { - bssrdf->sample_weight = sample_weight * 3.0f; - bssrdf->radius = radius; - bssrdf->albedo = albedo; - bssrdf->texture_blur = texture_blur; - bssrdf->sharpness = sharpness; - bssrdf->N = N; - sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type); - } + bssrdf->radius = stack_load_float3(stack, data_node.z)*param1; + bssrdf->albedo = sd->svm_closure_weight; + bssrdf->texture_blur = param2; + bssrdf->sharpness = stack_load_float(stack, data_node.w); + bssrdf->N = N; + sd->flag |= bssrdf_setup(sd, bssrdf, (ClosureType)type); } break; From 3c852ba0741f794a697f95073b04921e9ff94039 Mon Sep 17 00:00:00 2001 From: Stefan Werner Date: Sat, 27 Jan 2018 10:36:22 +0100 Subject: [PATCH 16/16] Fix T53914: Volumetric scattering now goes correctly through transparent surfaces. There was a check for volume bounces at every surface intersection. That could lead to a volume scattered path being terminated when passing through a transparent surface. This check was superfluous, as the volume shader evaluation already checks the number of volume bounces and once it passes the max, volume shaders will not return scatter events any more. Reviewers: #cycles, brecht Reviewed By: #cycles, brecht Subscribers: brecht, #cycles Tags: #cycles Maniphest Tasks: T53914 Differential Revision: https://developer.blender.org/D3024 --- intern/cycles/kernel/kernel_path_state.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h index 2ae866bb051..e5e915791cb 100644 --- a/intern/cycles/kernel/kernel_path_state.h +++ b/intern/cycles/kernel/kernel_path_state.h @@ -179,13 +179,13 @@ ccl_device_inline float path_state_continuation_probability(KernelGlobals *kg, #endif } else { - /* Test max bounces for various ray types. */ + /* Test max bounces for various ray types. + The check for max_volume_bounce doesn't happen here but inside volume_shader_sample(). + See T53914. + */ if((state->bounce >= kernel_data.integrator.max_bounce) || (state->diffuse_bounce >= kernel_data.integrator.max_diffuse_bounce) || (state->glossy_bounce >= kernel_data.integrator.max_glossy_bounce) || -#ifdef __VOLUME__ - (state->volume_bounce >= kernel_data.integrator.max_volume_bounce) || -#endif (state->transmission_bounce >= kernel_data.integrator.max_transmission_bounce)) { return 0.0f;