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
This commit is contained in:
Brecht Van Lommel 2020-03-07 14:38:52 +01:00 committed by Brecht Van Lommel
parent 9d20f170c7
commit 1162ba206d
23 changed files with 212 additions and 66 deletions

View File

@ -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):

View File

@ -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)

View File

@ -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();

View File

@ -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");

View File

@ -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)

View File

@ -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) {

View File

@ -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) {

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -45,6 +45,8 @@ class Background : public Node {
bool transparent_glass;
float transparent_roughness_threshold;
float volume_step_size;
bool need_update;
Background();

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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. */

View File

@ -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 */

View File

@ -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),

View File

@ -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;

View File

@ -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) {

View File

@ -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 */

View File

@ -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 */