Triangles seem to reference incorrect vertices when trying to render a mesh in directx11

0

I have a c++/cx project where I'm rendering procedural meshes using DirectX-11. It worked before, but now, with a new mesh, the triangles appear incorrect, as if they reference the wrong vertex-index. I have spend ages trying to find out what is wrong, but I have absolutely no idea what could be causing this.

I load the vertex and triangle data from a text file, pass it to my custom mesh class, which creates the mesh from the data. when I log the vertex and triangle-data, it's all correct, so this makes me think something goes wrong when sending the data to the shaders, but I have no idea what can cause this.

Here's the (base) Mesh class:

#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;
        });
}

and here's the actual mesh class, called 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
}

the VertexPositionColor struct is just this:

        struct VertexPositionColor
        {
            XMFLOAT3 Position;
            XMFLOAT3 Color;
        };

I know this is a lot of code, but I have no idea what could be causing this. I would really appreciate any pointers in the right direction.

directx
rendering
shader
c++-cx
vertices
asked on Stack Overflow Jun 25, 2019 by Stef

1 Answer

1

A few pointers here, seeing I have been through the same issues over time as what you are experiencing.

  1. Memory Alignment and size, just make sure your VertexPositionColour is actually 32 bytes wide as you expect and that its not packing the values into the first 24 bytes. Ensure you are following 16 byte boundary alignment as well. You could pad the structure and use XMFloat4 to ensure the padding is correct.
  2. Double check that your index buffer is 32 bit indicies. But that looks ok.
  3. In most cases I have found, when the data looks right, its an alignment in the buffer issue. Some of the convenience functions you are using also hide some of the details I usually explicitly set. Where you can, sometimes being more verbose in your buffer definitions also helps with the hard to find bugs.

Good luck.

answered on Stack Overflow Aug 5, 2019 by ErnieDingo

User contributions licensed under CC BY-SA 3.0