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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pmutil.c,v 2.6 2021/03/23 00:07:13 rschregle Exp $";
3 #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 $Id: pmutil.c,v 2.6 2021/03/23 00:07:13 rschregle Exp $
16 */
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 photonDensity, photonDensity
32 };
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 sprintf(errmsg, "multiple %s photon maps, dropping previous",
79 pmapName [type]);
80 error(WARNING, errmsg);
81 deletePhotons(pmaps [type]);
82 free(pmaps [type]);
83 }
84 pmaps [type] = pm;
85
86 /* 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 if (pm -> maxGather > pm -> numPhotons) {
107 /* 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 }
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 pmaps [t] = NULL;
131 }
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 float r2;
143 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 /* 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
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 scalecolor(flux, 2 * (1 - sqn -> dist2 / r2));
185 #endif
186 addcolor(irrad, flux);
187 }
188
189 /* Divide by search area PI * r^2, 1 / PI required as ambient
190 normalisation factor */
191 scalecolor(irrad, 1 / (PI * PI * r2));
192
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 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 }
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 float r2, gecc2, ph;
229 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 /* 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
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 scalecolor(irrad, 3 / (16 * PI * PI * r2 * sqrt(r2)));
278 return;
279 }
280 #if 0
281 else
282 /* Apply bias compensation to density estimate */
283 volumeBiasComp(pmap, ray, irrad);
284 #endif
285 }