Неправильный вывод буфера глубины (текстуры)?

Для эффекта SSAO мне нужно сгенерировать две текстуры: нормали (в пространстве обзора) и глубину.

Я решил использовать буфер глубины в качестве текстуры в соответствии с учебник Microsoft (глава Чтение буфера трафарета глубины как текстуры).

К сожалению, после рендеринга я не получил никакой информации из буфера глубины (нижнее изображение):

введите здесь описание изображения

Я думаю, это неправильно. И что странно, буфер глубины вроде работает (получаю правильный порядок граней и т. Д.).

Код буфера глубины:

//create depth stencil texture (depth buffer)
D3D11_TEXTURE2D_DESC descDepth;
ZeroMemory(&descDepth, sizeof(descDepth));
descDepth.Width = width;
descDepth.Height = height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_R24G8_TYPELESS;
descDepth.SampleDesc.Count = antiAliasing.getCount();
descDepth.SampleDesc.Quality = antiAliasing.getQuality();
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;

ID3D11Texture2D* depthStencil = NULL;
result = device->CreateTexture2D(&descDepth, NULL, &depthStencil);
ERROR_HANDLE(SUCCEEDED(result), L"Could not create depth stencil texture.", MOD_GRAPHIC);

D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
//setup the description of the shader resource view
shaderResourceViewDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
shaderResourceViewDesc.ViewDimension = antiAliasing.isOn() ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D;
shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
shaderResourceViewDesc.Texture2D.MipLevels = 1;

//create the shader resource view.
ERROR_HANDLE(SUCCEEDED(device->CreateShaderResourceView(depthStencil, &shaderResourceViewDesc, &depthStencilShaderResourceView)),
    L"Could not create shader resource view for depth buffer.", MOD_GRAPHIC);

createDepthStencilStates();
//set the depth stencil state.
context->OMSetDepthStencilState(depthStencilState3D, 1);

D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
// Initialize the depth stencil view.
ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));

// Set up the depth stencil view description.
depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilViewDesc.ViewDimension = antiAliasing.isOn() ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;
depthStencilViewDesc.Texture2D.MipSlice = 0;
//depthStencilViewDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH;

// Create the depth stencil view.
result = device->CreateDepthStencilView(depthStencil, &depthStencilViewDesc, &depthStencilView);
ERROR_HANDLE(SUCCEEDED(result), L"Could not create depth stencil view.", MOD_GRAPHIC);

После рендеринга с первым проходом я установил трафарет глубины как ресурс текстуры вместе с другими целями рендеринга (цвет, нормали), добавив его в массив:

ID3D11ShaderResourceView ** textures = new ID3D11ShaderResourceView *[targets.size()+1];
for (unsigned i = 0; i < targets.size(); i++) {
    textures[i] = targets[i]->getShaderResourceView();
}
textures[targets.size()] = depthStencilShaderResourceView;
context->PSSetShaderResources(0, targets.size()+1, textures);

Перед вторым проходом я вызываю context->OMSetRenderTargets(1, &myRenderTargetView, NULL);, чтобы отвязать буфер глубины (чтобы я мог использовать его как текстуру).

Затем я визуализирую свои текстуры (цели рендеринга из первого прохода + буфер глубины) с помощью тривиального шейдера постобработки, просто для целей отладки (второй проход):

Texture2D ColorTexture[3];
SamplerState ObjSamplerState;

float4 main(VS_OUTPUT input) : SV_TARGET0{
    float4 Color;
    Color = float4(0, 1, 1, 1);
    float2 textureCoordinates = input.textureCoordinates.xy * 2;
    if (input.textureCoordinates.x < 0.5f && input.textureCoordinates.y < 0.5f) {
        Color = ColorTexture[0].Sample(ObjSamplerState, textureCoordinates);
    }
    if (input.textureCoordinates.x > 0.5f && input.textureCoordinates.y < 0.5f) {
        textureCoordinates.x -= 0.5f;
        Color = ColorTexture[1].Sample(ObjSamplerState, textureCoordinates);
    }
    if (input.textureCoordinates.x < 0.5f && input.textureCoordinates.y > 0.5f) { //depth texture
        textureCoordinates.y -= 0.5f;
        Color = ColorTexture[2].Sample(ObjSamplerState, textureCoordinates);
    }
...

Он отлично работает с текстурой нормалей. Почему это не для буфера глубины (как для представления ресурсов шейдера)?


person PolGraphic    schedule 15.08.2015    source источник
comment
Буферы глубины часто выглядят равномерно красными при просмотре, потому что обычно значения находятся в диапазоне от 0,99 до 1 с неправильно установленными ближней и дальней плоскостями отсечения. Проверяли ли вы, что данные неверны, кроме визуального осмотра?   -  person Adam Miles    schedule 16.08.2015
comment
@AdamMiles, ты прав! После расследования я обнаружил, что значения действительно находятся между 0,999f и 1.000f. Я установил свои дальние и ближние плоскости отсечения с помощью DirectX::XMMatrixPerspectiveFovLH(DirectX::XM_PIDIV4, screenWidth / (FLOAT)screenHeight, 0.01f, 20000.0f); Должен ли я их изменить? такие значения, как 0.01f, 200.0f, не обеспечивают лучшие значения (в большем диапазоне), и, кроме того, часть моей геометрии обрезается. Есть ли что-нибудь еще, чем я могу манипулировать, чтобы добиться лучших результатов?   -  person PolGraphic    schedule 16.08.2015
comment
Значения должны максимально ограничивать видимый диапазон вашей сцены. Значение, близкое к обрезке 0,01, предполагает, что вы не хотите, чтобы объекты отсекались до тех пор, пока они не окажутся на расстоянии 1 см от камеры, вы, вероятно, могли бы уйти как минимум с 0,1 здесь. Дальний клип в 20000 предполагает расстояние прорисовки 20 км (при условии, что ваши единицы - это метры), что также кажется чрезмерным. Даже при 0,1 / 200 вероятность того, что в большинстве случаев будет ›0,9, но это не так уж и важно, за исключением тех случаев, когда вы пытаетесь визуализировать данные, как вы это делали. Возможно, при визуализации масштабировать 0,9–1 - ›0,0–1,0?   -  person Adam Miles    schedule 16.08.2015


Ответы (1)


Согласно комментариям:

Текстура была отрисована и отобрана правильно, но данные казались равномерно красными из-за данных, лежащих между 0,999 и 1,0f.

Есть несколько вещей, которые вы можете сделать, чтобы улучшить доступную точность глубины, но самый простой из них - просто убедиться, что ваши ближние и дальние расстояния клипа не слишком малы / велики для сцены, которую вы рисуете.

Предполагая, что ваши единицы измерения - это метры, ближний зажим 0,1 (10 см) и дальний зажим 200 (метров) намного более разумны, чем 1 см и 20 км.

Даже в этом случае не ожидайте увидеть слишком много черных / темных областей, нелинейный характер z-буфера по-прежнему будет означать, что большинство ваших значений глубины смещены в сторону 1. Если визуализация буфера глубины важна, тогда просто измените масштаб данных до нормализованного диапазона 0-1 перед их отображением.

person Adam Miles    schedule 16.08.2015