96 |
|
|
97 |
|
#define cvt_sdcolor(cv, svp) ccy2rgb(&(svp)->spec, (svp)->cieY, cv) |
98 |
|
|
99 |
+ |
typedef struct { |
100 |
+ |
double vy; /* brightness (for sorting) */ |
101 |
+ |
FVECT tdir; /* through sample direction (normalized) */ |
102 |
+ |
COLOR vcol; /* BTDF color */ |
103 |
+ |
} PEAKSAMP; /* BTDF peak sample */ |
104 |
+ |
|
105 |
+ |
/* Comparison function to put near-peak values in descending order */ |
106 |
+ |
static int |
107 |
+ |
cmp_psamp(const void *p1, const void *p2) |
108 |
+ |
{ |
109 |
+ |
double diff = (*(const PEAKSAMP *)p1).vy - (*(const PEAKSAMP *)p2).vy; |
110 |
+ |
if (diff > 0) return(-1); |
111 |
+ |
if (diff < 0) return(1); |
112 |
+ |
return(0); |
113 |
+ |
} |
114 |
+ |
|
115 |
|
/* Compute "through" component color for MAT_ABSDF */ |
116 |
|
static void |
117 |
|
compute_through(BSDFDAT *ndp) |
132 |
|
{0, -1.6}, |
133 |
|
{1.6, 0}, |
134 |
|
}; |
135 |
< |
const double peak_over = 1.3 + .4*frandom(); /* jitter threshold */ |
135 |
> |
const double peak_over = 1.5; |
136 |
> |
PEAKSAMP psamp[NDIR2CHECK]; |
137 |
|
SDSpectralDF *dfp; |
138 |
|
FVECT pdir; |
139 |
|
double tomega, srchrad; |
140 |
< |
COLOR vpeak, vsum; |
141 |
< |
int i; |
140 |
> |
double tomsum; |
141 |
> |
COLOR vpeak; |
142 |
> |
double vypeak, vysum; |
143 |
> |
int i, ns, ntot; |
144 |
|
SDError ec; |
145 |
|
|
146 |
|
if (ndp->pr->rod > 0) |
152 |
|
return; /* no specular transmission */ |
153 |
|
if (bright(ndp->pr->pcol) <= FTINY) |
154 |
|
return; /* pattern is black, here */ |
155 |
< |
srchrad = sqrt(dfp->minProjSA); /* else search for peak */ |
156 |
< |
setcolor(vpeak, 0, 0, 0); |
138 |
< |
setcolor(vsum, 0, 0, 0); |
139 |
< |
pdir[2] = 0.0; |
155 |
> |
srchrad = sqrt(dfp->minProjSA); /* else evaluate peak */ |
156 |
> |
vysum = 0; |
157 |
|
for (i = 0; i < NDIR2CHECK; i++) { |
141 |
– |
FVECT tdir; |
158 |
|
SDValue sv; |
159 |
< |
COLOR vcol; |
160 |
< |
tdir[0] = -ndp->vray[0] + dir2check[i][0]*srchrad; |
161 |
< |
tdir[1] = -ndp->vray[1] + dir2check[i][1]*srchrad; |
162 |
< |
tdir[2] = -ndp->vray[2]; |
163 |
< |
normalize(tdir); |
148 |
< |
ec = SDevalBSDF(&sv, tdir, ndp->vray, ndp->sd); |
159 |
> |
psamp[i].tdir[0] = -ndp->vray[0] + dir2check[i][0]*srchrad; |
160 |
> |
psamp[i].tdir[1] = -ndp->vray[1] + dir2check[i][1]*srchrad; |
161 |
> |
psamp[i].tdir[2] = -ndp->vray[2]; |
162 |
> |
normalize(psamp[i].tdir); |
163 |
> |
ec = SDevalBSDF(&sv, psamp[i].tdir, ndp->vray, ndp->sd); |
164 |
|
if (ec) |
165 |
|
goto baderror; |
166 |
< |
cvt_sdcolor(vcol, &sv); |
167 |
< |
addcolor(vsum, vcol); |
168 |
< |
if (sv.cieY > bright(vpeak)) { |
169 |
< |
copycolor(vpeak, vcol); |
170 |
< |
VCOPY(pdir, tdir); |
166 |
> |
cvt_sdcolor(psamp[i].vcol, &sv); |
167 |
> |
vysum += psamp[i].vy = sv.cieY; |
168 |
> |
} |
169 |
> |
if (vysum <= FTINY) /* zero neighborhood? */ |
170 |
> |
return; |
171 |
> |
qsort(psamp, NDIR2CHECK, sizeof(PEAKSAMP), cmp_psamp); |
172 |
> |
setcolor(vpeak, 0, 0, 0); |
173 |
> |
vypeak = tomsum = 0; /* combine top unique values */ |
174 |
> |
ns = 0; ntot = NDIR2CHECK; |
175 |
> |
for (i = 0; i < NDIR2CHECK; i++) { |
176 |
> |
if (i) { |
177 |
> |
if (psamp[i].vy == psamp[i-1].vy) { |
178 |
> |
vysum -= psamp[i].vy; |
179 |
> |
--ntot; |
180 |
> |
continue; /* assume duplicate sample */ |
181 |
> |
} |
182 |
> |
if (vypeak > 8.*psamp[i].vy*ns) |
183 |
> |
continue; /* peak cut-off */ |
184 |
|
} |
185 |
+ |
ec = SDsizeBSDF(&tomega, psamp[i].tdir, ndp->vray, |
186 |
+ |
SDqueryMin, ndp->sd); |
187 |
+ |
if (ec) |
188 |
+ |
goto baderror; |
189 |
+ |
if (tomega > 1.5*dfp->minProjSA) { |
190 |
+ |
if (!i) return; /* not really a peak? */ |
191 |
+ |
continue; |
192 |
+ |
} |
193 |
+ |
scalecolor(psamp[i].vcol, tomega); |
194 |
+ |
addcolor(vpeak, psamp[i].vcol); |
195 |
+ |
tomsum += tomega; |
196 |
+ |
vypeak += psamp[i].vy; |
197 |
+ |
++ns; |
198 |
|
} |
199 |
< |
if (pdir[2] == 0.0) |
200 |
< |
return; /* zero neighborhood */ |
201 |
< |
ec = SDsizeBSDF(&tomega, pdir, ndp->vray, SDqueryMin, ndp->sd); |
161 |
< |
if (ec) |
162 |
< |
goto baderror; |
163 |
< |
if (tomega > 1.5*dfp->minProjSA) |
164 |
< |
return; /* not really a peak? */ |
165 |
< |
if ((bright(vpeak) - ndp->sd->tLamb.cieY*(1./PI))*tomega <= .001) |
199 |
> |
if (vypeak*(ntot-ns) < peak_over*(vysum-vypeak)*ns) |
200 |
> |
return; /* peak not peaky enough */ |
201 |
> |
if ((vypeak/ns - ndp->sd->tLamb.cieY*(1./PI))*tomsum <= .001) |
202 |
|
return; /* < 0.1% transmission */ |
203 |
< |
for (i = 3; i--; ) /* remove peak from average */ |
168 |
< |
colval(vsum,i) -= colval(vpeak,i); |
169 |
< |
if (peak_over*bright(vsum) >= (NDIR2CHECK-1)*bright(vpeak)) |
170 |
< |
return; /* not peaky enough */ |
171 |
< |
copycolor(ndp->cthru, vpeak); /* else use it */ |
172 |
< |
scalecolor(ndp->cthru, tomega); |
203 |
> |
copycolor(ndp->cthru, vpeak); /* already scaled by omega */ |
204 |
|
multcolor(ndp->cthru, ndp->pr->pcol); /* modify by pattern */ |
205 |
|
return; |
206 |
|
baderror: |