0

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

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
Artur
  • 325
  • 2
  • 16
  • Which specific NuGet package are you using? What are the parameters to your device resources constructor? It looks to me like the Depth buffer isn't set up right. – Chuck Walbourn Apr 23 '20 at 17:59
  • Why do you have more than one commandList variable here? – Chuck Walbourn Apr 23 '20 at 18:01
  • @ChuckWalbourn, probably because I wrong understand things, but it worked, so I didn’t changed it. Should I have only one? – Artur Apr 23 '20 at 18:53
  • Make sure you only have one of: ``directxtk12_desktop_2015``, ``directxtk12_desktop_2017``, ``directxtk12_uwp`` in the same project. Also make sure you are *not* using ``directxtk_desktop_2015``, ``directxtk_desktop_2015``, or ``directxtk_uwp`` (i.e. the DX11 versions) – Chuck Walbourn Apr 23 '20 at 19:11
  • @ChuckWalbourn I meant commandList. I have installed `directxtk12_desktop_2015` version `2019.12.17.1` and that is the only NuGet package in my project. I checked it directly by opening the “packages” folder in the explorer – Artur Apr 23 '20 at 19:20
  • You only have one command list per frame from DeviceResources. You have to create your own command-list and handle submitting that work to use more than one. See [Microsoft Docs](https://learn.microsoft.com/en-us/windows/win32/direct3d12/executing-and-synchronizing-command-lists). – Chuck Walbourn Apr 23 '20 at 20:59

1 Answers1

1

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?

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
  • Thank You, for feedback, I editted my answer. After drawing few spheres I agree that the depth buffer is set wrong, so how it should be set? I also didn’t understand how should I make sphere with custom colors (not a texture) – Artur Apr 23 '20 at 18:52
  • Understood, how to set depth buffer, what about custom colour? – Artur Apr 23 '20 at 18:59
  • Updated answer with the details. Also added this example to the ``GeometricPrimitive`` wiki for [DX11](https://github.com/microsoft/DirectXTK/wiki/GeometricPrimitive#custom-vertex-format) and [DX12](https://github.com/microsoft/DirectXTK12/wiki/GeometricPrimitive#custom-vertex-format). – Chuck Walbourn Apr 23 '20 at 21:01