Directional Blur Node
authorJuho Vepsalainen <bebraw@gmail.com>
Thu, 27 Dec 2007 14:19:11 +0000 (14:19 +0000)
committerJuho Vepsalainen <bebraw@gmail.com>
Thu, 27 Dec 2007 14:19:11 +0000 (14:19 +0000)
Directional Blur node allows the users to do various blur operations on the input
image. It essentially offers three different kind of ways of blurring in one node.
It is possible to blur using a certain direction, spin and zoom. These three ways
can be used in conjunction.

The node contains following controls:
*Iterations, Wrap
*Center: X, Y
*Distance, Angle
*Spin
*Zoom

Iterations is used to determine the smoothness of the result. The more iterations,
the smoother result. Low values are good for preview.

Wrap means that the image is wrapped as if it was tiled on both x and y directions.
To see better what this means, try it with spin for instance.

Center values (X and Y) determine the location which is used as a pivot point for
the operations. It is center (0.5) of the image by default.

Distance and angle are used to adjust directional blur. The result can be described
as a sweep that varies based on given distance (bigger distance, longer sweep) and
angle. Angle is given in degrees.

Spin produces rotating blur based on given angle. Yet again it is in degrees. Also
negative values work.

Zoom causes the image to be zoomed towards set center point (Center values).

Thanks to Alfredo de Greef (eeshlo) for contribution.

Possible development ideas:
*Make an algorithm to extend image in case spin is used. Extend would temporarily
change the size of the canvas of the input image. Canvas would be filled based on
colors on the edges of the input image. After the blur operation has been done,
the image would be cropped back to normal size. The advantage of this would be nicer
result of spin (no problems with image size) on a computational cost.
*Make values animatable. This is something that is better solved on more general
level. ("everything is animatable" paradigm)
*Provide an option to calculate automatic value for iterations. A good value that
produces a smooth result could be calculated based on direction deltas. This would be
useful in conjuction of animatable values.

source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/BKE_utildefines.h
source/blender/blenkernel/intern/node.c
source/blender/makesdna/DNA_node_types.h
source/blender/nodes/CMP_node.h
source/blender/nodes/intern/CMP_nodes/CMP_directionalblur.c [new file with mode: 0644]
source/blender/src/drawnode.c

index b9df1e45bae90e41f2903ed6a5cd1f10b083fc4d..3fd9d00b208fa1f604bcdcd43a21e30087c9a425 100644 (file)
@@ -306,6 +306,7 @@ void                        set_node_shader_lamp_loop(void (*lamp_loop_func)(struct ShadeInput *, str
 #define CMP_NODE_INVERT                251
 #define CMP_NODE_NORMALIZE      252
 #define CMP_NODE_CROP          253
+#define CMP_NODE_DBLUR         254
 
 #define CMP_NODE_GLARE         301
 #define CMP_NODE_TONEMAP       302
index f3f66190c31b98f020bf2feb86d5cb006b390d08..d08f42375ac785f6456cdbf6e6487a924f4dd392 100644 (file)
 
 #define ABS(a)                                 ( (a)<0 ? (-(a)) : (a) )
 
+#define AVG2(x, y)             ( 0.5 * ((x) + (y)) )
+
 #define VECCOPY(v1,v2)          {*(v1)= *(v2); *(v1+1)= *(v2+1); *(v1+2)= *(v2+2);}
 #define VECCOPY2D(v1,v2)          {*(v1)= *(v2); *(v1+1)= *(v2+1);}
 #define QUATCOPY(v1,v2)         {*(v1)= *(v2); *(v1+1)= *(v2+1); *(v1+2)= *(v2+2); *(v1+3)= *(v2+3);}
index 4bcacae9fc5c7adab22052c5dd6a900e7f7e132c..9450b4353cf6c97a455f9678e359a6f0f3086e1a 100644 (file)
@@ -2374,6 +2374,7 @@ static void registerCompositNodes(ListBase *ntypelist)
        
        nodeRegisterType(ntypelist, &cmp_node_filter);
        nodeRegisterType(ntypelist, &cmp_node_blur);
+       nodeRegisterType(ntypelist, &cmp_node_dblur);
        nodeRegisterType(ntypelist, &cmp_node_vecblur);
        nodeRegisterType(ntypelist, &cmp_node_dilateerode);
        nodeRegisterType(ntypelist, &cmp_node_defocus);
index b5084c418848c399b5e37be44cab36221f1c9ab2..e010d8409fa8d1c0b66bf8b60e59a4a019123bec 100644 (file)
@@ -203,6 +203,12 @@ typedef struct NodeBlurData {
        int pad2;
 } NodeBlurData;
 
+typedef struct NodeDBlurData {
+       float center_x, center_y, distance, angle, spin, zoom;
+       short iter;
+       char wrap, pad;
+} NodeDBlurData;
+
 typedef struct NodeHueSat {
        float hue, sat, val;
 } NodeHueSat;
index 4b7e721ca57a80a58fa09068a5b2aafb6cb675f6..d1e04065835c9e1af6437aef731ecc71afe1f50b 100644 (file)
@@ -66,6 +66,7 @@ extern bNodeType cmp_node_normalize;
 
 extern bNodeType cmp_node_filter;
 extern bNodeType cmp_node_blur;
+extern bNodeType cmp_node_dblur;
 extern bNodeType cmp_node_vecblur;
 extern bNodeType cmp_node_dilateerode;
 extern bNodeType cmp_node_defocus;
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_directionalblur.c b/source/blender/nodes/intern/CMP_nodes/CMP_directionalblur.c
new file mode 100644 (file)
index 0000000..27f5351
--- /dev/null
@@ -0,0 +1,143 @@
+/**
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Alfredo de Greef  (eeshlo)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+static bNodeSocketType cmp_node_dblur_in[]= {
+       {       SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.f, 0.f, 1.f},
+       {       -1, 0, ""       }
+};
+
+static bNodeSocketType cmp_node_dblur_out[]= {
+       {       SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+       {       -1, 0, ""       }
+};
+
+static CompBuf *dblur(bNode *node, CompBuf *img, int iterations, int wrap,
+                 float center_x, float center_y, float dist, float angle, float spin, float zoom)
+{
+       if ((dist != 0.f) || (spin != 0.f) || (zoom != 0.f)) {
+               void (*getpix)(CompBuf*, float, float, float*) = wrap ? qd_getPixelLerpWrap : qd_getPixelLerp;
+               const float a= angle * (float)M_PI / 180.f;
+               const float itsc= 1.f / pow(2.f, (float)iterations);
+               float D;
+               float center_x_pix, center_y_pix;
+               float tx, ty;
+               float sc, rot;
+               CompBuf *tmp;
+               int i, j;
+               
+               tmp= dupalloc_compbuf(img);
+               
+               D= dist * sqrtf(img->x * img->x + img->y * img->y);
+               center_x_pix= center_x * img->x;
+               center_y_pix= center_y * img->y;
+
+               tx=  itsc * D * cos(a);
+               ty= -itsc * D * sin(a);
+               sc=  itsc * zoom;
+               rot= itsc * spin * (float)M_PI / 180.f;
+
+               /* blur the image */
+               for(i= 0; i < iterations; ++i) {
+                       const float cs= cos(rot), ss= sin(rot);
+                       const float isc= 1.f / (1.f + sc);
+                       unsigned int x, y;
+                       float col[4]= {0,0,0,0};
+
+                       for(y= 0; y < img->y; ++y) {
+                               const float v= isc * (y - center_y_pix) + ty;
+
+                               for(x= 0; x < img->x; ++x) {
+                                       const float  u= isc * (x - center_x_pix) + tx;
+                                       unsigned int p= (x + y * img->x) * img->type;
+
+                                       getpix(tmp, cs * u + ss * v + center_x_pix, cs * v - ss * u + center_y_pix, col);
+
+                                       /* mix img and transformed tmp */
+                                       for(j= 0; j < 4; ++j)
+                                               img->rect[p + j]= AVG2(img->rect[p + j], col[j]);
+                               }
+                       }
+
+                       /* copy img to tmp */
+                       if(i != (iterations - 1)) 
+                               memcpy(tmp->rect, img->rect, sizeof(float) * img->x * img->y * img->type);
+
+                       /* double transformations */
+                       tx *= 2.f, ty  *= 2.f;
+                       sc *= 2.f, rot *= 2.f;
+
+                       if(node->exec & NODE_BREAK) break;
+               }
+
+               free_compbuf(tmp);
+       }
+
+       return img;
+}
+
+static void node_composit_exec_dblur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+       NodeDBlurData *ndbd= node->storage;
+       CompBuf *new, *img= in[0]->data;
+       
+       if((img == NULL) || (out[0]->hasoutput == 0)) return;
+
+       if (img->type != CB_RGBA)
+               new = typecheck_compbuf(img, CB_RGBA);
+       else
+               new = dupalloc_compbuf(img);
+       
+       out[0]->data= dblur(node, new, ndbd->iter, ndbd->wrap, ndbd->center_x, ndbd->center_y, ndbd->distance, ndbd->angle, ndbd->spin, ndbd->zoom);
+}
+
+static void node_composit_init_dblur(bNode* node)
+{
+       NodeDBlurData *ndbd= MEM_callocN(sizeof(NodeDBlurData), "node dblur data");
+       node->storage= ndbd;
+       ndbd->center_x= 0.5;
+       ndbd->center_y= 0.5;
+}
+
+bNodeType cmp_node_dblur = {
+       /* *next,*prev */       NULL, NULL,
+       /* type code   */       CMP_NODE_DBLUR,
+       /* name        */       "Directional Blur",
+       /* width+range */       150, 120, 200,
+       /* class+opts  */       NODE_CLASS_OP_FILTER, NODE_OPTIONS,
+       /* input sock  */       cmp_node_dblur_in,
+       /* output sock */       cmp_node_dblur_out,
+       /* storage     */       "NodeDBlurData",
+       /* execfunc    */       node_composit_exec_dblur,
+       /* butfunc     */       NULL,
+       /* initfunc    */       node_composit_init_dblur,
+       /* freestoragefunc    */        node_free_standard_storage,
+       /* copystoragefunc    */        node_copy_standard_storage,
+       /* id          */       NULL
+};
index cc65b10c8e73497986d4ca933f1b7e9367b5359f..f641efacdbd996873c8f67177e16e682eb49014d 100644 (file)
@@ -1085,6 +1085,63 @@ static int node_composit_buts_blur(uiBlock *block, bNodeTree *ntree, bNode *node
        return 57;
 }
 
+static int node_composit_buts_dblur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+       if(block) {
+               NodeDBlurData *ndbd = node->storage;
+               short dy = butr->ymin + 171;
+               short dx = butr->xmax - butr->xmin;
+               short halfdx= (short)dx/2;
+
+               uiBlockBeginAlign(block);
+               uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Iterations:",
+                               butr->xmin, dy, dx, 19,
+                               &ndbd->iter, 1, 32, 10, 0, "Amount of iterations");
+               uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Wrap",
+                               butr->xmin, dy-= 19, dx, 19, 
+                               &ndbd->wrap, 0, 0, 0, 0, "Wrap blur");
+               uiBlockEndAlign(block);
+
+               dy-= 9;
+
+               uiDefBut(block, LABEL, B_NOP, "Center", butr->xmin, dy-= 19, dx, 19, NULL, 0.0f, 0.0f, 0, 0, "");
+
+               uiBlockBeginAlign(block);
+               uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "X:",
+                               butr->xmin, dy-= 19, halfdx, 19,
+                               &ndbd->center_x, 0.0f, 1.0f, 10, 0, "X center in percents");
+               uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Y:",
+                               butr->xmin+halfdx, dy, halfdx, 19,
+                               &ndbd->center_y, 0.0f, 1.0f, 10, 0, "Y center in percents");
+               uiBlockEndAlign(block);
+
+               dy-= 9;
+
+               uiBlockBeginAlign(block);
+               uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Distance:",
+                               butr->xmin, dy-= 19, dx, 19,
+                               &ndbd->distance, -1.0f, 1.0f, 10, 0, "Amount of which the image moves");
+               uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Angle:",
+                               butr->xmin, dy-= 19, dx, 19,
+                               &ndbd->angle, 0.0f, 360.0f, 1000, 0, "Angle in which the image will be moved");
+               uiBlockEndAlign(block);
+
+               dy-= 9;
+
+               uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Spin:",
+                               butr->xmin, dy-= 19, dx, 19,
+                               &ndbd->spin, -360.0f, 360.0f, 1000, 0, "Angle that is used to spin the image");
+
+               dy-= 9;
+
+               uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Zoom:",
+                               butr->xmin, dy-= 19, dx, 19,
+                               &ndbd->zoom, 0.0f, 100.0f, 100, 0, "Amount of which the image is zoomed");
+
+       }
+       return 190;
+}
+
 /* qdn: defocus node */
 static int node_composit_buts_defocus(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
 {
@@ -1334,7 +1391,6 @@ static int node_composit_buts_crop(uiBlock *block, bNodeTree *ntree, bNode *node
 {
        if(block) {
                NodeTwoXYs *ntxy= node->storage;
-               uiBut *bt;
                char elementheight = 19;
                short dx= (butr->xmax-butr->xmin)/2;
                short dy= butr->ymax - elementheight;
@@ -1350,22 +1406,22 @@ static int node_composit_buts_crop(uiBlock *block, bNodeTree *ntree, bNode *node
                dy-=elementheight;
 
                /* x1 */
-               bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "X1:",
+               uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "X1:",
                                         butr->xmin, dy, dx, elementheight,
                                         &ntxy->x1, xymin, xymax, 0, 0, "");
                /* y1 */
-               bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Y1:",
+               uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Y1:",
                                         butr->xmin+dx, dy, dx, elementheight,
                                         &ntxy->y1, xymin, xymax, 0, 0, "");
 
                dy-=elementheight;
 
                /* x2 */
-               bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "X2:",
+               uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "X2:",
                                         butr->xmin, dy, dx, elementheight,
                                         &ntxy->x2, xymin, xymax, 0, 0, "");
                /* y2 */
-               bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Y2:",
+               uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Y2:",
                                         butr->xmin+dx, dy, dx, elementheight,
                                         &ntxy->y2, xymin, xymax, 0, 0, "");
 
@@ -1808,6 +1864,9 @@ static void node_composit_set_butfunc(bNodeType *ntype)
                case CMP_NODE_BLUR:
                        ntype->butfunc= node_composit_buts_blur;
                        break;
+               case CMP_NODE_DBLUR:
+                       ntype->butfunc= node_composit_buts_dblur;
+                       break;
                /* qdn: defocus node */
                case CMP_NODE_DEFOCUS:
                        ntype->butfunc = node_composit_buts_defocus;