Page MenuHomec4science

pmapooc.c
No OneTemporary

File Metadata

Created
Sat, Apr 20, 08:26

pmapooc.c

/*
======================================================================
Photon map interface to out-of-core octree
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)
======================================================================
$Id: pmapooc.c,v 1.6 2020/04/08 15:14:21 rschregle Exp $
*/
#include "pmapdata.h" /* Includes pmapooc.h */
#include "source.h"
#include "otspecial.h"
#include "oocsort.h"
#include "oocbuild.h"
/* Returns photon position as sorting key for OOC_Octree & friends (notably
* for Morton code generation).
* !!! Uses type conversion from float via TEMPORARY storage;
* !!! THIS IS NOT THREAD SAFE!
* !!! RETURNED KEY PERSISTS ONLY IF COPIED BEFORE NEXT CALL! */
RREAL *OOC_PhotonKey (const void *p)
{
static FVECT photonPos; /* Temp storage for type conversion */
VCOPY(photonPos, ((Photon*)p) -> pos);
return photonPos;
}
#ifdef DEBUG_OOC
static int OOC_CheckKeys (FILE *file, const OOC_Octree *oct)
{
Photon p, lastp;
RREAL *key;
OOC_MortonIdx zIdx, lastzIdx = 0;
rewind(file);
memset(&lastp, 0, sizeof(lastp));
while (fread(&p, sizeof(p), 1, file) > 0) {
key = OOC_PhotonKey(&p);
zIdx = OOC_KEY2MORTON(key, oct);
if (zIdx < lastzIdx) {
error(INTERNAL, "photons not sorted");
return -1;
}
if (zIdx == lastzIdx) {
sprintf(errmsg, "identical key %021ld "
"for [%.9f, %.9f, %.9f]\tand [%.9f, %.9f, %.9f]",
zIdx, lastp.pos [0], lastp.pos [1], lastp.pos [2],
p.pos [0], p.pos [1], p.pos [2]);
error(WARNING, errmsg);
}
lastzIdx = zIdx;
memcpy(&lastp, &p, sizeof(p));
}
return 0;
}
#endif
void OOC_BuildPhotonMap (struct PhotonMap *pmap, unsigned numProc)
{
FILE *leafFile;
char leafFname [1024];
FVECT d, octOrg;
int i;
RREAL octSize = 0;
/* Determine octree size and origin from pmap extent and init octree */
VCOPY(octOrg, pmap -> minPos);
VSUB(d, pmap -> maxPos, pmap -> minPos);
for (i = 0; i < 3; i++)
if (octSize < d [i])
octSize = d [i];
if (octSize < FTINY)
error(INTERNAL, "zero octree size in OOC_BuildPhotonMap");
/* Derive leaf filename from photon map and open file */
strncpy(leafFname, pmap -> fileName, sizeof(leafFname));
strncat(leafFname, PMAP_OOC_LEAFSUFFIX,
sizeof(leafFname) - strlen(leafFname) - 1);
if (!(leafFile = fopen(leafFname, "w+b")))
error(SYSTEM, "failed to open leaf file in OOC_BuildPhotonMap");
#ifdef DEBUG_OOC
eputs("Sorting photons by Morton code...\n");
#endif
/* Sort photons in heapfile by Morton code and write to leaf file */
if (OOC_Sort(pmap -> heap, leafFile, PMAP_OOC_NUMBLK, PMAP_OOC_BLKSIZE,
numProc, sizeof(Photon), octOrg, octSize, OOC_PhotonKey))
error(INTERNAL, "failed out-of-core photon sort in OOC_BuildPhotonMap");
/* Init and build octree */
OOC_Init(&pmap -> store, sizeof(Photon), octOrg, octSize, OOC_PhotonKey,
leafFile);
#ifdef DEBUG_OOC
eputs("Checking leaf file consistency...\n");
OOC_CheckKeys(leafFile, &pmap -> store);
eputs("Building out-of-core octree...\n");
#endif
if (!OOC_Build(&pmap -> store, PMAP_OOC_LEAFMAX, PMAP_OOC_MAXDEPTH))
error(INTERNAL, "failed out-of-core octree build in OOC_BuildPhotonMap");
#ifdef DEBUG_OOC
eputs("Checking out-of-core octree consistency...\n");
if (OOC_Check(&pmap -> store, OOC_ROOT(&pmap -> store),
octOrg, octSize, 0))
error(INTERNAL, "inconsistent out-of-core octree; Time4Harakiri");
#endif
}
int OOC_SavePhotons (const struct PhotonMap *pmap, FILE *out)
{
return OOC_SaveOctree(&pmap -> store, out);
}
int OOC_LoadPhotons (struct PhotonMap *pmap, FILE *nodeFile)
{
FILE *leafFile;
char leafFname [1024];
/* Derive leaf filename from photon map and open file */
strncpy(leafFname, pmap -> fileName, sizeof(leafFname));
strncat(leafFname, PMAP_OOC_LEAFSUFFIX,
sizeof(leafFname) - strlen(leafFname) - 1);
if (!(leafFile = fopen(leafFname, "r")))
error(SYSTEM, "failed to open leaf file in OOC_LoadPhotons");
if (OOC_LoadOctree(&pmap -> store, nodeFile, OOC_PhotonKey, leafFile))
return -1;
return 0;
}
void OOC_InitFindPhotons (struct PhotonMap *pmap)
{
if (OOC_InitNearest(&pmap -> squeue, pmap -> maxGather + 1,
sizeof(Photon)))
error(SYSTEM, "can't allocate photon search queue");
}
static void OOC_InitPhotonCache (struct PhotonMap *pmap)
/* Initialise OOC photon cache */
{
static char warn = 1;
if (!pmap -> store.cache && !pmap -> numDensity) {
if (pmapCacheSize > 0) {
const unsigned pageSize = pmapCachePageSize * pmap -> maxGather,
numPages = pmapCacheSize / pageSize;
/* Allocate & init I/O cache in octree */
pmap -> store.cache = malloc(sizeof(OOC_Cache));
if (!pmap -> store.cache ||
OOC_CacheInit(pmap -> store.cache, numPages, pageSize,
sizeof(Photon))) {
error(SYSTEM, "failed OOC photon map cache init");
}
}
else if (warn) {
error(WARNING, "OOC photon map cache DISABLED");
warn = 0;
}
}
}
typedef struct {
const PhotonMap *pmap;
const float *norm;
} OOC_FilterData;
int OOC_FilterPhoton (void *p, void *fd)
/* Filter callback for photon kNN search, used by OOC_FindNearest() */
{
const Photon *photon = p;
const OOC_FilterData *filtData = fd;
const PhotonMap *pmap = filtData -> 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 (filtData -> norm &&
DOT(filtData->norm, photon->norm) <= PMAP_NORM_TOL * 127 * frandom())
return 0;
if (isContribPmap(pmap)) {
/* Lookup in contribution photon map; filter according to emitting
* light source if contrib list set, else accept all */
if (pmap -> srcContrib) {
OBJREC *srcMod;
const int srcIdx = photonSrcIdx(pmap, photon);
if (srcIdx < 0 || srcIdx >= nsources)
error(INTERNAL, "invalid light source index in photon map");
srcMod = findmaterial(source [srcIdx].so);
/* Reject photon if contributions from light source which emitted
* it are not sought */
if (!lu_find(pmap -> srcContrib, srcMod -> oname) -> data)
return 0;
}
/* Reject non-caustic photon if lookup for caustic contribs */
if (pmap -> lookupCaustic && !photon -> caustic)
return 0;
}
/* Accept photon */
return 1;
}
int OOC_FindPhotons (struct PhotonMap *pmap, const FVECT pos, const FVECT norm)
{
OOC_SearchFilter filt;
OOC_FilterData filtData;
float n [3];
/* Lazily init OOC cache */
if (!pmap -> store.cache)
OOC_InitPhotonCache(pmap);
/* Set up filter callback */
filtData.pmap = pmap;
if (norm)
VCOPY(n, norm);
filtData.norm = norm ? n : NULL;
filt.data = &filtData;
filt.func = OOC_FilterPhoton;
pmap -> maxDist2 = OOC_FindNearest(&pmap -> store,
OOC_ROOT(&pmap -> store), 0,
pmap -> store.org, pmap -> store.size,
pos, &filt, &pmap -> squeue,
pmap -> maxDist2);
if (pmap -> maxDist2 < 0)
error(INTERNAL, "failed k-NN photon lookup in OOC_FindPhotons");
/* Return success or failure (empty queue => none found) */
return pmap -> squeue.tail ? 0 : -1;
}
int OOC_Find1Photon (struct PhotonMap* pmap, const FVECT pos,
const FVECT norm, Photon *photon)
{
OOC_SearchFilter filt;
OOC_FilterData filtData;
float n [3], maxDist2;
/* Lazily init OOC cache */
if (!pmap -> store.cache)
OOC_InitPhotonCache(pmap);
/* Set up filter callback */
filtData.pmap = pmap;
if (norm)
VCOPY(n, norm);
filtData.norm = norm ? n : NULL;
filt.data = &filtData;
filt.func = OOC_FilterPhoton;
maxDist2 = OOC_Find1Nearest(&pmap -> store,
OOC_ROOT(&pmap -> store), 0,
pmap -> store.org, pmap -> store.size,
pos, &filt, photon, pmap -> maxDist2);
if (maxDist2 < 0)
error(INTERNAL, "failed 1-NN photon lookup in OOC_Find1Photon");
if (maxDist2 >= pmap -> maxDist2)
/* No photon found => failed */
return -1;
else {
/* Set photon distance => success */
pmap -> maxDist2 = maxDist2;
return 0;
}
}
int OOC_GetPhoton (struct PhotonMap *pmap, PhotonIdx idx,
Photon *photon)
{
return OOC_GetData(&pmap -> store, idx, photon);
}
Photon *OOC_GetNearestPhoton (const PhotonSearchQueue *squeue, PhotonIdx idx)
{
return OOC_GetNearest(squeue, idx);
}
PhotonIdx OOC_FirstPhoton (const struct PhotonMap* pmap)
{
return 0;
}

Event Timeline