1 |
|
#ifndef lint |
2 |
|
static const char RCSid[] = "$Id$"; |
3 |
|
#endif |
4 |
+ |
|
5 |
|
/* |
6 |
|
================================================================== |
7 |
|
Bias compensation for photon density estimates |
25 |
|
|
26 |
|
|
27 |
|
|
28 |
< |
void squeuePartition (PhotonSQNode* squeue, unsigned lo, |
28 |
> |
void squeuePartition (PhotonSearchQueueNode* squeue, unsigned lo, |
29 |
|
unsigned mid, unsigned hi) |
30 |
|
/* REVERSE Partition squeue such that all photons in |
31 |
|
squeue-hi+1..squeue-mid are farther than the median at squeue-mid+1, |
35 |
|
since the queue is initially a maxheap, so reverse sorting is expected |
36 |
|
to be faster. */ |
37 |
|
{ |
38 |
< |
unsigned l, h, p; |
39 |
< |
PhotonSQNode *lp, *hp, *pp; |
40 |
< |
float pivot, dist; |
40 |
< |
Photon* photon; |
38 |
> |
unsigned l, h, p; |
39 |
> |
PhotonSearchQueueNode *lp, *hp, *pp, tmp; |
40 |
> |
float pivot; |
41 |
|
|
42 |
|
while (hi > lo) { |
43 |
|
/* Grab pivot node in middle as an educated guess, since our |
48 |
|
lp = squeue - lo + 1; |
49 |
|
hp = squeue - hi + 1; |
50 |
|
pp = squeue - p + 1; |
51 |
< |
pivot = pp -> dist; |
51 |
> |
pivot = pp -> dist2; |
52 |
|
|
53 |
|
/* l & h converge, swapping elements out of order with respect to |
54 |
|
pivot node. */ |
55 |
|
while (l < h) { |
56 |
< |
while (lp -> dist <= pivot && l <= h && l < hi) |
56 |
> |
while (lp -> dist2 <= pivot && l <= h && l < hi) |
57 |
|
++l, --lp; |
58 |
< |
while (hp -> dist >= pivot && h >= l && h > lo) |
58 |
> |
|
59 |
> |
while (hp -> dist2 >= pivot && h >= l && h > lo) |
60 |
|
--h, ++hp; |
61 |
|
|
62 |
|
if (l < h) { |
63 |
|
/* Swap */ |
64 |
< |
photon = lp -> photon; |
65 |
< |
dist = lp -> dist; |
66 |
< |
lp -> photon = hp -> photon; |
67 |
< |
lp -> dist = hp -> dist; |
68 |
< |
hp -> photon = photon; |
69 |
< |
hp -> dist = dist; |
64 |
> |
tmp.idx = lp -> idx; |
65 |
> |
tmp.dist2 = lp -> dist2; |
66 |
> |
lp -> idx = hp -> idx; |
67 |
> |
lp -> dist2 = hp -> dist2; |
68 |
> |
hp -> idx = tmp.idx; |
69 |
> |
hp -> dist2 = tmp.dist2; |
70 |
|
} |
71 |
|
} |
72 |
|
|
73 |
|
/* Swap convergence and pivot node */ |
74 |
|
if (p > h) { |
75 |
|
/* Need this otherwise shit happens! |
76 |
< |
Since lp -> dist > hp -> dist, we swap either l or p depending |
76 |
> |
Since lp -> dist2 > hp -> dist2, we swap either l or p depending |
77 |
|
on whether we're above or below p */ |
78 |
|
h = l; |
79 |
|
hp = lp; |
80 |
|
} |
81 |
|
|
82 |
< |
photon = hp -> photon; |
83 |
< |
dist = hp -> dist; |
84 |
< |
hp -> photon = pp -> photon; |
85 |
< |
hp -> dist = pivot; |
86 |
< |
pp -> photon = photon; |
87 |
< |
pp -> dist = dist; |
82 |
> |
tmp.idx = hp -> idx; |
83 |
> |
tmp.dist2 = hp -> dist2; |
84 |
> |
hp -> idx = pp -> idx; |
85 |
> |
hp -> dist2 = pivot; |
86 |
> |
pp -> idx = tmp.idx; |
87 |
> |
pp -> dist2 = tmp.dist2; |
88 |
> |
|
89 |
|
if (h >= mid) |
90 |
|
hi = h - 1; |
91 |
+ |
|
92 |
|
if (h <= mid) |
93 |
|
lo = h + 1; |
94 |
|
} |
101 |
|
void biasComp (PhotonMap* pmap, COLOR irrad) |
102 |
|
/* Photon density estimate with bias compensation -- czech dis shit out! */ |
103 |
|
{ |
104 |
< |
unsigned i, numLo, numHi, numMid; |
105 |
< |
PhotonSQNode *sq; |
106 |
< |
PhotonBCNode *hist; |
107 |
< |
float r, totalWeight = 0; |
108 |
< |
PhotonSQNode *squeueEnd; |
109 |
< |
PhotonBCNode *histEnd; |
107 |
< |
COLOR fluxLo, fluxMid, irradVar, irradAvg, p, d; |
104 |
> |
unsigned i, numLo, numHi, numMid; |
105 |
> |
float r, totalWeight = 0; |
106 |
> |
COLOR fluxLo, fluxMid, irradVar, irradAvg, p, d; |
107 |
> |
Photon *photon; |
108 |
> |
PhotonSearchQueueNode *sqn, *sqEnd; |
109 |
> |
PhotonBiasCompNode *hist, *histEnd; |
110 |
|
|
111 |
|
if (!pmap -> biasCompHist) { |
112 |
|
/* Allocate bias compensation history */ |
113 |
< |
numHi = pmap -> maxGather - pmap -> minGather; |
114 |
< |
for (i = pmap -> minGather + 1; numHi > 1; numHi >>= 1, ++i); |
115 |
< |
pmap -> biasCompHist = (PhotonBCNode*)malloc(i * sizeof(PhotonBCNode)); |
113 |
> |
numHi = pmap -> maxGather - pmap -> minGather; |
114 |
> |
for (i = pmap -> minGather + 1; numHi > 1; numHi >>= 1, ++i); |
115 |
> |
pmap -> biasCompHist = calloc(i, sizeof(PhotonBiasCompNode)); |
116 |
> |
|
117 |
|
if (!pmap -> biasCompHist) |
118 |
|
error(USER, "can't allocate bias compensation history"); |
119 |
|
} |
120 |
|
|
121 |
< |
numLo = min(pmap -> minGather, pmap -> squeueEnd - 1); |
122 |
< |
numHi = min(pmap -> maxGather, pmap -> squeueEnd - 1); |
123 |
< |
sq = squeueEnd = pmap -> squeue + pmap -> squeueEnd - 1; |
121 |
> |
numLo = min(pmap -> minGather, pmap -> squeue.tail - 1); |
122 |
> |
numHi = min(pmap -> maxGather, pmap -> squeue.tail - 1); |
123 |
> |
sqn = sqEnd = pmap -> squeue.node + pmap -> squeue.tail - 1; |
124 |
|
histEnd = pmap -> biasCompHist; |
125 |
|
setcolor(fluxLo, 0, 0, 0); |
126 |
|
|
127 |
|
/* Partition to get numLo closest photons starting from END of queue */ |
128 |
< |
squeuePartition(squeueEnd, 1, numLo + 1, numHi); |
128 |
> |
squeuePartition(sqEnd, 1, numLo + 1, numHi); |
129 |
|
|
130 |
|
/* Get irradiance estimates (ignoring 1 / PI) using 1..numLo photons |
131 |
|
and chuck in history. Queue is traversed BACKWARDS. */ |
132 |
< |
for (i = 1; i <= numLo; i++, sq--) { |
133 |
< |
/* Make sure furthest two photons are consecutive wrt distance */ |
134 |
< |
squeuePartition(squeueEnd, i, i + 1, numLo + 1); |
135 |
< |
getPhotonFlux(sq -> photon, irrad); |
132 |
> |
for (i = 1; i <= numLo; i++, sqn--) { |
133 |
> |
/* Make sure furthest two photons are consecutive w.r.t. distance */ |
134 |
> |
squeuePartition(sqEnd, i, i + 1, numLo + 1); |
135 |
> |
photon = getNearestPhoton(&pmap -> squeue, sqn -> idx); |
136 |
> |
getPhotonFlux(photon, irrad); |
137 |
|
addcolor(fluxLo, irrad); |
138 |
|
/* Average radius between furthest two photons to improve accuracy */ |
139 |
< |
r = 0.25 * (sq -> dist + (sq - 1) -> dist + |
140 |
< |
2 * sqrt(sq -> dist * (sq - 1) -> dist)); |
139 |
> |
r = 0.25 * (sqn -> dist2 + (sqn - 1) -> dist2 + |
140 |
> |
2 * sqrt(sqn -> dist2 * (sqn - 1) -> dist2)); |
141 |
|
/* Add irradiance and weight to history. Weights should increase |
142 |
|
monotonically based on number of photons used for the estimate. */ |
143 |
|
histEnd -> irrad [0] = fluxLo [0] / r; |
168 |
|
numMid = (numLo + numHi) >> 1; |
169 |
|
/* Split interval to get numMid closest photons starting from the |
170 |
|
END of the queue */ |
171 |
< |
squeuePartition(squeueEnd, numLo, numMid, numHi); |
171 |
> |
squeuePartition(sqEnd, numLo, numMid, numHi); |
172 |
|
/* Make sure furthest two photons are consecutive wrt distance */ |
173 |
< |
squeuePartition(squeueEnd, numMid, numMid + 1, numHi); |
173 |
> |
squeuePartition(sqEnd, numMid, numMid + 1, numHi); |
174 |
|
copycolor(fluxMid, fluxLo); |
175 |
< |
sq = squeueEnd - numLo; |
175 |
> |
sqn = sqEnd - numLo; |
176 |
|
|
177 |
|
/* Get irradiance for numMid photons (ignoring 1 / PI) */ |
178 |
< |
for (i = numLo; i < numMid; i++, sq--) { |
179 |
< |
getPhotonFlux(sq -> photon, irrad); |
178 |
> |
for (i = numLo; i < numMid; i++, sqn--) { |
179 |
> |
photon = getNearestPhoton(&pmap -> squeue, sqn -> idx); |
180 |
> |
getPhotonFlux(photon, irrad); |
181 |
|
addcolor(fluxMid, irrad); |
182 |
|
} |
183 |
|
|
184 |
|
/* Average radius between furthest two photons to improve accuracy */ |
185 |
< |
r = 0.25 * (sq -> dist + (sq + 1) -> dist + |
186 |
< |
2 * sqrt(sq -> dist * (sq + 1) -> dist)); |
185 |
> |
r = 0.25 * (sqn -> dist2 + (sqn + 1) -> dist2 + |
186 |
> |
2 * sqrt(sqn -> dist2 * (sqn + 1) -> dist2)); |
187 |
|
|
188 |
|
/* Get deviation from current average, and probability that it's due |
189 |
|
to noise from gaussian distribution based on current variance. Since |
214 |
|
irradVar [i] = irradVar [i] / totalWeight - r * r; |
215 |
|
} |
216 |
|
|
217 |
< |
/* Need more photons -- recurse on [numMid, numHi] */ |
217 |
> |
/* Need more photons --> recurse on [numMid, numHi] */ |
218 |
|
numLo = numMid; |
219 |
|
copycolor(fluxLo, fluxMid); |
220 |
|
} |
221 |
|
else |
222 |
< |
/* Deviation is probably bias -- need fewer photons, |
222 |
> |
/* Deviation is probably bias --> need fewer photons, |
223 |
|
so recurse on [numLo, numMid] */ |
224 |
|
numHi = numMid; |
225 |
|
} |
226 |
|
|
227 |
|
--histEnd; |
228 |
+ |
|
229 |
|
for (i = 0; i <= 2; i++) { |
230 |
|
/* Estimated relative error */ |
231 |
|
d [i] = histEnd -> irrad [i] / irradAvg [i] - 1; |
241 |
|
|
242 |
|
/* Update statistix */ |
243 |
|
r = colorAvg(d); |
244 |
+ |
pmap -> rmsError += r * r; |
245 |
+ |
|
246 |
|
if (r < pmap -> minError) |
247 |
|
pmap -> minError = r; |
248 |
+ |
|
249 |
|
if (r > pmap -> maxError) |
250 |
|
pmap -> maxError = r; |
242 |
– |
pmap -> rmsError += r * r; |
251 |
|
|
252 |
|
if (numHi < pmap -> minGathered) |
253 |
|
pmap -> minGathered = numHi; |
254 |
+ |
|
255 |
|
if (numHi > pmap -> maxGathered) |
256 |
|
pmap -> maxGathered = numHi; |
257 |
|
|
261 |
|
|
262 |
|
|
263 |
|
|
264 |
+ |
/* Volume bias compensation disabled (probably redundant) */ |
265 |
+ |
#if 0 |
266 |
|
void volumeBiasComp (PhotonMap* pmap, const RAY* ray, COLOR irrad) |
267 |
|
/* Photon volume density estimate with bias compensation -- czech dis |
268 |
|
shit out! */ |
435 |
|
pmap -> totalGathered += numMid; |
436 |
|
++pmap -> numDensity; |
437 |
|
} |
438 |
< |
|
438 |
> |
#endif |