Game Development Reference
In-Depth Information
for ( int i=0; i<nBodies; i+=64)
{
int il = lIdx + i;
if ( il < nBodies )
{
if (overlaps(frustum, gLightGeometry[il]))
{
appendLightToList(il);
}
}
}
In overlaps() , a light-geometry overlap is checked against a frustum using the
separating axis theorem [Ericson 04]. If a light is overlapping the frustum, the
light index is stored to the list of the overlapping lights in appendLightToList() .
There are several data structures we can use to store the light list. The obvious
way would be to build a linked list using a few atomic operations [Yang et al. 10].
However, this approach is relatively expensive: we need to use a few global
atomic operations to insert a light, and a global memory write is necessary when-
ever an overlapping light is found. Therefore, we took another approach in which
a memory write is performed in two steps. A tile is computed by a thread group,
and so we can use shared memory for the first level storage. Light index storage
and counter for the storage is allocated as follows:
groupshared u32 ldsLightIdx[LIGHT_CAPACITY];
groupshared u32 ldsLightIdxCounter;
In our implementation, we set LIGHT_CAPACITY to 256. The appendLightToList()
is implemented as follows:
void appendLightToList( int i)
{
u32 dstIdx = 0;
InterlockedAdd( ldsLightIdxCounter, 1, dstIdx );
if ( dstIdx < LIGHT_CAPACITY )
ldsLightIdx[dstIdx] = i;
}
With this implementation, no global memory write is necessary until all the lights
are tested.
After testing all the lights against a frustum, indices of lights overlapping that
frustum are collected in the shared memory. The last step of the kernel is to write
these to the global memory.
For the storage of light indices in the global memory, we allocated two buffers:
gLightIdx , which is a memory pool for the indices, and gLightIdxCounter ,which
 
Search Nedrilad ::




Custom Search