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

# User Rev Content
1 greg 2.3 #ifndef lint
2 rschregle 2.5 static const char RCSid[] = "$Id: pmapbias.c,v 4.7 2015/11/16 13:32:03 taschreg Exp taschreg $";
3 greg 2.3 #endif
4 rschregle 2.5
5 greg 2.1 /*
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 rschregle 2.2 Roland Schregle ([email protected])
14     (c) Fraunhofer Institute for Solar Energy Systems
15 greg 2.1 ==================================================================
16    
17 rschregle 2.5 $Id: pmapbias.c,v 4.7 2015/11/16 13:32:03 taschreg Exp taschreg $
18 greg 2.1 */
19    
20    
21    
22     #include "pmapbias.h"
23     #include "pmap.h"
24     #include "pmaprand.h"
25    
26    
27    
28 rschregle 2.5 void squeuePartition (PhotonSearchQueueNode* squeue, unsigned lo,
29 greg 2.1 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 rschregle 2.5 unsigned l, h, p;
39     PhotonSearchQueueNode *lp, *hp, *pp, tmp;
40     float pivot;
41 greg 2.1
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 rschregle 2.5 pivot = pp -> dist2;
52 greg 2.1
53     /* l & h converge, swapping elements out of order with respect to
54     pivot node. */
55     while (l < h) {
56 rschregle 2.5 while (lp -> dist2 <= pivot && l <= h && l < hi)
57 greg 2.1 ++l, --lp;
58 rschregle 2.5
59     while (hp -> dist2 >= pivot && h >= l && h > lo)
60 greg 2.1 --h, ++hp;
61    
62     if (l < h) {
63     /* Swap */
64 rschregle 2.5 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 greg 2.1 }
71     }
72    
73     /* Swap convergence and pivot node */
74     if (p > h) {
75     /* Need this otherwise shit happens!
76 rschregle 2.5 Since lp -> dist2 > hp -> dist2, we swap either l or p depending
77 greg 2.1 on whether we're above or below p */
78     h = l;
79     hp = lp;
80     }
81    
82 rschregle 2.5 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 greg 2.1 if (h >= mid)
90     hi = h - 1;
91 rschregle 2.5
92 greg 2.1 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 rschregle 2.5 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 greg 2.1
111     if (!pmap -> biasCompHist) {
112     /* Allocate bias compensation history */
113 rschregle 2.5 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 greg 2.1 if (!pmap -> biasCompHist)
118     error(USER, "can't allocate bias compensation history");
119     }
120    
121 rschregle 2.5 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 greg 2.1 histEnd = pmap -> biasCompHist;
125     setcolor(fluxLo, 0, 0, 0);
126    
127     /* Partition to get numLo closest photons starting from END of queue */
128 rschregle 2.5 squeuePartition(sqEnd, 1, numLo + 1, numHi);
129 greg 2.1
130     /* Get irradiance estimates (ignoring 1 / PI) using 1..numLo photons
131     and chuck in history. Queue is traversed BACKWARDS. */
132 rschregle 2.5 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 greg 2.1 addcolor(fluxLo, irrad);
138     /* Average radius between furthest two photons to improve accuracy */
139 rschregle 2.5 r = 0.25 * (sqn -> dist2 + (sqn - 1) -> dist2 +
140     2 * sqrt(sqn -> dist2 * (sqn - 1) -> dist2));
141 greg 2.1 /* 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 rschregle 2.5 squeuePartition(sqEnd, numLo, numMid, numHi);
172 greg 2.1 /* Make sure furthest two photons are consecutive wrt distance */
173 rschregle 2.5 squeuePartition(sqEnd, numMid, numMid + 1, numHi);
174 greg 2.1 copycolor(fluxMid, fluxLo);
175 rschregle 2.5 sqn = sqEnd - numLo;
176 greg 2.1
177     /* Get irradiance for numMid photons (ignoring 1 / PI) */
178 rschregle 2.5 for (i = numLo; i < numMid; i++, sqn--) {
179     photon = getNearestPhoton(&pmap -> squeue, sqn -> idx);
180     getPhotonFlux(photon, irrad);
181 greg 2.1 addcolor(fluxMid, irrad);
182     }
183    
184     /* Average radius between furthest two photons to improve accuracy */
185 rschregle 2.5 r = 0.25 * (sqn -> dist2 + (sqn + 1) -> dist2 +
186     2 * sqrt(sqn -> dist2 * (sqn + 1) -> dist2));
187 greg 2.1
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 rschregle 2.5 /* Need more photons --> recurse on [numMid, numHi] */
218 greg 2.1 numLo = numMid;
219     copycolor(fluxLo, fluxMid);
220     }
221     else
222 rschregle 2.5 /* Deviation is probably bias --> need fewer photons,
223 greg 2.1 so recurse on [numLo, numMid] */
224     numHi = numMid;
225     }
226    
227     --histEnd;
228 rschregle 2.5
229 greg 2.1 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 rschregle 2.5 pmap -> rmsError += r * r;
245    
246 greg 2.1 if (r < pmap -> minError)
247     pmap -> minError = r;
248 rschregle 2.5
249 greg 2.1 if (r > pmap -> maxError)
250     pmap -> maxError = r;
251    
252     if (numHi < pmap -> minGathered)
253     pmap -> minGathered = numHi;
254 rschregle 2.5
255 greg 2.1 if (numHi > pmap -> maxGathered)
256     pmap -> maxGathered = numHi;
257    
258     pmap -> totalGathered += numHi;
259     ++pmap -> numDensity;
260     }
261    
262    
263    
264 rschregle 2.5 /* Volume bias compensation disabled (probably redundant) */
265     #if 0
266 greg 2.1 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 rschregle 2.5 #endif