SoftwareLightSplat.h file
Namespaces
- namespace Jazz2
- Root namespace of Jazz² Resurrection.
- namespace Jazz2::Rendering
- Scene rendering and viewport management.
- namespace Jazz2::Rendering::SoftwareLighting
Functions
- auto Distance(float d2) -> float
- Reciprocal square root estimate of the platform, where it has one worth using.
-
void SplatLight(float* lightmap,
std::
int32_t lmW, std:: int32_t lmH, float cx, float cy, float rLm, float radiusNearNorm, float intensity, float brightness) - Adds one light to a two-channel (intensity, brightness) float lightmap.
Function documentation
float Distance(float d2)
Reciprocal square root estimate of the platform, where it has one worth using.
The falloff needs one square root per texel of the lit annulus, and on the consoles without a pipelined one that is most of the splat: the Gekko/Broadway have no fsqrt at all, so std::sqrt is a software routine of a few hundred cycles, and the SH-4's fsqrt takes about 22 cycles and blocks the pipeline. Both do have a fast estimate of 1/sqrt(x) - frsqrte (the PowerPC architecture guarantees only 1 part in 32, so it is refined with two Newton steps, which lands within about 3e-6 from any estimate at least that good) and fsrra (accurate to the last bits on its own). The lightmap is quantized to 8 bits per channel before anything sees it, so a relative error of that size cannot change a single output value except at a quantization boundary.
Returns for a squared distance, as cheaply as the platform allows
void SplatLight(float* lightmap,
std:: int32_t lmW,
std:: int32_t lmH,
float cx,
float cy,
float rLm,
float radiusNearNorm,
float intensity,
float brightness)
Adds one light to a two-channel (intensity, brightness) float lightmap.
| Parameters | |
|---|---|
| lightmap | lmW * lmH texels of two floats each, row-major |
| lmW | Lightmap width in texels |
| lmH | Lightmap height in texels |
| cx | Light centre in lightmap texels |
| cy | Light centre in lightmap texels |
| rLm | Far radius in lightmap texels (at least 0.5) |
| radiusNearNorm | Near radius as a fraction of the far radius (may exceed 1: no falloff) |
| intensity | Added to the first channel of every texel the light reaches, scaled by the falloff |
| brightness | Added to the second channel the same way |
The falloff is the one in LightingFs.inc: strength is 1 out to the near radius and then ((1 - dist) / (1 - near))^3 to the far radius, in units of the far radius. Instead of visiting the whole bounding box and classifying every texel with two compares and a branch, each row is cut analytically into the texels inside the disc - |x - cx| <= sqrt(1 - dy^2) * rLm - and the flat core inside those - |x - cx| <= sqrt(near^2 - dy^2) * rLm. Texels outside the disc are never touched, core texels get two additions, and only the annulus pays for a square root. It is the same set of texels the per-texel tests select, up to floating-point rounding of a texel exactly on a boundary, where the strength is 0 or 1 to within ~1e-7 either way - except for a light with no falloff (near >= far), whose edge is a hard step and so lands one texel differently now and then; a host harness over 196 million texel values found no other difference above 1e-3. The annulus loops are branch-free so that the compiler can interleave several texels for the in-order cores this runs on; dx is recomputed from x rather than accumulated, so no iteration depends on the previous one.