Tag Archives: linderdaum

Omnidirectional shadows and VSDCT on OpenGL ES 3

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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).