Page MenuHomec4science

pmapfilt.c
No OneTemporary

File Metadata

Created
Wed, Nov 6, 22:36

pmapfilt.c

/*
======================================================================
Photon map filter callbacks for nearest neighbour search
Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
(c) Lucerne University of Applied Sciences and Arts,
supported by the Swiss National Science Foundation
(SNSF #147053, "Daylight Redirecting Components",
SNSF #179067, "Light Fields for Spatio-Temporal Glare Assessment")
(c) Tokyo University of Science,
supported by the JSPS Grants-in-Aid for Scientific Research
(KAKENHI JP19KK0115, "Three-Dimensional Light Flow")
======================================================================
$Id: pmapfilt.c,v 1.2 2020/11/16 22:28:23 u-no-hoo Exp u-no-hoo $
*/
#include "pmapfilt.h"
#include "pmapdata.h"
#include "pmap.h"
#include "random.h"
#include "source.h"
#include "otspecial.h"
int filterPhoton (const void *rec, const void *state)
/* Filter callback for photon kNN search */
{
const Photon *photon = rec;
const PhotonSearchFilterState *filtState = state;
const PhotonMap *pmap = filtState -> pmap;
/* Reject photon if normal faces away (ignored for volume photons) with
* tolerance to account for perturbation; note photon normal is coded
* in range [-127,127], hence we factor this in */
if (filtState -> norm &&
DOT(filtState->norm, photon->norm) <= PMAP_NORM_TOL * 127 * frandom()
)
return 0;
#ifdef PMAP_PHOTONFLOW
if (isLightFlowPmap(pmap) && hemiLightFlow && !sphericalIrrad) {
/* Hemispherical lookup mode; omit lightflow photons which pass normal
test above but lie behind the plane. This reduces bias near solid
boundaries (scene cube limits or actual geometry), in which case no
photons may be present behind the plane.
NOTE: filtstate->norm is REVERSED in this mode since photon->norm
(=photon direction here) points TOWARDS the receiving surface! */
FVECT photonVec;
VSUB(photonVec, photon -> pos, filtState -> pos);
if (DOT(filtState -> norm, photonVec) > FTINY)
return 0;
}
#endif
if (isContribPmap(pmap)) {
/* Lookup in contribution photon map; accept photon only if its
emitting light source modifier matches that of the filter state
(if defined). */
if (filtState -> srcMod) {
const int srcIdx = photonSrcIdx(pmap, photon);
if (srcIdx < 0 || srcIdx >= nsources)
error(INTERNAL, "invalid light source index in photon map");
if (filtState -> srcMod != findmaterial(source [srcIdx].so))
return 0;
}
/* Reject non-caustic photon if lookup for caustic contribs */
if (pmap -> lookupCaustic && !photon -> caustic)
return 0;
}
/* Accept photon */
return 1;
}
#ifdef PMAP_PATHFILT
/* Length of key strings for photon path LUT (plus terminator) */
#define PMAP_PATHKEYLEN ((sizeof(PhotonOrigin) + 1 << 1) + 1)
void initPhotonPaths (void *state)
/* Lazily allocate and initialise photon path ID lookup table and
* associate key buffer */
{
PhotonMap *pmap = state;
if (!pmap -> pathLUT) {
/* Allocate and init photon path ID lookup table of same size as
* search queue */
LUTAB initLUT = LU_SINIT(NULL, NULL);
if (!(pmap -> pathLUT = malloc(sizeof(LUTAB))))
error(SYSTEM, "failed photon path lookup table allocation");
memcpy(pmap -> pathLUT, &initLUT, sizeof(initLUT));
if (!lu_init(pmap -> pathLUT, pmap -> squeue.len))
error(INTERNAL, "failed photon path lookup table init");
}
if (!pmap -> pathLUTKeys) {
/* Allocate key buffer of same size as search queue (+1 for
* scratchpad at tail) */
unsigned k, maxKeys = pmap -> squeue.len + 1;
pmap -> pathLUTKeys = (char**)calloc(maxKeys, sizeof(char*));
for (k = 0; k < maxKeys; k++)
if ( pmap -> pathLUTKeys ||
!(pmap -> pathLUTKeys [k] = (char*)malloc(PMAP_PATHKEYLEN))
)
error(SYSTEM, "failed photon path LUT key buffer allocation");
}
/* Reset photon path ID key buffer */
pmap -> numPathLUTKeys = 0;
}
static char *photonPathKey (const Photon *photon, char *key)
{
/* Generate LUT key from photon path ID. Writes transposed hex string
into specified key buffer. */
PhotonOrigin pathId1 = photon -> org;
unsigned char pathId2 = photon -> proc;
char *kp = key;
unsigned i;
for (i = sizeof(PhotonOrigin) << 1;
i;
*kp++ = (pathId1 & 0x0f) + 'A', pathId1 >>= 4, i--
);
for (i = sizeof(unsigned char) << 1;
i;
*kp++ = (pathId2 & 0x0f) + 'A', pathId2 >>= 4, i--
);
*kp++ = '\0';
return key;
}
int checkPhotonPaths (const void *state)
/* Run sanity check on photon path ID lookup table */
{
const PhotonMap *pmap = state;
const PhotonSearchQueue *squeue = &pmap -> squeue;
const PhotonSearchQueueNode *squeueNode;
const Photon *photon;
const LUENT *lutEntry;
unsigned squeueIdx;
char key [PMAP_PATHKEYLEN];
if (!pmap -> pathLUT || !pmap -> pathLUTKeys)
error(INTERNAL, "photon path lookup table not initialised");
for (squeueIdx = 0, squeueNode = squeue -> node;
squeueIdx < squeue -> tail;
squeueIdx++, squeueNode++
) {
photon = getNearestPhoton(squeue, squeueNode -> idx);
photonPathKey(photon, key);
lutEntry = lu_find(pmap -> pathLUT, key);
if (!lutEntry || !lutEntry -> key || strcmp(lutEntry -> key, key))
error(CONSISTENCY, "invalid key in photon path LUT check");
if (!lutEntry -> data ||
(PhotonSearchQueueNode*)lutEntry -> data != squeueNode
)
error(CONSISTENCY, "invalid data in photon path LUT check");
}
return 0;
}
/* TODO: REPLACE pathLUTKeys SCRATCHPAD WITH LOCAL ARRAYS??? */
void **findPhotonPath (const void *rec, const void *state)
/* Photon path callback for k-NN search to map photon path IDs to search
* queue nodes via a lookup table. State points to the associated photon
* map containing the path lookup table. Returns modifiable pointer to data
* field of found LUT entry, which in turn points to the search queue node
* for the corresponding record. If no entry exists for the path ID, NULL
* is returned. */
{
const Photon *photon = rec;
const PhotonMap *pmap = state;
char *key;
LUENT *lutEntry;
if (!pmap -> pathLUT || !pmap -> pathLUTKeys)
error(INTERNAL, "photon path lookup table not initialised");
/* Generate key for photon's path and write into next free slot in key
buffer (using it as scratchpad) */
key = photonPathKey(photon,
pmap -> pathLUTKeys [pmap -> numPathLUTKeys]
);
#ifdef PMAP_DEBUGPATHS
printf("%s ", key);
#endif
/* Look up attribute for generated key, set last LUT entry in state */
if (!(lutEntry = lu_find(pmap -> pathLUT, key)))
/* Outta mammaries */
error(SYSTEM, "failed photon path lookup entry allocation");
return (void**)(lutEntry -> data ? &lutEntry -> data : NULL);
}
void addPhotonPath (const void *rec, void *data, void *state)
/* Photon path callback for k-NN search to add photon path IDs to lookup
table entries. State points to the associated photon map containing the
path lookup table. The new lookup table entry is initialised with the
specified data pointer */
{
const Photon *photon = rec;
PhotonMap *pmap = state;
char *key;
LUENT *lutEntry;
if (!pmap -> pathLUT || !pmap -> pathLUTKeys)
error(INTERNAL, "photon path lookup table not initialised");
/* Generate key for photon's path and write into next free slot in key
buffer */
key = photonPathKey(photon,
pmap -> pathLUTKeys [pmap -> numPathLUTKeys]
);
/* Find free LUT entry for generated key */
if (!(lutEntry = lu_find(pmap -> pathLUT, key)))
/* Outta mammaries */
error(SYSTEM, "failed photon path lookup entry allocation");
if (lutEntry -> data)
/* Occupied */
error(INTERNAL, "attempt to overwrite photon path lookup entry");
#ifdef PMAP_DEBUGPATHS
printf("%s add\n", key);
#endif
/* Set data and key fields, advance key buffer tail */
lutEntry -> data = data;
lutEntry -> key = pmap -> pathLUTKeys [pmap -> numPathLUTKeys];
if (pmap -> numPathLUTKeys > pmap -> squeue.tail)
/* Number of keys (and distinct path IDs) can never exceed the number
of photons currently in the search queue (+1 for scratchpad) */
error(INTERNAL, "photon path lookup table key overflow");
else
pmap -> numPathLUTKeys++;
}
static char emptyKey = '\0';
void deletePhotonPath (const void *rec, void *state)
/* Photon path callback for k-NN search to delete photon path IDs from
lookup table. State points to the associated photon map containing the
path ID lookup table. */
{
const Photon *photon = rec;
PhotonMap *pmap = state;
LUENT *lutEntry;
char *delKey, *relocKey;
if (!pmap -> pathLUT || !pmap -> pathLUTKeys)
error(INTERNAL, "photon path lookup table not initialised");
/* Generate key for photon's path and write into scratchpad at key buffer
tail (will be overwritten) */
delKey = photonPathKey(photon,
pmap -> pathLUTKeys [pmap -> numPathLUTKeys]
);
#ifdef PMAP_DEBUGPATHS
printf("%s del\n", delKey);
#endif
/* Find photon's LUT entry, check if valid, and get its key buffer slot */
lutEntry = lu_find(pmap -> pathLUT, delKey);
if (!lutEntry || !lutEntry -> key || !lutEntry -> data)
error(CONSISTENCY, "attempt to delete empty photon path LUT entry");
/* Delete photon LUT entry */
lu_delete(pmap -> pathLUT, delKey);
delKey = lutEntry -> key;
lutEntry -> key = &emptyKey; /* ??? */
/* Decrement key buffer tail and get last valid key */
relocKey = pmap -> pathLUTKeys [--pmap -> numPathLUTKeys];
if (delKey != relocKey) {
/* Reclaim deleted photon's key buffer slot by overwriting with last
valid key */
memcpy(delKey, relocKey, PMAP_PATHKEYLEN);
relocKey = delKey;
#ifdef PMAP_DEBUGPATHS
printf("%s reloc\n", relocKey);
#endif
/* Update the LUT entry owning the relocated key to point to its new
position in the overwritten slot, again checking for validity */
lutEntry = lu_find(pmap -> pathLUT, relocKey);
if (!lutEntry || !lutEntry -> key || !lutEntry -> data)
error(CONSISTENCY,
"attempt to delete empty photon path LUT entry"
);
lutEntry -> key = relocKey;
}
}
int clearPhotonPath (const LUENT *lutEntry, void *lut)
/* Clear entry in photon path ID lookup table */
{
#ifdef PMAP_DEBUGPATHS
printf("%s clr\n", lutEntry -> key);
#endif
lu_delete(lut, lutEntry -> key);
/* Apologies to Don Gregorio for abusing his LUT here... */
((LUENT*)lutEntry) -> key = &emptyKey;
return 0;
}
void resetPhotonPaths (void *state)
/* Reset (clear) all entries in photon path ID lookup table */
{
PhotonMap *pmap = state;
if (!pmap -> pathLUT)
error(INTERNAL, "photon path lookup table not initialised");
lu_doall(pmap -> pathLUT, clearPhotonPath, pmap -> pathLUT);
/* Reset photon path ID key buffer */
pmap -> numPathLUTKeys = 0;
}
#endif /* PMAP_PATHFILT */

Event Timeline