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; itotchild; 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; atotbound= 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; atotvert; 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; bstrandbuf->totbound; b++, sbound++) { + INIT_MINMAX(smin, smax); + + for(a=sbound->start; aend; 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; atotstrand; 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; cstrandbuf->totbound; c++, sbound++) { + if(clip_render_object(sbound->boundbox, bounds, winmat)) continue; - svert= strand->vert; + /* for each strand in this bounding box */ + for(a=sbound->start; aend; a++) { + strand= RE_findOrAddStrand(obr, a); + 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; btotvert-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 */ + /* 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]; - clip[1]= clip[2]; z[1]= z[2]; - clip[2]= clip[3]; z[2]= z[3]; + + for(b=0; btotvert-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]; + } } } } @@ -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; atotvert; 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; vtotvlak; 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; atotstrand; 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; cstrandbuf->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; aend; a++) { + strand= RE_findOrAddStrand(obr, a); - /* 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; - } + sseg.obi= obi; + sseg.buffer= strand->buffer; + sseg.sqadaptcos= sseg.buffer->adaptcos; + sseg.sqadaptcos *= sseg.sqadaptcos; + sseg.strand= strand; + svert= strand->vert; - if(ok && (sseg.buffer->lay & lay)) { - zbuf_project_cache_clear(cache, strand->totvert); + /* 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; + } - for(b=0; btotvert-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; + if(ok && (sseg.buffer->lay & lay)) { + zbuf_project_cache_clear(cache, strand->totvert); - 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); + for(b=0; btotvert-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; - if(!(c1 & c2 & c3 & c4)) - render_strand_segment(re, winmat, NULL, &zspan, 1, &sseg); + 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((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; vtotvlak; 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; vtotvlak; v++) {