Compositor: Add OIDN prefiltering option to Denoise node
It's equivalent to the OpenImageDenoise prefiltering option in Cycles. See D12043. Prefilter modes: - None: No prefiltering, use when guiding passes are noise-free. - Fast: Denoise image and guiding passes together. Improves quality when guiding passes are noisy using least amount of extra processing time. - Accurate: Prefilter noisy guiding passes before denoising image. Improves quality when guiding passes are noisy using extra processing time. Reviewed By: #compositing, jbakker, sergey Differential Revision: https://developer.blender.org/D12342
This commit is contained in:
parent
f256bfb3e2
commit
276eebb274
|
@ -31,6 +31,12 @@ DenoiseNode::DenoiseNode(bNode *editorNode) : Node(editorNode)
|
|||
void DenoiseNode::convertToOperations(NodeConverter &converter,
|
||||
const CompositorContext & /*context*/) const
|
||||
{
|
||||
if (!COM_is_denoise_supported()) {
|
||||
converter.mapOutputSocket(getOutputSocket(0),
|
||||
converter.addInputProxy(getInputSocket(0), false));
|
||||
return;
|
||||
}
|
||||
|
||||
bNode *node = this->getbNode();
|
||||
NodeDenoise *denoise = (NodeDenoise *)node->storage;
|
||||
|
||||
|
@ -39,8 +45,28 @@ void DenoiseNode::convertToOperations(NodeConverter &converter,
|
|||
operation->setDenoiseSettings(denoise);
|
||||
|
||||
converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
|
||||
converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
|
||||
converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
|
||||
if (denoise && denoise->prefilter == CMP_NODE_DENOISE_PREFILTER_ACCURATE) {
|
||||
{
|
||||
DenoisePrefilterOperation *normal_prefilter = new DenoisePrefilterOperation(
|
||||
DataType::Vector);
|
||||
normal_prefilter->set_image_name("normal");
|
||||
converter.addOperation(normal_prefilter);
|
||||
converter.mapInputSocket(getInputSocket(1), normal_prefilter->getInputSocket(0));
|
||||
converter.addLink(normal_prefilter->getOutputSocket(), operation->getInputSocket(1));
|
||||
}
|
||||
{
|
||||
DenoisePrefilterOperation *albedo_prefilter = new DenoisePrefilterOperation(DataType::Color);
|
||||
albedo_prefilter->set_image_name("albedo");
|
||||
converter.addOperation(albedo_prefilter);
|
||||
converter.mapInputSocket(getInputSocket(2), albedo_prefilter->getInputSocket(0));
|
||||
converter.addLink(albedo_prefilter->getOutputSocket(), operation->getInputSocket(2));
|
||||
}
|
||||
}
|
||||
else {
|
||||
converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
|
||||
converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
|
||||
}
|
||||
|
||||
converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,137 @@ static pthread_mutex_t oidn_lock = BLI_MUTEX_INITIALIZER;
|
|||
|
||||
namespace blender::compositor {
|
||||
|
||||
bool COM_is_denoise_supported()
|
||||
{
|
||||
#ifdef WITH_OPENIMAGEDENOISE
|
||||
/* Always supported through Accelerate framework BNNS on macOS. */
|
||||
# ifdef __APPLE__
|
||||
return true;
|
||||
# else
|
||||
return BLI_cpu_support_sse41();
|
||||
# endif
|
||||
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
class DenoiseFilter {
|
||||
private:
|
||||
#ifdef WITH_OPENIMAGEDENOISE
|
||||
oidn::DeviceRef device;
|
||||
oidn::FilterRef filter;
|
||||
#endif
|
||||
bool initialized_ = false;
|
||||
|
||||
public:
|
||||
~DenoiseFilter()
|
||||
{
|
||||
BLI_assert(!initialized_);
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENIMAGEDENOISE
|
||||
void init_and_lock_denoiser(MemoryBuffer *output)
|
||||
{
|
||||
/* Since it's memory intensive, it's better to run only one instance of OIDN at a time.
|
||||
* OpenImageDenoise is multithreaded internally and should use all available cores
|
||||
* nonetheless. */
|
||||
BLI_mutex_lock(&oidn_lock);
|
||||
|
||||
device = oidn::newDevice();
|
||||
device.commit();
|
||||
filter = device.newFilter("RT");
|
||||
initialized_ = true;
|
||||
set_image("output", output);
|
||||
}
|
||||
|
||||
void deinit_and_unlock_denoiser()
|
||||
{
|
||||
BLI_mutex_unlock(&oidn_lock);
|
||||
initialized_ = false;
|
||||
}
|
||||
|
||||
void set_image(const StringRef name, MemoryBuffer *buffer)
|
||||
{
|
||||
BLI_assert(initialized_);
|
||||
BLI_assert(!buffer->is_a_single_elem());
|
||||
filter.setImage(name.data(),
|
||||
buffer->getBuffer(),
|
||||
oidn::Format::Float3,
|
||||
buffer->getWidth(),
|
||||
buffer->getHeight(),
|
||||
0,
|
||||
buffer->get_elem_bytes_len());
|
||||
}
|
||||
|
||||
template<typename T> void set(const StringRef option_name, T value)
|
||||
{
|
||||
BLI_assert(initialized_);
|
||||
filter.set(option_name.data(), value);
|
||||
}
|
||||
|
||||
void execute()
|
||||
{
|
||||
BLI_assert(initialized_);
|
||||
filter.commit();
|
||||
filter.execute();
|
||||
}
|
||||
|
||||
#else
|
||||
void init_and_lock_denoiser(MemoryBuffer *UNUSED(output))
|
||||
{
|
||||
}
|
||||
|
||||
void deinit_and_unlock_denoiser()
|
||||
{
|
||||
}
|
||||
|
||||
void set_image(const StringRef UNUSED(name), MemoryBuffer *UNUSED(buffer))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T> void set(const StringRef UNUSED(option_name), T UNUSED(value))
|
||||
{
|
||||
}
|
||||
|
||||
void execute()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
DenoiseBaseOperation::DenoiseBaseOperation()
|
||||
{
|
||||
flags.is_fullframe_operation = true;
|
||||
output_rendered_ = false;
|
||||
}
|
||||
|
||||
bool DenoiseBaseOperation::determineDependingAreaOfInterest(rcti * /*input*/,
|
||||
ReadBufferOperation *readOperation,
|
||||
rcti *output)
|
||||
{
|
||||
if (isCached()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rcti newInput;
|
||||
newInput.xmax = this->getWidth();
|
||||
newInput.xmin = 0;
|
||||
newInput.ymax = this->getHeight();
|
||||
newInput.ymin = 0;
|
||||
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
|
||||
}
|
||||
|
||||
void DenoiseBaseOperation::get_area_of_interest(const int UNUSED(input_idx),
|
||||
const rcti &UNUSED(output_area),
|
||||
rcti &r_input_area)
|
||||
{
|
||||
r_input_area.xmin = 0;
|
||||
r_input_area.xmax = this->getWidth();
|
||||
r_input_area.ymin = 0;
|
||||
r_input_area.ymax = this->getHeight();
|
||||
}
|
||||
|
||||
DenoiseOperation::DenoiseOperation()
|
||||
{
|
||||
this->addInputSocket(DataType::Color);
|
||||
|
@ -35,8 +166,6 @@ DenoiseOperation::DenoiseOperation()
|
|||
this->addInputSocket(DataType::Color);
|
||||
this->addOutputSocket(DataType::Color);
|
||||
this->m_settings = nullptr;
|
||||
flags.is_fullframe_operation = true;
|
||||
output_rendered_ = false;
|
||||
}
|
||||
void DenoiseOperation::initExecution()
|
||||
{
|
||||
|
@ -54,6 +183,25 @@ void DenoiseOperation::deinitExecution()
|
|||
SingleThreadedOperation::deinitExecution();
|
||||
}
|
||||
|
||||
static bool are_guiding_passes_noise_free(NodeDenoise *settings)
|
||||
{
|
||||
switch (settings->prefilter) {
|
||||
case CMP_NODE_DENOISE_PREFILTER_NONE:
|
||||
case CMP_NODE_DENOISE_PREFILTER_ACCURATE: /* Prefiltered with #DenoisePrefilterOperation. */
|
||||
return true;
|
||||
case CMP_NODE_DENOISE_PREFILTER_FAST:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiseOperation::hash_output_params()
|
||||
{
|
||||
if (m_settings) {
|
||||
hash_params((int)m_settings->hdr, are_guiding_passes_noise_free(m_settings));
|
||||
}
|
||||
}
|
||||
|
||||
MemoryBuffer *DenoiseOperation::createMemoryBuffer(rcti *rect2)
|
||||
{
|
||||
MemoryBuffer *tileColor = (MemoryBuffer *)this->m_inputProgramColor->initializeTileData(rect2);
|
||||
|
@ -69,22 +217,6 @@ MemoryBuffer *DenoiseOperation::createMemoryBuffer(rcti *rect2)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool DenoiseOperation::determineDependingAreaOfInterest(rcti * /*input*/,
|
||||
ReadBufferOperation *readOperation,
|
||||
rcti *output)
|
||||
{
|
||||
if (isCached()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rcti newInput;
|
||||
newInput.xmax = this->getWidth();
|
||||
newInput.xmin = 0;
|
||||
newInput.ymax = this->getHeight();
|
||||
newInput.ymin = 0;
|
||||
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
|
||||
}
|
||||
|
||||
void DenoiseOperation::generateDenoise(MemoryBuffer *output,
|
||||
MemoryBuffer *input_color,
|
||||
MemoryBuffer *input_normal,
|
||||
|
@ -96,104 +228,46 @@ void DenoiseOperation::generateDenoise(MemoryBuffer *output,
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENIMAGEDENOISE
|
||||
/* Always supported through Accelerate framework BNNS on macOS. */
|
||||
# ifndef __APPLE__
|
||||
if (BLI_cpu_support_sse41())
|
||||
# endif
|
||||
{
|
||||
/* OpenImageDenoise needs full buffers. */
|
||||
MemoryBuffer *buf_color = input_color->is_a_single_elem() ? input_color->inflate() :
|
||||
input_color;
|
||||
MemoryBuffer *buf_normal = input_normal && input_normal->is_a_single_elem() ?
|
||||
input_normal->inflate() :
|
||||
input_normal;
|
||||
MemoryBuffer *buf_albedo = input_albedo && input_albedo->is_a_single_elem() ?
|
||||
input_albedo->inflate() :
|
||||
input_albedo;
|
||||
BLI_assert(COM_is_denoise_supported());
|
||||
/* OpenImageDenoise needs full buffers. */
|
||||
MemoryBuffer *buf_color = input_color->is_a_single_elem() ? input_color->inflate() : input_color;
|
||||
MemoryBuffer *buf_normal = input_normal && input_normal->is_a_single_elem() ?
|
||||
input_normal->inflate() :
|
||||
input_normal;
|
||||
MemoryBuffer *buf_albedo = input_albedo && input_albedo->is_a_single_elem() ?
|
||||
input_albedo->inflate() :
|
||||
input_albedo;
|
||||
|
||||
/* Since it's memory intensive, it's better to run only one instance of OIDN at a time.
|
||||
* OpenImageDenoise is multithreaded internally and should use all available cores nonetheless.
|
||||
*/
|
||||
BLI_mutex_lock(&oidn_lock);
|
||||
DenoiseFilter filter;
|
||||
filter.init_and_lock_denoiser(output);
|
||||
|
||||
oidn::DeviceRef device = oidn::newDevice();
|
||||
device.commit();
|
||||
filter.set_image("color", buf_color);
|
||||
filter.set_image("normal", buf_normal);
|
||||
filter.set_image("albedo", buf_albedo);
|
||||
|
||||
oidn::FilterRef filter = device.newFilter("RT");
|
||||
filter.setImage("color",
|
||||
buf_color->getBuffer(),
|
||||
oidn::Format::Float3,
|
||||
buf_color->getWidth(),
|
||||
buf_color->getHeight(),
|
||||
0,
|
||||
sizeof(float[4]));
|
||||
if (buf_normal && buf_normal->getBuffer()) {
|
||||
filter.setImage("normal",
|
||||
buf_normal->getBuffer(),
|
||||
oidn::Format::Float3,
|
||||
buf_normal->getWidth(),
|
||||
buf_normal->getHeight(),
|
||||
0,
|
||||
sizeof(float[3]));
|
||||
}
|
||||
if (buf_albedo && buf_albedo->getBuffer()) {
|
||||
filter.setImage("albedo",
|
||||
buf_albedo->getBuffer(),
|
||||
oidn::Format::Float3,
|
||||
buf_albedo->getWidth(),
|
||||
buf_albedo->getHeight(),
|
||||
0,
|
||||
sizeof(float[4]));
|
||||
}
|
||||
filter.setImage("output",
|
||||
output->getBuffer(),
|
||||
oidn::Format::Float3,
|
||||
buf_color->getWidth(),
|
||||
buf_color->getHeight(),
|
||||
0,
|
||||
sizeof(float[4]));
|
||||
|
||||
BLI_assert(settings);
|
||||
if (settings) {
|
||||
filter.set("hdr", settings->hdr);
|
||||
filter.set("srgb", false);
|
||||
}
|
||||
|
||||
filter.commit();
|
||||
filter.execute();
|
||||
BLI_mutex_unlock(&oidn_lock);
|
||||
|
||||
/* Copy the alpha channel, OpenImageDenoise currently only supports RGB. */
|
||||
output->copy_from(input_color, input_color->get_rect(), 3, COM_DATA_TYPE_VALUE_CHANNELS, 3);
|
||||
|
||||
/* Delete inflated buffers. */
|
||||
if (input_color->is_a_single_elem()) {
|
||||
delete buf_color;
|
||||
}
|
||||
if (input_normal && input_normal->is_a_single_elem()) {
|
||||
delete buf_normal;
|
||||
}
|
||||
if (input_albedo && input_albedo->is_a_single_elem()) {
|
||||
delete buf_albedo;
|
||||
}
|
||||
|
||||
return;
|
||||
BLI_assert(settings);
|
||||
if (settings) {
|
||||
filter.set("hdr", settings->hdr);
|
||||
filter.set("srgb", false);
|
||||
filter.set("cleanAux", are_guiding_passes_noise_free(settings));
|
||||
}
|
||||
#endif
|
||||
/* If built without OIDN or running on an unsupported CPU, just pass through. */
|
||||
UNUSED_VARS(input_albedo, input_normal, settings);
|
||||
output->copy_from(input_color, input_color->get_rect());
|
||||
}
|
||||
|
||||
void DenoiseOperation::get_area_of_interest(const int UNUSED(input_idx),
|
||||
const rcti &UNUSED(output_area),
|
||||
rcti &r_input_area)
|
||||
{
|
||||
r_input_area.xmin = 0;
|
||||
r_input_area.xmax = this->getWidth();
|
||||
r_input_area.ymin = 0;
|
||||
r_input_area.ymax = this->getHeight();
|
||||
filter.execute();
|
||||
filter.deinit_and_unlock_denoiser();
|
||||
|
||||
/* Copy the alpha channel, OpenImageDenoise currently only supports RGB. */
|
||||
output->copy_from(input_color, input_color->get_rect(), 3, COM_DATA_TYPE_VALUE_CHANNELS, 3);
|
||||
|
||||
/* Delete inflated buffers. */
|
||||
if (input_color->is_a_single_elem()) {
|
||||
delete buf_color;
|
||||
}
|
||||
if (input_normal && input_normal->is_a_single_elem()) {
|
||||
delete buf_normal;
|
||||
}
|
||||
if (input_albedo && input_albedo->is_a_single_elem()) {
|
||||
delete buf_albedo;
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiseOperation::update_memory_buffer(MemoryBuffer *output,
|
||||
|
@ -206,4 +280,57 @@ void DenoiseOperation::update_memory_buffer(MemoryBuffer *output,
|
|||
}
|
||||
}
|
||||
|
||||
DenoisePrefilterOperation::DenoisePrefilterOperation(DataType data_type)
|
||||
{
|
||||
this->addInputSocket(data_type);
|
||||
this->addOutputSocket(data_type);
|
||||
image_name_ = "";
|
||||
}
|
||||
|
||||
void DenoisePrefilterOperation::hash_output_params()
|
||||
{
|
||||
hash_param(image_name_);
|
||||
}
|
||||
|
||||
MemoryBuffer *DenoisePrefilterOperation::createMemoryBuffer(rcti *rect2)
|
||||
{
|
||||
MemoryBuffer *input = (MemoryBuffer *)this->get_input_operation(0)->initializeTileData(rect2);
|
||||
rcti rect;
|
||||
BLI_rcti_init(&rect, 0, getWidth(), 0, getHeight());
|
||||
|
||||
MemoryBuffer *result = new MemoryBuffer(getOutputSocket()->getDataType(), rect);
|
||||
generate_denoise(result, input);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DenoisePrefilterOperation::generate_denoise(MemoryBuffer *output, MemoryBuffer *input)
|
||||
{
|
||||
BLI_assert(COM_is_denoise_supported());
|
||||
|
||||
/* Denoising needs full buffers. */
|
||||
MemoryBuffer *input_buf = input->is_a_single_elem() ? input->inflate() : input;
|
||||
|
||||
DenoiseFilter filter;
|
||||
filter.init_and_lock_denoiser(output);
|
||||
filter.set_image(image_name_, input_buf);
|
||||
filter.execute();
|
||||
filter.deinit_and_unlock_denoiser();
|
||||
|
||||
/* Delete inflated buffers. */
|
||||
if (input->is_a_single_elem()) {
|
||||
delete input_buf;
|
||||
}
|
||||
}
|
||||
|
||||
void DenoisePrefilterOperation::update_memory_buffer(MemoryBuffer *output,
|
||||
const rcti &UNUSED(area),
|
||||
Span<MemoryBuffer *> inputs)
|
||||
{
|
||||
if (!output_rendered_) {
|
||||
this->generate_denoise(output, inputs[0]);
|
||||
output_rendered_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
|
|
@ -23,7 +23,24 @@
|
|||
|
||||
namespace blender::compositor {
|
||||
|
||||
class DenoiseOperation : public SingleThreadedOperation {
|
||||
bool COM_is_denoise_supported();
|
||||
|
||||
class DenoiseBaseOperation : public SingleThreadedOperation {
|
||||
protected:
|
||||
bool output_rendered_;
|
||||
|
||||
protected:
|
||||
DenoiseBaseOperation();
|
||||
|
||||
public:
|
||||
bool determineDependingAreaOfInterest(rcti *input,
|
||||
ReadBufferOperation *readOperation,
|
||||
rcti *output) override;
|
||||
|
||||
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
|
||||
};
|
||||
|
||||
class DenoiseOperation : public DenoiseBaseOperation {
|
||||
private:
|
||||
/**
|
||||
* \brief Cached reference to the input programs
|
||||
|
@ -37,8 +54,6 @@ class DenoiseOperation : public SingleThreadedOperation {
|
|||
*/
|
||||
NodeDenoise *m_settings;
|
||||
|
||||
bool output_rendered_;
|
||||
|
||||
public:
|
||||
DenoiseOperation();
|
||||
/**
|
||||
|
@ -55,16 +70,13 @@ class DenoiseOperation : public SingleThreadedOperation {
|
|||
{
|
||||
this->m_settings = settings;
|
||||
}
|
||||
bool determineDependingAreaOfInterest(rcti *input,
|
||||
ReadBufferOperation *readOperation,
|
||||
rcti *output) override;
|
||||
|
||||
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
|
||||
void update_memory_buffer(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
|
||||
protected:
|
||||
void hash_output_params() override;
|
||||
void generateDenoise(MemoryBuffer *output,
|
||||
MemoryBuffer *input_color,
|
||||
MemoryBuffer *input_normal,
|
||||
|
@ -74,4 +86,28 @@ class DenoiseOperation : public SingleThreadedOperation {
|
|||
MemoryBuffer *createMemoryBuffer(rcti *rect) override;
|
||||
};
|
||||
|
||||
class DenoisePrefilterOperation : public DenoiseBaseOperation {
|
||||
private:
|
||||
std::string image_name_;
|
||||
|
||||
public:
|
||||
DenoisePrefilterOperation(DataType data_type);
|
||||
|
||||
void set_image_name(StringRef name)
|
||||
{
|
||||
image_name_ = name;
|
||||
}
|
||||
|
||||
void update_memory_buffer(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
|
||||
protected:
|
||||
void hash_output_params() override;
|
||||
MemoryBuffer *createMemoryBuffer(rcti *rect) override;
|
||||
|
||||
private:
|
||||
void generate_denoise(MemoryBuffer *output, MemoryBuffer *input);
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
|
|
@ -2865,6 +2865,8 @@ static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), Po
|
|||
# endif
|
||||
#endif
|
||||
|
||||
uiItemL(layout, IFACE_("Prefilter:"), ICON_NONE);
|
||||
uiItemR(layout, ptr, "prefilter", DEFAULT_FLAGS, nullptr, ICON_NONE);
|
||||
uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
|
|
|
@ -1167,6 +1167,7 @@ typedef struct NodeCryptomatte {
|
|||
|
||||
typedef struct NodeDenoise {
|
||||
char hdr;
|
||||
char prefilter;
|
||||
} NodeDenoise;
|
||||
|
||||
typedef struct NodeAttributeClamp {
|
||||
|
@ -1840,6 +1841,14 @@ typedef enum CMPNodeSetAlphaMode {
|
|||
CMP_NODE_SETALPHA_MODE_REPLACE_ALPHA = 1,
|
||||
} CMPNodeSetAlphaMode;
|
||||
|
||||
/* Denoise Node. */
|
||||
/* `NodeDenoise.prefilter` */
|
||||
typedef enum CMPNodeDenoisePrefilter {
|
||||
CMP_NODE_DENOISE_PREFILTER_FAST = 0,
|
||||
CMP_NODE_DENOISE_PREFILTER_NONE = 1,
|
||||
CMP_NODE_DENOISE_PREFILTER_ACCURATE = 2
|
||||
} CMPNodeDenoisePrefilter;
|
||||
|
||||
#define CMP_NODE_PLANETRACKDEFORM_MBLUR_SAMPLES_MAX 64
|
||||
|
||||
/* Point Density shader node */
|
||||
|
|
|
@ -8890,12 +8890,37 @@ static void def_cmp_denoise(StructRNA *srna)
|
|||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
static const EnumPropertyItem prefilter_items[] = {
|
||||
{CMP_NODE_DENOISE_PREFILTER_NONE,
|
||||
"NONE",
|
||||
0,
|
||||
"None",
|
||||
"No prefiltering, use when guiding passes are noise-free"},
|
||||
{CMP_NODE_DENOISE_PREFILTER_FAST,
|
||||
"FAST",
|
||||
0,
|
||||
"Fast",
|
||||
"Denoise image and guiding passes together. Improves quality when guiding passes are noisy "
|
||||
"using least amount of extra processing time"},
|
||||
{CMP_NODE_DENOISE_PREFILTER_ACCURATE,
|
||||
"ACCURATE",
|
||||
0,
|
||||
"Accurate",
|
||||
"Prefilter noisy guiding passes before denoising image. Improves quality when guiding "
|
||||
"passes are noisy using extra processing time"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeDenoise", "storage");
|
||||
|
||||
prop = RNA_def_property(srna, "use_hdr", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "hdr", 0);
|
||||
RNA_def_property_ui_text(prop, "HDR", "Process HDR images");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "prefilter", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, prefilter_items);
|
||||
RNA_def_property_ui_text(prop, "", "Denoising prefilter");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_cmp_antialiasing(StructRNA *srna)
|
||||
|
|
|
@ -36,6 +36,7 @@ static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node)
|
|||
{
|
||||
NodeDenoise *ndg = MEM_callocN(sizeof(NodeDenoise), "node denoise data");
|
||||
ndg->hdr = true;
|
||||
ndg->prefilter = CMP_NODE_DENOISE_PREFILTER_ACCURATE;
|
||||
node->storage = ndg;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue