c++directx-12directxtk

Drawing spheres via DirectX12 Tool Kit


I have three problems when trying to draw spheres:

  1. Sphere is glitching in some angles: enter image description here
  2. Don’t know how to apply a color to sphere
  3. Can’t draw two spheres at one - only one is shown.

Code. Render:

void Game::Render()
{
if (m_timer.GetFrameCount() == 0)
{
return;
}

m_deviceResources->Prepare();
Clear();

auto commandList = m_deviceResources->GetCommandList();
PIXBeginEvent(commandList, PIX_COLOR_DEFAULT, L"Render");

auto commandList2 = m_deviceResources->GetCommandList();
PIXBeginEvent(commandList2, PIX_COLOR_DEFAULT, L"Draw Sphere");

m_shapeEffect->Apply(m_deviceResources->GetCommandList());

for (int i(0); i < vsphere; i++)
{
m_shapeEffect->SetWorld(d3dsphere[i]->world);
d3dsphere[i]->Draw(commandList2);
}

PIXEndEvent(commandList2);
PIXEndEvent(commandList);
PIXBeginEvent(m_deviceResources->GetCommandQueue(), PIX_COLOR_DEFAULT, L"Present");
m_deviceResources->Present();
m_graphicsMemory->Commit(m_deviceResources->GetCommandQueue());
PIXEndEvent(m_deviceResources->GetCommandQueue());
}

How I create shape effect

EffectPipelineStateDescription pd(
&VertexPositionColor::InputLayout,
CommonStates::Opaque,
CommonStates::DepthNone,
CommonStates::CullNone,
rtState,
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
m_shapeEffect = std::make_unique<BasicEffect>(device, EffectFlags::VertexColor, pd);

d3dsphere is a D3DSphere class object; the constructor and Draw method

D3DSphere(float x, float y, float z, float radius, float r, float g, float b, float a)  
{
this->x = x;
this->y = y;
this->z = z;

this->radius = radius;

this->shape = GeometricPrimitive::CreateSphere(radius*2.0f);

this->world = Matrix::Identity;
this->world = XMMatrixMultiply(this->world, Matrix::CreateTranslation(x, y, z));
this->index = vsphere;

d3dsphere[vsphere] = this;
vsphere++;
}

void D3DSphere::Draw(ID3d12GraphicsCommandList* commandList)
{
   this->shape->Draw(commandList);
}

Perhaps it will be useful if I figure, that the sphere radius(and everything in my scene) is very tiny(~10^-6)

By unknown for me reasons, the code of examples in Microsoft DirectX12 Tool Kit wiki page in most is not compatible with the headers I have installed via NuGet packages - I have different constructors, different arguments in methods. I think the problem is that I am using Visual Studio 15, but Microsoft recommends to use at least 17(there are two different DirectX12TK NuGet packages - one for VS15 and one for VS17 and above). It is weird.


I solved the third problem by changing code in rendering:

for(int i(0);i<vsphere;i++)
{
m_shapeEffect->SetMatrices(d3dsphere->world, m_view, m_projection);
m_shapeEffect->Apply(m_deviceResources->GetCommandList());
d3dsphere[i]->Draw();
}

DirectX12TK NuGet package version I use is 2019.12.17.1


Solution

  • Here you told the Pipeline State Object that you are using VertexPositionColor and want per-vertex color:

    EffectPipelineStateDescription pd(
    &VertexPositionColor::InputLayout,
    CommonStates::Opaque,
    CommonStates::DepthNone,
    CommonStates::CullNone,
    rtState,
    D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
    m_shapeEffect = std::make_unique<BasicEffect>(device, EffectFlags::VertexColor, pd);
    

    The actual vertex type created by GeometricPrimitive's factory methods is VertexPositionNormalTexture (the VertexType type alias is there to make that a bit easier).

    Therefore, the vertex data contains

    struct VertexPositionNormalTexture
    {
        XMFLOAT3 position;
        XMFLOAT3 normal;
        XMFLOAT2 textureCoordinate;
    }
    

    But you told the vertex shader that it's:

    const D3D12_INPUT_ELEMENT_DESC VertexPositionColor::InputElements[] =
    {
        { "SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
        { "COLOR",       0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
    };
    

    Change your BasicEffect to:

    EffectPipelineStateDescription pd(
    &GeometricPrimitive::VertexType::InputLayout,
    CommonStates::Opaque,
    CommonStates::DepthNone,
    CommonStates::CullNone,
    rtState,
    D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
    m_shapeEffect = std::make_unique<BasicEffect>(device, EffectFlags::None, pd);
    

    It will look boring without EffectFlags::Lighting and m_shapeEffect->EnableDefaultLighting();, but should render.

    If you want to create a vertex format other than VertexPositionNormalTexture, you can use the GeometricPrimitive custom geometry methods to generate the shape data, but you'll need implement the creation of the VB/IB and rendering in your own code (i.e. the GeometricPrimitive::CreateCustom method only supports VertexPositionNormalTexture).

    D3D12_VERTEX_BUFFER_VIEW m_vertexBufferView;
    D3D12_INDEX_BUFFER_VIEW m_indexBufferView;
    
    UINT m_indexCount;
    
    Microsoft::WRL::ComPtr<ID3D12Resource> m_vertexBuffer;
    Microsoft::WRL::ComPtr<ID3D12Resource> m_indexBuffer;
    
    // Create shape data
    std::vector<VertexPositionNormalTexture> vertices;
    std::vector<uint16_t> indices;
    GeometricPrimitive::CreateSphere(vertices, indices);
    
    std::vector<VertexPositionColor> newVerts;
    newVerts.reserve(vertices.size());
    for (auto it : vertices)
    {
        VertexPositionColor v;
        v.position = it.position;
        v.color = XMFLOAT4(it.normal.x, it.normal.y, it.normal.z, 1.f);
        newVerts.emplace_back(v);
    }
    
    // Place data on upload heap
    size_t vsize = newVerts.size() * sizeof(VertexPositionColor);
    SharedGraphicsResource vb = GraphicsMemory::Get().Allocate(vsize);
    memcpy(vb.Memory(), newVerts.data(), vsize);
    
    size_t isize = indices.size() * sizeof(uint16_t);
    SharedGraphicsResource ib = GraphicsMemory::Get().Allocate(isize);
    memcpy(ib.Memory(), indices.data(), isize);
    
    // You can render directly from the 'upload' heap or as shown here create static IB/VB resources
    ResourceUploadBatch resourceUpload(device);
    resourceUpload.Begin();
    
    CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT);
    
    auto vdesc = CD3DX12_RESOURCE_DESC::Buffer(vsize);
    auto idesc = CD3DX12_RESOURCE_DESC::Buffer(isize);
    
    DX::ThrowIfFailed(device->CreateCommittedResource(
        &heapProperties, D3D12_HEAP_FLAG_NONE, &vdesc, D3D12_RESOURCE_STATE_COPY_DEST,
        nullptr, IID_PPV_ARGS(m_vertexBuffer.GetAddressOf())));
    
    DX::ThrowIfFailed(device->CreateCommittedResource(
        &heapProperties, D3D12_HEAP_FLAG_NONE, &idesc, D3D12_RESOURCE_STATE_COPY_DEST,
        nullptr, IID_PPV_ARGS(m_indexBuffer.GetAddressOf())));
    
    resourceUpload.Upload(m_vertexBuffer.Get(), vb);
    resourceUpload.Upload(m_indexBuffer.Get(), ib);
    
    resourceUpload.Transition(m_vertexBuffer.Get(),
        D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
    resourceUpload.Transition(m_indexBuffer.Get(),
        D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER);
    
    auto uploadResourcesFinished = resourceUpload.End(m_deviceResources->GetCommandQueue());
    uploadResourcesFinished.wait();
    
    // Create matching effect for new vertex layout
    EffectPipelineStateDescription psd(
        &VertexPositionColor::InputLayout,
        CommonStates::Opaque,
        CommonStates::DepthDefault,
        CommonStates::CullNone,
       rtState);
    
    m_shapeEffect = std::make_unique<BasicEffect>(device, EffectFlags::VertexColor, psd);
    
    // Set up buffer views
    m_vertexBufferView = { m_vertexBuffer->GetGPUVirtualAddress(), UINT(vsize), sizeof(VertexPositionColor) };
    m_indexBufferView = { m_indexBuffer->GetGPUVirtualAddress(), UINT(isize), DXGI_FORMAT_R16_UINT };
    
    m_indexCount = UINT(indices.size());
    
    m_shapeEffect->Apply(commandList);
    
    commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);
    commandList->IASetIndexBuffer(&m_indexBufferView);
    commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    
    commandList->DrawIndexedInstanced(m_indexCount, 1, 0, 0, 0);
    

    The latest release of the DirectX Tool Kit for DX12 that supports Visual Studio 2015 is December 2019 which is directxtk12_desktop_2015. There's very little functional or API difference between December 2019 and April 2020, so I'm not sure why you think the wiki is outdated. What NuGet package and version are you using?