ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmutil.c
Revision: 2.5
Committed: Wed Apr 8 15:14:21 2020 UTC (4 years, 1 month ago) by rschregle
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 2.4: +7 -4 lines
Log Message:
Fixed est00pid bug in single photon lookups that returned junk when none found, added code to detect and handle (ignore).

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 rschregle 2.5 static const char RCSid[] = "$Id: pmutil.c,v 2.4 2020/01/23 18:27:02 rschregle Exp $";
3 greg 2.1 #endif
4    
5     /*
6     ======================================================================
7     Photon map utilities
8    
9     Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
10     (c) Fraunhofer Institute for Solar Energy Systems,
11     (c) Lucerne University of Applied Sciences and Arts,
12     supported by the Swiss National Science Foundation (SNSF, #147053)
13     ======================================================================
14    
15 rschregle 2.5 $Id: pmutil.c,v 2.4 2020/01/23 18:27:02 rschregle Exp $
16 greg 2.1 */
17    
18     #include "pmap.h"
19     #include "pmapio.h"
20     #include "pmapbias.h"
21     #include "otypes.h"
22     #include <sys/stat.h>
23    
24    
25     extern char *octname;
26    
27    
28     /* Photon map lookup functions per type */
29     void (*pmapLookup [NUM_PMAP_TYPES])(PhotonMap*, RAY*, COLOR) = {
30     photonDensity, photonPreCompDensity, photonDensity, volumePhotonDensity,
31 rschregle 2.2 photonDensity, photonDensity
32 greg 2.1 };
33    
34    
35    
36    
37     void colorNorm (COLOR c)
38     /* Normalise colour channels to average of 1 */
39     {
40     const float avg = colorAvg(c);
41    
42     if (!avg)
43     return;
44    
45     c [0] /= avg;
46     c [1] /= avg;
47     c [2] /= avg;
48     }
49    
50    
51    
52    
53     void loadPmaps (PhotonMap **pmaps, const PhotonMapParams *parm)
54     {
55     unsigned t;
56     struct stat octstat, pmstat;
57     PhotonMap *pm;
58     PhotonMapType type;
59    
60     for (t = 0; t < NUM_PMAP_TYPES; t++)
61     if (setPmapParam(&pm, parm + t)) {
62     /* Check if photon map newer than octree */
63     if (pm -> fileName && octname &&
64     !stat(pm -> fileName, &pmstat) && !stat(octname, &octstat) &&
65     octstat.st_mtime > pmstat.st_mtime) {
66     sprintf(errmsg, "photon map in file %s may be stale",
67     pm -> fileName);
68     error(USER, errmsg);
69     }
70    
71     /* Load photon map from file and get its type */
72     if ((type = loadPhotonMap(pm, pm -> fileName)) == PMAP_TYPE_NONE)
73     error(USER, "failed loading photon map");
74    
75     /* Assign to appropriate photon map type (deleting previously
76     * loaded photon map of same type if necessary) */
77     if (pmaps [type]) {
78 rschregle 2.4 sprintf(errmsg, "multiple %s photon maps, dropping previous",
79     pmapName [type]);
80     error(WARNING, errmsg);
81 greg 2.1 deletePhotons(pmaps [type]);
82     free(pmaps [type]);
83     }
84     pmaps [type] = pm;
85    
86 rschregle 2.4 /* Check for valid density estimate bandwidths */
87     if ((pm -> minGather > 1 || pm -> maxGather > 1) &&
88     (type == PMAP_TYPE_PRECOMP)) {
89     /* Force bwidth to 1 for precomputed pmap */
90     error(WARNING, "ignoring bandwidth for precomp photon map");
91     pm -> minGather = pm -> maxGather = 1;
92     }
93    
94     if ((pm -> maxGather > pm -> minGather) &&
95     (type == PMAP_TYPE_VOLUME)) {
96     /* Biascomp for volume pmaps (see volumePhotonDensity() below)
97     is considered redundant, and there's probably no point in
98     recovering by using the lower bandwidth, since it's probably
99     not what the user wants, so bail out. */
100     sprintf(errmsg,
101     "bias compensation is not available with %s photon maps",
102     pmapName [type]);
103     error(USER, errmsg);
104     }
105    
106 greg 2.1 if (pm -> maxGather > pm -> numPhotons) {
107     error(WARNING, "adjusting density estimate bandwidth");
108     pm -> minGather = pm -> maxGather = pm -> numPhotons;
109 rschregle 2.4 }
110 greg 2.1 }
111     }
112    
113    
114    
115     void cleanUpPmaps (PhotonMap **pmaps)
116     {
117     unsigned t;
118    
119     for (t = 0; t < NUM_PMAP_TYPES; t++) {
120     if (pmaps [t]) {
121     deletePhotons(pmaps [t]);
122     free(pmaps [t]);
123     }
124     }
125     }
126    
127    
128    
129    
130     void photonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad)
131     /* Photon density estimate. Returns irradiance at ray -> rop. */
132     {
133     unsigned i;
134 rschregle 2.3 float r2;
135 greg 2.1 COLOR flux;
136     Photon *photon;
137     const PhotonSearchQueueNode *sqn;
138    
139     setcolor(irrad, 0, 0, 0);
140    
141     if (!pmap -> maxGather)
142     return;
143    
144     /* Ignore sources */
145     if (ray -> ro && islight(objptr(ray -> ro -> omod) -> otype))
146     return;
147    
148     findPhotons(pmap, ray);
149    
150     /* Need at least 2 photons */
151     if (pmap -> squeue.tail < 2) {
152     #ifdef PMAP_NONEFOUND
153     sprintf(errmsg, "no photons found on %s at (%.3f, %.3f, %.3f)",
154     ray -> ro ? ray -> ro -> oname : "<null>",
155     ray -> rop [0], ray -> rop [1], ray -> rop [2]);
156     error(WARNING, errmsg);
157     #endif
158    
159     return;
160     }
161    
162     if (pmap -> minGather == pmap -> maxGather) {
163     /* No bias compensation. Just do a plain vanilla estimate */
164     sqn = pmap -> squeue.node + 1;
165    
166 rschregle 2.3 /* Average radius^2 between furthest two photons to improve accuracy */
167     r2 = max(sqn -> dist2, (sqn + 1) -> dist2);
168     r2 = 0.25 * (pmap -> maxDist2 + r2 + 2 * sqrt(pmap -> maxDist2 * r2));
169 greg 2.1
170     /* Skip the extra photon */
171     for (i = 1 ; i < pmap -> squeue.tail; i++, sqn++) {
172     photon = getNearestPhoton(&pmap -> squeue, sqn -> idx);
173     getPhotonFlux(photon, flux);
174     #ifdef PMAP_EPANECHNIKOV
175     /* Apply Epanechnikov kernel to photon flux based on photon dist */
176 rschregle 2.3 scalecolor(flux, 2 * (1 - sqn -> dist2 / r2));
177 greg 2.1 #endif
178     addcolor(irrad, flux);
179     }
180    
181     /* Divide by search area PI * r^2, 1 / PI required as ambient
182     normalisation factor */
183 rschregle 2.3 scalecolor(irrad, 1 / (PI * PI * r2));
184 greg 2.1
185     return;
186     }
187     else
188     /* Apply bias compensation to density estimate */
189     biasComp(pmap, irrad);
190     }
191    
192    
193    
194    
195     void photonPreCompDensity (PhotonMap *pmap, RAY *r, COLOR irrad)
196     /* Returns precomputed photon density estimate at ray -> rop. */
197     {
198     Photon p;
199    
200     setcolor(irrad, 0, 0, 0);
201    
202     /* Ignore sources */
203     if (r -> ro && islight(objptr(r -> ro -> omod) -> otype))
204     return;
205    
206 rschregle 2.5 if (find1Photon(preCompPmap, r, &p))
207     /* p contains a found photon, so get its irradiance, otherwise it
208     * remains zero under the assumption all photons are too distant
209     * to contribute significantly */
210     getPhotonFlux(&p, irrad);
211 greg 2.1 }
212    
213    
214    
215    
216     void volumePhotonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad)
217     /* Photon volume density estimate. Returns irradiance at ray -> rop. */
218     {
219     unsigned i;
220 rschregle 2.3 float r2, gecc2, ph;
221 greg 2.1 COLOR flux;
222     Photon *photon;
223     const PhotonSearchQueueNode *sqn;
224    
225     setcolor(irrad, 0, 0, 0);
226    
227     if (!pmap -> maxGather)
228     return;
229    
230     findPhotons(pmap, ray);
231    
232     /* Need at least 2 photons */
233     if (pmap -> squeue.tail < 2)
234     return;
235    
236     #if 0
237     /* Volume biascomp disabled (probably redundant) */
238     if (pmap -> minGather == pmap -> maxGather)
239     #endif
240     {
241     /* No bias compensation. Just do a plain vanilla estimate */
242     gecc2 = ray -> gecc * ray -> gecc;
243     sqn = pmap -> squeue.node + 1;
244    
245 rschregle 2.3 /* Average radius^2 between furthest two photons to improve accuracy */
246     r2 = max(sqn -> dist2, (sqn + 1) -> dist2);
247     r2 = 0.25 * (pmap -> maxDist2 + r2 + 2 * sqrt(pmap -> maxDist2 * r2));
248 greg 2.1
249     /* Skip the extra photon */
250     for (i = 1; i < pmap -> squeue.tail; i++, sqn++) {
251     photon = getNearestPhoton(&pmap -> squeue, sqn -> idx);
252    
253     /* Compute phase function for inscattering from photon */
254     if (gecc2 <= FTINY)
255     ph = 1;
256     else {
257     ph = DOT(ray -> rdir, photon -> norm) / 127;
258     ph = 1 + gecc2 - 2 * ray -> gecc * ph;
259     ph = (1 - gecc2) / (ph * sqrt(ph));
260     }
261    
262     getPhotonFlux(photon, flux);
263     scalecolor(flux, ph);
264     addcolor(irrad, flux);
265     }
266    
267     /* Divide by search volume 4 / 3 * PI * r^3 and phase function
268     normalization factor 1 / (4 * PI) */
269 rschregle 2.3 scalecolor(irrad, 3 / (16 * PI * PI * r2 * sqrt(r2)));
270 greg 2.1 return;
271     }
272     #if 0
273     else
274     /* Apply bias compensation to density estimate */
275     volumeBiasComp(pmap, ray, irrad);
276     #endif
277     }