ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmutil.c
Revision: 2.7
Committed: Fri Jan 10 21:43:22 2025 UTC (3 months, 2 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.6: +3 -2 lines
Log Message:
fix: Avoid second release of photon maps (malloc error)

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.7 static const char RCSid[] = "$Id: pmutil.c,v 2.6 2021/03/23 00:07:13 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 greg 2.7 $Id: pmutil.c,v 2.6 2021/03/23 00:07:13 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 rschregle 2.6
60 greg 2.1 for (t = 0; t < NUM_PMAP_TYPES; t++)
61 rschregle 2.6 if (setPmapParam(&pm, parm + t)) {
62 greg 2.1 /* 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 rschregle 2.6
71 greg 2.1 /* 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 rschregle 2.6
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 rschregle 2.6
94 rschregle 2.4 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 rschregle 2.6
106 greg 2.1 if (pm -> maxGather > pm -> numPhotons) {
107 rschregle 2.6 /* Clamp lookup bandwidth to total number of photons (minus one,
108     since density estimate gets extra photon to obtain averaged
109     radius) */
110     sprintf(
111     errmsg, "clamping density estimate bandwidth to %ld",
112     pm -> numPhotons
113     );
114     error(WARNING, errmsg);
115     pm -> minGather = pm -> maxGather = pm -> numPhotons - 1;
116     }
117 greg 2.1 }
118     }
119    
120    
121    
122     void cleanUpPmaps (PhotonMap **pmaps)
123     {
124     unsigned t;
125    
126     for (t = 0; t < NUM_PMAP_TYPES; t++) {
127     if (pmaps [t]) {
128     deletePhotons(pmaps [t]);
129     free(pmaps [t]);
130 greg 2.7 pmaps [t] = NULL;
131 greg 2.1 }
132     }
133     }
134    
135    
136    
137    
138     void photonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad)
139     /* Photon density estimate. Returns irradiance at ray -> rop. */
140     {
141     unsigned i;
142 rschregle 2.3 float r2;
143 greg 2.1 COLOR flux;
144     Photon *photon;
145     const PhotonSearchQueueNode *sqn;
146    
147     setcolor(irrad, 0, 0, 0);
148    
149     if (!pmap -> maxGather)
150     return;
151    
152     /* Ignore sources */
153     if (ray -> ro && islight(objptr(ray -> ro -> omod) -> otype))
154     return;
155    
156     findPhotons(pmap, ray);
157    
158     /* Need at least 2 photons */
159     if (pmap -> squeue.tail < 2) {
160     #ifdef PMAP_NONEFOUND
161     sprintf(errmsg, "no photons found on %s at (%.3f, %.3f, %.3f)",
162     ray -> ro ? ray -> ro -> oname : "<null>",
163     ray -> rop [0], ray -> rop [1], ray -> rop [2]);
164     error(WARNING, errmsg);
165     #endif
166    
167     return;
168     }
169    
170     if (pmap -> minGather == pmap -> maxGather) {
171     /* No bias compensation. Just do a plain vanilla estimate */
172     sqn = pmap -> squeue.node + 1;
173    
174 rschregle 2.3 /* Average radius^2 between furthest two photons to improve accuracy */
175     r2 = max(sqn -> dist2, (sqn + 1) -> dist2);
176     r2 = 0.25 * (pmap -> maxDist2 + r2 + 2 * sqrt(pmap -> maxDist2 * r2));
177 greg 2.1
178     /* Skip the extra photon */
179     for (i = 1 ; i < pmap -> squeue.tail; i++, sqn++) {
180     photon = getNearestPhoton(&pmap -> squeue, sqn -> idx);
181     getPhotonFlux(photon, flux);
182     #ifdef PMAP_EPANECHNIKOV
183     /* Apply Epanechnikov kernel to photon flux based on photon dist */
184 rschregle 2.3 scalecolor(flux, 2 * (1 - sqn -> dist2 / r2));
185 greg 2.1 #endif
186     addcolor(irrad, flux);
187     }
188    
189     /* Divide by search area PI * r^2, 1 / PI required as ambient
190     normalisation factor */
191 rschregle 2.3 scalecolor(irrad, 1 / (PI * PI * r2));
192 greg 2.1
193     return;
194     }
195     else
196     /* Apply bias compensation to density estimate */
197     biasComp(pmap, irrad);
198     }
199    
200    
201    
202    
203     void photonPreCompDensity (PhotonMap *pmap, RAY *r, COLOR irrad)
204     /* Returns precomputed photon density estimate at ray -> rop. */
205     {
206     Photon p;
207    
208     setcolor(irrad, 0, 0, 0);
209    
210     /* Ignore sources */
211     if (r -> ro && islight(objptr(r -> ro -> omod) -> otype))
212     return;
213    
214 rschregle 2.5 if (find1Photon(preCompPmap, r, &p))
215     /* p contains a found photon, so get its irradiance, otherwise it
216     * remains zero under the assumption all photons are too distant
217     * to contribute significantly */
218     getPhotonFlux(&p, irrad);
219 greg 2.1 }
220    
221    
222    
223    
224     void volumePhotonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad)
225     /* Photon volume density estimate. Returns irradiance at ray -> rop. */
226     {
227     unsigned i;
228 rschregle 2.3 float r2, gecc2, ph;
229 greg 2.1 COLOR flux;
230     Photon *photon;
231     const PhotonSearchQueueNode *sqn;
232    
233     setcolor(irrad, 0, 0, 0);
234    
235     if (!pmap -> maxGather)
236     return;
237    
238     findPhotons(pmap, ray);
239    
240     /* Need at least 2 photons */
241     if (pmap -> squeue.tail < 2)
242     return;
243    
244     #if 0
245     /* Volume biascomp disabled (probably redundant) */
246     if (pmap -> minGather == pmap -> maxGather)
247     #endif
248     {
249     /* No bias compensation. Just do a plain vanilla estimate */
250     gecc2 = ray -> gecc * ray -> gecc;
251     sqn = pmap -> squeue.node + 1;
252    
253 rschregle 2.3 /* Average radius^2 between furthest two photons to improve accuracy */
254     r2 = max(sqn -> dist2, (sqn + 1) -> dist2);
255     r2 = 0.25 * (pmap -> maxDist2 + r2 + 2 * sqrt(pmap -> maxDist2 * r2));
256 greg 2.1
257     /* Skip the extra photon */
258     for (i = 1; i < pmap -> squeue.tail; i++, sqn++) {
259     photon = getNearestPhoton(&pmap -> squeue, sqn -> idx);
260    
261     /* Compute phase function for inscattering from photon */
262     if (gecc2 <= FTINY)
263     ph = 1;
264     else {
265     ph = DOT(ray -> rdir, photon -> norm) / 127;
266     ph = 1 + gecc2 - 2 * ray -> gecc * ph;
267     ph = (1 - gecc2) / (ph * sqrt(ph));
268     }
269    
270     getPhotonFlux(photon, flux);
271     scalecolor(flux, ph);
272     addcolor(irrad, flux);
273     }
274    
275     /* Divide by search volume 4 / 3 * PI * r^3 and phase function
276     normalization factor 1 / (4 * PI) */
277 rschregle 2.3 scalecolor(irrad, 3 / (16 * PI * PI * r2 * sqrt(r2)));
278 greg 2.1 return;
279     }
280     #if 0
281     else
282     /* Apply bias compensation to density estimate */
283     volumeBiasComp(pmap, ray, irrad);
284     #endif
285     }