diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-10-07 19:01:44 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-10-07 19:01:44 +0400 |
commit | 94a9fa4711be6411002bdd32ffbb01c7402f4920 (patch) | |
tree | 22c8efaa75886c840044ad1c58b0450c6d29a44c | |
parent | 0d7d520ffa3cf52829f765687766db694b92f2b1 (diff) |
Fix for bug #13363: ray (qmc) shadows had some light leaking issues,
due to jittering of the start position for antialiasing in a pixel.
Now it distributes the start position over the fixed osa sample
positions, instead of of random positions in space. The ugly bit is
that a custom ordering was defined for osa 8/11/16 to ensure that the
first 4 are distributed relatively fair for adaptive sampling to decide
if more samples need to be taken.
-rw-r--r-- | source/blender/render/extern/include/RE_shader_ext.h | 1 | ||||
-rw-r--r-- | source/blender/render/intern/include/shading.h | 3 | ||||
-rw-r--r-- | source/blender/render/intern/source/rayshade.c | 104 | ||||
-rw-r--r-- | source/blender/render/intern/source/rendercore.c | 12 | ||||
-rw-r--r-- | source/blender/render/intern/source/shadeinput.c | 124 | ||||
-rw-r--r-- | source/blender/render/intern/source/zbuf.c | 4 |
6 files changed, 146 insertions, 102 deletions
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index e8403053e0b..888474ffa18 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -157,6 +157,7 @@ typedef struct ShadeInput int xs, ys; /* pixel to be rendered */ int mask; /* subsample mask */ + float scanco[3]; /* original scanline coordinate without jitter */ int samplenr; /* sample counter, to detect if we should do shadow again */ int depth; /* 1 or larger on raytrace shading */ diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h index 6f1cb8dd7a9..54311d2515a 100644 --- a/source/blender/render/intern/include/shading.h +++ b/source/blender/render/intern/include/shading.h @@ -56,7 +56,8 @@ void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr); void shade_input_set_triangle_i(struct ShadeInput *shi, struct ObjectInstanceRen *obi, struct VlakRen *vlr, short i1, short i2, short i3); void shade_input_set_triangle(struct ShadeInput *shi, volatile int obi, volatile int facenr, int normal_flip); void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from); -void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float z); +void shade_input_calc_viewco(struct ShadeInput *shi, float x, float y, float z, float *view, float *dxyview, float *co, float *dxco, float *dyco); +void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float sx, float sy, float z); void shade_input_set_uv(struct ShadeInput *shi); void shade_input_set_normals(struct ShadeInput *shi); void shade_input_flip_normals(struct ShadeInput *shi); diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 9d457e7f0fc..f822d41bb85 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -1792,21 +1792,62 @@ void ray_ao(ShadeInput *shi, float *shadfac) ray_ao_spheresamp(shi, shadfac); } +static void ray_shadow_jittered_coords(ShadeInput *shi, int max, float jitco[RE_MAX_OSA][3], int *totjitco) +{ + /* magic numbers for reordering sample positions to give better + * results with adaptive sample, when it usually only takes 4 samples */ + int order8[8] = {0, 1, 5, 6, 2, 3, 4, 7}; + int order11[11] = {1, 3, 8, 10, 0, 2, 4, 5, 6, 7, 9}; + int order16[16] = {1, 3, 9, 12, 0, 6, 7, 8, 13, 2, 4, 5, 10, 11, 14, 15}; + int count = count_mask(shi->mask); + + /* for better antialising shadow samples are distributed over the subpixel + * sample coordinates, this only works for raytracing depth 0 though */ + if(!shi->strand && shi->depth == 0 && count > 1 && count <= max) { + float xs, ys, zs, view[3]; + int samp, ordsamp, tot= 0; + + for(samp=0; samp<R.osa; samp++) { + if(R.osa == 8) ordsamp = order8[samp]; + else if(R.osa == 11) ordsamp = order11[samp]; + else if(R.osa == 16) ordsamp = order16[samp]; + else ordsamp = samp; + + if(shi->mask & (1<<ordsamp)) { + /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */ + xs= (float)shi->scanco[0] + R.jit[ordsamp][0] + 0.5f; + ys= (float)shi->scanco[1] + R.jit[ordsamp][1] + 0.5f; + zs= shi->scanco[2]; + + shade_input_calc_viewco(shi, xs, ys, zs, view, NULL, jitco[tot], NULL, NULL); + tot++; + } + } + + *totjitco= tot; + } + else { + VECCOPY(jitco[0], shi->co); + *totjitco= 1; + } +} static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *shadfac, Isect *isec) { QMCSampler *qsa=NULL; - QMCSampler *qsa_jit=NULL; int samples=0; - float samp3d[3], jit[3], jitbias= 0.0f; + float samp3d[3]; float fac=0.0f, vec[3]; float colsq[4]; float adapt_thresh = lar->adapt_thresh; - int max_samples = lar->ray_totsamp; - float pos[3]; + int min_adapt_samples=4, max_samples = lar->ray_totsamp; + float *co; int do_soft=1, full_osa=0; + float jitco[RE_MAX_OSA][3]; + int totjitco; + colsq[0] = colsq[1] = colsq[2] = 0.0; if(isec->mode==RE_RAY_SHADOW_TRA) { shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f; @@ -1823,21 +1864,16 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float * if (do_soft) max_samples = lar->ray_totsamp; else max_samples = (R.osa > 4)?R.osa:5; } - - if(shi->vlr && ((shi->vlr->flag & R_FULL_OSA) == 0)) - jitbias= 0.5f*(VecLength(shi->dxco) + VecLength(shi->dyco)); + + ray_shadow_jittered_coords(shi, max_samples, jitco, &totjitco); /* sampling init */ - if (lar->ray_samp_method==LA_SAMP_HALTON) { + if (lar->ray_samp_method==LA_SAMP_HALTON) qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples); - qsa_jit = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples); - } else if (lar->ray_samp_method==LA_SAMP_HAMMERSLEY) { + else if (lar->ray_samp_method==LA_SAMP_HAMMERSLEY) qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples); - qsa_jit = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples); - } QMC_initPixel(qsa, shi->thread); - QMC_initPixel(qsa_jit, shi->thread); VECCOPY(vec, lampco); @@ -1845,18 +1881,11 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float * while (samples < max_samples) { isec->faceorig= (RayFace*)shi->vlr; isec->oborig= RAY_OBJECT_SET(&R, shi->obi); - + /* manually jitter the start shading co-ord per sample * based on the pre-generated OSA texture sampling offsets, * for anti-aliasing sharp shadow edges. */ - VECCOPY(pos, shi->co); - if (shi->vlr && !full_osa) { - QMC_sampleRect(jit, qsa_jit, shi->thread, samples, 1.0, 1.0); - - pos[0] += shi->dxco[0]*jit[0] + shi->dyco[0]*jit[1]; - pos[1] += shi->dxco[1]*jit[0] + shi->dyco[1]*jit[1]; - pos[2] += shi->dxco[2]*jit[0] + shi->dyco[2]*jit[1]; - } + co = jitco[samples % totjitco]; if (do_soft) { /* sphere shadow source */ @@ -1864,9 +1893,9 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float * float ru[3], rv[3], v[3], s[3]; /* calc tangent plane vectors */ - v[0] = pos[0] - lampco[0]; - v[1] = pos[1] - lampco[1]; - v[2] = pos[2] - lampco[2]; + v[0] = co[0] - lampco[0]; + v[1] = co[1] - lampco[1]; + v[2] = co[2] - lampco[2]; Normalize(v); VecOrthoBasisf(v, ru, rv); @@ -1879,13 +1908,6 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float * s[2] = samp3d[0]*ru[2] + samp3d[1]*rv[2]; VECCOPY(samp3d, s); - - if(jitbias != 0.0f) { - /* bias away somewhat to avoid self intersection */ - pos[0] -= jitbias*v[0]; - pos[1] -= jitbias*v[1]; - pos[2] -= jitbias*v[2]; - } } else { /* sampling, returns quasi-random vector in [sizex,sizey]^2 plane */ @@ -1901,20 +1923,20 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float * VECCOPY(isec->end, vec); } - if(jitbias != 0.0f && !(do_soft && lar->type==LA_LOCAL)) { + if(shi->strand) { /* bias away somewhat to avoid self intersection */ + float jitbias= 0.5f*(VecLength(shi->dxco) + VecLength(shi->dyco)); float v[3]; - VECSUB(v, pos, isec->end); + VECSUB(v, co, isec->end); Normalize(v); - pos[0] -= jitbias*v[0]; - pos[1] -= jitbias*v[1]; - pos[2] -= jitbias*v[2]; + co[0] -= jitbias*v[0]; + co[1] -= jitbias*v[1]; + co[2] -= jitbias*v[2]; } - VECCOPY(isec->start, pos); - + VECCOPY(isec->start, co); /* trace the ray */ if(isec->mode==RE_RAY_SHADOW_TRA) { @@ -1941,7 +1963,7 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float * if ((lar->ray_samp_method == LA_SAMP_HALTON)) { /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */ - if ((max_samples > 4) && (adapt_thresh > 0.0) && (samples > max_samples / 3)) { + if ((max_samples > min_adapt_samples) && (adapt_thresh > 0.0) && (samples > max_samples / 3)) { if (isec->mode==RE_RAY_SHADOW_TRA) { if ((shadfac[3] / samples > (1.0-adapt_thresh)) || (shadfac[3] / samples < adapt_thresh)) break; @@ -1963,8 +1985,6 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float * } else shadfac[3]= 1.0f-fac/samples; - if (qsa_jit) - release_thread_qmcsampler(&R, shi->thread, qsa_jit); if (qsa) release_thread_qmcsampler(&R, shi->thread, qsa); } diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index 05ff0d3c020..1eb42bca569 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -1465,7 +1465,7 @@ static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRe { ShadeInput *shi= ssamp->shi; ShadeResult shr; - float texfac, orthoarea, nor[3], alpha; + float texfac, orthoarea, nor[3], alpha, sx, sy; /* cache for shadow */ shi->samplenr= R.shadowsamplenr[shi->thread]++; @@ -1476,8 +1476,8 @@ static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRe shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2); /* center pixel */ - x += 0.5f; - y += 0.5f; + sx = x + 0.5f; + sy = y + 0.5f; /* we estimate the area here using shi->dxco and shi->dyco. we need to enabled shi->osatex these are filled. we compute two areas, one with @@ -1486,13 +1486,13 @@ static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRe shi->osatex= 1; VECCOPY(nor, shi->facenor); - calc_view_vector(shi->facenor, x, y); + calc_view_vector(shi->facenor, sx, sy); Normalize(shi->facenor); - shade_input_set_viewco(shi, x, y, z); + shade_input_set_viewco(shi, x, y, sx, sy, z); orthoarea= VecLength(shi->dxco)*VecLength(shi->dyco); VECCOPY(shi->facenor, nor); - shade_input_set_viewco(shi, x, y, z); + shade_input_set_viewco(shi, x, y, sx, sy, z); *area= VecLength(shi->dxco)*VecLength(shi->dyco); *area= MIN2(*area, 2.0f*orthoarea); diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 8904999432a..476330152ec 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -573,31 +573,25 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert } } -/* scanline pixel coordinates */ -/* requires set_triangle */ -void shade_input_set_viewco(ShadeInput *shi, float x, float y, float z) +/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */ +void shade_input_calc_viewco(ShadeInput *shi, float x, float y, float z, float *view, float *dxyview, float *co, float *dxco, float *dyco) { - float fac; + /* returns not normalized, so is in viewplane coords */ + calc_view_vector(view, x, y); - /* currently in use for dithering (soft shadow), node preview, irregular shad */ - shi->xs= (int)(x); - shi->ys= (int)(y); - - calc_view_vector(shi->view, x, y); /* returns not normalized, so is in viewplane coords */ - - /* wire cannot use normal for calculating shi->co */ if(shi->mat->mode & MA_WIRE) { - + /* wire cannot use normal for calculating shi->co, so + * we reconstruct the coordinate less accurate */ if(R.r.mode & R_ORTHO) - calc_renderco_ortho(shi->co, x, y, z); + calc_renderco_ortho(co, x, y, z); else - calc_renderco_zbuf(shi->co, shi->view, z); + calc_renderco_zbuf(co, view, z); } else { - float dface, v1[3]; + /* for non-wire, intersect with the triangle to get the exact coord */ + float fac, dface, v1[3]; VECCOPY(v1, shi->v1->co); - if(shi->obi->flag & R_TRANSFORMED) Mat4MulVecfl(shi->obi->mat, v1); @@ -609,72 +603,98 @@ void shade_input_set_viewco(ShadeInput *shi, float x, float y, float z) float fx= 2.0f/(R.winx*R.winmat[0][0]); float fy= 2.0f/(R.winy*R.winmat[1][1]); - shi->co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0]; - shi->co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1]; + co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0]; + co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1]; /* using a*x + b*y + c*z = d equation, (a b c) is normal */ if(shi->facenor[2]!=0.0f) - shi->co[2]= (dface - shi->facenor[0]*shi->co[0] - shi->facenor[1]*shi->co[1])/shi->facenor[2]; + co[2]= (dface - shi->facenor[0]*co[0] - shi->facenor[1]*co[1])/shi->facenor[2]; else - shi->co[2]= 0.0f; + co[2]= 0.0f; - if(shi->osatex || (R.r.mode & R_SHADOW) ) { - shi->dxco[0]= fx; - shi->dxco[1]= 0.0f; + if(dxco && dyco) { + dxco[0]= fx; + dxco[1]= 0.0f; if(shi->facenor[2]!=0.0f) - shi->dxco[2]= (shi->facenor[0]*fx)/shi->facenor[2]; + dxco[2]= (shi->facenor[0]*fx)/shi->facenor[2]; else - shi->dxco[2]= 0.0f; + dxco[2]= 0.0f; - shi->dyco[0]= 0.0f; - shi->dyco[1]= fy; + dyco[0]= 0.0f; + dyco[1]= fy; if(shi->facenor[2]!=0.0f) - shi->dyco[2]= (shi->facenor[1]*fy)/shi->facenor[2]; + dyco[2]= (shi->facenor[1]*fy)/shi->facenor[2]; else - shi->dyco[2]= 0.0f; + dyco[2]= 0.0f; - if( (shi->mat->texco & TEXCO_REFL) ) { - if(shi->co[2]!=0.0f) fac= 1.0f/shi->co[2]; else fac= 0.0f; - shi->dxview= -R.viewdx*fac; - shi->dyview= -R.viewdy*fac; + if(dxyview) { + if(co[2]!=0.0f) fac= 1.0f/co[2]; else fac= 0.0f; + dxyview[0]= -R.viewdx*fac; + dxyview[1]= -R.viewdy*fac; } } } else { float div; - div= shi->facenor[0]*shi->view[0] + shi->facenor[1]*shi->view[1] + shi->facenor[2]*shi->view[2]; + div= shi->facenor[0]*view[0] + shi->facenor[1]*view[1] + shi->facenor[2]*view[2]; if (div!=0.0f) fac= dface/div; else fac= 0.0f; - shi->co[0]= fac*shi->view[0]; - shi->co[1]= fac*shi->view[1]; - shi->co[2]= fac*shi->view[2]; + co[0]= fac*view[0]; + co[1]= fac*view[1]; + co[2]= fac*view[2]; /* pixel dx/dy for render coord */ - if(shi->osatex || (R.r.mode & R_SHADOW) ) { + if(dxco && dyco) { float u= dface/(div - R.viewdx*shi->facenor[0]); float v= dface/(div - R.viewdy*shi->facenor[1]); - shi->dxco[0]= shi->co[0]- (shi->view[0]-R.viewdx)*u; - shi->dxco[1]= shi->co[1]- (shi->view[1])*u; - shi->dxco[2]= shi->co[2]- (shi->view[2])*u; + dxco[0]= co[0]- (view[0]-R.viewdx)*u; + dxco[1]= co[1]- (view[1])*u; + dxco[2]= co[2]- (view[2])*u; - shi->dyco[0]= shi->co[0]- (shi->view[0])*v; - shi->dyco[1]= shi->co[1]- (shi->view[1]-R.viewdy)*v; - shi->dyco[2]= shi->co[2]- (shi->view[2])*v; + dyco[0]= co[0]- (view[0])*v; + dyco[1]= co[1]- (view[1]-R.viewdy)*v; + dyco[2]= co[2]- (view[2])*v; - if( (shi->mat->texco & TEXCO_REFL) ) { + if(dxyview) { if(fac!=0.0f) fac= 1.0f/fac; - shi->dxview= -R.viewdx*fac; - shi->dyview= -R.viewdy*fac; + dxyview[0]= -R.viewdx*fac; + dxyview[1]= -R.viewdy*fac; } } } } /* cannot normalize earlier, code above needs it at viewplane level */ - Normalize(shi->view); + Normalize(view); +} + +/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */ +void shade_input_set_viewco(ShadeInput *shi, float x, float y, float xs, float ys, float z) +{ + float *dxyview= NULL, *dxco= NULL, *dyco= NULL; + + /* currently in use for dithering (soft shadow), node preview, irregular shad */ + shi->xs= (int)xs; + shi->ys= (int)ys; + + /* original scanline coordinate without jitter */ + shi->scanco[0]= x; + shi->scanco[1]= y; + shi->scanco[2]= z; + + /* check if we need derivatives */ + if(shi->osatex || (R.r.mode & R_SHADOW)) { + dxco= shi->dxco; + dyco= shi->dyco; + + if((shi->mat->texco & TEXCO_REFL)) + dxyview= &shi->dxview; + } + + shade_input_calc_viewco(shi, xs, ys, z, shi->view, dxyview, shi->co, dxco, dyco); } /* calculate U and V, for scanline (silly render face u and v are in range -1 to 0) */ @@ -1301,7 +1321,8 @@ void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y) for(samp=0; samp<R.osa; samp++) { if(curmask & (1<<samp)) { - xs= (float)x + R.jit[samp][0] + 0.5f; /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */ + /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */ + xs= (float)x + R.jit[samp][0] + 0.5f; ys= (float)y + R.jit[samp][1] + 0.5f; if(shi_cp) @@ -1310,7 +1331,7 @@ void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y) shi->mask= (1<<samp); // shi->rl= ssamp->rlpp[samp]; shi->samplenr= R.shadowsamplenr[shi->thread]++; /* this counter is not being reset per pixel */ - shade_input_set_viewco(shi, xs, ys, (float)ps->z); + shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z); shade_input_set_uv(shi); shade_input_set_normals(shi); @@ -1329,9 +1350,10 @@ void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y) xs= (float)x + 0.5f; ys= (float)y + 0.5f; } + shi->mask= curmask; shi->samplenr= R.shadowsamplenr[shi->thread]++; - shade_input_set_viewco(shi, xs, ys, (float)ps->z); + shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z); shade_input_set_uv(shi); shade_input_set_normals(shi); shi++; diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index 1726c061df1..0ddcf78b8f0 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -3839,7 +3839,7 @@ static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int } shi->mask= (1<<samp); shi->samplenr= R.shadowsamplenr[shi->thread]++; - shade_input_set_viewco(shi, xs, ys, (float)z); + shade_input_set_viewco(shi, x, y, xs, ys, (float)z); shade_input_set_uv(shi); shade_input_set_normals(shi); @@ -3859,7 +3859,7 @@ static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int } shi->mask= curmask; shi->samplenr= R.shadowsamplenr[shi->thread]++; - shade_input_set_viewco(shi, xs, ys, (float)z); + shade_input_set_viewco(shi, x, y, xs, ys, (float)z); shade_input_set_uv(shi); shade_input_set_normals(shi); } |