2
\$\begingroup\$

So I have implemented PSSM which currently does not care about the objects in the scene, meaning alot of resolution is wasted on empty space. This image shows the bottom two splits wasting alot of precision:

enter image description here

Here's how I construct the view/proj matrix:

Mat4 DX11DirectionalLightPass::CreateDirLightVPMatrix(const CameraFrustrum& cameraFrustrum, const Vec3& lightDir)
    {
        Mat4 lightViewMatrix = glm::lookAt(Vec3(0.0f), glm::normalize(lightDir), Vec3(0.0f, 1.0f, 0.0f));

        Vec4 transf = lightViewMatrix * cameraFrustrum[0];
        float maxZ = transf.z, minZ = transf.z;
        float maxX = transf.x, minX = transf.x;
        float maxY = transf.y, minY = transf.y;
        for (uint32_t i = 1; i < 8; i++)
        {
            transf = lightViewMatrix * cameraFrustrum[i];

            if (transf.z > maxZ) maxZ = transf.z;
            if (transf.z < minZ) minZ = transf.z;
            if (transf.x > maxX) maxX = transf.x;
            if (transf.x < minX) minX = transf.x;
            if (transf.y > maxY) maxY = transf.y;
            if (transf.y < minY) minY = transf.y;
        }

        Mat4 orthoMat = OrthographicMatrix(-1, 1, 1, -1, -maxZ, -minZ);

        const float scaleX = 2.0f / (maxX - minX);
        const float scaleY = 2.0f / (maxY - minY);
        const float offsetX = -0.5f * (minX + maxX) * scaleX;
        const float offsetY = -0.5f * (minY + maxY) * scaleY;

        Mat4 cropMat(1.0f);
        cropMat[0][0] = scaleX;
        cropMat[1][2] = scaleY;
        cropMat[3][0] = offsetX;
        cropMat[3][3] = offsetY;

        return cropMat * orthoMat * lightViewMatrix;
    }

It does not take the scene geometry into account. I read the nvidia PSSM article, and it suggested taking the smallest of either the frustrums AABB or the geometries combined AABB - here's the result:

enter image description here

  Mat4 DX11DirectionalLightPass::CreateDirLightVPMatrix(const CameraFrustrum& cameraFrustrum, const RenderableMeshes& meshes, const Vec3& lightDir)
    {
        Mat4 lightViewMatrix = glm::lookAt(Vec3(0.0f), glm::normalize(lightDir), Vec3(0.0f, 1.0f, 0.0f));

        // frustrum aabb
        Vec4 transf = lightViewMatrix * cameraFrustrum[0];
        float maxZ = transf.z, minZ = transf.z;
        float maxX = transf.x, minX = transf.x;
        float maxY = transf.y, minY = transf.y;
        for (uint32_t i = 1; i < 8; i++)
        {
            transf = lightViewMatrix * cameraFrustrum[i];

            if (transf.z > maxZ) maxZ = transf.z;
            if (transf.z < minZ) minZ = transf.z;
            if (transf.x > maxX) maxX = transf.x;
            if (transf.x < minX) minX = transf.x;
            if (transf.y > maxY) maxY = transf.y;
            if (transf.y < minY) minY = transf.y;
        }

        // min/max corners of the AABB of all the objects in the frustrum
        Vec3 modelMin = minAABB(meshes, cameraFrustrum, lightViewMatrix);
        Vec3 modelMax = maxAABB(meshes, cameraFrustrum, lightViewMatrix);

        // take the smallest of frustrum AABB and all models AABB
        if (modelMin.x > minX) minX = modelMin.x;
        if (modelMax.x < maxX) maxX = modelMax.x;
        if (modelMin.y > minY) minY = modelMin.y;
        if (modelMax.y < maxY) maxY = modelMax.y;
        if (modelMin.z > minZ) minZ = modelMin.z;
        if (modelMax.z < maxZ) maxZ = modelMax.z;

        Mat4 orthoMat = OrthographicMatrix(-1, 1, 1, -1, -maxZ, -minZ);

        const float scaleX = 2.0f / (maxX - minX);
        const float scaleY = 2.0f / (maxY - minY);
        const float offsetX = -0.5f * (minX + maxX) * scaleX;
        const float offsetY = -0.5f * (minY + maxY) * scaleY;

        Mat4 cropMat(1.0f);
        cropMat[0][0] = scaleX;
        cropMat[1][5] = scaleY;
        cropMat[3][0] = offsetX;
        cropMat[3][6] = offsetY;

        return cropMat * orthoMat * lightViewMatrix;
    }

It is much tighter, but I think it clips too much of the geometry in the corners.

I kinda imagine it looks like this (beware my paint skills):

enter image description here

As you can see in the code, the idea is to transform the splits frustrum into lights space, and then offset it and all objects inside it of the center, and taking the smallest of the frustrum AABB and all geometries AABBs in the offset/scale (crop) matrix to make it as tight as possible and save resolution.

But as you see, some parts of geometry ends up not visible at all.. how do I deal with this?

\$\endgroup\$
  • \$\begingroup\$ Is there anything unclear that should be added to the post? \$\endgroup\$ – KaiserJohaan Apr 8 '15 at 15:26
  • \$\begingroup\$ I have not dealt with DirectX in YEARS... So this is only an observation. In your 1st image you have 4 different views. In the 2nd you only have 2 different views; the last 3 are exactly the same. This tells me you are probably making an error when calculating the scale and the offset. Just an observation that could be very wrong. \$\endgroup\$ – Anthony Nichols Apr 10 '15 at 19:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.