This is the documentation for Enlighten.

Probe interpolation

Overview

Once the Enlighten probe solver has been run to compute lighting values for the precomputed probe positions, the next step is typically to interpolate the results between the fixed probe positions to produce a final result for the actual locations of dynamic objects in the scene.

The Enlighten SDK contains functions for performing this interpolation, defined in EnlightenInterpolation.h. The SDK interpolation functions for regular grids and octrees of probes can use additional visibility information generated during the precompute to improve the results of the interpolation.

The data requirements for probes are as follows:

  • If you want to run the probe solver, you must load the m_ProbeSetPrecomp block.
  • If you want to do probe interpolation, and the probe set is an octree, you must load the m_InterpolationData block.
  • If you want to do probe interpolation, and the probe set isn't an octree, then you need only load m_InterpolationData if you haven't loaded m_ProbeSetPrecomp (that is, you don't want to run solves).
  • If you want the probe interpolation to use the precomputed visibility information for a regular grid or octree, you must load the m_VisibilityData block.

If the probe set is an unstructured grid, you must supply with it an array of positions. There is no precomputed visibility information for unstructured sets, so interpolation will only take distance into account.

Probe set offsets

For large worlds it is desirable to do the precompute of individual scene sections around the origin (either because of precision in the precompute or precision in the renderer). When then combining two sections that are both precomputed around the origin, it is not possible to do proper probe interpolation between those sections because there is no offset input especially for regular grids.

In the low-level API, you can use the Transform function of Enlighten::InterpolationInputSet to specify offsets for probe sets in this scenario. In the High Level Runtime, you can use EnqueueSetProbeSetTransform

Probe interpolation example

This simple example computes interpolated output for a single location, from a single input probe set.

// Array of probe interpolants. In the first step of the interpolation, these are computed from the probe position. This stage is potentially expensive,
// and unnecessary to repeat if the object hasn't moved. If the m_RecomputeInterpolants flag is set to false then this object will assume its array of
// interpolants was computed in a previous run of the interpolation task and is still valid; this first stage will be skipped.
ProbeInterpolant probeInterpolants[16];
 
// Array of output arrays to receive the final output of the interpolation. These values will always be recomputed from the current lighting values of
// the static probes, even if the first stage of interpolation was skipped.
float redOutput[SH_ORDER_L1];
float greenOutput[SH_ORDER_L1];
float blueOutput[SH_ORDER_L1];
float envVisOutput[SH_ORDER_L1];          // Relies on the envVisShNumCoefficients probe set precompute parameter having been set to a suitable value,
                                          // since for environment visibility we interpolate between precomputed values.
 
// Structure describing a point to compute interpolated output for.
InterpolatedPoint interpolatedPoint;
interpolatedPoint.m_Position = worldPosition;
interpolatedPoint.m_Interpolants  probeInterpolants;
interpolatedPoint.m_OutputFormat = PROBE_OUTPUT_FORMAT_FP32;
interpolatedPoint.m_MaxNumInterpolants = 16;
interpolatedPoint.m_NumInterpolants = 0;
interpolatedPoint.m_ShOrder = SH_ORDER_L1;
interpolatedPoint.m_EnvVisShOrder = SH_ORDER_L1;      // Need not be the same as the order for R, G and B. May be 0.
interpolatedPoint.m_RecomputeInterpolants = true;
interpolatedPoint.m_Output[OUTPUT_R] = redOutput;
interpolatedPoint.m_Output[OUTPUT_G] = greenOutput;
interpolatedPoint.m_Output[OUTPUT_B] = blueOutput;
interpolatedPoint.m_Output[OUTPUT_ENV_VIS] = envVisOutput;
 
// Structure describing a static probe set to use as the source from which to interpolate lighting results
InterpolationInputSet interpolationInputSet;
interpolationInputSet.m_ProbeSetCore = coreData;
interpolationInputSet.m_ProbePositionArray = NULL;    // not required for a regular grid or voxel octree
interpolationInputSet.m_OutputFloat = probeLightingResults;
interpolationInputSet.m_OutputShOrder = Enlighten::SH_ORDER_L1; // set this to the SH order used when solving the probe set
 
// Structure describing the probe interpolation task
ProbeInterpolationTask probeInterpolationTask;
probeInterpolationTask.m_InterpolationInputs = &interpolationInputSet;
probeInterpolationTask.m_NumInterpolationInputs = 1;
probeInterpolationTask.m_InterpolatedPointArray = &interpolatedPoint;
probeInterpolationTask.m_ArrayLength = 1;
probeInterpolationTask.m_RecomputeAllInterpolants = false;    // set this to true if the list of input probe sets has changed
 
Geo::u32 timeInMicroseconds;
DoProbeInterpolationTask(&probeInterpolationTask, timeInMicroseconds);
 
// redOutput, greenOutput, blueOutput and envVisOutput will now contain the SH results, which for instance can be uploaded as shader constants for rendering