c++graphicsdirectxdirect3ddirectx-12

How to draw a sphere in DirectX 12?


I want to draw spheres in my DirectX 12 application. I only support vertex and pixel shaders for now. The idea is to generate a vertex and an index buffer to draw the sphere.
The sphere will have the following properties:
a) A radius of 1
b) Center will be will be the world center(0,0,0).
c) Subdivision. Controlling how mush vertex/indices are generated.

(a) and (b) will also allowing me to scale and translate the basic sphere inside vertex shaders.
So how to generate these vertex and index buffers?

Vertices layout will look like this:

D3D12_INPUT_ELEMENT_DESC inputLayoutElement[] =
{
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
};

Then drawing:

commandList->SetPipelineState(m_PSO);

commandList->SetGraphicsRootSignature(m_rootSignature);
commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

commandList->IASetVertexBuffers(0, 1, &m_vertexBuffer); // Vertex buffer here
commandList->IASetIndexBuffer(&m_indexBuffer);// Index buffer here

commandList->DrawIndexedInstanced(m_indexCount, 1, 0, 0, 0);

So basically I need to generate an array of vertices for the vertex buffer and an array of indices for the index buffer.

1) Vertex buffer is created using an array of vertices:

std::vector<Math::Vec3> 

2) Index buffer is created using an array of indices:

std::vector<nbUint32>

So HOW to generate them ?

My software uses a right handed coordinate system:
RHS

I saw a similar post but it is unanswered. And the comments suggest to use a tessellation shader that I don't support.


Solution

  • So thanks to Chuck Walbourn link I have it working.
    Generation look like this:

    
    
    SphereVertexAndIndexBuffers::SphereVertexAndIndexBuffers()
    {
            using namespace DirectX;
    
            // The arrays to generate.
            std::vector<Math::Vec3> vertices;
            std::vector<uint32_t> indices;
    
            // @See : https://github.com/microsoft/DirectXTK12/blob/main/Src/Geometry.cpp
            static const uint32_t tessellation = 16;
            static const float radius = 1.0f;
    
            const uint32_t verticalSegments = tessellation;
            const uint32_t horizontalSegments = tessellation * 2;
    
            // Create rings of vertices at progressively higher latitudes.
            for (uint32_t i = 0; i <= verticalSegments; i++)
            {
                const float v = 1 - float(i) / float(verticalSegments);
    
                const float latitude = (float(i) * XM_PI / float(verticalSegments)) - XM_PIDIV2;
                float dy, dxz;
    
                XMScalarSinCos(&dy, &dxz, latitude);
    
                // Create a single ring of vertices at this latitude.
                for (uint32_t j = 0; j <= horizontalSegments; j++)
                {
                    const float u = float(j) / float(horizontalSegments);
    
                    const float longitude = float(j) * XM_2PI / float(horizontalSegments);
                    float dx, dz;
    
                    XMScalarSinCos(&dx, &dz, longitude);
    
                    dx *= dxz;
                    dz *= dxz;
    
                    const XMVECTOR normal = XMVectorSet(dx, dy, dz, 0);
                    const XMVECTOR textureCoordinate = XMVectorSet(u, v, 0, 0);
    
                    XMVECTOR xmvertex = XMVectorScale(normal, radius);
    
                    XMFLOAT3 float3Vertex;
                    XMStoreFloat3(&float3Vertex, xmvertex);
         
                    vertices.push_back(Math::Vec3(float3Vertex.x, float3Vertex.y, float3Vertex.z));
                }
            }
    
            // Fill the index buffer with triangles joining each pair of latitude rings.
            const uint32_t stride = horizontalSegments + 1;
    
            for (uint32_t i = 0; i < verticalSegments; i++)
            {
                for (uint32_t j = 0; j <= horizontalSegments; j++)
                {
                    const uint32_t nextI = i + 1;
                    const uint32_t nextJ = (j + 1) % stride;
    
                    indices.push_back(i * stride + j);
                    indices.push_back(nextI * stride + j);
                    indices.push_back(i * stride + nextJ);
    
                    indices.push_back(i * stride + nextJ);
                    indices.push_back(nextI * stride + j);
                    indices.push_back(nextI * stride + nextJ);
                }
            }
    
    
            _ASSERT(GraphicResourceAllocatorPtr<DX12_GRAPHIC_ALLOC_PARAMETERS>->createVertexBuffer(
                vertices, m_vtxBuffer)
            );
    
            _ASSERT(GraphicResourceAllocatorPtr<DX12_GRAPHIC_ALLOC_PARAMETERS>->createIndexBuffer(
                indices, m_idxBuffer)
            );
    }
    
    
    
    
    When rendering use the D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST topology