Skocz do zawartości

SC5Shout

Członkowie
  • Postów

    2
  • Dołączył

  • Ostatnio

Posty napisane przez SC5Shout

  1. Mam problem z cieniami dla światła punktowego. Widziałem sporo artykułów, filmików, pytań zadanych na forach związanych z tym tematem:

    i napisałem taki (pseudo) kod

    struct PointShadowMatrix
    {
        glm::mat4 viewProjection[6];
    };
    const glm::mat4 shadowProj = glm::perspective(Math::HALF_PI, 1.0f, 25.0f, 1.0f);
    
    const glm::vec3 lightPos = light.getPosition();
    
    PointShadowMatrix shadowData;
    shadowData.viewProjection[0] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(1.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
    shadowData.viewProjection[1] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
    shadowData.viewProjection[2] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, -1.0));
    shadowData.viewProjection[3] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, -1.0, 0.0), glm::vec3(0.0, 0.0, 1.0));
    shadowData.viewProjection[4] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 0.0, 1.0), glm::vec3(0.0, 1.0, 0.0));
    shadowData.viewProjection[5] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 0.0, -1.0), glm::vec3(0.0, 1.0, 0.0));
    
    shadowConstantBuffer.AddData(shadowData);
    
    auto textureCube = TextureCube(
        .Width = 1024,
        .Height = 1024,
        .MipLevels = 1,
        .Format = DXGI_FORMAT_R24G8_TYPELESS,
        .BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE
    );
    
    auto cubeDepthRenderTarget = CubeRenderTarget(
        .resource = textureCube,
        .FirstArraySlice = 0,
        .MipSlice = 0
    );
    
    auto shader = Shader(.path = "PointShadowShader.hlsl");
    
    shader.Bind();
    cubeDepthRenderTarget.Bind();
    shadowConstantBuffer.Bind();
    
    SetViewport(.w = 1024, .h = 1024);
    ClearDepth(cubeDepthRenderTarget, 0.0f);
    
    DrawDepth();

    PointShadowShader:

    struct VertexInput
    {
        float3 position : POSITION;
        
        nointerpolation float4 modelToWorld1 : I_MODEL_TO_WORLD_ONE;
        nointerpolation float4 modelToWorld2 : I_MODEL_TO_WORLD_TWO;
        nointerpolation float4 modelToWorld3 : I_MODEL_TO_WORLD_THREE;
        nointerpolation float4 modelToWorld4 : I_MODEL_TO_WORLD_FOUR;
    };
    
    float4 VSMain(VertexInput input) : SV_POSITION
    {
        float4x4 model = float4x4(input.modelToWorld1, input.modelToWorld2, input.modelToWorld3, input.modelToWorld4);
        return mul(float4(input.position, 1.0f), model);
    }
    
    cbuffer PointShadowData : register(b4)
    {
        row_major float4x4 pointShadowViewProjection[6];
    };
    
    struct GS_OUTPUT
    {
        float4 position : SV_POSITION;
        float3 worldPosition : WORLD_POSITION;
        uint RTIndex : SV_RenderTargetArrayIndex;
    };
    
    [maxvertexcount(18)]
    void GSMain(triangle float4 position[3] : SV_POSITION, inout TriangleStream<GS_OUTPUT> OutStream)
    {
        for (uint face = 0; face < 6; ++face)
        {
            GS_OUTPUT output;
    
            output.RTIndex = face;
    
            for (uint v = 0; v < 3; ++v)
            {
                output.worldPosition = position[v].xyz;
                output.position = mul(position[v], pointShadowViewProjection[face]);
                OutStream.Append(output);
            }
            OutStream.RestartStrip();
        }
    }
    
    cbuffer LightInfo : register(b1)
    {
        float3 lightPos;
    };
    
    struct PixelInput
    {
        float4 position : SV_POSITION;
        float3 worldPosition : WORLD_POSITION;
    };
    
    float PSMain(PixelInput input) : SV_DEPTH
    {
        //próbowałem input.position zamiast input.worldPosition, efekt ten sam
        //próbowałem rozwiązania z artykułu NVidi - obliczenie kwadratu dystansu
        //próbowałem zwykłego dystansu bez dzielenia przez far plane
        //nic nie pomogło
        return length(input.worldPosition - lightPos) / 25.0f;
    }

    mapa cieni wygląda nawet dobrze:

    1dpbcMpUoRaXTwe5haZJNNSlZv4WAxbpVk2F0Gfn

    ale jak odpale apke to cienie już niekoniecznie:

    b0amiSy1l0g1cyAQzt4oeQbLEeJTAg44mXE5GPTh

    fioletowa kula to "wizualizator" światła

    kolejny screenshot, tym razem ze światłem za ścianą:

    c1bo5frkRB0lhzxSQJdQTGwBc1omM6Jl8xBmeYkA

    funkcja do samplowania tej mapy:

    float PointLightShadows(float3 worldPosition, float3 lightPosition)
    {
        float3 fragToLight = worldPosition - lightPosition;
        float distance = length(fragToLight);
        
        return t_pointShadowMap.SampleCmpLevelZero(g_shadowBorder, float4(fragToLight, lightIndex), distance / 25.0f);
    }

    Jak już wspominałem wcześniej, wchodziłem w wiele linków na ten temat i nie wiem, nic nie pomagało.

    Bufor głębi jest czyszczony na `0`, `depthFunc` jest ustawione na `GREATER`.

    Myślałem, że problem może leżeć np. w pozycji światła, ale sprawdziłem i w obu tych przypadkach (shadow pass, color pass), pozycja jest ta sama.

    Gdzie może leżeć błąd? Jak go naprawić? Jakie rzeczy powinienem wziąć pod uwagę debugując ten problem?

    Próbowałem jeszcze obliczyć `lightPosition - worldPosition` zamiast `worldPosition - lightPosition`, to też nie naprawia cieni. Zmieniałem wartości `up` w funkcji `lookUp` na różne, np. zamiast `glm::vec3(0.0f, 1.0f, 0.0f)` na `glm::vec3(0.0f, -1.0f, 0.0f)`. Negowałem po kolei `x`, `y`, `z` w `fragToLight`, zmieniałem z `row_major` na `column_major`, zmieniałem kolejności mnożenia, używałem funkcji `glm` z postfixami `RH` i `LH`.

×
×
  • Utwórz nowe...