Fix T51308: Bright/Contrast Doesn't respect Pre-multiplied Alpha
authorSergey Sharybin <sergey.vfx@gmail.com>
Mon, 22 May 2017 15:12:13 +0000 (17:12 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Mon, 22 May 2017 15:15:45 +0000 (17:15 +0200)
Brightness/contrast node was changing color but did not modify alpha
or ensured colors are premultiplied on the output. This was giving
artifacts later on unless alpha was manually converted.

Compositor is supposed to work in premultiplied alpha (except of
some really corner cases) so it makes sense to ensure premultiplied
alpha after brightness/contrast node.

This is now done as an option enabled by default, so we:

(a) Keep compatibility with old files.
(b) Have correct behavior for newly created files.

Later on we can get rid of this option.

source/blender/compositor/nodes/COM_BrightnessNode.cpp
source/blender/compositor/operations/COM_BrightnessOperation.cpp
source/blender/compositor/operations/COM_BrightnessOperation.h
source/blender/editors/space_node/drawnode.c
source/blender/makesrna/intern/rna_nodetree.c
source/blender/nodes/NOD_static_types.h
source/blender/nodes/composite/nodes/node_composite_brightness.c

index 053f286c66e9ecb8b8f3d192f2d9147215caca19..6729571fac0fbb0c416a88bd080b69d7af52f12f 100644 (file)
@@ -31,7 +31,9 @@ BrightnessNode::BrightnessNode(bNode *editorNode) : Node(editorNode)
 
 void BrightnessNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
 {
+       bNode *bnode = this->getbNode();
        BrightnessOperation *operation = new BrightnessOperation();
+       operation->setUsePremultiply((bnode->custom1 & 1) != 0);
        converter.addOperation(operation);
        
        converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
index 33e35c3fe3bbf5b9afbd746c41983aab46e9654c..c7ba86b66bc22ba26779cde2eebb053eefa8d208 100644 (file)
@@ -29,7 +29,14 @@ BrightnessOperation::BrightnessOperation() : NodeOperation()
        this->addInputSocket(COM_DT_VALUE);
        this->addOutputSocket(COM_DT_COLOR);
        this->m_inputProgram = NULL;
+       this->m_use_premultiply = false;
 }
+
+void BrightnessOperation::setUsePremultiply(bool use_premultiply)
+{
+       this->m_use_premultiply = use_premultiply;
+}
+
 void BrightnessOperation::initExecution()
 {
        this->m_inputProgram = this->getInputSocketReader(0);
@@ -64,11 +71,16 @@ void BrightnessOperation::executePixelSampled(float output[4], float x, float y,
                delta *= -1;
                b = a * (brightness + delta);
        }
-       
+       if (this->m_use_premultiply) {
+               premul_to_straight_v4(inputValue);
+       }
        output[0] = a * inputValue[0] + b;
        output[1] = a * inputValue[1] + b;
        output[2] = a * inputValue[2] + b;
        output[3] = inputValue[3];
+       if (this->m_use_premultiply) {
+               straight_to_premul_v4(output);
+       }
 }
 
 void BrightnessOperation::deinitExecution()
index 22086ae11e83cc43f55a0ae1614acebb8c221df0..ff492f2b102c3fc21a07559ad1be1c58fd20a93c 100644 (file)
@@ -34,6 +34,8 @@ private:
        SocketReader *m_inputBrightnessProgram;
        SocketReader *m_inputContrastProgram;
 
+       bool m_use_premultiply;
+
 public:
        BrightnessOperation();
        
@@ -52,5 +54,6 @@ public:
         */
        void deinitExecution();
 
+       void setUsePremultiply(bool use_premultiply);
 };
 #endif
index bbbbad41aa0c97780bbbe5afbea81422f0de5826..f58b4050834deeae9536ab96c6e4ca26bc6938a7 100644 (file)
@@ -2478,6 +2478,11 @@ static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), P
        uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
 }
 
+static void node_composit_buts_brightcontrast(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+       uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE);
+}
+
 /* only once called */
 static void node_composit_set_butfunc(bNodeType *ntype)
 {
@@ -2705,6 +2710,8 @@ static void node_composit_set_butfunc(bNodeType *ntype)
                case CMP_NODE_SUNBEAMS:
                        ntype->draw_buttons = node_composit_buts_sunbeams;
                        break;
+               case CMP_NODE_BRIGHTCONTRAST:
+                       ntype->draw_buttons = node_composit_buts_brightcontrast;
        }
 }
 
index 60b75fca6895c89464a3a11fcc808d24476c4221..22d07d739cdf102b3fe92832c4d568b4a1e4f1e4 100644 (file)
@@ -5239,6 +5239,16 @@ static void def_cmp_luma_matte(StructRNA *srna)
        RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
 }
 
+static void def_cmp_brightcontrast(StructRNA *srna)
+{
+       PropertyRNA *prop;
+
+       prop = RNA_def_property(srna, "use_premultiply", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
+       RNA_def_property_ui_text(prop, "Convert Premul", "Keep output image premultiplied alpha");
+       RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
 static void def_cmp_chroma_matte(StructRNA *srna)
 {
        PropertyRNA *prop;
index e754d06339707e91d8f367399b7322bd0e838318..02422a8622adfd148007ba95a149f30e167be245 100644 (file)
@@ -179,7 +179,7 @@ DefNode( CompositorNode, CMP_NODE_DISPLACE,       0,                      "DISPL
 DefNode( CompositorNode, CMP_NODE_COMBHSVA,       0,                      "COMBHSVA",       CombHSVA,         "Combine HSVA",      ""              )
 DefNode( CompositorNode, CMP_NODE_MATH,           def_math,               "MATH",           Math,             "Math",              ""              )
 DefNode( CompositorNode, CMP_NODE_LUMA_MATTE,     def_cmp_luma_matte,     "LUMA_MATTE",     LumaMatte,        "Luminance Key",     ""              )
-DefNode( CompositorNode, CMP_NODE_BRIGHTCONTRAST, 0,                      "BRIGHTCONTRAST", BrightContrast,   "Bright/Contrast",   ""              )
+DefNode( CompositorNode, CMP_NODE_BRIGHTCONTRAST, def_cmp_brightcontrast, "BRIGHTCONTRAST", BrightContrast,   "Bright/Contrast",   ""              )
 DefNode( CompositorNode, CMP_NODE_GAMMA,          0,                      "GAMMA",          Gamma,            "Gamma",             ""              )
 DefNode( CompositorNode, CMP_NODE_INVERT,         def_cmp_invert,         "INVERT",         Invert,           "Invert",            ""              )
 DefNode( CompositorNode, CMP_NODE_NORMALIZE,      0,                      "NORMALIZE",      Normalize,        "Normalize",         ""              )
index 62f23f417b2b1d01e2b6459c08c399e93862a3b5..26e4d3a52c98fec180d7a0d93726c86720baad56 100644 (file)
@@ -46,6 +46,10 @@ static bNodeSocketTemplate cmp_node_brightcontrast_out[] = {
        {       -1, 0, ""       }
 };
 
+static void node_composit_init_brightcontrast(bNodeTree *UNUSED(ntree), bNode *node)
+{
+       node->custom1 = 1;
+}
 
 void register_node_type_cmp_brightcontrast(void)
 {
@@ -53,6 +57,7 @@ void register_node_type_cmp_brightcontrast(void)
        
        cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
        node_type_socket_templates(&ntype, cmp_node_brightcontrast_in, cmp_node_brightcontrast_out);
+       node_type_init(&ntype, node_composit_init_brightcontrast);
 
        nodeRegisterType(&ntype);
 }