Поскольку у меня хорошо работают тени на местности, я хотел двигаться вперед по ним, размышляя о том, что не так с тенями на моих инстанцированных объектах.
С этой целью я пытаюсь выполнить 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);
}
}
ФОТО ЦВЕТА ЧЕРНОЙ ГРАНИЦЫ: Не ожидаемый результат