ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapbias.c
Revision: 2.4
Committed: Tue Sep 1 16:27:52 2015 UTC (8 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R0
Changes since 2.3: +1 -2 lines
Log Message:
Removed redundant $Id: in file

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pmapbias.c,v 2.3 2015/08/18 18:45:55 greg Exp $";
3 #endif
4 /*
5 ==================================================================
6 Bias compensation for photon density estimates
7
8 For background see:
9 R. Schregle, "Bias Compensation for Photon Maps",
10 Computer Graphics Forum, v22:n4, pp. 729-742, Dec. 2003.
11
12 Roland Schregle ([email protected])
13 (c) Fraunhofer Institute for Solar Energy Systems
14 ==================================================================
15
16 */
17
18
19
20 #include "pmapbias.h"
21 #include "pmap.h"
22 #include "pmaprand.h"
23
24
25
26 void squeuePartition (PhotonSQNode* squeue, unsigned lo,
27 unsigned mid, unsigned hi)
28 /* REVERSE Partition squeue such that all photons in
29 squeue-hi+1..squeue-mid are farther than the median at squeue-mid+1,
30 and those in squeue-mid+2..squeue-lo+1 are closer than the median.
31 This means that squeue points to the END of the queue, and the (1-based)
32 indices are offsets relative to it. This convoluted scheme is adopted
33 since the queue is initially a maxheap, so reverse sorting is expected
34 to be faster. */
35 {
36 unsigned l, h, p;
37 PhotonSQNode *lp, *hp, *pp;
38 float pivot, dist;
39 Photon* photon;
40
41 while (hi > lo) {
42 /* Grab pivot node in middle as an educated guess, since our
43 queue is sorta sorted. */
44 l = lo;
45 h = hi;
46 p = mid;
47 lp = squeue - lo + 1;
48 hp = squeue - hi + 1;
49 pp = squeue - p + 1;
50 pivot = pp -> dist;
51
52 /* l & h converge, swapping elements out of order with respect to
53 pivot node. */
54 while (l < h) {
55 while (lp -> dist <= pivot && l <= h && l < hi)
56 ++l, --lp;
57 while (hp -> dist >= pivot && h >= l && h > lo)
58 --h, ++hp;
59
60 if (l < h) {
61 /* Swap */
62 photon = lp -> photon;
63 dist = lp -> dist;
64 lp -> photon = hp -> photon;
65 lp -> dist = hp -> dist;
66 hp -> photon = photon;
67 hp -> dist = dist;
68 }
69 }
70
71 /* Swap convergence and pivot node */
72 if (p > h) {
73 /* Need this otherwise shit happens!
74 Since lp -> dist > hp -> dist, we swap either l or p depending
75 on whether we're above or below p */
76 h = l;
77 hp = lp;
78 }
79
80 photon = hp -> photon;
81 dist = hp -> dist;
82 hp -> photon = pp -> photon;
83 hp -> dist = pivot;
84 pp -> photon = photon;
85 pp -> dist = dist;
86 if (h >= mid)
87 hi = h - 1;
88 if (h <= mid)
89 lo = h + 1;
90 }
91
92 /* Once lo & hi have converged, we have found the median! */
93 }
94
95
96
97 void biasComp (PhotonMap* pmap, COLOR irrad)
98 /* Photon density estimate with bias compensation -- czech dis shit out! */
99 {
100 unsigned i, numLo, numHi, numMid;
101 PhotonSQNode *sq;
102 PhotonBCNode *hist;
103 float r, totalWeight = 0;
104 PhotonSQNode *squeueEnd;
105 PhotonBCNode *histEnd;
106 COLOR fluxLo, fluxMid, irradVar, irradAvg, p, d;
107
108 if (!pmap -> biasCompHist) {
109 /* Allocate bias compensation history */
110 numHi = pmap -> maxGather - pmap -> minGather;
111 for (i = pmap -> minGather + 1; numHi > 1; numHi >>= 1, ++i);
112 pmap -> biasCompHist = (PhotonBCNode*)malloc(i * sizeof(PhotonBCNode));
113 if (!pmap -> biasCompHist)
114 error(USER, "can't allocate bias compensation history");
115 }
116
117 numLo = min(pmap -> minGather, pmap -> squeueEnd - 1);
118 numHi = min(pmap -> maxGather, pmap -> squeueEnd - 1);
119 sq = squeueEnd = pmap -> squeue + pmap -> squeueEnd - 1;
120 histEnd = pmap -> biasCompHist;
121 setcolor(fluxLo, 0, 0, 0);
122
123 /* Partition to get numLo closest photons starting from END of queue */
124 squeuePartition(squeueEnd, 1, numLo + 1, numHi);
125
126 /* Get irradiance estimates (ignoring 1 / PI) using 1..numLo photons
127 and chuck in history. Queue is traversed BACKWARDS. */
128 for (i = 1; i <= numLo; i++, sq--) {
129 /* Make sure furthest two photons are consecutive wrt distance */
130 squeuePartition(squeueEnd, i, i + 1, numLo + 1);
131 getPhotonFlux(sq -> photon, irrad);
132 addcolor(fluxLo, irrad);
133 /* Average radius between furthest two photons to improve accuracy */
134 r = 0.25 * (sq -> dist + (sq - 1) -> dist +
135 2 * sqrt(sq -> dist * (sq - 1) -> dist));
136 /* Add irradiance and weight to history. Weights should increase
137 monotonically based on number of photons used for the estimate. */
138 histEnd -> irrad [0] = fluxLo [0] / r;
139 histEnd -> irrad [1] = fluxLo [1] / r;
140 histEnd -> irrad [2] = fluxLo [2] / r;
141 totalWeight += histEnd++ -> weight = BIASCOMP_WGT((float)i);
142 }
143
144 /* Compute expected value (average) and variance of irradiance based on
145 history for numLo photons. */
146 setcolor(irradAvg, 0, 0, 0);
147 setcolor(irradVar, 0, 0, 0);
148
149 for (hist = pmap -> biasCompHist; hist < histEnd; ++hist)
150 for (i = 0; i <= 2; ++i) {
151 irradAvg [i] += r = hist -> weight * hist -> irrad [i];
152 irradVar [i] += r * hist -> irrad [i];
153 }
154
155 for (i = 0; i <= 2; ++i) {
156 r = irradAvg [i] /= totalWeight;
157 irradVar [i] = irradVar [i] / totalWeight - r * r;
158 }
159
160 /* Do binary search within interval [numLo, numHi]. numLo is towards
161 the END of the queue. */
162 while (numHi - numLo > 1) {
163 numMid = (numLo + numHi) >> 1;
164 /* Split interval to get numMid closest photons starting from the
165 END of the queue */
166 squeuePartition(squeueEnd, numLo, numMid, numHi);
167 /* Make sure furthest two photons are consecutive wrt distance */
168 squeuePartition(squeueEnd, numMid, numMid + 1, numHi);
169 copycolor(fluxMid, fluxLo);
170 sq = squeueEnd - numLo;
171
172 /* Get irradiance for numMid photons (ignoring 1 / PI) */
173 for (i = numLo; i < numMid; i++, sq--) {
174 getPhotonFlux(sq -> photon, irrad);
175 addcolor(fluxMid, irrad);
176 }
177
178 /* Average radius between furthest two photons to improve accuracy */
179 r = 0.25 * (sq -> dist + (sq + 1) -> dist +
180 2 * sqrt(sq -> dist * (sq + 1) -> dist));
181
182 /* Get deviation from current average, and probability that it's due
183 to noise from gaussian distribution based on current variance. Since
184 we are doing this for each colour channel we can also detect
185 chromatic bias. */
186 for (i = 0; i <= 2; ++i) {
187 d [i] = irradAvg [i] - (irrad [i] = fluxMid [i] / r);
188 p [i] = exp(-0.5 * d [i] * d [i] / irradVar [i]);
189 }
190
191 if (pmapRandom(pmap -> randState) < colorAvg(p)) {
192 /* Deviation is probably noise, so add mid irradiance to history */
193 copycolor(histEnd -> irrad, irrad);
194 totalWeight += histEnd++ -> weight = BIASCOMP_WGT((float)numMid);
195 setcolor(irradAvg, 0, 0, 0);
196 setcolor(irradVar, 0, 0, 0);
197
198 /* Update average and variance */
199 for (hist = pmap -> biasCompHist; hist < histEnd; ++hist)
200 for (i = 0; i <= 2; i++) {
201 r = hist -> irrad [i];
202 irradAvg [i] += hist -> weight * r;
203 irradVar [i] += hist -> weight * r * r;
204 }
205
206 for (i = 0; i <= 2; i++) {
207 r = irradAvg [i] /= totalWeight;
208 irradVar [i] = irradVar [i] / totalWeight - r * r;
209 }
210
211 /* Need more photons -- recurse on [numMid, numHi] */
212 numLo = numMid;
213 copycolor(fluxLo, fluxMid);
214 }
215 else
216 /* Deviation is probably bias -- need fewer photons,
217 so recurse on [numLo, numMid] */
218 numHi = numMid;
219 }
220
221 --histEnd;
222 for (i = 0; i <= 2; i++) {
223 /* Estimated relative error */
224 d [i] = histEnd -> irrad [i] / irradAvg [i] - 1;
225
226 #ifdef BIASCOMP_BWIDTH
227 /* Return bandwidth instead of irradiance */
228 irrad [i] = numHi / PI;
229 #else
230 /* 1 / PI required as ambient normalisation factor */
231 irrad [i] = histEnd -> irrad [i] / (PI * PI);
232 #endif
233 }
234
235 /* Update statistix */
236 r = colorAvg(d);
237 if (r < pmap -> minError)
238 pmap -> minError = r;
239 if (r > pmap -> maxError)
240 pmap -> maxError = r;
241 pmap -> rmsError += r * r;
242
243 if (numHi < pmap -> minGathered)
244 pmap -> minGathered = numHi;
245 if (numHi > pmap -> maxGathered)
246 pmap -> maxGathered = numHi;
247
248 pmap -> totalGathered += numHi;
249 ++pmap -> numDensity;
250 }
251
252
253
254 void volumeBiasComp (PhotonMap* pmap, const RAY* ray, COLOR irrad)
255 /* Photon volume density estimate with bias compensation -- czech dis
256 shit out! */
257 {
258 unsigned i, numLo, numHi, numMid = 0;
259 PhotonSQNode *sq;
260 PhotonBCNode *hist;
261 const float gecc2 = ray -> gecc * ray -> gecc;
262 float r, totalWeight = 0;
263 PhotonSQNode *squeueEnd;
264 PhotonBCNode *histEnd;
265 COLOR fluxLo, fluxMid, irradVar, irradAvg, p, d;
266
267 if (!pmap -> biasCompHist) {
268 /* Allocate bias compensation history */
269 numHi = pmap -> maxGather - pmap -> minGather;
270 for (i = pmap -> minGather + 1; numHi > 1; numHi >>= 1, ++i);
271 pmap -> biasCompHist = (PhotonBCNode*)malloc(i * sizeof(PhotonBCNode));
272 if (!pmap -> biasCompHist)
273 error(USER, "can't allocate bias compensation history");
274 }
275
276 numLo = min(pmap -> minGather, pmap -> squeueEnd - 1);
277 numHi = min(pmap -> maxGather, pmap -> squeueEnd - 1);
278 sq = squeueEnd = pmap -> squeue + pmap -> squeueEnd - 1;
279 histEnd = pmap -> biasCompHist;
280 setcolor(fluxLo, 0, 0, 0);
281 /* Partition to get numLo closest photons starting from END of queue */
282 squeuePartition(squeueEnd, 1, numLo, numHi);
283
284 /* Get irradiance estimates (ignoring constants) using 1..numLo photons
285 and chuck in history. Queue is traversed BACKWARDS. */
286 for (i = 1; i <= numLo; i++, sq--) {
287 /* Make sure furthest two photons are consecutive wrt distance */
288 squeuePartition(squeueEnd, i, i + 1, numHi);
289
290 /* Compute phase function for inscattering from photon */
291 if (gecc2 <= FTINY)
292 r = 1;
293 else {
294 r = DOT(ray -> rdir, sq -> photon -> norm) / 127;
295 r = 1 + gecc2 - 2 * ray -> gecc * r;
296 r = (1 - gecc2) / (r * sqrt(r));
297 }
298
299 getPhotonFlux(sq -> photon, irrad);
300 scalecolor(irrad, r);
301 addcolor(fluxLo, irrad);
302 /* Average radius between furthest two photons to improve accuracy */
303 r = 0.25 * (sq -> dist + (sq - 1) -> dist +
304 2 * sqrt(sq -> dist * (sq - 1) -> dist));
305 r *= sqrt(r);
306 /* Add irradiance and weight to history. Weights should increase
307 monotonically based on number of photons used for the estimate. */
308 histEnd -> irrad [0] = fluxLo [0] / r;
309 histEnd -> irrad [1] = fluxLo [1] / r;
310 histEnd -> irrad [2] = fluxLo [2] / r;
311 totalWeight += histEnd++ -> weight = BIASCOMP_WGT((float)i);
312 }
313
314 /* Compute expected value (average) and variance of irradiance based on
315 history for numLo photons. */
316 setcolor(irradAvg, 0, 0, 0);
317 setcolor(irradVar, 0, 0, 0);
318
319 for (hist = pmap -> biasCompHist; hist < histEnd; ++hist)
320 for (i = 0; i <= 2; ++i) {
321 irradAvg [i] += r = hist -> weight * hist -> irrad [i];
322 irradVar [i] += r * hist -> irrad [i];
323 }
324
325 for (i = 0; i <= 2; ++i) {
326 r = irradAvg [i] /= totalWeight;
327 irradVar [i] = irradVar [i] / totalWeight - r * r;
328 }
329
330 /* Do binary search within interval [numLo, numHi]. numLo is towards
331 the END of the queue. */
332 while (numHi - numLo > 1) {
333 numMid = (numLo + numHi) >> 1;
334 /* Split interval to get numMid closest photons starting from the
335 END of the queue */
336 squeuePartition(squeueEnd, numLo, numMid, numHi);
337 /* Make sure furthest two photons are consecutive wrt distance */
338 squeuePartition(squeueEnd, numMid, numMid + 1, numHi);
339 copycolor(fluxMid, fluxLo);
340 sq = squeueEnd - numLo;
341
342 /* Get irradiance for numMid photons (ignoring constants) */
343 for (i = numLo; i < numMid; i++, sq--) {
344 /* Compute phase function for inscattering from photon */
345 if (gecc2 <= FTINY)
346 r = 1;
347 else {
348 r = DOT(ray -> rdir, sq -> photon -> norm) / 127;
349 r = 1 + gecc2 - 2 * ray -> gecc * r;
350 r = (1 - gecc2) / (r * sqrt(r));
351 }
352
353 getPhotonFlux(sq -> photon, irrad);
354 scalecolor(irrad, r);
355 addcolor(fluxMid, irrad);
356 }
357
358 /* Average radius between furthest two photons to improve accuracy */
359 r = 0.25 * (sq -> dist + (sq + 1) -> dist +
360 2 * sqrt(sq -> dist * (sq + 1) -> dist));
361 r *= sqrt(r);
362
363 /* Get deviation from current average, and probability that it's due
364 to noise from gaussian distribution based on current variance. Since
365 we are doing this for each colour channel we can also detect
366 chromatic bias. */
367 for (i = 0; i <= 2; ++i) {
368 d [i] = irradAvg [i] - (irrad [i] = fluxMid [i] / r);
369 p [i] = exp(-0.5 * d [i] * d [i] / irradVar [i]);
370 }
371
372 if (pmapRandom(pmap -> randState) < colorAvg(p)) {
373 /* Deviation is probably noise, so add mid irradiance to history */
374 copycolor(histEnd -> irrad, irrad);
375 totalWeight += histEnd++ -> weight = BIASCOMP_WGT((float)numMid);
376 setcolor(irradAvg, 0, 0, 0);
377 setcolor(irradVar, 0, 0, 0);
378
379 /* Update average and variance */
380 for (hist = pmap -> biasCompHist; hist < histEnd; ++hist)
381 for (i = 0; i <= 2; i++) {
382 r = hist -> irrad [i];
383 irradAvg [i] += hist -> weight * r;
384 irradVar [i] += hist -> weight * r * r;
385 }
386 for (i = 0; i <= 2; i++) {
387 r = irradAvg [i] /= totalWeight;
388 irradVar [i] = irradVar [i] / totalWeight - r * r;
389 }
390
391 /* Need more photons -- recurse on [numMid, numHi] */
392 numLo = numMid;
393 copycolor(fluxLo, fluxMid);
394 }
395 else
396 /* Deviation is probably bias -- need fewer photons,
397 so recurse on [numLo, numMid] */
398 numHi = numMid;
399 }
400
401 --histEnd;
402 for (i = 0; i <= 2; i++) {
403 /* Estimated relative error */
404 d [i] = histEnd -> irrad [i] / irradAvg [i] - 1;
405 /* Divide by 4 / 3 * PI for search volume (r^3 already accounted
406 for) and phase function normalization factor 1 / (4 * PI) */
407 irrad [i] = histEnd -> irrad [i] * 3 / (16 * PI * PI);
408 }
409
410 /* Update statistix */
411 r = colorAvg(d);
412 if (r < pmap -> minError)
413 pmap -> minError = r;
414 if (r > pmap -> maxError)
415 pmap -> maxError = r;
416 pmap -> rmsError += r * r;
417
418 if (numMid < pmap -> minGathered)
419 pmap -> minGathered = numMid;
420 if (numMid > pmap -> maxGathered)
421 pmap -> maxGathered = numMid;
422
423 pmap -> totalGathered += numMid;
424 ++pmap -> numDensity;
425 }
426