ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmutil.c
Revision: 2.4
Committed: Thu Jan 23 18:27:02 2020 UTC (4 years, 9 months ago) by rschregle
Content type: text/plain
Branch: MAIN
Changes since 2.3: +26 -4 lines
Log Message:
Added check for deprecated biascomp with volume pmaps in loadPmaps().

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 rschregle 2.4 static const char RCSid[] = "$Id: pmutil.c,v 2.3 2018/02/09 14:57:42 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.4 $Id: pmutil.c,v 2.3 2018/02/09 14:57:42 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     find1Photon(preCompPmap, r, &p);
207     getPhotonFlux(&p, irrad);
208     }
209    
210    
211    
212    
213     void volumePhotonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad)
214     /* Photon volume density estimate. Returns irradiance at ray -> rop. */
215     {
216     unsigned i;
217 rschregle 2.3 float r2, gecc2, ph;
218 greg 2.1 COLOR flux;
219     Photon *photon;
220     const PhotonSearchQueueNode *sqn;
221    
222     setcolor(irrad, 0, 0, 0);
223    
224     if (!pmap -> maxGather)
225     return;
226    
227     findPhotons(pmap, ray);
228    
229     /* Need at least 2 photons */
230     if (pmap -> squeue.tail < 2)
231     return;
232    
233     #if 0
234     /* Volume biascomp disabled (probably redundant) */
235     if (pmap -> minGather == pmap -> maxGather)
236     #endif
237     {
238     /* No bias compensation. Just do a plain vanilla estimate */
239     gecc2 = ray -> gecc * ray -> gecc;
240     sqn = pmap -> squeue.node + 1;
241    
242 rschregle 2.3 /* Average radius^2 between furthest two photons to improve accuracy */
243     r2 = max(sqn -> dist2, (sqn + 1) -> dist2);
244     r2 = 0.25 * (pmap -> maxDist2 + r2 + 2 * sqrt(pmap -> maxDist2 * r2));
245 greg 2.1
246     /* Skip the extra photon */
247     for (i = 1; i < pmap -> squeue.tail; i++, sqn++) {
248     photon = getNearestPhoton(&pmap -> squeue, sqn -> idx);
249    
250     /* Compute phase function for inscattering from photon */
251     if (gecc2 <= FTINY)
252     ph = 1;
253     else {
254     ph = DOT(ray -> rdir, photon -> norm) / 127;
255     ph = 1 + gecc2 - 2 * ray -> gecc * ph;
256     ph = (1 - gecc2) / (ph * sqrt(ph));
257     }
258    
259     getPhotonFlux(photon, flux);
260     scalecolor(flux, ph);
261     addcolor(irrad, flux);
262     }
263    
264     /* Divide by search volume 4 / 3 * PI * r^3 and phase function
265     normalization factor 1 / (4 * PI) */
266 rschregle 2.3 scalecolor(irrad, 3 / (16 * PI * PI * r2 * sqrt(r2)));
267 greg 2.1 return;
268     }
269     #if 0
270     else
271     /* Apply bias compensation to density estimate */
272     volumeBiasComp(pmap, ray, irrad);
273     #endif
274     }