From 1162ba206dd7792414d3ae716877ba1383de8dab Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 7 Mar 2020 14:38:52 +0100 Subject: Cycles: change volume step size controls, auto adjust based on voxel size By default it will now set the step size to the voxel size for smoke and volume objects, and 1/10th the bounding box for procedural volume shaders. New settings are: * Scene render/preview step rate: to globally adjust detail and performance * Material step rate: multiplied with auto detected per-object step size * World step size: distance to steo for world shader Differential Revision: https://developer.blender.org/D1777 --- intern/cycles/blender/addon/properties.py | 36 +++++++++++--- intern/cycles/blender/addon/ui.py | 16 ++++-- intern/cycles/blender/blender_shader.cpp | 2 + intern/cycles/blender/blender_sync.cpp | 3 +- intern/cycles/kernel/geom/geom_object.h | 11 +++++ intern/cycles/kernel/kernel_path.h | 8 +-- intern/cycles/kernel/kernel_path_branched.h | 6 +-- intern/cycles/kernel/kernel_textures.h | 1 + intern/cycles/kernel/kernel_types.h | 10 ++-- intern/cycles/kernel/kernel_volume.h | 51 ++++++++++++------- intern/cycles/kernel/split/kernel_do_volume.h | 8 +-- intern/cycles/render/background.cpp | 4 ++ intern/cycles/render/background.h | 2 + intern/cycles/render/integrator.cpp | 4 +- intern/cycles/render/integrator.h | 2 +- intern/cycles/render/object.cpp | 71 +++++++++++++++++++++++++++ intern/cycles/render/object.h | 3 ++ intern/cycles/render/osl.cpp | 8 ++- intern/cycles/render/scene.cpp | 1 + intern/cycles/render/scene.h | 1 + intern/cycles/render/shader.cpp | 18 ++++--- intern/cycles/render/shader.h | 4 +- intern/cycles/render/svm.cpp | 8 ++- 23 files changed, 212 insertions(+), 66 deletions(-) (limited to 'intern') diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index cd72da128aa..c91e210bbd8 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -444,13 +444,20 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): default=8, ) - volume_step_size: FloatProperty( - name="Step Size", - description="Distance between volume shader samples when rendering the volume " - "(lower values give more accurate and detailed results, but also increased render time)", - default=0.1, - min=0.0000001, max=100000.0, soft_min=0.01, soft_max=1.0, precision=4, - unit='LENGTH' + volume_step_rate: FloatProperty( + name="Step Rate", + description="Globally adjust detail for volume rendering, on top of automatically estimated step size. " + "Higher values reduce render time, lower values render with more detail", + default=1.0, + min=0.01, max=100.0, soft_min=0.1, soft_max=10.0, precision=2 + ) + + volume_preview_step_rate: FloatProperty( + name="Step Rate", + description="Globally adjust detail for volume rendering, on top of automatically estimated step size. " + "Higher values reduce render time, lower values render with more detail", + default=1.0, + min=0.01, max=100.0, soft_min=0.1, soft_max=10.0, precision=2 ) volume_max_steps: IntProperty( @@ -934,6 +941,14 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup): default='LINEAR', ) + volume_step_rate: FloatProperty( + name="Step Rate", + description="Scale the distance between volume shader samples when rendering the volume " + "(lower values give more accurate and detailed results, but also increased render time)", + default=1.0, + min=0.001, max=1000.0, soft_min=0.1, soft_max=10.0, precision=4 + ) + displacement_method: EnumProperty( name="Displacement Method", description="Method to use for the displacement", @@ -1044,6 +1059,13 @@ class CyclesWorldSettings(bpy.types.PropertyGroup): items=enum_volume_interpolation, default='LINEAR', ) + volume_step_size: FloatProperty( + name="Step Size", + description="Distance between volume shader samples when rendering the volume " + "(lower values give more accurate and detailed results, but also increased render time)", + default=1.0, + min=0.0000001, max=100000.0, soft_min=0.1, soft_max=100.0, precision=4 + ) @classmethod def register(cls): diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index e545d436c85..5f994faa435 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -373,7 +373,7 @@ class CYCLES_RENDER_PT_subdivision(CyclesButtonsPanel, Panel): col = layout.column() sub = col.column(align=True) sub.prop(cscene, "dicing_rate", text="Dicing Rate Render") - sub.prop(cscene, "preview_dicing_rate", text="Preview") + sub.prop(cscene, "preview_dicing_rate", text="Viewport") col.separator() @@ -428,9 +428,11 @@ class CYCLES_RENDER_PT_volumes(CyclesButtonsPanel, Panel): scene = context.scene cscene = scene.cycles - col = layout.column() - col.prop(cscene, "volume_step_size", text="Step Size") - col.prop(cscene, "volume_max_steps", text="Max Steps") + col = layout.column(align=True) + col.prop(cscene, "volume_step_rate", text="Step Rate Render") + col.prop(cscene, "volume_preview_step_rate", text="Viewport") + + layout.prop(cscene, "volume_max_steps", text="Max Steps") class CYCLES_RENDER_PT_light_paths(CyclesButtonsPanel, Panel): @@ -1696,6 +1698,9 @@ class CYCLES_WORLD_PT_settings_volume(CyclesButtonsPanel, Panel): sub.prop(cworld, "volume_sampling", text="Sampling") col.prop(cworld, "volume_interpolation", text="Interpolation") col.prop(cworld, "homogeneous_volume", text="Homogeneous") + sub = col.column() + sub.active = not cworld.homogeneous_volume + sub.prop(cworld, "volume_step_size") class CYCLES_MATERIAL_PT_preview(CyclesButtonsPanel, Panel): @@ -1827,6 +1832,9 @@ class CYCLES_MATERIAL_PT_settings_volume(CyclesButtonsPanel, Panel): sub.prop(cmat, "volume_sampling", text="Sampling") col.prop(cmat, "volume_interpolation", text="Interpolation") col.prop(cmat, "homogeneous_volume", text="Homogeneous") + sub = col.column() + sub.active = not cmat.homogeneous_volume + sub.prop(cmat, "volume_step_rate") def draw(self, context): self.draw_shared(self, context, context.material) diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index dc226805664..59c1539d207 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -1260,6 +1260,7 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all) shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume"); shader->volume_sampling_method = get_volume_sampling(cmat); shader->volume_interpolation_method = get_volume_interpolation(cmat); + shader->volume_step_rate = get_float(cmat, "volume_step_rate"); shader->displacement_method = get_displacement_method(cmat); shader->set_graph(graph); @@ -1324,6 +1325,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, shader->heterogeneous_volume = !get_boolean(cworld, "homogeneous_volume"); shader->volume_sampling_method = get_volume_sampling(cworld); shader->volume_interpolation_method = get_volume_interpolation(cworld); + shader->volume_step_rate = get_float(cworld, "volume_step_size"); } else if (new_viewport_parameters.use_scene_world && b_world) { BackgroundNode *background = new BackgroundNode(); diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 3d932825ae7..9f7797efb97 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -262,7 +262,8 @@ void BlenderSync::sync_integrator() integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces"); integrator->volume_max_steps = get_int(cscene, "volume_max_steps"); - integrator->volume_step_size = get_float(cscene, "volume_step_size"); + integrator->volume_step_rate = (preview) ? get_float(cscene, "volume_preview_step_rate") : + get_float(cscene, "volume_step_rate"); integrator->caustics_reflective = get_boolean(cscene, "caustics_reflective"); integrator->caustics_refractive = get_boolean(cscene, "caustics_refractive"); diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h index ac2ddf575ca..c6d02ed9702 100644 --- a/intern/cycles/kernel/geom/geom_object.h +++ b/intern/cycles/kernel/geom/geom_object.h @@ -320,6 +320,17 @@ ccl_device_inline uint object_patch_map_offset(KernelGlobals *kg, int object) return kernel_tex_fetch(__objects, object).patch_map_offset; } +/* Volume step size */ + +ccl_device_inline float object_volume_step_size(KernelGlobals *kg, int object) +{ + if (object == OBJECT_NONE) { + return kernel_data.background.volume_step_size; + } + + return kernel_tex_fetch(__object_volume_step, object); +} + /* Pass ID for shader */ ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd) diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 74377f2c069..db35303e3f1 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -171,19 +171,19 @@ ccl_device_forceinline VolumeIntegrateResult kernel_path_volume(KernelGlobals *k Ray volume_ray = *ray; volume_ray.t = (hit) ? isect->t : FLT_MAX; - bool heterogeneous = volume_stack_is_heterogeneous(kg, state->volume_stack); + float step_size = volume_stack_step_size(kg, state->volume_stack); # ifdef __VOLUME_DECOUPLED__ int sampling_method = volume_stack_sampling_method(kg, state->volume_stack); bool direct = (state->flag & PATH_RAY_CAMERA) != 0; - bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, direct, sampling_method); + bool decoupled = kernel_volume_use_decoupled(kg, step_size, direct, sampling_method); if (decoupled) { /* cache steps along volume for repeated sampling */ VolumeSegment volume_segment; shader_setup_from_volume(kg, sd, &volume_ray); - kernel_volume_decoupled_record(kg, state, &volume_ray, sd, &volume_segment, heterogeneous); + kernel_volume_decoupled_record(kg, state, &volume_ray, sd, &volume_segment, step_size); volume_segment.sampling_method = sampling_method; @@ -229,7 +229,7 @@ ccl_device_forceinline VolumeIntegrateResult kernel_path_volume(KernelGlobals *k { /* integrate along volume segment with distance sampling */ VolumeIntegrateResult result = kernel_volume_integrate( - kg, state, sd, &volume_ray, L, throughput, heterogeneous); + kg, state, sd, &volume_ray, L, throughput, step_size); # ifdef __VOLUME_SCATTER__ if (result == VOLUME_PATH_SCATTERED) { diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index 0d5781fe3d1..337c4fb1d10 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -91,7 +91,7 @@ ccl_device_forceinline void kernel_branched_path_volume(KernelGlobals *kg, Ray volume_ray = *ray; volume_ray.t = (hit) ? isect->t : FLT_MAX; - bool heterogeneous = volume_stack_is_heterogeneous(kg, state->volume_stack); + float step_size = volume_stack_step_size(kg, state->volume_stack); # ifdef __VOLUME_DECOUPLED__ /* decoupled ray marching only supported on CPU */ @@ -100,7 +100,7 @@ ccl_device_forceinline void kernel_branched_path_volume(KernelGlobals *kg, VolumeSegment volume_segment; shader_setup_from_volume(kg, sd, &volume_ray); - kernel_volume_decoupled_record(kg, state, &volume_ray, sd, &volume_segment, heterogeneous); + kernel_volume_decoupled_record(kg, state, &volume_ray, sd, &volume_segment, step_size); /* direct light sampling */ if (volume_segment.closure_flag & SD_SCATTER) { @@ -171,7 +171,7 @@ ccl_device_forceinline void kernel_branched_path_volume(KernelGlobals *kg, path_state_branch(&ps, j, num_samples); VolumeIntegrateResult result = kernel_volume_integrate( - kg, &ps, sd, &volume_ray, L, &tp, heterogeneous); + kg, &ps, sd, &volume_ray, L, &tp, step_size); # ifdef __VOLUME_SCATTER__ if (result == VOLUME_PATH_SCATTERED) { diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 1cae34348c9..c8e01677d09 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -35,6 +35,7 @@ KERNEL_TEX(KernelObject, __objects) KERNEL_TEX(Transform, __object_motion_pass) KERNEL_TEX(DecomposedTransform, __object_motion) KERNEL_TEX(uint, __object_flag) +KERNEL_TEX(float, __object_volume_step) /* cameras */ KERNEL_TEX(DecomposedTransform, __camera_motion) diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index c5be93e2cda..6a0e74efc91 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -887,13 +887,13 @@ enum ShaderDataFlag { SD_HAS_DISPLACEMENT = (1 << 26), /* Has constant emission (value stored in __shaders) */ SD_HAS_CONSTANT_EMISSION = (1 << 27), - /* Needs to access attributes */ - SD_NEED_ATTRIBUTES = (1 << 28), + /* Needs to access attributes for volume rendering */ + SD_NEED_VOLUME_ATTRIBUTES = (1 << 28), SD_SHADER_FLAGS = (SD_USE_MIS | SD_HAS_TRANSPARENT_SHADOW | SD_HAS_VOLUME | SD_HAS_ONLY_VOLUME | SD_HETEROGENEOUS_VOLUME | SD_HAS_BSSRDF_BUMP | SD_VOLUME_EQUIANGULAR | SD_VOLUME_MIS | SD_VOLUME_CUBIC | SD_HAS_BUMP | SD_HAS_DISPLACEMENT | - SD_HAS_CONSTANT_EMISSION | SD_NEED_ATTRIBUTES) + SD_HAS_CONSTANT_EMISSION | SD_NEED_VOLUME_ATTRIBUTES) }; /* Object flags. */ @@ -1275,6 +1275,7 @@ typedef struct KernelBackground { /* only shader index */ int surface_shader; int volume_shader; + float volume_step_size; int transparent; float transparent_roughness_squared_threshold; @@ -1282,7 +1283,6 @@ typedef struct KernelBackground { float ao_factor; float ao_distance; float ao_bounces_factor; - float ao_pad; } KernelBackground; static_assert_align(KernelBackground, 16); @@ -1355,7 +1355,7 @@ typedef struct KernelIntegrator { /* volume render */ int use_volumes; int volume_max_steps; - float volume_step_size; + float volume_step_rate; int volume_samples; int start_sample; diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index f443bb88463..035fcdbc8e1 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -101,15 +101,19 @@ ccl_device float kernel_volume_channel_get(float3 value, int channel) #ifdef __VOLUME__ -ccl_device bool volume_stack_is_heterogeneous(KernelGlobals *kg, ccl_addr_space VolumeStack *stack) +ccl_device float volume_stack_step_size(KernelGlobals *kg, ccl_addr_space VolumeStack *stack) { + float step_size = FLT_MAX; + for (int i = 0; stack[i].shader != SHADER_NONE; i++) { int shader_flag = kernel_tex_fetch(__shaders, (stack[i].shader & SHADER_MASK)).flags; + bool heterogeneous = false; + if (shader_flag & SD_HETEROGENEOUS_VOLUME) { - return true; + heterogeneous = true; } - else if (shader_flag & SD_NEED_ATTRIBUTES) { + else if (shader_flag & SD_NEED_VOLUME_ATTRIBUTES) { /* We want to render world or objects without any volume grids * as homogeneous, but can only verify this at run-time since other * heterogeneous volume objects may be using the same shader. */ @@ -117,13 +121,19 @@ ccl_device bool volume_stack_is_heterogeneous(KernelGlobals *kg, ccl_addr_space if (object != OBJECT_NONE) { int object_flag = kernel_tex_fetch(__object_flag, object); if (object_flag & SD_OBJECT_HAS_VOLUME_ATTRIBUTES) { - return true; + heterogeneous = true; } } } + + if (heterogeneous) { + float object_step_size = object_volume_step_size(kg, stack[i].object); + object_step_size *= kernel_data.integrator.volume_step_rate; + step_size = fminf(object_step_size, step_size); + } } - return false; + return step_size; } ccl_device int volume_stack_sampling_method(KernelGlobals *kg, VolumeStack *stack) @@ -158,12 +168,13 @@ ccl_device int volume_stack_sampling_method(KernelGlobals *kg, VolumeStack *stac ccl_device_inline void kernel_volume_step_init(KernelGlobals *kg, ccl_addr_space PathState *state, + const float object_step_size, float t, float *step_size, float *step_offset) { const int max_steps = kernel_data.integrator.volume_max_steps; - float step = min(kernel_data.integrator.volume_step_size, t); + float step = min(object_step_size, t); /* compute exact steps in advance for malloc */ if (t > max_steps * step) { @@ -199,7 +210,8 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, ccl_addr_space PathState *state, Ray *ray, ShaderData *sd, - float3 *throughput) + float3 *throughput, + const float object_step_size) { float3 tp = *throughput; const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ @@ -207,7 +219,7 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, /* prepare for stepping */ int max_steps = kernel_data.integrator.volume_max_steps; float step_offset, step_size; - kernel_volume_step_init(kg, state, ray->t, &step_size, &step_offset); + kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset); /* compute extinction at the start */ float t = 0.0f; @@ -264,8 +276,9 @@ ccl_device_noinline void kernel_volume_shadow(KernelGlobals *kg, { shader_setup_from_volume(kg, shadow_sd, ray); - if (volume_stack_is_heterogeneous(kg, state->volume_stack)) - kernel_volume_shadow_heterogeneous(kg, state, ray, shadow_sd, throughput); + float step_size = volume_stack_step_size(kg, state->volume_stack); + if (step_size != FLT_MAX) + kernel_volume_shadow_heterogeneous(kg, state, ray, shadow_sd, throughput, step_size); else kernel_volume_shadow_homogeneous(kg, state, ray, shadow_sd, throughput); } @@ -533,7 +546,8 @@ kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg, Ray *ray, ShaderData *sd, PathRadiance *L, - ccl_addr_space float3 *throughput) + ccl_addr_space float3 *throughput, + const float object_step_size) { float3 tp = *throughput; const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ @@ -541,7 +555,7 @@ kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg, /* prepare for stepping */ int max_steps = kernel_data.integrator.volume_max_steps; float step_offset, step_size; - kernel_volume_step_init(kg, state, ray->t, &step_size, &step_offset); + kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset); /* compute coefficients at the start */ float t = 0.0f; @@ -679,12 +693,13 @@ kernel_volume_integrate(KernelGlobals *kg, Ray *ray, PathRadiance *L, ccl_addr_space float3 *throughput, - bool heterogeneous) + float step_size) { shader_setup_from_volume(kg, sd, ray); - if (heterogeneous) - return kernel_volume_integrate_heterogeneous_distance(kg, state, ray, sd, L, throughput); + if (step_size != FLT_MAX) + return kernel_volume_integrate_heterogeneous_distance( + kg, state, ray, sd, L, throughput, step_size); else return kernel_volume_integrate_homogeneous(kg, state, ray, sd, L, throughput, true); } @@ -735,7 +750,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, Ray *ray, ShaderData *sd, VolumeSegment *segment, - bool heterogeneous) + const float object_step_size) { const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ @@ -743,9 +758,9 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, int max_steps; float step_size, step_offset; - if (heterogeneous) { + if (object_step_size != FLT_MAX) { max_steps = kernel_data.integrator.volume_max_steps; - kernel_volume_step_init(kg, state, ray->t, &step_size, &step_offset); + kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset); # ifdef __KERNEL_CPU__ /* NOTE: For the branched path tracing it's possible to have direct diff --git a/intern/cycles/kernel/split/kernel_do_volume.h b/intern/cycles/kernel/split/kernel_do_volume.h index 45b839db05f..b24699ec39c 100644 --- a/intern/cycles/kernel/split/kernel_do_volume.h +++ b/intern/cycles/kernel/split/kernel_do_volume.h @@ -44,7 +44,7 @@ ccl_device_noinline bool kernel_split_branched_path_volume_indirect_light_iter(K branched_state->isect.t : FLT_MAX; - bool heterogeneous = volume_stack_is_heterogeneous(kg, branched_state->path_state.volume_stack); + float step_size = volume_stack_step_size(kg, branched_state->path_state.volume_stack); for (int j = branched_state->next_sample; j < num_samples; j++) { ccl_global PathState *ps = &kernel_split_state.path_state[ray_index]; @@ -61,7 +61,7 @@ ccl_device_noinline bool kernel_split_branched_path_volume_indirect_light_iter(K /* integrate along volume segment with distance sampling */ VolumeIntegrateResult result = kernel_volume_integrate( - kg, ps, sd, &volume_ray, L, tp, heterogeneous); + kg, ps, sd, &volume_ray, L, tp, step_size); # ifdef __VOLUME_SCATTER__ if (result == VOLUME_PATH_SCATTERED) { @@ -164,12 +164,12 @@ ccl_device void kernel_do_volume(KernelGlobals *kg) if (!kernel_data.integrator.branched || IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)) { # endif /* __BRANCHED_PATH__ */ - bool heterogeneous = volume_stack_is_heterogeneous(kg, state->volume_stack); + float step_size = volume_stack_step_size(kg, state->volume_stack); { /* integrate along volume segment with distance sampling */ VolumeIntegrateResult result = kernel_volume_integrate( - kg, state, sd, &volume_ray, L, throughput, heterogeneous); + kg, state, sd, &volume_ray, L, throughput, step_size); # ifdef __VOLUME_SCATTER__ if (result == VOLUME_PATH_SCATTERED) { diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp index 6553ca735e4..5a61ead2c54 100644 --- a/intern/cycles/render/background.cpp +++ b/intern/cycles/render/background.cpp @@ -43,6 +43,8 @@ NODE_DEFINE(Background) SOCKET_BOOLEAN(transparent_glass, "Transparent Glass", false); SOCKET_FLOAT(transparent_roughness_threshold, "Transparent Roughness Threshold", 0.0f); + SOCKET_FLOAT(volume_step_size, "Volume Step Size", 0.1f); + SOCKET_NODE(shader, "Shader", &Shader::node_type); return type; @@ -91,6 +93,8 @@ void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene else kbackground->volume_shader = SHADER_NONE; + kbackground->volume_step_size = volume_step_size * scene->integrator->volume_step_rate; + /* No background node, make world shader invisible to all rays, to skip evaluation in kernel. */ if (bg_shader->graph->nodes.size() <= 1) { kbackground->surface_shader |= SHADER_EXCLUDE_ANY; diff --git a/intern/cycles/render/background.h b/intern/cycles/render/background.h index fb27430f9a3..c2ca1f75179 100644 --- a/intern/cycles/render/background.h +++ b/intern/cycles/render/background.h @@ -45,6 +45,8 @@ class Background : public Node { bool transparent_glass; float transparent_roughness_threshold; + float volume_step_size; + bool need_update; Background(); diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index ee1aa5988bf..d856f7a300f 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -50,7 +50,7 @@ NODE_DEFINE(Integrator) SOCKET_INT(ao_bounces, "AO Bounces", 0); SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024); - SOCKET_FLOAT(volume_step_size, "Volume Step Size", 0.1f); + SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f); SOCKET_BOOLEAN(caustics_reflective, "Reflective Caustics", true); SOCKET_BOOLEAN(caustics_refractive, "Refractive Caustics", true); @@ -143,7 +143,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene } kintegrator->volume_max_steps = volume_max_steps; - kintegrator->volume_step_size = volume_step_size; + kintegrator->volume_step_rate = volume_step_rate; kintegrator->caustics_reflective = caustics_reflective; kintegrator->caustics_refractive = caustics_refractive; diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h index 9930e907aea..9804caebe6e 100644 --- a/intern/cycles/render/integrator.h +++ b/intern/cycles/render/integrator.h @@ -45,7 +45,7 @@ class Integrator : public Node { int ao_bounces; int volume_max_steps; - float volume_step_size; + float volume_step_rate; bool caustics_reflective; bool caustics_refractive; diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 4987b6089d7..c84007823d2 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -17,6 +17,7 @@ #include "render/camera.h" #include "device/device.h" #include "render/hair.h" +#include "render/integrator.h" #include "render/light.h" #include "render/mesh.h" #include "render/curves.h" @@ -65,6 +66,7 @@ struct UpdateObjectTransformState { KernelObject *objects; Transform *object_motion_pass; DecomposedTransform *object_motion; + float *object_volume_step; /* Flags which will be synchronized to Integrator. */ bool have_motion; @@ -266,6 +268,65 @@ uint Object::visibility_for_tracing() const return trace_visibility; } +float Object::compute_volume_step_size() const +{ + if (!geometry->has_volume) { + return FLT_MAX; + } + + /* Compute step rate from shaders. */ + float step_rate = FLT_MAX; + + foreach (Shader *shader, geometry->used_shaders) { + if (shader->has_volume) { + if ((shader->heterogeneous_volume && shader->has_volume_spatial_varying) || + (shader->has_volume_attribute_dependency)) { + step_rate = fminf(shader->volume_step_rate, step_rate); + } + } + } + + if (step_rate == FLT_MAX) { + return FLT_MAX; + } + + /* Compute step size from voxel grids. */ + float step_size = FLT_MAX; + + foreach (Attribute &attr, geometry->attributes.attributes) { + if (attr.element == ATTR_ELEMENT_VOXEL) { + ImageHandle &handle = attr.data_voxel(); + const ImageMetaData &metadata = handle.metadata(); + if (metadata.width == 0 || metadata.height == 0 || metadata.depth == 0) { + continue; + } + + /* Step size is transformed from voxel to world space. */ + Transform voxel_tfm = tfm; + if (metadata.use_transform_3d) { + voxel_tfm = tfm * transform_inverse(metadata.transform_3d); + } + + float3 size = make_float3( + 1.0f / metadata.width, 1.0f / metadata.height, 1.0f / metadata.depth); + float voxel_step_size = min3(fabs(transform_direction(&voxel_tfm, size))); + + if (voxel_step_size > 0.0f) { + step_size = fminf(voxel_step_size, step_size); + } + } + } + + if (step_size == FLT_MAX) { + /* Fall back to 1/10th of bounds for procedural volumes. */ + step_size = 0.1f * average(bounds.size()); + } + + step_size *= step_rate; + + return step_size; +} + int Object::get_device_index() const { return index; @@ -451,6 +512,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s flag |= SD_OBJECT_HOLDOUT_MASK; } state->object_flag[ob->index] = flag; + state->object_volume_step[ob->index] = FLT_MAX; /* Have curves. */ if (geom->type == Geometry::HAIR) { @@ -504,6 +566,7 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, state.objects = dscene->objects.alloc(scene->objects.size()); state.object_flag = dscene->object_flag.alloc(scene->objects.size()); + state.object_volume_step = dscene->object_volume_step.alloc(scene->objects.size()); state.object_motion = NULL; state.object_motion_pass = NULL; @@ -624,6 +687,7 @@ void ObjectManager::device_update_flags( /* Object info flag. */ uint *object_flag = dscene->object_flag.data(); + float *object_volume_step = dscene->object_volume_step.data(); /* Object volume intersection. */ vector volume_objects; @@ -634,6 +698,10 @@ void ObjectManager::device_update_flags( volume_objects.push_back(object); } has_volume_objects = true; + object_volume_step[object->index] = object->compute_volume_step_size(); + } + else { + object_volume_step[object->index] = FLT_MAX; } } @@ -651,6 +719,7 @@ void ObjectManager::device_update_flags( else { object_flag[object->index] &= ~(SD_OBJECT_HAS_VOLUME | SD_OBJECT_HAS_VOLUME_ATTRIBUTES); } + if (object->is_shadow_catcher) { object_flag[object->index] |= SD_OBJECT_SHADOW_CATCHER; } @@ -679,6 +748,7 @@ void ObjectManager::device_update_flags( /* Copy object flag. */ dscene->object_flag.copy_to_device(); + dscene->object_volume_step.copy_to_device(); } void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene) @@ -725,6 +795,7 @@ void ObjectManager::device_free(Device *, DeviceScene *dscene) dscene->object_motion_pass.free(); dscene->object_motion.free(); dscene->object_flag.free(); + dscene->object_volume_step.free(); } void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 7bd3edf769b..2c2870cd0f2 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -97,6 +97,9 @@ class Object : public Node { /* Returns the index that is used in the kernel for this object. */ int get_device_index() const; + /* Compute step size from attributes, shaders, transforms. */ + float compute_volume_step_size() const; + protected: /* Specifies the position of the object in scene->objects and * in the device vectors. Gets set in device_update. */ diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index d17d7270cd5..74eb61e2dff 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -760,16 +760,14 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath) else if (current_type == SHADER_TYPE_VOLUME) { if (node->has_spatial_varying()) current_shader->has_volume_spatial_varying = true; + if (node->has_attribute_dependency()) + current_shader->has_volume_attribute_dependency = true; } if (node->has_object_dependency()) { current_shader->has_object_dependency = true; } - if (node->has_attribute_dependency()) { - current_shader->has_attribute_dependency = true; - } - if (node->has_integrator_dependency()) { current_shader->has_integrator_dependency = true; } @@ -1143,8 +1141,8 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader) shader->has_displacement = false; shader->has_surface_spatial_varying = false; shader->has_volume_spatial_varying = false; + shader->has_volume_attribute_dependency = false; shader->has_object_dependency = false; - shader->has_attribute_dependency = false; shader->has_integrator_dependency = false; /* generate surface shader */ diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 76f62fd6690..77c66779c20 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -63,6 +63,7 @@ DeviceScene::DeviceScene(Device *device) object_motion_pass(device, "__object_motion_pass", MEM_GLOBAL), object_motion(device, "__object_motion", MEM_GLOBAL), object_flag(device, "__object_flag", MEM_GLOBAL), + object_volume_step(device, "__object_volume_step", MEM_GLOBAL), camera_motion(device, "__camera_motion", MEM_GLOBAL), attributes_map(device, "__attributes_map", MEM_GLOBAL), attributes_float(device, "__attributes_float", MEM_GLOBAL), diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index d2570138b53..6b10a901d7b 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -91,6 +91,7 @@ class DeviceScene { device_vector object_motion_pass; device_vector object_motion; device_vector object_flag; + device_vector object_volume_step; /* cameras */ device_vector camera_motion; diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index cc6eb2e5e7f..747fc58f81a 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -178,6 +178,8 @@ NODE_DEFINE(Shader) volume_interpolation_method_enum, VOLUME_INTERPOLATION_LINEAR); + SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f); + static NodeEnum displacement_method_enum; displacement_method_enum.insert("bump", DISPLACE_BUMP); displacement_method_enum.insert("true", DISPLACE_TRUE); @@ -203,10 +205,11 @@ Shader::Shader() : Node(node_type) has_bssrdf_bump = false; has_surface_spatial_varying = false; has_volume_spatial_varying = false; + has_volume_attribute_dependency = false; has_object_dependency = false; - has_attribute_dependency = false; has_integrator_dependency = false; has_volume_connected = false; + prev_volume_step_rate = 0.0f; displacement_method = DISPLACE_BUMP; @@ -353,9 +356,10 @@ void Shader::tag_update(Scene *scene) scene->geometry_manager->need_update = true; } - if (has_volume != prev_has_volume) { + if (has_volume != prev_has_volume || volume_step_rate != prev_volume_step_rate) { scene->geometry_manager->need_flags_update = true; scene->object_manager->need_flags_update = true; + prev_volume_step_rate = volume_step_rate; } } @@ -533,10 +537,12 @@ void ShaderManager::device_update_common(Device *device, /* in this case we can assume transparent surface */ if (shader->has_volume_connected && !shader->has_surface) flag |= SD_HAS_ONLY_VOLUME; - if (shader->heterogeneous_volume && shader->has_volume_spatial_varying) - flag |= SD_HETEROGENEOUS_VOLUME; - if (shader->has_attribute_dependency) - flag |= SD_NEED_ATTRIBUTES; + if (shader->has_volume) { + if (shader->heterogeneous_volume && shader->has_volume_spatial_varying) + flag |= SD_HETEROGENEOUS_VOLUME; + } + if (shader->has_volume_attribute_dependency) + flag |= SD_NEED_VOLUME_ATTRIBUTES; if (shader->has_bssrdf_bump) flag |= SD_HAS_BSSRDF_BUMP; if (device->info.has_volume_decoupled) { diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h index 5a5b42de994..1509150228f 100644 --- a/intern/cycles/render/shader.h +++ b/intern/cycles/render/shader.h @@ -92,6 +92,8 @@ class Shader : public Node { bool heterogeneous_volume; VolumeSampling volume_sampling_method; int volume_interpolation_method; + float volume_step_rate; + float prev_volume_step_rate; /* synchronization */ bool need_update; @@ -118,8 +120,8 @@ class Shader : public Node { bool has_bssrdf_bump; bool has_surface_spatial_varying; bool has_volume_spatial_varying; + bool has_volume_attribute_dependency; bool has_object_dependency; - bool has_attribute_dependency; bool has_integrator_dependency; /* displacement */ diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 2946614a3b7..c4218f7df1e 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -444,16 +444,14 @@ void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet &done) else if (current_type == SHADER_TYPE_VOLUME) { if (node->has_spatial_varying()) current_shader->has_volume_spatial_varying = true; + if (node->has_attribute_dependency()) + current_shader->has_volume_attribute_dependency = true; } if (node->has_object_dependency()) { current_shader->has_object_dependency = true; } - if (node->has_attribute_dependency()) { - current_shader->has_attribute_dependency = true; - } - if (node->has_integrator_dependency()) { current_shader->has_integrator_dependency = true; } @@ -864,8 +862,8 @@ void SVMCompiler::compile(Shader *shader, array &svm_nodes, int index, Sum shader->has_displacement = false; shader->has_surface_spatial_varying = false; shader->has_volume_spatial_varying = false; + shader->has_volume_attribute_dependency = false; shader->has_object_dependency = false; - shader->has_attribute_dependency = false; shader->has_integrator_dependency = false; /* generate bump shader */ -- cgit v1.2.3