feather option for dilate/erode node - needed for alpha masks so we can (blur in/out), currently only positive values supported.

This commit is contained in:
Campbell Barton
2012-06-16 13:46:20 +00:00
parent 2f29f8d186
commit 265262a5d5
16 changed files with 566 additions and 11 deletions

View File

@@ -2098,4 +2098,3 @@ void clear_scene_in_nodes(Main *bmain, Scene *sce)
}
}
}

View File

@@ -288,6 +288,10 @@ set(SRC
nodes/COM_BokehBlurNode.h
nodes/COM_DirectionalBlurNode.cpp
nodes/COM_DirectionalBlurNode.h
operations/COM_GaussianAlphaXBlurOperation.cpp
operations/COM_GaussianAlphaXBlurOperation.h
operations/COM_GaussianAlphaYBlurOperation.cpp
operations/COM_GaussianAlphaYBlurOperation.h
operations/COM_GaussianXBlurOperation.cpp
operations/COM_GaussianXBlurOperation.h
operations/COM_GaussianYBlurOperation.cpp

View File

@@ -25,6 +25,8 @@
#include "COM_ExecutionSystem.h"
#include "COM_DilateErodeOperation.h"
#include "COM_AntiAliasOperation.h"
#include "COM_GaussianAlphaXBlurOperation.h"
#include "COM_GaussianAlphaYBlurOperation.h"
#include "BLI_math.h"
DilateErodeNode::DilateErodeNode(bNode *editorNode) : Node(editorNode)
@@ -70,6 +72,53 @@ void DilateErodeNode::convertToOperations(ExecutionSystem *graph, CompositorCont
graph->addOperation(operation);
}
}
else if (editorNode->custom1 == CMP_NODE_DILATEERODE_DISTANCE_FEATHER) {
/* this uses a modified gaussian blur function otherwise its far too slow */
if (editorNode->custom2 > 0) {
CompositorQuality quality = context->getQuality();
/* initialize node data */
NodeBlurData *data = (NodeBlurData *)&this->alpha_blur;
memset(data, 0, sizeof(*data));
data->sizex = data->sizey = editorNode->custom2;
data->filtertype = R_FILTER_GAUSS;
GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation();
operationx->setData(data);
operationx->setQuality(quality);
this->getInputSocket(0)->relinkConnections(operationx->getInputSocket(0), 0, graph);
this->getInputSocket(1)->relinkConnections(operationx->getInputSocket(1), 1, graph);
graph->addOperation(operationx);
GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation();
operationy->setData(data);
operationy->setQuality(quality);
this->getOutputSocket(0)->relinkConnections(operationy->getOutputSocket());
graph->addOperation(operationy);
addLink(graph, operationx->getOutputSocket(), operationy->getInputSocket(0));
addLink(graph, operationx->getInputSocket(1)->getConnection()->getFromSocket(), operationy->getInputSocket(1));
addPreviewOperation(graph, operationy->getOutputSocket());
/* TODO? */
/* see gaussian blue node for original usage */
#if 0
if (!connectedSizeSocket) {
operationx->setSize(size);
operationy->setSize(size);
}
#else
operationx->setSize(1.0f);
operationy->setSize(1.0f);
#endif
}
else {
ErodeDistanceOperation *operation = new ErodeDistanceOperation();
operation->setDistance(-editorNode->custom2);
this->getInputSocket(0)->relinkConnections(operation->getInputSocket(0), 0, graph);
this->getOutputSocket(0)->relinkConnections(operation->getOutputSocket(0));
graph->addOperation(operation);
}
}
else {
if (editorNode->custom2 > 0) {
DilateStepOperation *operation = new DilateStepOperation();

View File

@@ -30,6 +30,7 @@
* @ingroup Node
*/
class DilateErodeNode : public Node {
NodeBlurData alpha_blur; /* only used for blurring alpha, since the dilate/erode node doesnt have this */
public:
DilateErodeNode(bNode *editorNode);
void convertToOperations(ExecutionSystem *graph, CompositorContext *context);

View File

@@ -27,11 +27,11 @@ extern "C" {
#include "RE_pipeline.h"
}
BlurBaseOperation::BlurBaseOperation() : NodeOperation()
BlurBaseOperation::BlurBaseOperation(DataType data_type=COM_DT_COLOR) : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR);
this->addInputSocket(data_type);
this->addInputSocket(COM_DT_VALUE);
this->addOutputSocket(COM_DT_COLOR);
this->addOutputSocket(data_type);
this->setComplex(true);
this->inputProgram = NULL;
this->data = NULL;
@@ -89,6 +89,24 @@ float *BlurBaseOperation::make_gausstab(int rad)
return gausstab;
}
/* normalized distance from the current (inverted so 1.0 is close and 0.0 is far) */
float *BlurBaseOperation::make_dist_fac_inverse(int rad)
{
float *dist_fac_invert, val;
int i, n;
n = 2 * rad + 1;
dist_fac_invert = new float[n];
for (i = -rad; i <= rad; i++) {
val = 1.0f - fabsf(((float)i / (float)rad));
dist_fac_invert[i + rad] = val;
}
return dist_fac_invert;
}
void BlurBaseOperation::deinitExecution()
{
this->inputProgram = NULL;

View File

@@ -35,8 +35,9 @@ protected:
SocketReader *inputProgram;
SocketReader *inputSize;
NodeBlurData *data;
BlurBaseOperation();
BlurBaseOperation(DataType data_type);
float *make_gausstab(int rad);
float *make_dist_fac_inverse(int rad);
float size;
bool deleteData;
bool sizeavailable;

View File

@@ -26,7 +26,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
FastGaussianBlurOperation::FastGaussianBlurOperation() : BlurBaseOperation()
FastGaussianBlurOperation::FastGaussianBlurOperation() : BlurBaseOperation(COM_DT_COLOR)
{
this->iirgaus = NULL;
}

View File

@@ -0,0 +1,186 @@
/*
* Copyright 2011, 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:
* Jeroen Bakker
* Monique Dewanchand
* Campbell Barton
*/
#include "COM_GaussianAlphaXBlurOperation.h"
#include "BLI_math.h"
extern "C" {
#include "RE_pipeline.h"
}
GaussianAlphaXBlurOperation::GaussianAlphaXBlurOperation() : BlurBaseOperation(COM_DT_VALUE)
{
this->gausstab = NULL;
this->rad = 0;
}
void *GaussianAlphaXBlurOperation::initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers)
{
if (!this->sizeavailable) {
updateGauss(memoryBuffers);
}
void *buffer = getInputOperation(0)->initializeTileData(NULL, memoryBuffers);
return buffer;
}
void GaussianAlphaXBlurOperation::initExecution()
{
BlurBaseOperation::initExecution();
if (this->sizeavailable) {
float rad = size * this->data->sizex;
if (rad < 1)
rad = 1;
this->rad = rad;
this->gausstab = BlurBaseOperation::make_gausstab(rad);
this->distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad);
}
}
void GaussianAlphaXBlurOperation::updateGauss(MemoryBuffer **memoryBuffers)
{
if (this->gausstab == NULL) {
updateSize(memoryBuffers);
float rad = size * this->data->sizex;
if (rad < 1)
rad = 1;
this->rad = rad;
this->gausstab = BlurBaseOperation::make_gausstab(rad);
}
if (this->distbuf_inv == NULL) {
updateSize(memoryBuffers);
float rad = size * this->data->sizex;
if (rad < 1)
rad = 1;
this->rad = rad;
this->distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad);
}
}
void GaussianAlphaXBlurOperation::executePixel(float *color, int x, int y, MemoryBuffer *inputBuffers[], void *data)
{
MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
float *buffer = inputBuffer->getBuffer();
int bufferwidth = inputBuffer->getWidth();
int bufferstartx = inputBuffer->getRect()->xmin;
int bufferstarty = inputBuffer->getRect()->ymin;
int miny = y;
int maxy = y;
int minx = x - this->rad;
int maxx = x + this->rad;
miny = max(miny, inputBuffer->getRect()->ymin);
minx = max(minx, inputBuffer->getRect()->xmin);
maxy = min(maxy, inputBuffer->getRect()->ymax);
maxx = min(maxx, inputBuffer->getRect()->xmax);
/* *** this is the main part which is different to 'GaussianXBlurOperation' *** */
int step = getStep();
int offsetadd = getOffsetAdd();
int bufferindex = ((minx - bufferstartx) * 4) + ((miny - bufferstarty) * 4 * bufferwidth);
/* gauss */
float tempColor = 0.0f;
float overallmultiplyer = 0.0f;
/* dilate */
float value_max = buffer[(x * 4) + (y * 4 * bufferwidth)]; /* init with the current color to avoid unneeded lookups */
float distfacinv_max = 1.0f; /* 0 to 1 */
for (int nx = minx; nx < maxx; nx += step) {
const int index = (nx - x) + this->rad;
float value = buffer[bufferindex];
float multiplyer;
/* gauss */
{
multiplyer = gausstab[index];
tempColor += value * multiplyer;
overallmultiplyer += multiplyer;
}
/* dilate - find most extreme color */
if (value > value_max) {
#if 0
multiplyer = 1.0f - ((fabsf(x - nx)) / (float)this->rad);
#else
multiplyer = distbuf_inv[index];
#endif
value *= multiplyer;
if ((value > value_max) == TRUE) {
value_max = value;
distfacinv_max = multiplyer;
}
}
bufferindex += offsetadd;
}
/* blend between the max value and gauss blue - gives nice feather */
const float value_gauss = tempColor / overallmultiplyer;
const float value_final = (value_max * distfacinv_max) + (value_gauss * (1.0f - distfacinv_max));
color[0] = value_final;
}
void GaussianAlphaXBlurOperation::deinitExecution()
{
BlurBaseOperation::deinitExecution();
delete [] this->gausstab;
this->gausstab = NULL;
delete [] this->distbuf_inv;
this->distbuf_inv = NULL;
}
bool GaussianAlphaXBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
rcti sizeInput;
sizeInput.xmin = 0;
sizeInput.ymin = 0;
sizeInput.xmax = 5;
sizeInput.ymax = 5;
NodeOperation *operation = this->getInputOperation(1);
if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
return true;
}
else {
if (this->sizeavailable && this->gausstab != NULL) {
newInput.xmax = input->xmax + rad;
newInput.xmin = input->xmin - rad;
newInput.ymax = input->ymax;
newInput.ymin = input->ymin;
}
else {
newInput.xmax = this->getWidth();
newInput.xmin = 0;
newInput.ymax = this->getHeight();
newInput.ymin = 0;
}
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2011, 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:
* Jeroen Bakker
* Monique Dewanchand
* Campbell Barton
*/
#ifndef _COM_GaussianAlphaXBlurOperation_h
#define _COM_GaussianAlphaXBlurOperation_h
#include "COM_NodeOperation.h"
#include "COM_BlurBaseOperation.h"
class GaussianAlphaXBlurOperation : public BlurBaseOperation {
private:
float *gausstab;
float *distbuf_inv;
int rad;
void updateGauss(MemoryBuffer **memoryBuffers);
public:
GaussianAlphaXBlurOperation();
/**
* @brief the inner loop of this program
*/
void executePixel(float *color, int x, int y, MemoryBuffer * inputBuffers[], void *data);
/**
* @brief initialize the execution
*/
void initExecution();
/**
* @brief Deinitialize the execution
*/
void deinitExecution();
void *initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers);
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
};
#endif

View File

@@ -0,0 +1,183 @@
/*
* Copyright 2011, 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:
* Jeroen Bakker
* Monique Dewanchand
* Campbell Barton
*/
#include "COM_GaussianAlphaYBlurOperation.h"
#include "BLI_math.h"
extern "C" {
#include "RE_pipeline.h"
}
GaussianAlphaYBlurOperation::GaussianAlphaYBlurOperation() : BlurBaseOperation(COM_DT_VALUE)
{
this->gausstab = NULL;
this->rad = 0;
}
void *GaussianAlphaYBlurOperation::initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers)
{
if (!this->sizeavailable) {
updateGauss(memoryBuffers);
}
void *buffer = getInputOperation(0)->initializeTileData(NULL, memoryBuffers);
return buffer;
}
void GaussianAlphaYBlurOperation::initExecution()
{
if (this->sizeavailable) {
float rad = size * this->data->sizey;
if (rad < 1)
rad = 1;
this->rad = rad;
this->gausstab = BlurBaseOperation::make_gausstab(rad);
this->distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad);
}
}
void GaussianAlphaYBlurOperation::updateGauss(MemoryBuffer **memoryBuffers)
{
if (this->gausstab == NULL) {
updateSize(memoryBuffers);
float rad = size * this->data->sizey;
if (rad < 1)
rad = 1;
this->rad = rad;
this->gausstab = BlurBaseOperation::make_gausstab(rad);
}
if (this->distbuf_inv == NULL) {
updateSize(memoryBuffers);
float rad = size * this->data->sizex;
if (rad < 1)
rad = 1;
this->rad = rad;
this->distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad);
}
}
void GaussianAlphaYBlurOperation::executePixel(float *color, int x, int y, MemoryBuffer *inputBuffers[], void *data)
{
MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
float *buffer = inputBuffer->getBuffer();
int bufferwidth = inputBuffer->getWidth();
int bufferstartx = inputBuffer->getRect()->xmin;
int bufferstarty = inputBuffer->getRect()->ymin;
int miny = y - this->rad;
int maxy = y + this->rad;
int minx = x;
int maxx = x;
miny = max(miny, inputBuffer->getRect()->ymin);
minx = max(minx, inputBuffer->getRect()->xmin);
maxy = min(maxy, inputBuffer->getRect()->ymax);
maxx = min(maxx, inputBuffer->getRect()->xmax);
/* *** this is the main part which is different to 'GaussianYBlurOperation' *** */
int step = getStep();
/* gauss */
float tempColor = 0.0f;
float overallmultiplyer = 0.0f;
/* dilate */
float value_max = buffer[(x * 4) + (y * 4 * bufferwidth)]; /* init with the current color to avoid unneeded lookups */
float distfacinv_max = 1.0f; /* 0 to 1 */
for (int ny = miny; ny < maxy; ny += step) {
int bufferindex = ((minx - bufferstartx) * 4) + ((ny - bufferstarty) * 4 * bufferwidth);
const int index = (ny - y) + this->rad;
float value = buffer[bufferindex];
float multiplyer;
/* gauss */
{
multiplyer = gausstab[index];
tempColor += value * multiplyer;
overallmultiplyer += multiplyer;
}
/* dilate - find most extreme color */
if (value > value_max) {
#if 0
multiplyer = 1.0f - ((fabsf(y - ny)) / (float)this->rad);
#else
multiplyer = distbuf_inv[index];
#endif
value *= multiplyer;
if (value > value_max) {
value_max = value;
distfacinv_max = multiplyer;
}
}
}
/* blend between the max value and gauss blue - gives nice feather */
const float value_gauss = tempColor / overallmultiplyer;
const float value_final = (value_max * distfacinv_max) + (value_gauss * (1.0f - distfacinv_max));
color[0] = value_final;
}
void GaussianAlphaYBlurOperation::deinitExecution()
{
BlurBaseOperation::deinitExecution();
delete [] this->gausstab;
this->gausstab = NULL;
delete [] this->distbuf_inv;
this->distbuf_inv = NULL;
}
bool GaussianAlphaYBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
rcti sizeInput;
sizeInput.xmin = 0;
sizeInput.ymin = 0;
sizeInput.xmax = 5;
sizeInput.ymax = 5;
NodeOperation *operation = this->getInputOperation(1);
if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
return true;
}
else {
if (this->sizeavailable && this->gausstab != NULL) {
newInput.xmax = input->xmax;
newInput.xmin = input->xmin;
newInput.ymax = input->ymax + rad;
newInput.ymin = input->ymin - rad;
}
else {
newInput.xmax = this->getWidth();
newInput.xmin = 0;
newInput.ymax = this->getHeight();
newInput.ymin = 0;
}
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2011, 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:
* Jeroen Bakker
* Monique Dewanchand
* Campbell Barton
*/
#ifndef _COM_GaussianAlphaYBlurOperation_h
#define _COM_GaussianAlphaYBlurOperation_h
#include "COM_NodeOperation.h"
#include "COM_BlurBaseOperation.h"
class GaussianAlphaYBlurOperation : public BlurBaseOperation {
private:
float *gausstab;
float *distbuf_inv;
int rad;
void updateGauss(MemoryBuffer **memoryBuffers);
public:
GaussianAlphaYBlurOperation();
/**
* the inner loop of this program
*/
void executePixel(float *color, int x, int y, MemoryBuffer * inputBuffers[], void *data);
/**
* @brief initialize the execution
*/
void initExecution();
/**
* Deinitialize the execution
*/
void deinitExecution();
void *initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers);
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
};
#endif

View File

@@ -27,7 +27,7 @@ extern "C" {
#include "RE_pipeline.h"
}
GaussianBokehBlurOperation::GaussianBokehBlurOperation() : BlurBaseOperation()
GaussianBokehBlurOperation::GaussianBokehBlurOperation() : BlurBaseOperation(COM_DT_COLOR)
{
this->gausstab = NULL;
}

View File

@@ -27,7 +27,7 @@ extern "C" {
#include "RE_pipeline.h"
}
GaussianXBlurOperation::GaussianXBlurOperation() : BlurBaseOperation()
GaussianXBlurOperation::GaussianXBlurOperation() : BlurBaseOperation(COM_DT_COLOR)
{
this->gausstab = NULL;
this->rad = 0;

View File

@@ -27,7 +27,7 @@ extern "C" {
#include "RE_pipeline.h"
}
GaussianYBlurOperation::GaussianYBlurOperation() : BlurBaseOperation()
GaussianYBlurOperation::GaussianYBlurOperation() : BlurBaseOperation(COM_DT_COLOR)
{
this->gausstab = NULL;
this->rad = 0;

View File

@@ -361,6 +361,7 @@ typedef struct bNodeSocketValueRGBA {
#define CMP_NODE_DILATEERODE_STEP 0
#define CMP_NODE_DILATEERODE_DISTANCE_THRESH 1
#define CMP_NODE_DILATEERODE_DISTANCE 2
#define CMP_NODE_DILATEERODE_DISTANCE_FEATHER 3
typedef struct NodeFrame {
short flag;

View File

@@ -2049,10 +2049,11 @@ static void def_cmp_dilate_erode(StructRNA *srna)
PropertyRNA *prop;
static EnumPropertyItem type_items[] = {
{CMP_NODE_DILATEERODE_STEP, "STEP", 0, "Step", ""},
{CMP_NODE_DILATEERODE_STEP, "STEP", 0, "Step", ""},
{CMP_NODE_DILATEERODE_DISTANCE_THRESH, "THRESHOLD", 0, "Threshold", ""},
{CMP_NODE_DILATEERODE_DISTANCE, "DISTANCE", 0, "Distance", ""},
{0, NULL, 0, NULL, NULL}
{CMP_NODE_DILATEERODE_DISTANCE_FEATHER,"FEATHER", 0, "Feather", ""},
{0, NULL, 0, NULL, NULL}
};
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);