From 5489611e53176ad4c1d5ac626db6377b27624cce Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 14 Aug 2019 15:30:26 +0200 Subject: Compositor: Added denoising node This node is built on Intel's OpenImageDenoise library. Other denoisers could be integrated, for example Lukas' Cycles denoiser. Compositor: Made OpenImageDenoise optional, added CMake and build_env files to find OIDN Compositor: Fixed some warnings in the denoising operator build_environment: Updated OpenImageDenoise to 0.8.1 build_environment: Updated OpenImageDenoise in `make deps` for macOS Reviewers: sergey, jbakker, brecht Reviewed By: brecht Subscribers: YAFU, LazyDodo, Zen_YS, slumber, samgreen, tjvoll, yeus, ponomarovmax, getrad, coder.kalyan, vitos1k, Yegor, DeepBlender, kumaran7, Darkfie9825, aliasguru, aafra, ace_dragon, juang3d, pandrodor, cdog, lordodin, jtheninja, mavek, marcog, 5k1n2, Atair, rawalanche, 0o00o0oo, filibis, poor, lukasstockner97 Tags: #compositing Differential Revision: https://developer.blender.org/D4304 --- source/blender/compositor/CMakeLists.txt | 13 +- source/blender/compositor/intern/COM_Converter.cpp | 6 +- .../blender/compositor/nodes/COM_DenoiseNode.cpp | 47 +++++++ source/blender/compositor/nodes/COM_DenoiseNode.h | 37 +++++ .../compositor/operations/COM_DenoiseOperation.cpp | 154 +++++++++++++++++++++ .../compositor/operations/COM_DenoiseOperation.h | 71 ++++++++++ 6 files changed, 326 insertions(+), 2 deletions(-) create mode 100644 source/blender/compositor/nodes/COM_DenoiseNode.cpp create mode 100644 source/blender/compositor/nodes/COM_DenoiseNode.h create mode 100644 source/blender/compositor/operations/COM_DenoiseOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DenoiseOperation.h (limited to 'source/blender/compositor') diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 308a95c0e0c..50b5951f99f 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -276,11 +276,12 @@ set(SRC nodes/COM_VectorBlurNode.h operations/COM_VectorBlurOperation.cpp operations/COM_VectorBlurOperation.h - nodes/COM_BlurNode.cpp nodes/COM_BlurNode.h nodes/COM_BokehBlurNode.cpp nodes/COM_BokehBlurNode.h + nodes/COM_DenoiseNode.h + nodes/COM_DenoiseNode.cpp nodes/COM_DespeckleNode.cpp nodes/COM_DespeckleNode.h nodes/COM_DilateErodeNode.cpp @@ -490,6 +491,8 @@ set(SRC operations/COM_ConvolutionEdgeFilterOperation.h operations/COM_ConvolutionFilterOperation.cpp operations/COM_ConvolutionFilterOperation.h + operations/COM_DenoiseOperation.h + operations/COM_DenoiseOperation.cpp operations/COM_DespeckleOperation.cpp operations/COM_DespeckleOperation.h operations/COM_DilateErodeOperation.cpp @@ -558,4 +561,12 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() +if(WITH_OPENIMAGEDENOISE) + add_definitions(-DWITH_OPENIMAGEDENOISE) + add_definitions(-DOIDN_STATIC_LIB) + list(APPEND INC_SYS + ${OPENIMAGEDENOISE_INCLUDE_DIRS} + ) +endif() + blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index 9dc55527f0d..704833389f8 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -53,6 +53,7 @@ extern "C" { #include "COM_CropNode.h" #include "COM_CryptomatteNode.h" #include "COM_DefocusNode.h" +#include "COM_DenoiseNode.h" #include "COM_DespeckleNode.h" #include "COM_DifferenceMatteNode.h" #include "COM_DilateErodeNode.h" @@ -122,7 +123,7 @@ bool Converter::is_fast_node(bNode *b_node) b_node->type == CMP_NODE_BOKEHBLUR || b_node->type == CMP_NODE_GLARE || b_node->type == CMP_NODE_DBLUR || b_node->type == CMP_NODE_MOVIEDISTORTION || b_node->type == CMP_NODE_LENSDIST || b_node->type == CMP_NODE_DOUBLEEDGEMASK || - b_node->type == CMP_NODE_DILATEERODE); + b_node->type == CMP_NODE_DILATEERODE || b_node->type == CMP_NODE_DENOISE); } Node *Converter::convert(bNode *b_node) @@ -402,6 +403,9 @@ Node *Converter::convert(bNode *b_node) case CMP_NODE_CRYPTOMATTE: node = new CryptomatteNode(b_node); break; + case CMP_NODE_DENOISE: + node = new DenoiseNode(b_node); + break; } return node; } diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.cpp b/source/blender/compositor/nodes/COM_DenoiseNode.cpp new file mode 100644 index 00000000000..7de120d1204 --- /dev/null +++ b/source/blender/compositor/nodes/COM_DenoiseNode.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2019, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Stefan Werner + */ + +#include "COM_DenoiseNode.h" +#include "DNA_node_types.h" +#include "COM_SetValueOperation.h" +#include "COM_MixOperation.h" +#include "COM_DenoiseOperation.h" + +DenoiseNode::DenoiseNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void DenoiseNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *node = this->getbNode(); + NodeDenoise *denoise = (NodeDenoise *)node->storage; + + DenoiseOperation *operation = new DenoiseOperation(); + converter.addOperation(operation); + operation->setDenoiseSettings(denoise); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.h b/source/blender/compositor/nodes/COM_DenoiseNode.h new file mode 100644 index 00000000000..0924da8931c --- /dev/null +++ b/source/blender/compositor/nodes/COM_DenoiseNode.h @@ -0,0 +1,37 @@ +/* + * Copyright 2019, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Stefan Werner + */ + +#ifndef __COM_DENOISENODE_H__ +#define __COM_DENOISENODE_H__ + +#include "COM_Node.h" + +/** + * \brief DenoiseNode + * \ingroup Node + */ +class DenoiseNode : public Node { + public: + DenoiseNode(bNode *editorNode); + void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; +}; + +#endif diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cpp b/source/blender/compositor/operations/COM_DenoiseOperation.cpp new file mode 100644 index 00000000000..af568490c72 --- /dev/null +++ b/source/blender/compositor/operations/COM_DenoiseOperation.cpp @@ -0,0 +1,154 @@ +/* + * Copyright 2019, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Stefan Werner + */ + +#include "COM_DenoiseOperation.h" +#include "BLI_math.h" +#ifdef WITH_OPENIMAGEDENOISE +# include +#endif +#include + +DenoiseOperation::DenoiseOperation() : SingleThreadedOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VECTOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_settings = NULL; +} +void DenoiseOperation::initExecution() +{ + SingleThreadedOperation::initExecution(); + this->m_inputProgramColor = getInputSocketReader(0); + this->m_inputProgramAlbedo = getInputSocketReader(1); + this->m_inputProgramNormal = getInputSocketReader(2); +} + +void DenoiseOperation::deinitExecution() +{ + this->m_inputProgramColor = NULL; + this->m_inputProgramAlbedo = NULL; + this->m_inputProgramNormal = NULL; + SingleThreadedOperation::deinitExecution(); +} + +MemoryBuffer *DenoiseOperation::createMemoryBuffer(rcti *rect2) +{ + MemoryBuffer *tileColor = (MemoryBuffer *)this->m_inputProgramColor->initializeTileData(rect2); + MemoryBuffer *tileAlbedo = (MemoryBuffer *)this->m_inputProgramAlbedo->initializeTileData(rect2); + MemoryBuffer *tileNormal = (MemoryBuffer *)this->m_inputProgramNormal->initializeTileData(rect2); + rcti rect; + rect.xmin = 0; + rect.ymin = 0; + rect.xmax = getWidth(); + rect.ymax = getHeight(); + MemoryBuffer *result = new MemoryBuffer(COM_DT_COLOR, &rect); + float *data = result->getBuffer(); + this->generateDenoise(data, tileColor, tileAlbedo, tileNormal, this->m_settings); + return result; +} + +bool DenoiseOperation::determineDependingAreaOfInterest(rcti * /*input*/, + ReadBufferOperation *readOperation, + rcti *output) +{ + if (isCached()) { + return false; + } + else { + 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(float *data, + MemoryBuffer *inputTileColor, + MemoryBuffer *inputTileAlbedo, + MemoryBuffer *inputTileNormal, + NodeDenoise *settings) +{ + float *inputBufferColor = inputTileColor->getBuffer(); + BLI_assert(inputBufferColor); + if (!inputBufferColor) { + return; + } +#ifdef WITH_OPENIMAGEDENOISE + oidn::DeviceRef device = oidn::newDevice(); + device.commit(); + + oidn::FilterRef filter = device.newFilter("RT"); + filter.setImage("color", + inputBufferColor, + oidn::Format::Float3, + inputTileColor->getWidth(), + inputTileColor->getHeight(), + 0, + 4 * sizeof(float)); + if (inputTileAlbedo && inputTileAlbedo->getBuffer()) { + filter.setImage("albedo", + inputTileAlbedo->getBuffer(), + oidn::Format::Float3, + inputTileAlbedo->getWidth(), + inputTileAlbedo->getHeight(), + 0, + 4 * sizeof(float)); + } + if (inputTileNormal && inputTileNormal->getBuffer()) { + filter.setImage("normal", + inputTileNormal->getBuffer(), + oidn::Format::Float3, + inputTileNormal->getWidth(), + inputTileNormal->getHeight(), + 0, + 3 * sizeof(float)); + } + filter.setImage("output", + data, + oidn::Format::Float3, + inputTileColor->getWidth(), + inputTileColor->getHeight(), + 0, + 4 * sizeof(float)); + + BLI_assert(settings); + if (settings) { + filter.set("hdr", settings->hdr); + filter.set("srgb", false); + } + + filter.commit(); + filter.execute(); + + /* copy the alpha channel, OpenImageDenoise currently only supports RGB */ + size_t numPixels = inputTileColor->getWidth() * inputTileColor->getHeight(); + for (size_t i = 0; i < numPixels; ++i) { + data[i * 4 + 3] = inputBufferColor[i * 4 + 3]; + } +#else + ::memcpy(data, + inputBufferColor, + inputTileColor->getWidth() * inputTileColor->getHeight() * sizeof(float) * 4); +#endif +} diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.h b/source/blender/compositor/operations/COM_DenoiseOperation.h new file mode 100644 index 00000000000..6e19bd6034a --- /dev/null +++ b/source/blender/compositor/operations/COM_DenoiseOperation.h @@ -0,0 +1,71 @@ +/* + * Copyright 2019, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Stefan Werner + */ + +#ifndef __COM_DENOISEBASEOPERATION_H__ +#define __COM_DENOISEBASEOPERATION_H__ + +#include "COM_SingleThreadedOperation.h" +#include "DNA_node_types.h" + +class DenoiseOperation : public SingleThreadedOperation { + private: + /** + * \brief Cached reference to the input programs + */ + SocketReader *m_inputProgramColor; + SocketReader *m_inputProgramAlbedo; + SocketReader *m_inputProgramNormal; + + /** + * \brief settings of the denoise node. + */ + NodeDenoise *m_settings; + + public: + DenoiseOperation(); + /** + * Initialize the execution + */ + void initExecution(); + + /** + * Deinitialize the execution + */ + void deinitExecution(); + + void setDenoiseSettings(NodeDenoise *settings) + { + this->m_settings = settings; + } + bool determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output); + + protected: + void generateDenoise(float *data, + MemoryBuffer *inputTileColor, + MemoryBuffer *inputTileAlbedo, + MemoryBuffer *inputTileNormal, + NodeDenoise *settings); + + MemoryBuffer *createMemoryBuffer(rcti *rect); +}; +#endif -- cgit v1.2.3