Render feature request:
Auto-clip Lamp Buffer Setting a good range for clipping start/end for Lamp buffers is important for good quality shadow (depth details). That can be quite a hassle, when many lamps or animated objects are involved. This option allows to have the clipping range calculated based on the visible vertices in the spotbundle. For clip start and clip end it can be set individually. Typically the clip start defines quality most. The shadow buffer 'bias' value is corrected for this automatic clipping too, to ensure that ranges that differ give same biasing appearance. (If this wasn't done, you would see lighted areas become darker or lighter, or even artefacts, when the range changes suddenly NOTE: since it only checks for vertices, be aware that large planes can give errors. Implementation note: zbuffer values are non-linear (1/z) because that allows linear interpolation while filling scanlines. That's the main reason for the precision to be highest close to the eye (or lamp). It's even a useful feature, since you want details to be precise when they're closeby. Since these values are also in the -1 to 1 range, using floats here wouldn't solve problems a lot. Maybe trying a 64 bits Z once might be an interesting coding job.
This commit is contained in:
@@ -306,6 +306,8 @@ typedef struct LampRen
|
||||
float soft;
|
||||
/** amount of subsample buffers */
|
||||
short buffers, filtertype;
|
||||
/** autoclip */
|
||||
short bufflag;
|
||||
/** shadow plus halo: detail level */
|
||||
short shadhalostep;
|
||||
/** Near clip of the lamp */
|
||||
|
||||
@@ -2075,7 +2075,7 @@ static void init_render_mesh(Render *re, Object *ob, Object *par, int only_verts
|
||||
static void initshadowbuf(Render *re, LampRen *lar, float mat[][4])
|
||||
{
|
||||
struct ShadBuf *shb;
|
||||
float hoek, temp, viewinv[4][4];
|
||||
float viewinv[4][4];
|
||||
|
||||
/* if(la->spsi<16) return; */
|
||||
|
||||
@@ -2110,13 +2110,9 @@ static void initshadowbuf(Render *re, LampRen *lar, float mat[][4])
|
||||
MTC_Mat4MulMat4(shb->viewmat, viewinv, shb->winmat);
|
||||
|
||||
/* projection */
|
||||
hoek= saacos(lar->spotsi);
|
||||
temp= 0.5*shb->size*cos(hoek)/sin(hoek);
|
||||
shb->d= lar->clipsta;
|
||||
|
||||
shb->pixsize= (shb->d)/temp;
|
||||
|
||||
shb->clipend= lar->clipend;
|
||||
|
||||
/* bias is percentage, made 2x karger 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;
|
||||
@@ -2333,6 +2329,7 @@ static LampRen *add_render_lamp(Render *re, Object *ob)
|
||||
if(re->r.mode & R_SHADOW) {
|
||||
if (la->type==LA_SPOT && (lar->mode & LA_SHAD) ) {
|
||||
/* Per lamp, one shadow buffer is made. */
|
||||
lar->bufflag= la->bufflag;
|
||||
Mat4CpyMat4(mat, ob->obmat);
|
||||
initshadowbuf(re, lar, mat); // mat is altered
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_lamp_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_utildefines.h"
|
||||
@@ -265,10 +266,95 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square)
|
||||
|
||||
}
|
||||
|
||||
/* sets start/end clipping. lar->shb should be initialized */
|
||||
static void shadowbuf_autoclip(Render *re, LampRen *lar)
|
||||
{
|
||||
VlakRen *vlr= NULL;
|
||||
VertRen *ver= NULL;
|
||||
Material *ma= NULL;
|
||||
float minz, maxz, vec[3], viewmat[4][4];
|
||||
unsigned int lay = -1;
|
||||
int a, ok= 1;
|
||||
|
||||
minz= 1.0e30f; maxz= -1.0e30f;
|
||||
Mat4CpyMat4(viewmat, lar->shb->viewmat);
|
||||
|
||||
if(lar->mode & LA_LAYER) lay= lar->lay;
|
||||
|
||||
/* clear clip, is being set if face is visible (clip is calculated for real later) */
|
||||
for(a=0; a<re->totvert; a++) {
|
||||
if((a & 255)==0) ver= RE_findOrAddVert(re, a);
|
||||
else ver++;
|
||||
|
||||
ver->clip= 0;
|
||||
}
|
||||
|
||||
/* set clip in vertices when face visible */
|
||||
for(a=0; a<re->totvlak; a++) {
|
||||
|
||||
if((a & 255)==0) vlr= re->blovl[a>>8];
|
||||
else vlr++;
|
||||
|
||||
/* note; these conditions are copied from zbuffer_shadow() */
|
||||
if(vlr->mat!= ma) {
|
||||
ma= vlr->mat;
|
||||
ok= 1;
|
||||
if((ma->mode & MA_SHADBUF)==0) ok= 0;
|
||||
}
|
||||
|
||||
if(ok && (vlr->lay & lay)) {
|
||||
vlr->v1->clip= 1;
|
||||
vlr->v2->clip= 1;
|
||||
vlr->v3->clip= 1;
|
||||
if(vlr->v4) vlr->v4->clip= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate min and max */
|
||||
for(a=0; a< re->totvert;a++) {
|
||||
if((a & 255)==0) ver= RE_findOrAddVert(re, a);
|
||||
else ver++;
|
||||
|
||||
if(ver->clip) {
|
||||
VECCOPY(vec, ver->co);
|
||||
Mat4MulVecfl(viewmat, vec);
|
||||
/* Z on visible side of lamp space */
|
||||
if(vec[2] < 0.0f) {
|
||||
float inpr, z= -vec[2];
|
||||
|
||||
/* since vec is rotated in lampspace, this is how to get the cosine of angle */
|
||||
/* precision is set 20% larger */
|
||||
vec[2]*= 1.2f;
|
||||
Normalise(vec);
|
||||
inpr= - vec[2];
|
||||
|
||||
if(inpr>=lar->spotsi) {
|
||||
if(z<minz) minz= z;
|
||||
if(z>maxz) maxz= z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* set clipping min and max */
|
||||
if(minz < maxz) {
|
||||
float delta= (maxz - minz)*0.02f; /* threshold to prevent precision issues */
|
||||
|
||||
if(lar->bufflag & LA_SHADBUF_AUTO_START)
|
||||
lar->shb->d= minz - delta;
|
||||
if(lar->bufflag & LA_SHADBUF_AUTO_END)
|
||||
lar->shb->clipend= maxz + delta;
|
||||
|
||||
/* bias was calculated as percentage, we scale it to prevent animation issues */
|
||||
delta= (lar->clipend-lar->clipsta)/(maxz-minz);
|
||||
lar->shb->bias= (int) (delta*(float)lar->shb->bias);
|
||||
}
|
||||
}
|
||||
|
||||
void makeshadowbuf(Render *re, LampRen *lar)
|
||||
{
|
||||
ShadBuf *shb= lar->shb;
|
||||
float wsize, *jitbuf, twozero[2]= {0.0f, 0.0f};
|
||||
float wsize, *jitbuf, twozero[2]= {0.0f, 0.0f}, angle, temp;
|
||||
int *rectz, samples;
|
||||
|
||||
/* jitter, weights */
|
||||
@@ -280,10 +366,17 @@ void makeshadowbuf(Render *re, LampRen *lar)
|
||||
else if(shb->totbuf==9) jitbuf= give_jitter_tab(3);
|
||||
else jitbuf= twozero;
|
||||
|
||||
if(lar->bufflag & (LA_SHADBUF_AUTO_START|LA_SHADBUF_AUTO_END))
|
||||
shadowbuf_autoclip(re, lar);
|
||||
|
||||
/* matrices and window: in winmat the transformation is being put,
|
||||
transforming from observer view to lamp view, including lamp window matrix */
|
||||
|
||||
angle= saacos(lar->spotsi);
|
||||
temp= 0.5f*shb->size*cos(angle)/sin(angle);
|
||||
shb->pixsize= (shb->d)/temp;
|
||||
wsize= shb->pixsize*(shb->size/2.0);
|
||||
|
||||
|
||||
i_window(-wsize, wsize, -wsize, wsize, shb->d, shb->clipend, shb->winmat);
|
||||
MTC_Mat4MulMat4(shb->persmat, shb->viewmat, shb->winmat);
|
||||
/* temp, will be restored */
|
||||
|
||||
@@ -1836,7 +1836,7 @@ void zbuffer_shadow(Render *re, LampRen *lar, int *rectz, int size, float jitx,
|
||||
{
|
||||
ZSpan zspan;
|
||||
VlakRen *vlr= NULL;
|
||||
Material *ma=0;
|
||||
Material *ma= NULL;
|
||||
int a, ok=1, lay= -1;
|
||||
|
||||
if(lar->mode & LA_LAYER) lay= lar->lay;
|
||||
@@ -1860,6 +1860,7 @@ void zbuffer_shadow(Render *re, LampRen *lar, int *rectz, int size, float jitx,
|
||||
if((a & 255)==0) vlr= re->blovl[a>>8];
|
||||
else vlr++;
|
||||
|
||||
/* note, these conditions are copied in shadowbuf_autoclip() */
|
||||
if(vlr->mat!= ma) {
|
||||
ma= vlr->mat;
|
||||
ok= 1;
|
||||
|
||||
Reference in New Issue
Block a user