50 |
|
|
51 |
|
typedef struct { |
52 |
|
COLOR v; /* hemisphere sample value */ |
53 |
+ |
float d; /* reciprocal distance (1/rt) */ |
54 |
|
FVECT p; /* intersection point */ |
55 |
|
} AMBSAMP; /* sample value */ |
56 |
|
|
105 |
|
case VDB_xY: return(db2==VDB_x ? VDB_y : VDB_X); |
106 |
|
case VDB_Xy: return(db2==VDB_y ? VDB_x : VDB_Y); |
107 |
|
} |
108 |
< |
error(INTERNAL, "forbidden diagonal in vdb_edge()"); |
108 |
> |
error(CONSISTENCY, "forbidden diagonal in vdb_edge()"); |
109 |
|
return(-1); |
110 |
|
} |
111 |
|
|
208 |
|
AMBSAMP *ap = &ambsam(hp,i,j); |
209 |
|
RAY ar; |
210 |
|
/* generate hemispherical sample */ |
211 |
< |
if (!getambsamp(&ar, hp, i, j, 0)) |
212 |
< |
goto badsample; |
213 |
< |
/* limit vertex distance */ |
211 |
> |
if (!getambsamp(&ar, hp, i, j, 0) || ar.rt <= FTINY) { |
212 |
> |
memset(ap, 0, sizeof(AMBSAMP)); |
213 |
> |
return(NULL); |
214 |
> |
} |
215 |
> |
ap->d = 1.0/ar.rt; /* limit vertex distance */ |
216 |
|
if (ar.rt > 10.0*thescene.cusize) |
217 |
|
ar.rt = 10.0*thescene.cusize; |
215 |
– |
else if (ar.rt <= FTINY) /* should never happen! */ |
216 |
– |
goto badsample; |
218 |
|
VSUM(ap->p, ar.rorg, ar.rdir, ar.rt); |
219 |
|
copycolor(ap->v, ar.rcol); |
220 |
|
return(ap); |
220 |
– |
badsample: |
221 |
– |
setcolor(ap->v, 0., 0., 0.); |
222 |
– |
VCOPY(ap->p, hp->rp->rop); |
223 |
– |
return(NULL); |
221 |
|
} |
222 |
|
|
223 |
|
|
243 |
|
ep[0] += d2; |
244 |
|
ep[-hp->ns] += d2; |
245 |
|
} |
246 |
< |
if (j) { /* from behind */ |
247 |
< |
d2 = b - bright(ap[-1].v); |
248 |
< |
d2 *= d2; |
249 |
< |
ep[0] += d2; |
250 |
< |
ep[-1] += d2; |
251 |
< |
} |
246 |
> |
if (!j) continue; |
247 |
> |
/* from behind */ |
248 |
> |
d2 = b - bright(ap[-1].v); |
249 |
> |
d2 *= d2; |
250 |
> |
ep[0] += d2; |
251 |
> |
ep[-1] += d2; |
252 |
> |
if (!i) continue; |
253 |
> |
/* diagonal */ |
254 |
> |
d2 = b - bright(ap[-hp->ns-1].v); |
255 |
> |
d2 *= d2; |
256 |
> |
ep[0] += d2; |
257 |
> |
ep[-hp->ns-1] += d2; |
258 |
|
} |
259 |
|
/* correct for number of neighbors */ |
260 |
< |
earr[0] *= 2.f; |
261 |
< |
earr[hp->ns-1] *= 2.f; |
262 |
< |
earr[(hp->ns-1)*hp->ns] *= 2.f; |
263 |
< |
earr[(hp->ns-1)*hp->ns + hp->ns-1] *= 2.f; |
260 |
> |
earr[0] *= 8./3.; |
261 |
> |
earr[hp->ns-1] *= 8./3.; |
262 |
> |
earr[(hp->ns-1)*hp->ns] *= 8./3.; |
263 |
> |
earr[(hp->ns-1)*hp->ns + hp->ns-1] *= 8./3.; |
264 |
|
for (i = 1; i < hp->ns-1; i++) { |
265 |
< |
earr[i*hp->ns] *= 4./3.; |
266 |
< |
earr[i*hp->ns + hp->ns-1] *= 4./3.; |
265 |
> |
earr[i*hp->ns] *= 8./5.; |
266 |
> |
earr[i*hp->ns + hp->ns-1] *= 8./5.; |
267 |
|
} |
268 |
|
for (j = 1; j < hp->ns-1; j++) { |
269 |
< |
earr[j] *= 4./3.; |
270 |
< |
earr[(hp->ns-1)*hp->ns + j] *= 4./3.; |
269 |
> |
earr[j] *= 8./5.; |
270 |
> |
earr[(hp->ns-1)*hp->ns + j] *= 8./5.; |
271 |
|
} |
272 |
|
return(earr); |
273 |
|
} |
278 |
|
ambsupersamp(double acol[3], AMBHEMI *hp, int cnt) |
279 |
|
{ |
280 |
|
float *earr = getambdiffs(hp); |
281 |
< |
double e2sum = 0; |
281 |
> |
double e2rem = 0; |
282 |
|
AMBSAMP *ap; |
283 |
|
RAY ar; |
284 |
< |
COLOR asum; |
284 |
> |
double asum[3]; |
285 |
|
float *ep; |
286 |
< |
int i, j, n; |
286 |
> |
int i, j, n, nss; |
287 |
|
|
288 |
|
if (earr == NULL) /* just skip calc. if no memory */ |
289 |
|
return; |
290 |
< |
/* add up estimated variances */ |
291 |
< |
for (ep = earr + hp->ns*hp->ns; ep-- > earr; ) |
292 |
< |
e2sum += *ep; |
290 |
> |
/* accumulate estimated variances */ |
291 |
> |
for (ep = earr + hp->ns*hp->ns; ep > earr; ) |
292 |
> |
e2rem += *--ep; |
293 |
|
ep = earr; /* perform super-sampling */ |
294 |
|
for (ap = hp->sa, i = 0; i < hp->ns; i++) |
295 |
|
for (j = 0; j < hp->ns; j++, ap++) { |
296 |
< |
int nss = *ep/e2sum*cnt + frandom(); |
297 |
< |
setcolor(asum, 0., 0., 0.); |
296 |
> |
if (e2rem <= FTINY) |
297 |
> |
goto done; /* nothing left to do */ |
298 |
> |
nss = *ep/e2rem*cnt + frandom(); |
299 |
> |
asum[0] = asum[1] = asum[2] = 0.0; |
300 |
|
for (n = 1; n <= nss; n++) { |
301 |
|
if (!getambsamp(&ar, hp, i, j, n)) { |
302 |
|
nss = n-1; |
305 |
|
addcolor(asum, ar.rcol); |
306 |
|
} |
307 |
|
if (nss) { /* update returned ambient value */ |
308 |
< |
const double ssf = 1./(nss + 1); |
308 |
> |
const double ssf = 1./(nss + 1.); |
309 |
|
for (n = 3; n--; ) |
310 |
< |
acol[n] += ssf*colval(asum,n) + |
310 |
> |
acol[n] += ssf*asum[n] + |
311 |
|
(ssf - 1.)*colval(ap->v,n); |
312 |
|
} |
313 |
< |
e2sum -= *ep++; /* update remainders */ |
313 |
> |
e2rem -= *ep++; /* update remainders */ |
314 |
|
cnt -= nss; |
315 |
|
} |
316 |
+ |
done: |
317 |
|
free(earr); |
318 |
|
} |
319 |
|
|
323 |
|
vertex_flags(AMBHEMI *hp) |
324 |
|
{ |
325 |
|
uby8 *vflags = (uby8 *)calloc(hp->ns*hp->ns, sizeof(uby8)); |
320 |
– |
double *dist2a = (double *)malloc(sizeof(double)*hp->ns); |
326 |
|
uby8 *vf; |
327 |
+ |
AMBSAMP *ap; |
328 |
|
int i, j; |
329 |
|
|
330 |
< |
if ((vflags == NULL) | (dist2a == NULL)) |
330 |
> |
if (vflags == NULL) |
331 |
|
error(SYSTEM, "out of memory in vertex_flags()"); |
332 |
< |
vf = vflags; /* compute distances along first row */ |
333 |
< |
for (j = 0; j < hp->ns; j++) { |
334 |
< |
dist2a[j] = dist2(ambsam(hp,0,j).p, hp->rp->rop); |
335 |
< |
++vf; |
336 |
< |
if (!j) continue; |
331 |
< |
if (dist2a[j] >= dist2a[j-1]) |
332 |
< |
vf[0] |= 1<<VDB_x; |
332 |
> |
vf = vflags; |
333 |
> |
ap = hp->sa; /* compute farthest along first row */ |
334 |
> |
for (j = 0; j < hp->ns-1; j++, vf++, ap++) |
335 |
> |
if (ap[0].d <= ap[1].d) |
336 |
> |
vf[0] |= 1<<VDB_X; |
337 |
|
else |
338 |
< |
vf[-1] |= 1<<VDB_X; |
339 |
< |
} |
338 |
> |
vf[1] |= 1<<VDB_x; |
339 |
> |
++vf; ++ap; |
340 |
|
/* flag subsequent rows */ |
341 |
|
for (i = 1; i < hp->ns; i++) { |
342 |
< |
double d2n = dist2(ambsam(hp,i,0).p, hp->rp->rop); |
343 |
< |
for (j = 0; j < hp->ns-1; j++) { |
340 |
< |
double d2 = d2n; |
341 |
< |
if (d2 >= dist2a[j]) /* row before */ |
342 |
> |
for (j = 0; j < hp->ns-1; j++, vf++, ap++) { |
343 |
> |
if (ap[0].d <= ap[-hp->ns].d) /* row before */ |
344 |
|
vf[0] |= 1<<VDB_y; |
345 |
|
else |
346 |
|
vf[-hp->ns] |= 1<<VDB_Y; |
347 |
< |
dist2a[j] = d2n; |
346 |
< |
if (d2 >= dist2a[j+1]) /* diagonal we care about */ |
347 |
> |
if (ap[0].d <= ap[1-hp->ns].d) /* diagonal we care about */ |
348 |
|
vf[0] |= 1<<VDB_Xy; |
349 |
|
else |
350 |
|
vf[1-hp->ns] |= 1<<VDB_xY; |
351 |
< |
d2n = dist2(ambsam(hp,i,j+1).p, hp->rp->rop); |
351 |
< |
if (d2 >= d2n) /* column after */ |
351 |
> |
if (ap[0].d <= ap[1].d) /* column after */ |
352 |
|
vf[0] |= 1<<VDB_X; |
353 |
|
else |
354 |
|
vf[1] |= 1<<VDB_x; |
355 |
– |
++vf; |
355 |
|
} |
356 |
< |
if (d2n >= dist2a[j]) /* final column edge */ |
356 |
> |
if (ap[0].d <= ap[-hp->ns].d) /* final column edge */ |
357 |
|
vf[0] |= 1<<VDB_y; |
358 |
|
else |
359 |
|
vf[-hp->ns] |= 1<<VDB_Y; |
360 |
< |
dist2a[j] = d2n; |
362 |
< |
++vf; |
360 |
> |
++vf; ++ap; |
361 |
|
} |
364 |
– |
free(dist2a); |
362 |
|
return(vflags); |
363 |
|
} |
364 |
|
|
546 |
|
|
547 |
|
|
548 |
|
/* Compute anisotropic radii and eigenvector directions */ |
549 |
< |
static int |
549 |
> |
static void |
550 |
|
eigenvectors(FVECT uv[2], float ra[2], FVECT hessian[3]) |
551 |
|
{ |
552 |
|
double hess2[2][2]; |
568 |
|
if (i == 1) /* double-root (circle) */ |
569 |
|
evalue[1] = evalue[0]; |
570 |
|
if (!i || ((evalue[0] = fabs(evalue[0])) <= FTINY*FTINY) | |
571 |
< |
((evalue[1] = fabs(evalue[1])) <= FTINY*FTINY) ) |
572 |
< |
error(INTERNAL, "bad eigenvalue calculation"); |
573 |
< |
|
571 |
> |
((evalue[1] = fabs(evalue[1])) <= FTINY*FTINY) ) { |
572 |
> |
ra[0] = ra[1] = maxarad; |
573 |
> |
return; |
574 |
> |
} |
575 |
|
if (evalue[0] > evalue[1]) { |
576 |
|
ra[0] = sqrt(sqrt(4.0/evalue[0])); |
577 |
|
ra[1] = sqrt(sqrt(4.0/evalue[1])); |
728 |
|
} |
729 |
|
|
730 |
|
|
731 |
+ |
/* Compute potential light leak direction flags for cache value */ |
732 |
+ |
static uint32 |
733 |
+ |
ambcorral(AMBHEMI *hp, FVECT uv[2], const double r0, const double r1) |
734 |
+ |
{ |
735 |
+ |
const double max_d = 1.0/(minarad*ambacc + 0.001); |
736 |
+ |
const double ang_res = 0.5*PI/(hp->ns-1); |
737 |
+ |
const double ang_step = ang_res/((int)(16/PI*ang_res) + (1+FTINY)); |
738 |
+ |
double avg_d = 0; |
739 |
+ |
uint32 flgs = 0; |
740 |
+ |
int i, j; |
741 |
+ |
/* don't bother for a few samples */ |
742 |
+ |
if (hp->ns < 12) |
743 |
+ |
return(0); |
744 |
+ |
/* check distances overhead */ |
745 |
+ |
for (i = hp->ns*3/4; i-- > hp->ns>>2; ) |
746 |
+ |
for (j = hp->ns*3/4; j-- > hp->ns>>2; ) |
747 |
+ |
avg_d += ambsam(hp,i,j).d; |
748 |
+ |
avg_d *= 4.0/(hp->ns*hp->ns); |
749 |
+ |
if (avg_d*r0 >= 1.0) /* ceiling too low for corral? */ |
750 |
+ |
return(0); |
751 |
+ |
if (avg_d >= max_d) /* insurance */ |
752 |
+ |
return(0); |
753 |
+ |
/* else circle around perimeter */ |
754 |
+ |
for (i = 0; i < hp->ns; i++) |
755 |
+ |
for (j = 0; j < hp->ns; j += !i|(i==hp->ns-1) ? 1 : hp->ns-1) { |
756 |
+ |
AMBSAMP *ap = &ambsam(hp,i,j); |
757 |
+ |
FVECT vec; |
758 |
+ |
double u, v; |
759 |
+ |
double ang, a1; |
760 |
+ |
int abp; |
761 |
+ |
if ((ap->d <= FTINY) | (ap->d >= max_d)) |
762 |
+ |
continue; /* too far or too near */ |
763 |
+ |
VSUB(vec, ap->p, hp->rp->rop); |
764 |
+ |
u = DOT(vec, uv[0]) * ap->d; |
765 |
+ |
v = DOT(vec, uv[1]) * ap->d; |
766 |
+ |
if ((r0*r0*u*u + r1*r1*v*v) * ap->d*ap->d <= 1.0) |
767 |
+ |
continue; /* occluder outside ellipse */ |
768 |
+ |
ang = atan2a(v, u); /* else set direction flags */ |
769 |
+ |
for (a1 = ang-.5*ang_res; a1 <= ang+.5*ang_res; a1 += ang_step) |
770 |
+ |
flgs |= 1L<<(int)(16/PI*(a1 + 2.*PI*(a1 < 0))); |
771 |
+ |
} |
772 |
+ |
return(flgs); |
773 |
+ |
} |
774 |
+ |
|
775 |
+ |
|
776 |
|
int |
777 |
|
doambient( /* compute ambient component */ |
778 |
|
COLOR rcol, /* input/output color */ |
781 |
|
FVECT uv[2], /* returned (optional) */ |
782 |
|
float ra[2], /* returned (optional) */ |
783 |
|
float pg[2], /* returned (optional) */ |
784 |
< |
float dg[2] /* returned (optional) */ |
784 |
> |
float dg[2], /* returned (optional) */ |
785 |
> |
uint32 *crlp /* returned (optional) */ |
786 |
|
) |
787 |
|
{ |
788 |
|
AMBHEMI *hp = inithemi(rcol, r, wt); |
802 |
|
pg[0] = pg[1] = 0.0; |
803 |
|
if (dg != NULL) |
804 |
|
dg[0] = dg[1] = 0.0; |
805 |
+ |
if (crlp != NULL) |
806 |
+ |
*crlp = 0; |
807 |
|
/* sample the hemisphere */ |
808 |
|
acol[0] = acol[1] = acol[2] = 0.0; |
809 |
|
cnt = 0; |
824 |
|
return(-1); /* return value w/o Hessian */ |
825 |
|
} |
826 |
|
cnt = ambssamp*wt + 0.5; /* perform super-sampling? */ |
827 |
< |
if (cnt > 0) |
827 |
> |
if (cnt > 8) |
828 |
|
ambsupersamp(acol, hp, cnt); |
829 |
|
copycolor(rcol, acol); /* final indirect irradiance/PI */ |
830 |
|
if ((ra == NULL) & (pg == NULL) & (dg == NULL)) { |
838 |
|
K = 1.0; |
839 |
|
pg = NULL; |
840 |
|
dg = NULL; |
841 |
+ |
crlp = NULL; |
842 |
|
} |
843 |
|
ap = hp->sa; /* relative Y channel from here on... */ |
844 |
|
for (i = hp->ns*hp->ns; i--; ap++) |
874 |
|
if (ra[0] > maxarad) |
875 |
|
ra[0] = maxarad; |
876 |
|
} |
877 |
+ |
/* flag encroached directions */ |
878 |
+ |
if ((wt >= 0.5-FTINY) & (crlp != NULL)) |
879 |
+ |
*crlp = ambcorral(hp, uv, ra[0]*ambacc, ra[1]*ambacc); |
880 |
|
if (pg != NULL) { /* cap gradient if necessary */ |
881 |
|
d = pg[0]*pg[0]*ra[0]*ra[0] + pg[1]*pg[1]*ra[1]*ra[1]; |
882 |
|
if (d > 1.0) { |