ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapbias.c
Revision: 2.3
Committed: Tue Aug 18 18:45:55 2015 UTC (8 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.2: +5 -2 lines
Log Message:
Added missing RCSid forgotten during initial check-in

File Contents

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