adrien bedel
adrien bedel

Reputation: 116

Shadow map doesn't work with world space transformation (OpenGL)

I'm trying to implement shadow maps into my 3D world I created with openGL. I want to be able to move around the map and the shadow to follow as I move, so I needed a light Projection matrix that take into account my world view frustrum.

        glm::mat4 lightProjectionMatrix = glm::ortho<float>(camera->_width * -0.5f, camera->_width * 0.5f,
                                                            camera->_height * -0.5f, camera->_height * 0.5f,
                                                            camera->_deep * -0.5f, camera->_deep * 0.5f);
        glm::mat4 lightViewMatrix = glm::lookAt(camera->_centroid, camera->_centroid + glm::vec3(-1, -1, 0) , glm::vec3(0, 1, 0));
        glm::mat4 lightModelMatrix = glm::mat4(1.0);
        glm::mat4 lightMvp = depthProjectionMatrix * depthViewMatrix * depthModelMatrix;

The width, height, deep and centroid variables are from a cuboid of the orthographic projection for the light. To have it I used my world camera frustrum corners, rotated them into light space to do my calculation. Once I got the centroid and dimension of the cuboid into light space I convert them back into world space.

And this is my world projection matrix

    _projection = glm::perspective(glm::radians(_fov), _screenRatio, _near, _far);
    _projection = glm::scale(_projection, glm::vec3(-1, 1, 1));
    _view = glm::lookAt(_cameraPos, _cameraPos + _dirLook, _cameraUp);
    _mvp = _projection * _view;

the scale is to have a left handed world axis.

Now that I have all that I should be able to have a shadow texture with the positions as follow :

    gl_Position = mvp * aPos;
    shadowCoord = lightMvp * gl_Position;

but, my shadow aren't appearing. So I printed out some test case to see whats wrong :

auto pos = glm::vec3(50, 50, 300);
        auto worldPos = _mvp * glm::vec4(pos, 1);
        auto Light = lightMvp * glm::vec4(pos, 1);
        auto worldLight = lightMvp * worldPos;
        auto worldViewLight = lightMvp * _view * glm::vec4(pos, 1);

        std::cout << "-----------" << std::endl;
        std::cout << "worldPos = " << worldPos.x << " " << worldPos.y << " " << worldPos.z << std::endl;
        std::cout << "Light = " << Light.x << " " << Light.y << " " << Light.z << std::endl;
        std::cout << "worldLight = " << worldLight.x << " " << worldLight.y << " " << worldLight.z << std::endl;
        std::cout << "worldViewLight = " << worldViewLight.x << " " << worldViewLight.y << " " << worldViewLight.z << std::endl;
worldPos = -194.856 -346.41 302.806
Light = 0.621941 0 0.177444
worldLight = 268.828 -0.0950791 67.447
worldViewLight = 1.15693 -0.250944 0.221805

And here are the results. when I multiply by light and world matrix I don't have values clamp between 0 and 1. And this is what I should have.

Note that my terrain is properly rendering and shadows appear when I don't multiply them by world space because they are clamp between 0 and 1.

So I don't understand why my world matrix breaks that.

Any ideas or advice?

Upvotes: 0

Views: 416

Answers (1)

Bram
Bram

Reputation: 8283

When you transform to your light-space, you used an already transformed position. Instead, you should use the original vertex location for both the cam and the light transformation:

gl_Position = mvp * aPos;
shadowCoord = lightMvp * aPos; // DO NOT USE gl_Position;

Further things to note:

  • The resulting coordinate will range from -1 (near plane) to +1 (far plane) and not 0..1 as you write.
  • The scaling by -1,1,1 looks suspect: if you do that, you go from right handed coord sys to a left handed coord sys. If you want your camera or light to point in the opposite direction, don't mirror one axis, but turn it 180 degrees.
  • In your first snippet, you intermingle depth and light prefixes. Copy N Paste error?
  • What are your NEAR and FAR values?

Upvotes: 1

Related Questions