Defocus Composite Node, by Alfredo de Greef
authorTon Roosendaal <ton@blender.org>
Thu, 21 Dec 2006 18:11:07 +0000 (18:11 +0000)
committerTon Roosendaal <ton@blender.org>
Thu, 21 Dec 2006 18:11:07 +0000 (18:11 +0000)
Log:
http://www.blender3d.org/cms/Composite__Defocus.836.0.html

An incredible quality composite effect, might be slow but worth waiting
for!

12 files changed:
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/intern/ipo.c
source/blender/blenkernel/intern/node.c
source/blender/blenkernel/intern/node_composite.c
source/blender/makesdna/DNA_camera_types.h
source/blender/makesdna/DNA_node_types.h
source/blender/render/intern/source/texture.c
source/blender/src/buttons_editing.c
source/blender/src/drawnode.c
source/blender/src/drawobject.c
source/blender/src/editipo.c
source/blender/src/toets.c

index b69bad1fbfdedc1048b681751af0f48a4609f742..ab4d5b70e6ee620a512237404ca63c19eaf444c5 100644 (file)
@@ -245,6 +245,7 @@ void                        set_node_shader_lamp_loop(void (*lamp_loop_func)(struct ShadeInput *, str
 #define CMP_NODE_INDEX_MASK            241
 #define CMP_NODE_MAP_UV                        242
 #define CMP_NODE_ID_MASK               243
+#define CMP_NODE_DEFOCUS               244
 
 /* filter types */
 
index 009fca69ceb6865b6e9f97d59ee0cc6ef3f3ff0e..ec3f38d67f73907eaf2f0f65278d773a0e448728 100644 (file)
@@ -164,6 +164,7 @@ int la_ar[LA_TOTIPO]= {
 };
 
 /* yafray: aperture & focal distance curves added */
+/* qdn: FDIST now available to Blender as well for defocus node */
 int cam_ar[CAM_TOTIPO]= {
        CAM_LENS, CAM_STA, CAM_END, CAM_YF_APERT, CAM_YF_FDIST
 };
index 59dcccc1f8d42338cfa59a1a0cf6840479380f77..d5fd43ac5ca40c9cd2d17a070228a515a988e1ca 100644 (file)
@@ -804,6 +804,21 @@ bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup)
                        node->storage= add_mapping();
                else if(type==CMP_NODE_BLUR)
                        node->storage= MEM_callocN(sizeof(NodeBlurData), "node blur data");
+               else if(type==CMP_NODE_DEFOCUS) {
+                       /* qdn: defocus node */
+                       NodeDefocus *nbd = MEM_callocN(sizeof(NodeDefocus), "node defocus data");
+                       nbd->bktype = 0;
+                       nbd->rotation = 0.f;
+                       nbd->preview = 1;
+                       nbd->gamco = 0;
+                       nbd->samples = 16;
+                       nbd->fstop = 128.f;
+                       nbd->maxblur = 0;
+                       nbd->bthresh = 1.f;
+                       nbd->scale = 1.f;
+                       nbd->no_zbuf = 1;
+                       node->storage = nbd;
+               }
                else if(type==CMP_NODE_VECBLUR) {
                        NodeBlurData *nbd= MEM_callocN(sizeof(NodeBlurData), "node blur data");
                        node->storage= nbd;
index 9030b072b9d81dff2a1084e9490f8167e548c22f..c21c2633698eb71248dad3e2dc087007eb6971d6 100644 (file)
 
 #include "MEM_guardedalloc.h"
 
+#include "DNA_camera_types.h" /* qdn: defocus node, need camera info */
 #include "DNA_ID.h"
 #include "DNA_image_types.h"
 #include "DNA_node_types.h"
+#include "DNA_object_types.h"
 #include "DNA_material_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_texture_types.h"
@@ -52,6 +54,7 @@
 
 #include "BLI_arithb.h"
 #include "BLI_blenlib.h"
+#include "BLI_rand.h"
 #include "BLI_threads.h"
 
 #include "IMB_imbuf_types.h"
@@ -2883,7 +2886,7 @@ static void bokeh_single_image(CompBuf *new, CompBuf *img, float fac, NodeBlurDa
                        float fi= (float)i/radxf;
                        float dist= sqrt(fj*fj + fi*fi);
                        
-//                     *dgauss= hexagon_filter(fi, fj);
+               //*dgauss= hexagon_filter(fi, fj);
                        *dgauss= RE_filter_value(nbd->filtertype, 2.0f*dist - 1.0f);
 
                        val+= *dgauss;
@@ -3133,6 +3136,758 @@ static bNodeType cmp_node_blur= {
        
 };
 
+/* ************ qdn: Defocus node ****************** */
+static bNodeSocketType cmp_node_defocus_in[]= {
+       {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+       {       SOCK_VALUE, 1, "Z",                     0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+       {       -1, 0, ""       }
+};
+static bNodeSocketType cmp_node_defocus_out[]= {
+       {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+       {       -1, 0, ""       }
+};
+
+
+// line coefs for point sampling & scancon. data.
+typedef struct BokehCoeffs {
+       float x0, y0, dx, dy;
+       float ls_x, ls_y;
+       float min_x, min_y, max_x, max_y;
+} BokehCoeffs;
+
+// returns array of BokehCoeffs
+// returns length of array in 'len_bkh',
+// radius squared of inscribed disk in 'inradsq', needed in getWeight() test,
+// BKH[8] is the data returned for the bokeh shape & bkh_b[4] is it's 2d bound
+static void makeBokeh(char bktype, char ro, int* len_bkh, float* inradsq, BokehCoeffs BKH[8], float bkh_b[4])
+{
+       float x0, x1, y0, y1, dx, dy, iDxy, w = ro*M_PI/180.f;
+       float wi = (360.f/bktype)*M_PI/180.f;
+       int i, ov, nv;
+       
+       // bktype must be at least 3 & <= 8
+       bktype = (bktype<3) ? 3 : ((bktype>8) ? 8 : bktype);
+       *len_bkh = bktype;
+       *inradsq = -1.f;
+
+       for (i=0; i<(*len_bkh); i++) {
+               x0 = cos(w);
+               y0 = sin(w);
+               w += wi;
+               x1 = cos(w);
+               y1 = sin(w);
+               if ((*inradsq)<0.f) {
+                       // radius squared of inscribed disk
+                       float idx=(x0+x1)*0.5f, idy=(y0+y1)*0.5f;
+                       *inradsq = idx*idx + idy*idy;
+               }
+               BKH[i].x0 = x0;
+               BKH[i].y0 = y0;
+               dx = x1-x0, dy = y1-y0;
+               iDxy = 1.f / sqrt(dx*dx + dy*dy);
+               dx *= iDxy;
+               dy *= iDxy;
+               BKH[i].dx = dx;
+               BKH[i].dy = dy;
+       }
+
+       // precalc scanconversion data
+       // bokeh bound, not transformed, for scanconvert
+       bkh_b[0] = bkh_b[2] = 1e10f;    // xmin/ymin
+       bkh_b[1] = bkh_b[3] = -1e10f;   // xmax/ymax
+       ov = (*len_bkh) - 1;
+       for (nv=0; nv<(*len_bkh); nv++) {
+               bkh_b[0] = MIN2(bkh_b[0], BKH[nv].x0);  // xmin
+               bkh_b[1] = MAX2(bkh_b[1], BKH[nv].x0);  // xmax
+               bkh_b[2] = MIN2(bkh_b[2], BKH[nv].y0);  // ymin
+               bkh_b[3] = MAX2(bkh_b[3], BKH[nv].y0);  // ymax
+               BKH[nv].min_x = MIN2(BKH[ov].x0, BKH[nv].x0);
+               BKH[nv].max_x = MAX2(BKH[ov].x0, BKH[nv].x0);
+               BKH[nv].min_y = MIN2(BKH[ov].y0, BKH[nv].y0);
+               BKH[nv].max_y = MAX2(BKH[ov].y0, BKH[nv].y0);
+               dy = BKH[nv].y0 - BKH[ov].y0;
+               BKH[nv].ls_x = (BKH[nv].x0 - BKH[ov].x0) / ((dy==0.f) ? 1.f : dy);
+               BKH[nv].ls_y = (BKH[nv].ls_x==0.f) ? 1.f : (1.f/BKH[nv].ls_x);
+               ov = nv;
+       }
+}
+
+// test if u/v inside shape & returns weight value
+static float getWeight(BokehCoeffs* BKH, int len_bkh, float u, float v, float rad, float inradsq)
+{
+       BokehCoeffs* bc = BKH;
+       float cdist, irad = (rad==0.f) ? 1.f : (1.f/rad);
+       u *= irad;
+       v *= irad;
+       // early out test1: if point outside outer unit disk, it cannot be inside shape
+       cdist = u*u + v*v;
+       if (cdist>1.f) return 0.f;
+       
+       // early out test2: if point inside or on inner disk, point must be inside shape
+       if (cdist<=inradsq) return 1.f;
+       
+       while (len_bkh--) {
+               if ((bc->dy*(u - bc->x0) - bc->dx*(v - bc->y0)) > 0.f) return 0.f;
+               bc++;
+       }
+       return 1.f;
+}
+
+// QMC.seq. for sampling, A.Keller, EMS
+static float RI_vdC(unsigned int bits, unsigned int r)
+{
+       bits = ( bits << 16) | ( bits >> 16);
+       bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8);
+       bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4);
+       bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2);
+       bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1);
+       bits ^= r;
+       return (float)((double)bits / 4294967296.0);
+}
+
+// single channel IIR gaussian filtering
+// much faster than anything else, constant time independent of width
+// should extend to multichannel and make this a node, could be useful
+static void IIR_gauss(CompBuf* buf, float sigma)
+{
+       double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3];
+       float *X, *Y, *W;
+       int i, x, y, sz;
+
+       // single channel only for now
+       if (buf->type != CB_VAL) return;
+
+       // <0.5 not valid, though can have a possibly useful sort of sharpening effect
+       if (sigma < 0.5) return;
+       
+       // see "Recursive Gabor Filtering" by Young/VanVliet
+       // all factors here in double.prec. Required, because for single.prec it seems to blow up if sigma > ~200
+       if (sigma >= 3.556)
+               q = 0.9804*(sigma - 3.556) + 2.5091;
+       else // sigma >= 0.5
+               q = (0.0561*sigma + 0.5784)*sigma - 0.2568;
+       q2 = q*q;
+       sc = (1.1668 + q)*(3.203729649  + (2.21566 + q)*q);
+       // no gabor filtering here, so no complex multiplies, just the regular coefs.
+       // all negated here, so as not to have to recalc Triggs/Sdika matrix
+       cf[1] = q*(5.788961737 + (6.76492 + 3.0*q)*q)/ sc;
+       cf[2] = -q2*(3.38246 + 3.0*q)/sc;
+       // 0 & 3 unchanged
+       cf[3] = q2*q/sc;
+       cf[0] = 1.0 - cf[1] - cf[2] - cf[3];
+
+       // Triggs/Sdika border corrections,
+       // it seems to work, not entirely sure if it is actually totally correct,
+       // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark),
+       // found one other implementation by Cristoph Lampert,
+       // but neither seem to be quite the same, result seems to be ok sofar anyway.
+       // Extra scale factor here to not have to do it in filter,
+       // though maybe this had something to with the precision errors
+       sc = cf[0]/((1.0 + cf[1] - cf[2] + cf[3])*(1.0 - cf[1] - cf[2] - cf[3])*(1.0 + cf[2] + (cf[1] - cf[3])*cf[3]));
+       tsM[0] = sc*(-cf[3]*cf[1] + 1.0 - cf[3]*cf[3] - cf[2]);
+       tsM[1] = sc*((cf[3] + cf[1])*(cf[2] + cf[3]*cf[1]));
+       tsM[2] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
+       tsM[3] = sc*(cf[1] + cf[3]*cf[2]);
+       tsM[4] = sc*(-(cf[2] - 1.0)*(cf[2] + cf[3]*cf[1]));
+       tsM[5] = sc*(-(cf[3]*cf[1] + cf[3]*cf[3] + cf[2] - 1.0)*cf[3]);
+       tsM[6] = sc*(cf[3]*cf[1] + cf[2] + cf[1]*cf[1] - cf[2]*cf[2]);
+       tsM[7] = sc*(cf[1]*cf[2] + cf[3]*cf[2]*cf[2] - cf[1]*cf[3]*cf[3] - cf[3]*cf[3]*cf[3] - cf[3]*cf[2] + cf[3]);
+       tsM[8] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
+
+#define YVV(L)\
+{\
+       W[0] = cf[0]*X[0] + cf[1]*X[0] + cf[2]*X[0] + cf[3]*X[0];\
+       W[1] = cf[0]*X[1] + cf[1]*W[0] + cf[2]*X[0] + cf[3]*X[0];\
+       W[2] = cf[0]*X[2] + cf[1]*W[1] + cf[2]*W[0] + cf[3]*X[0];\
+       for (i=3; i<L; i++)\
+               W[i] = cf[0]*X[i] + cf[1]*W[i-1] + cf[2]*W[i-2] + cf[3]*W[i-3];\
+       tsu[0] = W[L-1] - X[L-1];\
+       tsu[1] = W[L-2] - X[L-1];\
+       tsu[2] = W[L-3] - X[L-1];\
+       tsv[0] = tsM[0]*tsu[0] + tsM[1]*tsu[1] + tsM[2]*tsu[2] + X[L-1];\
+       tsv[1] = tsM[3]*tsu[0] + tsM[4]*tsu[1] + tsM[5]*tsu[2] + X[L-1];\
+       tsv[2] = tsM[6]*tsu[0] + tsM[7]*tsu[1] + tsM[8]*tsu[2] + X[L-1];\
+       Y[L-1] = cf[0]*W[L-1] + cf[1]*tsv[0] + cf[2]*tsv[1] + cf[3]*tsv[2];\
+       Y[L-2] = cf[0]*W[L-2] + cf[1]*Y[L-1] + cf[2]*tsv[0] + cf[3]*tsv[1];\
+       Y[L-3] = cf[0]*W[L-3] + cf[1]*Y[L-2] + cf[2]*Y[L-1] + cf[3]*tsv[0];\
+       for (i=L-4; i>=0; i--)\
+               Y[i] = cf[0]*W[i] + cf[1]*Y[i+1] + cf[2]*Y[i+2] + cf[3]*Y[i+3];\
+}
+
+       // intermediate buffers
+       sz = MAX2(buf->x, buf->y);
+       Y = MEM_callocN(sz*sizeof(float), "IIR_gauss Y buf");
+       W = MEM_callocN(sz*sizeof(float), "IIR_gauss W buf");
+       // H
+       for (y=0; y<buf->y; y++) {
+               X = &buf->rect[y*buf->x];
+               YVV(buf->x);
+               memcpy(X, Y, sizeof(float)*buf->x);
+       }
+       // V
+       X = MEM_callocN(buf->y*sizeof(float), "IIR_gauss X buf");
+       for (x=0; x<buf->x; x++) {
+               for (y=0; y<buf->y; y++)
+                       X[y] = buf->rect[x + y*buf->x];
+               YVV(buf->y);
+               for (y=0; y<buf->y; y++)
+                       buf->rect[x + y*buf->x] = Y[y];
+       }
+       MEM_freeN(X);
+
+       MEM_freeN(W);
+       MEM_freeN(Y);
+#undef YVV
+}
+
+static void defocus_blur(CompBuf* new, CompBuf* img, CompBuf* zbuf, float inpval, NodeDefocus* nqd)
+{
+       CompBuf *wts;   // weights buffer
+       CompBuf *crad;  // CoC radius buffer
+       BokehCoeffs BKH[8];     // bokeh shape data, here never > 8 pts.
+       float bkh_b[4] = {0};   // shape 2D bound
+       unsigned int p, px, p4, zp, cp, cp4;
+       float *ctcol, u, v, iZ, ct_crad, bcrad, lwt, wt=0, cR2=0;
+       float dof_sp, maxfgc, nmaxc, scf, bk_hn_theta=0, inradsq=0;
+       float cam_fdist=1, cam_invfdist=1, cam_lens=35;
+       int x, y, sx, sy, len_bkh=0;
+       float aspect, aperture;
+       int minsz;
+       
+       // get some required params from the current scene camera
+       Object* camob = G.scene->camera;
+       if (camob->type==OB_CAMERA) {
+               Camera* cam = (Camera*)camob->data;
+               cam_lens = cam->lens;
+               cam_fdist = (cam->YF_dofdist==0.f) ? 1e10f : cam->YF_dofdist;
+               cam_invfdist = 1.f/cam_fdist;
+       }
+
+       // guess work here.. best match with raytraced result
+       minsz = MIN2(img->x, img->y);
+       dof_sp = (float)minsz / (16.f / cam_lens);      // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov);
+       
+       // aperture
+       aspect = (img->x > img->y) ? (img->y / (float)img->x) : (img->x / (float)img->y);
+       aperture = 0.5f*(cam_lens / (aspect*32.f)) / nqd->fstop;
+       
+       // if not disk, make bokeh coefficients and other needed data
+       if (nqd->bktype!=0) {
+               makeBokeh(nqd->bktype, nqd->rotation, &len_bkh, &inradsq, BKH, bkh_b);
+               bk_hn_theta = 0.5 * nqd->bktype * sin(2.0 * M_PI / nqd->bktype);        // weight factor
+       }
+       
+       // accumulated weights
+       wts = alloc_compbuf(img->x, img->y, CB_VAL, 1);
+       // CoC radius buffer
+       crad = alloc_compbuf(img->x, img->y, CB_VAL, 1);
+
+       // if 'no_zbuf' flag set (which is always set if input is not an image),
+       // values are instead interpreted directly as blur radius values
+       if (nqd->no_zbuf) {
+               for (p=0; p<(unsigned int)(img->x*img->y); p++) {
+                       crad->rect[p] = zbuf ? (zbuf->rect[p]*nqd->scale) : inpval;
+                       if (crad->rect[p] < 0.01f) crad->rect[p] = 0.01f;
+                       // if maxblur!=0, limit maximum
+                       if (nqd->maxblur != 0.f) crad->rect[p] = MIN2(crad->rect[p], nqd->maxblur);
+               }
+       }
+       else {
+               // actual zbuffer.
+               // separate foreground from background CoC's
+               // then blur background and blend in again with foreground,
+               // improves the 'blurred foreground overlapping in-focus midground' sharp boundary problem.
+               // wts buffer here used for blendmask
+               maxfgc = 0.f; // maximum foreground CoC radius
+               for (y=0; y<img->y; y++) {
+                       p = y * img->x;
+                       for (x=0; x<img->x; x++) {
+                               px = p + x;
+                               iZ = (zbuf->rect[px]==0.f) ? 0.f : (1.f/zbuf->rect[px]);
+                               crad->rect[px] = 0.5f*(aperture*(dof_sp*(cam_invfdist - iZ) - 1.f));
+                               if (crad->rect[px] <= 0.f) {
+                                       wts->rect[px] = 1.f;
+                                       crad->rect[px] = -crad->rect[px];
+                                       if (crad->rect[px] > maxfgc) maxfgc = crad->rect[px];
+                               }
+                               else crad->rect[px] = wts->rect[px] = 0;
+                       }
+               }
+               
+               // fast blur...
+               IIR_gauss(crad, 2.f*maxfgc);
+               IIR_gauss(wts, 2.f*maxfgc);
+               
+               // find new maximum to scale it back to original
+               // (could skip this, not strictly necessary, in general, difference is quite small, but just in case...)
+               nmaxc = 0;
+               for (p=0; p<(img->x*img->y); p++)
+                       if (crad->rect[p] > nmaxc) nmaxc = crad->rect[p];
+               // rescale factor
+               scf = (nmaxc==0.f) ? 1.f: (maxfgc / nmaxc);
+               
+               // and blend...
+               for (y=0; y<img->y; y++) {
+                       p = y*img->x;
+                       for (x=0; x<img->x; x++) {
+                               px = p + x;
+                               iZ = (zbuf->rect[px]==0.f) ? 0.f : (1.f/zbuf->rect[px]);
+                               bcrad = 0.5f*fabs(aperture*(dof_sp*(cam_invfdist - iZ) - 1.f));
+                               // scale crad back to original maximum and blend
+                               crad->rect[px] = bcrad + wts->rect[px]*(scf*crad->rect[px] - bcrad);
+                               if (crad->rect[px] < 0.01f) crad->rect[px] = 0.01f;
+                               // if maxblur!=0, limit maximum
+                               if (nqd->maxblur != 0.f) crad->rect[px] = MIN2(crad->rect[px], nqd->maxblur);
+                               // clear weights for next part
+                               wts->rect[px] = 0.f;
+                       }
+               }
+               
+       }
+
+       //------------------------------------------------------------------
+       // main loop
+       for (y=0; y<img->y; y++) {
+               // some sort of visual feedback would be nice, or at least this text in the renderwin header
+               // but for now just print some info in the console every 8 scanlines.
+               if (((y & 7)==0) || (y==(img->y-1))) {
+                       printf("\rdefocus: Processing Line %d of %d ... ", y+1, img->y);
+                       fflush(stdout);
+               }
+               zp = y * img->x;
+               for (x=0; x<img->x; x++) {
+                       cp = zp + x;
+                       cp4 = cp * img->type;
+
+                       // Circle of Confusion radius for current pixel
+                       cR2 = ct_crad = crad->rect[cp];
+                       cR2 *= cR2;
+                       
+                       // pixel color
+                       ctcol = &img->rect[cp4];
+                       
+                       if (!nqd->preview) {
+                               int xs, xe, ys, ye;
+                               float lwt, wtcol[4] = {0}, aacol[4] = {0};
+
+                               // shape weight
+                               if (nqd->bktype==0)     // disk
+                                       wt = 1.f/((float)M_PI*cR2);
+                               else
+                                       wt = 1.f/(cR2*bk_hn_theta);
+
+                               // weighted color
+                               wtcol[0] = wt*ctcol[0];
+                               if (new->type != CB_VAL) {
+                                       wtcol[1] = wt*ctcol[1];
+                                       wtcol[2] = wt*ctcol[2];
+                                       wtcol[3] = wt*ctcol[3];
+                               }
+
+                               // macro for background blur overlap test
+                               // unfortunately, since this is done per pixel,
+                               // it has a very significant negative impact on processing time...
+                               // (eg. aa disk blur without test: 112 sec, vs with test: 176 sec...)
+                               // iff center blur radius > threshold
+                               // and if overlap pixel in focus, do nothing, else add color/weigbt
+                               // (threshold constant is dependant on amount of blur)
+                               #define TESTBG1(c, w) {\
+                                       if (ct_crad > nqd->bthresh) {\
+                                               if (crad->rect[p] > nqd->bthresh) {\
+                                                       new->rect[p] += c[0];\
+                                                       wts->rect[p] += w;\
+                                               }\
+                                       }\
+                                       else {\
+                                               new->rect[p] += c[0];\
+                                               wts->rect[p] += w;\
+                                       }\
+                               }
+                               #define TESTBG4(c, w) {\
+                                       if (ct_crad > nqd->bthresh) {\
+                                               if (crad->rect[p] > nqd->bthresh) {\
+                                                       new->rect[p4] += c[0];\
+                                                       new->rect[p4+1] += c[1];\
+                                                       new->rect[p4+2] += c[2];\
+                                                       new->rect[p4+3] += c[3];\
+                                                       wts->rect[p] += w;\
+                                               }\
+                                       }\
+                                       else {\
+                                               new->rect[p4] += c[0];\
+                                               new->rect[p4+1] += c[1];\
+                                               new->rect[p4+2] += c[2];\
+                                               new->rect[p4+3] += c[3];\
+                                               wts->rect[p] += w;\
+                                       }\
+                               }
+                               if (nqd->bktype == 0) {
+                                       // Disk
+                                       int _x, i, j, di;
+                                       float Dj, T;
+                                       // AA pixel
+                                       #define AAPIX(a, b) {\
+                                               int _ny = b;\
+                                               if ((_ny >= 0) && (_ny < new->y)) {\
+                                                       int _nx = a;\
+                                                       if ((_nx >=0) && (_nx < new->x)) {\
+                                                               p = _ny*new->x + _nx;\
+                                                               if (new->type==CB_VAL) {\
+                                                                       TESTBG1(aacol, lwt);\
+                                                               }\
+                                                               else {\
+                                                                       p4 = p * new->type;\
+                                                                       TESTBG4(aacol, lwt);\
+                                                               }\
+                                                       }\
+                                               }\
+                                       }
+                                       // circle scanline
+                                       #define CSCAN(a, b) {\
+                                               int _ny = y + b;\
+                                               if ((_ny >= 0) && (_ny < new->y)) {\
+                                                       xs = x - a + 1;\
+                                                       if (xs < 0) xs = 0;\
+                                                       xe = x + a;\
+                                                       if (xe > new->x) xe = new->x;\
+                                                       p = _ny*new->x + xs;\
+                                                       if (new->type==CB_VAL) {\
+                                                               for (_x=xs; _x<xe; _x++, p++) TESTBG1(wtcol, wt);\
+                                                       }\
+                                                       else {\
+                                                               p4 = p * new->type;\
+                                                               for (_x=xs; _x<xe; _x++, p++, p4+=new->type) TESTBG4(wtcol, wt);\
+                                                       }\
+                                               }\
+                                       }
+                                       i = ceil(ct_crad);
+                                       j = 0;
+                                       T = 0;
+                                       while (i > j) {
+                                               Dj = sqrt(cR2 - j*j);
+                                               Dj -= floor(Dj);
+                                               di = 0;
+                                               if (Dj > T) { i--;  di = 1; }
+                                               T = Dj;
+                                               aacol[0] = wtcol[0]*Dj;
+                                               if (new->type != CB_VAL) {
+                                                       aacol[1] = wtcol[1]*Dj;
+                                                       aacol[2] = wtcol[2]*Dj;
+                                                       aacol[3] = wtcol[3]*Dj;
+                                               }
+                                               lwt = wt*Dj;
+                                               if (i!=j) {
+                                                       // outer pixels
+                                                       AAPIX(x+j, y+i);
+                                                       AAPIX(x+j, y-i);
+                                                       if (j) {
+                                                               AAPIX(x-j, y+i); // BL
+                                                               AAPIX(x-j, y-i); // TL
+                                                       }
+                                                       if (di) { // only when i changed, interior of outer section
+                                                               CSCAN(j, i); // bottom
+                                                               CSCAN(j, -i); // top
+                                                       }
+                                               }
+                                               // lower mid section
+                                               AAPIX(x+i, y+j);
+                                               if (i) AAPIX(x-i, y+j);
+                                               CSCAN(i, j);
+                                               // upper mid section
+                                               if (j) {
+                                                       AAPIX(x+i, y-j);
+                                                       if (i) AAPIX(x-i, y-j);
+                                                       CSCAN(i, -j);
+                                               }
+                                               j++;
+                                       }
+                                       #undef CSCAN
+                                       #undef AAPIX
+                               }
+                               else {
+                                       // n-agonal
+                                       int ov, nv;
+                                       float mind, maxd, lwt;
+                                       ys = MAX2((int)floor(bkh_b[2]*ct_crad + y), 0);
+                                       ye = MIN2((int)ceil(bkh_b[3]*ct_crad + y), new->y - 1);
+                                       for (sy=ys; sy<=ye; sy++) {
+                                               float fxs = 1e10f, fxe = -1e10f;
+                                               float yf = (sy - y)/ct_crad;
+                                               int found = 0;
+                                               ov = len_bkh - 1;
+                                               mind = maxd = 0;
+                                               for (nv=0; nv<len_bkh; nv++) {
+                                                       if ((BKH[nv].max_y >= yf) && (BKH[nv].min_y <= yf)) {
+                                                               float tx = BKH[ov].x0 + BKH[nv].ls_x*(yf - BKH[ov].y0);
+                                                               if (tx < fxs) { fxs = tx;  mind = BKH[nv].ls_x; }
+                                                               if (tx > fxe) { fxe = tx;  maxd = BKH[nv].ls_x; }
+                                                               if (++found == 2) break;
+                                                       }
+                                                       ov = nv;
+                                               }
+                                               if (found) {
+                                                       fxs = fxs*ct_crad + x;
+                                                       fxe = fxe*ct_crad + x;
+                                                       xs = (int)floor(fxs), xe = (int)ceil(fxe);
+                                                       // AA hack for first and last x pixel, near vertical edges only
+                                                       if (fabs(mind) <= 1.f) {
+                                                               if ((xs >= 0) && (xs < new->x)) {
+                                                                       lwt = 1.f-(fxs - xs);
+                                                                       aacol[0] = wtcol[0]*lwt;
+                                                                       p = xs + sy*new->x;
+                                                                       if (new->type==CB_VAL) {
+                                                                               lwt *= wt;
+                                                                               TESTBG1(aacol, lwt);
+                                                                       }
+                                                                       else {
+                                                                               p4 = p * new->type;
+                                                                               aacol[1] = wtcol[1]*lwt;
+                                                                               aacol[2] = wtcol[2]*lwt;
+                                                                               aacol[3] = wtcol[3]*lwt;
+                                                                               lwt *= wt;
+                                                                               TESTBG4(aacol, lwt);
+                                                                       }
+                                                               }
+                                                       }
+                                                       if (fabs(maxd) <= 1.f) {
+                                                               if ((xe >= 0) && (xe < new->x)) {
+                                                                       lwt = 1.f-(xe - fxe);
+                                                                       aacol[0] = wtcol[0]*lwt;
+                                                                       p = xe + sy*new->x;
+                                                                       if (new->type==CB_VAL) {
+                                                                               lwt *= wt;
+                                                                               TESTBG1(aacol, lwt);
+                                                                       }
+                                                                       else {
+                                                                               p4 = p * new->type;
+                                                                               aacol[1] = wtcol[1]*lwt;
+                                                                               aacol[2] = wtcol[2]*lwt;
+                                                                               aacol[3] = wtcol[3]*lwt;
+                                                                               lwt *= wt;
+                                                                               TESTBG4(aacol, lwt);
+                                                                       }
+                                                               }
+                                                       }
+                                                       xs = MAX2(xs+1, 0);
+                                                       xe = MIN2(xe, new->x);
+                                                       // remaining interior scanline
+                                                       p = sy*new->x + xs;
+                                                       if (new->type==CB_VAL) {
+                                                               for (sx=xs; sx<xe; sx++, p++) TESTBG1(wtcol, wt);
+                                                       }
+                                                       else {
+                                                               p4 = p * new->type;
+                                                               for (sx=xs; sx<xe; sx++, p++, p4+=new->type) TESTBG4(wtcol, wt);
+                                                       }
+                                               }
+                                       }
+
+                                       // now traverse in opposite direction, y scanlines,
+                                       // but this time only draw the near horizontal edges,
+                                       // applying same AA hack as above
+                                       xs = MAX2((int)floor(bkh_b[0]*ct_crad + x), 0);
+                                       xe = MIN2((int)ceil(bkh_b[1]*ct_crad + x), img->x - 1);
+                                       for (sx=xs; sx<=xe; sx++) {
+                                               float xf = (sx - x)/ct_crad;
+                                               float fys = 1e10f, fye = -1e10f;
+                                               int found = 0;
+                                               ov = len_bkh - 1;
+                                               mind = maxd = 0;
+                                               for (nv=0; nv<len_bkh; nv++) {
+                                                       if ((BKH[nv].max_x >= xf) && (BKH[nv].min_x <= xf)) {
+                                                               float ty = BKH[ov].y0 + BKH[nv].ls_y*(xf - BKH[ov].x0);
+                                                               if (ty < fys) { fys = ty;  mind = BKH[nv].ls_y; }
+                                                               if (ty > fye) { fye = ty;  maxd = BKH[nv].ls_y; }
+                                                               if (++found == 2) break;
+                                                       }
+                                                       ov = nv;
+                                               }
+                                               if (found) {
+                                                       fys = fys*ct_crad + y;
+                                                       fye = fye*ct_crad + y;
+                                                       // near horizontal edges only, line slope <= 1
+                                                       if (fabs(mind) <= 1.f) {
+                                                               int iys = (int)floor(fys);
+                                                               if ((iys >= 0) && (iys < new->y)) {
+                                                                       lwt = 1.f - (fys - iys);
+                                                                       aacol[0] = wtcol[0]*lwt;
+                                                                       p = sx + iys*new->x;
+                                                                       if (new->type==CB_VAL) {
+                                                                               lwt *= wt;
+                                                                               TESTBG1(aacol, lwt);
+                                                                       }
+                                                                       else {
+                                                                               p4 = p * new->type;
+                                                                               aacol[1] = wtcol[1]*lwt;
+                                                                               aacol[2] = wtcol[2]*lwt;
+                                                                               aacol[3] = wtcol[3]*lwt;
+                                                                               lwt *= wt;
+                                                                               TESTBG4(aacol, lwt);
+                                                                       }
+                                                               }
+                                                       }
+                                                       if (fabs(maxd) <= 1.f) {
+                                                               int iye = ceil(fye);
+                                                               if ((iye >= 0) && (iye < new->y)) {
+                                                                       lwt = 1.f - (iye - fye);
+                                                                       aacol[0] = wtcol[0]*lwt;
+                                                                       p = sx + iye*new->x;
+                                                                       if (new->type==CB_VAL) {
+                                                                               lwt *= wt;
+                                                                               TESTBG1(aacol, lwt);
+                                                                       }
+                                                                       else {
+                                                                               p4 = p * new->type;
+                                                                               aacol[1] = wtcol[1]*lwt;
+                                                                               aacol[2] = wtcol[2]*lwt;
+                                                                               aacol[3] = wtcol[3]*lwt;
+                                                                               lwt *= wt;
+                                                                               TESTBG4(aacol, lwt);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                               }
+                               #undef TESTBG4
+                               #undef TESTBG1
+
+                       }
+                       else {
+                               // sampled, simple rejection sampling here, good enough
+                               unsigned int maxsam, s, ui = BLI_rand()*BLI_rand();
+                               float cpr = BLI_frand();
+                               if (nqd->no_zbuf)
+                                       maxsam = nqd->samples;  // no zbuffer input, use sample value directly
+                               else {
+                                 // depth adaptive sampling hack, the more out of focus, the more samples taken, 16 minimum.
+                                       maxsam = (int)(0.5f + nqd->samples*(1.f-(float)exp(-fabs(zbuf->rect[cp] - cam_fdist))));
+                                       if (maxsam < 16) maxsam = 16;
+                               }
+                               float wcor = 1.f/(float)maxsam;
+                               for (s=0; s<maxsam; ++s) {
+                                       u = ct_crad*(2.f*RI_vdC(s, ui) - 1.f);
+                                       v = ct_crad*(2.f*(s + cpr)/(float)maxsam - 1.f);
+                                       // should use extra 0.5 offset here, but will cause gap around focal point...
+                                       sx = (int)(x + u), sy = (int)(y + v);
+                                       if ((sx<0) || (sx >= new->x) || (sy<0) || (sy >= new->y)) continue;
+                                       p = sx + sy*new->x;
+                                       p4 = p * new->type;
+                                       if (nqd->bktype==0)     // Disk
+                                               lwt = ((u*u + v*v)<=cR2) ? wcor : 0.f;
+                                       else    // AA not needed here
+                                               lwt = wcor * getWeight(BKH, len_bkh, u, v, ct_crad, inradsq);
+                                       // prevent background bleeding onto in-focus pixels, user-option
+                                       if (ct_crad > nqd->bthresh) {  // if center blur > threshold
+                                               if (crad->rect[p] > nqd->bthresh) { // if overlap pixel in focus, do nothing, else add color/weigbt
+                                                       new->rect[p4] += ctcol[0] * lwt;
+                                                       if (new->type != CB_VAL) {
+                                                               new->rect[p4+1] += ctcol[1] * lwt;
+                                                               new->rect[p4+2] += ctcol[2] * lwt;
+                                                               new->rect[p4+3] += ctcol[3] * lwt;
+                                                       }
+                                                       wts->rect[p] += lwt;
+                                               }
+                                       }
+                                       else {
+                                               new->rect[p4] += ctcol[0] * lwt;
+                                               if (new->type != CB_VAL) {
+                                                       new->rect[p4+1] += ctcol[1] * lwt;
+                                                       new->rect[p4+2] += ctcol[2] * lwt;
+                                                       new->rect[p4+3] += ctcol[3] * lwt;
+                                               }
+                                               wts->rect[p] += lwt;
+                                       }
+                               }
+                       }
+
+               }
+       }
+       
+       // finally, normalize
+       for (y=0; y<new->y; y++) {
+               p = y * new->x;
+               p4 = p * new->type;
+               for (x=0; x<new->x; x++) {
+                       float dv = (wts->rect[p]==0.f) ? 1.f : (1.f/wts->rect[p]);
+                       new->rect[p4] *= dv;
+                       if (new->type!=CB_VAL) {
+                               new->rect[p4+1] *= dv;
+                               new->rect[p4+2] *= dv;
+                               new->rect[p4+3] *= dv;
+                       }
+                       p++;
+                       p4 += new->type;
+               }
+       }
+
+       free_compbuf(crad);
+       free_compbuf(wts);
+       
+       printf("Done\n");
+}
+
+
+static void node_composit_exec_defocus(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+       CompBuf *new, *old, *zbuf_use = NULL, *img = in[0]->data, *zbuf = in[1]->data;
+       NodeDefocus* nqd = node->storage;
+       
+       if ((img==NULL) || (out[0]->hasoutput==0)) return;
+       
+       // if image not valid type or fstop==infinite (128), nothing to do, pass in to out
+       if (((img->type!=CB_RGBA) && (img->type!=CB_VAL)) || ((nqd->no_zbuf==0) && (nqd->fstop==128.f))) {
+               new = alloc_compbuf(img->x, img->y, img->type, 0);
+               new->rect = img->rect;
+               out[0]->data = new;
+               return;
+       }
+       
+       if (zbuf!=NULL) {
+               // Zbuf input, check to make sure, single channel, same size
+               // doesn't have to be actual zbuffer, but must be value type
+               if ((zbuf->x != img->x) || (zbuf->y != img->y)) {
+                       // could do a scale here instead...
+                       printf("Z input must be same size as image !\n");
+                       return;
+               }
+               zbuf_use = typecheck_compbuf(zbuf, CB_VAL);
+       }
+       else nqd->no_zbuf = 1;  // no zbuffer input
+               
+       // ok, process
+       old = img;
+       if (nqd->gamco) {
+               // gamma correct, blender func is simplified, fixed value & RGBA only, should make user param
+               old = dupalloc_compbuf(img);
+               gamma_correct_compbuf(old, 0);
+       }
+       
+       new = alloc_compbuf(old->x, old->y, old->type, 1);
+       defocus_blur(new, old, zbuf_use, in[1]->vec[0]*nqd->scale, node->storage);
+       
+       if (nqd->gamco) {
+               gamma_correct_compbuf(new, 1);
+               free_compbuf(old);
+       }
+       
+       out[0]->data = new;
+       if (zbuf_use && (zbuf_use != zbuf)) free_compbuf(zbuf_use);
+}
+
+static bNodeType cmp_node_defocus = {
+       /* type code   */       CMP_NODE_DEFOCUS,
+       /* name        */       "Defocus",
+       /* width+range */       150, 120, 200,
+       /* class+opts  */       NODE_CLASS_OP_FILTER, NODE_OPTIONS,
+       /* input sock  */       cmp_node_defocus_in,
+       /* output sock */       cmp_node_defocus_out,
+       /* storage     */       "NodeDefocus",
+       /* execfunc    */       node_composit_exec_defocus
+};
+
 /* **************** VECTOR BLUR ******************** */
 static bNodeSocketType cmp_node_vecblur_in[]= {
        {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
@@ -4652,6 +5407,7 @@ bNodeType *node_all_composit[]= {
        &cmp_node_splitviewer,
        &cmp_node_mapuv,
        &cmp_node_idmask,
+       &cmp_node_defocus,
        NULL
 };
 
index 5ea0960dd4b3c6642ab3722fd35c31d77cf1e108..8bf9d951f80f562402cf9b8139c63aeaccd4bb87 100644 (file)
@@ -53,6 +53,8 @@ typedef struct Camera {
        float shiftx, shifty;
        
        /* yafray: dof params */
+       /* qdn: yafray var 'YF_dofdist' now enabled for defocus composit node as well.
+               The name was not changed so that no other files need to be modified */
        float YF_dofdist, YF_aperture;
        short YF_bkhtype, YF_bkhbias;
        float YF_bkhrot;
index db7db374dcc4903fa6d40aa8ceeedf35034be5c4..e2eea44925d8b5a2d78260f1224ca7884d695b1d 100644 (file)
@@ -217,5 +217,11 @@ typedef struct NodeGeometry {
        char uvname[32];
 } NodeGeometry;
 
-#endif
+/* qdn: Defocus blur node */
+typedef struct NodeDefocus {
+       char bktype, rotation, preview, gamco;
+       short samples, no_zbuf;
+       float fstop, maxblur, bthresh, scale;
+} NodeDefocus;
 
+#endif
index 643b4c9338fed79d7ce24bf1a3f6519f8fb63a78..e02a1e2ae8365ccead6c5abc64b0e2bffcc17fd2 100644 (file)
@@ -1707,7 +1707,6 @@ void do_material_tex(ShadeInput *shi)
                                                }
                                                else {
                                                        float nor[3], dot;
-                                               
                                                        /* prevent bump to become negative normal */
                                                        nor[0]= Tnor*tex->norfac*texres.nor[0];
                                                        nor[1]= Tnor*tex->norfac*texres.nor[1];
index 114f97bec6774da6c944955dd55c61cf66ce7f4a..ba3cc54ecc25cbe44fedabdcca62d3dcc6f0e834 100644 (file)
@@ -2770,36 +2770,40 @@ static void editing_panel_camera_type(Object *ob, Camera *cam)
 
        uiDefBut(block, LABEL, 10, "Lens:", 10, 180, 150, 20, 0, 0.0, 0.0, 0, 0, "");
        
-if(cam->type==CAM_ORTHO) {
+       if(cam->type==CAM_ORTHO) {
                uiDefButF(block, NUM,REDRAWVIEW3D, "Scale:",
                                  10, 160, 150, 20, &cam->ortho_scale, 0.01, 1000.0, 50, 0, "Specify the ortho scaling of the used camera");
        } else {
                uiDefButF(block, NUM,REDRAWVIEW3D, "Lens:",
                                  10, 160, 150, 20, &cam->lens, 1.0, 250.0, 100, 0, "Specify the lens of the camera");
        }
-       
+
+/* qdn: focal dist. param. from yafray now enabled for Blender as well, to use with defocus composit node */
+       uiDefButF(block, NUM, REDRAWVIEW3D, "DoFDist:", 10, 140, 150, 20 /*0, 125, 150, 20*/, &cam->YF_dofdist, 0.0, 5000.0, 50, 0, "Sets distance to point of focus (enable 'Limits' to make visible in 3Dview)");
+
        uiDefButS(block, TOG, REDRAWVIEW3D, "Orthographic",
-                         10, 135, 150, 20, &cam->type, 0, 0, 0, 0, "Render orthogonally");
+                         10, 115, 150, 20, &cam->type, 0, 0, 0, 0, "Render orthogonally");
+                         //10, 135, 150, 20, &cam->type, 0, 0, 0, 0, "Render orthogonally");
        
-       uiDefBut(block, LABEL, 0, "Clipping:", 10, 110, 150, 20, 0, 0.0, 0.0, 0, 0, "");
+       uiDefBut(block, LABEL, 0, "Clipping:", 10, 90, 150, 20, 0, 0.0, 0.0, 0, 0, "");
        
        uiBlockBeginAlign(block);
        uiDefButF(block, NUM,REDRAWVIEW3D, "Start:",
-                         10, 90, 150, 20, &cam->clipsta, 0.001*grid, 100.0*grid, 10, 0, "Specify the startvalue of the the field of view");
+                         10, 70, 150, 20, &cam->clipsta, 0.001*grid, 100.0*grid, 10, 0, "Specify the startvalue of the the field of view");
        uiDefButF(block, NUM,REDRAWVIEW3D, "End:",
-                         10, 70, 150, 20, &cam->clipend, 1.0, 5000.0*grid, 100, 0, "Specify the endvalue of the the field of view");
+                         10, 50, 150, 20, &cam->clipend, 1.0, 5000.0*grid, 100, 0, "Specify the endvalue of the the field of view");
        uiBlockEndAlign(block);
                        
        uiDefButF(block, NUM,REDRAWVIEW3D, "Size:",
                          170, 25, 150, 20, &cam->drawsize, 0.1*grid, 10.0, 10, 0, "The size that the camera is displayed in the 3D View (different to the object's scale)");
 
-       uiDefBut(block, LABEL, 0, "Shift:", 10, 45, 150, 20, 0, 0.0, 0.0, 0, 0, "");
+       uiDefBut(block, LABEL, 0, "Shift:", 10, 25, 150, 20, 0, 0.0, 0.0, 0, 0, "");
                                  
        uiBlockBeginAlign(block);
        uiDefButF(block, NUM,REDRAWVIEW3D, "X:",
-               10, 25, 75, 20, &cam->shiftx, -2.0, 2.0, 1, 2, "Horizontally shifts the camera view, without changing the perspective");
+               10, 5, 75, 20, &cam->shiftx, -2.0, 2.0, 1, 2, "Horizontally shifts the camera view, without changing the perspective");
        uiDefButF(block, NUM,REDRAWVIEW3D, "Y:",
-               85, 25, 75, 20, &cam->shifty, -2.0, 2.0, 1, 2, "Vertically shifts the camera view, without changing the perspective");
+               85, 5, 75, 20, &cam->shifty, -2.0, 2.0, 1, 2, "Vertically shifts the camera view, without changing the perspective");
        uiBlockEndAlign(block);
        
        uiDefBut(block, LABEL, 0, "Show:", 170, 180, 150, 20, 0, 0.0, 0.0, 0, 0, "");
index b6af394b9f464454c55bc60e71f49519ba44378b..d0b47023a63344d5b5f0c9c68446799bb9bda394 100644 (file)
@@ -996,6 +996,60 @@ static int node_composit_buts_blur(uiBlock *block, bNodeTree *ntree, bNode *node
        return 38;
 }
 
+/* qdn: defocus node */
+static int node_composit_buts_defocus(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+       if(block) {
+               NodeDefocus *nqd = node->storage;
+               short dy = butr->ymin + 209;
+               short dx = butr->xmax - butr->xmin; 
+               char* mstr1 = "Bokeh Type%t|Octagon %x8|Heptagon %x7|Hexagon %x6|Pentagon %x5|Square %x4|Triangle %x3|Disk %x0";
+
+               uiDefBut(block, LABEL, B_NOP, "Bokeh Type", butr->xmin, dy, dx, 19, NULL, 0, 0, 0, 0, "");
+               uiDefButC(block, MENU, B_NODE_EXEC+node->nr, mstr1,
+                         butr->xmin, dy-19, dx, 19,
+                         &nqd->bktype, 0, 0, 0, 0, "Bokeh type");
+               if (nqd->bktype) { /* for some reason rotating a disk doesn't seem to work... ;) */
+                       uiDefButC(block, NUM, B_NODE_EXEC+node->nr, "Rotate:",
+                                 butr->xmin, dy-38, dx, 19,
+                                 &nqd->rotation, 0, 90, 0, 0, "Bokeh shape rotation offset in degrees");
+               }
+               uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Gamma Correct",
+                         butr->xmin, dy-57, dx, 19,
+                         &nqd->gamco, 0, 0, 0, 0, "Enable gamma correction before and after main process");
+               if (nqd->no_zbuf==0) {
+                       // only needed for zbuffer input
+                       uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "fStop:",
+                                 butr->xmin, dy-76, dx, 19,
+                                 &nqd->fstop, 0.5, 128, 10, 0, "Amount of focal blur, 128=infinity=perfect focus, half the value doubles the blur radius");
+               }
+               uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Maxblur:",
+                         butr->xmin, dy-95, dx, 19,
+                         &nqd->maxblur, 0, 10000, 1000, 0, "blur limit, maximum CoC radius, 0=no limit");
+               uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "BThreshold:",
+                         butr->xmin, dy-114, dx, 19,
+                         &nqd->bthresh, 0, 100, 100, 0, "CoC radius threshold, prevents background bleed on in-focus midground, 0=off");
+               uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Preview",
+                         butr->xmin, dy-142, dx, 19,
+                         &nqd->preview, 0, 0, 0, 0, "Enable sampling mode, useful for preview when using low samplecounts");
+               if (nqd->preview) {
+                       /* only visible when sampling mode enabled */
+                       uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Samples:",
+                                 butr->xmin, dy-161, dx, 19,
+                                 &nqd->samples, 16, 256, 0, 0, "Number of samples (16=grainy, higher=less noise)");
+               }
+               uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "No zbuffer",
+                         butr->xmin, dy-190, dx, 19,
+                         &nqd->no_zbuf, 0, 0, 0, 0, "Enable when using an image as input instead of actual zbuffer (auto enabled if node not image based, eg. time node)");
+               if (nqd->no_zbuf) {
+                       uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Zscale:",
+                           butr->xmin, dy-209, dx, 19,
+                           &nqd->scale, 0, 1000, 100, 0, "Scales the Z input when not using a zbuffer, controls maximum blur designated by the color white or input value 1");
+               }
+       }
+       return 228;
+}
+
 static int node_composit_buts_vecblur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
 {
        if(block) {
@@ -1423,6 +1477,10 @@ static void node_composit_set_butfunc(bNodeType *ntype)
                case CMP_NODE_BLUR:
                        ntype->butfunc= node_composit_buts_blur;
                        break;
+               /*  qdn: defocus node */
+               case CMP_NODE_DEFOCUS:
+                       ntype->butfunc = node_composit_buts_defocus;
+                       break;
                case CMP_NODE_VECBLUR:
                        ntype->butfunc= node_composit_buts_vecblur;
                        break;
index 567e4a7bab2779d2f0042cf0bb6d7441d860be5a..d322b2cf0b7ca2ab8b7da8fad538c0d4810493b6 100644 (file)
@@ -873,6 +873,7 @@ static void draw_limit_line(float sta, float end, unsigned int col)
 
 
 /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
+/* qdn: now also enabled for Blender to set focus point for defocus composit node */
 static void draw_focus_cross(float dist, float size)
 {
        glBegin(GL_LINES);
@@ -976,8 +977,8 @@ static void drawcamera(Object *ob, int flag)
 
                        if(cam->flag & CAM_SHOWLIMITS) {
                                draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF);
-                               /* yafray: dof focus point */
-                               if (G.scene->r.renderer==R_YAFRAY) draw_focus_cross(cam->YF_dofdist, cam->drawsize);
+                               /* qdn: was yafray only, now also enabled for Blender to be used with defocus composit node */
+                               draw_focus_cross(cam->YF_dofdist, cam->drawsize);
                        }
 
                        wrld= G.scene->world;
index 1f8fdf0f981b116b07393b3353568867dc96ea53..04d44d157ea85564057772056c5d9e5fb77ecff1 100644 (file)
@@ -2635,8 +2635,9 @@ void common_insertkey(void)
                                id= G.buts->lockpoin;
                                if(id) {
                                        /* yafray: insert key extended with aperture and focal distance */
+                                       /* qdn: FocalDistance now enabled for Blender as wel, for use with defocus node */
                                        if (G.scene->r.renderer==R_INTERN)
-                                               event= pupmenu("Insert Key %t|Lens%x0|Clipping%x1");
+                                               event= pupmenu("Insert Key %t|Lens%x0|Clipping%x1|FocalDistance%x3");
                                        else
                                                event= pupmenu("Insert Key %t|Lens%x0|Clipping%x1|Aperture%x2|FocalDistance%x3");
                                        if(event== -1) return;
index 51c54cf6661914d38efa2d0f44c91405a29e03f9..ffa7fe218f5f65cbe3fbd78938841fc98a7d94fd 100644 (file)
@@ -459,6 +459,10 @@ int blenderqread(unsigned short event, short val)
                        BIF_save_rendered_image_fs();
                        return 0;
                }
+               else if(G.qual==LR_SHIFTKEY) {
+                       newspace(curarea, SPACE_NODE);
+                       return 0;
+               }
                else if(G.qual & LR_CTRLKEY) {
                        BIF_screendump(0);
                }