Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brecht>2020-03-07 16:38:52 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2020-03-18 13:23:05 +0300
commit1162ba206dd7792414d3ae716877ba1383de8dab (patch)
tree3b243a7c33dfbbc6414e96a4df6b37ddc47531cd
parent9d20f170c7c07ac38e86130de591ae98e9c0cf80 (diff)
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
-rw-r--r--intern/cycles/blender/addon/properties.py36
-rw-r--r--intern/cycles/blender/addon/ui.py16
-rw-r--r--intern/cycles/blender/blender_shader.cpp2
-rw-r--r--intern/cycles/blender/blender_sync.cpp3
-rw-r--r--intern/cycles/kernel/geom/geom_object.h11
-rw-r--r--intern/cycles/kernel/kernel_path.h8
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h6
-rw-r--r--intern/cycles/kernel/kernel_textures.h1
-rw-r--r--intern/cycles/kernel/kernel_types.h10
-rw-r--r--intern/cycles/kernel/kernel_volume.h51
-rw-r--r--intern/cycles/kernel/split/kernel_do_volume.h8
-rw-r--r--intern/cycles/render/background.cpp4
-rw-r--r--intern/cycles/render/background.h2
-rw-r--r--intern/cycles/render/integrator.cpp4
-rw-r--r--intern/cycles/render/integrator.h2
-rw-r--r--intern/cycles/render/object.cpp71
-rw-r--r--intern/cycles/render/object.h3
-rw-r--r--intern/cycles/render/osl.cpp8
-rw-r--r--intern/cycles/render/scene.cpp1
-rw-r--r--intern/cycles/render/scene.h1
-rw-r--r--intern/cycles/render/shader.cpp18
-rw-r--r--intern/cycles/render/shader.h4
-rw-r--r--intern/cycles/render/svm.cpp8
23 files changed, 212 insertions, 66 deletions
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<Object *> 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<Transform> object_motion_pass;
device_vector<DecomposedTransform> object_motion;
device_vector<uint> object_flag;
+ device_vector<float> object_volume_step;
/* cameras */
device_vector<DecomposedTransform> 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<int4> &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 */