diff options
author | Ton Roosendaal <ton@blender.org> | 2006-02-03 23:39:36 +0300 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2006-02-03 23:39:36 +0300 |
commit | 6ac2c83016c4f0cd713e3170ce55f22b5e99707c (patch) | |
tree | eee13b4ae9c0fd4205c6d29b0d3c82b6fed235a8 | |
parent | 7a7c33ea2713e06c1f9581838a3b2c0e8ce1f48c (diff) |
Redoing the blur filters for composit;
http://www.blender.org/bf/filters/
I found out current blur actually doesn't do gauss, but more did regular
quadratic. Now you can choose common filter types, but more specifically;
- set gamma on, to emphasize bright parts in blur more than darker parts
- use the bokeh option for (current circlular only) blur based on true
area filters (meaning, for each pixel it samples the entire surrounding).
This enables more effects, but is also much slower. Have to check on
optimization for this still... use with care!
-rw-r--r-- | source/blender/blenkernel/bad_level_call_stubs/stubs.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node_composite.c | 197 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 27 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 6 | ||||
-rw-r--r-- | source/blender/render/extern/include/RE_pipeline.h | 4 | ||||
-rw-r--r-- | source/blender/render/intern/source/initrender.c | 35 | ||||
-rw-r--r-- | source/blender/src/drawnode.c | 27 |
8 files changed, 267 insertions, 33 deletions
diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c index e15b308e8b3..bd802215bfd 100644 --- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c +++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c @@ -218,4 +218,4 @@ int multitex(struct Tex *tex, float *texvec, float *dxt, float *dyt, int osatex struct Render *RE_GetRender(const char *name) {return (struct Render *)NULL;} struct RenderResult *RE_GetResult(Render *re) {return (struct RenderResult *)NULL;} float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype) {return NULL;} - +float RE_filter_value(int type, float x) {return 0.0f;} diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index e2dc623859e..80393db65c0 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -771,6 +771,8 @@ bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup) node->storage= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f); else if(type==CMP_NODE_MAP_VALUE) node->storage= add_mapping(); + else if(type==CMP_NODE_BLUR) + node->storage= MEM_callocN(sizeof(NodeBlurData), "node blur data"); } return node; diff --git a/source/blender/blenkernel/intern/node_composite.c b/source/blender/blenkernel/intern/node_composite.c index 8157f56c6e6..60cf84c7f92 100644 --- a/source/blender/blenkernel/intern/node_composite.c +++ b/source/blender/blenkernel/intern/node_composite.c @@ -85,9 +85,9 @@ static CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc) if(cbuf->type==CB_RGBA) cbuf->rect= MEM_mallocT(4*sizeof(float)*sizex*sizey, "compbuf RGBA rect"); else if(cbuf->type==CB_VEC3) - cbuf->rect= MEM_mallocT(4*sizeof(float)*sizex*sizey, "compbuf Vector3 rect"); + cbuf->rect= MEM_mallocT(3*sizeof(float)*sizex*sizey, "compbuf Vector3 rect"); else if(cbuf->type==CB_VEC2) - cbuf->rect= MEM_mallocT(4*sizeof(float)*sizex*sizey, "compbuf Vector2 rect"); + cbuf->rect= MEM_mallocT(2*sizeof(float)*sizex*sizey, "compbuf Vector2 rect"); else cbuf->rect= MEM_mallocT(sizeof(float)*sizex*sizey, "compbuf Fac rect"); cbuf->malloc= 1; @@ -100,6 +100,13 @@ static CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc) return cbuf; } +static CompBuf *dupalloc_compbuf(CompBuf *cbuf) +{ + CompBuf *dupbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1); + memcpy(dupbuf->rect, cbuf->rect, cbuf->type*sizeof(float)*cbuf->x*cbuf->y); + return dupbuf; +} + void free_compbuf(CompBuf *cbuf) { if(cbuf->malloc && cbuf->rect) @@ -1501,7 +1508,7 @@ static bNodeType cmp_node_map_value= { }; -/* **************** GAUSS BLUR ******************** */ +/* **************** BLUR ******************** */ static bNodeSocketType cmp_node_blur_in[]= { { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, { SOCK_VALUE, 1, "Size", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, @@ -1512,7 +1519,7 @@ static bNodeSocketType cmp_node_blur_out[]= { { -1, 0, "" } }; -static float *make_gausstab(int rad) +static float *make_gausstab(int filtertype, int rad) { float *gausstab, sum, val; int i, n; @@ -1523,7 +1530,7 @@ static float *make_gausstab(int rad) sum = 0.0f; for (i = -rad; i <= rad; i++) { - val = exp(-4.0*((float)i*i) / (float) (rad*rad)); + val= RE_filter_value(filtertype, (float)i/(float)rad); sum += val; gausstab[i+rad] = val; } @@ -1552,7 +1559,7 @@ static float *make_bloomtab(int rad) return bloomtab; } -static void blur_single_image(CompBuf *new, CompBuf *img, float blurx, float blury) +static void blur_single_image(CompBuf *new, CompBuf *img, float scale, NodeBlurData *nbd) { CompBuf *work; register float sum, val; @@ -1567,13 +1574,13 @@ static void blur_single_image(CompBuf *new, CompBuf *img, float blurx, float blu work= alloc_compbuf(imgx, imgy, img->type, 1); // allocs /* horizontal */ - rad = ceil(blurx); + rad = scale*(float)nbd->sizex; if(rad>imgx/2) rad= imgx/2; else if(rad<1) rad= 1; - gausstab= make_gausstab(rad); + gausstab= make_gausstab(nbd->filtertype, rad); gausstabcent= gausstab+rad; for (y = 0; y < imgy; y++) { @@ -1611,13 +1618,13 @@ static void blur_single_image(CompBuf *new, CompBuf *img, float blurx, float blu /* vertical */ MEM_freeT(gausstab); - rad = ceil(blury); + rad = scale*(float)nbd->sizey; if(rad>imgy/2) rad= imgy/2; else if(rad<1) rad= 1; - gausstab= make_gausstab(rad); + gausstab= make_gausstab(nbd->filtertype, rad); gausstabcent= gausstab+rad; bigstep = pix*imgx; @@ -1660,7 +1667,7 @@ static void blur_single_image(CompBuf *new, CompBuf *img, float blurx, float blu } /* reference has to be mapped 0-1, and equal in size */ -static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float blurx, float blury) +static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float fac, NodeBlurData *nbd) { CompBuf *wbuf; register float val; @@ -1677,14 +1684,14 @@ static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float memset(wbuf->rect, sizeof(float)*imgx*imgy, 0); /* horizontal */ - radx = ceil(blurx); + radx = (float)nbd->sizex; if(radx>imgx/2) radx= imgx/2; else if(radx<1) radx= 1; /* vertical */ - rady = ceil(blury); + rady = (float)nbd->sizey; if(rady>imgy/2) rady= imgy/2; else if(rady<1) @@ -1780,8 +1787,130 @@ static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float } +static void gamma_correct_compbuf(CompBuf *img, int inversed) +{ + float *drect; + int x; + + drect= img->rect; + if(inversed) { + for(x=img->x*img->y; x>0; x--, drect+=4) { + if(drect[0]>0.0f) drect[0]= sqrt(drect[0]); else drect[0]= 0.0f; + if(drect[1]>0.0f) drect[1]= sqrt(drect[1]); else drect[1]= 0.0f; + if(drect[2]>0.0f) drect[2]= sqrt(drect[2]); else drect[2]= 0.0f; + } + } + else { + for(x=img->x*img->y; x>0; x--, drect+=4) { + if(drect[0]>0.0f) drect[0]*= drect[0]; else drect[0]= 0.0f; + if(drect[1]>0.0f) drect[1]*= drect[1]; else drect[1]= 0.0f; + if(drect[2]>0.0f) drect[2]*= drect[2]; else drect[2]= 0.0f; + } + } +} +#if 0 +static float hexagon_filter(float fi, float fj) +{ + fi= fabs(fi); + fj= fabs(fj); + + if(fj>0.33f) { + fj= (fj-0.33f)/0.66f; + if(fi+fj>1.0f) + return 0.0f; + else + return 1.0f; + } + else return 1.0f; +} +#endif +/* uses full filter, no horizontal/vertical optimize possible */ +static void bokeh_single_image(CompBuf *new, CompBuf *img, float fac, NodeBlurData *nbd) +{ + register float val; + float radxf, radyf; + float *gausstab, *dgauss; + int radx, rady, imgx= img->x, imgy= img->y; + int x, y; + int i, j; + float *src, *dest; + + /* horizontal */ + radx = fac*(float)nbd->sizex; + if(radx>imgx/2) + radx= imgx/2; + else if(radx<1) + radx= 1; + + /* vertical */ + rady = fac*(float)nbd->sizey; + if(rady>imgy/2) + rady= imgy/2; + else if(rady<1) + rady= 1; + + radxf= (float)radx; + radyf= (float)rady; + + /* create a full filter image */ + gausstab= MEM_mallocT(sizeof(float)*radx*rady*4, "filter tab"); + dgauss= gausstab; + val= 0.0f; + for(j=-rady; j<rady; j++) { + for(i=-radx; i<radx; i++, dgauss++) { + float fj= (float)j/radyf; + float fi= (float)i/radxf; + float dist= sqrt(fj*fj + fi*fi); + +// *dgauss= hexagon_filter(fi, fj); + *dgauss= RE_filter_value(nbd->filtertype, 2.0f*dist - 1.0f); + + val+= *dgauss; + } + } + val= 1.0f/val; + for(j= 4*radx*rady -1; j>=0; j--) + gausstab[j]*= val; + + + /* vars to store before we go */ + // refd= ref->rect; + src= img->rect; + + memset(new->rect, 4*imgx*imgy, 0); + + for (y = 0; y < imgy; y++) { + for (x = 0; x < imgx ; x++, src+=4) {//, refd++) { + int minxr= x-radx<0?-x:-radx; + int maxxr= x+radx>imgx?imgx-x:radx; + int minyr= y-rady<0?-y:-rady; + int maxyr= y+rady>imgy?imgy-y:rady; + + float *destd= new->rect + 4*( (y + minyr)*imgx + x + minxr); + + float *dgausd= gausstab + (minyr+rady)*2*radx + minxr+radx; + + for (i= minyr; i < maxyr; i++, destd+= 4*imgx, dgausd+= 2*radx) { + dest= destd; + dgauss= dgausd; + for (j= minxr; j < maxxr; j++, dest+=4, dgauss++) { + + val= *dgauss; + dest[0] += val * src[0]; + dest[1] += val * src[1]; + dest[2] += val * src[2]; + dest[3] += val * src[3]; + } + } + } + } + + MEM_freeT(gausstab); +} + + /* reference has to be mapped 0-1, and equal in size */ -static void blur_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float blurx, float blury) +static void blur_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, NodeBlurData *nbd) { CompBuf *blurbuf; register float sum, val; @@ -1804,17 +1933,17 @@ static void blur_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float else blurd[0]= refd[0]; } - blur_single_image(blurbuf, blurbuf, blurx, blury); + blur_single_image(blurbuf, blurbuf, 1.0f, nbd); /* horizontal */ - radx = ceil(blurx); + radx = (float)nbd->sizex; if(radx>imgx/2) radx= imgx/2; else if(radx<1) radx= 1; /* vertical */ - rady = ceil(blury); + rady = (float)nbd->sizey; if(rady>imgy/2) rady= imgy/2; else if(rady<1) @@ -1823,7 +1952,7 @@ static void blur_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float x= MAX2(radx, rady); maintabs= MEM_mallocT(x*sizeof(void *), "gauss array"); for(i= 0; i<x; i++) - maintabs[i]= make_gausstab(i+1); + maintabs[i]= make_gausstab(nbd->filtertype, i+1); refd= blurbuf->rect; dest= new->rect; @@ -1906,7 +2035,7 @@ static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bN /* make output size of input image */ new= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs - blur_with_reference(new, img, in[1]->data, (float)node->custom1, (float)node->custom2); + blur_with_reference(new, img, in[1]->data, node->storage); out[0]->data= new; } @@ -1917,19 +2046,35 @@ static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bN new->rect= img->rect; } else { + NodeBlurData *nbd= node->storage; + CompBuf *gammabuf; + /* make output size of input image */ new= alloc_compbuf(img->x, img->y, img->type, 1); // allocs - if(1) - blur_single_image(new, img, in[1]->vec[0]*(float)node->custom1, in[1]->vec[0]*(float)node->custom2); + + if(nbd->gamma) { + gammabuf= dupalloc_compbuf(img); + gamma_correct_compbuf(gammabuf, 0); + } + else gammabuf= img; + + if(nbd->bokeh) + bokeh_single_image(new, gammabuf, in[1]->vec[0], nbd); + else if(1) + blur_single_image(new, gammabuf, in[1]->vec[0], nbd); else /* bloom experimental... */ - bloom_with_reference(new, img, NULL, in[1]->vec[0]*(float)node->custom1, in[1]->vec[0]*(float)node->custom2); + bloom_with_reference(new, gammabuf, NULL, in[1]->vec[0], nbd); + + if(nbd->gamma) { + gamma_correct_compbuf(new, 1); + free_compbuf(gammabuf); + } } out[0]->data= new; } } -/* custom1 custom2 = blur filter size */ static bNodeType cmp_node_blur= { /* type code */ CMP_NODE_BLUR, /* name */ "Blur", @@ -1937,7 +2082,7 @@ static bNodeType cmp_node_blur= { /* class+opts */ NODE_CLASS_OPERATOR, NODE_OPTIONS, /* input sock */ cmp_node_blur_in, /* output sock */ cmp_node_blur_out, - /* storage */ "", + /* storage */ "NodeBlurData", /* execfunc */ node_composit_exec_blur }; @@ -1955,6 +2100,7 @@ static bNodeSocketType cmp_node_vecblur_out[]= { static void node_composit_exec_vecblur(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { + NodeBlurData nbd; CompBuf *new, *img= in[0]->data, *vecbuf= in[1]->data, *wbuf; float *vect, *dest; int x, y; @@ -1984,7 +2130,8 @@ static void node_composit_exec_vecblur(void *data, bNode *node, bNodeStack **in, /* make output size of input image */ new= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs - blur_with_reference(new, img, wbuf, 100.0f, 100.0f); + nbd.sizex= 100; nbd.sizey= 100; nbd.filtertype= R_FILTER_GAUSS; + blur_with_reference(new, img, wbuf, &nbd); free_compbuf(wbuf); out[0]->data= new; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 6342578115e..96828d0faa4 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3593,6 +3593,25 @@ static void bone_version_239(ListBase *lb) } } +static void ntree_version_241(bNodeTree *ntree) +{ + bNode *node; + + if(ntree->type==NTREE_COMPOSIT) { + for(node= ntree->nodes.first; node; node= node->next) { + if(node->type==CMP_NODE_BLUR) { + if(node->storage==NULL) { + NodeBlurData *nbd= MEM_callocN(sizeof(NodeBlurData), "node blur patch"); + nbd->sizex= node->custom1; + nbd->sizey= node->custom2; + nbd->filtertype= R_FILTER_QUAD; + node->storage= nbd; + } + } + } + } +} + static void do_versions(FileData *fd, Library *lib, Main *main) { /* WATCH IT!!!: pointers from libdata have not been converted */ @@ -5253,6 +5272,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) if(main->versionfile <= 241) { Scene *sce; bArmature *arm; + bNodeTree *ntree; /* updating layers still */ for(arm= main->armature.first; arm; arm= arm->id.next) { @@ -5265,7 +5285,14 @@ static void do_versions(FileData *fd, Library *lib, Main *main) /* adds default layer */ if(sce->r.layers.first==NULL) scene_add_render_layer(sce); + /* node version changes */ + if(sce->nodetree) + ntree_version_241(sce->nodetree); } + + for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) + ntree_version_241(ntree); + //Object *ob; /* for empty drawsize and drawtype */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 05d3a276607..340f000316a 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -185,5 +185,11 @@ typedef struct NodeImageAnim { char cyclic, movie; } NodeImageAnim; +typedef struct NodeBlurData { + short sizex, sizey; + short filtertype; + char bokeh, gamma; +} NodeBlurData; + #endif diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 1afce546791..07d0b0a1315 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -171,8 +171,8 @@ void RE_test_break_cb (struct Render *re, int (*f)(void)); void RE_test_return_cb (struct Render *re, int (*f)(void)); void RE_error_cb (struct Render *re, void (*f)(const char *str)); - - +/* should move to kernel once... still unsure on how/where */ +float RE_filter_value(int type, float x); #endif /* RE_PIPELINE_H */ diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index 9a36cf99e27..19d593a9409 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -153,6 +153,41 @@ static float filt_mitchell(float x) /* Mitchell & Netravali's two-param cubic */ return 0.0; } +/* x ranges from -1 to 1 */ +float RE_filter_value(int type, float x) +{ + float gaussfac= 1.6f; + + x= ABS(x); + + switch(type) { + case R_FILTER_BOX: + if(x>1.0) return 0.0f; + return 1.0; + + case R_FILTER_TENT: + if(x>1.0) return 0.0f; + return 1.0f-x; + + case R_FILTER_GAUSS: + x*= gaussfac; + return (1.0/exp(x*x) - 1.0/exp(gaussfac*gaussfac*2.25)); + + case R_FILTER_MITCH: + return filt_mitchell(x*gaussfac); + + case R_FILTER_QUAD: + return filt_quadratic(x*gaussfac); + + case R_FILTER_CUBIC: + return filt_cubic(x*gaussfac); + + case R_FILTER_CATROM: + return filt_catrom(x*gaussfac); + } + return 0.0f; +} + static float calc_weight(Render *re, float *weight, int i, int j) { float x, y, dist, totw= 0.0; diff --git a/source/blender/src/drawnode.c b/source/blender/src/drawnode.c index 9dc00c18065..ed8f6d81ba9 100644 --- a/source/blender/src/drawnode.c +++ b/source/blender/src/drawnode.c @@ -699,17 +699,34 @@ static int node_composit_buts_renderresult(uiBlock *block, bNodeTree *ntree, bNo static int node_composit_buts_blur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) { if(block) { + NodeBlurData *nbd= node->storage; uiBut *bt; + short dy= butr->ymin+19; + short dx= (butr->xmax-butr->xmin)/2; + short dx3=(butr->xmax-butr->xmin)/3; + char str[256]; uiBlockBeginAlign(block); + sprintf(str, "Filter Type%%t|Flat %%x%d|Tent %%x%d|Quad %%x%d|Cubic %%x%d|Gauss %%x%d|CatRom %%x%d|Mitch %%x%d", R_FILTER_BOX, R_FILTER_TENT, R_FILTER_QUAD, R_FILTER_CUBIC, R_FILTER_GAUSS, R_FILTER_CATROM, R_FILTER_MITCH); + uiDefButS(block, MENU, B_NODE_EXEC,str, + butr->xmin, dy, dx3, 19, + &nbd->filtertype, 0, 0, 0, 0, "Set sampling filter for blur"); + uiDefButC(block, TOG, B_NODE_EXEC, "Bokeh", + butr->xmin+dx3, dy, dx3, 19, + &nbd->bokeh, 0, 0, 0, 0, "Uses circular filter, warning it's slow!"); + uiDefButC(block, TOG, B_NODE_EXEC, "Gamma", + butr->xmin+2*dx3, dy, dx3, 19, + &nbd->gamma, 0, 0, 0, 0, "Applies filter on gamma corrected values"); + + dy-=19; bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "X:", - butr->xmin, butr->ymin, (butr->xmax-butr->xmin)/2, 19, - &node->custom1, 0, 256, 0, 0, ""); + butr->xmin, dy, dx, 19, + &nbd->sizex, 0, 256, 0, 0, ""); bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Y:", - butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin, (butr->xmax-butr->xmin)/2, 19, - &node->custom2, 0, 256, 0, 0, ""); + butr->xmin+dx, dy, dx, 19, + &nbd->sizey, 0, 256, 0, 0, ""); } - return 19; + return 38; } static int node_composit_buts_filter(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) |