From 0f2b2e3c60173e85e137df71392d867576e65ac1 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 20 Dec 2007 16:35:27 +0000 Subject: Strand Render Simplification ============================ - Strand render now has options to remove child strands as the object's faces becomes smaller, in the Simplification particle panel. - "Reference Size" is the approximate size of the object on screen, after which simplification starts. - "Rate" is how fast strands are removed. - "Transition" is the percentage of strands being faded out as they are removed. - Another "Viewport" option removes strands on faces that are outside of the viewport. "Rate" again controls how fast these are removed. - Strand render in Blender Units now has an adjustable minimum width. Below this minimum width, strands start fading out instead of getting smaller. --- .../blender/render/intern/include/render_types.h | 2 +- .../blender/render/intern/include/renderdatabase.h | 2 + source/blender/render/intern/include/strand.h | 3 ++ .../blender/render/intern/source/convertblender.c | 45 ++++++++++++-------- .../blender/render/intern/source/renderdatabase.c | 18 ++++++++ source/blender/render/intern/source/strand.c | 49 ++++++++++++++++------ 6 files changed, 89 insertions(+), 30 deletions(-) (limited to 'source/blender/render/intern') diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 4a731878ffb..7fbbd0f5abc 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -343,7 +343,7 @@ typedef struct StrandBuffer { unsigned int lay; int overrideuv; int flag, maxdepth; - float adaptcos; + float adaptcos, minwidth; float winmat[4][4]; int winx, winy; diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h index 0346f2d6413..c919a54008e 100644 --- a/source/blender/render/intern/include/renderdatabase.h +++ b/source/blender/render/intern/include/renderdatabase.h @@ -69,6 +69,7 @@ typedef struct StrandTableNode { struct StrandRen *strand; float *winspeed; float *surfnor; + float *simplify; struct MCol *mcol; float *uv; int totuv, totmcol; @@ -112,6 +113,7 @@ int RE_vlakren_get_normal(struct Render *re, struct ObjectInstanceRen *obi, stru float *RE_strandren_get_surfnor(struct ObjectRen *obr, struct StrandRen *strand, int verify); float *RE_strandren_get_uv(struct ObjectRen *obr, struct StrandRen *strand, int n, char **name, int verify); struct MCol *RE_strandren_get_mcol(struct ObjectRen *obr, struct StrandRen *strand, int n, char **name, int verify); +float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify); float *RE_strandren_get_winspeed(struct ObjectInstanceRen *obi, struct StrandRen *strand, int verify); struct VertRen *RE_vertren_copy(struct ObjectRen *obr, struct VertRen *ver); diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h index 7f37317d4d5..34a147c1933 100644 --- a/source/blender/render/intern/include/strand.h +++ b/source/blender/render/intern/include/strand.h @@ -68,6 +68,9 @@ typedef struct StrandPoint { /* screen space */ float hoco[4]; float x, y; + + /* simplification */ + float alpha; } StrandPoint; typedef struct StrandSegment { diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index de3bd6079a4..eb5bb3f2f71 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -983,7 +983,7 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo { static VertRen *v1= NULL, *v2= NULL; VlakRen *vlr; - float nor[3], cross[3], w, dx, dy, width; + float nor[3], cross[3], crosslen, w, dx, dy, width; static float anor[3], avec[3]; int flag, i; static int second=0; @@ -992,14 +992,11 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo Normalize(nor); // nor needed as tangent Crossf(cross, vec, nor); - if(ma->mode&MA_STR_B_UNITS) - Normalize(cross); - /* turn cross in pixelsize */ w= vec[2]*re->winmat[2][3] + re->winmat[3][3]; - dx= re->winx*cross[0]*re->winmat[0][0]/w; - dy= re->winy*cross[1]*re->winmat[1][1]/w; - w= sqrt(dx*dx + dy*dy); + dx= re->winx*cross[0]*re->winmat[0][0]; + dy= re->winy*cross[1]*re->winmat[1][1]; + w= sqrt(dx*dx + dy*dy)/w; if(w!=0.0f) { float fac; @@ -1013,12 +1010,16 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo width= ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end); - /* use actual Blender units for strand width and fall back to min 1px */ + /* use actual Blender units for strand width and fall back to minimum width */ if(ma->mode & MA_STR_B_UNITS){ - if(width < 1.0f/w) - width= 1.0f/w; + crosslen= VecLength(cross); + w= 2.0f*crosslen*ma->strand_min/w; + + if(width < w) + width= w; + /*cross is the radius of the strand so we want it to be half of full width */ - VecMulf(cross,0.5); + VecMulf(cross,0.5/crosslen); } else width/=w; @@ -1496,7 +1497,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem float *orco=0,*surfnor=0,*uvco=0, strandlen=0.0f, curlen=0.0f; float hasize, pa_size, pa_time, r_tilt, cfra=bsystem_time(ob,(float)CFRA,0.0); float loc_tex[3], size_tex[3], adapt_angle=0.0, adapt_pix=0.0, random; - int i, a, k, max_k=0, totpart, totuv=0, override_uv=-1; + float simplify[2]; + int i, a, k, max_k=0, totpart, totuv=0, override_uv=-1, dosimplify = 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}; char **uv_name=0; @@ -1639,9 +1641,10 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem Mat4CpyMat4(strandbuf->winmat, re->winmat); strandbuf->winx= re->winx; strandbuf->winy= re->winy; - strandbuf->maxdepth= 2; /* TODO */ + strandbuf->maxdepth= 2; strandbuf->adaptcos= cos((float)part->adapt_angle*(float)(M_PI/180.0)); strandbuf->overrideuv= override_uv; + strandbuf->minwidth= ma->strand_min; if(part->flag & PART_HAIR_BSPLINE) strandbuf->flag |= R_STRAND_BSPLINE; @@ -1720,7 +1723,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if(totchild && (part->draw&PART_DRAW_PARENT)==0) continue; } - else{ + else { ChildParticle *cpa= psys->child+a-totpart; pa_time=psys_get_child_time(psys, cpa, cfra); @@ -1778,6 +1781,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem } } + dosimplify= psys_render_simplify_params(psys, cpa, simplify); + if(path_nbr) { cache = psys->childcache[a-totpart]; max_k = (int)cache->steps; @@ -1805,6 +1810,12 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem strand->vert= svert; VECCOPY(strand->orco, orco); + if(dosimplify) { + float *ssimplify= RE_strandren_get_simplify(obr, strand, 1); + ssimplify[0]= simplify[0]; + ssimplify[1]= simplify[1]; + } + if(surfnor) { float *snor= RE_strandren_get_surfnor(obr, strand, 1); VECCOPY(snor, surfnor); @@ -3886,7 +3897,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, int index, in show_emitter= 0; for(psys=ob->particlesystem.first; psys; psys=psys->next) { show_emitter += psys->part->draw & PART_DRAW_EMITTER; - psys_particles_to_render_backup(ob, psys); + psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy); } /* if no psys has "show emitter" selected don't render emitter */ @@ -3910,7 +3921,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, int index, in for(psys=ob->particlesystem.first; psys; psys=psys->next, psysindex++) { obr= RE_addRenderObject(re, ob, par, index, psysindex); init_render_object_data(re, obr, only_verts); - psys_render_backup_to_particles(ob, psys); + psys_render_restore(ob, psys); /* only add instance for objects that have not been used for dupli */ if(!(ob->transflag & OB_RENDER_DUPLI)) @@ -4666,7 +4677,7 @@ void RE_Database_FromScene_Vectors(Render *re, Scene *sce) } else { /* check if both have same amounts of vertices */ if(obi->totvector!=oldobi->totvector) { - printf("Warning: object %s has different amount of vertices on other frame\n", obi->ob->id.name+2); + printf("Warning: object %s has different amount of vertices or strands on other frame\n", obi->ob->id.name+2); continue; } diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index 3906b1fc001..79c87252fc2 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -104,6 +104,7 @@ #define RE_MCOL_ELEMS 4 #define RE_UV_ELEMS 2 #define RE_SURFNOR_ELEMS 3 +#define RE_SIMPLIFY_ELEMS 2 float *RE_vertren_get_sticky(ObjectRen *obr, VertRen *ver, int verify) { @@ -590,6 +591,21 @@ MCol *RE_strandren_get_mcol(ObjectRen *obr, StrandRen *strand, int n, char **nam return node->mcol + index*RE_MCOL_ELEMS; } +float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify) +{ + float *simplify; + int nr= strand->index>>8; + + simplify= obr->strandnodes[nr].simplify; + if(simplify==NULL) { + if(verify) + simplify= obr->strandnodes[nr].simplify= MEM_callocN(256*RE_SIMPLIFY_ELEMS*sizeof(float), "simplify table"); + else + return NULL; + } + return simplify + (strand->index & 255)*RE_SIMPLIFY_ELEMS; +} + /* winspeed is exception, it is stored per instance */ float *RE_strandren_get_winspeed(ObjectInstanceRen *obi, StrandRen *strand, int verify) { @@ -743,6 +759,8 @@ void free_renderdata_strandnodes(StrandTableNode *strandnodes) MEM_freeN(strandnodes[a].winspeed); if(strandnodes[a].surfnor) MEM_freeN(strandnodes[a].surfnor); + if(strandnodes[a].simplify) + MEM_freeN(strandnodes[a].simplify); } MEM_freeN(strandnodes); diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c index 42c6d559f65..4f0e9764a43 100644 --- a/source/blender/render/intern/source/strand.c +++ b/source/blender/render/intern/source/strand.c @@ -321,7 +321,8 @@ void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint) { Material *ma; StrandBuffer *strandbuf; - float p[4][3], data[4], cross[3], w, dx, dy, t; + float *simplify; + float p[4][3], data[4], cross[3], crosslen, w, dx, dy, t; int type; strandbuf= sseg->buffer; @@ -378,25 +379,34 @@ void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint) Normalize(spoint->nor); spoint->width= strand_eval_width(ma, spoint->strandco); + + /* simplification */ + simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0); + spoint->alpha= (simplify)? simplify[1]: 1.0f; /* outer points */ Crossf(cross, spoint->co, spoint->tan); - if(strandbuf->flag & R_STRAND_B_UNITS) - Normalize(cross); - w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3]; - dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w; - dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w; - w= sqrt(dx*dx + dy*dy); + dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]; + dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]; + w= sqrt(dx*dx + dy*dy)/w; if(w > 0.0f) { if(strandbuf->flag & R_STRAND_B_UNITS) { - w= 1.0f/w; + crosslen= VecLength(cross); + w= 2.0f*crosslen*strandbuf->minwidth/w; - if(spoint->width < w) + if(spoint->width < w) { + spoint->alpha= spoint->width/w; spoint->width= w; - VecMulf(cross, spoint->width*0.5f); + } + + if(simplify) + /* squared because we only change width, not length */ + spoint->width *= simplify[0]*simplify[0]; + + VecMulf(cross, spoint->width*0.5f/crosslen); } else VecMulf(cross, spoint->width/w); @@ -528,7 +538,7 @@ static void strand_project_point(float winmat[][4], float winx, float winy, Stra } #include "BLI_rand.h" -void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint); +static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint); static void strand_shade_get(StrandPart *spart, int lookup, ShadeSample *ssamp, StrandPoint *spoint, StrandVert *svert, StrandSegment *sseg) { @@ -653,7 +663,7 @@ static int strand_test_clip(float winmat[][4], ZSpan *zspan, float *bounds, floa return clipflag; } -void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint) +static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint) { ShadeInput *shi= ssamp->shi; ShadeResult *shr= ssamp->shr; @@ -685,6 +695,21 @@ void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, Str shade_samples_do_AO(ssamp); shade_input_do_shade(shi, shr); + /* apply simplification */ + if(spoint->alpha < 1.0f) { + shr->combined[0] *= spoint->alpha; + shr->combined[1] *= spoint->alpha; + shr->combined[2] *= spoint->alpha; + shr->combined[3] *= spoint->alpha; + + shr->col[0] *= spoint->alpha; + shr->col[1] *= spoint->alpha; + shr->col[2] *= spoint->alpha; + shr->col[3] *= spoint->alpha; + + shr->alpha *= spoint->alpha; + } + /* include lamphalos for strand, since halo layer was added already */ if(re->flag & R_LAMPHALO) if(shi->layflag & SCE_LAY_HALO) -- cgit v1.2.3