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); }