ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapbias.c
Revision: 2.5
Committed: Tue May 17 17:39:47 2016 UTC (7 years, 11 months ago) by rschregle
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R2, rad5R3, rad5R1, HEAD
Changes since 2.4: +65 -53 lines
Log Message:
Initial import of ooC photon map

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pmapbias.c,v 4.7 2015/11/16 13:32:03 taschreg Exp taschreg $";
3 #endif
4
5 /*
6 ==================================================================
7 Bias compensation for photon density estimates
8
9 For background see:
10 R. Schregle, "Bias Compensation for Photon Maps",
11 Computer Graphics Forum, v22:n4, pp. 729-742, Dec. 2003.
12
13 Roland Schregle ([email protected])
14 (c) Fraunhofer Institute for Solar Energy Systems
15 ==================================================================
16
17 $Id: pmapbias.c,v 4.7 2015/11/16 13:32:03 taschreg Exp taschreg $
18 */
19
20
21
22 #include "pmapbias.h"
23 #include "pmap.h"
24 #include "pmaprand.h"
25
26
27
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,
32 and those in squeue-mid+2..squeue-lo+1 are closer than the median.
33 This means that squeue points to the END of the queue, and the (1-based)
34 indices are offsets relative to it. This convoluted scheme is adopted
35 since the queue is initially a maxheap, so reverse sorting is expected
36 to be faster. */
37 {
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
44 queue is sorta sorted. */
45 l = lo;
46 h = hi;
47 p = mid;
48 lp = squeue - lo + 1;
49 hp = squeue - hi + 1;
50 pp = squeue - p + 1;
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 -> dist2 <= pivot && l <= h && l < hi)
57 ++l, --lp;
58
59 while (hp -> dist2 >= pivot && h >= l && h > lo)
60 --h, ++hp;
61
62 if (l < h) {
63 /* Swap */
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 -> 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 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 }
95
96 /* Once lo & hi have converged, we have found the median! */
97 }
98
99
100
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 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 = 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 -> 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(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++, 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 * (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;
144 histEnd -> irrad [1] = fluxLo [1] / r;
145 histEnd -> irrad [2] = fluxLo [2] / r;
146 totalWeight += histEnd++ -> weight = BIASCOMP_WGT((float)i);
147 }
148
149 /* Compute expected value (average) and variance of irradiance based on
150 history for numLo photons. */
151 setcolor(irradAvg, 0, 0, 0);
152 setcolor(irradVar, 0, 0, 0);
153
154 for (hist = pmap -> biasCompHist; hist < histEnd; ++hist)
155 for (i = 0; i <= 2; ++i) {
156 irradAvg [i] += r = hist -> weight * hist -> irrad [i];
157 irradVar [i] += r * hist -> irrad [i];
158 }
159
160 for (i = 0; i <= 2; ++i) {
161 r = irradAvg [i] /= totalWeight;
162 irradVar [i] = irradVar [i] / totalWeight - r * r;
163 }
164
165 /* Do binary search within interval [numLo, numHi]. numLo is towards
166 the END of the queue. */
167 while (numHi - numLo > 1) {
168 numMid = (numLo + numHi) >> 1;
169 /* Split interval to get numMid closest photons starting from the
170 END of the queue */
171 squeuePartition(sqEnd, numLo, numMid, numHi);
172 /* Make sure furthest two photons are consecutive wrt distance */
173 squeuePartition(sqEnd, numMid, numMid + 1, numHi);
174 copycolor(fluxMid, fluxLo);
175 sqn = sqEnd - numLo;
176
177 /* Get irradiance for numMid photons (ignoring 1 / PI) */
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 * (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
190 we are doing this for each colour channel we can also detect
191 chromatic bias. */
192 for (i = 0; i <= 2; ++i) {
193 d [i] = irradAvg [i] - (irrad [i] = fluxMid [i] / r);
194 p [i] = exp(-0.5 * d [i] * d [i] / irradVar [i]);
195 }
196
197 if (pmapRandom(pmap -> randState) < colorAvg(p)) {
198 /* Deviation is probably noise, so add mid irradiance to history */
199 copycolor(histEnd -> irrad, irrad);
200 totalWeight += histEnd++ -> weight = BIASCOMP_WGT((float)numMid);
201 setcolor(irradAvg, 0, 0, 0);
202 setcolor(irradVar, 0, 0, 0);
203
204 /* Update average and variance */
205 for (hist = pmap -> biasCompHist; hist < histEnd; ++hist)
206 for (i = 0; i <= 2; i++) {
207 r = hist -> irrad [i];
208 irradAvg [i] += hist -> weight * r;
209 irradVar [i] += hist -> weight * r * r;
210 }
211
212 for (i = 0; i <= 2; i++) {
213 r = irradAvg [i] /= totalWeight;
214 irradVar [i] = irradVar [i] / totalWeight - r * r;
215 }
216
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,
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;
232
233 #ifdef BIASCOMP_BWIDTH
234 /* Return bandwidth instead of irradiance */
235 irrad [i] = numHi / PI;
236 #else
237 /* 1 / PI required as ambient normalisation factor */
238 irrad [i] = histEnd -> irrad [i] / (PI * PI);
239 #endif
240 }
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;
251
252 if (numHi < pmap -> minGathered)
253 pmap -> minGathered = numHi;
254
255 if (numHi > pmap -> maxGathered)
256 pmap -> maxGathered = numHi;
257
258 pmap -> totalGathered += numHi;
259 ++pmap -> numDensity;
260 }
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! */
269 {
270 unsigned i, numLo, numHi, numMid = 0;
271 PhotonSQNode *sq;
272 PhotonBCNode *hist;
273 const float gecc2 = ray -> gecc * ray -> gecc;
274 float r, totalWeight = 0;
275 PhotonSQNode *squeueEnd;
276 PhotonBCNode *histEnd;
277 COLOR fluxLo, fluxMid, irradVar, irradAvg, p, d;
278
279 if (!pmap -> biasCompHist) {
280 /* Allocate bias compensation history */
281 numHi = pmap -> maxGather - pmap -> minGather;
282 for (i = pmap -> minGather + 1; numHi > 1; numHi >>= 1, ++i);
283 pmap -> biasCompHist = (PhotonBCNode*)malloc(i * sizeof(PhotonBCNode));
284 if (!pmap -> biasCompHist)
285 error(USER, "can't allocate bias compensation history");
286 }
287
288 numLo = min(pmap -> minGather, pmap -> squeueEnd - 1);
289 numHi = min(pmap -> maxGather, pmap -> squeueEnd - 1);
290 sq = squeueEnd = pmap -> squeue + pmap -> squeueEnd - 1;
291 histEnd = pmap -> biasCompHist;
292 setcolor(fluxLo, 0, 0, 0);
293 /* Partition to get numLo closest photons starting from END of queue */
294 squeuePartition(squeueEnd, 1, numLo, numHi);
295
296 /* Get irradiance estimates (ignoring constants) using 1..numLo photons
297 and chuck in history. Queue is traversed BACKWARDS. */
298 for (i = 1; i <= numLo; i++, sq--) {
299 /* Make sure furthest two photons are consecutive wrt distance */
300 squeuePartition(squeueEnd, i, i + 1, numHi);
301
302 /* Compute phase function for inscattering from photon */
303 if (gecc2 <= FTINY)
304 r = 1;
305 else {
306 r = DOT(ray -> rdir, sq -> photon -> norm) / 127;
307 r = 1 + gecc2 - 2 * ray -> gecc * r;
308 r = (1 - gecc2) / (r * sqrt(r));
309 }
310
311 getPhotonFlux(sq -> photon, irrad);
312 scalecolor(irrad, r);
313 addcolor(fluxLo, irrad);
314 /* Average radius between furthest two photons to improve accuracy */
315 r = 0.25 * (sq -> dist + (sq - 1) -> dist +
316 2 * sqrt(sq -> dist * (sq - 1) -> dist));
317 r *= sqrt(r);
318 /* Add irradiance and weight to history. Weights should increase
319 monotonically based on number of photons used for the estimate. */
320 histEnd -> irrad [0] = fluxLo [0] / r;
321 histEnd -> irrad [1] = fluxLo [1] / r;
322 histEnd -> irrad [2] = fluxLo [2] / r;
323 totalWeight += histEnd++ -> weight = BIASCOMP_WGT((float)i);
324 }
325
326 /* Compute expected value (average) and variance of irradiance based on
327 history for numLo photons. */
328 setcolor(irradAvg, 0, 0, 0);
329 setcolor(irradVar, 0, 0, 0);
330
331 for (hist = pmap -> biasCompHist; hist < histEnd; ++hist)
332 for (i = 0; i <= 2; ++i) {
333 irradAvg [i] += r = hist -> weight * hist -> irrad [i];
334 irradVar [i] += r * hist -> irrad [i];
335 }
336
337 for (i = 0; i <= 2; ++i) {
338 r = irradAvg [i] /= totalWeight;
339 irradVar [i] = irradVar [i] / totalWeight - r * r;
340 }
341
342 /* Do binary search within interval [numLo, numHi]. numLo is towards
343 the END of the queue. */
344 while (numHi - numLo > 1) {
345 numMid = (numLo + numHi) >> 1;
346 /* Split interval to get numMid closest photons starting from the
347 END of the queue */
348 squeuePartition(squeueEnd, numLo, numMid, numHi);
349 /* Make sure furthest two photons are consecutive wrt distance */
350 squeuePartition(squeueEnd, numMid, numMid + 1, numHi);
351 copycolor(fluxMid, fluxLo);
352 sq = squeueEnd - numLo;
353
354 /* Get irradiance for numMid photons (ignoring constants) */
355 for (i = numLo; i < numMid; i++, sq--) {
356 /* Compute phase function for inscattering from photon */
357 if (gecc2 <= FTINY)
358 r = 1;
359 else {
360 r = DOT(ray -> rdir, sq -> photon -> norm) / 127;
361 r = 1 + gecc2 - 2 * ray -> gecc * r;
362 r = (1 - gecc2) / (r * sqrt(r));
363 }
364
365 getPhotonFlux(sq -> photon, irrad);
366 scalecolor(irrad, r);
367 addcolor(fluxMid, irrad);
368 }
369
370 /* Average radius between furthest two photons to improve accuracy */
371 r = 0.25 * (sq -> dist + (sq + 1) -> dist +
372 2 * sqrt(sq -> dist * (sq + 1) -> dist));
373 r *= sqrt(r);
374
375 /* Get deviation from current average, and probability that it's due
376 to noise from gaussian distribution based on current variance. Since
377 we are doing this for each colour channel we can also detect
378 chromatic bias. */
379 for (i = 0; i <= 2; ++i) {
380 d [i] = irradAvg [i] - (irrad [i] = fluxMid [i] / r);
381 p [i] = exp(-0.5 * d [i] * d [i] / irradVar [i]);
382 }
383
384 if (pmapRandom(pmap -> randState) < colorAvg(p)) {
385 /* Deviation is probably noise, so add mid irradiance to history */
386 copycolor(histEnd -> irrad, irrad);
387 totalWeight += histEnd++ -> weight = BIASCOMP_WGT((float)numMid);
388 setcolor(irradAvg, 0, 0, 0);
389 setcolor(irradVar, 0, 0, 0);
390
391 /* Update average and variance */
392 for (hist = pmap -> biasCompHist; hist < histEnd; ++hist)
393 for (i = 0; i <= 2; i++) {
394 r = hist -> irrad [i];
395 irradAvg [i] += hist -> weight * r;
396 irradVar [i] += hist -> weight * r * r;
397 }
398 for (i = 0; i <= 2; i++) {
399 r = irradAvg [i] /= totalWeight;
400 irradVar [i] = irradVar [i] / totalWeight - r * r;
401 }
402
403 /* Need more photons -- recurse on [numMid, numHi] */
404 numLo = numMid;
405 copycolor(fluxLo, fluxMid);
406 }
407 else
408 /* Deviation is probably bias -- need fewer photons,
409 so recurse on [numLo, numMid] */
410 numHi = numMid;
411 }
412
413 --histEnd;
414 for (i = 0; i <= 2; i++) {
415 /* Estimated relative error */
416 d [i] = histEnd -> irrad [i] / irradAvg [i] - 1;
417 /* Divide by 4 / 3 * PI for search volume (r^3 already accounted
418 for) and phase function normalization factor 1 / (4 * PI) */
419 irrad [i] = histEnd -> irrad [i] * 3 / (16 * PI * PI);
420 }
421
422 /* Update statistix */
423 r = colorAvg(d);
424 if (r < pmap -> minError)
425 pmap -> minError = r;
426 if (r > pmap -> maxError)
427 pmap -> maxError = r;
428 pmap -> rmsError += r * r;
429
430 if (numMid < pmap -> minGathered)
431 pmap -> minGathered = numMid;
432 if (numMid > pmap -> maxGathered)
433 pmap -> maxGathered = numMid;
434
435 pmap -> totalGathered += numMid;
436 ++pmap -> numDensity;
437 }
438 #endif