Hair render: using strand "Blender Unit" size didn't correctly
clip for larger/wider strands. Now code clips strands based
on the maximum width.

Also found bad code for using clipping flags, which was mixed up,
and probably caused hair strands to be missing in cases.
This commit is contained in:
Ton Roosendaal 2010-12-26 17:47:17 +00:00
parent 31eadb358d
commit c4a56fda6d
6 changed files with 61 additions and 31 deletions

@ -433,7 +433,9 @@ typedef struct StrandBuffer {
int overrideuv;
int flag, maxdepth;
float adaptcos, minwidth, widthfade;
float maxwidth; /* for cliptest of strands in blender unit */
float winmat[4][4];
int winx, winy;
} StrandBuffer;

@ -90,7 +90,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);
void strand_minmax(struct StrandRen *strand, float *min, float *max, float width);
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);

@ -4176,13 +4176,23 @@ static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset)
}
if(obr->strandbuf) {
float width;
/* compute average bounding box of strandpoint itself (width) */
if(obr->strandbuf->flag & R_STRAND_B_UNITS)
obr->strandbuf->maxwidth= MAX2(obr->strandbuf->ma->strand_sta, obr->strandbuf->ma->strand_end);
else
obr->strandbuf->maxwidth= 0.0f;
width= obr->strandbuf->maxwidth;
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);
strand_minmax(strand, smin, smax, width);
}
VECCOPY(sbound->boundbox[0], smin);

@ -1398,19 +1398,21 @@ int clip_render_object(float boundbox[][3], float *bounds, float winmat[][4])
fl= 0;
if(bounds) {
if(vec[0] > bounds[1]*vec[3]) fl |= 1;
if(vec[0]< bounds[0]*vec[3]) fl |= 2;
if(vec[0] < bounds[0]*vec[3]) fl |= 1;
else if(vec[0] > bounds[1]*vec[3]) fl |= 2;
if(vec[1] > bounds[3]*vec[3]) fl |= 4;
if(vec[1]< bounds[2]*vec[3]) fl |= 8;
else if(vec[1]< bounds[2]*vec[3]) fl |= 8;
}
else {
if(vec[0] < -vec[3]) fl |= 1;
if(vec[0] > vec[3]) fl |= 2;
if(vec[1] < -vec[3]) fl |= 4;
if(vec[1] > vec[3]) fl |= 8;
else if(vec[0] > vec[3]) fl |= 2;
if(vec[1] > vec[3]) fl |= 4;
else if(vec[1] < -vec[3]) fl |= 8;
}
if(vec[2] < -vec[3]) fl |= 16;
if(vec[2] > vec[3]) fl |= 32;
else if(vec[2] > vec[3]) fl |= 32;
flag &= fl;
if(flag==0) return 0;

@ -578,7 +578,8 @@ static void do_strand_fillac(void *handle, int x, int y, float u, float v, float
}
}
static int strand_test_clip(float winmat[][4], ZSpan *zspan, float *bounds, float *co, float *zcomp)
/* width is calculated in hoco space, to ensure strands are visible */
static int strand_test_clip(float winmat[][4], ZSpan *zspan, float *bounds, float *co, float *zcomp, float widthx, float widthy)
{
float hoco[4];
int clipflag= 0;
@ -588,10 +589,11 @@ static int strand_test_clip(float winmat[][4], ZSpan *zspan, float *bounds, floa
/* we compare z without perspective division for segment sorting */
*zcomp= hoco[2];
if(hoco[0] > bounds[1]*hoco[3]) clipflag |= 1;
else if(hoco[0]< bounds[0]*hoco[3]) clipflag |= 2;
else if(hoco[1] > bounds[3]*hoco[3]) clipflag |= 4;
else if(hoco[1]< bounds[2]*hoco[3]) clipflag |= 8;
if(hoco[0]+widthx < bounds[0]*hoco[3]) clipflag |= 1;
else if(hoco[0]-widthx > bounds[1]*hoco[3]) clipflag |= 2;
if(hoco[1]-widthy > bounds[3]*hoco[3]) clipflag |= 4;
else if(hoco[1]+widthy < bounds[2]*hoco[3]) clipflag |= 8;
clipflag |= testclip(hoco);
@ -826,6 +828,7 @@ int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBa
/* for all object instances */
for(obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) {
Material *ma;
float widthx, widthy;
obr= obi->obr;
@ -848,6 +851,9 @@ int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBa
if(clip_render_object(obi->obr->boundbox, bounds, winmat))
continue;
widthx= obr->strandbuf->maxwidth*obwinmat[0][0];
widthy= obr->strandbuf->maxwidth*obwinmat[1][1];
/* for each bounding box containing a number of strands */
sbound= obr->strandbuf->bound;
@ -861,14 +867,14 @@ int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBa
svert= strand->vert;
/* keep clipping and z depth for 4 control points */
clip[1]= strand_test_clip(obwinmat, &zspan, bounds, svert->co, &z[1]);
clip[2]= strand_test_clip(obwinmat, &zspan, bounds, (svert+1)->co, &z[2]);
clip[1]= strand_test_clip(obwinmat, &zspan, bounds, svert->co, &z[1], widthx, widthy);
clip[2]= strand_test_clip(obwinmat, &zspan, bounds, (svert+1)->co, &z[2], widthx, widthy);
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(obwinmat, &zspan, bounds, (svert+2)->co, &z[3]);
clip[3]= strand_test_clip(obwinmat, &zspan, bounds, (svert+2)->co, &z[3], widthx, widthy);
}
else {
clip[3]= clip[2]; z[3]= z[2];
@ -1025,12 +1031,22 @@ void free_strand_surface(Render *re)
BLI_freelistN(&re->strandsurface);
}
void strand_minmax(StrandRen *strand, float *min, float *max)
void strand_minmax(StrandRen *strand, float *min, float *max, float width)
{
StrandVert *svert;
float vec[3], width2= 2.0f*width;
int a;
for(a=0, svert=strand->vert; a<strand->totvert; a++, svert++)
DO_MINMAX(svert->co, min, max)
for(a=0, svert=strand->vert; a<strand->totvert; a++, svert++) {
VECCOPY(vec, svert->co);
DO_MINMAX(vec, min, max);
if(width!=0.0f) {
vec[0]+= width; vec[1]+= width; vec[2]+= width;
DO_MINMAX(vec, min, max);
vec[0]-= width2; vec[1]-= width2; vec[2]-= width2;
DO_MINMAX(vec, min, max);
}
}
}

@ -243,15 +243,15 @@ int testclip(float *v)
prevents issues with vertices lying exact on borders */
abs4= fabs(v[3]) + FLT_EPSILON;
if(v[2]< -abs4) c=16; /* this used to be " if(v[2]<0) ", see clippz() */
if( v[0] < -abs4) c+=1;
else if( v[0] > abs4) c+=2;
if( v[1] > abs4) c+=4;
else if( v[1] < -abs4) c+=8;
if(v[2] < -abs4) c+=16; /* this used to be " if(v[2]<0) ", see clippz() */
else if(v[2]> abs4) c+= 32;
if( v[0]>abs4) c+=2;
else if( v[0]< -abs4) c+=1;
if( v[1]>abs4) c+=4;
else if( v[1]< -abs4) c+=8;
return c;
}
@ -1782,10 +1782,10 @@ static int zbuf_part_project(ZbufProjectCache *cache, int index, float winmat[][
projectvert(co, winmat, ho);
wco= ho[3];
if(ho[0] > bounds[1]*wco) clipflag |= 1;
else if(ho[0]< bounds[0]*wco) clipflag |= 2;
if(ho[0] < bounds[0]*wco) clipflag |= 1;
else if(ho[0] > bounds[1]*wco) clipflag |= 2;
if(ho[1] > bounds[3]*wco) clipflag |= 4;
else if(ho[1]< bounds[2]*wco) clipflag |= 8;
else if(ho[1] < bounds[2]*wco) clipflag |= 8;
QUATCOPY(cache[cindex].ho, ho);
cache[cindex].clip= clipflag;