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. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs