mirror of
https://github.com/blender/blender
synced 2026-09-27 01:34:15 +03:00
Cycles: Add denoising backward motion vector pass with depth delta
A new backward motion vector denoising pass is added to Cycles. Its x and y component contain the same screen space motion vector data as the vector data pass, but the z component additionally stores the linear depth delta in camera space. A future version of OIDN plans to use this for viewport denoising. Thus, only backward motion vectors with linear depth delta, but not forward motion vectors are needed for now. Pull Request: https://projects.blender.org/blender/blender/pulls/157787
This commit is contained in:
parent
c6dddc25d3
commit
74ffed0a34
12 changed files with 125 additions and 57 deletions
|
|
@ -251,6 +251,7 @@ def list_render_passes(scene, srl):
|
|||
yield (n_("Denoising Normal"), "XYZ", 'VECTOR')
|
||||
yield (n_("Denoising Roughness"), "X", 'VALUE')
|
||||
yield (n_("Denoising Depth"), "Z", 'VALUE')
|
||||
yield (n_("Denoising Backward Motion"), "XYZ", 'VECTOR')
|
||||
|
||||
# Custom AOV passes.
|
||||
for aov in srl.aovs:
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ enum_view3d_shading_render_pass = (
|
|||
('DENOISING_SPECULAR_ALBEDO', "Denoising Specular Albedo", "Specular albedo pass used by denoiser"),
|
||||
('DENOISING_NORMAL', "Denoising Normal", "Normal pass used by denoiser"),
|
||||
('DENOISING_ROUGHNESS', "Denoising Roughness", "Roughness pass used by denoiser"),
|
||||
('DENOISING_BACKWARD_MOTION', "Denoising Backward Motion", "Backward motion pass used by denoiser"),
|
||||
('SAMPLE_COUNT', "Sample Count", "Per-pixel number of samples"),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -742,6 +742,7 @@ static bool get_known_pass_type(blender::RenderPass &b_pass, PassType &type, Pas
|
|||
MAP_PASS("Denoising Normal", PASS_DENOISING_NORMAL, true);
|
||||
MAP_PASS("Denoising Roughness", PASS_DENOISING_ROUGHNESS, true);
|
||||
MAP_PASS("Denoising Depth", PASS_DENOISING_DEPTH, true);
|
||||
MAP_PASS("Denoising Backward Motion", PASS_DENOISING_BACKWARD_MOTION, true);
|
||||
|
||||
MAP_PASS("Shadow Catcher", PASS_SHADOW_CATCHER, false);
|
||||
MAP_PASS("Noisy Shadow Catcher", PASS_SHADOW_CATCHER, true);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ enum DenoiserPass {
|
|||
DENOISER_PASS_ROUGHNESS = 1 << 3,
|
||||
DENOISER_PASS_DEPTH = 1 << 4,
|
||||
DENOISER_PASS_MOTION = 1 << 5,
|
||||
DENOISER_PASS_BACKWARD_MOTION = 1 << 6,
|
||||
};
|
||||
|
||||
using DenoiserPassMask = int;
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ KERNEL_STRUCT_MEMBER(film, int, is_rec709)
|
|||
KERNEL_STRUCT_MEMBER(film, float, exposure)
|
||||
/* Passed used. */
|
||||
KERNEL_STRUCT_MEMBER(film, int, pass_flag)
|
||||
KERNEL_STRUCT_MEMBER(film, int, denoising_pass_flag)
|
||||
KERNEL_STRUCT_MEMBER(film, int, light_pass_flag)
|
||||
/* Pass offsets. */
|
||||
KERNEL_STRUCT_MEMBER(film, int, pass_stride)
|
||||
|
|
@ -133,6 +134,7 @@ KERNEL_STRUCT_MEMBER(film, int, pass_denoising_specular_albedo)
|
|||
KERNEL_STRUCT_MEMBER(film, int, pass_denoising_normal)
|
||||
KERNEL_STRUCT_MEMBER(film, int, pass_denoising_roughness)
|
||||
KERNEL_STRUCT_MEMBER(film, int, pass_denoising_depth)
|
||||
KERNEL_STRUCT_MEMBER(film, int, pass_denoising_backward_motion)
|
||||
/* AOVs. */
|
||||
KERNEL_STRUCT_MEMBER(film, int, pass_aov_color)
|
||||
KERNEL_STRUCT_MEMBER(film, int, pass_aov_value)
|
||||
|
|
|
|||
|
|
@ -134,6 +134,12 @@ ccl_device_forceinline void film_write_denoising_features_surface(KernelGlobals
|
|||
film_write_pass_spectrum(buffer + kernel_data.film.pass_denoising_specular_albedo,
|
||||
denoising_specular_albedo);
|
||||
}
|
||||
|
||||
if (kernel_data.film.pass_denoising_backward_motion != PASS_UNUSED) {
|
||||
const float3 backward_motion = primitive_motion_vector_backward_depth_delta(kg, sd);
|
||||
film_write_pass_float3(buffer + kernel_data.film.pass_denoising_backward_motion,
|
||||
backward_motion);
|
||||
}
|
||||
}
|
||||
|
||||
/* Portion deferred to the next bounce. Specularity uses the feature weight, transparent
|
||||
|
|
|
|||
|
|
@ -184,42 +184,42 @@ ccl_device Float3Type primitive_tangent(KernelGlobals kg, ccl_private ShaderData
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Motion vector for motion pass */
|
||||
/* Motion vector common */
|
||||
|
||||
ccl_device_forceinline float4 primitive_motion_vector(KernelGlobals kg,
|
||||
const ccl_private ShaderData *sd)
|
||||
ccl_device_forceinline void primitive_motion_data_without_camera(KernelGlobals kg,
|
||||
const ccl_private ShaderData *sd,
|
||||
ccl_private float3 *motion_center,
|
||||
ccl_private float3 *motion_pre,
|
||||
ccl_private float3 *motion_post)
|
||||
{
|
||||
/* center position */
|
||||
float3 center;
|
||||
|
||||
#if defined(__HAIR__) || defined(__POINTCLOUD__)
|
||||
const bool is_curve_or_point = sd->type & (PRIMITIVE_CURVE | PRIMITIVE_POINT);
|
||||
if (is_curve_or_point) {
|
||||
center = make_float3(0.0f, 0.0f, 0.0f);
|
||||
*motion_center = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
if (sd->type & PRIMITIVE_CURVE) {
|
||||
# if defined(__HAIR__)
|
||||
center = curve_motion_center_location(kg, sd);
|
||||
*motion_center = curve_motion_center_location(kg, sd);
|
||||
# endif
|
||||
}
|
||||
else if (sd->type & PRIMITIVE_POINT) {
|
||||
# if defined(__POINTCLOUD__)
|
||||
center = point_motion_center_location(kg, sd);
|
||||
*motion_center = point_motion_center_location(kg, sd);
|
||||
# endif
|
||||
}
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
object_position_transform(kg, sd, ¢er);
|
||||
object_position_transform(kg, sd, motion_center);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
center = sd->P;
|
||||
*motion_center = sd->P;
|
||||
}
|
||||
|
||||
float3 motion_pre = center;
|
||||
float3 motion_post = center;
|
||||
*motion_pre = *motion_center;
|
||||
*motion_post = *motion_center;
|
||||
|
||||
/* deformation motion */
|
||||
AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
|
|
@ -230,14 +230,14 @@ ccl_device_forceinline float4 primitive_motion_vector(KernelGlobals kg,
|
|||
|
||||
#if defined(__HAIR__) || defined(__POINTCLOUD__)
|
||||
if (is_curve_or_point) {
|
||||
motion_pre = make_float3(primitive_surface_attribute<float4>(kg, sd, desc));
|
||||
*motion_pre = make_float3(primitive_surface_attribute<float4>(kg, sd, desc));
|
||||
desc.offset += numverts;
|
||||
motion_post = make_float3(primitive_surface_attribute<float4>(kg, sd, desc));
|
||||
*motion_post = make_float3(primitive_surface_attribute<float4>(kg, sd, desc));
|
||||
|
||||
/* Curve */
|
||||
if ((sd->object_flag & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
|
||||
object_position_transform(kg, sd, &motion_pre);
|
||||
object_position_transform(kg, sd, &motion_post);
|
||||
object_position_transform(kg, sd, motion_pre);
|
||||
object_position_transform(kg, sd, motion_post);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -245,9 +245,9 @@ ccl_device_forceinline float4 primitive_motion_vector(KernelGlobals kg,
|
|||
if (sd->type & PRIMITIVE_TRIANGLE)
|
||||
{
|
||||
/* Triangle */
|
||||
motion_pre = triangle_attribute<float3>(kg, sd, desc);
|
||||
*motion_pre = triangle_attribute<float3>(kg, sd, desc);
|
||||
desc.offset += numverts;
|
||||
motion_post = triangle_attribute<float3>(kg, sd, desc);
|
||||
*motion_post = triangle_attribute<float3>(kg, sd, desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -256,12 +256,18 @@ ccl_device_forceinline float4 primitive_motion_vector(KernelGlobals kg,
|
|||
Transform tfm;
|
||||
|
||||
tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_PRE);
|
||||
motion_pre = transform_point(&tfm, motion_pre);
|
||||
*motion_pre = transform_point(&tfm, *motion_pre);
|
||||
|
||||
tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_POST);
|
||||
motion_post = transform_point(&tfm, motion_post);
|
||||
*motion_post = transform_point(&tfm, *motion_post);
|
||||
}
|
||||
|
||||
float3 motion_center;
|
||||
ccl_device_forceinline void primitive_motion_data_camera_step(KernelGlobals kg,
|
||||
ccl_private float3 *motion_center,
|
||||
ccl_private float3 *motion_pre,
|
||||
ccl_private float3 *motion_post)
|
||||
{
|
||||
Transform tfm;
|
||||
|
||||
/* camera motion, for perspective/orthographic motion.pre/post will be a
|
||||
* world-to-raster matrix, for panorama it's world-to-camera, for custom
|
||||
|
|
@ -270,45 +276,55 @@ ccl_device_forceinline float4 primitive_motion_vector(KernelGlobals kg,
|
|||
/* TODO: Custom cameras don't have inverse mappings yet, so we fall back to
|
||||
* camera-space vectors here for now. */
|
||||
tfm = kernel_data.cam.worldtocamera;
|
||||
motion_center = normalize(transform_point(&tfm, center));
|
||||
*motion_center = normalize(transform_point(&tfm, *motion_center));
|
||||
|
||||
tfm = kernel_data.cam.motion_pass_pre;
|
||||
motion_pre = normalize(transform_point(&tfm, motion_pre));
|
||||
*motion_pre = normalize(transform_point(&tfm, *motion_pre));
|
||||
|
||||
tfm = kernel_data.cam.motion_pass_post;
|
||||
motion_post = normalize(transform_point(&tfm, motion_post));
|
||||
*motion_post = normalize(transform_point(&tfm, *motion_post));
|
||||
}
|
||||
else if (kernel_data.cam.type != CAMERA_PANORAMA) {
|
||||
/* Perspective and orthographics camera use the world-to-raster matrix. */
|
||||
ProjectionTransform projection = kernel_data.cam.worldtoraster;
|
||||
motion_center = transform_perspective(&projection, center);
|
||||
*motion_center = transform_perspective(&projection, *motion_center);
|
||||
|
||||
projection = kernel_data.cam.perspective_pre;
|
||||
motion_pre = transform_perspective(&projection, motion_pre);
|
||||
*motion_pre = transform_perspective(&projection, *motion_pre);
|
||||
|
||||
projection = kernel_data.cam.perspective_post;
|
||||
motion_post = transform_perspective(&projection, motion_post);
|
||||
*motion_post = transform_perspective(&projection, *motion_post);
|
||||
}
|
||||
else {
|
||||
/* Panorama cameras have their own inverse mappings. */
|
||||
tfm = kernel_data.cam.worldtocamera;
|
||||
motion_center = normalize(transform_point(&tfm, center));
|
||||
motion_center = make_float3(direction_to_panorama(&kernel_data.cam, motion_center));
|
||||
motion_center.x *= kernel_data.cam.width;
|
||||
motion_center.y *= kernel_data.cam.height;
|
||||
*motion_center = normalize(transform_point(&tfm, *motion_center));
|
||||
*motion_center = make_float3(direction_to_panorama(&kernel_data.cam, *motion_center));
|
||||
motion_center->x *= kernel_data.cam.width;
|
||||
motion_center->y *= kernel_data.cam.height;
|
||||
|
||||
tfm = kernel_data.cam.motion_pass_pre;
|
||||
motion_pre = normalize(transform_point(&tfm, motion_pre));
|
||||
motion_pre = make_float3(direction_to_panorama(&kernel_data.cam, motion_pre));
|
||||
motion_pre.x *= kernel_data.cam.width;
|
||||
motion_pre.y *= kernel_data.cam.height;
|
||||
*motion_pre = normalize(transform_point(&tfm, *motion_pre));
|
||||
*motion_pre = make_float3(direction_to_panorama(&kernel_data.cam, *motion_pre));
|
||||
motion_pre->x *= kernel_data.cam.width;
|
||||
motion_pre->y *= kernel_data.cam.height;
|
||||
|
||||
tfm = kernel_data.cam.motion_pass_post;
|
||||
motion_post = normalize(transform_point(&tfm, motion_post));
|
||||
motion_post = make_float3(direction_to_panorama(&kernel_data.cam, motion_post));
|
||||
motion_post.x *= kernel_data.cam.width;
|
||||
motion_post.y *= kernel_data.cam.height;
|
||||
*motion_post = normalize(transform_point(&tfm, *motion_post));
|
||||
*motion_post = make_float3(direction_to_panorama(&kernel_data.cam, *motion_post));
|
||||
motion_post->x *= kernel_data.cam.width;
|
||||
motion_post->y *= kernel_data.cam.height;
|
||||
}
|
||||
}
|
||||
|
||||
/* Motion vector for motion pass */
|
||||
|
||||
ccl_device_forceinline float4 primitive_motion_vector(KernelGlobals kg,
|
||||
const ccl_private ShaderData *sd)
|
||||
{
|
||||
float3 motion_center, motion_pre, motion_post;
|
||||
primitive_motion_data_without_camera(kg, sd, &motion_center, &motion_pre, &motion_post);
|
||||
primitive_motion_data_camera_step(kg, &motion_center, &motion_pre, &motion_post);
|
||||
|
||||
motion_pre = motion_pre - motion_center;
|
||||
motion_post = motion_center - motion_post;
|
||||
|
|
@ -316,4 +332,27 @@ ccl_device_forceinline float4 primitive_motion_vector(KernelGlobals kg,
|
|||
return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
|
||||
}
|
||||
|
||||
/* Motion vector for denoising backward motion pass */
|
||||
|
||||
ccl_device_forceinline float3
|
||||
primitive_motion_vector_backward_depth_delta(KernelGlobals kg, const ccl_private ShaderData *sd)
|
||||
{
|
||||
Transform tfm;
|
||||
float3 motion_center, motion_pre, motion_post;
|
||||
primitive_motion_data_without_camera(kg, sd, &motion_center, &motion_pre, &motion_post);
|
||||
|
||||
/* Get camera-space vectors for linear depth delta. */
|
||||
tfm = kernel_data.cam.worldtocamera;
|
||||
float3 motion_center_cam = transform_point(&tfm, motion_center);
|
||||
tfm = kernel_data.cam.motion_pass_pre;
|
||||
float3 motion_pre_cam = transform_point(&tfm, motion_pre);
|
||||
|
||||
primitive_motion_data_camera_step(kg, &motion_center, &motion_pre, &motion_post);
|
||||
|
||||
motion_pre = motion_pre - motion_center;
|
||||
float linear_depth_delta_pre = motion_pre_cam.z - motion_center_cam.z;
|
||||
|
||||
return make_float3(motion_pre.x, motion_pre.y, linear_depth_delta_pre);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
|||
|
|
@ -339,11 +339,6 @@ enum PassType {
|
|||
PASS_TRANSMISSION_COLOR,
|
||||
/* No Scatter color since it's tricky to define what it would even mean. */
|
||||
PASS_MIST,
|
||||
PASS_DENOISING_ALBEDO,
|
||||
PASS_DENOISING_SPECULAR_ALBEDO,
|
||||
PASS_DENOISING_NORMAL,
|
||||
PASS_DENOISING_ROUGHNESS,
|
||||
PASS_DENOISING_DEPTH,
|
||||
PASS_RENDER_TIME,
|
||||
|
||||
/* PASS_SHADOW_CATCHER accumulates contribution of shadow catcher object which is not affected by
|
||||
|
|
@ -374,10 +369,19 @@ enum PassType {
|
|||
PASS_VOLUME_MAJORANT_SAMPLE_COUNT,
|
||||
PASS_CATEGORY_DATA_END = 63,
|
||||
|
||||
/* Denoising passes */
|
||||
PASS_DENOISING_ALBEDO,
|
||||
PASS_DENOISING_SPECULAR_ALBEDO,
|
||||
PASS_DENOISING_NORMAL,
|
||||
PASS_DENOISING_ROUGHNESS,
|
||||
PASS_DENOISING_DEPTH,
|
||||
PASS_DENOISING_BACKWARD_MOTION,
|
||||
PASS_CATEGORY_DENOISING_END = 95,
|
||||
|
||||
PASS_BAKE_PRIMITIVE,
|
||||
PASS_BAKE_SEED,
|
||||
PASS_BAKE_DIFFERENTIAL,
|
||||
PASS_CATEGORY_BAKE_END = 95,
|
||||
PASS_CATEGORY_BAKE_END = 127,
|
||||
|
||||
PASS_DENOISING_PREVIOUS,
|
||||
|
||||
|
|
|
|||
|
|
@ -362,17 +362,15 @@ void Camera::update(Scene *scene)
|
|||
}
|
||||
|
||||
if (need_motion == Scene::MOTION_PASS) {
|
||||
if (camera_type == CAMERA_PANORAMA || camera_type == CAMERA_CUSTOM) {
|
||||
if (have_motion) {
|
||||
kcam->motion_pass_pre = transform_inverse(motion[0]);
|
||||
kcam->motion_pass_post = transform_inverse(motion[motion.size() - 1]);
|
||||
}
|
||||
else {
|
||||
kcam->motion_pass_pre = kcam->worldtocamera;
|
||||
kcam->motion_pass_post = kcam->worldtocamera;
|
||||
}
|
||||
if (have_motion) {
|
||||
kcam->motion_pass_pre = transform_inverse(motion[0]);
|
||||
kcam->motion_pass_post = transform_inverse(motion[motion.size() - 1]);
|
||||
}
|
||||
else {
|
||||
kcam->motion_pass_pre = kcam->worldtocamera;
|
||||
kcam->motion_pass_post = kcam->worldtocamera;
|
||||
}
|
||||
if (camera_type != CAMERA_PANORAMA && camera_type != CAMERA_CUSTOM) {
|
||||
if (have_motion || fov != fov_pre || fov != fov_post) {
|
||||
/* Note the values for perspective_pre/perspective_post calculated for MOTION_PASS are
|
||||
* different to those calculated for MOTION_BLUR below, so the code has not been combined.
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
|||
kfilm->exposure = exposure;
|
||||
kfilm->pass_alpha_threshold = pass_alpha_threshold;
|
||||
kfilm->pass_flag = 0;
|
||||
kfilm->denoising_pass_flag = 0;
|
||||
|
||||
kfilm->use_approximate_shadow_catcher = get_use_approximate_shadow_catcher();
|
||||
|
||||
|
|
@ -200,6 +201,7 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
|||
kfilm->pass_denoising_normal = PASS_UNUSED;
|
||||
kfilm->pass_denoising_roughness = PASS_UNUSED;
|
||||
kfilm->pass_denoising_depth = PASS_UNUSED;
|
||||
kfilm->pass_denoising_backward_motion = PASS_UNUSED;
|
||||
kfilm->pass_sample_count = PASS_UNUSED;
|
||||
kfilm->pass_render_time = PASS_UNUSED;
|
||||
kfilm->pass_adaptive_aux_buffer = PASS_UNUSED;
|
||||
|
|
@ -251,6 +253,9 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
|||
else if (pass->get_type() <= PASS_CATEGORY_DATA_END) {
|
||||
kfilm->pass_flag |= pass_flag;
|
||||
}
|
||||
else if (pass->get_type() <= PASS_CATEGORY_DENOISING_END) {
|
||||
kfilm->denoising_pass_flag |= pass_flag;
|
||||
}
|
||||
else {
|
||||
assert(pass->get_type() <= PASS_CATEGORY_BAKE_END);
|
||||
}
|
||||
|
|
@ -387,6 +392,9 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
|||
case PASS_DENOISING_DEPTH:
|
||||
kfilm->pass_denoising_depth = kfilm->pass_stride;
|
||||
break;
|
||||
case PASS_DENOISING_BACKWARD_MOTION:
|
||||
kfilm->pass_denoising_backward_motion = kfilm->pass_stride;
|
||||
break;
|
||||
|
||||
case PASS_SHADOW_CATCHER:
|
||||
kfilm->pass_shadow_catcher = kfilm->pass_stride;
|
||||
|
|
@ -563,6 +571,9 @@ void Film::update_passes(Scene *scene)
|
|||
if (denoiser_passes & DENOISER_PASS_MOTION) {
|
||||
add_auto_pass(scene, PASS_MOTION);
|
||||
}
|
||||
if (denoiser_passes & DENOISER_PASS_BACKWARD_MOTION) {
|
||||
add_auto_pass(scene, PASS_DENOISING_BACKWARD_MOTION);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create passes for shadow catcher. */
|
||||
|
|
@ -789,7 +800,7 @@ uint Film::get_kernel_features(const Scene *scene) const
|
|||
!is_volume_guiding_pass(pass_type);
|
||||
|
||||
if (has_denoise_pass ||
|
||||
(pass_type >= PASS_DENOISING_ALBEDO && pass_type <= PASS_DENOISING_DEPTH))
|
||||
(pass_type >= PASS_DENOISING_ALBEDO && pass_type <= PASS_DENOISING_BACKWARD_MOTION))
|
||||
{
|
||||
kernel_features |= KERNEL_FEATURE_DENOISING;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ const NodeEnum *Pass::get_type_enum()
|
|||
pass_type_enum.insert("denoising_normal", PASS_DENOISING_NORMAL);
|
||||
pass_type_enum.insert("denoising_roughness", PASS_DENOISING_ROUGHNESS);
|
||||
pass_type_enum.insert("denoising_depth", PASS_DENOISING_DEPTH);
|
||||
pass_type_enum.insert("denoising_backward_motion", PASS_DENOISING_BACKWARD_MOTION);
|
||||
pass_type_enum.insert("denoising_previous", PASS_DENOISING_PREVIOUS);
|
||||
pass_type_enum.insert("volume_majorant", PASS_VOLUME_MAJORANT);
|
||||
pass_type_enum.insert("volume_majorant_sample_count", PASS_VOLUME_MAJORANT_SAMPLE_COUNT);
|
||||
|
|
@ -311,6 +312,7 @@ PassInfo Pass::get_info(const PassType type,
|
|||
case PASS_DENOISING_ALBEDO:
|
||||
case PASS_DENOISING_SPECULAR_ALBEDO:
|
||||
case PASS_DENOISING_NORMAL:
|
||||
case PASS_DENOISING_BACKWARD_MOTION:
|
||||
pass_info.num_components = 3;
|
||||
break;
|
||||
case PASS_DENOISING_ROUGHNESS:
|
||||
|
|
|
|||
|
|
@ -412,7 +412,9 @@ Scene::MotionType Scene::need_motion() const
|
|||
if (integrator->get_motion_blur()) {
|
||||
return MOTION_BLUR;
|
||||
}
|
||||
if (Pass::contains(passes, PASS_MOTION)) {
|
||||
if (Pass::contains(passes, PASS_MOTION) ||
|
||||
Pass::contains(passes, PASS_DENOISING_BACKWARD_MOTION))
|
||||
{
|
||||
return MOTION_PASS;
|
||||
}
|
||||
return MOTION_NONE;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue