beyond-all-reason / spring

A powerful free cross-platform RTS game engine
https://beyond-all-reason.github.io/spring/
Other
220 stars 102 forks source link

Shadow quality gets progressively worse as camera zooms in #744

Open springraaar opened 1 year ago

springraaar commented 1 year ago

image

I got the above image using MF v2.10 on crucible v3.1 map. On my springsettings.cfg I have "ShadowMapSize = 4096" which should be pretty good (it is if i zoom out)

The mapinfo.lua has sunDir = {-0.3, 1.0, -0.5},

As the camera zooms in a user would expect to get a progressively sharper and more detailed image of objects, but the shadows get much worse instead.

lhog commented 1 year ago

Some semi-relevant code for my future reference:

float CShadowHandler::GetOrthoProjectedFrustumRadius(CCamera* cam, const CMatrix44f& lightMat, float3& projPos) {
    float3 frustumPoints[8];

    #if 0
    {
        float sqRadius = 0.0f;
        projPos = CalcShadowProjectionPos(cam, &frustumPoints[0]);

        // calculate radius of the minimally-bounding sphere around projected frustum
        for (unsigned int n = 0; n < 8; n++) {
            sqRadius = std::max(sqRadius, (frustumPoints[n] - projPos).SqLength());
        }

        const float maxMapDiameter = readMap->GetBoundingRadius() * 2.0f;
        const float frustumDiameter = std::sqrt(sqRadius) * 2.0f;

        return (std::min(maxMapDiameter, frustumDiameter));
    }
    #else
    {
        CMatrix44f centeredLightMap = lightMat;
        //centeredLightMap.SetPos(projPos = CalcShadowProjectionPos(cam, &frustumPoints[0]));

        const float rawRange = camera->GetFarPlaneDist() * 1.4f;
        const float badRange = rawRange - 300.0f;

        static constexpr float T1 = 100.0f;
        static constexpr float T2 = 200.0f;
        const std::initializer_list<float4> upperClipPlanes = {
            float4{  UpVector,  -(readMap->GetCurrMinHeight() - T1) },
            float4{  RgtVector,  (0                           + T2) },
            float4{  FwdVector,  (0                           + T2) },
            float4{ -UpVector,   (readMap->GetCurrMaxHeight() + T1) },
            float4{ -RgtVector,  (mapDims.mapx * SQUARE_SIZE  + T2) },
            float4{ -FwdVector,  (mapDims.mapy * SQUARE_SIZE  + T2) }
        };

        const std::array<int2, 4> winRelPos = {
            int2{0                         ,                          0},
            int2{globalRendering->viewSizeX,                          0},
            int2{0                         , globalRendering->viewSizeY},
            int2{globalRendering->viewSizeX, globalRendering->viewSizeY}
        };

        std::array<float3, 5> camPoints;

        const float3 camPos = camera->GetPos();

        camPoints[4] = camPos;
        projPos = camPos;
        for (int i = 0; i < 4; ++i) {
            const int wx = winRelPos[i].x + globalRendering->viewPosX;
            const int wy = globalRendering->viewSizeY - 1 - winRelPos[i].y;

            const float3 pxlDir = camera->CalcPixelDir(wx, wy);

            const CUnit* unit = nullptr;
            const CFeature* feature = nullptr;
            const float traceDist = TraceRay::GuiTraceRay(camPos, pxlDir, rawRange, nullptr, unit, feature, true, true, true);
            if ((traceDist < 0.0f || traceDist > badRange)) {
                camPoints[i] = camPos + (pxlDir * rawRange);
                if (!ClampRayInMap(camPos, camPoints[i])) {
                    //camPoints[i] = Clamp(camPoints[i], float3{ -T2, readMap->GetCurrMinHeight() - T1, -T2 }, { mapDims.mapx * SQUARE_SIZE + T2, readMap->GetCurrMaxHeight() + T1, mapDims.mapy * SQUARE_SIZE + T2 });
                    camPoints[i].x = Clamp(camPoints[i].x, -T2, mapDims.mapx * SQUARE_SIZE + T2);
                    camPoints[i].y = Clamp(camPoints[i].y, readMap->GetCurrMinHeight() - T1, readMap->GetCurrMaxHeight() + T1);
                    camPoints[i].z = Clamp(camPoints[i].z, -T2, mapDims.mapy * SQUARE_SIZE + T2);
                }
            }
            else {
                camPoints[i] = camPos + (pxlDir * traceDist);
            }

            projPos += camPoints[i];
        }
        projPos *= 0.2f;

        centeredLightMap.SetPos(projPos);

        float2 xbounds = { std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
        float2 zbounds = { std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };

        for (const auto& camPoint : camPoints) {
            float4 lvCamPoint = centeredLightMap * camPoint;

            xbounds.x = std::min(xbounds.x, lvCamPoint.x);
            xbounds.y = std::max(xbounds.y, lvCamPoint.x);
            zbounds.x = std::min(zbounds.x, lvCamPoint.z);
            zbounds.y = std::max(zbounds.y, lvCamPoint.z);
        }
        return (std::max(xbounds.y - xbounds.x, zbounds.y - zbounds.x));
        /*
        // find projected width along {x,z}-axes (.x := min, .y := max)
        float2 xbounds = {std::numeric_limits<float>::max(), -std::numeric_limits<float>::max()};
        float2 zbounds = {std::numeric_limits<float>::max(), -std::numeric_limits<float>::max()};

        for (unsigned int n = 0; n < 8; n++) {
            frustumPoints[n] = centeredLightMap * frustumPoints[n];

            xbounds.x = std::min(xbounds.x, frustumPoints[n].x);
            xbounds.y = std::max(xbounds.y, frustumPoints[n].x);
            zbounds.x = std::min(zbounds.x, frustumPoints[n].z);
            zbounds.y = std::max(zbounds.y, frustumPoints[n].z);
        }

        // factor in z-bounds to prevent clipping
        return (std::min(readMap->GetBoundingRadius() * 2.0f, std::max(xbounds.y - xbounds.x, zbounds.y - zbounds.x)));
        */

    }
    #endif
}
lhog commented 1 year ago

screen02337 screen02338 screen02339