Realtime Cubemap Placement

Realtime Cubemap Placement

When using screen space global illumination, alpha blended surface become a problem because you can’t defer the ray evaluation. Doing the SS casts in a forward pass isn’t an option because of the high performance need and inability of temporal smoothing.

Therefore, we implemented a system that collects stochastic queries of all currently rendered objects. The queries are triggered at a random point inside the bounding volume of the object. We then merge those “points of interest”, to get a linearly decreasing density if you are far away from the viewer.

The cubemaps are then updated once the viewer does not move anymore. We do not update cubemaps outside the frustum and prefer the nearest ones.


Alpha Rendering

We pick the nearest two cubemaps per alpha blended object and calculate the influence in the vertex shader as follows:

float DistNear = length(PositionWS-nearest_pos);
float DistSecond = length(PositionWS-second_pos);
blendVal=DistNear / (DistNear + DistSecond + epsilon);

Deferred rendering

For opaque objects, we render the cubemaps in a deferred pass into a RGB16F specular and a RGBA16F diffuse texture. We use blending to simple add the intensity values.

The cubemap radius is dependant of the mentioned density to get an average overlap of 1.5 cubemaps. We use a weighting of 1 from the center to half of the radius and smoothstep to zero from the half of the radius to the sphere’s boundary. The diffuse alpha channel stores the cubemap intensity. In the compositing process we do the following to normalize the overlapping cubemaps and add the skybox where we miss information:

vec4 CubeMapDiff = texture ( tIBL_cubeDiff, TexCoord);
float normalizationFactor = 1.0;
float skyBoxInfluence = 0.0;
if(CubeMapDiff.w > 1.0)
normalizationFactor /= CubeMapDiff.w;
else skyBoxInfluence = pow(1.0 - CubeMapDiff.w, 3.0);
vec3 cubemapInfluence = normalizationFactor* + skyBoxInfluence*diffuseCubeLookup(skybox, normalWS);

We then simply use Krzysztof Narkowicz’s Analytic DFG term for the final compositing step.

Influence clamping

Unfortunately, we introduce some light bleeding for the blended cubemaps.

No clamping
Clamping enabled

We clamp the cubemap influence based on the angle from the center to the surface, as done in a classic lambert term.

blendValue *= max(dot(ViewMatrixInv*normalize(deltaToCenter), -surfaceNormalWS), 0.0);
ibl_diff = vec4(diffusePart * blendValue, blendValue);
ibl_spec = specCubeLookup(cubeMap, reflect(ViewMatrixInv*PosSS, surfaceNormalWS), roughness) * blendValue;
IBL disabled
IBL enabled, no clamping
IBL enabled with clamping

Leave a Reply

Your email address will not be published. Required fields are marked *