ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapooc.c
Revision: 1.6
Committed: Wed Apr 8 15:14:21 2020 UTC (4 years ago) by rschregle
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 1.5: +24 -12 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

# Content
1 /*
2 ======================================================================
3 Photon map interface to out-of-core octree
4
5 Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
6 (c) Lucerne University of Applied Sciences and Arts,
7 supported by the Swiss National Science Foundation (SNSF, #147053)
8 ======================================================================
9
10 $Id: pmapooc.c,v 1.5 2018/11/08 00:54:07 greg Exp $
11 */
12
13
14
15 #include "pmapdata.h" /* Includes pmapooc.h */
16 #include "source.h"
17 #include "otspecial.h"
18 #include "oocsort.h"
19 #include "oocbuild.h"
20
21
22
23 /* Returns photon position as sorting key for OOC_Octree & friends (notably
24 * for Morton code generation).
25 * !!! Uses type conversion from float via TEMPORARY storage;
26 * !!! THIS IS NOT THREAD SAFE!
27 * !!! RETURNED KEY PERSISTS ONLY IF COPIED BEFORE NEXT CALL! */
28 RREAL *OOC_PhotonKey (const void *p)
29 {
30 static FVECT photonPos; /* Temp storage for type conversion */
31
32 VCOPY(photonPos, ((Photon*)p) -> pos);
33 return photonPos;
34 }
35
36
37
38 #ifdef DEBUG_OOC
39 static int OOC_CheckKeys (FILE *file, const OOC_Octree *oct)
40 {
41 Photon p, lastp;
42 RREAL *key;
43 OOC_MortonIdx zIdx, lastzIdx = 0;
44
45 rewind(file);
46 memset(&lastp, 0, sizeof(lastp));
47
48 while (fread(&p, sizeof(p), 1, file) > 0) {
49 key = OOC_PhotonKey(&p);
50 zIdx = OOC_KEY2MORTON(key, oct);
51
52 if (zIdx < lastzIdx) {
53 error(INTERNAL, "photons not sorted");
54 return -1;
55 }
56
57 if (zIdx == lastzIdx) {
58 sprintf(errmsg, "identical key %021ld "
59 "for [%.9f, %.9f, %.9f]\tand [%.9f, %.9f, %.9f]",
60 zIdx, lastp.pos [0], lastp.pos [1], lastp.pos [2],
61 p.pos [0], p.pos [1], p.pos [2]);
62 error(WARNING, errmsg);
63 }
64
65 lastzIdx = zIdx;
66 memcpy(&lastp, &p, sizeof(p));
67 }
68
69 return 0;
70 }
71 #endif
72
73
74
75 void OOC_BuildPhotonMap (struct PhotonMap *pmap, unsigned numProc)
76 {
77 FILE *leafFile;
78 char leafFname [1024];
79 FVECT d, octOrg;
80 int i;
81 RREAL octSize = 0;
82
83 /* Determine octree size and origin from pmap extent and init octree */
84 VCOPY(octOrg, pmap -> minPos);
85 VSUB(d, pmap -> maxPos, pmap -> minPos);
86 for (i = 0; i < 3; i++)
87 if (octSize < d [i])
88 octSize = d [i];
89
90 if (octSize < FTINY)
91 error(INTERNAL, "zero octree size in OOC_BuildPhotonMap");
92
93 /* Derive leaf filename from photon map and open file */
94 strncpy(leafFname, pmap -> fileName, sizeof(leafFname));
95 strncat(leafFname, PMAP_OOC_LEAFSUFFIX,
96 sizeof(leafFname) - strlen(leafFname) - 1);
97 if (!(leafFile = fopen(leafFname, "w+b")))
98 error(SYSTEM, "failed to open leaf file in OOC_BuildPhotonMap");
99
100 #ifdef DEBUG_OOC
101 eputs("Sorting photons by Morton code...\n");
102 #endif
103
104 /* Sort photons in heapfile by Morton code and write to leaf file */
105 if (OOC_Sort(pmap -> heap, leafFile, PMAP_OOC_NUMBLK, PMAP_OOC_BLKSIZE,
106 numProc, sizeof(Photon), octOrg, octSize, OOC_PhotonKey))
107 error(INTERNAL, "failed out-of-core photon sort in OOC_BuildPhotonMap");
108
109 /* Init and build octree */
110 OOC_Init(&pmap -> store, sizeof(Photon), octOrg, octSize, OOC_PhotonKey,
111 leafFile);
112
113 #ifdef DEBUG_OOC
114 eputs("Checking leaf file consistency...\n");
115 OOC_CheckKeys(leafFile, &pmap -> store);
116
117 eputs("Building out-of-core octree...\n");
118 #endif
119
120 if (!OOC_Build(&pmap -> store, PMAP_OOC_LEAFMAX, PMAP_OOC_MAXDEPTH))
121 error(INTERNAL, "failed out-of-core octree build in OOC_BuildPhotonMap");
122
123 #ifdef DEBUG_OOC
124 eputs("Checking out-of-core octree consistency...\n");
125 if (OOC_Check(&pmap -> store, OOC_ROOT(&pmap -> store),
126 octOrg, octSize, 0))
127 error(INTERNAL, "inconsistent out-of-core octree; Time4Harakiri");
128 #endif
129 }
130
131
132
133 int OOC_SavePhotons (const struct PhotonMap *pmap, FILE *out)
134 {
135 return OOC_SaveOctree(&pmap -> store, out);
136 }
137
138
139
140 int OOC_LoadPhotons (struct PhotonMap *pmap, FILE *nodeFile)
141 {
142 FILE *leafFile;
143 char leafFname [1024];
144
145 /* Derive leaf filename from photon map and open file */
146 strncpy(leafFname, pmap -> fileName, sizeof(leafFname));
147 strncat(leafFname, PMAP_OOC_LEAFSUFFIX,
148 sizeof(leafFname) - strlen(leafFname) - 1);
149
150 if (!(leafFile = fopen(leafFname, "r")))
151 error(SYSTEM, "failed to open leaf file in OOC_LoadPhotons");
152
153 if (OOC_LoadOctree(&pmap -> store, nodeFile, OOC_PhotonKey, leafFile))
154 return -1;
155
156 return 0;
157 }
158
159
160
161 void OOC_InitFindPhotons (struct PhotonMap *pmap)
162 {
163 if (OOC_InitNearest(&pmap -> squeue, pmap -> maxGather + 1,
164 sizeof(Photon)))
165 error(SYSTEM, "can't allocate photon search queue");
166 }
167
168
169
170 static void OOC_InitPhotonCache (struct PhotonMap *pmap)
171 /* Initialise OOC photon cache */
172 {
173 static char warn = 1;
174
175 if (!pmap -> store.cache && !pmap -> numDensity) {
176 if (pmapCacheSize > 0) {
177 const unsigned pageSize = pmapCachePageSize * pmap -> maxGather,
178 numPages = pmapCacheSize / pageSize;
179 /* Allocate & init I/O cache in octree */
180 pmap -> store.cache = malloc(sizeof(OOC_Cache));
181
182 if (!pmap -> store.cache ||
183 OOC_CacheInit(pmap -> store.cache, numPages, pageSize,
184 sizeof(Photon))) {
185 error(SYSTEM, "failed OOC photon map cache init");
186 }
187 }
188 else if (warn) {
189 error(WARNING, "OOC photon map cache DISABLED");
190 warn = 0;
191 }
192 }
193 }
194
195
196
197 typedef struct {
198 const PhotonMap *pmap;
199 const float *norm;
200 } OOC_FilterData;
201
202
203
204 int OOC_FilterPhoton (void *p, void *fd)
205 /* Filter callback for photon kNN search, used by OOC_FindNearest() */
206 {
207 const Photon *photon = p;
208 const OOC_FilterData *filtData = fd;
209 const PhotonMap *pmap = filtData -> pmap;
210
211 /* Reject photon if normal faces away (ignored for volume photons) with
212 * tolerance to account for perturbation; note photon normal is coded
213 * in range [-127,127], hence we factor this in */
214 if (filtData -> norm &&
215 DOT(filtData->norm, photon->norm) <= PMAP_NORM_TOL * 127 * frandom())
216 return 0;
217
218 if (isContribPmap(pmap)) {
219 /* Lookup in contribution photon map; filter according to emitting
220 * light source if contrib list set, else accept all */
221
222 if (pmap -> srcContrib) {
223 OBJREC *srcMod;
224 const int srcIdx = photonSrcIdx(pmap, photon);
225
226 if (srcIdx < 0 || srcIdx >= nsources)
227 error(INTERNAL, "invalid light source index in photon map");
228
229 srcMod = findmaterial(source [srcIdx].so);
230
231 /* Reject photon if contributions from light source which emitted
232 * it are not sought */
233 if (!lu_find(pmap -> srcContrib, srcMod -> oname) -> data)
234 return 0;
235 }
236
237 /* Reject non-caustic photon if lookup for caustic contribs */
238 if (pmap -> lookupCaustic && !photon -> caustic)
239 return 0;
240 }
241
242 /* Accept photon */
243 return 1;
244 }
245
246
247
248 int OOC_FindPhotons (struct PhotonMap *pmap, const FVECT pos, const FVECT norm)
249 {
250 OOC_SearchFilter filt;
251 OOC_FilterData filtData;
252 float n [3];
253
254 /* Lazily init OOC cache */
255 if (!pmap -> store.cache)
256 OOC_InitPhotonCache(pmap);
257
258 /* Set up filter callback */
259 filtData.pmap = pmap;
260 if (norm)
261 VCOPY(n, norm);
262 filtData.norm = norm ? n : NULL;
263 filt.data = &filtData;
264 filt.func = OOC_FilterPhoton;
265
266 pmap -> maxDist2 = OOC_FindNearest(&pmap -> store,
267 OOC_ROOT(&pmap -> store), 0,
268 pmap -> store.org, pmap -> store.size,
269 pos, &filt, &pmap -> squeue,
270 pmap -> maxDist2);
271
272 if (pmap -> maxDist2 < 0)
273 error(INTERNAL, "failed k-NN photon lookup in OOC_FindPhotons");
274
275 /* Return success or failure (empty queue => none found) */
276 return pmap -> squeue.tail ? 0 : -1;
277 }
278
279
280
281 int OOC_Find1Photon (struct PhotonMap* pmap, const FVECT pos,
282 const FVECT norm, Photon *photon)
283 {
284 OOC_SearchFilter filt;
285 OOC_FilterData filtData;
286 float n [3], maxDist2;
287
288 /* Lazily init OOC cache */
289 if (!pmap -> store.cache)
290 OOC_InitPhotonCache(pmap);
291
292 /* Set up filter callback */
293 filtData.pmap = pmap;
294 if (norm)
295 VCOPY(n, norm);
296 filtData.norm = norm ? n : NULL;
297 filt.data = &filtData;
298 filt.func = OOC_FilterPhoton;
299
300 maxDist2 = OOC_Find1Nearest(&pmap -> store,
301 OOC_ROOT(&pmap -> store), 0,
302 pmap -> store.org, pmap -> store.size,
303 pos, &filt, photon, pmap -> maxDist2);
304
305 if (maxDist2 < 0)
306 error(INTERNAL, "failed 1-NN photon lookup in OOC_Find1Photon");
307
308 if (maxDist2 >= pmap -> maxDist2)
309 /* No photon found => failed */
310 return -1;
311 else {
312 /* Set photon distance => success */
313 pmap -> maxDist2 = maxDist2;
314 return 0;
315 }
316 }
317
318
319
320 int OOC_GetPhoton (struct PhotonMap *pmap, PhotonIdx idx,
321 Photon *photon)
322 {
323 return OOC_GetData(&pmap -> store, idx, photon);
324 }
325
326
327
328 Photon *OOC_GetNearestPhoton (const PhotonSearchQueue *squeue, PhotonIdx idx)
329 {
330 return OOC_GetNearest(squeue, idx);
331 }
332
333
334
335 PhotonIdx OOC_FirstPhoton (const struct PhotonMap* pmap)
336 {
337 return 0;
338 }