Cycles: add denoising settings to the render properties

Enabling render and viewport denoising is now both done from the render
properties. View layers still can individually be enabled/disabled for
denoising and have their own denoising parameters.

Note that the denoising engine also affects how denoising data passes are
output even if no denoising happens on the render itself, to make the passes
compatible with the engine.

This includes internal refactoring for how denoising parameters are passed
along, trying to avoid code duplication and unclear naming.

Ref T76259
This commit is contained in:
Brecht Van Lommel 2020-05-31 23:49:10 +02:00
parent 88157b9efb
commit 0a3bde6300
Notes: blender-bot 2023-02-14 06:05:22 +01:00
Referenced by issue #79219, Cycles NLM denoiser: clean lighting pass is broken
Referenced by issue #76259, Cycles OpenImageDenoise improvements
24 changed files with 474 additions and 244 deletions

View File

@ -182,10 +182,20 @@ enum_aov_types = (
('COLOR', "Color", "Write a Color pass", 1),
)
enum_viewport_denoising = (
('NONE', "None", "Disable viewport denoising", 0),
('OPTIX', "OptiX AI-Accelerated", "Use the OptiX denoiser running on the GPU (requires at least one compatible OptiX device)", 1),
)
def enum_optix_denoiser(self, context):
if not context or bool(context.preferences.addons[__package__].preferences.get_devices_for_type('OPTIX')):
return [('OPTIX', "OptiX", "Use the OptiX AI denoiser with GPU acceleration, only available on NVIDIA GPUs", 2)]
return []
def enum_preview_denoiser(self, context):
items = [('AUTO', "Auto", "Use the fastest available denoiser for viewport rendering", 0)]
items += enum_optix_denoiser(self, context)
return items
def enum_denoiser(self, context):
items = [('NLM', "NLM", "Cycles native non-local means denoiser, running on any compute device", 1)]
items += enum_optix_denoiser(self, context)
return items
enum_denoising_optix_input_passes = (
('RGB', "Color", "Use only color as input", 1),
@ -224,11 +234,29 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Pause all viewport preview renders",
default=False,
)
preview_denoising: EnumProperty(
name="Viewport Denoising",
description="Denoise the image after each preview update with the selected denoiser engine",
items=enum_viewport_denoising,
default='NONE',
use_denoising: BoolProperty(
name="Use Denoising",
description="Denoise the rendered image",
default=False,
)
use_preview_denoising: BoolProperty(
name="Use Viewport Denoising",
description="Denoise the image in the 3D viewport",
default=False,
)
denoiser: EnumProperty(
name="Denoiser",
description="Denoise the image with the selected denoiser",
items=enum_denoiser,
default=1,
)
preview_denoiser: EnumProperty(
name="Viewport Denoiser",
description="Denoise the image after each preview update with the selected denoiser",
items=enum_preview_denoiser,
default=0,
)
use_square_samples: BoolProperty(
@ -244,7 +272,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default=128,
)
preview_samples: IntProperty(
name="Preview Samples",
name="Viewport Samples",
description="Number of samples to render in the viewport, unlimited if 0",
min=0, max=(1 << 24),
default=32,
@ -464,7 +492,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
subtype='PIXEL'
)
preview_dicing_rate: FloatProperty(
name="Preview Dicing Rate",
name="Viewport Dicing Rate",
description="Size of a micropolygon in pixels during preview render",
min=0.1, max=1000.0, soft_min=0.5,
default=8.0,
@ -1330,7 +1358,7 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
use_denoising: BoolProperty(
name="Use Denoising",
description="Denoise the rendered image",
default=False,
default=True,
update=update_render_passes,
)
denoising_diffuse_direct: BoolProperty(
@ -1400,12 +1428,6 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
default=0,
)
use_optix_denoising: BoolProperty(
name="OptiX AI-Accelerated",
description="Use the OptiX denoiser to denoise the rendered image",
default=False,
update=update_render_passes,
)
denoising_optix_input_passes: EnumProperty(
name="Input Passes",
description="Passes handed over to the OptiX denoiser (this can have different effects on the denoised image)",

View File

@ -112,10 +112,6 @@ def show_device_active(context):
return True
return context.preferences.addons[__package__].preferences.has_active_device()
def show_optix_denoising(context):
# OptiX AI denoiser can be used when at least one device supports OptiX
return bool(context.preferences.addons[__package__].preferences.get_devices_for_type('OPTIX'))
def draw_samples_info(layout, context):
cscene = context.scene.cycles
@ -190,11 +186,6 @@ class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
col.prop(cscene, "aa_samples", text="Render")
col.prop(cscene, "preview_aa_samples", text="Viewport")
# Viewport denoising is currently only supported with OptiX
if show_optix_denoising(context):
col = layout.column()
col.prop(cscene, "preview_denoising")
if not use_branched_path(context):
draw_samples_info(layout, context)
@ -256,6 +247,39 @@ class CYCLES_RENDER_PT_sampling_adaptive(CyclesButtonsPanel, Panel):
col.prop(cscene, "adaptive_threshold", text="Noise Threshold")
col.prop(cscene, "adaptive_min_samples", text="Min Samples")
class CYCLES_RENDER_PT_sampling_denoising(CyclesButtonsPanel, Panel):
bl_label = "Denoising"
bl_parent_id = "CYCLES_RENDER_PT_sampling"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = context.scene
cscene = scene.cycles
heading = layout.column(align=True, heading="Render")
row = heading.row(align=True)
row.prop(cscene, "use_denoising", text="")
sub = row.row()
sub.active = cscene.use_denoising
sub.prop(cscene, "denoiser", text="")
heading = layout.column(align=True, heading="Viewport")
row = heading.row(align=True)
row.prop(cscene, "use_preview_denoising", text="")
sub = row.row()
sub.active = cscene.use_preview_denoising
sub.prop(cscene, "preview_denoiser", text="")
sub = heading.row(align=True)
sub.active = cscene.use_preview_denoising
sub.prop(cscene, "preview_denoising_start_sample", text="Start Sample")
class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
bl_label = "Advanced"
bl_parent_id = "CYCLES_RENDER_PT_sampling"
@ -730,11 +754,6 @@ class CYCLES_RENDER_PT_performance_viewport(CyclesButtonsPanel, Panel):
col.prop(rd, "preview_pixel_size", text="Pixel Size")
col.prop(cscene, "preview_start_resolution", text="Start Pixels")
if show_optix_denoising(context):
sub = col.row(align=True)
sub.active = cscene.preview_denoising != 'NONE'
sub.prop(cscene, "preview_denoising_start_sample", text="Denoising Start Sample")
class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
bl_label = "Filter"
@ -957,12 +976,17 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
bl_context = "view_layer"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
cscene = context.scene.cycles
return CyclesButtonsPanel.poll(context) and cscene.use_denoising
def draw_header(self, context):
scene = context.scene
view_layer = context.view_layer
cycles_view_layer = view_layer.cycles
layout = self.layout
layout = self.layout
layout.prop(cycles_view_layer, "use_denoising", text="")
def draw(self, context):
@ -973,18 +997,15 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
scene = context.scene
view_layer = context.view_layer
cycles_view_layer = view_layer.cycles
denoiser = scene.cycles.denoiser
layout.active = cycles_view_layer.use_denoising
layout.active = denoiser != 'NONE' and cycles_view_layer.use_denoising
col = layout.column()
if show_optix_denoising(context):
col.prop(cycles_view_layer, "use_optix_denoising")
col.separator(factor=2.0)
if cycles_view_layer.use_optix_denoising:
col.prop(cycles_view_layer, "denoising_optix_input_passes")
return
if denoiser == 'OPTIX':
col.prop(cycles_view_layer, "denoising_optix_input_passes")
return
col.prop(cycles_view_layer, "denoising_radius", text="Radius")
@ -2237,6 +2258,7 @@ classes = (
CYCLES_RENDER_PT_sampling,
CYCLES_RENDER_PT_sampling_sub_samples,
CYCLES_RENDER_PT_sampling_adaptive,
CYCLES_RENDER_PT_sampling_denoising,
CYCLES_RENDER_PT_sampling_advanced,
CYCLES_RENDER_PT_light_paths,
CYCLES_RENDER_PT_light_paths_max_bounces,

View File

@ -873,7 +873,8 @@ BufferParams BlenderSync::get_buffer_params(BL::Scene &b_scene,
BL::RegionView3D &b_rv3d,
Camera *cam,
int width,
int height)
int height,
const bool use_denoiser)
{
BufferParams params;
bool use_border = false;
@ -907,8 +908,7 @@ BufferParams BlenderSync::get_buffer_params(BL::Scene &b_scene,
PassType display_pass = update_viewport_display_passes(b_v3d, params.passes);
/* Can only denoise the combined image pass */
params.denoising_data_pass = display_pass == PASS_COMBINED &&
update_viewport_display_denoising(b_v3d, b_scene);
params.denoising_data_pass = display_pass == PASS_COMBINED && use_denoiser;
return params;
}

View File

@ -21,13 +21,6 @@
CCL_NAMESPACE_BEGIN
enum DenoiserType {
DENOISER_NONE = 0,
DENOISER_OPTIX = 1,
DENOISER_NUM
};
enum ComputeDevice {
COMPUTE_DEVICE_CPU = 0,
COMPUTE_DEVICE_CUDA = 1,
@ -120,49 +113,6 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
}
}
/* Ensure there is an OptiX device when using the OptiX denoiser. */
bool use_optix_denoising = get_enum(cscene, "preview_denoising", DENOISER_NUM, DENOISER_NONE) ==
DENOISER_OPTIX &&
!background;
BL::Scene::view_layers_iterator b_view_layer;
for (b_scene.view_layers.begin(b_view_layer); b_view_layer != b_scene.view_layers.end();
++b_view_layer) {
PointerRNA crl = RNA_pointer_get(&b_view_layer->ptr, "cycles");
if (get_boolean(crl, "use_optix_denoising")) {
use_optix_denoising = true;
}
}
if (use_optix_denoising && device.type != DEVICE_OPTIX) {
vector<DeviceInfo> optix_devices = Device::available_devices(DEVICE_MASK_OPTIX);
if (!optix_devices.empty()) {
/* Convert to a special multi device with separate denoising devices. */
if (device.multi_devices.empty()) {
device.multi_devices.push_back(device);
}
/* Try to use the same physical devices for denoising. */
for (const DeviceInfo &cuda_device : device.multi_devices) {
if (cuda_device.type == DEVICE_CUDA) {
for (const DeviceInfo &optix_device : optix_devices) {
if (cuda_device.num == optix_device.num) {
device.id += optix_device.id;
device.denoising_devices.push_back(optix_device);
break;
}
}
}
}
if (device.denoising_devices.empty()) {
/* Simply use the first available OptiX device. */
const DeviceInfo optix_device = optix_devices.front();
device.id += optix_device.id; /* Uniquely identify this special multi device. */
device.denoising_devices.push_back(optix_device);
}
}
}
return device;
}

View File

@ -157,8 +157,14 @@ void BlenderSession::create_session()
}
/* set buffer parameters */
BufferParams buffer_params = BlenderSync::get_buffer_params(
b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene,
b_render,
b_v3d,
b_rv3d,
scene->camera,
width,
height,
session_params.denoising.use);
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
@ -239,8 +245,14 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL);
BL::RegionView3D b_null_region_view3d(PointerRNA_NULL);
BufferParams buffer_params = BlenderSync::get_buffer_params(
b_scene, b_render, b_null_space_view3d, b_null_region_view3d, scene->camera, width, height);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene,
b_render,
b_null_space_view3d,
b_null_region_view3d,
scene->camera,
width,
height,
session_params.denoising.use);
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
@ -468,14 +480,19 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
session->update_render_tile_cb = function_bind(
&BlenderSession::update_render_tile, this, _1, _2);
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
/* get buffer parameters */
SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background);
BufferParams buffer_params = BlenderSync::get_buffer_params(
b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height);
/* render each layer */
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
b_engine, b_userpref, b_scene, background, b_view_layer);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene,
b_render,
b_v3d,
b_rv3d,
scene->camera,
width,
height,
session_params.denoising.use);
/* temporary render result to find needed passes and views */
BL::RenderResult b_rr = begin_render_result(
@ -485,35 +502,26 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
BL::RenderLayer b_rlay = *b_single_rlay;
b_rlay_name = b_view_layer.name();
/* add passes */
vector<Pass> passes = sync->sync_render_passes(
b_rlay, b_view_layer, session_params.adaptive_sampling);
buffer_params.passes = passes;
/* Update denoising parameters. */
session->set_denoising(session_params.denoising);
PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
bool use_denoising = get_boolean(crl, "use_denoising");
bool use_optix_denoising = get_boolean(crl, "use_optix_denoising");
bool write_denoising_passes = get_boolean(crl, "denoising_store_passes");
bool use_denoising = session_params.denoising.use;
bool store_denoising_passes = session_params.denoising.store_passes;
buffer_params.denoising_data_pass = use_denoising || write_denoising_passes;
buffer_params.denoising_data_pass = use_denoising || store_denoising_passes;
buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES);
buffer_params.denoising_prefiltered_pass = write_denoising_passes && !use_optix_denoising;
session->params.run_denoising = use_denoising || write_denoising_passes;
session->params.full_denoising = use_denoising && !use_optix_denoising;
session->params.optix_denoising = use_denoising && use_optix_denoising;
session->params.write_denoising_passes = write_denoising_passes && !use_optix_denoising;
session->params.denoising.radius = get_int(crl, "denoising_radius");
session->params.denoising.strength = get_float(crl, "denoising_strength");
session->params.denoising.feature_strength = get_float(crl, "denoising_feature_strength");
session->params.denoising.relative_pca = get_boolean(crl, "denoising_relative_pca");
session->params.denoising.optix_input_passes = get_enum(crl, "denoising_optix_input_passes");
session->tile_manager.schedule_denoising = session->params.run_denoising;
buffer_params.denoising_prefiltered_pass = store_denoising_passes &&
session_params.denoising.type == DENOISER_NLM;
scene->film->denoising_data_pass = buffer_params.denoising_data_pass;
scene->film->denoising_clean_pass = buffer_params.denoising_clean_pass;
scene->film->denoising_prefiltered_pass = buffer_params.denoising_prefiltered_pass;
/* Add passes */
vector<Pass> passes = sync->sync_render_passes(
b_rlay, b_view_layer, session_params.adaptive_sampling, session_params.denoising);
buffer_params.passes = passes;
scene->film->pass_alpha_threshold = b_view_layer.pass_alpha_threshold();
scene->film->tag_passes_update(scene, passes);
scene->film->tag_update(scene);
@ -798,7 +806,7 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
/* increase samples, but never decrease */
session->set_samples(session_params.samples);
session->set_denoising_start_sample(session_params.denoising_start_sample);
session->set_denoising_start_sample(session_params.denoising.start_sample);
session->set_pause(session_pause);
/* copy recalc flags, outside of mutex so we can decide to do the real
@ -830,22 +838,24 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
sync->sync_camera(b_render, b_camera_override, width, height, "");
/* get buffer parameters */
BufferParams buffer_params = BlenderSync::get_buffer_params(
b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene,
b_render,
b_v3d,
b_rv3d,
scene->camera,
width,
height,
session_params.denoising.use);
if (session_params.device.type != DEVICE_OPTIX &&
session_params.device.denoising_devices.empty()) {
/* cannot use OptiX denoising when it is not supported by the device. */
buffer_params.denoising_data_pass = false;
}
else {
session->set_denoising(buffer_params.denoising_data_pass, true);
if (!buffer_params.denoising_data_pass) {
session_params.denoising.use = false;
}
session->set_denoising(session_params.denoising);
/* Update film if denoising data was enabled or disabled. */
if (scene->film->denoising_data_pass != buffer_params.denoising_data_pass) {
scene->film->denoising_data_pass = buffer_params.denoising_data_pass;
/* Force a scene and session reset below. */
scene->film->tag_update(scene);
}
@ -916,8 +926,14 @@ bool BlenderSession::draw(int w, int h)
if (reset) {
SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background);
BufferParams buffer_params = BlenderSync::get_buffer_params(
b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene,
b_render,
b_v3d,
b_rv3d,
scene->camera,
width,
height,
session_params.denoising.use);
bool session_pause = BlenderSync::get_session_pause(b_scene, background);
if (session_pause == false) {
@ -934,8 +950,14 @@ bool BlenderSession::draw(int w, int h)
update_status_progress();
/* draw */
BufferParams buffer_params = BlenderSync::get_buffer_params(
b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene,
b_render,
b_v3d,
b_rv3d,
scene->camera,
width,
height,
session->params.denoising.use);
DeviceDrawParams draw_params;
if (session->params.display_buffer_linear) {

View File

@ -537,7 +537,8 @@ int BlenderSync::get_denoising_pass(BL::RenderPass &b_pass)
vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
BL::ViewLayer &b_view_layer,
bool adaptive_sampling)
bool adaptive_sampling,
const DenoiseParams &denoising)
{
vector<Pass> passes;
@ -554,16 +555,13 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
Pass::add(pass_type, passes, b_pass.name().c_str());
}
PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles");
bool use_denoising = get_boolean(crp, "use_denoising");
bool use_optix_denoising = get_boolean(crp, "use_optix_denoising");
bool write_denoising_passes = get_boolean(crp, "denoising_store_passes");
PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
scene->film->denoising_flags = 0;
if (use_denoising || write_denoising_passes) {
if (!use_optix_denoising) {
if (denoising.use || denoising.store_passes) {
if (denoising.type == DENOISER_NLM) {
#define MAP_OPTION(name, flag) \
if (!get_boolean(crp, name)) \
if (!get_boolean(crl, name)) \
scene->film->denoising_flags |= flag;
MAP_OPTION("denoising_diffuse_direct", DENOISING_CLEAN_DIFFUSE_DIR);
MAP_OPTION("denoising_diffuse_indirect", DENOISING_CLEAN_DIFFUSE_IND);
@ -576,11 +574,11 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str());
}
if (write_denoising_passes) {
if (denoising.store_passes) {
b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str());
b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str());
b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str());
if (!use_optix_denoising) {
if (denoising.type == DENOISER_NLM) {
b_engine.add_pass("Denoising Shadowing", 1, "X", b_view_layer.name().c_str());
b_engine.add_pass("Denoising Variance", 3, "RGB", b_view_layer.name().c_str());
b_engine.add_pass("Denoising Intensity", 1, "X", b_view_layer.name().c_str());
@ -592,46 +590,46 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
}
#ifdef __KERNEL_DEBUG__
if (get_boolean(crp, "pass_debug_bvh_traversed_nodes")) {
if (get_boolean(crl, "pass_debug_bvh_traversed_nodes")) {
b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str());
Pass::add(PASS_BVH_TRAVERSED_NODES, passes, "Debug BVH Traversed Nodes");
}
if (get_boolean(crp, "pass_debug_bvh_traversed_instances")) {
if (get_boolean(crl, "pass_debug_bvh_traversed_instances")) {
b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_view_layer.name().c_str());
Pass::add(PASS_BVH_TRAVERSED_INSTANCES, passes, "Debug BVH Traversed Instances");
}
if (get_boolean(crp, "pass_debug_bvh_intersections")) {
if (get_boolean(crl, "pass_debug_bvh_intersections")) {
b_engine.add_pass("Debug BVH Intersections", 1, "X", b_view_layer.name().c_str());
Pass::add(PASS_BVH_INTERSECTIONS, passes, "Debug BVH Intersections");
}
if (get_boolean(crp, "pass_debug_ray_bounces")) {
if (get_boolean(crl, "pass_debug_ray_bounces")) {
b_engine.add_pass("Debug Ray Bounces", 1, "X", b_view_layer.name().c_str());
Pass::add(PASS_RAY_BOUNCES, passes, "Debug Ray Bounces");
}
#endif
if (get_boolean(crp, "pass_debug_render_time")) {
if (get_boolean(crl, "pass_debug_render_time")) {
b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str());
Pass::add(PASS_RENDER_TIME, passes, "Debug Render Time");
}
if (get_boolean(crp, "pass_debug_sample_count")) {
if (get_boolean(crl, "pass_debug_sample_count")) {
b_engine.add_pass("Debug Sample Count", 1, "X", b_view_layer.name().c_str());
Pass::add(PASS_SAMPLE_COUNT, passes, "Debug Sample Count");
}
if (get_boolean(crp, "use_pass_volume_direct")) {
if (get_boolean(crl, "use_pass_volume_direct")) {
b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str());
Pass::add(PASS_VOLUME_DIRECT, passes, "VolumeDir");
}
if (get_boolean(crp, "use_pass_volume_indirect")) {
if (get_boolean(crl, "use_pass_volume_indirect")) {
b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str());
Pass::add(PASS_VOLUME_INDIRECT, passes, "VolumeInd");
}
/* Cryptomatte stores two ID/weight pairs per RGBA layer.
* User facing parameter is the number of pairs. */
int crypto_depth = divide_up(min(16, get_int(crp, "pass_crypto_depth")), 2);
int crypto_depth = divide_up(min(16, get_int(crl, "pass_crypto_depth")), 2);
scene->film->cryptomatte_depth = crypto_depth;
scene->film->cryptomatte_passes = CRYPT_NONE;
if (get_boolean(crp, "use_pass_crypto_object")) {
if (get_boolean(crl, "use_pass_crypto_object")) {
for (int i = 0; i < crypto_depth; i++) {
string passname = cryptomatte_prefix + string_printf("Object%02d", i);
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
@ -640,7 +638,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes |
CRYPT_OBJECT);
}
if (get_boolean(crp, "use_pass_crypto_material")) {
if (get_boolean(crl, "use_pass_crypto_material")) {
for (int i = 0; i < crypto_depth; i++) {
string passname = cryptomatte_prefix + string_printf("Material%02d", i);
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
@ -649,7 +647,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes |
CRYPT_MATERIAL);
}
if (get_boolean(crp, "use_pass_crypto_asset")) {
if (get_boolean(crl, "use_pass_crypto_asset")) {
for (int i = 0; i < crypto_depth; i++) {
string passname = cryptomatte_prefix + string_printf("Asset%02d", i);
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
@ -658,19 +656,19 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes |
CRYPT_ASSET);
}
if (get_boolean(crp, "pass_crypto_accurate") && scene->film->cryptomatte_passes != CRYPT_NONE) {
if (get_boolean(crl, "pass_crypto_accurate") && scene->film->cryptomatte_passes != CRYPT_NONE) {
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes |
CRYPT_ACCURATE);
}
if (adaptive_sampling) {
Pass::add(PASS_ADAPTIVE_AUX_BUFFER, passes);
if (!get_boolean(crp, "pass_debug_sample_count")) {
if (!get_boolean(crl, "pass_debug_sample_count")) {
Pass::add(PASS_SAMPLE_COUNT, passes);
}
}
RNA_BEGIN (&crp, b_aov, "aovs") {
RNA_BEGIN (&crl, b_aov, "aovs") {
bool is_color = (get_enum(b_aov, "type") == 1);
string name = get_string(b_aov, "name");
@ -773,7 +771,8 @@ bool BlenderSync::get_session_pause(BL::Scene &b_scene, bool background)
SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
BL::Preferences &b_preferences,
BL::Scene &b_scene,
bool background)
bool background,
BL::ViewLayer b_view_layer)
{
SessionParams params;
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
@ -851,9 +850,22 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
params.tile_order = TILE_BOTTOM_TO_TOP;
}
/* other parameters */
/* Denoising */
params.denoising = get_denoise_params(b_scene, b_view_layer, background);
if (params.denoising.use) {
/* Add additional denoising devices if we are rendering and denoising
* with different devices. */
params.device.add_denoising_devices(params.denoising.type);
/* Check if denoiser is supported by device. */
if (!(params.device.denoisers & params.denoising.type)) {
params.denoising.use = false;
}
}
/* Viewport Performance */
params.start_resolution = get_int(cscene, "preview_start_resolution");
params.denoising_start_sample = get_int(cscene, "preview_denoising_start_sample");
params.pixel_size = b_engine.get_preview_pixel_size(b_scene);
/* other parameters */
@ -906,4 +918,52 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
return params;
}
DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
BL::ViewLayer &b_view_layer,
bool background)
{
DenoiseParams denoising;
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
if (background) {
/* Final Render Denoising */
denoising.use = get_boolean(cscene, "use_denoising");
denoising.type = (DenoiserType)get_enum(cscene, "denoiser", DENOISER_NUM, DENOISER_NONE);
if (b_view_layer) {
PointerRNA clayer = RNA_pointer_get(&b_view_layer.ptr, "cycles");
if (!get_boolean(clayer, "use_denoising")) {
denoising.use = false;
}
denoising.radius = get_int(clayer, "denoising_radius");
denoising.strength = get_float(clayer, "denoising_strength");
denoising.feature_strength = get_float(clayer, "denoising_feature_strength");
denoising.relative_pca = get_boolean(clayer, "denoising_relative_pca");
denoising.optix_input_passes = get_enum(clayer, "denoising_optix_input_passes");
denoising.store_passes = get_boolean(clayer, "denoising_store_passes");
}
}
else {
/* Viewport Denoising */
denoising.use = get_boolean(cscene, "use_preview_denoising");
denoising.type = (DenoiserType)get_enum(
cscene, "preview_denoiser", DENOISER_NUM, DENOISER_NONE);
denoising.start_sample = get_int(cscene, "preview_denoising_start_sample");
/* Auto select fastest denoiser. */
if (denoising.type == DENOISER_NONE) {
if (!Device::available_devices(DEVICE_MASK_OPTIX).empty()) {
denoising.type = DENOISER_OPTIX;
}
else {
denoising.use = false;
}
}
}
return denoising;
}
CCL_NAMESPACE_END

View File

@ -75,7 +75,8 @@ class BlenderSync {
void sync_view_layer(BL::SpaceView3D &b_v3d, BL::ViewLayer &b_view_layer);
vector<Pass> sync_render_passes(BL::RenderLayer &b_render_layer,
BL::ViewLayer &b_view_layer,
bool adaptive_sampling);
bool adaptive_sampling,
const DenoiseParams &denoising);
void sync_integrator();
void sync_camera(BL::RenderSettings &b_render,
BL::Object &b_override,
@ -94,10 +95,12 @@ class BlenderSync {
/* get parameters */
static SceneParams get_scene_params(BL::Scene &b_scene, bool background);
static SessionParams get_session_params(BL::RenderEngine &b_engine,
BL::Preferences &b_userpref,
BL::Scene &b_scene,
bool background);
static SessionParams get_session_params(
BL::RenderEngine &b_engine,
BL::Preferences &b_userpref,
BL::Scene &b_scene,
bool background,
BL::ViewLayer b_view_layer = BL::ViewLayer(PointerRNA_NULL));
static bool get_session_pause(BL::Scene &b_scene, bool background);
static BufferParams get_buffer_params(BL::Scene &b_scene,
BL::RenderSettings &b_render,
@ -105,12 +108,17 @@ class BlenderSync {
BL::RegionView3D &b_rv3d,
Camera *cam,
int width,
int height);
int height,
const bool use_denoiser);
static PassType get_pass_type(BL::RenderPass &b_pass);
static int get_denoising_pass(BL::RenderPass &b_pass);
private:
static DenoiseParams get_denoise_params(BL::Scene &b_scene,
BL::ViewLayer &b_view_layer,
bool background);
/* sync */
void sync_lights(BL::Depsgraph &b_depsgraph, bool update_all);
void sync_materials(BL::Depsgraph &b_depsgraph, bool update_all);

View File

@ -61,17 +61,6 @@ const bool BlenderViewportParameters::custom_viewport_parameters() const
return !(use_scene_world && use_scene_lights);
}
bool BlenderViewportParameters::get_viewport_display_denoising(BL::SpaceView3D &b_v3d,
BL::Scene &b_scene)
{
bool use_denoising = false;
if (b_v3d) {
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
use_denoising = get_enum(cscene, "preview_denoising") != 0;
}
return use_denoising;
}
PassType BlenderViewportParameters::get_viewport_display_render_pass(BL::SpaceView3D &b_v3d)
{
PassType display_pass = PASS_NONE;
@ -83,11 +72,6 @@ PassType BlenderViewportParameters::get_viewport_display_render_pass(BL::SpaceVi
return display_pass;
}
bool update_viewport_display_denoising(BL::SpaceView3D &b_v3d, BL::Scene &b_scene)
{
return BlenderViewportParameters::get_viewport_display_denoising(b_v3d, b_scene);
}
PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes)
{
if (b_v3d) {

View File

@ -44,15 +44,11 @@ class BlenderViewportParameters {
friend class BlenderSync;
public:
/* Get whether to enable denoising data pass in viewport. */
static bool get_viewport_display_denoising(BL::SpaceView3D &b_v3d, BL::Scene &b_scene);
/* Retrieve the render pass that needs to be displayed on the given `SpaceView3D`
* When the `b_v3d` parameter is not given `PASS_NONE` will be returned. */
static PassType get_viewport_display_render_pass(BL::SpaceView3D &b_v3d);
};
bool update_viewport_display_denoising(BL::SpaceView3D &b_v3d, BL::Scene &b_scene);
PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes);
CCL_NAMESPACE_END

View File

@ -603,6 +603,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
info.has_osl = true;
info.has_profiling = true;
info.has_peer_memory = false;
info.denoisers = DENOISER_ALL;
foreach (const DeviceInfo &device, subdevices) {
/* Ensure CPU device does not slow down GPU. */
@ -647,6 +648,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
info.has_osl &= device.has_osl;
info.has_profiling &= device.has_profiling;
info.has_peer_memory |= device.has_peer_memory;
info.denoisers &= device.denoisers;
}
return info;
@ -667,4 +669,43 @@ void Device::free_memory()
network_devices.free_memory();
}
/* DeviceInfo */
void DeviceInfo::add_denoising_devices(DenoiserType denoiser_type)
{
assert(denoising_devices.empty());
if (denoiser_type == DENOISER_OPTIX && type != DEVICE_OPTIX) {
vector<DeviceInfo> optix_devices = Device::available_devices(DEVICE_MASK_OPTIX);
if (!optix_devices.empty()) {
/* Convert to a special multi device with separate denoising devices. */
if (multi_devices.empty()) {
multi_devices.push_back(*this);
}
/* Try to use the same physical devices for denoising. */
for (const DeviceInfo &cuda_device : multi_devices) {
if (cuda_device.type == DEVICE_CUDA) {
for (const DeviceInfo &optix_device : optix_devices) {
if (cuda_device.num == optix_device.num) {
id += optix_device.id;
denoising_devices.push_back(optix_device);
break;
}
}
}
}
if (denoising_devices.empty()) {
/* Simply use the first available OptiX device. */
const DeviceInfo optix_device = optix_devices.front();
id += optix_device.id; /* Uniquely identify this special multi device. */
denoising_devices.push_back(optix_device);
}
denoisers = denoiser_type;
}
}
}
CCL_NAMESPACE_END

View File

@ -83,6 +83,7 @@ class DeviceInfo {
bool use_split_kernel; /* Use split or mega kernel. */
bool has_profiling; /* Supports runtime collection of profiling info. */
bool has_peer_memory; /* GPU has P2P access to memory of another GPU. */
DenoiserTypeMask denoisers; /* Supported denoiser types. */
int cpu_threads;
vector<DeviceInfo> multi_devices;
vector<DeviceInfo> denoising_devices;
@ -101,6 +102,7 @@ class DeviceInfo {
use_split_kernel = false;
has_profiling = false;
has_peer_memory = false;
denoisers = DENOISER_NONE;
}
bool operator==(const DeviceInfo &info)
@ -110,6 +112,9 @@ class DeviceInfo {
(type == info.type && num == info.num && description == info.description));
return id == info.id;
}
/* Add additional devices needed for the specified denoiser. */
void add_denoising_devices(DenoiserType denoiser_type);
};
class DeviceRequestedFeatures {

View File

@ -943,7 +943,7 @@ class CPUDevice : public Device {
}
}
void denoise(DenoisingTask &denoising, RenderTile &tile)
void denoise_nlm(DenoisingTask &denoising, RenderTile &tile)
{
ProfilingHelper profiling(denoising.profiler, PROFILING_DENOISING);
@ -1001,10 +1001,9 @@ class CPUDevice : public Device {
}
}
RenderTile tile;
DenoisingTask denoising(this, task);
denoising.profiler = &kg->profiler;
DenoisingTask *denoising = NULL;
RenderTile tile;
while (task.acquire_tile(this, tile, task.tile_types)) {
if (tile.task == RenderTile::PATH_TRACE) {
if (use_split_kernel) {
@ -1019,7 +1018,13 @@ class CPUDevice : public Device {
render(task, tile, kg);
}
else if (tile.task == RenderTile::DENOISE) {
denoise(denoising, tile);
if (task.denoising.type == DENOISER_NLM) {
if (denoising == NULL) {
denoising = new DenoisingTask(this, task);
denoising->profiler = &kg->profiler;
}
denoise_nlm(*denoising, tile);
}
task.update_progress(&tile, tile.w * tile.h);
}
@ -1037,6 +1042,7 @@ class CPUDevice : public Device {
kg->~KernelGlobals();
kgbuffer.free();
delete split_kernel;
delete denoising;
}
void thread_denoise(DeviceTask &task)
@ -1060,7 +1066,7 @@ class CPUDevice : public Device {
profiler.add_state(&denoising_profiler_state);
denoising.profiler = &denoising_profiler_state;
denoise(denoising, tile);
denoise_nlm(denoising, tile);
task.update_progress(&tile, tile.w * tile.h);
profiler.remove_state(&denoising_profiler_state);
@ -1344,6 +1350,7 @@ void device_cpu_info(vector<DeviceInfo> &devices)
info.has_osl = true;
info.has_half_images = true;
info.has_profiling = true;
info.denoisers = DENOISER_NLM;
devices.insert(devices.begin(), info);
}

View File

@ -130,6 +130,7 @@ void device_cuda_info(vector<DeviceInfo> &devices)
info.has_half_images = (major >= 3);
info.has_volume_decoupled = false;
info.has_adaptive_stop_per_sample = false;
info.denoisers = DENOISER_NLM;
/* Check if the device has P2P access to any other device in the system. */
for (int peer_num = 0; peer_num < count && !info.has_peer_memory; peer_num++) {

View File

@ -56,8 +56,8 @@ DenoisingTask::DenoisingTask(Device *device, const DeviceTask &task)
tile_info->frames[i] = task.denoising_frames[i - 1];
}
write_passes = task.denoising_write_passes;
do_filter = task.denoising_do_filter;
do_prefilter = task.denoising.store_passes && task.denoising.type == DENOISER_NLM;
do_filter = task.denoising_do_filter && task.denoising.type == DENOISER_NLM;
}
DenoisingTask::~DenoisingTask()
@ -91,7 +91,7 @@ void DenoisingTask::set_render_buffer(RenderTile *rtiles)
target_buffer.stride = rtiles[9].stride;
target_buffer.ptr = rtiles[9].buffer;
if (write_passes && rtiles[9].buffers) {
if (do_prefilter && rtiles[9].buffers) {
target_buffer.denoising_output_offset =
rtiles[9].buffers->params.get_denoising_prefiltered_offset();
}
@ -111,7 +111,7 @@ void DenoisingTask::setup_denoising_buffer()
rect = rect_clip(rect,
make_int4(tile_info->x[0], tile_info->y[0], tile_info->x[3], tile_info->y[3]));
buffer.use_intensity = write_passes || (tile_info->num_frames > 1);
buffer.use_intensity = do_prefilter || (tile_info->num_frames > 1);
buffer.passes = buffer.use_intensity ? 15 : 14;
buffer.width = rect.z - rect.x;
buffer.stride = align_up(buffer.width, 4);
@ -343,7 +343,7 @@ void DenoisingTask::run_denoising(RenderTile *tile)
reconstruct();
}
if (write_passes) {
if (do_prefilter) {
write_buffer();
}

View File

@ -60,7 +60,7 @@ class DenoisingTask {
int4 rect;
int4 filter_area;
bool write_passes;
bool do_prefilter;
bool do_filter;
struct DeviceFunctions {

View File

@ -313,6 +313,7 @@ void device_network_info(vector<DeviceInfo> &devices)
info.has_volume_decoupled = false;
info.has_adaptive_stop_per_sample = false;
info.has_osl = false;
info.denoisers = DENOISER_NONE;
devices.push_back(info);
}

View File

@ -120,6 +120,7 @@ void device_opencl_info(vector<DeviceInfo> &devices)
info.use_split_kernel = true;
info.has_volume_decoupled = false;
info.has_adaptive_stop_per_sample = false;
info.denoisers = DENOISER_NLM;
info.id = id;
/* Check OpenCL extensions */

View File

@ -721,7 +721,7 @@ class OptiXDevice : public CUDADevice {
const CUDAContextScope scope(cuContext);
// Choose between OptiX and NLM denoising
if (task.denoising_use_optix) {
if (task.denoising.type == DENOISER_OPTIX) {
// Map neighboring tiles onto this device, indices are as following:
// Where index 4 is the center tile and index 9 is the target for the result.
// 0 1 2
@ -1561,6 +1561,7 @@ void device_optix_info(const vector<DeviceInfo> &cuda_devices, vector<DeviceInfo
info.type = DEVICE_OPTIX;
info.id += "_OptiX";
info.denoisers |= DENOISER_OPTIX;
devices.push_back(info);
}

View File

@ -31,8 +31,32 @@ class RenderBuffers;
class RenderTile;
class Tile;
enum DenoiserType {
DENOISER_NLM = 1,
DENOISER_OPTIX = 2,
DENOISER_NUM,
DENOISER_NONE = 0,
DENOISER_ALL = ~0,
};
typedef int DenoiserTypeMask;
class DenoiseParams {
public:
/* Apply denoiser to image. */
bool use;
/* Output denoising data passes (possibly without applying the denoiser). */
bool store_passes;
/* Denoiser type. */
DenoiserType type;
/* Viewport start sample. */
int start_sample;
/** Native Denoiser **/
/* Pixel radius for neighboring pixels to take into account. */
int radius;
/* Controls neighbor pixel weighting for the denoising filter. */
@ -46,18 +70,36 @@ class DenoiseParams {
int neighbor_frames;
/* Clamp the input to the range of +-1e8. Should be enough for any legitimate data. */
bool clamp_input;
/** Optix Denoiser **/
/* Passes handed over to the OptiX denoiser (default to color + albedo). */
int optix_input_passes;
DenoiseParams()
{
use = false;
store_passes = false;
type = DENOISER_NLM;
radius = 8;
strength = 0.5f;
feature_strength = 0.5f;
relative_pca = false;
neighbor_frames = 2;
clamp_input = true;
optix_input_passes = 2;
start_sample = 0;
}
/* Test if a denoising task needs to run, also to prefilter passes for the native
* denoiser when we are not applying denoising to the combined image. */
bool need_denoising_task() const
{
return (use || (store_passes && type == DENOISER_NLM));
}
};
@ -116,8 +158,7 @@ class DeviceTask {
vector<int> denoising_frames;
bool denoising_do_filter;
bool denoising_use_optix;
bool denoising_write_passes;
bool denoising_do_prefilter;
int pass_stride;
int frame_stride;

View File

@ -378,8 +378,9 @@ void DenoiseTask::create_task(DeviceTask &task)
/* Denoising parameters. */
task.denoising = denoiser->params;
task.denoising_do_filter = true;
task.denoising_write_passes = false;
task.denoising.type = DENOISER_NLM;
task.denoising.use = true;
task.denoising.store_passes = false;
task.denoising_from_render = false;
task.denoising_frames.resize(neighbor_frames.size());

View File

@ -805,7 +805,7 @@ DeviceRequestedFeatures Session::get_requested_device_features()
requested_features.use_baking = bake_manager->get_baking();
requested_features.use_integrator_branched = (scene->integrator->method ==
Integrator::BRANCHED_PATH);
if (params.run_denoising) {
if (params.denoising.use || params.denoising.store_passes) {
requested_features.use_denoising = true;
requested_features.use_shadow_tricks = true;
}
@ -942,24 +942,31 @@ void Session::set_pause(bool pause_)
pause_cond.notify_all();
}
void Session::set_denoising(bool denoising, bool optix_denoising)
void Session::set_denoising(const DenoiseParams &denoising)
{
const bool need_denoise = denoising.need_denoising_task();
if (need_denoise && !(params.device.denoisers & denoising.type)) {
progress.set_error("Denoiser type not supported by compute device");
return;
}
/* Lock buffers so no denoising operation is triggered while the settings are changed here. */
thread_scoped_lock buffers_lock(buffers_mutex);
params.run_denoising = denoising;
params.full_denoising = !optix_denoising;
params.optix_denoising = optix_denoising;
params.denoising = denoising;
// TODO(pmours): Query the required overlap value for denoising from the device?
tile_manager.slice_overlap = denoising && !params.background ? 64 : 0;
tile_manager.schedule_denoising = denoising && !buffers;
tile_manager.slice_overlap = need_denoise && !params.background ? 64 : 0;
/* Schedule per tile denoising for final renders if we are either denoising or
* need prefiltered passes for the native denoiser. */
tile_manager.schedule_denoising = need_denoise && !buffers;
}
void Session::set_denoising_start_sample(int sample)
{
if (sample != params.denoising_start_sample) {
params.denoising_start_sample = sample;
if (sample != params.denoising.start_sample) {
params.denoising.start_sample = sample;
pause_cond.notify_all();
}
@ -1079,10 +1086,10 @@ void Session::update_status_time(bool show_pause, bool show_done)
*/
substatus += string_printf(", Sample %d/%d", progress.get_current_sample(), num_samples);
}
if (params.full_denoising || params.optix_denoising) {
if (params.denoising.use) {
substatus += string_printf(", Denoised %d tiles", progress.get_denoised_tiles());
}
else if (params.run_denoising) {
else if (params.denoising.store_passes && params.denoising.type == DENOISER_NLM) {
substatus += string_printf(", Prefiltered %d tiles", progress.get_denoised_tiles());
}
}
@ -1111,7 +1118,7 @@ bool Session::render_need_denoise(bool &delayed)
delayed = false;
/* Denoising enabled? */
if (!params.run_denoising) {
if (!params.denoising.need_denoising_task()) {
return false;
}
@ -1128,7 +1135,7 @@ bool Session::render_need_denoise(bool &delayed)
}
/* Do not denoise until the sample at which denoising should start is reached. */
if (tile_manager.state.sample < params.denoising_start_sample) {
if (tile_manager.state.sample < params.denoising.start_sample) {
return false;
}
@ -1179,9 +1186,6 @@ void Session::render(bool need_denoise)
task.pass_denoising_clean = scene->film->denoising_clean_offset;
task.denoising_from_render = true;
task.denoising_do_filter = params.full_denoising;
task.denoising_use_optix = params.optix_denoising;
task.denoising_write_passes = params.write_denoising_passes;
if (tile_manager.schedule_denoising) {
/* Acquire denoising tiles during rendering. */

View File

@ -62,10 +62,6 @@ class SessionParams {
bool display_buffer_linear;
bool run_denoising;
bool write_denoising_passes;
bool full_denoising;
bool optix_denoising;
DenoiseParams denoising;
double cancel_timeout;
@ -94,11 +90,6 @@ class SessionParams {
use_profiling = false;
run_denoising = false;
write_denoising_passes = false;
full_denoising = false;
optix_denoising = false;
display_buffer_linear = false;
cancel_timeout = 0.1;
@ -125,7 +116,8 @@ class SessionParams {
cancel_timeout == params.cancel_timeout && reset_timeout == params.reset_timeout &&
text_timeout == params.text_timeout &&
progressive_update_timeout == params.progressive_update_timeout &&
tile_order == params.tile_order && shadingsystem == params.shadingsystem);
tile_order == params.tile_order && shadingsystem == params.shadingsystem &&
denoising.type == params.denoising.type);
}
};
@ -161,7 +153,7 @@ class Session {
void reset(BufferParams &params, int samples);
void set_pause(bool pause);
void set_samples(int samples);
void set_denoising(bool denoising, bool optix_denoising);
void set_denoising(const DenoiseParams &denoising);
void set_denoising_start_sample(int sample);
bool update_scene();

View File

@ -40,7 +40,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 4
#define BLENDER_FILE_SUBVERSION 5
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@ -78,22 +78,45 @@ static IDProperty *cycles_properties_from_ID(ID *id)
return (idprop) ? IDP_GetPropertyTypeFromGroup(idprop, "cycles", IDP_GROUP) : NULL;
}
static IDProperty *cycles_properties_from_view_layer(ViewLayer *view_layer)
{
IDProperty *idprop = view_layer->id_properties;
return (idprop) ? IDP_GetPropertyTypeFromGroup(idprop, "cycles", IDP_GROUP) : NULL;
}
static float cycles_property_float(IDProperty *idprop, const char *name, float default_value)
{
IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_FLOAT);
return (prop) ? IDP_Float(prop) : default_value;
}
static float cycles_property_int(IDProperty *idprop, const char *name, int default_value)
static int cycles_property_int(IDProperty *idprop, const char *name, int default_value)
{
IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_INT);
return (prop) ? IDP_Int(prop) : default_value;
}
static bool cycles_property_boolean(IDProperty *idprop, const char *name, bool default_value)
static void cycles_property_int_set(IDProperty *idprop, const char *name, int value)
{
IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_INT);
return (prop) ? IDP_Int(prop) : default_value;
if (prop) {
IDP_Int(prop) = value;
}
else {
IDPropertyTemplate val = {0};
val.i = value;
IDP_AddToGroup(idprop, IDP_New(IDP_INT, &val, name));
}
}
static bool cycles_property_boolean(IDProperty *idprop, const char *name, bool default_value)
{
return cycles_property_int(idprop, name, default_value);
}
static void cycles_property_boolean_set(IDProperty *idprop, const char *name, bool value)
{
cycles_property_int_set(idprop, name, value);
}
static void displacement_node_insert(bNodeTree *ntree)
@ -1524,4 +1547,52 @@ void do_versions_after_linking_cycles(Main *bmain)
}
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_ATLEAST(bmain, 290, 5)) {
/* New denoiser settings. */
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
IDProperty *cscene = cycles_properties_from_ID(&scene->id);
/* Check if any view layers had (optix) denoising enabled. */
bool use_optix = false;
bool use_denoising = false;
for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
view_layer = view_layer->next) {
IDProperty *cview_layer = cycles_properties_from_view_layer(view_layer);
if (cview_layer) {
use_denoising = use_denoising ||
cycles_property_boolean(cview_layer, "use_denoising", false);
use_optix = use_optix ||
cycles_property_boolean(cview_layer, "use_optix_denoising", false);
}
}
if (cscene) {
const int DENOISER_NLM = 1;
const int DENOISER_OPTIX = 2;
/* Enable denoiser if it was enabled for one view layer before. */
cycles_property_int_set(cscene, "denoiser", (use_optix) ? DENOISER_OPTIX : DENOISER_NLM);
cycles_property_boolean_set(cscene, "use_denoising", use_denoising);
/* Migrate Optix denoiser to new settings. */
if (cycles_property_int(cscene, "preview_denoising", 0)) {
cycles_property_boolean_set(cscene, "use_preview_denoising", true);
cycles_property_boolean_set(cscene, "preview_denoiser", DENOISER_OPTIX);
}
}
/* Enable denoising in all view layer if there was no denoising before,
* so that enabling the scene settings auto enables it for all view layers. */
if (!use_denoising) {
for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
view_layer = view_layer->next) {
IDProperty *cview_layer = cycles_properties_from_view_layer(view_layer);
if (cview_layer) {
cycles_property_boolean_set(cview_layer, "use_denoising", true);
}
}
}
}
}
}