iImage based Vector Blur

After a couple of experiments with variable blur filters, I tried
a more interesting, and who knows... original approach. :)

First watch results here:
http://www.blender.org/bf/rt0001_0030.avi
http://www.blender.org/bf/hand0001_0060.avi

These are the steps in producing such results:

- In preprocess, the speed vectors to previous and next frame are
  calculated. Speed vectors are screen-aligned and in pixel size.
- while rendering, these vectors get calculated per sample, and
  accumulated in the vector buffer checking for "minimum speed".
  (on start the vector buffer is initialized on max speed).

- After render:
- The entire image, all pixels, then is converted to quad polygons.
- Also the z value of the pixels is assigned to the polygons
- The vertices for the quads use averaged speed vectors (of the 4
  corner faces), using a 'minimum but non-zero' speed rule.

  This minimal speed trick works very well to prevent 'tearing' apart
  when multiple faces move in different directions in a pixel, or to
  be able to separate moving pixels clearly from non-moving ones

- So, now we have a sort of 'mask' of quad polygons. The previous steps
  guaranteed that this mask doesn't have antialias color info, and has
  speed vectors that ensure individual parts to move nicely without
  tearing effects. The Z allows multiple layers of moving masks.

- Then, in temporal buffer, faces get tagged if they move or not
- These tags then go to an anti-alias routine, which assigns alpha
  values to edge faces, based on the method we used in past to antialias
  bitmaps (still in our code, check the antialias.c in imbuf!)

- finally, the tag buffer is used to tag which z values of the original
  image have to be included (to allow blur go behind stuff).

- OK, now we're ready for accumulating! In a loop, all faces then get
  drawn (with zbuffer) with increasing influence of their speed vectors.
  The resulting image then is accumulated on top of the original with a
  decreasing weighting value.

It sounds all quite complex... but the speed is still encouraging. Above
images have 64 mblur steps, which takes about 1-3 seconds per frame.

Usage notes:

- Make sure the render-layer has passes 'Vector' and 'Z' on.
- add in Compositor the VectorBlur node, and connect the image, Z and
  speed to the inputs.
- The node allows to set amount of steps (10 steps = 10 forward, 10 back).
  and to set a maximum speed in pixels... to prevent extreme moving things
  to blur too wide.
This commit is contained in:
2006-02-06 22:11:50 +00:00
parent 4c59280ed8
commit f45546a1d3
15 changed files with 814 additions and 203 deletions

View File

@@ -44,6 +44,7 @@ typedef struct DupliObject {
struct DupliObject *next, *prev;
struct Object *ob;
unsigned int origlay;
int index;
float mat[4][4], omat[4][4];
} DupliObject;

View File

@@ -277,7 +277,7 @@ int where_on_path(Object *ob, float ctime, float *vec, float *dir) /* returns OK
/* ****************** DUPLICATOR ************** */
static void new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay)
static void new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index)
{
DupliObject *dob= MEM_mallocN(sizeof(DupliObject), "dupliobject");
BLI_addtail(lb, dob);
@@ -285,6 +285,7 @@ static void new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay)
Mat4CpyMat4(dob->mat, mat);
Mat4CpyMat4(dob->omat, ob->obmat);
dob->origlay= ob->lay;
dob->index= index;
ob->lay= lay;
}
@@ -302,7 +303,7 @@ static void group_duplilist(ListBase *lb, Object *ob)
for(go= ob->dup_group->gobject.first; go; go= go->next) {
if(go->ob!=ob) {
Mat4MulMat4(mat, go->ob->obmat, ob->obmat);
new_dupli_object(lb, go->ob, mat, ob->lay);
new_dupli_object(lb, go->ob, mat, ob->lay, 0);
}
}
}
@@ -331,7 +332,7 @@ static void frames_duplilist(ListBase *lb, Object *ob)
if(ok) {
do_ob_ipo(ob);
where_is_object_time(ob, (float)G.scene->r.cfra);
new_dupli_object(lb, ob, ob->obmat, ob->lay);
new_dupli_object(lb, ob, ob->obmat, ob->lay, G.scene->r.cfra);
}
}
@@ -369,7 +370,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, float *co, float *n
Mat4CpyMat4(tmat, obmat);
Mat4MulMat43(obmat, tmat, mat);
}
new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay);
new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index);
}
static void vertex_duplilist(ListBase *lb, Scene *sce, Object *par)
@@ -442,7 +443,7 @@ static void particle_duplilist(ListBase *lb, Scene *sce, Object *par, PartEff *p
float ctime, vec1[3];
float vec[3], tmat[4][4], mat[3][3];
float *q2;
int lay, a;
int lay, a, counter; /* counter is used to find in render the indexed object */
pa= paf->keys;
if(pa==0) {
@@ -465,7 +466,7 @@ static void particle_duplilist(ListBase *lb, Scene *sce, Object *par, PartEff *p
/* temp copy, to have ipos etc to work OK */
copyob= *ob;
for(a=0, pa= paf->keys; a<paf->totpart; a++, pa+=paf->totkey) {
for(a=0, pa= paf->keys, counter=0; a<paf->totpart; a++, pa+=paf->totkey, counter++) {
if(paf->flag & PAF_STATIC) {
float mtime;
@@ -473,7 +474,7 @@ static void particle_duplilist(ListBase *lb, Scene *sce, Object *par, PartEff *p
where_is_particle(paf, pa, pa->time, vec1);
mtime= pa->time+pa->lifetime;
for(ctime= pa->time; ctime<mtime; ctime+=paf->staticstep) {
for(ctime= pa->time; ctime<mtime; ctime+=paf->staticstep, counter++) {
/* make sure hair grows until the end.. */
if(ctime>pa->time+pa->lifetime) ctime= pa->time+pa->lifetime;
@@ -500,7 +501,7 @@ static void particle_duplilist(ListBase *lb, Scene *sce, Object *par, PartEff *p
/* put object back in original state, so it cam be restored OK */
Mat4CpyMat4(tmat, ob->obmat);
Mat4CpyMat4(ob->obmat, copyob.obmat);
new_dupli_object(lb, ob, tmat, par->lay);
new_dupli_object(lb, ob, tmat, par->lay, counter);
}
}
else { // non static particles
@@ -527,10 +528,10 @@ static void particle_duplilist(ListBase *lb, Scene *sce, Object *par, PartEff *p
VECCOPY(ob->obmat[3], vec);
/* put object back in original state, so it cam be restored OK */
/* put object back in original state, so it can be restored OK */
Mat4CpyMat4(tmat, ob->obmat);
Mat4CpyMat4(ob->obmat, copyob.obmat);
new_dupli_object(lb, ob, tmat, par->lay);
new_dupli_object(lb, ob, tmat, par->lay, counter);
}
}
/* temp copy, to have ipos etc to work OK */
@@ -605,7 +606,7 @@ static void font_duplilist(ListBase *lb, Object *par)
Mat4CpyMat4(obmat, par->obmat);
VECCOPY(obmat[3], vec);
new_dupli_object(lb, ob, obmat, par->lay);
new_dupli_object(lb, ob, obmat, par->lay, a);
}
}

View File

@@ -778,6 +778,9 @@ 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_VECBLUR) {
node->custom1= 32;
}
}
return node;

View File

@@ -70,6 +70,7 @@ typedef struct CompBuf {
/* defines also used for pixel size */
#define CB_RGBA 4
#define CB_VEC4 4
#define CB_VEC3 3
#define CB_VEC2 2
#define CB_VAL 1
@@ -819,7 +820,7 @@ static CompBuf *compbuf_from_pass(RenderLayer *rl, int rectx, int recty, int pas
if(passcode==SCE_PASS_Z)
buftype= CB_VAL;
else if(passcode==SCE_PASS_VECTOR)
buftype= CB_VEC2;
buftype= CB_VEC4;
else if(passcode==SCE_PASS_RGBA)
buftype= CB_RGBA;
@@ -2138,7 +2139,8 @@ static bNodeType cmp_node_blur= {
/* **************** VECTOR BLUR ******************** */
static bNodeSocketType cmp_node_vecblur_in[]= {
{ SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{ SOCK_VECTOR, 1, "Vec", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_VALUE, 1, "Z", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_VECTOR, 1, "Speed", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
};
static bNodeSocketType cmp_node_vecblur_out[]= {
@@ -2146,45 +2148,46 @@ static bNodeSocketType cmp_node_vecblur_out[]= {
{ -1, 0, "" }
};
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;
extern void zbuf_accumulate_vecblur(int samples, int maxspeed, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect);
if(img==NULL || vecbuf==NULL || out[0]->hasoutput==0)
// NodeBlurData nbd;
CompBuf *new, *img= in[0]->data, *vecbuf= in[2]->data, *zbuf= in[1]->data;
if(img==NULL || vecbuf==NULL || zbuf==NULL || out[0]->hasoutput==0)
return;
if(vecbuf->x!=img->x || vecbuf->y!=img->y) {
printf("cannot do different sized vecbuf yet\n");
printf("ERROR: cannot do different sized vecbuf yet\n");
return;
}
if(vecbuf->type!=CB_VEC2) {
printf("input should be vecbuf\n");
if(vecbuf->type!=CB_VEC4) {
printf("ERROR: input should be vecbuf\n");
return;
}
if(zbuf->type!=CB_VAL) {
printf("ERROR: input should be zbuf\n");
return;
}
if(zbuf->x!=img->x || zbuf->y!=img->y) {
printf("ERROR: cannot do different sized zbuf yet\n");
return;
}
/* make weights version of vectors */
wbuf= alloc_compbuf(img->x, img->y, CB_VAL, 1); // allocs
dest= wbuf->rect;
vect= vecbuf->rect;
for(y=0; y<img->y; y++) {
for(x=0; x<img->x; x++, dest++, vect+=2) {
*dest= 0.02f*sqrt(vect[0]*vect[0] + vect[1]*vect[1]);
if(*dest>1.0f) *dest= 1.0f;
}
}
//new= alloc_compbuf(img->x, img->y, img->type, 1);
new= dupalloc_compbuf(img);
/* make output size of input image */
new= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
// do_filter3(vecbuf, vecbuf, soft, 1.0f);
nbd.sizex= 100; nbd.sizey= 100; nbd.filtertype= R_FILTER_GAUSS;
blur_with_reference(new, img, wbuf, &nbd);
/* call special zbuffer version */
zbuf_accumulate_vecblur(node->custom1, node->custom2, img->x, img->y, new->rect, img->rect, vecbuf->rect, zbuf->rect);
free_compbuf(wbuf);
out[0]->data= new;
}
/* custom1: itterations, custom2: maxspeed (0 = nolimit) */
static bNodeType cmp_node_vecblur= {
/* type code */ CMP_NODE_VECBLUR,
/* name */ "Vector Blur",

View File

@@ -54,7 +54,7 @@ typedef struct ShadeResult
float ao[3];
float ray[3];
float nor[3];
float winspeed[3];
float winspeed[4];
} ShadeResult;
@@ -84,7 +84,7 @@ typedef struct ShadeInput
/* texture coordinates */
float lo[3], gl[3], uv[3], ref[3], orn[3], winco[3], sticky[3], vcol[3], rad[3];
float vn[3], vno[3], facenor[3], view[3], refcol[4], displace[3];
float strand, tang[3], stress, winspeed[3];
float strand, tang[3], stress, winspeed[4];
/* dx/dy OSA coordinates */
float dxco[3], dyco[3];

View File

@@ -40,6 +40,7 @@
#include "RE_pipeline.h"
#include "RE_shader_ext.h" /* TexResult, ShadeResult, ShadeInput */
struct Object;
struct MemArena;
struct VertTableNode;
struct Octree;
@@ -86,7 +87,6 @@ typedef struct Octree {
int branchcount, nodecount;
} Octree;
/* controls state of render, everything that's read-only during render stage */
struct Render
{
@@ -150,6 +150,7 @@ struct Render
struct HaloRen **bloha;
int blovllen;
struct VlakRen **blovl;
ListBase objecttable;
struct GHash *orco_hash;
@@ -189,6 +190,14 @@ typedef struct ShadBuf {
char *cbuf;
} ShadBuf;
/* ------------------------------------------------------------------------- */
/* lookup of objects in database */
typedef struct ObjectRen {
struct ObjectRen *next, *prev;
struct Object *ob, *par;
int index, startvert, endvert, startface, endface;
} ObjectRen;
/* ------------------------------------------------------------------------- */
typedef struct VertRen

View File

@@ -30,6 +30,7 @@
#ifndef RENDERDATABASE_H
#define RENDERDATABASE_H
struct Object;
struct VlakRen;
struct VertRen;
struct HaloRen;
@@ -61,6 +62,7 @@ struct VertRen *RE_findOrAddVert(struct Render *re, int nr);
struct HaloRen *RE_findOrAddHalo(struct Render *re, int nr);
struct HaloRen *RE_inithalo(struct Render *re, struct Material *ma, float *vec, float *vec1, float *orco, float hasize,
float vectsize, int seed);
void RE_addRenderObject(struct Render *re, struct Object *ob, struct Object *par, int index, int sve, int eve, int sfa, int efa);
float *RE_vertren_get_sticky(struct Render *re, struct VertRen *ver, int verify);
float *RE_vertren_get_stress(struct Render *re, struct VertRen *ver, int verify);

View File

@@ -1445,6 +1445,7 @@ static void init_render_mesh(Render *re, Object *ob, int only_verts)
totvlako= re->totvlak;
totverto= re->totvert;
if(!only_verts) {
need_orco= 0;
for(a=1; a<=ob->totcol; a++) {
ma= give_render_material(re, ob, a);
@@ -1459,6 +1460,7 @@ static void init_render_mesh(Render *re, Object *ob, int only_verts)
}
if(need_orco) orco = get_object_orco(re, ob);
}
dm = mesh_create_derived_render(ob);
dm_needsfree= 1;
@@ -2185,7 +2187,7 @@ static void init_render_surf(Render *re, Object *ob)
freedisplist(&displist);
}
static void init_render_curve(Render *re, Object *ob)
static void init_render_curve(Render *re, Object *ob, int only_verts)
{
extern Material defmaterial; // initrender.c
Curve *cu;
@@ -2257,6 +2259,7 @@ static void init_render_curve(Render *re, Object *ob)
}
}
if(only_verts==0) {
startvlak= re->totvlak;
index= dl->index;
for(a=0; a<dl->parts; a++, index+=3) {
@@ -2284,6 +2287,7 @@ static void init_render_curve(Render *re, Object *ob)
vlr->lay= ob->lay;
}
}
}
else if (dl->type==DL_SURF) {
int p1,p2,p3,p4;
@@ -2304,6 +2308,7 @@ static void init_render_curve(Render *re, Object *ob)
}
}
if(dl->bevelSplitFlag || only_verts==0) {
startvlak= re->totvlak;
for(a=0; a<dl->parts; a++) {
@@ -2377,6 +2382,7 @@ static void init_render_curve(Render *re, Object *ob)
if(vlr->v4->flag) VECCOPY(vlr->v4->n, vlr->n);
}
}
}
dl= dl->next;
}
@@ -2430,7 +2436,9 @@ static void set_phong_threshold(Render *re, Object *ob, int startface, int numfa
}
}
static void init_render_object(Render *re, Object *ob, int only_verts)
/* par = pointer to duplicator parent, needed for object lookup table */
/* index = when duplicater copies same object (particle), the counter */
static void init_render_object(Render *re, Object *ob, Object *par, int index, int only_verts)
{
float mat[4][4];
int startface, startvert;
@@ -2443,7 +2451,7 @@ static void init_render_object(Render *re, Object *ob, int only_verts)
if(ob->type==OB_LAMP)
add_render_lamp(re, ob, 1);
else if ELEM(ob->type, OB_FONT, OB_CURVE)
init_render_curve(re, ob);
init_render_curve(re, ob, only_verts);
else if(ob->type==OB_SURF)
init_render_surf(re, ob);
else if(ob->type==OB_MESH)
@@ -2458,6 +2466,8 @@ static void init_render_object(Render *re, Object *ob, int only_verts)
/* generic post process here */
if(startvert!=re->totvert) {
RE_addRenderObject(re, ob, par, index, startvert, re->totvert, startface, re->totvlak);
/* the exception below is because displace code now is in init_render_mesh call,
I will look at means to have autosmooth enabled for all object types
and have it as general postprocess, like displace */
@@ -2810,7 +2820,7 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
if (re->r.renderer==R_YAFRAY) {
if ((ob->type!=OB_MBALL) && ((ob->transflag & OB_DUPLIFRAMES)!=0)) {
printf("Object %s has OB_DUPLIFRAMES set, adding to renderlist\n", ob->id.name);
init_render_object(re, ob, 0);
init_render_object(re, ob, NULL, 0, 0);
}
}
/* before make duplis, update particle for current frame */
@@ -2822,7 +2832,7 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
}
if(ob->type==OB_MBALL) {
init_render_object(re, ob, 0);
init_render_object(re, ob, NULL, 0, 0);
}
else {
DupliObject *dob;
@@ -2844,7 +2854,7 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
printf("Adding dupli matrix for object %s\n", obd->id.name);
YAF_addDupliMtx(obd);
}
else init_render_object(re, obd, 0);
else init_render_object(re, obd, ob, dob->index, 0);
}
Mat4CpyMat4(obd->obmat, dob->omat);
}
@@ -2864,14 +2874,14 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
(ob->parent->type!=OB_LATTICE) && YAF_objectKnownData(ob))
printf("From parent: Added dupli matrix for linked data object %s\n", ob->id.name);
else
init_render_object(re, ob, 0);
init_render_object(re, ob, NULL, 0, 0);
}
else if ((ob->type!=OB_EMPTY) && (ob->type!=OB_LAMP) && (ob->type!=OB_ARMATURE) && YAF_objectKnownData(ob))
printf("Added dupli matrix for linked data object %s\n", ob->id.name);
else
init_render_object(re, ob, 0);
init_render_object(re, ob, NULL, 0, 0);
}
else init_render_object(re, ob, 0);
else init_render_object(re, ob, NULL, 0, 0);
}
}
@@ -2944,7 +2954,7 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
re->stats_draw(&re->i);
}
static void database_fromscene_vectors(Render *re, Scene *scene)
static void database_fromscene_vectors(Render *re, Scene *scene, int timeoffset)
{
extern int slurph_opt; /* key.c */
Base *base;
@@ -2968,9 +2978,8 @@ static void database_fromscene_vectors(Render *re, Scene *scene)
else lay= re->scene->lay;
/* applies changes fully, still using G.scene for timing... */
G.scene->r.cfra--;
G.scene->r.cfra+=timeoffset;
scene_update_for_newframe(re->scene, lay);
G.scene->r.cfra++;
/* if no camera, viewmat should have been set! */
if(re->scene->camera) {
@@ -3007,7 +3016,7 @@ static void database_fromscene_vectors(Render *re, Scene *scene)
}
if(ob->type==OB_MBALL) {
init_render_object(re, ob, 1);
init_render_object(re, ob, NULL, 0, 1);
}
else {
DupliObject *dob;
@@ -3018,7 +3027,7 @@ static void database_fromscene_vectors(Render *re, Scene *scene)
Mat4CpyMat4(obd->obmat, dob->mat);
if(obd->type!=OB_MBALL) {
init_render_object(re, obd, 1);
init_render_object(re, obd, ob, dob->index, 1);
}
Mat4CpyMat4(obd->obmat, dob->omat);
}
@@ -3026,75 +3035,167 @@ static void database_fromscene_vectors(Render *re, Scene *scene)
}
}
else {
init_render_object(re, ob, 1);
init_render_object(re, ob, NULL, 0, 1);
}
}
}
project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0);
/* do this in end, particles for example need cfra */
G.scene->r.cfra-=timeoffset;
}
static void calculate_speedvectors(Render *re, VertTableNode *nodesb, int starta, int startb, int endvert, int step)
{
VertRen *ver= NULL, *oldver= NULL;
float *speed, div, zco[2], oldzco[2];
float zmulx= re->winx/2, zmuly= re->winy/2, len;
float winsq= re->winx*re->winy, winroot= sqrt(winsq);
int a, b;
/* set first vertices OK */
a= starta-1;
ver= re->vertnodes[a>>8].vert + (a & 255);
b= startb-1;
oldver= nodesb[b>>8].vert + (b & 255);
for(a=starta, b= startb; a<endvert; a++, b++) {
if((a & 255)==0)
ver= re->vertnodes[a>>8].vert;
else
ver++;
if((b & 255)==0)
oldver= nodesb[b>>8].vert;
else
oldver++;
/* now map both hocos to screenspace, uses very primitive clip still */
if(ver->ho[3]<0.1f) div= 10.0f;
else div= 1.0f/ver->ho[3];
zco[0]= zmulx*(1.0+ver->ho[0]*div);
zco[1]= zmuly*(1.0+ver->ho[1]*div);
if(oldver->ho[3]<0.1f) div= 10.0f;
else div= 1.0f/oldver->ho[3];
oldzco[0]= zmulx*(1.0+oldver->ho[0]*div);
oldzco[1]= zmuly*(1.0+oldver->ho[1]*div);
zco[0]= oldzco[0] - zco[0];
zco[1]= oldzco[1] - zco[1];
/* maximize speed for image width, otherwise it never looks good */
len= zco[0]*zco[0] + zco[1]*zco[1];
if(len > winsq) {
len= winroot/sqrt(len);
zco[0]*= len;
zco[1]*= len;
}
speed= RE_vertren_get_winspeed(re, ver, 1);
if(step) {
speed[2]= -zco[0];
speed[3]= -zco[1];
}
else {
speed[0]= zco[0];
speed[1]= zco[1];
}
//printf("speed %d %f %f\n", a, speed[0], speed[1]);
}
}
void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
{
struct VertTableNode *vertnodes;
int vertnodeslen, totvert;
VertTableNode *oldvertnodes, *newvertnodes, *vertnodes;
ObjectRen *obren, *oldobren;
ListBase oldtable, newtable, *table;
int oldvertnodeslen, oldtotvert, newvertnodeslen, newtotvert;
int step;
printf("creating speed vectors \n");
re->r.mode |= R_SPEED;
/* creates entire dbase */
database_fromscene_vectors(re, sce);
database_fromscene_vectors(re, sce, -1);
/* copy away vertex info */
vertnodes= re->vertnodes;
vertnodeslen= re->vertnodeslen;
totvert= re->totvert;
oldvertnodes= re->vertnodes;
oldvertnodeslen= re->vertnodeslen;
oldtotvert= re->totvert;
re->vertnodes= NULL;
re->vertnodeslen= 0;
/* free dbase and make the real one */
/* copy away object table */
oldtable= re->objecttable;
re->objecttable.first= re->objecttable.last= NULL;
/* free dbase and make the future one */
RE_Database_Free(re);
/* creates entire dbase */
database_fromscene_vectors(re, sce, +1);
/* copy away vertex info */
newvertnodes= re->vertnodes;
newvertnodeslen= re->vertnodeslen;
newtotvert= re->totvert;
re->vertnodes= NULL;
re->vertnodeslen= 0;
/* copy away object table */
newtable= re->objecttable;
re->objecttable.first= re->objecttable.last= NULL;
/* free dbase and make the real one */
RE_Database_Free(re);
RE_Database_FromScene(re, sce, 1);
if(re->totvert!=totvert) {
printf("ERROR: vertex tables different in size %d %d\n", re->totvert, totvert);
for(step= 0; step<2; step++) {
if(step) {
table= &newtable;
vertnodes= newvertnodes;
}
else {
VertRen *ver= NULL, *oldver= NULL;
float *speed, div, zco[2], oldzco[2];
float zmulx= re->winx/2, zmuly= re->winy/2;
int a;
for(a=0; a< re->totvert;a++) {
if((a & 255)==0) {
ver= re->vertnodes[a>>8].vert;
oldver= vertnodes[a>>8].vert;
}
else {
ver++;
oldver++;
table= &oldtable;
vertnodes= oldvertnodes;
}
/* now map both hocos to screenspace */
div= 1.0f/ver->ho[3];
zco[0]= zmulx*(1.0+ver->ho[0]*div);
zco[1]= zmuly*(1.0+ver->ho[1]*div);
oldobren= table->first;
div= 1.0f/oldver->ho[3];
oldzco[0]= zmulx*(1.0+oldver->ho[0]*div);
oldzco[1]= zmuly*(1.0+oldver->ho[1]*div);
for(obren= re->objecttable.first; obren && oldobren; obren= obren->next, oldobren= oldobren->next) {
int ok= 1;
speed= RE_vertren_get_winspeed(re, ver, 1);
speed[0]= oldzco[0] - zco[0];
speed[1]= oldzco[1] - zco[1];
//printf("speed %d %f %f\n", a, speed[0], speed[1]);
/* find matching object in old table */
if(oldobren->ob!=obren->ob || oldobren->par!=obren->par || oldobren->index!=obren->index) {
ok= 0;
for(oldobren= table->first; oldobren; oldobren= oldobren->next)
if(oldobren->ob==obren->ob && oldobren->par==obren->par && oldobren->index==obren->index)
break;
if(oldobren==NULL)
oldobren= table->first;
else
ok= 1;
}
if(ok==0)
continue;
/* check if both have same amounts of vertices */
if(obren->endvert-obren->startvert != oldobren->endvert-oldobren->startvert)
continue;
calculate_speedvectors(re, vertnodes, obren->startvert, oldobren->startvert, obren->endvert, step);
}
}
free_renderdata_vertnodes(vertnodes);
free_renderdata_vertnodes(oldvertnodes);
BLI_freelistN(&oldtable);
free_renderdata_vertnodes(newvertnodes);
BLI_freelistN(&newtable);
}

View File

@@ -182,6 +182,16 @@ static void render_layer_add_pass(RenderLayer *rl, int rectsize, int passtype, c
BLI_addtail(&rl->passes, rpass);
rpass->passtype= passtype;
if(passtype==SCE_PASS_VECTOR) {
float *rect;
int x;
/* initialize to max speed */
rect= rpass->rect= RE_mallocN(sizeof(float)*rectsize, mallocstr);
for(x= rectsize-1; x>=0; x--)
rect[x]= 10000.0f;
}
else
rpass->rect= RE_callocN(sizeof(float)*rectsize, mallocstr);
}
@@ -240,7 +250,7 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop)
if(srl->passflag & SCE_PASS_Z)
render_layer_add_pass(rl, rectx*recty, SCE_PASS_Z, "Layer float Z");
if(srl->passflag & SCE_PASS_VECTOR)
render_layer_add_pass(rl, rectx*recty*2, SCE_PASS_VECTOR, "layer float Vector");
render_layer_add_pass(rl, rectx*recty*4, SCE_PASS_VECTOR, "layer float Vector");
if(srl->passflag & SCE_PASS_NORMAL)
render_layer_add_pass(rl, rectx*recty*3, SCE_PASS_NORMAL, "layer float Normal");
if(srl->passflag & SCE_PASS_RGBA)
@@ -339,7 +349,7 @@ static void merge_render_result(RenderResult *rr, RenderResult *rrpart)
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, 1);
break;
case SCE_PASS_VECTOR:
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, 2);
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, 4);
break;
case SCE_PASS_RGBA:
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, 4);

View File

@@ -2025,7 +2025,8 @@ void shade_input_set_coords(ShadeInput *shi, float u, float v, int i1, int i2, i
if(s1 && s2 && s3) {
shi->winspeed[0]= (l*s3[0] - u*s1[0] - v*s2[0]);
shi->winspeed[1]= (l*s3[1] - u*s1[1] - v*s2[1]);
shi->winspeed[2]= 0.0f;
shi->winspeed[2]= (l*s3[2] - u*s1[2] - v*s2[2]);
shi->winspeed[3]= (l*s3[3] - u*s1[3] - v*s2[3]);
}
}
@@ -2530,7 +2531,7 @@ void *shadepixel(ShadePixelInfo *shpi, float x, float y, int z, volatile int fac
// }
/* additional passes */
shr->winspeed[0]= shi.winspeed[0]; shr->winspeed[1]= shi.winspeed[1];
QUATCOPY(shr->winspeed, shi.winspeed);
VECCOPY(shr->nor, shi.vn);
/* NOTE: this is not correct here, sky from raytrace gets corrected... */
@@ -2716,8 +2717,18 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset,
col= shr->nor;
break;
case SCE_PASS_VECTOR:
col= shr->winspeed;
pixsize= 2;
{
/* add minimum speed in pixel */
fp= rpass->rect + 4*offset;
if( (ABS(shr->winspeed[0]) + ABS(shr->winspeed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
fp[0]= shr->winspeed[0];
fp[1]= shr->winspeed[1];
}
if( (ABS(shr->winspeed[2]) + ABS(shr->winspeed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
fp[2]= shr->winspeed[2];
fp[3]= shr->winspeed[3];
}
}
break;
}
if(col) {
@@ -2761,7 +2772,7 @@ static void add_passes(RenderLayer *rl, int offset, ShadeResult *shr)
break;
case SCE_PASS_VECTOR:
col= shr->winspeed;
pixsize= 2;
pixsize= 4;
break;
}
if(col) {
@@ -3121,7 +3132,7 @@ void zbufshade_tile(RenderPart *pa)
QUATCOPY(fcol, shpi.shr.combined);
/* passes */
if(*rp && addpassflag)
if(addpassflag)
add_passes(rl, offs, &shpi.shr);
}
if(y&1)

View File

@@ -59,7 +59,9 @@
#include "MEM_guardedalloc.h"
#include "BKE_utildefines.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
@@ -91,7 +93,7 @@
#define RE_STRAND_ELEMS 1
#define RE_TANGENT_ELEMS 3
#define RE_STRESS_ELEMS 1
#define RE_WINSPEED_ELEMS 2
#define RE_WINSPEED_ELEMS 4
float *RE_vertren_get_sticky(Render *re, VertRen *ver, int verify)
{
@@ -170,7 +172,7 @@ float *RE_vertren_get_tangent(Render *re, VertRen *ver, int verify)
return tangent + (ver->index & 255)*RE_TANGENT_ELEMS;
}
/* needs malloc */
/* needs calloc! not all renderverts have them */
float *RE_vertren_get_winspeed(Render *re, VertRen *ver, int verify)
{
float *winspeed;
@@ -179,7 +181,7 @@ float *RE_vertren_get_winspeed(Render *re, VertRen *ver, int verify)
winspeed= re->vertnodes[nr].winspeed;
if(winspeed==NULL) {
if(verify)
winspeed= re->vertnodes[nr].winspeed= MEM_mallocN(256*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table");
winspeed= re->vertnodes[nr].winspeed= MEM_callocN(256*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table");
else
return NULL;
}
@@ -224,10 +226,26 @@ VertRen *RE_findOrAddVert(Render *re, int nr)
return v;
}
void RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int sve, int eve, int sfa, int efa)
{
ObjectRen *obr= MEM_mallocN(sizeof(ObjectRen), "object render struct");
BLI_addtail(&re->objecttable, obr);
obr->ob= ob;
obr->par= par;
obr->index= index;
obr->startvert= sve;
obr->endvert= eve;
obr->startface= sfa;
obr->endface= efa;
}
void free_renderdata_vertnodes(VertTableNode *vertnodes)
{
int a;
if(vertnodes==NULL) return;
for(a=0; vertnodes[a].vert; a++) {
MEM_freeN(vertnodes[a].vert);
@@ -276,6 +294,8 @@ void free_renderdata_tables(Render *re)
re->vertnodes= NULL;
re->vertnodeslen= 0;
}
BLI_freelistN(&re->objecttable);
}

View File

@@ -38,6 +38,9 @@
#include <string.h>
#include "BLI_blenlib.h"
#include "BLI_threads.h"
#include "BLI_jitter.h"
#include "MTC_matrixops.h"
#include "MEM_guardedalloc.h"
@@ -1865,7 +1868,430 @@ void zbuffer_shadow(Render *re, LampRen *lar, int *rectz, int size)
zbuf_free_span(&zspan);
}
/* ******************** VECBLUR ACCUM BUF ************************* */
static void zbuf_fill_in_rgba(ZSpan *zspan, float *col, float alpha, float *v1, float *v2, float *v3, float *v4)
{
double zxd, zyd, zy0, zverg;
float x0,y0,z0;
float x1,y1,z1,x2,y2,z2,xx1;
float *span1, *span2;
float *rectpofs, *rp, *rectzofs, *rz;
int x, y;
int sn1, sn2, rectx, my0, my2;
/* init */
zbuf_init_span(zspan);
/* set spans */
zbuf_add_to_span(zspan, v1, v2);
zbuf_add_to_span(zspan, v2, v3);
zbuf_add_to_span(zspan, v3, v4);
zbuf_add_to_span(zspan, v4, v1);
/* clipped */
if(zspan->minp2==NULL || zspan->maxp2==NULL) return;
if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
// printf("my %d %d\n", my0, my2);
if(my2<my0) return;
/* ZBUF DX DY, in floats still */
x1= v1[0]- v2[0];
x2= v2[0]- v3[0];
y1= v1[1]- v2[1];
y2= v2[1]- v3[1];
z1= v1[2]- v2[2];
z2= v2[2]- v3[2];
x0= y1*z2-z1*y2;
y0= z1*x2-x1*z2;
z0= x1*y2-y1*x2;
if(z0==0.0) return;
xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
zxd= -(double)x0/(double)z0;
zyd= -(double)y0/(double)z0;
zy0= ((double)my2)*zyd + (double)xx1;
/* start-offset in rect */
rectx= zspan->rectx;
rectzofs= (float *)(zspan->rectz+rectx*my2);
rectpofs= (float *)(zspan->rectp+4*rectx*my2);
/* correct span */
sn1= (my0 + my2)/2;
if(zspan->span1[sn1] < zspan->span2[sn1]) {
span1= zspan->span1+my2;
span2= zspan->span2+my2;
}
else {
span1= zspan->span2+my2;
span2= zspan->span1+my2;
}
for(y=my2; y>=my0; y--, span1--, span2--) {
sn1= floor(*span1);
sn2= floor(*span2);
sn1++;
if(sn2>=rectx) sn2= rectx-1;
if(sn1<0) sn1= 0;
if(sn2>=sn1) {
zverg= (double)sn1*zxd + zy0;
rz= rectzofs+sn1;
rp= rectpofs+4*sn1;
x= sn2-sn1;
while(x>=0) {
if( zverg < *rz) {
*rz= zverg;
VECCOPY(rp, col);
rp[3]= alpha;
}
zverg+= zxd;
rz++;
rp+=4;
x--;
}
}
zy0-=zyd;
rectzofs-= rectx;
rectpofs-= 4*rectx;
}
}
static void antialias_tagbuf(int xsize, int ysize, char *rectmove)
{
char *row1, *row2, *row3;
char prev, next, step;
int a, x, y;
/* 1: tag pixels to be candidate for AA */
for(y=2; y<ysize; y++) {
/* setup rows */
row1= rectmove + (y-2)*xsize;
row2= row1 + xsize;
row3= row2 + xsize;
for(x=2; x<xsize; x++, row1++, row2++, row3++) {
if(row2[1]) {
if(row2[0]==0 || row2[2]==0 || row1[1]==0 || row3[1]==0)
row2[1]= 128;
}
}
}
/* 2: evaluate horizontal scanlines and calculate alphas */
row1= rectmove;
for(y=0; y<ysize; y++) {
row1++;
for(x=1; x<xsize; x++, row1++) {
if(row1[0]==128 && row1[1]==128) {
/* find previous color and next color and amount of steps to blend */
prev= row1[-1];
step= 1;
while(x+step<xsize && row1[step]==128)
step++;
if(x+step!=xsize) {
/* now we can blend values */
next= row1[step];
if(prev!=next) {
for(a=0; a<step; a++) {
int fac, mfac;
fac= ((a+1)<<8)/(step+1);
mfac= 255-fac;
row1[a]= (prev*mfac + next*fac)>>8;
}
}
}
}
}
}
/* 2: evaluate vertical scanlines and calculate alphas */
for(x=0; x<xsize; x++) {
row1= rectmove + x+xsize;
for(y=1; y<ysize; y++, row1+=xsize) {
if(row1[0]==128 && row1[xsize]==128) {
/* find previous color and next color and amount of steps to blend */
prev= row1[-xsize];
step= 1;
while(y+step<ysize && row1[step*xsize]==128)
step++;
if(y+step!=ysize) {
/* now we can blend values */
next= row1[step*xsize];
if(prev!=next) {
for(a=0; a<step; a++) {
int fac, mfac;
fac= ((a+1)<<8)/(step+1);
mfac= 255-fac;
row1[a*xsize]= (prev*mfac + next*fac)>>8;
}
}
}
}
}
}
/* last: pixels with 0 we fill in zbuffer, with 1 we skip for mask */
for(y=2; y<ysize; y++) {
/* setup rows */
row1= rectmove + (y-2)*xsize;
row2= row1 + xsize;
row3= row2 + xsize;
for(x=2; x<xsize; x++, row1++, row2++, row3++) {
if(row2[1]==0) {
if(row2[0]>1 || row2[2]>1 || row1[1]>1 || row3[1]>1)
row2[1]= 1;
}
}
}
}
void zbuf_accumulate_vecblur(int samples, int maxspeed, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect)
{
ZSpan zspan;
float jit[16][2];
float v1[3], v2[3], v3[3], v4[3], fx, fy;
float *rectdraw, *rectvz, *dvz, *dimg, *dvec1, *dvec2, *dz1, *dz2, *rectz;
float maxspeedsq= (float)maxspeed*maxspeed;
int y, x, step;
char *rectmove, *dm;
zbuf_alloc_span(&zspan, xsize, ysize);
zspan.zmulx= ((float)xsize)/2.0;
zspan.zmuly= ((float)ysize)/2.0;
zspan.zofsx= 0.0f;
zspan.zofsy= 0.0f;
/* the buffers */
rectz= MEM_mallocT(sizeof(float)*xsize*ysize, "zbuf accum");
zspan.rectz= (int *)rectz;
rectmove= MEM_callocT(xsize*ysize, "rectmove");
rectdraw= MEM_mallocT(4*sizeof(float)*xsize*ysize, "rect draw");
zspan.rectp= (int *)rectdraw;
/* make vertex buffer with averaged speed and zvalues */
rectvz= MEM_callocT(5*sizeof(float)*(xsize+1)*(ysize+1), "vertices");
dvz= rectvz;
for(y=0; y<=ysize; y++) {
if(y==0) {
dvec1= vecbufrect + 4*y*xsize;
dz1= zbufrect + y*xsize;
}
else {
dvec1= vecbufrect + 4*(y-1)*xsize;
dz1= zbufrect + (y-1)*xsize;
}
if(y==ysize) {
dvec2= vecbufrect + 4*(y-1)*xsize;
dz2= zbufrect + (y-1)*xsize;
}
else {
dvec2= vecbufrect + 4*y*xsize;
dz2= zbufrect + y*xsize;
}
for(x=0; x<=xsize; x++, dz1++, dz2++) {
/* two vectors, so a step loop */
for(step=0; step<2; step++, dvec1+=2, dvec2+=2, dvz+=2) {
/* average on minimal speed */
int div= 0;
if(x!=0) {
if(dvec1[-4]!=0.0f || dvec1[-3]!=0.0f) {
dvz[0]= dvec1[-4];
dvz[1]= dvec1[-3];
div++;
}
if(dvec2[-4]!=0.0f || dvec2[-3]!=0.0f) {
if(div==0) {
dvz[0]= dvec2[-4];
dvz[1]= dvec2[-3];
div++;
}
else if( (ABS(dvec2[-4]) + ABS(dvec2[-3]))< (ABS(dvz[0]) + ABS(dvz[1])) ) {
dvz[0]= dvec2[-4];
dvz[1]= dvec2[-3];
}
}
}
if(x!=xsize) {
if(dvec1[0]!=0.0f || dvec1[1]!=0.0f) {
if(div==0) {
dvz[0]= dvec1[0];
dvz[1]= dvec1[1];
div++;
}
else if( (ABS(dvec1[0]) + ABS(dvec1[1]))< (ABS(dvz[0]) + ABS(dvz[1])) ) {
dvz[0]= dvec1[0];
dvz[1]= dvec1[1];
}
}
if(dvec2[0]!=0.0f || dvec2[1]!=0.0f) {
if(div==0) {
dvz[0]= dvec2[0];
dvz[1]= dvec2[1];
}
else if( (ABS(dvec2[0]) + ABS(dvec2[1]))< (ABS(dvz[0]) + ABS(dvz[1])) ) {
dvz[0]= dvec2[0];
dvz[1]= dvec2[1];
}
}
}
if(maxspeed) {
float speedsq= dvz[0]*dvz[0] + dvz[1]*dvz[1];
if(speedsq > maxspeedsq) {
speedsq= (float)maxspeed/sqrt(speedsq);
dvz[0]*= speedsq;
dvz[1]*= speedsq;
}
}
}
/* the z coordinate */
if(x!=0) {
if(x!=xsize)
dvz[0]= 0.25f*(dz1[-1] + dz2[-1] + dz1[0] + dz2[0]);
else dvz[0]= 0.5f*(dz1[0] + dz2[0]);
}
else dvz[0]= 0.5f*(dz1[-1] + dz2[-1]);
dvz++;
}
}
/* set border speeds to keep border speeds on border */
dz1= rectvz;
dz2= rectvz+5*(ysize)*(xsize+1);
for(x=0; x<=xsize; x++, dz1+=5, dz2+=5) {
dz1[1]= 0.0f;
dz2[1]= 0.0f;
dz1[3]= 0.0f;
dz2[3]= 0.0f;
}
dz1= rectvz;
dz2= rectvz+5*(xsize);
for(y=0; y<=ysize; y++, dz1+=5*(xsize+1), dz2+=5*(xsize+1)) {
dz1[0]= 0.0f;
dz2[0]= 0.0f;
dz1[2]= 0.0f;
dz2[2]= 0.0f;
}
/* tag moving pixels, only these faces we draw */
dm= rectmove;
dvec1= vecbufrect;
for(x=xsize*ysize; x>0; x--, dm++, dvec1+=4) {
if(dvec1[0]!=0.0f || dvec1[1]!=0.0f)
*dm= 255;
}
antialias_tagbuf(xsize, ysize, rectmove);
BLI_initjit(jit[0], 16);
/* accumulate */
samples/= 2;
for(step= 1; step<=samples; step++) {
float speedfac= 0.5f*(float)step/(float)(samples+1);
float blendfac= 1.0f/(ABS(step)+1);
float mfac= 1.0f-blendfac;
int side, z= 4;
for(side=0; side<2; side++) {
/* clear zbuf, if we draw future we fill in not moving pixels */
if(0)
for(x= xsize*ysize-1; x>=0; x--) rectz[x]= 10e16;
else
for(x= xsize*ysize-1; x>=0; x--) {
if(rectmove[x]==0)
rectz[x]= zbufrect[x];
else
rectz[x]= 10e16;
}
/* clear drawing buffer */
for(x= 4*xsize*ysize-1; x>=0; x--) rectdraw[x]= 0.0f;
dimg= imgrect;
dm= rectmove;
dz1= rectvz;
dz2= rectvz + 5*(xsize + 1);
if(side) {
dz1+= 2;
dz2+= 2;
z= 2;
speedfac= -speedfac;
}
for(fy= -0.5f+jit[step & 15][0], y=0; y<ysize; y++, fy+=1.0f) {
for(fx= -0.5f+jit[step & 15][1], x=0; x<xsize; x++, fx+=1.0f, dimg+=4, dz1+=5, dz2+=5, dm++) {
if(*dm>1) {
float alpha= (*dm==255?1.0f:((float)*dm)/255.0f);
/* make vertices */
v1[0]= speedfac*dz1[0]+fx; v1[1]= speedfac*dz1[1]+fy; v1[2]= dz1[z];
v2[0]= speedfac*dz1[5]+fx+1.0f; v2[1]= speedfac*dz1[6]+fy; v2[2]= dz1[z+5];
v3[0]= speedfac*dz2[5]+fx+1.0f; v3[1]= speedfac*dz2[6]+fy+1.0f; v3[2]= dz2[z+5];
v4[0]= speedfac*dz2[0]+fx; v4[1]= speedfac*dz2[1]+fy+1.0f; v4[2]= dz2[z];
zbuf_fill_in_rgba(&zspan, dimg, alpha, v1, v2, v3, v4);
}
}
dz1+=5;
dz2+=5;
}
/* accum */
for(dz1= rectdraw, dz2=newrect, x= xsize*ysize-1; x>=0; x--, dz1+=4, dz2+=4) {
if(dz1[3]!=0.0f) {
if(dz1[3]==1.0f) {
dz2[0]= mfac*dz2[0] + blendfac*dz1[0];
dz2[1]= mfac*dz2[1] + blendfac*dz1[1];
dz2[2]= mfac*dz2[2] + blendfac*dz1[2];
dz2[3]= mfac*dz2[3] + blendfac*dz1[3];
}
else {
float bfac= dz1[3]*blendfac;
float mf= 1.0f - bfac;
dz2[0]= mf*dz2[0] + bfac*dz1[0];
dz2[1]= mf*dz2[1] + bfac*dz1[1];
dz2[2]= mf*dz2[2] + bfac*dz1[2];
dz2[3]= mf*dz2[3] + bfac*dz1[3];
}
}
}
}
}
MEM_freeT(rectz);
MEM_freeT(rectmove);
MEM_freeT(rectdraw);
MEM_freeT(rectvz);
zbuf_free_span(&zspan);
}
/* ******************** ABUF ************************* */

View File

@@ -795,6 +795,23 @@ static int node_composit_buts_blur(uiBlock *block, bNodeTree *ntree, bNode *node
return 38;
}
static int node_composit_buts_vecblur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
{
if(block) {
short dy= butr->ymin;
short dx= (butr->xmax-butr->xmin);
uiBlockBeginAlign(block);
uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Samples:",
butr->xmin, dy+19, dx, 19,
&node->custom1, 1, 256, 0, 0, "Amount of samples");
uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "MaxSpeed:",
butr->xmin, dy, dx, 19,
&node->custom2, 0, 1024, 0, 0, "If not zero, maximum speed in pixels");
}
return 38;
}
static int node_composit_buts_filter(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
{
if(block) {
@@ -892,6 +909,9 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_BLUR:
ntype->butfunc= node_composit_buts_blur;
break;
case CMP_NODE_VECBLUR:
ntype->butfunc= node_composit_buts_vecblur;
break;
case CMP_NODE_FILTER:
ntype->butfunc= node_composit_buts_filter;
break;

View File

@@ -154,6 +154,7 @@ static void snode_handle_recalc(SpaceNode *snode)
}
snode->nodetree->timecursor= NULL;
waitcursor(0);
}
}
}

View File

@@ -264,6 +264,8 @@ static Scene *preview_prepare_scene(RenderInfo *ri, int id_type, ID *id, int pr_
if(id_type==ID_MA) {
Material *mat= (Material *)id;
sce->r.mode |= R_SHADOW;
if(id) {
if(pr_method==PR_ICON_RENDER) {
sce->lay= 1<<MA_SPHERE_A;
@@ -299,6 +301,7 @@ static Scene *preview_prepare_scene(RenderInfo *ri, int id_type, ID *id, int pr_
Lamp *la= (Lamp *)id;
sce->lay= 1<<MA_LAMP;
sce->r.mode &= ~R_SHADOW;
for(base= sce->base.first; base; base= base->next) {
if(base->object->id.name[2]=='p') {