diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-01-29 15:20:42 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-01-29 15:20:42 +0300 |
commit | 8e94028ed57861595e959d30476a74c48868a991 (patch) | |
tree | 6e773858db822dba27b314f76356650a67418462 | |
parent | 5bf5b030e5dd87d4ff80fc44a5b5fb242ad385c2 (diff) |
Bounding box clipping in the render engine.
Now bounding boxes are computed per object, and checked first before
zbuffering objects. For strands, bounding boxes are computed per
original face in the mesh. Overall the speed improvement from this
is quite small (zbuffering is rarely the bottleneck), but it seems a
sensible thing to do anyway.
-rw-r--r-- | source/blender/blenkernel/intern/particle_system.c | 22 | ||||
-rw-r--r-- | source/blender/render/intern/include/render_types.h | 11 | ||||
-rw-r--r-- | source/blender/render/intern/include/renderdatabase.h | 1 | ||||
-rw-r--r-- | source/blender/render/intern/include/strand.h | 1 | ||||
-rw-r--r-- | source/blender/render/intern/source/convertblender.c | 61 | ||||
-rw-r--r-- | source/blender/render/intern/source/renderdatabase.c | 27 | ||||
-rw-r--r-- | source/blender/render/intern/source/strand.c | 96 | ||||
-rw-r--r-- | source/blender/render/intern/source/zbuf.c | 87 |
8 files changed, 210 insertions, 96 deletions
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 3db42f091d4..c0ffb7c62f8 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -780,6 +780,21 @@ void *exec_distribution(void *data) return 0; } +/* not thread safe, but qsort doesn't take userdata argument */ +static int *COMPARE_ORIG_INDEX = NULL; +static int compare_orig_index(const void *p1, const void *p2) +{ + int index1 = COMPARE_ORIG_INDEX[*(const int*)p1]; + int index2 = COMPARE_ORIG_INDEX[*(const int*)p2]; + + if(index1 < index2) + return -1; + else if(index1 == index2) + return 0; + else + return 1; +} + /* creates a distribution of coordinates on a DerivedMesh */ /* */ /* 1. lets check from what we are emitting */ @@ -1157,6 +1172,13 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm MEM_freeN(sum); + /* for hair, sort by origindex, allows optimizations in rendering */ + if(part->type == PART_HAIR) { + COMPARE_ORIG_INDEX= dm->getFaceDataArray(dm, CD_ORIGINDEX); + if(COMPARE_ORIG_INDEX) + qsort(index, totpart, sizeof(int), compare_orig_index); + } + /* weights are no longer used except for FROM_PARTICLE, which needs them zeroed for indexing */ if(from==PART_FROM_PARTICLE){ for(i=0; i<tot; i++) diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 3a8a491a852..7b68552e5fb 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -247,13 +247,15 @@ typedef struct ObjectRen { struct Scene *sce; int index, psysindex, flag, lay; + float boundbox[2][3]; + int totvert, totvlak, totstrand, tothalo; int vertnodeslen, vlaknodeslen, strandnodeslen, blohalen; struct VertTableNode *vertnodes; struct VlakTableNode *vlaknodes; struct StrandTableNode *strandnodes; struct HaloRen **bloha; - ListBase strandbufs; + struct StrandBuffer *strandbuf; char (*mtface)[32]; char (*mcol)[32]; @@ -346,7 +348,7 @@ typedef struct StrandSurface { int (*face)[4]; float (*co)[3]; /* for occlusion caching */ - float (*col)[3]; /* for occlusion */ + float (*col)[3]; /* for speedvectors */ float (*prevco)[3], (*nextco)[3]; int totvert, totface; @@ -354,13 +356,14 @@ typedef struct StrandSurface { typedef struct StrandBound { int start, end; - float bbox[2][3]; + float boundbox[2][3]; } StrandBound; typedef struct StrandBuffer { struct StrandBuffer *next, *prev; struct StrandVert *vert; - int totvert; + struct StrandBound *bound; + int totvert, totbound; struct ObjectRen *obr; struct Material *ma; diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h index cfcbb4e7775..a204aa7876b 100644 --- a/source/blender/render/intern/include/renderdatabase.h +++ b/source/blender/render/intern/include/renderdatabase.h @@ -85,6 +85,7 @@ void free_renderdata_vlaknodes(struct VlakTableNode *vlaknodes); void set_normalflags(struct Render *re, struct ObjectRen *obr); void project_renderdata(struct Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, float xoffs, int do_buckets); +int clip_render_object(float boundbox[][3], float *bounds, float mat[][4]); /* functions are not exported... so wrong names */ diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h index f001bc42112..ebe026e3fec 100644 --- a/source/blender/render/intern/include/strand.h +++ b/source/blender/render/intern/include/strand.h @@ -93,6 +93,7 @@ typedef struct StrandShadeCache StrandShadeCache; void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint); void render_strand_segment(struct Render *re, float winmat[][4], struct StrandPart *spart, struct ZSpan *zspan, int totzspan, StrandSegment *sseg); +void strand_minmax(struct StrandRen *strand, float *min, float *max); struct StrandSurface *cache_strand_surface(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, float mat[][4], int timeoffset); void free_strand_surface(struct Render *re); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 6a8059bbdab..7b81acdbc1c 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -111,6 +111,7 @@ #include "strand.h" #include "texture.h" #include "sss.h" +#include "strand.h" #include "zbuf.h" #ifndef DISABLE_YAFRAY /* disable yafray */ @@ -1482,6 +1483,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem ParticleCacheKey *cache=0; StrandBuffer *strandbuf=0; StrandVert *svert=0; + StrandBound *sbound= 0; StrandRen *strand=0; RNG *rng= 0; float loc[3],loc1[3],loc0[3],vel[3],mat[4][4],nmat[3][3],co[3],nor[3],time; @@ -1491,6 +1493,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem int i, a, k, max_k=0, totpart, totuv=0, override_uv=-1, dosimplify = 0, dosurfacecache = 0; int path_possible=0, keys_possible=0, baked_keys=0, totchild=psys->totchild; int seed, path_nbr=0, path=0, orco1=0, adapt=0, uv[3]={0,0,0}, num; + int totface, *origindex = 0; char **uv_name=0; /* 1. check that everything is ok & updated */ @@ -1653,6 +1656,18 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem else if((re->wrld.mode & WO_AMB_OCC) && (re->wrld.ao_gather_method == WO_AOGATHER_APPROX)) if(ma->amb != 0.0f) dosurfacecache= 1; + + totface= psmd->dm->getNumFaces(psmd->dm); + origindex= psmd->dm->getFaceDataArray(psmd->dm, CD_ORIGINDEX); + if(origindex) { + for(a=0; a<totface; a++) + strandbuf->totbound= MAX2(strandbuf->totbound, origindex[a]); + strandbuf->totbound++; + } + strandbuf->totbound++; + strandbuf->bound= MEM_callocN(sizeof(StrandBound)*strandbuf->totbound, "StrandBound"); + sbound= strandbuf->bound; + sbound->start= sbound->end= 0; } } } @@ -1802,6 +1817,13 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem cache = psys->childcache[a-totpart]; max_k = (int)cache->steps; } + + if(strandbuf) { + if(origindex[cpa->num]+1 > sbound - strandbuf->bound) { + sbound= strandbuf->bound + origindex[cpa->num]+1; + sbound->start= sbound->end= obr->totstrand; + } + } } /* surface normal shading setup */ @@ -1845,6 +1867,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem } } } + + sbound->end++; } /* strandco computation setup */ @@ -3841,6 +3865,11 @@ static void check_non_flat_quads(ObjectRen *obr) static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset) { Object *ob= obr->ob; + VertRen *ver= NULL; + StrandRen *strand= NULL; + StrandBound *sbound= NULL; + float min[3], max[3], smin[3], smax[3]; + int a, b; if(obr->totvert || obr->totvlak || obr->tothalo || obr->totstrand) { /* the exception below is because displace code now is in init_render_mesh call, @@ -3858,6 +3887,36 @@ static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset) check_non_flat_quads(obr); set_fullsample_flag(re, obr); + + /* compute bounding boxes for clipping */ + INIT_MINMAX(min, max); + for(a=0; a<obr->totvert; a++) { + if((a & 255)==0) ver= obr->vertnodes[a>>8].vert; + else ver++; + + DO_MINMAX(ver->co, min, max); + } + + if(obr->strandbuf) { + sbound= obr->strandbuf->bound; + for(b=0; b<obr->strandbuf->totbound; b++, sbound++) { + INIT_MINMAX(smin, smax); + + for(a=sbound->start; a<sbound->end; a++) { + strand= RE_findOrAddStrand(obr, a); + strand_minmax(strand, smin, smax); + } + + VECCOPY(sbound->boundbox[0], smin); + VECCOPY(sbound->boundbox[1], smax); + + DO_MINMAX(smin, min, max); + DO_MINMAX(smax, min, max); + } + } + + VECCOPY(obr->boundbox[0], min); + VECCOPY(obr->boundbox[1], max); } } } @@ -4674,7 +4733,7 @@ static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *ve } if(obr->strandnodes) { - strandbuf= obr->strandbufs.first; + strandbuf= obr->strandbuf; mesh= (strandbuf)? strandbuf->surface: NULL; /* compute speed vectors at surface vertices */ diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index 9495360f089..5a749515416 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -711,7 +711,7 @@ StrandBuffer *RE_addStrandBuffer(ObjectRen *obr, int totvert) strandbuf->totvert= totvert; strandbuf->obr= obr; - BLI_addtail(&obr->strandbufs, strandbuf); + obr->strandbuf= strandbuf; return strandbuf; } @@ -842,9 +842,12 @@ void free_renderdata_tables(Render *re) obr->strandnodeslen= 0; } - for(strandbuf=obr->strandbufs.first; strandbuf; strandbuf=strandbuf->next) + strandbuf= obr->strandbuf; + if(strandbuf) { if(strandbuf->vert) MEM_freeN(strandbuf->vert); - BLI_freelistN(&obr->strandbufs); + if(strandbuf->bound) MEM_freeN(strandbuf->bound); + MEM_freeN(strandbuf); + } if(obr->mtface) MEM_freeN(obr->mtface); @@ -1342,13 +1345,11 @@ void RE_makeRenderInstances(Render *re) re->instancetable= newlist; } -#if 0 -int clip_render_object(ObjectInstanceRen *obi, float *bounds, float winmat[][4]) +int clip_render_object(float boundbox[][3], float *bounds, float winmat[][4]) { - float mat[4][4], vec[4], max, min, (*boundbox)[3]; + float mat[4][4], vec[4]; int a, fl, flag= -1; - boundbox= obi->obr->boundbox; Mat4CpyMat4(mat, winmat); for(a=0; a<8; a++) { @@ -1374,22 +1375,10 @@ int clip_render_object(ObjectInstanceRen *obi, float *bounds, float winmat[][4]) if(vec[2] < -vec[3]) fl |= 16; if(vec[2] > vec[3]) fl |= 32; -#if 0 - max= vec[3]; - min= -vec[3]; - - wco= ho[3]; - if(vec[0] < min) fl |= 1; - if(vec[0] > max) fl |= 2; - if(vec[1] < min) fl |= 4; - if(vec[1] > max) fl |= 8; -#endif - flag &= fl; if(flag==0) return 0; } return flag; } -#endif diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c index 91b3dfbe621..e66d12de15b 100644 --- a/source/blender/render/intern/source/strand.c +++ b/source/blender/render/intern/source/strand.c @@ -750,12 +750,13 @@ int zbuffer_strands_abuf(Render *re, RenderPart *pa, RenderLayer *rl, APixstrand ZSpan zspan; StrandRen *strand=0; StrandVert *svert; + StrandBound *sbound; StrandPart spart; StrandSegment sseg; StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg; MemArena *memarena; float z[4], bounds[4], winmat[4][4]; - int a, b, i, totsegment, clip[4]; + int a, b, c, i, totsegment, clip[4]; if(re->test_break()) return 0; @@ -800,58 +801,66 @@ int zbuffer_strands_abuf(Render *re, RenderPart *pa, RenderLayer *rl, APixstrand sortseg= sortsegments; totsegment= 0; + /* for all object instances */ for(obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) { obr= obi->obr; + if(!obr->strandbuf || !(obr->strandbuf->lay & rl->lay)) + continue; + + /* compute matrix and try clipping whole object */ if(obi->flag & R_TRANSFORMED) zbuf_make_winmat(re, obi->mat, winmat); else zbuf_make_winmat(re, NULL, winmat); - for(a=0; a<obr->totstrand; a++) { - if((a & 255)==0) strand= obr->strandnodes[a>>8].strand; - else strand++; + if(clip_render_object(obi->obr->boundbox, bounds, winmat)) + continue; - if(re->test_break()) - break; - - if(!(strand->buffer->lay & rl->lay)) + /* for each bounding box containing a number of strands */ + sbound= obr->strandbuf->bound; + for(c=0; c<obr->strandbuf->totbound; c++, sbound++) { + if(clip_render_object(sbound->boundbox, bounds, winmat)) continue; - svert= strand->vert; - - /* keep clipping and z depth for 4 control points */ - clip[1]= strand_test_clip(winmat, &zspan, bounds, svert->co, &z[1]); - clip[2]= strand_test_clip(winmat, &zspan, bounds, (svert+1)->co, &z[2]); - clip[0]= clip[1]; z[0]= z[1]; - - for(b=0; b<strand->totvert-1; b++, svert++) { - /* compute 4th point clipping and z depth */ - if(b < strand->totvert-2) { - clip[3]= strand_test_clip(winmat, &zspan, bounds, (svert+2)->co, &z[3]); - } - else { - clip[3]= clip[2]; z[3]= z[2]; - } - - /* check clipping and add to sortsegments buffer */ - if(!(clip[0] & clip[1] & clip[2] & clip[3])) { - sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment)); - sortseg->obi= i; - sortseg->strand= strand->index; - sortseg->segment= b; + /* for each strand in this bounding box */ + for(a=sbound->start; a<sbound->end; a++) { + strand= RE_findOrAddStrand(obr, a); + svert= strand->vert; - sortseg->z= 0.5f*(z[1] + z[2]); + /* keep clipping and z depth for 4 control points */ + clip[1]= strand_test_clip(winmat, &zspan, bounds, svert->co, &z[1]); + clip[2]= strand_test_clip(winmat, &zspan, bounds, (svert+1)->co, &z[2]); + clip[0]= clip[1]; z[0]= z[1]; - sortseg->next= firstseg; - firstseg= sortseg; - totsegment++; + for(b=0; b<strand->totvert-1; b++, svert++) { + /* compute 4th point clipping and z depth */ + if(b < strand->totvert-2) { + clip[3]= strand_test_clip(winmat, &zspan, bounds, (svert+2)->co, &z[3]); + } + else { + clip[3]= clip[2]; z[3]= z[2]; + } + + /* check clipping and add to sortsegments buffer */ + if(!(clip[0] & clip[1] & clip[2] & clip[3])) { + sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment)); + sortseg->obi= i; + sortseg->strand= strand->index; + sortseg->segment= b; + + sortseg->z= 0.5f*(z[1] + z[2]); + + sortseg->next= firstseg; + firstseg= sortseg; + totsegment++; + } + + /* shift clipping and z depth */ + clip[0]= clip[1]; z[0]= z[1]; + clip[1]= clip[2]; z[1]= z[2]; + clip[2]= clip[3]; z[2]= z[3]; } - - /* shift clipping and z depth */ - clip[0]= clip[1]; z[0]= z[1]; - clip[1]= clip[2]; z[1]= z[2]; - clip[2]= clip[3]; z[2]= z[3]; } } } @@ -973,3 +982,12 @@ void free_strand_surface(Render *re) BLI_freelistN(&re->strandsurface); } +void strand_minmax(StrandRen *strand, float *min, float *max) +{ + StrandVert *svert; + int a; + + for(a=0, svert=strand->vert; a<strand->totvert; a++, svert++) + DO_MINMAX(svert->co, min, max) +} + diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index 21c31d55e87..080a66e46a7 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -2081,6 +2081,9 @@ void zbuffer_solid(RenderPart *pa, RenderLayer *rl, void(*fillfunc)(RenderPart*, else zbuf_make_winmat(&R, NULL, winmat); + if(clip_render_object(obi->obr->boundbox, bounds, winmat)) + continue; + zbuf_project_cache_clear(cache, obr->totvert); for(v=0; v<obr->totvlak; v++) { @@ -2337,8 +2340,9 @@ void zbuffer_shadow(Render *re, float winmat[][4], LampRen *lar, int *rectz, int StrandSegment sseg; StrandRen *strand= NULL; StrandVert *svert; + StrandBound *sbound; float obwinmat[4][4], ho1[4], ho2[4], ho3[4], ho4[4]; - int a, b, i, c1, c2, c3, c4, ok=1, lay= -1; + int a, b, c, i, c1, c2, c3, c4, ok=1, lay= -1; if(lar->mode & LA_LAYER) lay= lar->lay; @@ -2374,6 +2378,9 @@ void zbuffer_shadow(Render *re, float winmat[][4], LampRen *lar, int *rectz, int else Mat4CpyMat4(obwinmat, winmat); + if(clip_render_object(obi->obr->boundbox, NULL, obwinmat)) + continue; + zbuf_project_cache_clear(cache, obr->totvert); /* faces */ @@ -2417,45 +2424,54 @@ void zbuffer_shadow(Render *re, float winmat[][4], LampRen *lar, int *rectz, int } /* strands */ - for(a=0; a<obr->totstrand; a++) { - if((a & 255)==0) strand= obr->strandnodes[a>>8].strand; - else strand++; + if(obr->strandbuf) { + /* for each bounding box containing a number of strands */ + sbound= obr->strandbuf->bound; + for(c=0; c<obr->strandbuf->totbound; c++, sbound++) { + if(clip_render_object(sbound->boundbox, NULL, obwinmat)) + continue; - sseg.obi= obi; - sseg.buffer= strand->buffer; - sseg.sqadaptcos= sseg.buffer->adaptcos; - sseg.sqadaptcos *= sseg.sqadaptcos; - sseg.strand= strand; - svert= strand->vert; + /* for each strand in this bounding box */ + for(a=sbound->start; a<sbound->end; a++) { + strand= RE_findOrAddStrand(obr, a); + + sseg.obi= obi; + sseg.buffer= strand->buffer; + sseg.sqadaptcos= sseg.buffer->adaptcos; + sseg.sqadaptcos *= sseg.sqadaptcos; + sseg.strand= strand; + svert= strand->vert; + + /* note, these conditions are copied in shadowbuf_autoclip() */ + if(sseg.buffer->ma!= ma) { + ma= sseg.buffer->ma; + ok= 1; + if((ma->mode & MA_SHADBUF)==0) ok= 0; + } - /* note, these conditions are copied in shadowbuf_autoclip() */ - if(sseg.buffer->ma!= ma) { - ma= sseg.buffer->ma; - ok= 1; - if((ma->mode & MA_SHADBUF)==0) ok= 0; - } + if(ok && (sseg.buffer->lay & lay)) { + zbuf_project_cache_clear(cache, strand->totvert); - if(ok && (sseg.buffer->lay & lay)) { - zbuf_project_cache_clear(cache, strand->totvert); + for(b=0; b<strand->totvert-1; b++, svert++) { + sseg.v[0]= (b > 0)? (svert-1): svert; + sseg.v[1]= svert; + sseg.v[2]= svert+1; + sseg.v[3]= (b < strand->totvert-2)? svert+2: svert+1; - for(b=0; b<strand->totvert-1; b++, svert++) { - sseg.v[0]= (b > 0)? (svert-1): svert; - sseg.v[1]= svert; - sseg.v[2]= svert+1; - sseg.v[3]= (b < strand->totvert-2)? svert+2: svert+1; + c1= zbuf_shadow_project(cache, sseg.v[0]-strand->vert, obwinmat, sseg.v[0]->co, ho1); + c2= zbuf_shadow_project(cache, sseg.v[1]-strand->vert, obwinmat, sseg.v[1]->co, ho2); + c3= zbuf_shadow_project(cache, sseg.v[2]-strand->vert, obwinmat, sseg.v[2]->co, ho3); + c4= zbuf_shadow_project(cache, sseg.v[3]-strand->vert, obwinmat, sseg.v[3]->co, ho4); - c1= zbuf_shadow_project(cache, sseg.v[0]-strand->vert, obwinmat, sseg.v[0]->co, ho1); - c2= zbuf_shadow_project(cache, sseg.v[1]-strand->vert, obwinmat, sseg.v[1]->co, ho2); - c3= zbuf_shadow_project(cache, sseg.v[2]-strand->vert, obwinmat, sseg.v[2]->co, ho3); - c4= zbuf_shadow_project(cache, sseg.v[3]-strand->vert, obwinmat, sseg.v[3]->co, ho4); + if(!(c1 & c2 & c3 & c4)) + render_strand_segment(re, winmat, NULL, &zspan, 1, &sseg); + } + } - if(!(c1 & c2 & c3 & c4)) - render_strand_segment(re, winmat, NULL, &zspan, 1, &sseg); + if((a & 255)==255 && re->test_break()) + break; } } - - if((a & 255)==255 && re->test_break()) - break; } if(re->test_break()) @@ -2599,6 +2615,9 @@ void zbuffer_sss(RenderPart *pa, unsigned int lay, void *handle, void (*func)(vo else zbuf_make_winmat(&R, NULL, winmat); + if(clip_render_object(obi->obr->boundbox, bounds, winmat)) + continue; + zbuf_project_cache_clear(cache, obr->totvert); for(v=0; v<obr->totvlak; v++) { @@ -3286,7 +3305,6 @@ static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, un /* to center the sample position */ zspan->zofsx -= 0.5f; zspan->zofsy -= 0.5f; - } /* we use this to test if nothing was filled in */ @@ -3303,6 +3321,9 @@ static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, un else zbuf_make_winmat(&R, NULL, winmat); + if(clip_render_object(obi->obr->boundbox, bounds, winmat)) + continue; + zbuf_project_cache_clear(cache, obr->totvert); for(v=0; v<obr->totvlak; v++) { |