--- ray/src/rt/ambcomp.c 2014/05/08 04:02:40 2.53 +++ ray/src/rt/ambcomp.c 2014/05/18 18:59:55 2.61 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: ambcomp.c,v 2.53 2014/05/08 04:02:40 greg Exp $"; +static const char RCSid[] = "$Id: ambcomp.c,v 2.61 2014/05/18 18:59:55 greg Exp $"; #endif /* * Routines to compute "ambient" values using Monte Carlo @@ -25,29 +25,6 @@ static const char RCSid[] = "$Id: ambcomp.c,v 2.53 201 extern void SDsquare2disk(double ds[2], double seedx, double seedy); - /* vertex direction bit positions */ -#define VDB_xy 0 -#define VDB_y 01 -#define VDB_x 02 -#define VDB_Xy 03 -#define VDB_xY 04 -#define VDB_X 05 -#define VDB_Y 06 -#define VDB_XY 07 - /* get opposite vertex direction bit */ -#define VDB_OPP(f) (~(f) & 07) - /* adjacent triangle vertex flags */ -static const int adjacent_trifl[8] = { - 0, /* forbidden diagonal */ - 1<ns + (j)) -#define ambsam(h,i,j) (h)->sa[ambndx(h,i,j)] +#define AI(h,i,j) ((i)*(h)->ns + (j)) +#define ambsam(h,i,j) (h)->sa[AI(h,i,j)] typedef struct { FVECT r_i, r_i1, e_i, rcp, rI2_eJ2; double I1, I2; - int valid; } FFTRI; /* vectors and coefficients for Hessian calculation */ -/* Get index for adjacent vertex */ static int -adjacent_verti(AMBHEMI *hp, int i, int j, int dbit) -{ - int i0 = i*hp->ns + j; - - switch (dbit) { - case VDB_y: return(i0 - hp->ns); - case VDB_x: return(i0 - 1); - case VDB_Xy: return(i0 - hp->ns + 1); - case VDB_xY: return(i0 + hp->ns - 1); - case VDB_X: return(i0 + 1); - case VDB_Y: return(i0 + hp->ns); - /* the following should never occur */ - case VDB_xy: return(i0 - hp->ns - 1); - case VDB_XY: return(i0 + hp->ns + 1); - } - return(-1); -} - - -/* Get vertex direction bit for the opposite edge to complete triangle */ -static int -vdb_edge(int db1, int db2) -{ - switch (db1) { - case VDB_x: return(db2==VDB_y ? VDB_Xy : VDB_Y); - case VDB_y: return(db2==VDB_x ? VDB_xY : VDB_X); - case VDB_X: return(db2==VDB_Xy ? VDB_y : VDB_xY); - case VDB_Y: return(db2==VDB_xY ? VDB_x : VDB_Xy); - case VDB_xY: return(db2==VDB_x ? VDB_y : VDB_X); - case VDB_Xy: return(db2==VDB_y ? VDB_x : VDB_Y); - } - error(CONSISTENCY, "forbidden diagonal in vdb_edge()"); - return(-1); -} - - -static AMBHEMI * -inithemi( /* initialize sampling hemisphere */ - COLOR ac, - RAY *r, - double wt +ambsample( /* initial ambient division sample */ + AMBHEMI *hp, + int i, + int j, + int n ) { - AMBHEMI *hp; - double d; - int n, i; - /* set number of divisions */ - if (ambacc <= FTINY && - wt > (d = 0.8*intens(ac)*r->rweight/(ambdiv*minweight))) - wt = d; /* avoid ray termination */ - n = sqrt(ambdiv * wt) + 0.5; - i = 1 + 5*(ambacc > FTINY); /* minimum number of samples */ - if (n < i) - n = i; - /* allocate sampling array */ - hp = (AMBHEMI *)malloc(sizeof(AMBHEMI) + sizeof(AMBSAMP)*(n*n - 1)); - if (hp == NULL) - return(NULL); - hp->rp = r; - hp->ns = n; - /* assign coefficient */ - copycolor(hp->acoef, ac); - d = 1.0/(n*n); - scalecolor(hp->acoef, d); - /* make tangent plane axes */ - hp->uy[0] = 0.5 - frandom(); - hp->uy[1] = 0.5 - frandom(); - hp->uy[2] = 0.5 - frandom(); - for (i = 3; i--; ) - if ((-0.6 < r->ron[i]) & (r->ron[i] < 0.6)) - break; - if (i < 0) - error(CONSISTENCY, "bad ray direction in inithemi"); - hp->uy[i] = 1.0; - VCROSS(hp->ux, hp->uy, r->ron); - normalize(hp->ux); - VCROSS(hp->uy, r->ron, hp->ux); - /* we're ready to sample */ - return(hp); -} - - -/* Sample ambient division and apply weighting coefficient */ -static int -getambsamp(RAY *arp, AMBHEMI *hp, int i, int j, int n) -{ + AMBSAMP *ap = &ambsam(hp,i,j); + RAY ar; int hlist[3], ii; double spt[2], zd; + /* generate hemispherical sample */ /* ambient coefficient for weight */ if (ambacc > FTINY) - setcolor(arp->rcoef, AVGREFL, AVGREFL, AVGREFL); + setcolor(ar.rcoef, AVGREFL, AVGREFL, AVGREFL); else - copycolor(arp->rcoef, hp->acoef); - if (rayorigin(arp, AMBIENT, hp->rp, arp->rcoef) < 0) + copycolor(ar.rcoef, hp->acoef); + if (rayorigin(&ar, AMBIENT, hp->rp, ar.rcoef) < 0) { + if (!n) memset(ap, 0, sizeof(AMBSAMP)); return(0); + } if (ambacc > FTINY) { - multcolor(arp->rcoef, hp->acoef); - scalecolor(arp->rcoef, 1./AVGREFL); + multcolor(ar.rcoef, hp->acoef); + scalecolor(ar.rcoef, 1./AVGREFL); } hlist[0] = hp->rp->rno; hlist[1] = j; @@ -186,41 +89,38 @@ getambsamp(RAY *arp, AMBHEMI *hp, int i, int j, int n) SDsquare2disk(spt, (j+spt[1])/hp->ns, (i+spt[0])/hp->ns); zd = sqrt(1. - spt[0]*spt[0] - spt[1]*spt[1]); for (ii = 3; ii--; ) - arp->rdir[ii] = spt[0]*hp->ux[ii] + + ar.rdir[ii] = spt[0]*hp->ux[ii] + spt[1]*hp->uy[ii] + zd*hp->rp->ron[ii]; - checknorm(arp->rdir); - dimlist[ndims++] = ambndx(hp,i,j) + 90171; - rayvalue(arp); /* evaluate ray */ - ndims--; /* apply coefficient */ - multcolor(arp->rcol, arp->rcoef); + checknorm(ar.rdir); + dimlist[ndims++] = AI(hp,i,j) + 90171; + rayvalue(&ar); /* evaluate ray */ + ndims--; + if (ar.rt <= FTINY) + return(0); /* should never happen */ + multcolor(ar.rcol, ar.rcoef); /* apply coefficient */ + if (!n || ar.rt*ap->d < 1.0) /* new/closer distance? */ + ap->d = 1.0/ar.rt; + if (!n) { /* record first vertex & value */ + if (ar.rt > 10.0*thescene.cusize) + ar.rt = 10.0*thescene.cusize; + VSUM(ap->p, ar.rorg, ar.rdir, ar.rt); + copycolor(ap->v, ar.rcol); + } else { /* else update recorded value */ + hp->acol[RED] -= colval(ap->v,RED); + hp->acol[GRN] -= colval(ap->v,GRN); + hp->acol[BLU] -= colval(ap->v,BLU); + zd = 1.0/(double)(n+1); + scalecolor(ar.rcol, zd); + zd *= (double)n; + scalecolor(ap->v, zd); + addcolor(ap->v, ar.rcol); + } + addcolor(hp->acol, ap->v); /* add to our sum */ return(1); } -static AMBSAMP * -ambsample( /* initial ambient division sample */ - AMBHEMI *hp, - int i, - int j -) -{ - AMBSAMP *ap = &ambsam(hp,i,j); - RAY ar; - /* generate hemispherical sample */ - if (!getambsamp(&ar, hp, i, j, 0) || ar.rt <= FTINY) { - memset(ap, 0, sizeof(AMBSAMP)); - return(NULL); - } - ap->d = 1.0/ar.rt; /* limit vertex distance */ - if (ar.rt > 10.0*thescene.cusize) - ar.rt = 10.0*thescene.cusize; - VSUM(ap->p, ar.rorg, ar.rdir, ar.rt); - copycolor(ap->v, ar.rcol); - return(ap); -} - - /* Estimate errors based on ambient division differences */ static float * getambdiffs(AMBHEMI *hp) @@ -243,25 +143,31 @@ getambdiffs(AMBHEMI *hp) ep[0] += d2; ep[-hp->ns] += d2; } - if (j) { /* from behind */ - d2 = b - bright(ap[-1].v); - d2 *= d2; - ep[0] += d2; - ep[-1] += d2; - } + if (!j) continue; + /* from behind */ + d2 = b - bright(ap[-1].v); + d2 *= d2; + ep[0] += d2; + ep[-1] += d2; + if (!i) continue; + /* diagonal */ + d2 = b - bright(ap[-hp->ns-1].v); + d2 *= d2; + ep[0] += d2; + ep[-hp->ns-1] += d2; } /* correct for number of neighbors */ - earr[0] *= 2.f; - earr[hp->ns-1] *= 2.f; - earr[(hp->ns-1)*hp->ns] *= 2.f; - earr[(hp->ns-1)*hp->ns + hp->ns-1] *= 2.f; + earr[0] *= 8./3.; + earr[hp->ns-1] *= 8./3.; + earr[(hp->ns-1)*hp->ns] *= 8./3.; + earr[(hp->ns-1)*hp->ns + hp->ns-1] *= 8./3.; for (i = 1; i < hp->ns-1; i++) { - earr[i*hp->ns] *= 4./3.; - earr[i*hp->ns + hp->ns-1] *= 4./3.; + earr[i*hp->ns] *= 8./5.; + earr[i*hp->ns + hp->ns-1] *= 8./5.; } for (j = 1; j < hp->ns-1; j++) { - earr[j] *= 4./3.; - earr[(hp->ns-1)*hp->ns + j] *= 4./3.; + earr[j] *= 8./5.; + earr[(hp->ns-1)*hp->ns + j] *= 8./5.; } return(earr); } @@ -269,134 +175,125 @@ getambdiffs(AMBHEMI *hp) /* Perform super-sampling on hemisphere (introduces bias) */ static void -ambsupersamp(double acol[3], AMBHEMI *hp, int cnt) +ambsupersamp(AMBHEMI *hp, int cnt) { float *earr = getambdiffs(hp); - double e2sum = 0.0; + double e2rem = 0; AMBSAMP *ap; RAY ar; - double asum[3]; float *ep; - int i, j, n; + int i, j, n, nss; if (earr == NULL) /* just skip calc. if no memory */ return; - /* add up estimated variances */ - for (ep = earr + hp->ns*hp->ns; ep-- > earr; ) - e2sum += *ep; + /* accumulate estimated variances */ + for (ep = earr + hp->ns*hp->ns; ep > earr; ) + e2rem += *--ep; ep = earr; /* perform super-sampling */ for (ap = hp->sa, i = 0; i < hp->ns; i++) for (j = 0; j < hp->ns; j++, ap++) { - int nss = *ep/e2sum*cnt + frandom(); - asum[0] = asum[1] = asum[2] = 0.0; - for (n = 1; n <= nss; n++) { - if (!getambsamp(&ar, hp, i, j, n)) { - nss = n-1; - break; - } - addcolor(asum, ar.rcol); - } - if (nss) { /* update returned ambient value */ - const double ssf = 1./(nss + 1); - for (n = 3; n--; ) - acol[n] += ssf*asum[n] + - (ssf - 1.)*colval(ap->v,n); - } - e2sum -= *ep++; /* update remainders */ - cnt -= nss; + if (e2rem <= FTINY) + goto done; /* nothing left to do */ + nss = *ep/e2rem*cnt + frandom(); + for (n = 1; n <= nss; n++) + cnt -= ambsample(hp, i, j, n); + e2rem -= *ep++; /* update remainder */ } +done: free(earr); } -/* Compute vertex flags, indicating farthest in each direction */ -static uby8 * -vertex_flags(AMBHEMI *hp) +static AMBHEMI * +samp_hemi( /* sample indirect hemisphere */ + COLOR rcol, + RAY *r, + double wt +) { - uby8 *vflags = (uby8 *)calloc(hp->ns*hp->ns, sizeof(uby8)); - uby8 *vf; - AMBSAMP *ap; - int i, j; - - if (vflags == NULL) - error(SYSTEM, "out of memory in vertex_flags()"); - vf = vflags; - ap = hp->sa; /* compute farthest along first row */ - for (j = 0; j < hp->ns-1; j++, vf++, ap++) - if (ap[0].d <= ap[1].d) - vf[0] |= 1<ns; i++) { - for (j = 0; j < hp->ns-1; j++, vf++, ap++) { - if (ap[0].d <= ap[-hp->ns].d) /* row before */ - vf[0] |= 1<ns] |= 1<ns].d) /* diagonal we care about */ - vf[0] |= 1<ns] |= 1<ns].d) /* final column edge */ - vf[0] |= 1<ns] |= 1< (d = 0.8*intens(rcol)*r->rweight/(ambdiv*minweight))) + wt = d; /* avoid ray termination */ + n = sqrt(ambdiv * wt) + 0.5; + i = 1 + 5*(ambacc > FTINY); /* minimum number of samples */ + if (n < i) + n = i; + /* allocate sampling array */ + hp = (AMBHEMI *)malloc(sizeof(AMBHEMI) + sizeof(AMBSAMP)*(n*n - 1)); + if (hp == NULL) + error(SYSTEM, "out of memory in samp_hemi"); + hp->rp = r; + hp->ns = n; + hp->acol[RED] = hp->acol[GRN] = hp->acol[BLU] = 0.0; + hp->sampOK = 0; + /* assign coefficient */ + copycolor(hp->acoef, rcol); + d = 1.0/(n*n); + scalecolor(hp->acoef, d); + /* make tangent plane axes */ + hp->uy[0] = 0.5 - frandom(); + hp->uy[1] = 0.5 - frandom(); + hp->uy[2] = 0.5 - frandom(); + for (i = 3; i--; ) + if ((-0.6 < r->ron[i]) & (r->ron[i] < 0.6)) + break; + if (i < 0) + error(CONSISTENCY, "bad ray direction in samp_hemi"); + hp->uy[i] = 1.0; + VCROSS(hp->ux, hp->uy, r->ron); + normalize(hp->ux); + VCROSS(hp->uy, r->ron, hp->ux); + /* sample divisions */ + for (i = hp->ns; i--; ) + for (j = hp->ns; j--; ) + hp->sampOK += ambsample(hp, i, j, 0); + copycolor(rcol, hp->acol); + if (!hp->sampOK) { /* utter failure? */ + free(hp); + return(NULL); } - return(vflags); + if (hp->sampOK < hp->ns*hp->ns) { + hp->sampOK *= -1; /* soft failure */ + return(hp); + } + n = ambssamp*wt + 0.5; + if (n > 8) { /* perform super-sampling? */ + ambsupersamp(hp, n); + copycolor(rcol, hp->acol); + } + return(hp); /* all is well */ } /* Return brightness of farthest ambient sample */ static double -back_ambval(AMBHEMI *hp, int i, int j, int dbit1, int dbit2, const uby8 *vflags) +back_ambval(AMBHEMI *hp, const int n1, const int n2, const int n3) { - const int v0 = ambndx(hp,i,j); - const int tflags = (1<sa[v0].v,CIEY)); - v1 = adjacent_verti(hp, i, j, dbit1); - if (vflags[v0] & 1<v2 */ - return(colval(hp->sa[v1].v,CIEY)); - v2 = adjacent_verti(hp, i, j, dbit2); - if (vflags[v0] & 1<v1 */ - return(colval(hp->sa[v2].v,CIEY)); - /* else check if v1>v2 */ - if (vflags[v1] & 1<sa[v1].v,CIEY)); - return(colval(hp->sa[v2].v,CIEY)); + if (hp->sa[n1].d <= hp->sa[n2].d) { + if (hp->sa[n1].d <= hp->sa[n3].d) + return(colval(hp->sa[n1].v,CIEY)); + return(colval(hp->sa[n3].v,CIEY)); + } + if (hp->sa[n2].d <= hp->sa[n3].d) + return(colval(hp->sa[n2].v,CIEY)); + return(colval(hp->sa[n3].v,CIEY)); } /* Compute vectors and coefficients for Hessian/gradient calcs */ static void -comp_fftri(FFTRI *ftp, AMBHEMI *hp, int i, int j, int dbit, const uby8 *vflags) +comp_fftri(FFTRI *ftp, AMBHEMI *hp, const int n0, const int n1) { - const int i0 = ambndx(hp,i,j); - double rdot_cp, dot_e, dot_er, rdot_r, rdot_r1, J2; - int i1, ii; + double rdot_cp, dot_e, dot_er, rdot_r, rdot_r1, J2; + int ii; - ftp->valid = 0; /* check if we can skip this edge */ - ii = adjacent_trifl[dbit]; - if ((vflags[i0] & ii) == ii) /* cancels if vertex used as value */ - return; - i1 = adjacent_verti(hp, i, j, dbit); - ii = adjacent_trifl[VDB_OPP(dbit)]; - if ((vflags[i1] & ii) == ii) /* on either end (for both triangles) */ - return; - /* else go ahead with calculation */ - VSUB(ftp->r_i, hp->sa[i0].p, hp->rp->rop); - VSUB(ftp->r_i1, hp->sa[i1].p, hp->rp->rop); - VSUB(ftp->e_i, hp->sa[i1].p, hp->sa[i0].p); + VSUB(ftp->r_i, hp->sa[n0].p, hp->rp->rop); + VSUB(ftp->r_i1, hp->sa[n1].p, hp->rp->rop); + VSUB(ftp->e_i, hp->sa[n1].p, hp->sa[n0].p); VCROSS(ftp->rcp, ftp->r_i, ftp->r_i1); rdot_cp = 1.0/DOT(ftp->rcp,ftp->rcp); dot_e = DOT(ftp->e_i,ftp->e_i); @@ -410,7 +307,6 @@ comp_fftri(FFTRI *ftp, AMBHEMI *hp, int i, int j, int J2 = ( 0.5*(rdot_r - rdot_r1) - dot_er*ftp->I2 ) / dot_e; for (ii = 3; ii--; ) ftp->rI2_eJ2[ii] = ftp->I2*ftp->r_i[ii] + J2*ftp->e_i[ii]; - ftp->valid++; } @@ -436,11 +332,6 @@ comp_hessian(FVECT hess[3], FFTRI *ftp, FVECT nrm) double d1, d2, d3, d4; double I3, J3, K3; int i, j; - - if (!ftp->valid) { /* preemptive test */ - memset(hess, 0, sizeof(FVECT)*3); - return; - } /* compute intermediate coefficients */ d1 = 1.0/DOT(ftp->r_i,ftp->r_i); d2 = 1.0/DOT(ftp->r_i1,ftp->r_i1); @@ -504,10 +395,6 @@ comp_gradient(FVECT grad, FFTRI *ftp, FVECT nrm) double f1; int i; - if (!ftp->valid) { /* preemptive test */ - memset(grad, 0, sizeof(FVECT)); - return; - } f1 = 2.0*DOT(nrm, ftp->rcp); VCROSS(ncp, nrm, ftp->e_i); for (i = 3; i--; ) @@ -597,7 +484,6 @@ ambHessian( /* anisotropic radii & pos. gradient */ static char memerrmsg[] = "out of memory in ambHessian()"; FVECT (*hessrow)[3] = NULL; FVECT *gradrow = NULL; - uby8 *vflags; FVECT hessian[3]; FVECT gradient; FFTRI fftr; @@ -619,11 +505,9 @@ ambHessian( /* anisotropic radii & pos. gradient */ error(SYSTEM, memerrmsg); memset(gradient, 0, sizeof(gradient)); } - /* get vertex position flags */ - vflags = vertex_flags(hp); /* compute first row of edges */ for (j = 0; j < hp->ns-1; j++) { - comp_fftri(&fftr, hp, 0, j, VDB_X, vflags); + comp_fftri(&fftr, hp, AI(hp,0,j), AI(hp,0,j+1)); if (hessrow != NULL) comp_hessian(hessrow[j], &fftr, hp->rp->ron); if (gradrow != NULL) @@ -633,7 +517,7 @@ ambHessian( /* anisotropic radii & pos. gradient */ for (i = 0; i < hp->ns-1; i++) { FVECT hesscol[3]; /* compute first vertical edge */ FVECT gradcol; - comp_fftri(&fftr, hp, i, 0, VDB_Y, vflags); + comp_fftri(&fftr, hp, AI(hp,i,0), AI(hp,i+1,0)); if (hessrow != NULL) comp_hessian(hesscol, &fftr, hp->rp->ron); if (gradrow != NULL) @@ -642,9 +526,10 @@ ambHessian( /* anisotropic radii & pos. gradient */ FVECT hessdia[3]; /* compute triangle contributions */ FVECT graddia; double backg; - backg = back_ambval(hp, i, j, VDB_X, VDB_Y, vflags); + backg = back_ambval(hp, AI(hp,i,j), + AI(hp,i,j+1), AI(hp,i+1,j)); /* diagonal (inner) edge */ - comp_fftri(&fftr, hp, i, j+1, VDB_xY, vflags); + comp_fftri(&fftr, hp, AI(hp,i,j+1), AI(hp,i+1,j)); if (hessrow != NULL) { comp_hessian(hessdia, &fftr, hp->rp->ron); rev_hessian(hesscol); @@ -656,14 +541,15 @@ ambHessian( /* anisotropic radii & pos. gradient */ add2gradient(gradient, gradrow[j], graddia, gradcol, backg); } /* initialize edge in next row */ - comp_fftri(&fftr, hp, i+1, j+1, VDB_x, vflags); + comp_fftri(&fftr, hp, AI(hp,i+1,j+1), AI(hp,i+1,j)); if (hessrow != NULL) comp_hessian(hessrow[j], &fftr, hp->rp->ron); if (gradrow != NULL) comp_gradient(gradrow[j], &fftr, hp->rp->ron); /* new column edge & paired triangle */ - backg = back_ambval(hp, i+1, j+1, VDB_x, VDB_y, vflags); - comp_fftri(&fftr, hp, i, j+1, VDB_Y, vflags); + backg = back_ambval(hp, AI(hp,i+1,j+1), + AI(hp,i+1,j), AI(hp,i,j+1)); + comp_fftri(&fftr, hp, AI(hp,i,j+1), AI(hp,i+1,j+1)); if (hessrow != NULL) { comp_hessian(hesscol, &fftr, hp->rp->ron); rev_hessian(hessdia); @@ -683,7 +569,6 @@ ambHessian( /* anisotropic radii & pos. gradient */ /* release row buffers */ if (hessrow != NULL) free(hessrow); if (gradrow != NULL) free(gradrow); - free(vflags); if (ra != NULL) /* extract eigenvectors & radii */ eigenvectors(uv, ra, hessian); @@ -728,6 +613,9 @@ ambcorral(AMBHEMI *hp, FVECT uv[2], const double r0, c const double ang_step = ang_res/((int)(16/PI*ang_res) + (1+FTINY)); double avg_d = 0; uint32 flgs = 0; + FVECT vec; + double d, u, v; + double ang, a1; int i, j; /* don't bother for a few samples */ if (hp->ns < 12) @@ -745,21 +633,33 @@ ambcorral(AMBHEMI *hp, FVECT uv[2], const double r0, c for (i = 0; i < hp->ns; i++) for (j = 0; j < hp->ns; j += !i|(i==hp->ns-1) ? 1 : hp->ns-1) { AMBSAMP *ap = &ambsam(hp,i,j); - FVECT vec; - double u, v; - double ang, a1; - int abp; if ((ap->d <= FTINY) | (ap->d >= max_d)) continue; /* too far or too near */ VSUB(vec, ap->p, hp->rp->rop); - u = DOT(vec, uv[0]) * ap->d; - v = DOT(vec, uv[1]) * ap->d; + d = DOT(vec, hp->rp->ron); + d = 1.0/sqrt(DOT(vec,vec) - d*d); + u = DOT(vec, uv[0]) * d; + v = DOT(vec, uv[1]) * d; if ((r0*r0*u*u + r1*r1*v*v) * ap->d*ap->d <= 1.0) continue; /* occluder outside ellipse */ ang = atan2a(v, u); /* else set direction flags */ for (a1 = ang-.5*ang_res; a1 <= ang+.5*ang_res; a1 += ang_step) flgs |= 1L<<(int)(16/PI*(a1 + 2.*PI*(a1 < 0))); } + /* add low-angle incident (< 20deg) */ + if (fabs(hp->rp->rod) <= 0.342) { + u = -DOT(hp->rp->rdir, uv[0]); + v = -DOT(hp->rp->rdir, uv[1]); + if ((r0*r0*u*u + r1*r1*v*v) > hp->rp->rot*hp->rp->rot) { + ang = atan2a(v, u); + ang += 2.*PI*(ang < 0); + ang *= 16/PI; + if ((ang < .5) | (ang >= 31.5)) + flgs |= 0x80000001; + else + flgs |= 3L<<(int)(ang-.5); + } + } return(flgs); } @@ -776,15 +676,12 @@ doambient( /* compute ambient component */ uint32 *crlp /* returned (optional) */ ) { - AMBHEMI *hp = inithemi(rcol, r, wt); - int cnt; + AMBHEMI *hp = samp_hemi(rcol, r, wt); FVECT my_uv[2]; - double d, K, acol[3]; + double d, K; AMBSAMP *ap; - int i, j; - /* check/initialize */ - if (hp == NULL) - return(0); + int i; + /* clear return values */ if (uv != NULL) memset(uv, 0, sizeof(FVECT)*2); if (ra != NULL) @@ -795,34 +692,15 @@ doambient( /* compute ambient component */ dg[0] = dg[1] = 0.0; if (crlp != NULL) *crlp = 0; - /* sample the hemisphere */ - acol[0] = acol[1] = acol[2] = 0.0; - cnt = 0; - for (i = hp->ns; i--; ) - for (j = hp->ns; j--; ) - if ((ap = ambsample(hp, i, j)) != NULL) { - addcolor(acol, ap->v); - ++cnt; - } - if (!cnt) { - setcolor(rcol, 0.0, 0.0, 0.0); - free(hp); - return(0); /* no valid samples */ + if (hp == NULL) /* sampling falure? */ + return(0); + + if ((ra == NULL) & (pg == NULL) & (dg == NULL) || + (hp->sampOK < 0) | (hp->ns < 4)) { + free(hp); /* Hessian not requested/possible */ + return(-1); /* value-only return value */ } - if (cnt < hp->ns*hp->ns) { /* incomplete sampling? */ - copycolor(rcol, acol); - free(hp); - return(-1); /* return value w/o Hessian */ - } - cnt = ambssamp*wt + 0.5; /* perform super-sampling? */ - if (cnt > 8) - ambsupersamp(acol, hp, cnt); - copycolor(rcol, acol); /* final indirect irradiance/PI */ - if ((ra == NULL) & (pg == NULL) & (dg == NULL)) { - free(hp); - return(-1); /* no radius or gradient calc. */ - } - if ((d = bright(acol)) > FTINY) { /* normalize Y values */ + if ((d = bright(rcol)) > FTINY) { /* normalize Y values */ d = 0.99*(hp->ns*hp->ns)/d; K = 0.01; } else { /* or fall back on geometric Hessian */ @@ -857,7 +735,7 @@ doambient( /* compute ambient component */ if (ra[1] < minarad) ra[1] = minarad; } - ra[0] *= d = 1.0/sqrt(sqrt(wt)); + ra[0] *= d = 1.0/sqrt(wt); if ((ra[1] *= d) > 2.0*ra[0]) ra[1] = 2.0*ra[0]; if (ra[1] > maxarad) { @@ -866,7 +744,7 @@ doambient( /* compute ambient component */ ra[0] = maxarad; } /* flag encroached directions */ - if ((wt >= 0.5-FTINY) & (crlp != NULL)) + if ((wt >= 0.89*AVGREFL) & (crlp != NULL)) *crlp = ambcorral(hp, uv, ra[0]*ambacc, ra[1]*ambacc); if (pg != NULL) { /* cap gradient if necessary */ d = pg[0]*pg[0]*ra[0]*ra[0] + pg[1]*pg[1]*ra[1]*ra[1];