This is the documentation for Enlighten.

Per pixel probe lighting


Per pixel probe lighting provides the highest possible effective indirect lighting resolution in areas close to the viewer, but automatically reduces the effective resolution in distant areas.

The technique uses a 3D virtual texture, implemented with an indirection clipmap texture which indexes into an atlas of tiles.

This technique provides accurate lighting across very large meshes. The runtime cost increases only with the number of probes updated, regardless of the number of objects that are lit by probes.

We recommend to use per pixel probe lighting in most cases.

To use per pixel probe lighting:

  • The High Level Runtime must be configured to enable the Entire Probe Set Solver. 
  • Automatic probe placement must be used.
  • L1 SH probe output must be used.
  • floating point probe output must be used.

Use the High Level Runtime update manager to update the virtual texture with the results of the radiosity computation. To render indirect lighting, sample the probe SH coefficients from the virtual texture and evaluate SH lighting in the direction of the pixel normal.

Initial setup

Use PppiConfiguration to configure the 3D virtual texture. To get started quickly, use the default constructor for reasonable defaults. When constructing the High level runtime update manager, assign your configuration to UpdateManagerProperties::m_PppiConfiguration.

	Enlighten::UpdateManagerProperties properties;
	properties.m_UseEntireProbeSetSolver = true;
	properties.m_PppiConfiguration = Enlighten::PppiConfiguration();

Call GetPppiRequiredOutputTextures with the same configuration to find the size and format of the required output textures. 

	Enlighten::PppiOutputTextureRequirements requirements = GetPppiRequiredOutputTextures(properties.m_PppiConfiguration);

Create rendering resources of the required size and format for each of the output textures.

The update manager does not take ownership of these textures, and the caller must ensure that their lifetime is the same as the update manager. 

We recommend to use textures in shared GPU memory, with linear untiled layout, on platforms which allow this. Enlighten can write directly to these textures on the CPU. If this option is not available, allocate a separate buffer large enough to hold a copy of the texture data.

Fill UpdateManagerProperties::m_PppiOutputWorkspace with the layout of the output textures in memory.

If your output textures cannot be written directly on the CPU, when each texture is updated, you must flush the modified part of this buffer to the GPU using your preferred graphics API. Provide an implementation of IPppiTextureUpdateHandler that does this when the output textures are written. 

Each time you call IUpdateManager::AllocateProbeSetIUpdateManager::EnqueueRemoveProbeSet or IUpdateManager::Update, the virtual texture is updated and output texture update notifications are produced. Because many notifications might be generated in a single frame, we recommend to batch multiple updates to minimize the number of graphics API calls required.

class PppiTextureUpdateHandler : public Enlighten::IPppiTextureUpdateHandler
{
	void UpdateAtlas(const Enlighten::VolumeTextureRegion& region)
	{
		// mark the specified regions of the atlas texture to be copied from CPU to GPU
	}

	void UpdateIndirection(const Enlighten::IndirectionTextureRegions& regions)
	{
		// mark the specified regions of the atlas texture to be copied from CPU to GPU
	}
};

Each frame

Before drawing meshes, call IUpdateManager::Update. Specify the view origin to obtain full resolution indirect lighting close to the viewer.

As an optional optimization, limit the LOD distance to trade lighting accuracy for faster updates. 

If you call IUpdateManager::Update for different views on alternating frames, you may incur some unnecessarily expensive indirection texture updates.

If both views are very similar, provide the average view origin to IUpdateManager::Update. If the views are very different, create one instance of the update manager for each view.

Render indirect lighting

To sample the virtual texture in a pixel shader, use the output textures and the shader parameters returned by IUpdateManager::Update with the SamplePppiVirtualTexture function in GeoRuntime/Resources/PppiCommon.cg.

Excerpt: PppiCommon.cg
struct PppiSample
{
	float4 R;
	float4 G;
	float4 B;
	float InverseValidity;
	float EnvironmentVisibility;
};

PppiSample SamplePppiVirtualTexture(float3 worldPosition, float3 viewOrigin)
{
	...
}

The worldPosition argument is the world space position of the pixel. The viewOrigin argument is the position of the camera, used to determine the level of detail.

PppiSample R, G and B contain the L1 SH coefficients for each colour channel. Use this to evaluate SH lighting in the direction of the pixel normal.

In areas close to invalid (culled) probes, the lighting result is darkened. To compensate for this, multiply the lighting result by InverseValidity.