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 (9 years, 8 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

# User Rev Content
1 greg 2.3 #ifndef lint
2 greg 2.4 static const char RCSid[] = "$Id: pmapbias.c,v 2.3 2015/08/18 18:45:55 greg Exp $";
3 greg 2.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     */
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 greg 2.3