Search code examples
openglglslshadershadowshadow-mapping

Are soft shadows possible with point light using cubemap (OpenGL/GLSL)?


I coded a 3D application managing spot light shadow mapping. To do this I use classical shadow mapping technique (I fill a depth texture in the first render pass and in the second render pass I compare the distance from light to the first occluder and the distance from the light to the vertex position to know if my fragment is in shadow or not).

Here's a screenshot (spot light/2D depth texture shadow mapping):

enter image description here

In this example I use PCF shadow mapping technique using the function 'textureProjOffset'. Here's a piece of code from my fragment shader:

Sampler used:

sampler2DShadow Shadow2DSampler[MAX_LIGHTS_COUNT];

For HARD shadows:

shadowFactor = textureProj(Shadow2DSampler[idx], ShadowCoords[idx]);

For PCF SOFT shadows:

for (int idy = offset; idy >= -offset; idy--)
                for (int idx = -offset; idx <= offset; idx++)
                    shadowFactor += textureProjOffset(
                        Shadow2DSampler[idz], ShadowCoords[idz], ivec2(idx, idy)); 

I have also managed the basic cubemap shadow mapping to manage omnidirectional shadow mapping currently applied for point lights. To do this in the first render pass I use a geometry shader to dispatch both the projection and view matrix provided by the 6 shadow frustrums (all in ONE pass! It's different of the technique concisting to fill 6 separate textures with this time 6 render states).

Here's a screenshot (spot light/Cube depth texture shadow mapping):

enter image description here

As you can see, it's only HARD shadow mapping. To recover the depth value encoded into the cubemap I have to use this time the function 'texture' (textureProj does not exists for 'samplerCube' and 'samplerCubeShadow'). Next I have to compute the distance between the light position and the vertex position in world space and then convert it into clip space because the depth value contained into the texture is already in clip space.

Here's a piece of code from the fragment shader to see the process:

Sampler used:

samplerCubeShadow ShadowCubeSampler[MAX_LIGHTS_COUNT];

For HARD shadows:

float ConvertDistToClipSpace(vec3 lightDir_ws)
{
    vec3 AbsVec = abs(lightDir_ws);
    float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z));

    float NormZComp = (NearFar.y + NearFar.x)/(NearFar.y - NearFar.x)
        - (2.0f * NearFar.y * NearFar.x)/(LocalZcomp * NearFar.y - NearFar.x);

    return ((NormZComp + 1) * 0.5f);
}

float GetBiased_Cube_Hard_ShadowFactor(vec3 vertexPosition_ws, int idx)
{
    vec3 lightToVertexDir_ws = vertexPosition_ws - LightPos_ws.xyz;
    float LightToVertexClipDist = ConvertDistToClipSpace(lightToVertexDir_ws);

    float LightToOccluderClipDist = texture(
        ShadowCubeSampler[idx], vec4(lightToVertexDir_ws, LightToVertexClipDist));

    if (LightToOccluderClipDist < LightToVertexClipDist)
        return (0.0f);
    return (1.0f);
}

And know, what about PCF SOFT shadows using cubemap ? I do some researches and apparently it does not exist any function to recover a texture offset like it's possible using simple 2D textures and using in the fragment shader the keyword 'sampler2DShadow'. Am I wrong ? (I hope so!).

I think I have a solution (of course if it does not exist any solution with cubemap):

Apparently, to recover a texture offset I will have to use 6 separate textures (so an array of 'sampler2DShadow' with a size of 6 and not a 'samplerCubeShadow'). So I will have equally as uniform an array of matrix4x4 respresenting the representation of the world in light space like I did for spot light shadow mapping in my first case. And then I will use for the 6 textures the method 'textureProjOffset'.

So, What do you think? Is it possible to do PCF soft shadows using cubemap or not? If it's not the case, is my solution correct ? Is it possible to use a function like 'textureProjOffset' using 'samplerCube' or 'samplerCubeShadow'? Or is there an alternative?

Thanks a lot in advance for your help!


Solution

  • The only way I know to achieve PCF soft shadows for cubemaps is to query the texture multiple times with small offset. This method is for example described in this GPU Gems article (12.4).