View/Projection Matrices for Cascaded Shadow Mapping

Started by
9 comments, last by Seabolt 8 years, 3 months ago

Hey,

I'm trying to implement Cascaded Shadow Mapping. Currently I have a problem creating the correct View and Projection Matrices for the light camera. I proceed as follows:

Let 0.1 be the near plane and 8.0f the far plane for the first cascade. Then I compute the following:


float fovRadians = 70.0 * ( M_PI / 180.0);
float viewRatio = 16.0 / 9.0;
float nearHeight = 2.0 * tan(fovRadians / 2.0) * 8.0;
float nearWidth = nearHeight * viewRatio;

// Compute the 8 corner point of the bounding box around the view frustum from the near plane to the plane at depth 8.0f in world space.

frontLeftBottom = (cam->getCamPos() + cam->getViewVector() * 0.1f - cam->getRightVector() * 0.5f * nearWidth - cam->getUpVector() * 0.5f * nearHeight);
frontLeftTop = (cam->getCamPos() + cam->getViewVector() * 0.1f - cam->getRightVector() * 0.5f * nearWidth + cam->getUpVector() * 0.5f * nearHeight);
frontRightBottom = (cam->getCamPos() + cam->getViewVector() * 0.1f + cam->getRightVector() * 0.5f * nearWidth - cam->getUpVector() * 0.5f * nearHeight);
frontRightTop = (cam->getCamPos() + cam->getViewVector() * 0.1f + cam->getRightVector() * 0.5f * nearWidth + cam->getUpVector() * 0.5f * nearHeight);
backLeftBottom = (cam->getCamPos() + cam->getViewVector() * 8.0f - cam->getRightVector() * 0.5f * nearWidth - cam->getUpVector() * 0.5f * nearHeight);
backLeftTop = (cam->getCamPos() + cam->getViewVector() * 8.0f - cam->getRightVector() * 0.5f * nearWidth + cam->getUpVector() * 0.5f * nearHeight);
backRightBottom = (cam->getCamPos() + cam->getViewVector() * 8.0f + cam->getRightVector() * 0.5f * nearWidth - cam->getUpVector() * 0.5f * nearHeight);
backRightTop = (cam->getCamPos() + cam->getViewVector() * 8.0f + cam->getRightVector() * 0.5f * nearWidth + cam->getUpVector() * 0.5f * nearHeight);


// Compute the center of that box
centroid = (frontLeftBottom + frontLeftTop + frontRightBottom + frontRightTop + backLeftBottom + backLeftTop + backRightBottom + backRightTop) * 1.0f/8.0f;


right = glm::cross(glm::vec3(0,-1.0,-1.0),glm::vec3(0,1,0));
up = glm::cross(glm::vec3(0,-1.0,-1.0),right);
// This is the view matrix for the light and the first shadow cascade ( (0,-1.0,-1.0) is the direction of the light )
V = glm::lookAt(centroid,centroid + glm::vec3(0,-1.0,-1.0), up);


How do I now compute an orthographic projection matrix for the light space (directional light)? Ignore, that there may be shadow casters that are far away, I want an orthographic projection, that projects exactly the bounding box that I have computed above in world space. How exactly do I get my projection matrix from that 8 world space positions?

Thank you very much.

Xardes

Advertisement

You seem to love the English language. "Top", "Bottom". Sometimes I like it. With x,y you never know, if it's centre, or top or bottom. But if you get that out of the way in the first two lines, you could use indices for the rest and you code would fit into the pre container.

Thanks for the hint. Is it really that.. distracting, that it doesn't perfectly fit?

So, to create an orthographic projection for directional light I can use glm::ortho(left, right, bottom, top, near, far).

What I need to do, if I understand that correctly, is to transform my bounding box of the view frustum from world space to lightspace. So my Lightviewmatrix transforms the vertices, such that the centroid of my boundingbox is at (0,0,0) and the lightdirection (0,-1,-1) equals (0,0,-1) right? So I would need to transform my bounding box in the same way, such that it is in light space and use these values for glm::ortho?

Any help is greatly appreciated.

Xardes

I got a little further with my shadow mapping, but its not perfect yet.

Since I provided a Video last time and people could help me faster, I just try that again:

(From the perspective of a second camera. You see the world space around the actual camera.)

I proceed as follows:

1. Compute the 8 Corners of the frustrum (yellow in Video) of the camera.

2. Compute the 8 corners of the smallest bounding box around that frustrum.

3. Compute the center of that bounding box. (sum of all corners divided by 8)

4. Compute the Light view Matrix (V = glm::lookAt(center, center + lightDirection, lightUpVector))

5. Transform all 8 corners into light space (Multiply with V from 4.)

6. Compute the min/max X and Y values over all 8 transformed corners.

7. Choose the min/max values for z large enough, that all shadow casting objects are included, where ever the frustrum is.

8. Compute the Projection Matrix P = glm::ortho(xMin,xMax,yMin,yMax,zMin,zMax)

9. Use V and P for shadow mapping as usual.

You can see the result in the video. The problem is, that depending on the horizontal angle of the camera a lot of shadow map resolution is wasted, because the shadow map does not "rotate with the camera". How do I achieve that?

Thanks in advance for any help. o/

Xardes


You can see the result in the video. The problem is, that depending on the horizontal angle of the camera a lot of shadow map resolution is wasted, because the shadow map does not "rotate with the camera". How do I achieve that?
I haven't implemented anything close to CSM but I've read (from Crytek's presentations IIRC) that rotating shadowmaps arent actually a good thing. By rotating the shadowmaps you create instability when sampling from frame to frame, which introduces shimmering. They got around that by simply not rotating the shadowmaps, wasted resolution yes but they get stable results.

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

I haven't implemented anything close to CSM but I've read (from Crytek's presentations IIRC) that rotating shadowmaps arent actually a good thing. By rotating the shadowmaps you create instability when sampling from frame to frame, which introduces shimmering. They got around that by simply not rotating the shadowmaps, wasted resolution yes but they get stable results.

I've also read the slides from Crytek "Playing with real time shadows" (not sure, if there is a paper or more except that). Yes, they do say, that rotating shadow maps introduces "shimmering" as a temporal artifact, however there are no visuals for that. I would like to evaluate for myself, if that is actually visible in my scenario. I doubt, that this is visible, for sufficiently high resolution and sampling rate of the shadow maps.

I'm not sure what you mean by not rotating with the horizontal angle, the light's frustum should only try to bind to the view frustum. If you're wasting space, you should be reducing your clipping planes, binding either on a ground plane or a maximum height. This is the seminal tutorial for cascaded shadow maps, and their solution is the generate an AABB of the scene and then bind to that.

Also the shimmering artifact is real and is a huge distraction, but can be solved by not moving the light frustum by more than one shadow map texel.

Perception is when one imagination clashes with another

Thanks for the help so far.

What I want to achieve, is what Crytek calls "View space aligned shadow frustrum alignment" (http://www.crytek.com/download/Playing%20with%20Real-Time%20Shadows.pdf).

Basically, I want, that for 8 given points in world space, that form a cube (or box) of arbitrary size, position and orientation and an arbitrary light direction, I want to know, how to choose light view and projection matrix, such that I get a "View space aligned" shadow frustrum.

Thanks again,

Xardes

Ah I see...

It looks like they are making arbitrary splits based on the view frustums forward axis, fitting to those bounding boxes, and then rendering with an imperfect light frustum? That is interesting, if not artifact prone...

Perception is when one imagination clashes with another

Yes, that may introduce artifacts. At least that "shadow edge shimmering". But other techniques introduce artifacts as well and I still want to try this and see for myself, how it looks. However I am really stuck figuring out, which Matrices they use as view and projection matrix..

This topic is closed to new replies.

Advertisement