[Bf-blender-cvs] [bc82f2772fd] cycles-x: Cycles X: Support OIDN with guiding pass prefiltering

Sergey Sharybin noreply at git.blender.org
Fri Jul 30 11:47:10 CEST 2021


Commit: bc82f2772fdb20466ada068e09096d256916eaed
Author: Sergey Sharybin
Date:   Tue Jul 27 19:18:53 2021 +0200
Branches: cycles-x
https://developer.blender.org/rBbc82f2772fdb20466ada068e09096d256916eaed

Cycles X: Support OIDN with guiding pass prefiltering

Straightforward implementation based on example from the OIDN 1.4
release page. Always configure the beauty pass denoising with the
`cleanAux true`, so that when guiding passes are noise-free we
don't filter them and don't introduce possible artifacts. When the
pre-filtering is enabled, then on top of cleanAux option we will
filter the guiding passes.

Has a separate option for viewport and final rendering, as pre-filter
is not coming for free and for viewport we want to be as interactive
as possible by default. From quick tests it seems that pre-filter is
rather quick, so maybe it can be enabled for viewport as well.

The final render has the option enabled by default to help with cases
when the result is tricky and noisy. If the passes are known to be
noise free is better to disable filtering manually. Can re-iterate
over the default value after gaining some more statistics.

Test file: F10242785
Ground truth: {F10242777}

|Samples|NLM|OIDN Old|OIDN new no filter|OIDN new with filter|
|64|{F10245231}|{F10245242}|{F10245244}|{F10245243}|
|256|{F10245232}|{F10245248}|{F10245233}|{F10245249}|

Extra result with the `pvt_flat.blend` scene:
|Samples|NLM|OIDN Old|OIDN new no filter|OIDN new with filter|
|256|{F10245234}|{F10245237}|{F10245235}|{F10245236}|
|512|{F10245238}|{F10245241}|{F10245239}|{F10245240}|

NOTE: NLM is done in the master branch, where lighting is handled a bit
different. Hence the difference in the light condition.

Differential Revision: https://developer.blender.org/D12043

===================================================================

M	intern/cycles/blender/addon/properties.py
M	intern/cycles/blender/addon/ui.py
M	intern/cycles/blender/blender_sync.cpp
M	intern/cycles/device/device_denoise.h
M	intern/cycles/integrator/denoiser_oidn.cpp
M	intern/cycles/integrator/denoiser_oidn.h
M	intern/cycles/render/integrator.cpp
M	intern/cycles/render/integrator.h

===================================================================

diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 59cd15c96d8..95f9e1a49f7 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -248,6 +248,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
         description="Denoise the image in the 3D viewport",
         default=False,
     )
+    use_preview_denoising_prefilter: BoolProperty(
+        name="Use Denoising Prefilter",
+        description="Prefilter noisy guiding (albedo and normal) passes to improve denoising quality when using OpenImageDenoiser",
+        default=False,
+    )
 
     denoiser: EnumProperty(
         name="Denoiser",
@@ -1209,6 +1214,11 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
         items=enum_denoising_input_passes,
         default='RGB_ALBEDO_NORMAL',
     )
+    use_denoising_prefilter: BoolProperty(
+        name="Use Denoising Prefilter",
+        description="Prefilter noisy guiding (albedo and normal) passes to improve denoising quality when using OpenImageDenoiser",
+        default=True,
+    )
 
     @classmethod
     def register(cls):
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 8553d172ccf..c17232656c0 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -126,6 +126,20 @@ def draw_samples_info(layout, context):
         col.label(text="%s AA" % aa)
 
 
+def get_effective_preview_denoiser(context):
+    scene = context.scene
+    cscene = scene.cycles
+
+    if cscene.preview_denoiser != "AUTO":
+        return cscene.preview_denoiser
+
+    if context.preferences.addons[__package__].preferences.get_devices_for_type('OPTIX'):
+        return 'OPTIX'
+
+    return 'OIDN'
+
+
+
 class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
     bl_label = "Sampling"
 
@@ -161,12 +175,15 @@ class CYCLES_RENDER_PT_sampling_viewport(CyclesButtonsPanel, Panel):
         sub.active = cscene.use_preview_denoising
         sub.prop(cscene, "preview_denoiser", text="")
 
-        sub = heading.row(align=True)
+        sub = heading.column(align=True)
         sub.active = cscene.use_preview_denoising
         sub.prop(cscene, "preview_denoising_start_sample", text="Start Sample")
-        sub = heading.row(align=True)
-        sub.active = cscene.use_preview_denoising
         sub.prop(cscene, "preview_denoising_input_passes", text="Input Passes")
+        sub_row = sub.row()
+
+        effective_preview_denoiser = get_effective_preview_denoiser(context)
+        if effective_preview_denoiser == 'OPENIMAGEDENOISE':
+            sub_row.prop(cscene, "use_preview_denoising_prefilter", text="Prefilter")
 
 
 class CYCLES_RENDER_PT_sampling_render(CyclesButtonsPanel, Panel):
@@ -829,6 +846,7 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
             col.prop(cycles_view_layer, "denoising_optix_input_passes")
         elif denoiser == 'OPENIMAGEDENOISE':
             col.prop(cycles_view_layer, "denoising_openimagedenoise_input_passes")
+            col.prop(cycles_view_layer, "use_denoising_prefilter", text="Prefilter")
 
 
 class CYCLES_PT_post_processing(CyclesButtonsPanel, Panel):
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index ded8a7cdd1f..1dabf6240eb 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -377,6 +377,7 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
     integrator->set_denoise_start_sample(denoise_params.start_sample);
     integrator->set_use_denoise_pass_albedo(denoise_params.use_pass_albedo);
     integrator->set_use_denoise_pass_normal(denoise_params.use_pass_normal);
+    integrator->set_use_denoise_prefilter(denoise_params.use_prefilter);
   }
 
   /* UPDATE_NONE as we don't want to tag the integrator as modified (this was done by the
@@ -905,6 +906,8 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
                                              DENOISER_INPUT_RGB_ALBEDO_NORMAL);
 
       denoising.store_passes = get_boolean(clayer, "denoising_store_passes");
+
+      denoising.use_prefilter = get_boolean(clayer, "use_denoising_prefilter");
     }
   }
   else {
@@ -913,6 +916,7 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
     denoising.type = (DenoiserType)get_enum(
         cscene, "preview_denoiser", DENOISER_NUM, DENOISER_NONE);
     denoising.start_sample = get_int(cscene, "preview_denoising_start_sample");
+    denoising.use_prefilter = get_boolean(cscene, "use_preview_denoising_prefilter");
 
     input_passes = (DenoiserInput)get_enum(
         cscene, "preview_denoising_input_passes", DENOISER_INPUT_NUM, DENOISER_INPUT_RGB_ALBEDO);
diff --git a/intern/cycles/device/device_denoise.h b/intern/cycles/device/device_denoise.h
index a1f88df3c34..5d958fa03bf 100644
--- a/intern/cycles/device/device_denoise.h
+++ b/intern/cycles/device/device_denoise.h
@@ -38,41 +38,32 @@ typedef int DenoiserTypeMask;
 class DenoiseParams {
  public:
   /* Apply denoiser to image. */
-  bool use;
+  bool use = false;
 
   /* Output denoising data passes (possibly without applying the denoiser). */
-  bool store_passes;
+  bool store_passes = false;
 
   /* Denoiser type. */
-  DenoiserType type;
+  DenoiserType type = DENOISER_OPENIMAGEDENOISE;
 
   /* Viewport start sample. */
-  int start_sample;
+  int start_sample = 0;
 
-  /* Extra passes which are used by the denoiser (the color pass is always used). */
-  bool use_pass_albedo;
-  bool use_pass_normal;
+  /* Extra passes which are used by the denoiser (the color pass is always used).
+   * Default to color + albedo only, since normal input does not always have the desired effect
+   * when denoising with OptiX. */
+  bool use_pass_albedo = true;
+  bool use_pass_normal = false;
 
-  DenoiseParams()
-  {
-    use = false;
-    store_passes = false;
-
-    type = DENOISER_OPENIMAGEDENOISE;
+  bool use_prefilter = false;
 
-    /* Default to color + albedo only, since normal input does not always have the desired effect
-     * when denoising with OptiX. */
-    use_pass_albedo = true;
-    use_pass_normal = false;
-
-    start_sample = 0;
-  }
+  DenoiseParams() = default;
 
   bool modified(const DenoiseParams &other) const
   {
     return !(use == other.use && store_passes == other.store_passes && type == other.type &&
              start_sample == other.start_sample && use_pass_albedo == other.use_pass_albedo &&
-             use_pass_normal == other.use_pass_normal);
+             use_pass_normal == other.use_pass_normal && use_prefilter == other.use_prefilter);
   }
 };
 
diff --git a/intern/cycles/integrator/denoiser_oidn.cpp b/intern/cycles/integrator/denoiser_oidn.cpp
index bc1fb8c112a..bd3175a7356 100644
--- a/intern/cycles/integrator/denoiser_oidn.cpp
+++ b/intern/cycles/integrator/denoiser_oidn.cpp
@@ -32,27 +32,8 @@ CCL_NAMESPACE_BEGIN
 
 thread_mutex OIDNDenoiser::mutex_;
 
-class OIDNDenoiser::State {
- public:
-  State()
-  {
-  }
-
-  ~State()
-  {
-  }
-
-#ifdef WITH_OPENIMAGEDENOISE
-  oidn::DeviceRef oidn_device;
-  oidn::FilterRef oidn_filter;
-
-  bool use_pass_albedo = false;
-  bool use_pass_normal = false;
-#endif
-};
-
 OIDNDenoiser::OIDNDenoiser(Device *path_trace_device, const DenoiseParams &params)
-    : Denoiser(path_trace_device, params), state_(make_unique<State>())
+    : Denoiser(path_trace_device, params)
 {
   DCHECK_EQ(params.type, DENOISER_OPENIMAGEDENOISE);
 
@@ -73,46 +54,6 @@ static bool oidn_progress_monitor_function(void *user_ptr, double /*n*/)
 }
 #endif
 
-bool OIDNDenoiser::load_kernels(Progress *progress)
-{
-  if (!Denoiser::load_kernels(progress)) {
-    return false;
-  }
-
-  /* Make sure all lazily-initializable resources are initialized and are ready for use by the
-   * denoising process. */
-
-#ifdef WITH_OPENIMAGEDENOISE
-  if (state_->oidn_filter) {
-    if (params_.use_pass_albedo != state_->use_pass_albedo ||
-        params_.use_pass_normal != state_->use_pass_normal) {
-      state_->oidn_device = nullptr;
-      state_->oidn_filter = nullptr;
-    }
-  }
-
-  if (!state_->oidn_device) {
-    state_->oidn_device = oidn::newDevice();
-    state_->oidn_device.commit();
-  }
-
-  if (!state_->oidn_filter) {
-    state_->oidn_filter = state_->oidn_device.newFilter("RT");
-    state_->oidn_filter.set("hdr", true);
-    state_->oidn_filter.set("srgb", false);
-
-    state_->oidn_filter.setProgressMonitorFunction(oidn_progress_monitor_function, this);
-  }
-
-  state_->use_pass_albedo = params_.use_pass_albedo;
-  state_->use_pass_normal = params_.use_pass_normal;
-
-  return true;
-#else
-  return false;
-#endif
-}
-
 #ifdef WITH_OPENIMAGEDENOISE
 
 class OIDNPass {
@@ -162,30 +103,31 @@ class OIDNPass {
    * outside of generic pass handling. */
   bool need_scale = false;
 
+  /* The content of the pass has been pre-filtered. */
+  bool is_filtered = false;
+
   /* For the scaled passes, the data which holds values of scaled pixels. */
   array<float> scaled_buffer;
 };
 
 class OIDNDenoiseContext {
  public:
-  OIDNDenoiseContext(const DenoiseParams &denoise_params,
+  OIDNDenoiseContext(OIDNDenoiser *denoiser,
+                     const DenoiseParams &denoise_params,
                      const BufferParams &buffer_params,
                      RenderBuffers *render_buffers,
-                     oidn::FilterRef *oidn_filter,
                      const int num_samples,
                      const bool allow_inplace_modification)
-      : denoise_params_(denoise_params),
+      : denoiser_(denoiser),
+        denoise_params_(denoise_params),
         buffer_params_(buffer_params),
         render_buffers_(render_buffers),
-        oidn_filter_(oidn_filter),
         num_samples_(num_samples),
         allow_inplace_modification_(allow_inplace_modification),
         pass_sample_count_(buffer_params_.get_pass_offset(PASS_SAMPLE_COUNT))
   {
     if (denoise_params_.use_pass_albedo) {
       oidn_albedo_pass_ = OIDNPass(buffer_params_, "albedo", PASS_DENOISING_ALBEDO);
-      /* NOTE: The albedo pass is always ensured to be set from the denoise(

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list