From 9fa438b4e94b0d61dde3e535b9d3fbc04db9a10b Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Sun, 15 Oct 2006 11:50:46 +0000 Subject: Another shadowbuffer goodie: the "Halfway trick" http://www.blender3d.org/cms/Shadow_buffer__Halfway.786.0.html Simply said: by using the average of the nearest and 2nd nearest Z value in Shadowbuffers you can reduce bias errors very well. For backwards compatibility it is a new buffer type though. --- source/blender/blenkernel/intern/object.c | 1 + source/blender/makesdna/DNA_lamp_types.h | 1 + source/blender/render/intern/include/zbuf.h | 1 + .../blender/render/intern/source/convertblender.c | 7 ++- source/blender/render/intern/source/initrender.c | 14 ++--- source/blender/render/intern/source/shadbuf.c | 7 ++- source/blender/render/intern/source/zbuf.c | 72 ++++++++++++++++++---- source/blender/src/buttons_shading.c | 21 ++++--- 8 files changed, 94 insertions(+), 30 deletions(-) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 47654dc15e4..fd0bd47430e 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -580,6 +580,7 @@ void *add_lamp(void) la->ray_samp= la->ray_sampy= la->ray_sampz= 1; la->area_size=la->area_sizey=la->area_sizez= 1.0; la->buffers= 1; + la->buftype= LA_SHADBUF_HALFWAY; return la; } diff --git a/source/blender/makesdna/DNA_lamp_types.h b/source/blender/makesdna/DNA_lamp_types.h index bc233b14fa4..22696c48878 100644 --- a/source/blender/makesdna/DNA_lamp_types.h +++ b/source/blender/makesdna/DNA_lamp_types.h @@ -115,6 +115,7 @@ typedef struct Lamp { /* buftype, no flag */ #define LA_SHADBUF_REGULAR 0 #define LA_SHADBUF_IRREGULAR 1 +#define LA_SHADBUF_HALFWAY 2 /* bufflag, auto clipping */ #define LA_SHADBUF_AUTO_START 1 diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h index ebad8f241f7..cd8ad8626db 100644 --- a/source/blender/render/intern/include/zbuf.h +++ b/source/blender/render/intern/include/zbuf.h @@ -77,6 +77,7 @@ typedef struct ZSpan { float zmulx, zmuly, zofsx, zofsy; /* transform from hoco to zbuf co */ int *rectz, *arectz; /* zbuffers, arectz is for transparant */ + int *rectz1; /* seconday z buffer for shadowbuffer (2nd closest z) */ int *rectp; /* polygon index buffer */ APixstr *apixbuf, *curpstr; /* apixbuf for transparent */ struct ListBase *apsmbase; diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index dc509bfa7d8..aedb5aa13c0 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -2155,11 +2155,15 @@ static void initshadowbuf(Render *re, LampRen *lar, float mat[][4]) shb->d= lar->clipsta; shb->clipend= lar->clipend; - /* bias is percentage, made 2x karger because of correction for angle of incidence */ + /* bias is percentage, made 2x larger because of correction for angle of incidence */ /* when a ray is closer to parallel of a face, bias value is increased during render */ shb->bias= (0.02*lar->bias)*0x7FFFFFFF; shb->bias= shb->bias*(100/re->r.size); + /* halfway method (average of first and 2nd z) reduces bias issues */ + if(lar->buftype==LA_SHADBUF_HALFWAY) + shb->bias= 0.1f*shb->bias; + } @@ -2227,6 +2231,7 @@ static LampRen *add_render_lamp(Render *re, Object *ob) lar->shadhalostep = la->shadhalostep; lar->clipsta = la->clipsta; lar->clipend = la->clipend; + lar->bias = la->bias; lar->type= la->type; diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index 30beae1c467..15e7ff63293 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -478,15 +478,15 @@ void RE_SetCamera(Render *re, Object *camera) clipend= cam->clipend; } else if(camera->type==OB_LAMP) { - /* fac= cos( PI*((float)(256- la->spsi))/512.0 ); */ - - /* phi= acos(fac); */ - /* lens= 16.0*fac/sin(phi); */ - lens= re->lens; + Lamp *la= camera->data; + float fac= cos( M_PI*la->spotsize/360.0 ); + float phi= acos(fac); + + lens= 16.0*fac/sin(phi); if(lens==0.0f) lens= 35.0; - clipsta= 0.1; - clipend= 1000.0; + clipsta= la->clipsta; + clipend= la->clipend; } else { /* envmap exception... */ lens= re->lens; diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c index 2194d202351..73889b6578a 100644 --- a/source/blender/render/intern/source/shadbuf.c +++ b/source/blender/render/intern/source/shadbuf.c @@ -369,6 +369,9 @@ void makeshadowbuf(Render *re, LampRen *lar) float wsize, *jitbuf, twozero[2]= {0.0f, 0.0f}, angle, temp; int *rectz, samples; + /* XXXX EVIL! this global is used in clippyra(), zbuf.c */ + R.clipcrop= 1.0f; + if(lar->bufflag & (LA_SHADBUF_AUTO_START|LA_SHADBUF_AUTO_END)) shadowbuf_autoclip(re, lar); @@ -386,8 +389,8 @@ void makeshadowbuf(Render *re, LampRen *lar) i_window(-wsize, wsize, -wsize, wsize, shb->d, shb->clipend, shb->winmat); MTC_Mat4MulMat4(shb->persmat, shb->viewmat, shb->winmat); - - if(lar->buftype==LA_SHADBUF_REGULAR) { + + if(ELEM(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY)) { /* jitter, weights */ shb->jit= give_jitter_tab(shb->samp); make_jitter_weight_tab(shb, lar->filtertype); diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index deb5031ebf3..dc096fc0495 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -682,7 +682,7 @@ static void zbufline(ZSpan *zspan, int zvlnr, float *vec1, float *vec2) static void zbufline_onlyZ(ZSpan *zspan, int zvlnr, float *vec1, float *vec2) { - int *rectz; + int *rectz, *rectz1= NULL; int start, end, x, y, oldx, oldy, ofs; int dz, vergz, maxtest= 0; float dx, dy; @@ -716,6 +716,8 @@ static void zbufline_onlyZ(ZSpan *zspan, int zvlnr, float *vec1, float *vec2) if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow rectz= zspan->rectz + oldy*zspan->rectx+ start; + if(zspan->rectz1) + rectz1= zspan->rectz1 + oldy*zspan->rectx+ start; if(dy<0) ofs= -zspan->rectx; else ofs= zspan->rectx; @@ -726,18 +728,24 @@ static void zbufline_onlyZ(ZSpan *zspan, int zvlnr, float *vec1, float *vec2) if(y!=oldy) { oldy= y; rectz+= ofs; + if(rectz1) rectz1+= ofs; } if(x>=0 && y>=0 && yrecty) { - if(vergz<*rectz) { + if(vergz < *rectz) { + if(rectz1) *rectz1= *rectz; *rectz= vergz; } + else if(rectz1 && vergz < *rectz1) + *rectz1= vergz; } v1[1]+= dy; if(maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0; else vergz+= dz; + + if(rectz1) rectz1++; } } else { @@ -765,6 +773,8 @@ static void zbufline_onlyZ(ZSpan *zspan, int zvlnr, float *vec1, float *vec2) if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow rectz= zspan->rectz + start*zspan->rectx+ oldx; + if(zspan->rectz1) + rectz1= zspan->rectz1 + start*zspan->rectx+ oldx; if(dx<0) ofs= -1; else ofs= 1; @@ -775,17 +785,24 @@ static void zbufline_onlyZ(ZSpan *zspan, int zvlnr, float *vec1, float *vec2) if(x!=oldx) { oldx= x; rectz+= ofs; + if(rectz1) rectz1+= ofs; } if(x>=0 && y>=0 && xrectx) { - if(vergz<*rectz) { + if(vergz < *rectz) { + if(rectz1) *rectz1= *rectz; *rectz= vergz; } + else if(rectz1 && vergz < *rectz1) + *rectz1= vergz; } v1[0]+= dx; if(maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0; else vergz+= dz; + + if(rectz1) + rectz1+=zspan->rectx; } } } @@ -1183,14 +1200,15 @@ static void zbuffillGL4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3 * @param v3 [4 floats, world coordinates] third vertex */ +/* now: filling two Z values, the closest and 2nd closest */ static void zbuffillGL_onlyZ(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4) { double zxd, zyd, zy0, zverg; float x0,y0,z0; float x1,y1,z1,x2,y2,z2,xx1; float *span1, *span2; - int *rz, x, y; - int sn1, sn2, rectx, *rectzofs, my0, my2; + int *rz, *rz1, x, y; + int sn1, sn2, rectx, *rectzofs, *rectzofs1= NULL, my0, my2; /* init */ zbuf_init_span(zspan); @@ -1237,6 +1255,8 @@ static void zbuffillGL_onlyZ(ZSpan *zspan, int zvlnr, float *v1, float *v2, floa /* start-offset in rect */ rectx= zspan->rectx; rectzofs= (zspan->rectz+rectx*my2); + if(zspan->rectz1) + rectzofs1= (zspan->rectz1+rectx*my2); /* correct span */ sn1= (my0 + my2)/2; @@ -1261,20 +1281,30 @@ static void zbuffillGL_onlyZ(ZSpan *zspan, int zvlnr, float *v1, float *v2, floa if(sn2>=sn1) { zverg= (double)sn1*zxd + zy0; rz= rectzofs+sn1; + rz1= rectzofs1+sn1; x= sn2-sn1; while(x>=0) { - if( (int)zverg < *rz) { - *rz= (int)zverg; + int zvergi= (int)zverg; + /* option: maintain two depth values, closest and 2nd closest */ + if(zvergi < *rz) { + if(rectzofs1) *rz1= *rz; + *rz= zvergi; } + else if(rectzofs1 && zvergi < *rz1) + *rz1= zvergi; + zverg+= zxd; + rz++; + rz1++; x--; } } zy0-=zyd; rectzofs-= rectx; + if(rectzofs1) rectzofs1-= rectx; } } @@ -1309,6 +1339,7 @@ static void clippyra(float *labda, float *v1, float *v2, int *b2, int *b3, int a v13= v1[3]; } else { + /* XXXXX EVIL! this is a R global, whilst this function can be called for shadow, before R was set */ dw= R.clipcrop*(v2[3]-v1[3]); v13= R.clipcrop*v1[3]; } @@ -1425,7 +1456,7 @@ void zbufclip(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, { float *vlzp[32][3], labda[3][2]; float vez[400], *trias[40]; - + if(c1 | c2 | c3) { /* not in middle */ if(c1 & c2 & c3) { /* completely out */ return; @@ -1445,6 +1476,7 @@ void zbufclip(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, clipflag[1]= ( (c1 & 3) | (c2 & 3) | (c3 & 3) ); clipflag[2]= ( (c1 & 12) | (c2 & 12) | (c3 & 12) ); } + else clipflag[1]=clipflag[2]= 0; for(b=0;b<3;b++) { @@ -1454,7 +1486,7 @@ void zbufclip(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, for(v=0; v2) { for(b3=3; b3<=b1; b3++) { vlzp[clvl][0]= trias[0]; @@ -1861,11 +1894,15 @@ void zbuffer_shadow(Render *re, LampRen *lar, int *rectz, int size, float jitx, /* the buffers */ zspan.rectz= rectz; fillrect(rectz, size, size, 0x7FFFFFFE); + if(lar->buftype==LA_SHADBUF_HALFWAY) { + zspan.rectz1= MEM_mallocN(size*size*sizeof(int), "seconday z buffer"); + fillrect(zspan.rectz1, size, size, 0x7FFFFFFE); + } /* filling methods */ zspan.zbuflinefunc= zbufline_onlyZ; zspan.zbuffunc= zbuffillGL_onlyZ; - + for(a=0; atotvlak; a++) { if((a & 255)==0) vlr= re->blovl[a>>8]; @@ -1889,6 +1926,15 @@ void zbuffer_shadow(Render *re, LampRen *lar, int *rectz, int size, float jitx, } } } + + /* merge buffers */ + if(lar->buftype==LA_SHADBUF_HALFWAY) { + for(a=size*size -1; a>=0; a--) + rectz[a]= (rectz[a]>>1) + (zspan.rectz1[a]>>1); + + MEM_freeN(zspan.rectz1); + } + zbuf_free_span(&zspan); } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 7798d50a663..c7bfef675ee 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -2148,8 +2148,15 @@ static void lamp_panel_spot(Object *ob, Lamp *la) uiDefButBitS(block, TOG, LA_SHAD_RAY, B_SHADRAY,"Ray Shadow",10,180,80,19,&la->mode, 0, 0, 0, 0, "Use ray tracing for shadow"); if(la->type==LA_SPOT) { uiDefButBitS(block, TOG, LA_SHAD_BUF, B_SHADBUF, "Buf.Shadow",10,160,80,19,&la->mode, 0, 0, 0, 0, "Lets spotlight produce shadows using shadow buffer"); - if(la->mode & LA_SHAD_BUF) - uiDefButC(block, MENU, B_REDR, "Classical %x0|Irregular %x1", 10,140,80,19,&la->buftype, 0, 0, 0, 0, "Buffer type, Irregular buffer produces sharp shadow always, but doesn't support ZTransp shadow receiving"); + if(la->mode & LA_SHAD_BUF) { + char *tip= "Regular buffer type"; + if(la->buftype==LA_SHADBUF_IRREGULAR) + tip= "Irregular buffer produces sharp shadow always, but it doesn't show up for raytracing"; + else if(la->buftype==LA_SHADBUF_HALFWAY) + tip= "Regular buffer, averaginng the closest and 2nd closest Z value for reducing biasing"; + + uiDefButC(block, MENU, B_REDR, "Classical %x0|Classic-Halfway %x2|Irregular %x1", 10,140,80,19,&la->buftype, 0, 0, 0, 0, tip); + } } uiBlockEndAlign(block); @@ -2169,12 +2176,12 @@ static void lamp_panel_spot(Object *ob, Lamp *la) uiDefButF(block, NUMSLI,B_LAMPREDRAW,"HaloInt ", 100,135,200,19,&la->haint, 0.0, 5.0, 0, 0, "Sets the intensity of the spotlight halo"); if(la->mode & LA_SHAD_BUF) { - if(la->buftype==LA_SHADBUF_REGULAR) { + if(ELEM(la->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY)) { uiBlockBeginAlign(block); uiDefButS(block, NUM,B_SBUFF,"ShadowBufferSize:", 100,110,200,19, &la->bufsize,512,10240, 0, 0, "Sets the size of the shadow buffer to nearest multiple of 16"); - uiDefButS(block, ROW,B_NOP, "Box", 100,90,65,19, &la->filtertype, 0.0, LA_SHADBUF_BOX, 0, 0, "Apply Box filter for shadowbuffer"); - uiDefButS(block, ROW,B_NOP, "Tent", 165,90,65,19, &la->filtertype, 0.0, LA_SHADBUF_TENT, 0, 0, "Apply Tent filter for shadowbuffer"); - uiDefButS(block, ROW,B_NOP, "Gauss", 230,90,70,19, &la->filtertype, 0.0, LA_SHADBUF_GAUSS, 0, 0, "Apply Gauss filter for shadowbuffer"); + uiDefButS(block, ROW,B_NOP, "Box", 100,90,65,19, &la->filtertype, 0.0, LA_SHADBUF_BOX, 0, 0, "Apply Box filter for shadowbuffer samples"); + uiDefButS(block, ROW,B_NOP, "Tent", 165,90,65,19, &la->filtertype, 0.0, LA_SHADBUF_TENT, 0, 0, "Apply Tent filter for shadowbuffer samples"); + uiDefButS(block, ROW,B_NOP, "Gauss", 230,90,70,19, &la->filtertype, 0.0, LA_SHADBUF_GAUSS, 0, 0, "Apply Gauss filter for shadowbuffer samples"); // uiDefButS(block, ROW,B_NOP,"SubSamples: 1", 100,90,140,19, &la->buffers, 1.0, 1.0, 0, 0, "Amount of lampbuffer subsamples, a value of larger than 1 halves the shadowbuffer size"); // uiDefButS(block, ROW,B_NOP,"4", 240,90,30,19, &la->buffers, 1.0, 4.0, 0, 0, "Amount of lampbuffer subsamples, this halves the actual shadowbuffer size"); @@ -2183,7 +2190,7 @@ static void lamp_panel_spot(Object *ob, Lamp *la) uiBlockBeginAlign(block); uiDefButS(block, NUM,B_LAMPREDRAW,"Samples:", 100,60,100,19, &la->samp,1.0,16.0, 0, 0, "Sets the number of shadow map samples"); uiDefButS(block, NUM,B_NOP,"Halo step:", 200,60,100,19, &la->shadhalostep, 0.0, 12.0, 0, 0, "Sets the volumetric halo sampling frequency"); - uiDefButF(block, NUM,B_LAMPREDRAW,"Bias:", 100,40,100,19, &la->bias, 0.01, 5.0, 1, 0, "Sets the shadow map sampling bias"); + uiDefButF(block, NUM,B_LAMPREDRAW,"Bias:", 100,40,100,19, &la->bias, 0.001, 5.0, 1, 0, "Sets the shadow map sampling bias"); uiDefButF(block, NUM,B_LAMPREDRAW,"Soft:", 200,40,100,19, &la->soft,1.0,100.0, 100, 0, "Sets the size of the shadow sample area"); } else { /* LA_SHADBUF_IRREGULAR */ -- cgit v1.2.3