Skip to content

Commit

Permalink
Cycles: Add OpenImageDenoise quality option
Browse files Browse the repository at this point in the history
This adds a new "Quality" option for OIDN to switch between the existing
"High" and "Balanced" modes and the new "Fast" mode introduced in OIDN 2.3.

Pull Request: https://projects.blender.org/blender/blender/pulls/121374
  • Loading branch information
Attila Áfra authored and Brecht Van Lommel committed May 6, 2024
1 parent 69472c8 commit 2a0a6f1
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 19 deletions.
2 changes: 2 additions & 0 deletions intern/cycles/blender/addon/presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class AddPresetSampling(AddPresetBase, Operator):
"cycles.denoiser",
"cycles.denoising_input_passes",
"cycles.denoising_prefilter",
"cycles.denoising_quality",
]

preset_subdir = "cycles/sampling"
Expand All @@ -80,6 +81,7 @@ class AddPresetViewportSampling(AddPresetBase, Operator):
"cycles.preview_denoiser",
"cycles.preview_denoising_input_passes",
"cycles.preview_denoising_prefilter",
"cycles.preview_denoising_quality",
"cycles.preview_denoising_start_sample",
]

Expand Down
31 changes: 29 additions & 2 deletions intern/cycles/blender/addon/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,21 @@ def enum_denoiser(self, context):
3),
)

enum_denoising_quality = (
('HIGH',
"High",
"High quality",
1),
('BALANCED',
"Balanced",
"Balanced between performance and quality",
2),
('FAST',
"Fast",
"High performance",
3),
)

enum_direct_light_sampling_type = (
('MULTIPLE_IMPORTANCE_SAMPLING',
"Multiple Importance Sampling",
Expand Down Expand Up @@ -342,10 +357,16 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
)
denoising_prefilter: EnumProperty(
name="Denoising Prefilter",
description="Prefilter noisy guiding (albedo and normal) passes to improve denoising quality when using OpenImageDenoiser",
description="Prefilter noisy guiding (albedo and normal) passes to improve denoising quality when using OpenImageDenoise",
items=enum_denoising_prefilter,
default='ACCURATE',
)
denoising_quality: EnumProperty(
name="Denoising Quality",
description="Overall denoising quality when using OpenImageDenoise",
items=enum_denoising_quality,
default='HIGH',
)
denoising_input_passes: EnumProperty(
name="Denoising Input Passes",
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
Expand All @@ -371,10 +392,16 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
)
preview_denoising_prefilter: EnumProperty(
name="Viewport Denoising Prefilter",
description="Prefilter noisy guiding (albedo and normal) passes to improve denoising quality when using OpenImageDenoiser",
description="Prefilter noisy guiding (albedo and normal) passes to improve denoising quality when using OpenImageDenoise",
items=enum_denoising_prefilter,
default='FAST',
)
preview_denoising_quality: EnumProperty(
name="Viewport Denoising Quality",
description="Overall denoising quality when using OpenImageDenoise",
items=enum_denoising_quality,
default='BALANCED',
)
preview_denoising_input_passes: EnumProperty(
name="Viewport Denoising Input Passes",
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
Expand Down
2 changes: 2 additions & 0 deletions intern/cycles/blender/addon/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ def draw(self, context):
effective_preview_denoiser = get_effective_preview_denoiser(context, has_oidn_gpu)
if effective_preview_denoiser == 'OPENIMAGEDENOISE':
col.prop(cscene, "preview_denoising_prefilter", text="Prefilter")
col.prop(cscene, "preview_denoising_quality", text="Quality")

col.prop(cscene, "preview_denoising_start_sample", text="Start Sample")

Expand Down Expand Up @@ -307,6 +308,7 @@ def draw(self, context):
col.prop(cscene, "denoising_input_passes", text="Passes")
if cscene.denoiser == 'OPENIMAGEDENOISE':
col.prop(cscene, "denoising_prefilter", text="Prefilter")
col.prop(cscene, "denoising_quality", text="Quality")

if cscene.denoiser == 'OPENIMAGEDENOISE':
row = col.row()
Expand Down
10 changes: 4 additions & 6 deletions intern/cycles/blender/sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -987,9 +987,8 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
denoising.use_gpu = get_boolean(cscene, "denoising_use_gpu");
denoising.prefilter = (DenoiserPrefilter)get_enum(
cscene, "denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_NONE);
/* This currently only affects NVIDIA and the difference in quality is too small to justify
* exposing a setting to the user. */
denoising.quality = DENOISER_QUALITY_HIGH;
denoising.quality = (DenoiserQuality)get_enum(
cscene, "denoising_quality", DENOISER_QUALITY_NUM, DENOISER_QUALITY_HIGH);

input_passes = (DenoiserInput)get_enum(
cscene, "denoising_input_passes", DENOISER_INPUT_NUM, DENOISER_INPUT_RGB_ALBEDO_NORMAL);
Expand All @@ -1009,9 +1008,8 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
denoising.use_gpu = get_boolean(cscene, "preview_denoising_use_gpu");
denoising.prefilter = (DenoiserPrefilter)get_enum(
cscene, "preview_denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_FAST);
/* This currently only affects NVIDIA and the difference in quality is too small to justify
* exposing a setting to the user. */
denoising.quality = DENOISER_QUALITY_BALANCED;
denoising.quality = (DenoiserQuality)get_enum(
cscene, "preview_denoising_quality", DENOISER_QUALITY_NUM, DENOISER_QUALITY_BALANCED);
denoising.start_sample = get_int(cscene, "preview_denoising_start_sample");

input_passes = (DenoiserInput)get_enum(
Expand Down
1 change: 1 addition & 0 deletions intern/cycles/device/denoise.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const NodeEnum *DenoiseParams::get_quality_enum()
if (quality_enum.empty()) {
quality_enum.insert("high", DENOISER_QUALITY_HIGH);
quality_enum.insert("balanced", DENOISER_QUALITY_BALANCED);
quality_enum.insert("fast", DENOISER_QUALITY_FAST);
}

return &quality_enum;
Expand Down
1 change: 1 addition & 0 deletions intern/cycles/device/denoise.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ enum DenoiserPrefilter {
enum DenoiserQuality {
DENOISER_QUALITY_HIGH = 1,
DENOISER_QUALITY_BALANCED = 2,
DENOISER_QUALITY_FAST = 3,
DENOISER_QUALITY_NUM,
};

Expand Down
32 changes: 21 additions & 11 deletions intern/cycles/integrator/denoiser_oidn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,17 +164,7 @@ class OIDNDenoiseContext {
oidn_filter.setProgressMonitorFunction(oidn_progress_monitor_function, denoiser_);
oidn_filter.set("hdr", true);
oidn_filter.set("srgb", false);

# if OIDN_VERSION_MAJOR >= 2
switch (denoise_params_.quality) {
case DENOISER_QUALITY_BALANCED:
oidn_filter.set("quality", OIDN_QUALITY_BALANCED);
break;
case DENOISER_QUALITY_HIGH:
default:
oidn_filter.set("quality", OIDN_QUALITY_HIGH);
}
# endif
set_quality(oidn_filter);

if (denoise_params_.prefilter == DENOISER_PREFILTER_NONE ||
denoise_params_.prefilter == DENOISER_PREFILTER_ACCURATE)
Expand Down Expand Up @@ -211,6 +201,7 @@ class OIDNDenoiseContext {
oidn::FilterRef oidn_filter = oidn_device.newFilter("RT");
set_pass(oidn_filter, oidn_pass);
set_output_pass(oidn_filter, oidn_pass);
set_quality(oidn_filter);
oidn_filter.commit();
oidn_filter.execute();

Expand Down Expand Up @@ -413,6 +404,25 @@ class OIDNDenoiseContext {
set_pass(oidn_filter, "output", oidn_pass);
}

void set_quality(oidn::FilterRef &oidn_filter)
{
# if OIDN_VERSION_MAJOR >= 2
switch (denoise_params_.quality) {
case DENOISER_QUALITY_FAST:
# if OIDN_VERSION >= 20300
oidn_filter.set("quality", OIDN_QUALITY_FAST);
break;
# endif
case DENOISER_QUALITY_BALANCED:
oidn_filter.set("quality", OIDN_QUALITY_BALANCED);
break;
case DENOISER_QUALITY_HIGH:
default:
oidn_filter.set("quality", OIDN_QUALITY_HIGH);
}
# endif
}

/* Scale output pass to match adaptive sampling per-pixel scale, as well as bring alpha channel
* back. */
void postprocess_output(const OIDNPass &oidn_input_pass, const OIDNPass &oidn_output_pass)
Expand Down
5 changes: 5 additions & 0 deletions intern/cycles/integrator/denoiser_oidn_gpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ OIDNFilter OIDNDenoiserGPU::create_filter()

# if OIDN_VERSION_MAJOR >= 2
switch (quality_) {
case DENOISER_QUALITY_FAST:
# if OIDN_VERSION >= 20300
oidnSetFilterInt(filter, "quality", OIDN_QUALITY_FAST);
break;
# endif
case DENOISER_QUALITY_BALANCED:
oidnSetFilterInt(filter, "quality", OIDN_QUALITY_BALANCED);
break;
Expand Down
1 change: 1 addition & 0 deletions intern/cycles/scene/integrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ NODE_DEFINE(Integrator)
static NodeEnum denoiser_quality_enum;
denoiser_quality_enum.insert("high", DENOISER_QUALITY_HIGH);
denoiser_quality_enum.insert("balanced", DENOISER_QUALITY_BALANCED);
denoiser_quality_enum.insert("fast", DENOISER_QUALITY_FAST);

/* Default to accurate denoising with OpenImageDenoise. For interactive viewport
* it's best use OptiX and disable the normal pass since it does not always have
Expand Down

0 comments on commit 2a0a6f1

Please sign in to comment.