Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F80293090
pmapooc.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Aug 30, 23:48
Size
10 KB
Mime Type
text/x-c
Expires
Sun, Sep 1, 23:48 (2 d)
Engine
blob
Format
Raw Data
Handle
20336830
Attached To
R10977 RADIANCE Photon Map
pmapooc.c
View Options
/*
======================================================================
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, "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: pmapooc.c,v 1.7 2021/03/22 23:00:00 rschregle Exp $
*/
#include "pmapdata.h"
/* Includes pmapooc.h */
#include "source.h"
#include "otspecial.h"
#include "oocsort.h"
#include "oocbuild.h"
#include "pmcontribsort.h"
/* PHOTON MAP BUILD ROUTINES ------------------------------------------ */
/* Returns photon position as sorting key for OOC_Octree & friends
* (notably for Morton code generation).
* !!! XXX: 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
void
OOC_CheckKeys
(
FILE
*
file
,
const
OOC_Octree
*
oct
)
{
Photon
p
,
lastp
;
RREAL
*
key
;
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"
);
if
(
zIdx
==
lastzIdx
)
{
sprintf
(
errmsg
,
"identical key %021ld "
"for [%.9f, %.9f, %.9f]
\t
and [%.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
));
}
}
#endif
void
OOC_BuildPhotonMap
(
struct
PhotonMap
*
pmap
,
unsigned
numProc
)
{
FILE
*
leafFile
;
char
*
leafFname
;
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 */
leafFname
=
malloc
(
strlen
(
pmap
->
fileName
)
+
strlen
(
PMAP_OOC_LEAFSUFFIX
)
+
1
);
if
(
!
leafFname
)
error
(
SYSTEM
,
"failed leaf filename alloc in OOC_BuildPhotonMap"
);
strcpy
(
leafFname
,
pmap
->
fileName
);
strcat
(
leafFname
,
PMAP_OOC_LEAFSUFFIX
);
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;
redirect to contrib sorting routine if contrib child pmap and
we have precomputed contributions, else we need a regular sort
before we can precompute */
if
(
isContribChildPmap
(
pmap
)
&&
pmap
->
preCompContrib
?
contribPhotonSort
(
pmap
,
leafFile
,
octOrg
,
octSize
,
PMAP_OOC_NUMBLK
,
PMAP_OOC_BLKSIZE
,
numProc
)
:
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
,
leafFname
);
#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
}
/* PHOTON MAP I/O ROUTINES ------------------------------------------ */
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
;
#ifdef DEBUG_OOC
/* Check octree for consistency */
if
(
OOC_Check
(
&
pmap
->
store
,
OOC_ROOT
(
&
pmap
->
store
),
pmap
->
store
.
org
,
pmap
->
store
.
size
,
0
))
return
-
1
;
#endif
return
0
;
}
/* PHOTON MAP SEARCH ROUTINES ------------------------------------------ */
void
OOC_InitFindPhotons
(
struct
PhotonMap
*
pmap
)
{
if
(
OOC_InitNearest
(
&
pmap
->
squeue
,
pmap
->
maxGather
+
1
,
sizeof
(
Photon
)
))
error
(
SYSTEM
,
"can't allocate photon search queue"
);
#ifdef PMAP_PATHFILT
initPhotonPaths
(
pmap
);
#endif
}
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
;
}
}
}
int
OOC_FindPhotons
(
struct
PhotonMap
*
pmap
,
const
FVECT
pos
,
const
FVECT
norm
)
{
OOC_SearchFilterCallback
filt
;
OOC_SearchFilterState
filtState
;
#ifdef PMAP_PATHFILT
OOC_SearchAttribCallback
paths
,
*
pathsPtr
=
NULL
;
#endif
float
res
,
n
[
3
];
/* Lazily init OOC cache */
if
(
!
pmap
->
store
.
cache
)
OOC_InitPhotonCache
(
pmap
);
/* Set up filter callback */
if
(
norm
)
VCOPY
(
n
,
norm
);
filtState
.
pmap
=
pmap
;
filtState
.
pos
=
pos
;
filtState
.
norm
=
norm
?
n
:
NULL
;
filt
.
state
=
&
filtState
;
filt
.
filtFunc
=
filterPhoton
;
/* Get sought light source modifier from pmap -> lastContribSrc if
precomputing contribution photon */
filtState
.
srcMod
=
isContribPmap
(
pmap
)
?
findmaterial
(
source
[
pmap
->
lastContribSrc
.
srcIdx
].
so
)
:
NULL
;
#ifdef PMAP_PATHFILT
/* Set up path ID callback to filter for photons from unique paths */
paths
.
state
=
pmap
;
paths
.
findFunc
=
findPhotonPath
;
paths
.
addFunc
=
addPhotonPath
;
paths
.
delFunc
=
deletePhotonPath
;
paths
.
checkFunc
=
checkPhotonPaths
;
pathsPtr
=
&
paths
;
resetPhotonPaths
(
pmap
);
res
=
OOC_FindNearest
(
&
pmap
->
store
,
OOC_ROOT
(
&
pmap
->
store
),
0
,
pmap
->
store
.
org
,
pmap
->
store
.
size
,
pos
,
&
filt
,
pathsPtr
,
&
pmap
->
squeue
,
pmap
->
maxDist2
);
#else
res
=
OOC_FindNearest
(
&
pmap
->
store
,
OOC_ROOT
(
&
pmap
->
store
),
0
,
pmap
->
store
.
org
,
pmap
->
store
.
size
,
pos
,
&
filt
,
NULL
,
&
pmap
->
squeue
,
pmap
->
maxDist2
);
#endif
/* PMAP_PATHFILT */
if
(
res
<
0
)
error
(
INTERNAL
,
"failed k-NN photon lookup in OOC_FindPhotons"
);
/* Get (maximum distance)^2 from search queue head */
pmap
->
maxDist2
=
pmap
->
squeue
.
node
[
0
].
dist2
;
/* 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_DataIdx
*
photonIdx
)
{
OOC_SearchFilterCallback
filt
;
OOC_SearchFilterState
filtState
;
float
n
[
3
],
maxDist2
;
/* Lazily init OOC cache */
if
(
!
pmap
->
store
.
cache
)
OOC_InitPhotonCache
(
pmap
);
/* Set up filter callback */
if
(
norm
)
VCOPY
(
n
,
norm
);
filtState
.
pmap
=
pmap
;
filtState
.
norm
=
norm
?
n
:
NULL
;
filtState
.
srcMod
=
NULL
;
filt
.
state
=
&
filtState
;
filt
.
filtFunc
=
filterPhoton
;
*
photonIdx
=
(
OOC_DataIdx
)(
-
1
);
maxDist2
=
OOC_Find1Nearest
(
&
pmap
->
store
,
OOC_ROOT
(
&
pmap
->
store
),
0
,
pmap
->
store
.
org
,
pmap
->
store
.
size
,
pos
,
&
filt
,
photon
,
photonIdx
,
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
;
}
}
/* PHOTON ACCESS ROUTINES ------------------------------------------ */
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
Log In to Comment