--- ray/src/rt/ambcomp.c 2014/05/07 20:20:24 2.51 +++ ray/src/rt/ambcomp.c 2014/05/11 19:03:37 2.58 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: ambcomp.c,v 2.51 2014/05/07 20:20:24 greg Exp $"; +static const char RCSid[] = "$Id: ambcomp.c,v 2.58 2014/05/11 19:03:37 greg Exp $"; #endif /* * Routines to compute "ambient" values using Monte Carlo @@ -25,29 +25,6 @@ static const char RCSid[] = "$Id: ambcomp.c,v 2.51 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(INTERNAL, "forbidden diagonal in vdb_edge()"); - return(-1); -} - - static AMBHEMI * inithemi( /* initialize sampling hemisphere */ COLOR ac, @@ -190,7 +128,7 @@ getambsamp(RAY *arp, AMBHEMI *hp, int i, int j, int n) spt[1]*hp->uy[ii] + zd*hp->rp->ron[ii]; checknorm(arp->rdir); - dimlist[ndims++] = ambndx(hp,i,j) + 90171; + dimlist[ndims++] = AI(hp,i,j) + 90171; rayvalue(arp); /* evaluate ray */ ndims--; /* apply coefficient */ multcolor(arp->rcol, arp->rcoef); @@ -243,25 +181,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); } @@ -272,22 +216,24 @@ static void ambsupersamp(double acol[3], 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(); + if (e2rem <= FTINY) + goto done; /* nothing left to do */ + nss = *ep/e2rem*cnt + frandom(); asum[0] = asum[1] = asum[2] = 0.0; for (n = 1; n <= nss; n++) { if (!getambsamp(&ar, hp, i, j, n)) { @@ -297,106 +243,44 @@ ambsupersamp(double acol[3], AMBHEMI *hp, int cnt) addcolor(asum, ar.rcol); } if (nss) { /* update returned ambient value */ - const double ssf = 1./(nss + 1); + 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 */ + e2rem -= *ep++; /* update remainders */ cnt -= nss; } +done: free(earr); } -/* Compute vertex flags, indicating farthest in each direction */ -static uby8 * -vertex_flags(AMBHEMI *hp) -{ - 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<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 +294,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 +319,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 +382,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--; ) @@ -537,7 +411,7 @@ add2gradient(FVECT grad, FVECT egrad1, FVECT egrad2, F /* Compute anisotropic radii and eigenvector directions */ -static int +static void eigenvectors(FVECT uv[2], float ra[2], FVECT hessian[3]) { double hess2[2][2]; @@ -559,9 +433,10 @@ eigenvectors(FVECT uv[2], float ra[2], FVECT hessian[3 if (i == 1) /* double-root (circle) */ evalue[1] = evalue[0]; if (!i || ((evalue[0] = fabs(evalue[0])) <= FTINY*FTINY) | - ((evalue[1] = fabs(evalue[1])) <= FTINY*FTINY) ) - error(INTERNAL, "bad eigenvalue calculation"); - + ((evalue[1] = fabs(evalue[1])) <= FTINY*FTINY) ) { + ra[0] = ra[1] = maxarad; + return; + } if (evalue[0] > evalue[1]) { ra[0] = sqrt(sqrt(4.0/evalue[0])); ra[1] = sqrt(sqrt(4.0/evalue[1])); @@ -596,7 +471,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; @@ -618,11 +492,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) @@ -632,7 +504,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) @@ -641,9 +513,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); @@ -655,14 +528,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); @@ -682,7 +556,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); @@ -727,22 +600,26 @@ 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 u, v; + double ang, a1; int i, j; - /* check distances above us */ + /* don't bother for a few samples */ + if (hp->ns < 12) + return(0); + /* check distances overhead */ for (i = hp->ns*3/4; i-- > hp->ns>>2; ) for (j = hp->ns*3/4; j-- > hp->ns>>2; ) avg_d += ambsam(hp,i,j).d; avg_d *= 4.0/(hp->ns*hp->ns); - if (avg_d >= max_d) /* too close to corral? */ + if (avg_d*r0 >= 1.0) /* ceiling too low for corral? */ return(0); + if (avg_d >= max_d) /* insurance */ + return(0); /* else circle around perimeter */ 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); @@ -754,6 +631,20 @@ ambcorral(AMBHEMI *hp, FVECT uv[2], const double r0, c 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); } @@ -823,6 +714,7 @@ doambient( /* compute ambient component */ K = 1.0; pg = NULL; dg = NULL; + crlp = NULL; } ap = hp->sa; /* relative Y channel from here on... */ for (i = hp->ns*hp->ns; i--; ap++) @@ -858,7 +750,8 @@ doambient( /* compute ambient component */ if (ra[0] > maxarad) ra[0] = maxarad; } - if (crlp != NULL) /* flag encroached directions */ + /* flag encroached directions */ + 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];