diff options
author | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2022-04-19 17:28:14 +0300 |
---|---|---|
committer | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2022-04-19 18:07:53 +0300 |
commit | 2890c11cd7b008c3c261b6aa833c826c85cac504 (patch) | |
tree | 5bc3432767fc6dd260e6fec18bd1817766572abd /intern/cycles/kernel | |
parent | 56cfd60d432bf387c21bf5bde08fece044fac99c (diff) |
Cycles: add support for volume motion blur
This adds support for rendering motion blur for volumes, using their
velocity field. This works for fluid simulations and imported VDB
volumes. For the latter, the name of the velocity field can be set per
volume object, with automatic detection of velocity fields that are
split into 3 scalar grids.
A new parameter is also added to scale velocity for more artistic control.
Like for Alembic and USD caches, a parameter to set the unit of time in
which the velocity vectors are expressed is also added. For Blender gas
simulations, the velocity unit should always be in seconds, so this is
only exposed for volume objects which may come from external OpenVDB
files.
These parameters are available under the `Render` panels for the fluid
domain and the volume object data properties respectively.
Credits: kernel advection code from Tangent Animation's Blackbird based
on earlier work by Geraldine Chua
Differential Revision: https://developer.blender.org/D14629
Diffstat (limited to 'intern/cycles/kernel')
-rw-r--r-- | intern/cycles/kernel/integrator/shader_eval.h | 59 | ||||
-rw-r--r-- | intern/cycles/kernel/types.h | 25 |
2 files changed, 81 insertions, 3 deletions
diff --git a/intern/cycles/kernel/integrator/shader_eval.h b/intern/cycles/kernel/integrator/shader_eval.h index 3066fb661a1..3ea53b3e647 100644 --- a/intern/cycles/kernel/integrator/shader_eval.h +++ b/intern/cycles/kernel/integrator/shader_eval.h @@ -831,6 +831,65 @@ ccl_device_inline void shader_eval_volume(KernelGlobals kg, /* todo: this is inefficient for motion blur, we should be * caching matrices instead of recomputing them each step */ shader_setup_object_transforms(kg, sd, sd->time); + + if ((sd->object_flag & SD_OBJECT_HAS_VOLUME_MOTION) != 0) { + AttributeDescriptor v_desc = find_attribute(kg, sd, ATTR_STD_VOLUME_VELOCITY); + kernel_assert(v_desc.offset != ATTR_STD_NOT_FOUND); + + const float3 P = sd->P; + const float velocity_scale = kernel_tex_fetch(__objects, sd->object).velocity_scale; + const float time_offset = kernel_data.cam.motion_position == MOTION_POSITION_CENTER ? + 0.5f : + 0.0f; + const float time = kernel_data.cam.motion_position == MOTION_POSITION_END ? + (1.0f - kernel_data.cam.shuttertime) + sd->time : + sd->time; + + /* Use a 1st order semi-lagrangian advection scheme to estimate what volume quantity + * existed, or will exist, at the given time: + * + * `phi(x, T) = phi(x - (T - t) * u(x, T), t)` + * + * where + * + * x : position + * T : super-sampled time (or ray time) + * t : current time of the simulation (in rendering we assume this is center frame with + * relative time = 0) + * phi : the volume quantity + * u : the velocity field + * + * But first we need to determine the velocity field `u(x, T)`, which we can estimate also + * using semi-lagrangian advection. + * + * `u(x, T) = u(x - (T - t) * u(x, T), t)` + * + * This is the typical way to model self-advection in fluid dynamics, however, we do not + * account for other forces affecting the velocity during simulation (pressure, buyoancy, + * etc.): this gives a linear interpolation when fluid are mostly "curvy". For better + * results, a higher order interpolation scheme can be used (at the cost of more lookups), + * or an interpolation of the velocity fields for the previous and next frames could also + * be used to estimate `u(x, T)` (which will cost more memory and lookups). + * + * References: + * "Eulerian Motion Blur", Kim and Ko, 2007 + * "Production Volume Rendering", Wreninge et al., 2012 + */ + + /* Find velocity. */ + float3 velocity = primitive_volume_attribute_float3(kg, sd, v_desc); + object_dir_transform(kg, sd, &velocity); + + /* Find advected P. */ + sd->P = P - (time - time_offset) * velocity_scale * velocity; + + /* Find advected velocity. */ + velocity = primitive_volume_attribute_float3(kg, sd, v_desc); + object_dir_transform(kg, sd, &velocity); + + /* Find advected P. */ + sd->P = P - (time - time_offset) * velocity_scale * velocity; + } # endif } diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 422285cd346..01df7948241 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -489,6 +489,18 @@ enum PanoramaType { PANORAMA_NUM_TYPES, }; +/* Specifies an offset for the shutter's time interval. */ +enum MotionPosition { + /* Shutter opens at the current frame. */ + MOTION_POSITION_START = 0, + /* Shutter is fully open at the current frame. */ + MOTION_POSITION_CENTER = 1, + /* Shutter closes at the current frame. */ + MOTION_POSITION_END = 2, + + MOTION_NUM_POSITIONS, +}; + /* Direct Light Sampling */ enum DirectLightSamplingType { @@ -635,6 +647,9 @@ typedef enum AttributeStandard { ATTR_STD_VOLUME_HEAT, ATTR_STD_VOLUME_TEMPERATURE, ATTR_STD_VOLUME_VELOCITY, + ATTR_STD_VOLUME_VELOCITY_X, + ATTR_STD_VOLUME_VELOCITY_Y, + ATTR_STD_VOLUME_VELOCITY_Z, ATTR_STD_POINTINESS, ATTR_STD_RANDOM_PER_ISLAND, ATTR_STD_SHADOW_TRANSPARENCY, @@ -808,6 +823,8 @@ enum ShaderDataObjectFlag { SD_OBJECT_CAUSTICS_CASTER = (1 << 9), /* object is caustics receiver */ SD_OBJECT_CAUSTICS_RECEIVER = (1 << 10), + /* object has attribute for volume motion */ + SD_OBJECT_HAS_VOLUME_MOTION = (1 << 11), /* object is using caustics */ SD_OBJECT_CAUSTICS = (SD_OBJECT_CAUSTICS_CASTER | SD_OBJECT_CAUSTICS_RECEIVER), @@ -815,7 +832,8 @@ enum ShaderDataObjectFlag { SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK | SD_OBJECT_MOTION | SD_OBJECT_TRANSFORM_APPLIED | SD_OBJECT_NEGATIVE_SCALE_APPLIED | SD_OBJECT_HAS_VOLUME | SD_OBJECT_INTERSECTS_VOLUME | SD_OBJECT_SHADOW_CATCHER | - SD_OBJECT_HAS_VOLUME_ATTRIBUTES | SD_OBJECT_CAUSTICS) + SD_OBJECT_HAS_VOLUME_ATTRIBUTES | SD_OBJECT_CAUSTICS | + SD_OBJECT_HAS_VOLUME_MOTION) }; typedef struct ccl_align(16) ShaderData @@ -1040,7 +1058,7 @@ typedef struct KernelCamera { int rolling_shutter_type; float rolling_shutter_duration; - int pad; + int motion_position; } KernelCamera; static_assert_align(KernelCamera, 16); @@ -1386,7 +1404,8 @@ typedef struct KernelObject { uint visibility; int primitive_type; - int pad1; + /* Volume velocity scale. */ + float velocity_scale; } KernelObject; static_assert_align(KernelObject, 16); |