[Bf-blender-cvs] [8393ccd0763] master: Cycles: Add OptiX temporal denoising support
Patrick Mours
noreply at git.blender.org
Wed Jan 5 15:58:52 CET 2022
Commit: 8393ccd07634b3152b18d4d527b1460dab9dbe06
Author: Patrick Mours
Date: Tue Jan 4 21:39:54 2022 +0100
Branches: master
https://developer.blender.org/rB8393ccd07634b3152b18d4d527b1460dab9dbe06
Cycles: Add OptiX temporal denoising support
Enables the `bpy.ops.cycles.denoise_animation()` operator again and modifies it to support
temporal denoising with OptiX. This requires renders that were done with both the "Vector"
and "Denoising Data" passes.
Differential Revision: https://developer.blender.org/D11442
===================================================================
M intern/cycles/blender/python.cpp
M intern/cycles/blender/sync.h
M intern/cycles/device/denoise.cpp
M intern/cycles/device/denoise.h
M intern/cycles/device/optix/device_impl.cpp
M intern/cycles/device/optix/device_impl.h
M intern/cycles/device/queue.h
M intern/cycles/kernel/device/gpu/kernel.h
M intern/cycles/kernel/types.h
M intern/cycles/scene/pass.cpp
M intern/cycles/session/denoising.cpp
M intern/cycles/session/denoising.h
===================================================================
diff --git a/intern/cycles/blender/python.cpp b/intern/cycles/blender/python.cpp
index 024dae306b0..f509d5c2eeb 100644
--- a/intern/cycles/blender/python.cpp
+++ b/intern/cycles/blender/python.cpp
@@ -735,27 +735,20 @@ static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepat
static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
{
-#if 1
- (void)args;
- (void)keywords;
-#else
static const char *keyword_list[] = {
- "preferences", "scene", "view_layer", "input", "output", "tile_size", "samples", NULL};
+ "preferences", "scene", "view_layer", "input", "output", NULL};
PyObject *pypreferences, *pyscene, *pyviewlayer;
PyObject *pyinput, *pyoutput = NULL;
- int tile_size = 0, samples = 0;
if (!PyArg_ParseTupleAndKeywords(args,
keywords,
- "OOOO|Oii",
+ "OOOO|O",
(char **)keyword_list,
&pypreferences,
&pyscene,
&pyviewlayer,
&pyinput,
- &pyoutput,
- &tile_size,
- &samples)) {
+ &pyoutput)) {
return NULL;
}
@@ -777,14 +770,10 @@ static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *key
&RNA_ViewLayer,
PyLong_AsVoidPtr(pyviewlayer),
&viewlayerptr);
- PointerRNA cviewlayer = RNA_pointer_get(&viewlayerptr, "cycles");
+ BL::ViewLayer b_view_layer(viewlayerptr);
- DenoiseParams params;
- params.radius = get_int(cviewlayer, "denoising_radius");
- params.strength = get_float(cviewlayer, "denoising_strength");
- params.feature_strength = get_float(cviewlayer, "denoising_feature_strength");
- params.relative_pca = get_boolean(cviewlayer, "denoising_relative_pca");
- params.neighbor_frames = get_int(cviewlayer, "denoising_neighbor_frames");
+ DenoiseParams params = BlenderSync::get_denoise_params(b_scene, b_view_layer, true);
+ params.use = true;
/* Parse file paths list. */
vector<string> input, output;
@@ -812,24 +801,15 @@ static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *key
}
/* Create denoiser. */
- DenoiserPipeline denoiser(device);
- denoiser.params = params;
+ DenoiserPipeline denoiser(device, params);
denoiser.input = input;
denoiser.output = output;
- if (tile_size > 0) {
- denoiser.tile_size = make_int2(tile_size, tile_size);
- }
- if (samples > 0) {
- denoiser.samples_override = samples;
- }
-
/* Run denoiser. */
if (!denoiser.run()) {
PyErr_SetString(PyExc_ValueError, denoiser.error.c_str());
return NULL;
}
-#endif
Py_RETURN_NONE;
}
diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h
index d074f90bb1b..3722b938863 100644
--- a/intern/cycles/blender/sync.h
+++ b/intern/cycles/blender/sync.h
@@ -105,11 +105,11 @@ class BlenderSync {
static BufferParams get_buffer_params(
BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height);
- private:
static DenoiseParams get_denoise_params(BL::Scene &b_scene,
BL::ViewLayer &b_view_layer,
bool background);
+ private:
/* sync */
void sync_lights(BL::Depsgraph &b_depsgraph, bool update_all);
void sync_materials(BL::Depsgraph &b_depsgraph, bool update_all);
diff --git a/intern/cycles/device/denoise.cpp b/intern/cycles/device/denoise.cpp
index c291a7a0adb..8ae2bb213e4 100644
--- a/intern/cycles/device/denoise.cpp
+++ b/intern/cycles/device/denoise.cpp
@@ -76,6 +76,8 @@ NODE_DEFINE(DenoiseParams)
SOCKET_BOOLEAN(use_pass_albedo, "Use Pass Albedo", true);
SOCKET_BOOLEAN(use_pass_normal, "Use Pass Normal", false);
+ SOCKET_BOOLEAN(temporally_stable, "Temporally Stable", false);
+
SOCKET_ENUM(prefilter, "Prefilter", *prefilter_enum, DENOISER_PREFILTER_FAST);
return type;
diff --git a/intern/cycles/device/denoise.h b/intern/cycles/device/denoise.h
index 3f30506ae06..07868527fc5 100644
--- a/intern/cycles/device/denoise.h
+++ b/intern/cycles/device/denoise.h
@@ -72,6 +72,9 @@ class DenoiseParams : public Node {
bool use_pass_albedo = true;
bool use_pass_normal = true;
+ /* Configure the denoiser to use motion vectors, previous image and a temporally stable model. */
+ bool temporally_stable = false;
+
DenoiserPrefilter prefilter = DENOISER_PREFILTER_FAST;
static const NodeEnum *get_type_enum();
@@ -83,7 +86,8 @@ class DenoiseParams : public Node {
{
return !(use == other.use && type == other.type && start_sample == other.start_sample &&
use_pass_albedo == other.use_pass_albedo &&
- use_pass_normal == other.use_pass_normal && prefilter == other.prefilter);
+ use_pass_normal == other.use_pass_normal &&
+ temporally_stable == other.temporally_stable && prefilter == other.prefilter);
}
};
diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp
index 38cc3330ebd..009661b2dec 100644
--- a/intern/cycles/device/optix/device_impl.cpp
+++ b/intern/cycles/device/optix/device_impl.cpp
@@ -566,6 +566,19 @@ class OptiXDevice::DenoiseContext {
}
}
+ if (denoise_params.temporally_stable) {
+ prev_output.device_pointer = render_buffers->buffer.device_pointer;
+
+ prev_output.offset = buffer_params.get_pass_offset(PASS_DENOISING_PREVIOUS);
+
+ prev_output.stride = buffer_params.stride;
+ prev_output.pass_stride = buffer_params.pass_stride;
+
+ num_input_passes += 1;
+ use_pass_flow = true;
+ pass_motion = buffer_params.get_pass_offset(PASS_MOTION);
+ }
+
use_guiding_passes = (num_input_passes - 1) > 0;
if (use_guiding_passes) {
@@ -574,6 +587,7 @@ class OptiXDevice::DenoiseContext {
guiding_params.pass_albedo = pass_denoising_albedo;
guiding_params.pass_normal = pass_denoising_normal;
+ guiding_params.pass_flow = pass_motion;
guiding_params.stride = buffer_params.stride;
guiding_params.pass_stride = buffer_params.pass_stride;
@@ -588,6 +602,10 @@ class OptiXDevice::DenoiseContext {
guiding_params.pass_normal = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
+ if (use_pass_flow) {
+ guiding_params.pass_flow = guiding_params.pass_stride;
+ guiding_params.pass_stride += 2;
+ }
guiding_params.stride = buffer_params.width;
@@ -605,6 +623,16 @@ class OptiXDevice::DenoiseContext {
RenderBuffers *render_buffers = nullptr;
const BufferParams &buffer_params;
+ /* Previous output. */
+ struct {
+ device_ptr device_pointer = 0;
+
+ int offset = PASS_UNUSED;
+
+ int stride = -1;
+ int pass_stride = -1;
+ } prev_output;
+
/* Device-side storage of the guiding passes. */
device_only_memory<float> guiding_buffer;
@@ -614,6 +642,7 @@ class OptiXDevice::DenoiseContext {
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_albedo = PASS_UNUSED;
int pass_normal = PASS_UNUSED;
+ int pass_flow = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
@@ -624,6 +653,7 @@ class OptiXDevice::DenoiseContext {
bool use_guiding_passes = false;
bool use_pass_albedo = false;
bool use_pass_normal = false;
+ bool use_pass_flow = false;
int num_samples = 0;
@@ -632,6 +662,7 @@ class OptiXDevice::DenoiseContext {
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_denoising_albedo = PASS_UNUSED;
int pass_denoising_normal = PASS_UNUSED;
+ int pass_motion = PASS_UNUSED;
/* For passes which don't need albedo channel for denoising we replace the actual albedo with
* the (0.5, 0.5, 0.5). This flag indicates that the real albedo pass has been replaced with
@@ -702,6 +733,7 @@ bool OptiXDevice::denoise_filter_guiding_preprocess(DenoiseContext &context)
&context.guiding_params.pass_stride,
&context.guiding_params.pass_albedo,
&context.guiding_params.pass_normal,
+ &context.guiding_params.pass_flow,
&context.render_buffers->buffer.device_pointer,
&buffer_params.offset,
&buffer_params.stride,
@@ -709,6 +741,7 @@ bool OptiXDevice::denoise_filter_guiding_preprocess(DenoiseContext &context)
&context.pass_sample_count,
&context.pass_denoising_albedo,
&context.pass_denoising_normal,
+ &context.pass_motion,
&buffer_params.full_x,
&buffer_params.full_y,
&buffer_params.width,
@@ -881,7 +914,8 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
{
const bool recreate_denoiser = (denoiser_.optix_denoiser == nullptr) ||
(denoiser_.use_pass_albedo != context.use_pass_albedo) ||
- (denoiser_.use_pass_normal != context.use_pass_normal);
+ (denoiser_.use_pass_normal != context.use_pass_normal) ||
+ (denoiser_.use_pass_flow != context.use_pass_flow);
if (!recreate_denoiser) {
return true;
}
@@ -895,8 +929,14 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
OptixDenoiserOptions denoiser_options = {};
denoiser_options.guideAlbedo = context.use_pass_albedo;
denoiser_options.guideNormal = context.use_pass_normal;
+
+ OptixDenoiserModelKind model = OPTIX_DENOISER_MODEL_KIND_HDR;
+ if (context.use_pass_flow) {
+ model = OPTIX_DENOISER_MODEL_KI
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list