DirectX-11 SampleCmpLevelZero всегда возвращает цвет границы - PullRequest
0 голосов
/ 01 сентября 2018

Поскольку у меня хорошо работают тени на местности, я хотел двигаться вперед по ним, размышляя о том, что не так с тенями на моих инстанцированных объектах.

С этой целью я пытаюсь выполнить PCF на моей карте теней, чтобы сгладить края. Я свободно следую алгоритму в книге Фрэнка Луны для 3x3 PCF. Однако функция Texture2D.SampleCmpLevelZero, похоже, никогда не возвращает ничего, кроме цвета Border. Когда я запускаю одно касание обычного сэмплера текстуры, я получаю глубину, которая верна для позиции (поэтому, сравнивая ее с objPos.z, можно узнать, находится ли она в тени или нет). Чтобы проверить это и доказать, что он работает так, как я ожидал, я должен вывести результат SampleCmpLevelZero в красный канал, затем установить зеленый канал на 1, если в тени, или синий канал на 1, если горит.

Однако в результате все на свете становится пурпурным (R = 1 + B = 1), а все в тени - желтым (R = 1 + G = 1), что означает, что, несмотря на то, что обычный сэмплер получает его правильно, Сэмплер сравнения не дифференцируется. Цвет границы установлен на чистый белый, поэтому красный канал возвращает значение 1.0f. Если я изменю цвет границы на черный, вместо него будет 0 (в результате светло-голубые цвета будут чистыми). Реальная проблема в том, что я передаю обе функции с одинаковыми параметрами. Это то же значение местоположения для координат текстуры и то же значение глубины, используемое для сравнения. Я посмотрел на кучу похожих вопросов и думаю, что у меня все правильно, но все равно не работает. Кто-нибудь может осветить, в чем может быть проблема? Ожидаемый результат - это значение, интерполированное между 0 и 1, которое используется для смешивания теней. Дайте мне знать, если вам нужна дополнительная информация. Спасибо.

Модель шейдера 5_0

Инициализация состояния сэмплера (вызывается один раз и никогда не связывается):

ZeroMemory(&sampDesc, sizeof(sampDesc));
//float shadowColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };//Returns 1 if outside of light I guess?
float shadowColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };//Returns 0 if outside of light I guess?
sampDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
sampDesc.ComparisonFunc = D3D11_COMPARISON_LESS;
sampDesc.BorderColor[0] = shadowColor[0];
sampDesc.BorderColor[1] = shadowColor[1];
sampDesc.BorderColor[2] = shadowColor[2];
sampDesc.BorderColor[3] = shadowColor[3];
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = 0;

hr = dev->CreateSamplerState(&sampDesc, &ShadowSamplerPCF);
devcon->PSSetSamplers(1, 1, &ShadowSamplerPCF);

Создание текстуры карты теней:

lightInfo.ShadowWidth = 4096;
lightInfo.ShadowHeight = 4096;

ZeroMemory(&lightInfo.ShadowViewport, sizeof(D3D11_VIEWPORT));

lightInfo.ShadowViewport.TopLeftX = 0;
lightInfo.ShadowViewport.TopLeftY = 0;
lightInfo.ShadowViewport.Width = lightInfo.ShadowWidth;
lightInfo.ShadowViewport.Height = lightInfo.ShadowWidth;
lightInfo.ShadowViewport.MinDepth = 0.0f;
lightInfo.ShadowViewport.MaxDepth = 1.0f;

D3D11_TEXTURE2D_DESC texDesc;
ZeroMemory(&texDesc, sizeof(D3D11_TEXTURE2D_DESC));
texDesc.Width = lightInfo.ShadowWidth;
texDesc.Height = lightInfo.ShadowWidth;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.Format = DXGI_FORMAT_R32_TYPELESS;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_DEFAULT;
texDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
texDesc.CPUAccessFlags = 0;
texDesc.MiscFlags = 0;

// Create the depth stencil view desc
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
ZeroMemory(&descDSV, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
descDSV.Format = DXGI_FORMAT_D32_FLOAT;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;

//create shader resource view desc
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = texDesc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;

//create texture and depth/resource views
HRESULT hr;
hr = graphicsPointers.pdev->CreateTexture2D(&texDesc, NULL, &ShadowTex2D);
if (FAILED(hr))
{
    MessageBox(NULL, "ERROR: Failed to create Shadow Map Texture 2D", "LightWithShadowMapClass.cpp", MB_OK);
}
hr = graphicsPointers.pdev->CreateDepthStencilView(ShadowTex2D, &descDSV, &lightInfo.ShadowDSV);
if (FAILED(hr))
{
    MessageBox(NULL, "ERROR: Failed to create Shadow Map Depth Stencil View", "LightWithShadowMapClass.cpp", MB_OK);
}
hr = graphicsPointers.pdev->CreateShaderResourceView(ShadowTex2D, &srvDesc, &lightInfo.ShadowSRV);
if (FAILED(hr))
{
    MessageBox(NULL, "ERROR: Failed to create Shadow Map Shader Resource View", "LightWithShadowMapClass.cpp", MB_OK);
}

Вот как состояния сэмплера объявляются в шейдере:

SamplerState ObjSamplerState:register(s0); //Normal sampler, gets set based on what is being done. Usually is a wrap when rendering objects.
SamplerComparisonState ShadowSampler:register(s1); //Set once and never changes

А вот упрощенный пиксельный шейдер (делает один SampleCmp вместо 9):

//re-homogenize position after interpolation
        input.PosLight = mul(input.PosLight, lightVPMat); //PosLight is interpolated world Pos
        input.PosLight.xyz /= input.PosLight.w;

        //if position is not visible to the light, don't calculate shadows. Instead, render it normally.
        if (input.PosLight.x < -1.0f || input.PosLight.x > 1.0f ||
            input.PosLight.y < -1.0f || input.PosLight.y > 1.0f ||
            input.PosLight.z < 0.0f || input.PosLight.z > 1.0f)
        {
            finalColor = texColor * light.ambient;
            finalColor += saturate(dot(light.dir, input.Normal) * light.diffuse * texColor);
        }
        else
        {
            //transform clip space coords to texture space coords (-1:1 to 0:1)
            input.PosLight.x = (input.PosLight.x + 1.0f) / 2.0f;
            input.PosLight.y = (input.PosLight.y + 1.0f) / -2.0f;

            //sample shadow map - point sampler
            float percentLit = 0.0f;
            float shadowMapDepth = 0.0f;
            uint status = 0;

            //Note that the two sample commands are receiving the same coordinates.
            percentLit += ShadowMap.SampleCmpLevelZero(ShadowSampler, input.PosLight.xy, input.PosLight.z, int2(0, 0), status).r;

            shadowMapDepth = ShadowMap.Sample(ObjSamplerState, input.PosLight.xy).r;

            finalColor = texColor * light.ambient;
            finalColor += percentLit * saturate(dot(light.dir, input.Normal) * light.diffuse * texColor);

            if (shadowMapDepth < input.PosLight.z)
            {
                //in shadow
                finalColor = float4(percentLit, 1.0f, 0.0f, 1.0f);
            }
            else
            {
                //in light
                finalColor = float4(percentLit, 0.0f, 1.0f, 1.0f);

            }
        }

ФОТО ЦВЕТА ЧЕРНОЙ ГРАНИЦЫ: Не ожидаемый результат

...