尝试在DirectX11中渲染网格时,三角形似乎引用了不正确的顶点

时间:2019-06-25 15:13:40

标签: directx rendering shader c++-cx vertices

我有一个c ++ / cx项目,其中使用DirectX-11渲染过程网格。 以前可以使用,但是现在使用新的网格,三角形看起来不正确,就好像它们引用了错误的顶点索引一样。 我花了很长时间试图找出问题所在,但是我完全不知道是什么原因造成的。

我从文本文件加载顶点和三角形数据,并将其传递给我的自定义网格类,该类从数据创建网格。 当我记录顶点和三角形数据时,它们都是正确的,所以这使我认为在将数据发送到着色器时出了点问题,但是我不知道是什么原因引起的。

这是(基础)Mesh类:

#include <array>

#include "Data\Mesh.h"
#include "Utilities.h"

using namespace Ambiorix::Track3DComponent;
using namespace Ambiorix::Track3DComponent::Data;

Mesh::Mesh(ITrack3DLogger^ logger, ComPtr<ID3D11Device1> d3dDevice, ComPtr<ID3D11DeviceContext1> d3dContext)
    : _logger(logger),
    _inputLayout(nullptr),
    _vertexBuffer(nullptr),
    _indexBuffer(nullptr),
    _vertexBufferStride(0u),
    _vertexBufferOffset(0u),
    _indexFormat(DXGI_FORMAT_R16_UINT),
    _indexCount(0u),
    _primitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST),
    _isVertexShaderCreated(false),
    _isPixelShaderCreated(false)
{
    _d3dDevice = d3dDevice;
    _d3dContext = d3dContext;
    _modelMatrix = Utilities::CreateFloat4x4IdentityMatrix();
}

void Mesh::Render(ModelViewProjectionConstantBuffer* const modelViewProjectionConstantBuffer, bool visible)
{
    if (!_isVertexShaderCreated || !_isPixelShaderCreated)
    {
        return;
    }

    XMStoreFloat4x4(&modelViewProjectionConstantBuffer->model, XMLoadFloat4x4(&_modelMatrix));

    const unsigned int DESTINATION_SUB_RESOURCE = 0u;
    const D3D11_BOX* DESTINATION_BOX = nullptr;
    const unsigned int SOURCE_ROW_PITCH = 0u;
    const unsigned int SOURCE_DEPTH_PITCH = 0u;
    _d3dContext->UpdateSubresource(_constantBuffer.Get(), DESTINATION_SUB_RESOURCE, DESTINATION_BOX, modelViewProjectionConstantBuffer, SOURCE_ROW_PITCH, SOURCE_DEPTH_PITCH);

    const unsigned int START_SLOT = 0u;
    const unsigned int NUM_BUFFERS = 1u;
    _d3dContext->IASetVertexBuffers(START_SLOT, NUM_BUFFERS, _vertexBuffer.GetAddressOf(), &_vertexBufferStride, &_vertexBufferOffset);

    const unsigned int OFFSET = 0u;
    _d3dContext->IASetIndexBuffer(_indexBuffer.Get(), _indexFormat, OFFSET);

    _d3dContext->IASetPrimitiveTopology(_primitiveTopology);

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

    ID3D11ClassInstance*const* CLASS_INSTANCES = nullptr;
    const unsigned int NUM_CLASS_INSTANCES = 0u;
    _d3dContext->VSSetShader(_vertexShader.Get(), CLASS_INSTANCES, NUM_CLASS_INSTANCES);

    _d3dContext->VSSetConstantBuffers(START_SLOT, NUM_BUFFERS, _constantBuffer.GetAddressOf());

    _d3dContext->PSSetShader(_pixelShader.Get(), CLASS_INSTANCES, NUM_CLASS_INSTANCES);

    SetTexture();

    ID3D11BlendState* d3dBlendState;
    D3D11_BLEND_DESC omDesc;
    ZeroMemory(&omDesc, sizeof(D3D11_BLEND_DESC));
    omDesc.RenderTarget[0].BlendEnable = true;
    omDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
    omDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
    if (visible)
    {
        omDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; //apparently it's premultiplied. (cause otherwise it should be D3D11_BLEND_SRC_ALPHA)
        omDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
        omDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
    }
    else
    {
        omDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ZERO; //invisible
        omDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO; //invisible
        omDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA;
    }
    omDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
    omDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;

    //if (FAILED(d3dDevice->CreateBlendState(&omDesc, &d3dBlendState)))return false;
    _d3dDevice->CreateBlendState(&omDesc, &d3dBlendState);
    _d3dContext->OMSetBlendState(d3dBlendState, 0, 0xffffffff);

    const unsigned int START_INDEX_LOCATION = 0u;
    const int BASE_VERTEX_LOCATION = 0;
    _d3dContext->DrawIndexed(_indexCount, START_INDEX_LOCATION, BASE_VERTEX_LOCATION);
}

void Mesh::Translate(XMVECTOR& position)
{
    XMStoreFloat4x4(&_modelMatrix, XMMatrixTranspose(XMMatrixTranslationFromVector(position)));
}

void Mesh::Rotate(XMVECTOR& axis, float angle)
{
    XMStoreFloat4x4(&_modelMatrix, XMMatrixRotationAxis(axis, angle));
}

void Mesh::Transform(XMVECTOR& position, XMVECTOR& rotationQuaternion)
{
    static const XMVECTOR ZERO = { 0.0f, 0.0f, 0.0f, 0.0f };
    static const XMVECTOR ONE = { 1.0f, 1.0f, 1.0f, 0.0f };

    XMStoreFloat4x4(&_modelMatrix, XMMatrixTranspose(XMMatrixAffineTransformation(ONE, ZERO, rotationQuaternion, position)));
}

task<void> Mesh::CreateVertexShaderAsync(Platform::String^ relativeFileName, const D3D11_INPUT_ELEMENT_DESC *const vertexDescriptions, unsigned int vertexDescriptionCount)
{
    _logger->Trace(L"Mesh.CreateVertexShaderAsync()");

    return Utilities::ReadAllFileBytesAsync(relativeFileName)
        .then([this, vertexDescriptions, vertexDescriptionCount] (const Platform::Array<byte>^ vertexShaderBytes)
        {
            critical_section::scoped_lock lock(_criticalSection);

            if (vertexShaderBytes->Length == 0u)
            {
                _logger->Error(L"Mesh.CreateVertexShaderAsync() | Failed to load vertex shader.");
                return;
            }

            auto createVertexShaderResult = _d3dDevice->CreateVertexShader(vertexShaderBytes->Data, vertexShaderBytes->Length, nullptr, _vertexShader.GetAddressOf());
            if (FAILED(createVertexShaderResult))
            {
                _logger->Error(L"Mesh.CreateVertexShaderAsync() | Failed to create vertex shader.");
                return;
            }

            auto createInputLayoutResult = _d3dDevice->CreateInputLayout(vertexDescriptions, vertexDescriptionCount, vertexShaderBytes->Data, vertexShaderBytes->Length, _inputLayout.GetAddressOf());
            if (FAILED(createInputLayoutResult))
            {
                _logger->Error(L"Mesh.CreateVertexShaderAsync() | Failed to create input layout.");
                return;
            }

            _logger->Trace(L"Mesh.CreateVertexShaderAsync() | Vertex shader created.");
            _isVertexShaderCreated = true;
        });
}

task<void> Mesh::CreatePixelShaderAsync(Platform::String^ relativeFileName)
{
    _logger->Trace(L"Mesh.CreatePixelShaderAsync()");

    return Utilities::ReadAllFileBytesAsync(relativeFileName)
        .then([this](const Platform::Array<byte>^ pixelShaderBytes)
        {
            critical_section::scoped_lock lock(_criticalSection);

            if (pixelShaderBytes->Length == 0u)
            {
                _logger->Error(L"Mesh.CreatePixelShaderAsync() | Failed to load pixel shader.");
                return;
            }

            auto createPixelShaderResult = _d3dDevice->CreatePixelShader(pixelShaderBytes->Data, pixelShaderBytes->Length, nullptr, _pixelShader.GetAddressOf());
            if (FAILED(createPixelShaderResult))
            {
                _logger->Error(L"Mesh.CreatePixelShaderAsync() | Failed to create pixel shader.");
                return;
            }

            ModelViewProjectionConstantBuffer modelViewProjectionConstantBuffer;

            D3D11_SUBRESOURCE_DATA InitData;
            InitData.pSysMem = &modelViewProjectionConstantBuffer;
            InitData.SysMemPitch = 0u;
            InitData.SysMemSlicePitch = 0u;

            CD3D11_BUFFER_DESC bufferDescription(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);

            auto createConstantBuffer = _d3dDevice->CreateBuffer(&bufferDescription, &InitData, _constantBuffer.GetAddressOf());
            if (FAILED(createConstantBuffer))
            {
                _logger->Error(L"Mesh.CreatePixelShaderAsync() | Failed to create constant buffer.");
                return;
            }

            _logger->Trace(L"Mesh.CreatePixelShaderAsync() | Pixel shader created.");
            _isPixelShaderCreated = true;
        });
}

这是实际的网格物体类,称为CullingMesh:

#include "Data\CullingMesh.h"
#include "ShaderStructures\VertexPositionColor.h"
#include <DDSTextureLoader.h>
#include "Utilities.h"

using namespace Ambiorix::Track3DComponent;
using namespace Ambiorix::Track3DComponent::Data;
using namespace Ambiorix::Track3DComponent::ShaderStructures;

CullingMesh::CullingMesh(ITrack3DLogger^ logger, ComPtr<ID3D11Device1> d3dDevice, ComPtr<ID3D11DeviceContext1> d3dContext)
    : Mesh(logger, d3dDevice, d3dContext)
{
    _vertexBufferStride = sizeof(VertexPositionColor);

    _vertexShaderRelativeFilePath = ref new Platform::String(L"Ambiorix.Track3DComponent\\RoadVertexShader.cso");
    _pixelShaderRelativeFilePath = ref new Platform::String(L"Ambiorix.Track3DComponent\\RoadPixelShader.cso");
}

task<void> CullingMesh::InitializeAsync(const std::vector<Vector>*const vertices, const std::vector<int>*const triangles)
{
    _logger->Trace(L"CullingMesh.InitializeAsync()");

    std::vector<task<void>> tasks;
    tasks.push_back(CreateVertexShaderAsync(_vertexShaderRelativeFilePath, _vertexDescriptions, ARRAYSIZE(_vertexDescriptions)));
    tasks.push_back(CreatePixelShaderAsync(_pixelShaderRelativeFilePath));

    return when_all(tasks.begin(), tasks.end())
        .then([this, vertices, triangles]
    {
        CreateMesh(vertices, triangles);

        _logger->Trace("CullingMesh.InitializeAsync() | Done.");
    });
}

void CullingMesh::CreateMesh(const std::vector<Vector>*const vertices, const std::vector<int>*const triangles)
{
    _logger->Trace(L"CullingMesh.Initialize()");

    static const size_t VERTEX_COUNT = vertices->size();
    _logger->Error("VERTEX_COUNT: " + VERTEX_COUNT.ToString());

    auto vertexData = new VertexPositionColor[VERTEX_COUNT];
    for (int i = 0; i < VERTEX_COUNT; i++)
    {
        auto currentVertexData = &vertexData[i];
        XMFLOAT3 pos;
        XMStoreFloat3(&pos, Utilities::ToVector(vertices->at(i)));
        currentVertexData->Position = pos;
        currentVertexData->Color = { 1,0,0 };
    }

    D3D11_SUBRESOURCE_DATA vertexBufferData = { 0 };
    vertexBufferData.pSysMem = vertexData;
    vertexBufferData.SysMemPitch = 0u;
    vertexBufferData.SysMemSlicePitch = 0u;

    CD3D11_BUFFER_DESC vertexBufferDescription(static_cast<unsigned int>(sizeof(*vertexData) * VERTEX_COUNT), D3D11_BIND_VERTEX_BUFFER);

    auto createVertexBufferResult = _d3dDevice->CreateBuffer(&vertexBufferDescription, &vertexBufferData, _vertexBuffer.GetAddressOf());
    if (FAILED(createVertexBufferResult))
    {
        _logger->Error(L"CullingMesh.Initialize() | Failed to create vertex buffer.");
    }

    delete vertexData;

    _indexCount = (unsigned int)triangles->size();
    _logger->Error("_indexCount: " + _indexCount.ToString());

    auto triangleIndices = new unsigned int[_indexCount];
    for (unsigned int i = 0; i < _indexCount; i++)
    {
        triangleIndices[i] = triangles->at(i);
    }

    D3D11_SUBRESOURCE_DATA indexBufferData = { 0 };
    indexBufferData.pSysMem = triangleIndices;
    indexBufferData.SysMemPitch = 0u;
    indexBufferData.SysMemSlicePitch = 0u;

    CD3D11_BUFFER_DESC indexBufferDescription(sizeof(*triangleIndices) * _indexCount, D3D11_BIND_INDEX_BUFFER);

    auto createIndexBufferResult = _d3dDevice->CreateBuffer(&indexBufferDescription, &indexBufferData, _indexBuffer.GetAddressOf());
    if (FAILED(createIndexBufferResult))
    {
        _logger->Error(L"CullingMesh.Initialize() | Failed to create index buffer.");
    }

    delete triangleIndices;

    _logger->Trace("CullingMesh.Initialize() | Done.");
}

void CullingMesh::SetTexture()
{
    //no texture
}

VertexPositionColor结构就是这样:

        struct VertexPositionColor
        {
            XMFLOAT3 Position;
            XMFLOAT3 Color;
        };

我知道这是很多代码,但是我不知道是什么原因引起的。 我真的很感激任何朝着正确方向提出的建议。

1 个答案:

答案 0 :(得分:1)

这里有一些提示,表明随着时间的推移,我经历了与您遇到的相同的问题。

  1. 内存对齐和大小,只需确保您的VertexPositionColour实际上是您期望的32字节宽,并且不将值打包到前24个字节中即可。确保您也遵循16字节边界对齐。您可以填充结构并使用XMFloat4来确保填充正确。
  2. 仔细检查您的索引缓冲区是否为32位索引。但这看起来还可以。
  3. 在大多数情况下,我发现当数据看起来正确时,它在缓冲区问题中对齐。您使用的一些便利功能也隐藏了我通常显式设置的一些细节。在可能的情况下,有时在缓冲区定义中更加冗长,也有助于解决难以发现的错误。

祝你好运。