This is the documentation for Enlighten.

Material colour data


The albedo colour of a material describes the colour of light reflected by a surface with the material. The emissive colour of a material describes the colour and intensity of light emitted by an emissive surface with the material.

Only surfaces that are included in the radiosity computation can reflect or emit light.

Most materials have albedo colours that do not change while the game is running, which we call static albedo. When surfaces emit light that does not change while the game is running we call this static emissive. To minimize runtime cost, compute the static albedo and emissive colours in your editing tools, and store them as AlbedoBuffer and EmissiveBuffer objects along with the persistent radiosity data.

To provide colours for a surface within a radiosity system, you need:

You also need to extract some additional runtime data after the precompute.

For accurate lighting, use albedo and emissive colours that match the rendered materials. We recommend to compute this automatically by sampling the rendered material.

In some cases, a single uniform colour for the entire surface provides a good enough approximation. To ensure the most accurate and believable indirect lighting we recommend to generate and provide colours for a set of sample points on the surface of the rendered mesh. 

Instance ID

To compute material colours for a surface you need to know which engine mesh is associated with an instance ID. Use the instance GUID to easily identify the original engine mesh associated with an instance object.

To extract the instance ID and instance GUID for each instance object in a radiosity system, load the IPrecompInputSystem object.

// path: "precomp/[system name].is"
const Enlighten::IPrecompInputSystem* inputSystem
	= Geo::LoadInterfaceCompressed<Enlighten::IPrecompInputSystem>(path);

Call IPrecompInputSystem::GetInstanceArray to obtain information for each instance.

Each PrecompInputInstance object corresponds to an instance object within the system.

for(Geo::s32 i = 0; i != inputSystem->GetInstanceCount(); ++i)
{
	const Enlighten::PrecompInputInstance& inputInstance = inputSystem->GetInstanceArray()[i];
}

PrecompInputInstance::m_InstanceGuid contains the instance GUID and PrecompInputInstance::m_Id contains the corresponding instance ID.

By default, Enlighten automatically assigns an instance ID which is an index into an array with the same size as IPrecompInputSystem::GetInstanceCount. This makes it easy to store the instance GUIDs in an array indexed by instance ID.

Mesh index

If a single engine mesh produces more than one mesh object, use the index of the mesh object within the geometry object to identify the surface.

If you add only one mesh to each geometry object, the mesh index is always zero.

Material ID

Many editing tools allow the artist to set the colour of a mesh by assigning an engine material. To compute material colours for a surface, you need to know the engine material associated with the surface.

When an engine mesh is composed of more than one part that can each be assigned a different game engine material, add one material ID in the mesh object for each part.

If you add only one material to each mesh object, the material ID is always zero.

The example below shows psuedocode to create a mapping between a surface and the associated engine material, using the array of instance GUIDs indexed by instance ID.

for each instance ID
	find the engine instance associated with the instance GUID
	for each mesh within the engine instance
		for each material ID used in the mesh
			associate surface (instance ID, mesh index, material ID) with a reference to the assigned engine material

When engine material assignments are modified, it's easy to update this mapping.

It's not necessary to re-run the precompute when material colours or assignments are modified in your world editing tools.

Additional runtime data

To create the AlbedoBuffer or EmissiveBuffer objects, you need to extract some additional runtime data after the precompute.

Load the ClusterAlbedoWorkspaceMaterialData object for each radiosity system:

// path: "radiosity/[system name].caw"
const Enlighten::ClusterAlbedoWorkspaceMaterialData* materialData
	= ReadClusterAlbedoWorkspaceMaterialDataFromFile(path);


Call CreateDynamicMaterialWorkspace with the ClusterAlbedoWorkspaceMaterialData for the system.

Call CreateAlbedoBuffer with the InputWorkspace for the system.

You previously came across the InputWorkspace when you extracted the persistent radiosity data.

Extract this additional runtime data once after the precompute, and store it along with the persistent runtime data. Use this data to update albedo and emissive colours whenever they are modified in your world editing tools.

You need the DynamicMaterialWorkspace and ClusterAlbedoWorkspaceMaterialData only to create or update the AlbedoBuffer or EmissiveBuffer. If the buffers change only in the editing tools, but do not change at runtime, exclude these objects when you prepare the runtime data for the target platform.

Provide uniform colours

To provide uniform material colours for a surface, use the persistent runtime data and the instance ID, mesh index and material ID.

Obtain the uniform colours:

  • using your mapping between instance ID and engine mesh, or
  • using your mapping between surface and engine material.

Call MakeSingleSurfaceSelection to create a SurfaceSelection which identifies the surface.

Call SetMaterialAlbedoColour to set the colour for the SurfaceSelection.

Call SetMaterialAlbedoColour as many times as you need to provide colours for multiple surfaces.

Finally, call InitialiseAlbedoBufferFromMaterialWorkspace to commit the changes to the AlbedoBuffer.

Follow the same steps with the Emissive family of functions to provide emissive colours.

Sample point data

Information about the sample points is available after the precompute.

Load the IPrecompSystemDuster object to get the set of sample points for each radiosity system:

// path: "precomp/[system name].dust"
const Enlighten::IPrecompSystemDuster* materialData
	= Geo::LoadInterfaceCompressed<IPrecompSystemDuster>(path);

Within the IPrecompSystemDuster object, the following data is available for each sample point:

The face index refers to the mesh LOD that was included in the radiosity computation. 

From the IPrecompSystemDuster object, we recommend to extract and store only the information you need to compute sample colours.

Provide sample colours

Use the persistent runtime data along with the information you extracted for each sample to provide sample colours for each radiosity system

For the most accurate result, use your own renderer and materials to shade each of the sample points.

  1. For each instance in the system, construct a vertex buffer that contains one vertex for each sample point, interpolated from the original mesh vertices using the face index and barycentric coordinates.
  2. Create two output buffers, one for albedo and the other for emissive, which each contain a single colour for each sample point.
  3. For each instance in the system, draw the vertex buffer as a point list using your engine materials with a special pixel shader which outputs albedo and emissive colours to the output buffer.
  4. Read back the albedo and emissive output buffers to CPU accessible memory.
  5. Call InitialiseAlbedoBufferFromColoursPerPoint and InitialiseEmissiveBufferFromColoursPerPoint with the sampled albedo and emissive colours.