The Reason
In the previous text, we mentioned several times "sampling from Radiance Cache":
- During the setup of the Screen Probe, when calculating the Light PDF, we mentioned that when there is no history information, we will fallback to sampling from Radiance Cache Screen Probe Placement and Importance Sampling - What should I do if there is no historical information?
- When Trace Voxel, we mentioned that if both Screen Space and Mesh SDF Trace are ineffective, we will fallback to Voxel sampling, and information will also be obtained from Radiance Cache at this time.
- Although it is not the case in our Cube example, information will also be sampled from Radiance Cache when calculating indirect lighting for transparent objects.
So, what is Radiance Cache and why did Lumen choose this mechanism?
In the official introduction, Radiance Cache is divided into two parts: Screen Space and World. They have different resolutions and layouts, but both follow the same mechanism: they will reside in the graphics memory for a long time and slowly update over time.
You can think of them as Probes described multiple times before in the text, except that these Probes are no longer temporary and are persistent. Additionally, these Probes are also placed in world space.
Number
Actually, we have two parallel World Radiance Cache sets.
- One set is used for tracing opaque objects.
- The other set is specifically for transparent objects.
Clipmap
As the figure shows, World Radiance Cache is also divided into multiple Clip Maps. The Cache at farther distances is more sparse.
The figure shows two levels of Radiance Cache in our Cube case study. Pay attention to the Probe in the distance.
Data Structure
The basic construction method of Radiance Cache is:
- 1 3D Texture used for querying, acting as a jump table
- 1 actual Atlas Texture
Placement
In the official PPT, we can see this arrow.
The meaning of this arrow is that the World Radiance Cache is not simply uniformly distributed in space, but rather based on the Screen Space Radiance Cache, generating World Radiance Cache probes near surfaces with Screen Space Radiance Probes.
This can efficiently utilize limited World Radiance Cache resources.
Because we are reusing the World Radiance Cache from the previous frame, it is necessary to:
- Mark which Probes from the previous frame are no longer valid
- Mark which Probes are new
This is achieved through two passes, as shown in the following flowchart.
After this, the Probes need to be organized into a priority histogram to facilitate filtering out the set that needs updating.
Update
As the updating process of Radiance Cache is lengthy and the tracing process is the same as the Voxel Trace part described earlier, we will skip the same parts and only briefly introduce it here.
Timing
The timing for updating the Radiance Cache is after the Compute BRDF PDF and before the Compute Lighting PDF.
This is because the Compute Lighting PDF requires the results of the Radiance Cache.
Priority
Since the number of Probes in Radiance Cache is still high, it is impossible to update them all within one frame. Therefore, the Probes are marked per frame, and their priority is calculated. Then, a set of Probes to be updated is selected from the priority list, in order to stabilize the load of each frame.
This idea has already been explained in the Card Update section of the previous text, so it will not be repeated here.
Trace
The Trace mentioned here is actually consistent with the VoxelTrace mentioned earlier, and both ultimately call the RayTraceGlobalDistanceField function to implement it. Therefore, it will not be repeated here.
Query
You can refer to the code for visualizing Probes:
- Convert from world space coordinates to Probe coordinates in a specific Clipmap:
uint3 ProbeCoord = GetRadianceProbeCoord(ProbeWorldCenter, ClipmapIndex)
- Convert from Probe coordinates to Probe Index: query Indirect Texture:
uint ProbeIndex = GetProbeIndexFromIndirectionTexture(ProbeCoord, ProbeClipmapIndex);
- Retrieve Radiance for a specific direction based on Probe Index:
float3 Lighting = SampleIrradianceCacheProbe(ProbeIndex, SphereNormal) * Albedo;