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, 4 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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pmutil.c,v 2.3 2018/02/09 14:57:42 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.3 2018/02/09 14:57:42 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 error(WARNING, "adjusting density estimate bandwidth");
108 pm -> minGather = pm -> maxGather = pm -> numPhotons;
109 }
110 }
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 float r2;
135 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 /* 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
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 scalecolor(flux, 2 * (1 - sqn -> dist2 / r2));
177 #endif
178 addcolor(irrad, flux);
179 }
180
181 /* Divide by search area PI * r^2, 1 / PI required as ambient
182 normalisation factor */
183 scalecolor(irrad, 1 / (PI * PI * r2));
184
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 float r2, gecc2, ph;
218 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 /* 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
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 scalecolor(irrad, 3 / (16 * PI * PI * r2 * sqrt(r2)));
267 return;
268 }
269 #if 0
270 else
271 /* Apply bias compensation to density estimate */
272 volumeBiasComp(pmap, ray, irrad);
273 #endif
274 }