1 |
+ |
#ifndef lint |
2 |
+ |
static const char RCSid[] = "$Id$"; |
3 |
+ |
#endif |
4 |
|
/* |
5 |
|
================================================================== |
6 |
|
Photon map data structures and kd-tree handling |
11 |
|
supported by the Swiss National Science Foundation (SNSF, #147053) |
12 |
|
================================================================== |
13 |
|
|
11 |
– |
$Id$ |
14 |
|
*/ |
15 |
|
|
16 |
|
|
21 |
|
#include "otypes.h" |
22 |
|
#include "source.h" |
23 |
|
#include "rcontrib.h" |
24 |
+ |
#include "random.h" |
25 |
|
|
26 |
|
|
27 |
|
|
69 |
|
const PhotonPrimary* addPhotonPrimary (PhotonMap *pmap, const RAY *ray) |
70 |
|
{ |
71 |
|
PhotonPrimary *prim = NULL; |
72 |
+ |
FVECT dvec; |
73 |
|
|
74 |
|
if (!pmap || !ray) |
75 |
|
return NULL; |
102 |
|
prim -> srcIdx = -1; |
103 |
|
|
104 |
|
/* Reverse incident direction to point to light source */ |
105 |
< |
prim -> dir [0] = -ray -> rdir [0]; |
106 |
< |
prim -> dir [1] = -ray -> rdir [1]; |
107 |
< |
prim -> dir [2] = -ray -> rdir [2]; |
105 |
> |
dvec [0] = -ray -> rdir [0]; |
106 |
> |
dvec [1] = -ray -> rdir [1]; |
107 |
> |
dvec [2] = -ray -> rdir [2]; |
108 |
> |
prim -> dir = encodedir(dvec); |
109 |
|
|
110 |
< |
VCOPY(prim -> org, ray -> rorg); |
110 |
> |
VCOPY(prim -> pos, ray -> rop); |
111 |
|
|
112 |
|
return prim; |
113 |
|
} |
231 |
|
nearestNeighbours(pmap, pos, norm, node << 1); |
232 |
|
} |
233 |
|
|
234 |
< |
/* Reject photon if normal faces away (ignored for volume photons) */ |
235 |
< |
if (norm && DOT(norm, p -> norm) <= 0) |
234 |
> |
/* Reject photon if normal faces away (ignored for volume photons) with |
235 |
> |
* 50% tolerance to account for perturbation; note photon normal is coded |
236 |
> |
* in range [-127,127]. */ |
237 |
> |
if (norm && DOT(norm, p -> norm) <= 63.5 * frandom()) |
238 |
|
return; |
239 |
|
|
240 |
|
if (isContribPmap(pmap) && pmap -> srcContrib) { |
245 |
|
if (srcIdx < 0 || srcIdx >= nsources) |
246 |
|
error(INTERNAL, "invalid light source index in photon map"); |
247 |
|
|
248 |
< |
srcMod = objptr(source [srcIdx].so -> omod); |
248 |
> |
srcMod = findmaterial(source [srcIdx].so); |
249 |
|
|
250 |
|
/* Reject photon if contributions from light source which emitted it |
251 |
|
* are not sought */ |
316 |
|
/* Threshold below which we assume increasing max radius won't help */ |
317 |
|
#define PMAP_SHORT_LOOKUP_THRESH 1 |
318 |
|
|
319 |
+ |
/* Coefficient for adaptive maximum search radius */ |
320 |
+ |
#define PMAP_MAXDIST_COEFF 100 |
321 |
+ |
|
322 |
+ |
|
323 |
|
void findPhotons (PhotonMap* pmap, const RAY* ray) |
324 |
|
{ |
325 |
|
float pos [3], norm [3]; |
341 |
|
pmap -> minError = FHUGE; |
342 |
|
pmap -> maxError = -FHUGE; |
343 |
|
pmap -> rmsError = 0; |
344 |
< |
#ifdef PMAP_MAXDIST_ABS |
345 |
< |
/* Treat maxDistCoeff as an *absolute* and *fixed* max search radius. |
335 |
< |
Primarily intended for debugging; FOR ZE ECKSPURTZ ONLY! */ |
336 |
< |
pmap -> maxDist0 = pmap -> maxDistLimit = maxDistCoeff; |
337 |
< |
#else |
338 |
< |
/* Maximum search radius limit based on avg photon distance to |
339 |
< |
* centre of gravity */ |
344 |
> |
/* SQUARED max search radius limit is based on avg photon distance to |
345 |
> |
* centre of gravity, unless fixed by user (maxDistFix > 0) */ |
346 |
|
pmap -> maxDist0 = pmap -> maxDistLimit = |
347 |
< |
maxDistCoeff * pmap -> squeueSize * pmap -> CoGdist / |
348 |
< |
pmap -> heapSize; |
349 |
< |
#endif |
347 |
> |
maxDistFix > 0 ? maxDistFix * maxDistFix |
348 |
> |
: PMAP_MAXDIST_COEFF * pmap -> squeueSize * |
349 |
> |
pmap -> CoGdist / pmap -> heapSize; |
350 |
|
} |
351 |
|
|
352 |
|
do { |
366 |
|
nearestNeighbours(pmap, pos, norm, 1); |
367 |
|
} |
368 |
|
|
369 |
< |
#ifndef PMAP_MAXDIST_ABS |
369 |
> |
#ifdef PMAP_ITSYBITSY |
370 |
> |
if (pmap -> maxDist < FTINY) { |
371 |
> |
sprintf(errmsg, "itsy bitsy teeny weeny photon search radius %e", |
372 |
> |
sqrt(pmap -> maxDist)); |
373 |
> |
error(WARNING, errmsg); |
374 |
> |
} |
375 |
> |
#endif |
376 |
> |
|
377 |
|
if (pmap -> squeueEnd < pmap -> squeueSize * pmap -> gatherTolerance) { |
378 |
|
/* Short lookup; too few photons found */ |
379 |
|
if (pmap -> squeueEnd > PMAP_SHORT_LOOKUP_THRESH) { |
381 |
|
* PMAP_SHORT_LOOKUP_THRESH photons under the assumption there |
382 |
|
* really are no photons in the vicinity, and increasing the max |
383 |
|
* search radius therefore won't help */ |
384 |
< |
#ifdef PMAP_LOOKUP_WARN |
384 |
> |
#ifdef PMAP_LOOKUP_WARN |
385 |
|
sprintf(errmsg, |
386 |
|
"%d/%d %s photons found at (%.2f,%.2f,%.2f) on %s", |
387 |
|
pmap -> squeueEnd, pmap -> squeueSize, |
388 |
|
pmapName [pmap -> type], pos [0], pos [1], pos [2], |
389 |
|
ray -> ro ? ray -> ro -> oname : "<null>"); |
390 |
|
error(WARNING, errmsg); |
391 |
< |
#endif |
391 |
> |
#endif |
392 |
|
|
393 |
+ |
/* Bail out after warning if maxDist is fixed */ |
394 |
+ |
if (maxDistFix > 0) |
395 |
+ |
return; |
396 |
+ |
|
397 |
|
if (pmap -> maxDist0 < pmap -> maxDistLimit) { |
398 |
|
/* Increase max search radius if below limit & redo search */ |
399 |
|
pmap -> maxDist0 *= PMAP_MAXDIST_INC; |
400 |
< |
#ifdef PMAP_LOOKUP_REDO |
400 |
> |
#ifdef PMAP_LOOKUP_REDO |
401 |
|
redo = 1; |
402 |
< |
#endif |
403 |
< |
|
387 |
< |
#ifdef PMAP_LOOKUP_WARN |
402 |
> |
#endif |
403 |
> |
#ifdef PMAP_LOOKUP_WARN |
404 |
|
sprintf(errmsg, |
405 |
|
redo ? "restarting photon lookup with max radius %.1e" |
406 |
|
: "max photon lookup radius adjusted to %.1e", |
407 |
< |
pmap -> maxDist0); |
407 |
> |
sqrt(pmap -> maxDist0)); |
408 |
|
error(WARNING, errmsg); |
409 |
< |
#endif |
409 |
> |
#endif |
410 |
|
} |
411 |
< |
#ifdef PMAP_LOOKUP_REDO |
411 |
> |
#ifdef PMAP_LOOKUP_REDO |
412 |
|
else { |
413 |
|
sprintf(errmsg, "max photon lookup radius clamped to %.1e", |
414 |
< |
pmap -> maxDist0); |
414 |
> |
sqrt(pmap -> maxDist0)); |
415 |
|
error(WARNING, errmsg); |
416 |
|
} |
417 |
< |
#endif |
417 |
> |
#endif |
418 |
|
} |
419 |
|
|
420 |
|
/* Reset successful lookup counter */ |
421 |
|
pmap -> numLookups = 0; |
422 |
|
} |
423 |
|
else { |
424 |
+ |
/* Bail out after warning if maxDist is fixed */ |
425 |
+ |
if (maxDistFix > 0) |
426 |
+ |
return; |
427 |
+ |
|
428 |
|
/* Increment successful lookup counter and reduce max search radius if |
429 |
|
* wraparound */ |
430 |
|
pmap -> numLookups = (pmap -> numLookups + 1) % PMAP_MAXDIST_CNT; |
433 |
|
|
434 |
|
redo = 0; |
435 |
|
} |
436 |
< |
#endif |
436 |
> |
|
437 |
|
} while (redo); |
438 |
|
} |
439 |
|
|
473 |
|
dv [2] = pos [2] - p -> pos [2]; |
474 |
|
d2 = DOT(dv, dv); |
475 |
|
|
476 |
< |
if (d2 < pmap -> maxDist && DOT(norm, p -> norm) > 0) { |
477 |
< |
/* Closest photon so far with similar normal */ |
476 |
> |
if (d2 < pmap -> maxDist && DOT(norm, p -> norm) > 63.5 * frandom()) { |
477 |
> |
/* Closest photon so far with similar normal. We allow a 50% tolerance |
478 |
> |
* to account for perturbation in the latter; note the photon normal |
479 |
> |
* is coded in the range [-127,127]. */ |
480 |
|
pmap -> maxDist = d2; |
481 |
|
*photon = p; |
482 |
|
} |