This is the documentation for Enlighten.

Low level cubemap API


Overview

The dynamic cubemap generation API follows the same pattern as the other task based systems in Enlighten, and as usual the application is in control of the update rate and shading use. 

The following sections give an overview of how the low level cubemap runtime API should be used.

Loading precomputed cube map data

A RadCubeMapCore object can be created at runtime using the Utilities API as described in Loading precomputed data.

Preparing a RadCubeMapTask structure

The cube map solver API is very similar to that of the Enlighten System solver. It expects to be passed a list of input lighting buffers, one for each System on which the cube map being solved depends, in the correct order. There is a version of the PrepareInputLightingList() and GetInputWorkspaceListLength() functions that take a RadCubeMapCore in order to prepare this list, as shown in the code sample below.

// create the task structure
Enlighten::RadCubeMapTask cubeMapTask;
cubeMapTask.m_CoreCubeMap = radCubeMapCore; // the precomputed RadCubeMapCore

// prepare the ordered list of input lighting buffers - one for each system on which the cube map depends
cubeMapTask.m_InputLighting = GEO_NEW_ARRAY(const Enlighten::InputLightingBuffer*, Enlighten::GetInputWorkspaceListLength(cubeMapTask.m_CoreCubeMap));
Enlighten::PrepareInputLightingList(cubeMapTask.m_CoreCubeMap, inputLightingBufferArray.GetArray(), inputLightingBufferArray.GetSize(), cubeMapTask.m_InputLighting);

cubeMapTask.m_Environment		= emissiveEnvironment;               // optional emissive environment
cubeMapTask.m_OutputFormat		= Enlighten::ENLIGHTEN_FORMAT_FP16;  // output values as 16-bit floating point vectors
cubeMapTask.m_OutputScale		= 1.0f;                              // no extra scaling on output
cubeMapTask.m_ComputeMipMaps	= true;                              // compute full mip chain

for (s32 faceIdx = 0; faceIdx < 6; ++faceIdx)
{
	cubeMapTask.m_OutputTextures[faceIdx] = cubeMapOutputs[faceIdx];
}

Note that the emissive environment InputLightingBuffer is optional. Environment clusters are not smoothed so for best quality results it is recommended that you set this to NULL and composite the Enlighten cubemap output with a high resolution environment texture, such as a skybox, on the GPU. This can be done using the alpha mask computed by the cubemap solver and stored in the alpha channel of the texture when using the Enlighten::ENLIGHTEN_FORMAT_FP16 output format. Other output formats use the alpha channel for HDR-encoding so do not include this mask.

If you are not using an Enlighten emissive environment with cubemaps, set the environmentResolution cubemap precompute parameter to its minimum value of 1 for optimal memory usage and performance.

Solving a cubemap

Once the RadCubeMapTask structure has been prepared it must be passed to SolveCubeMapTask() along with a block of working memory. Unnecessary solves can be avoided by checking if all of the input lighting is static by calling the AllInputLightingStatic() helper function.

Geo::u32 timeUs, Geo::u32 numPixelsSolved;

// allocate some working memory for the solve
void* workingMemory = GEO_ALIGNED_MALLOC(Enlighten::CalcRequiredWorkspaceMemory(cubeMapTask->m_RadCubeMapCore), 16);

// solve the cubemap unless all of the input lighting is static
if(false == Enlighten::AllLightingInputsStatic(cubeMapTask.m_InputLighting, Enlighten::GetInputWorkspaceListLength(cubeMapTask.m_CoreCubeMap), cubeMapTask.m_Environment))
{
	bool solvedOk = Enlighten::SolveCubeMapTask(&cubeMapTask, workingMemory, timeUs, numPixelsSolved);
}

Computing radiosity-only output

To compute output which contains indirect, radiosity-only lighting, the cubemap solver must read input lighting from a list of BounceBuffers instead of a list of InputLightingBuffers. To specify this type of output simply assign the m_RadiosityOnlyLighting member of the RadCubeMapTask structure to an ordered list of pointers to BounceBuffer objects, one for each Enlighten System on which the cubemap depends. These BounceBuffers contain the results of executing the bounce re-sampling stage for each system.

// prepare the ordered list of bounce buffers - one for each system on which the cubemap depends
s32 numCubeMapDependencies = Enlighten::GetInputWorkspaceListLength(cubeMapTask.m_CoreCubeMap);
cubeMapTask.m_RadiosityOnlyLighting = GEO_NEW_ARRAY(const BounceBuffer*, numCubeMapDependencies);

for (s32 i = 0; i < numCubeMapDependencies; ++i)
{
    GeoGuid systemDepGuid = Enlighten::GetInputWorkspaceGUID(existingCubeMap->m_RadCubeMapCore, i);
    cubeMapTask.m_RadiosityOnlyLighting[i] = GetBounceBufferForSystem(systemDepGuid);
}

// the environment does not receive any radiosity lighting so set its InputLightingBuffer to NULL
cubeMapTask.m_Environment = NULL;

// you may wish to disable solver mip map generation if this will be done in your engine after the radiosity-only output has been composited with high frequency albedo and direct lighting on the GPU
cubeMapTask.m_ComputeMipMaps = false;

// as before, check the list of system InputLightingBuffers for static lighting and solve as normal
if(false == Enlighten::AllLightingInputsStatic(cubeMapTask.m_InputLighting, Enlighten::GetInputWorkspaceListLength(cubeMapTask.m_CoreCubeMap), cubeMapTask.m_Environment))
{
	bool solvedOk = Enlighten::SolveCubeMapTask(&cubeMapTask, workingMemory, timeUs, numPixelsSolved);
}


See also: