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, 9 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

# User Rev Content
1 greg 2.3 #ifndef lint
2     static const char RCSid[] = "$Id$";
3     #endif
4 greg 2.1 /*
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 rschregle 2.2 Roland Schregle ([email protected])
13     (c) Fraunhofer Institute for Solar Energy Systems
14 greg 2.1 ==================================================================
15    
16 greg 2.3 $Id: pmapbias.c,v 2.2 2015/05/08 13:20:23 rschregle Exp $
17 greg 2.1 */
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 greg 2.3