Как вручную визуализировать сетку, загруженную с помощью DirectX Toolkit

У меня есть проект C++/cx, в котором я рендерил процедурные сетки с использованием DirectX-11, кажется, что все работает нормально, но теперь я хотел также импортировать и визуализировать сетки из файлов (точнее, из fbx). Мне сказали использовать для этого DirectX Toolkit.

Я следовал инструкциям инструментария, и все это работало, но потом я попытался сделать это в своем проекте, но, похоже, это не сработало. Импортированная сетка не была видна, а существующие процедурные сетки были отображены неправильно (как будто без буфера глубины).

Затем я попытался вручную визуализировать импортированную сетку (идентично процедурным сеткам, без использования функции Draw из DirectXTK). Это работает лучше, все существующие сетки правильны, но цвет импортированной сетки неправильный; Я использую изготовленный на заказ вершинный и фрагментный шейдер, который использует только данные о положении и цвете вершины, но по некоторым причинам нормали импортированной сетки отправляются в шейдер вместо цветов вершин.

(Я даже не хочу, чтобы нормали сохранялись в сетке, но у меня, похоже, нет возможности экспортировать в fbx без нормалей, и даже если я удаляю их вручную из fbx, при импорте DirectXTK кажется пересчитать нормали)

Кто-нибудь знает, что я делаю не так? Это все еще относительно новое для меня, поэтому любая помощь приветствуется. Если вам нужно больше информации, просто дайте мне знать.

Вот мой код для рендеринга мешей:

Сначала основная функция рендеринга (которая вызывается один раз при каждом обновлении):

void Track3D::Render()
{
if (!_loadingComplete)
{
    return;
}

static const XMVECTORF32 up = { 0.0f, 1.0f, 0.0f, 0.0f };

// Prepare to pass the view matrix, and updated model matrix, to the shader
XMStoreFloat4x4(&_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(_CameraPosition, _CameraLookat, up)));

// Clear the back buffer and depth stencil view.
_d3dContext->ClearRenderTargetView(_renderTargetView.Get(), DirectX::Colors::Transparent);
_d3dContext->ClearDepthStencilView(_depthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

// Set render targets to the screen.
ID3D11RenderTargetView *const targets[1] = { _renderTargetView.Get() };
_d3dContext->OMSetRenderTargets(1, targets, _depthStencilView.Get());

// Here I render everything:
_TrackMesh->Render(_constantBufferData);
RenderExtra();
_ImportedMesh->Render(_constantBufferData);

Present();
}

Present-функция:

void Track3D::Present()
{
DXGI_PRESENT_PARAMETERS parameters = { 0 };
parameters.DirtyRectsCount = 0;
parameters.pDirtyRects = nullptr;
parameters.pScrollRect = nullptr;
parameters.pScrollOffset = nullptr;

HRESULT hr = S_OK;

hr = _swapChain->Present1(1, 0, &parameters);

if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
    OnDeviceLost();
}
else
{
    if (FAILED(hr))
    {
        throw Platform::Exception::CreateException(hr);
    }
}
}

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

void Mesh::Render(ModelViewProjectionConstantBuffer constantBufferData)
{
if (!_loadingComplete)
{
    return;
}

XMStoreFloat4x4(&constantBufferData.model, XMLoadFloat4x4(&_modelMatrix));  

// Prepare the constant buffer to send it to the Graphics device.
_d3dContext->UpdateSubresource(
    _constantBuffer.Get(),
    0,
    NULL,
    &constantBufferData,
    0,
    0
);

UINT offset = 0;
_d3dContext->IASetVertexBuffers(
    0,
    1,
    _vertexBuffer.GetAddressOf(),
    &_stride,
    &_offset
);

_d3dContext->IASetIndexBuffer(
    _indexBuffer.Get(),
    DXGI_FORMAT_R16_UINT, // Each index is one 16-bit unsigned integer (short).
    0
);

_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

_d3dContext->IASetInputLayout(_inputLayout.Get());

// Attach our vertex shader.
_d3dContext->VSSetShader(
    _vertexShader.Get(),
    nullptr,
    0
);

// Send the constant buffer to the Graphics device.
_d3dContext->VSSetConstantBuffers(
    0,
    1,
    _constantBuffer.GetAddressOf()
);

// Attach our pixel shader.
_d3dContext->PSSetShader(
    _pixelShader.Get(),
    nullptr,
    0
);  

SetTexture();

// Draw the objects.
_d3dContext->DrawIndexed(
    _indexCount,
    0,
    0
);
}

И это вершинный шейдер:

cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix model;
matrix view;
matrix projection;
};

struct VertexShaderInput
{
float3 pos : POSITION;
//float3 normal : NORMAL0; //uncommenting these changes the color data for some reason (but always wrong)
//float2 uv1 : TEXCOORD0;
//float2 uv2 : TEXCOORD1;
float3 color : COLOR0;
};

struct VertexShaderOutput
{
float3 color : COLOR0;
float4 pos : SV_POSITION;
};

VertexShaderOutput main(VertexShaderInput input)
{
VertexShaderOutput output;
float4 pos = float4(input.pos, 1.0f);

// Transform the vertex position into projected space.
pos = mul(pos, model);
pos = mul(pos, view);
pos = mul(pos, projection);
output.pos = pos;

output.color = input.color;

return output;
}

И это пиксельный шейдер:

struct PixelShaderInput
{
    float3 color: COLOR0;
};

float4 main(PixelShaderInput input) : SV_TARGET
{
    return float4(input.color.r, input.color.g, input.color.b, 1);
}

1 ответ

Наиболее вероятная проблема заключается в том, что вы не устанавливаете достаточно состояния для своего чертежа и что функции рисования DirectX Tool Kit задают состояния, которые не соответствуют тому, что требуется для существующего кода.

По соображениям производительности DirectX Tool Kit не сохраняет и не восстанавливает состояние. Вместо этого каждая функция рисования полностью устанавливает необходимое ей состояние и затем покидает его. Я документирую, какое состояние затронуто в вики в разделе " Управление состояниями " для каждого класса.

Приведенный выше код устанавливает буфер вершин, буфер индексов, макет ввода, вершинный шейдер, пиксельный шейдер, топологию примитивов и постоянный буфер VS в слоте 0.

Вы не установили состояние смешивания, состояние глубины / трафарета или состояние растеризатора. Вы не предоставили пиксельный шейдер, поэтому я не знаю, нужны ли вам постоянные буферы PS, сэмплеры или ресурсы шейдеров.

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

_d3dContext->RSSetState(nullptr);
_d3dContext->OMSetBlendState(nullptr, nullptr, 0);
_d3dContext->OMSetDepthStencilState(nullptr, 0xffffffff);

Смотрите также класс CommonStates.

Обычно не рекомендуется использовать идентификаторы, начинающиеся с _ в C++. Официально все идентификаторы, которые начинаются с _X где X - заглавная буква или __ зарезервированы для реализации компилятора и библиотеки, чтобы он мог конфликтовать с некоторыми вещами компилятора. m_ или что-то подобное лучше.

Другие вопросы по тегам