26 |
|
#endif |
27 |
|
|
28 |
|
typedef struct { |
29 |
– |
COLOR v; /* hemisphere sample value */ |
30 |
– |
float d; /* reciprocal distance */ |
29 |
|
FVECT p; /* intersection point */ |
30 |
+ |
float d; /* reciprocal distance */ |
31 |
+ |
SCOLOR v; /* hemisphere sample value */ |
32 |
|
} AMBSAMP; /* sample value */ |
33 |
|
|
34 |
|
typedef struct { |
35 |
|
RAY *rp; /* originating ray sample */ |
36 |
|
int ns; /* number of samples per axis */ |
37 |
|
int sampOK; /* acquired full sample set? */ |
38 |
< |
COLOR acoef; /* division contribution coefficient */ |
39 |
< |
double acol[3]; /* accumulated color */ |
38 |
> |
SCOLOR acoef; /* division contribution coefficient */ |
39 |
> |
SCOLOR acol; /* accumulated color */ |
40 |
|
FVECT ux, uy; /* tangent axis unit vectors */ |
41 |
|
AMBSAMP sa[1]; /* sample array (extends struct) */ |
42 |
|
} AMBHEMI; /* ambient sample hemisphere */ |
103 |
|
/* generate hemispherical sample */ |
104 |
|
/* ambient coefficient for weight */ |
105 |
|
if (ambacc > FTINY) |
106 |
< |
setcolor(ar.rcoef, AVGREFL, AVGREFL, AVGREFL); |
106 |
> |
setscolor(ar.rcoef, AVGREFL, AVGREFL, AVGREFL); |
107 |
|
else |
108 |
< |
copycolor(ar.rcoef, hp->acoef); |
108 |
> |
copyscolor(ar.rcoef, hp->acoef); |
109 |
|
if (rayorigin(&ar, AMBIENT, hp->rp, ar.rcoef) < 0) |
110 |
|
return(0); |
111 |
|
if (ambacc > FTINY) { |
112 |
< |
multcolor(ar.rcoef, hp->acoef); |
113 |
< |
scalecolor(ar.rcoef, 1./AVGREFL); |
112 |
> |
smultscolor(ar.rcoef, hp->acoef); |
113 |
> |
scalescolor(ar.rcoef, 1./AVGREFL); |
114 |
|
} |
115 |
|
hlist[0] = hp->rp->rno; |
116 |
|
hlist[1] = j; |
135 |
|
zd = raydistance(&ar); |
136 |
|
if (zd <= FTINY) |
137 |
|
return(0); /* should never happen */ |
138 |
< |
multcolor(ar.rcol, ar.rcoef); /* apply coefficient */ |
138 |
> |
smultscolor(ar.rcol, ar.rcoef); /* apply coefficient */ |
139 |
|
if (zd*ap->d < 1.0) /* new/closer distance? */ |
140 |
|
ap->d = 1.0/zd; |
141 |
|
if (!n) { /* record first vertex & value */ |
142 |
|
if (zd > 10.0*thescene.cusize + 1000.) |
143 |
|
zd = 10.0*thescene.cusize + 1000.; |
144 |
|
VSUM(ap->p, ar.rorg, ar.rdir, zd); |
145 |
< |
copycolor(ap->v, ar.rcol); |
145 |
> |
copyscolor(ap->v, ar.rcol); |
146 |
|
} else { /* else update recorded value */ |
147 |
< |
hp->acol[RED] -= colval(ap->v,RED); |
148 |
< |
hp->acol[GRN] -= colval(ap->v,GRN); |
149 |
< |
hp->acol[BLU] -= colval(ap->v,BLU); |
147 |
> |
sopscolor(hp->acol, -=, ap->v); |
148 |
|
zd = 1.0/(double)(n+1); |
149 |
< |
scalecolor(ar.rcol, zd); |
149 |
> |
scalescolor(ar.rcol, zd); |
150 |
|
zd *= (double)n; |
151 |
< |
scalecolor(ap->v, zd); |
152 |
< |
addcolor(ap->v, ar.rcol); |
151 |
> |
scalescolor(ap->v, zd); |
152 |
> |
saddscolor(ap->v, ar.rcol); |
153 |
|
} |
154 |
< |
addcolor(hp->acol, ap->v); /* add to our sum */ |
154 |
> |
saddscolor(hp->acol, ap->v); /* add to our sum */ |
155 |
|
return(1); |
156 |
|
} |
157 |
|
|
172 |
|
/* sum squared neighbor diffs */ |
173 |
|
for (ap = hp->sa, ep = earr, i = 0; i < hp->ns; i++) |
174 |
|
for (j = 0; j < hp->ns; j++, ap++, ep++) { |
175 |
< |
b = bright(ap[0].v); |
175 |
> |
b = pbright(ap[0].v); |
176 |
|
if (i) { /* from above */ |
177 |
< |
b1 = bright(ap[-hp->ns].v); |
177 |
> |
b1 = pbright(ap[-hp->ns].v); |
178 |
|
d2 = b - b1; |
179 |
< |
d2 *= d2*normf/(b + b1); |
179 |
> |
d2 *= d2*normf/(b + b1 + FTINY); |
180 |
|
ep[0] += d2; |
181 |
|
ep[-hp->ns] += d2; |
182 |
|
} |
183 |
|
if (!j) continue; |
184 |
|
/* from behind */ |
185 |
< |
b1 = bright(ap[-1].v); |
185 |
> |
b1 = pbright(ap[-1].v); |
186 |
|
d2 = b - b1; |
187 |
< |
d2 *= d2*normf/(b + b1); |
187 |
> |
d2 *= d2*normf/(b + b1 + FTINY); |
188 |
|
ep[0] += d2; |
189 |
|
ep[-1] += d2; |
190 |
|
if (!i) continue; |
191 |
|
/* diagonal */ |
192 |
< |
b1 = bright(ap[-hp->ns-1].v); |
192 |
> |
b1 = pbright(ap[-hp->ns-1].v); |
193 |
|
d2 = b - b1; |
194 |
< |
d2 *= d2*normf/(b + b1); |
194 |
> |
d2 *= d2*normf/(b + b1 + FTINY); |
195 |
|
ep[0] += d2; |
196 |
|
ep[-hp->ns-1] += d2; |
197 |
|
} |
243 |
|
|
244 |
|
static AMBHEMI * |
245 |
|
samp_hemi( /* sample indirect hemisphere */ |
246 |
< |
COLOR rcol, |
246 |
> |
SCOLOR rcol, |
247 |
|
RAY *r, |
248 |
|
double wt |
249 |
|
) |
252 |
|
double d; |
253 |
|
int n, i, j; |
254 |
|
/* insignificance check */ |
255 |
< |
if (bright(rcol) <= FTINY) |
255 |
> |
d = sintens(rcol); |
256 |
> |
if (d <= FTINY) |
257 |
|
return(NULL); |
258 |
|
/* set number of divisions */ |
259 |
|
if (ambacc <= FTINY && |
260 |
< |
wt > (d = 0.8*intens(rcol)*r->rweight/(ambdiv*minweight))) |
260 |
> |
wt > (d *= 0.8*r->rweight/(ambdiv*minweight))) |
261 |
|
wt = d; /* avoid ray termination */ |
262 |
|
n = sqrt(ambdiv * wt) + 0.5; |
263 |
|
i = 1 + (MINADIV-1)*(ambacc > FTINY); |
269 |
|
error(SYSTEM, "out of memory in samp_hemi"); |
270 |
|
hp->rp = r; |
271 |
|
hp->ns = n; |
272 |
< |
hp->acol[RED] = hp->acol[GRN] = hp->acol[BLU] = 0.0; |
272 |
> |
scolorblack(hp->acol); |
273 |
|
memset(hp->sa, 0, sizeof(AMBSAMP)*n*n); |
274 |
|
hp->sampOK = 0; |
275 |
|
/* assign coefficient */ |
276 |
< |
copycolor(hp->acoef, rcol); |
276 |
> |
copyscolor(hp->acoef, rcol); |
277 |
|
d = 1.0/(n*n); |
278 |
< |
scalecolor(hp->acoef, d); |
278 |
> |
scalescolor(hp->acoef, d); |
279 |
|
/* make tangent plane axes */ |
280 |
|
if (!getperpendicular(hp->ux, r->ron, 1)) |
281 |
|
error(CONSISTENCY, "bad ray direction in samp_hemi"); |
284 |
|
for (i = hp->ns; i--; ) |
285 |
|
for (j = hp->ns; j--; ) |
286 |
|
hp->sampOK += ambsample(hp, i, j, 0); |
287 |
< |
copycolor(rcol, hp->acol); |
287 |
> |
copyscolor(rcol, hp->acol); |
288 |
|
if (!hp->sampOK) { /* utter failure? */ |
289 |
|
free(hp); |
290 |
|
return(NULL); |
298 |
|
n = ambssamp*wt + 0.5; |
299 |
|
if (n > 8) { /* perform super-sampling? */ |
300 |
|
ambsupersamp(hp, n); |
301 |
< |
copycolor(rcol, hp->acol); |
301 |
> |
copyscolor(rcol, hp->acol); |
302 |
|
} |
303 |
|
return(hp); /* all is well */ |
304 |
|
} |
310 |
|
{ |
311 |
|
if (hp->sa[n1].d <= hp->sa[n2].d) { |
312 |
|
if (hp->sa[n1].d <= hp->sa[n3].d) |
313 |
< |
return(colval(hp->sa[n1].v,CIEY)); |
314 |
< |
return(colval(hp->sa[n3].v,CIEY)); |
313 |
> |
return(hp->sa[n1].v[0]); |
314 |
> |
return(hp->sa[n3].v[0]); |
315 |
|
} |
316 |
|
if (hp->sa[n2].d <= hp->sa[n3].d) |
317 |
< |
return(colval(hp->sa[n2].v,CIEY)); |
318 |
< |
return(colval(hp->sa[n3].v,CIEY)); |
317 |
> |
return(hp->sa[n2].v[0]); |
318 |
> |
return(hp->sa[n3].v[0]); |
319 |
|
} |
320 |
|
|
321 |
|
|
629 |
|
/* use vector for azimuth + 90deg */ |
630 |
|
VSUB(vd, ap->p, hp->rp->rop); |
631 |
|
/* brightness over cosine factor */ |
632 |
< |
gfact = colval(ap->v,CIEY) / DOT(hp->rp->ron, vd); |
632 |
> |
gfact = ap->v[0] / DOT(hp->rp->ron, vd); |
633 |
|
/* sine = proj_radius/vd_length */ |
634 |
|
dgsum[0] -= DOT(uv[1], vd) * gfact; |
635 |
|
dgsum[1] += DOT(uv[0], vd) * gfact; |
685 |
|
|
686 |
|
int |
687 |
|
doambient( /* compute ambient component */ |
688 |
< |
COLOR rcol, /* input/output color */ |
688 |
> |
SCOLOR rcol, /* input/output color */ |
689 |
|
RAY *r, |
690 |
|
double wt, |
691 |
|
FVECT uv[2], /* returned (optional) */ |
719 |
|
free(hp); /* Hessian not requested/possible */ |
720 |
|
return(-1); /* value-only return value */ |
721 |
|
} |
722 |
< |
if ((d = bright(rcol)) > FTINY) { /* normalize Y values */ |
723 |
< |
d = 0.99*(hp->ns*hp->ns)/d; |
722 |
> |
if ((d = scolor_mean(rcol)) > FTINY) { |
723 |
> |
d = 0.99*(hp->ns*hp->ns)/d; /* normalize avg. values */ |
724 |
|
K = 0.01; |
725 |
|
} else { /* or fall back on geometric Hessian */ |
726 |
|
K = 1.0; |
728 |
|
dg = NULL; |
729 |
|
crlp = NULL; |
730 |
|
} |
731 |
< |
ap = hp->sa; /* relative Y channel from here on... */ |
731 |
> |
ap = hp->sa; /* single channel from here on... */ |
732 |
|
for (i = hp->ns*hp->ns; i--; ap++) |
733 |
< |
colval(ap->v,CIEY) = bright(ap->v)*d + K; |
733 |
> |
ap->v[0] = scolor_mean(ap->v)*d + K; |
734 |
|
|
735 |
|
if (uv == NULL) /* make sure we have axis pointers */ |
736 |
|
uv = my_uv; |