Recently we have ported all the parts of our shading pipeline to OpenGL ES 3. The last piece of the puzzle was a decent implementation of omnidirectional shadow maps. We used a Virtual Shadow Depth Cube Texture (VSDCT) described in ShaderX3.
Here is a simple code snipped I wrote to convert cube map vec3 into a virtual texture vec2:
vec2 GetShadowTC( vec3 Dir )
{
float Sc;
float Tc;
float Ma;
float FaceIndex;
float rx = Dir.x;
float ry = Dir.y;
float rz = Dir.z;
vec3 adir = abs(Dir);
Ma = max( max( adir.x, adir.y ), adir.z );
if ( adir.x > adir.y && adir.x > adir.z )
{
Sc = ( rx > 0.0 ) ? rz : -rz;
Tc = ry;
FaceIndex = ( rx > 0.0 ) ? 0.0 : 1.0;
}
else if ( adir.y > adir.x && adir.y > adir.z )
{
Sc = rx;
Tc = ( ry > 0.0 ) ? rz : -rz;
FaceIndex = ( ry > 0.0 ) ? 2.0 : 3.0;
}
else
{
Sc = ( rz > 0.0 ) ? -rx : rx;
Tc = ry;
FaceIndex = ( rz > 0.0 ) ? 4.0 : 5.0;
}
float s = 0.5 * ( Sc / Ma + 1.0 );
float t = 0.5 * ( Tc / Ma + 1.0 );
s = s / 3.0;
t = t / 2.0;
float Flr = floor(FaceIndex / 3.0);
float Rmd = FaceIndex - (3.0 * Flr);
s += Rmd / 3.0;
t += Flr / 2.0;
return vec2( s, t );
}
The distance from the light source is packed into a 8-bit RGBA texture using this trick. Everything else is pretty straightforward.
Android demo (requires OpenGL ES 3).
