Basic Rendering

Started by
5 comments, last by Auskennfuchs 10 years, 3 months ago

I have found a couple tutorials on how to use DirectX11 and I have gotten a working example that renders one triangle. However when I try and enter 3 more points in to render(6 in total) it only shows the first triangle. I set the topology(using IASetPrimitiveTopology) to D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST which to the best of my understanding should draw a new triangle every 3 points.


How do I render more than one object/set of points?
Am I missing something critical about the way the rendering process works in DirectX?


Here is the code:


//********** Setup **********//
//Compile Vertex Shader
HR(D3DCompileFromFile(	
    shaderPath,	
    nullptr,	
    nullptr,	
    "VShader",	
    "vs_5_0",	
    shaderFlags,	
    0,	
    &VS,	
    nullptr	));

//Compile Pixel Shader
HR(D3DCompileFromFile(	
    shaderPath,	
    nullptr,	
    nullptr,	
    "PShader",	
    "ps_5_0",	
    shaderFlags,	
    0,	
    &PS,	
    nullptr	));	

//Encapsulate both shaders in shader objects
HR(m_pDevice->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS));
m_pDevice->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);

//Set the shader objects
m_pImmediateContext->VSSetShader(pVS, 0, 0);
m_pImmediateContext->PSSetShader(pPS, 0, 0);

//For playing around
VERTEX OurVertices[] ={	
    { 0.0f, 0.5f, 0.0f, { 0.0f, 1.0f, 0.0f, 1.0f } },	
    { 0.45f, -0.5, 0.0f, { 0.0f, 1.0f, 1.0f, 0.0f } },	
    { -0.45f, -0.5f, 0.0f, { 0.0f, 0.0f, 1.0f, 1.0f } },	
    { 0.0f, 0.5f, 0.0f, { 0.0f, 1.0f, 0.0f, 1.0f } },	
    { 0.45f, -0.5, 0.0f, { 0.0f, 1.0f, 1.0f, 0.0f } },	
    { -0.45f, -0.5f, 0.0f, { 0.0f, 0.0f, 1.0f, 1.0f } }
};

//Vertex buffer description
ZeroMemory(&bd, sizeof(bd));//Reserve memory for Vertex buffer description
bd.Usage = D3D11_USAGE_DYNAMIC;//Write access, access by CPU and GPU
bd.ByteWidth = sizeof(VERTEX) * 3;//Size of vertex struct * 3(x3 b/c x,y,z)
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;//Use as a vertex buffer
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;//Allow CPU to write buffer
m_pDevice->CreateBuffer(&bd, NULL, &pVBuffer);//Create vertex buffer

//Working with vertex buffer
m_pImmediateContext->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);//Map the buffer, pVBuffer is the buffer and ms is where we will put the buffer
memcpy(ms.pData, OurVertices, sizeof(OurVertices));//Copy data to mapped buffer
m_pImmediateContext->Unmap(pVBuffer, NULL);//Unmap buffer, allowing GPU to use buffer	

D3D11_INPUT_ELEMENT_DESC ied[] =//Describe to CPU how data is stored	
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};

m_pDevice->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout);
m_pImmediateContext->IASetInputLayout(pLayout);//Set layout, aply

//********************//

//********** Actual rendering **********//
m_pImmediateContext->ClearRenderTargetView(m_pRenderTargetView, DirectX::Colors::CornflowerBlue);//Clear background to blue
    stride = sizeof(VERTEX);//Size of VERTEX
    offset = 0;//Offset in which we start reading VERTEX bytes
    m_pImmediateContext->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);//Tells GPU which vertices to read
    m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);//Tells the GPU what type of geomitry to render(Points, Line segments, line, triangle, triangle strip).
    m_pImmediateContext->Draw(3, 0);//Draw 3 vertices  and start at vertice 0
HR(m_pSwapChain->Present(0, 0));//Display background(From buffer)
//********************//

EDIT:
I figured out that I need to run lines 57-59 which copy the vertexes to GPU memory and then run lines 79-81 which do the actual rendering for each object I want to render. For some reason I can't put for than 3 vertexes in OurVertices and to render another triangle you have to create a new array of vertexes and run the lines mentioned above.

Questions that remain:
Why can't I put more than 3 vertexes in OurVertices? Isn't the D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST setting supposed to let me do that? This is very critical because without this functioning how I think it should I can only draw 2d triangles.

Advertisement

Looks like the formatting got screwed up on your code but from what I can see your doing:


m_pImmediateContext->Draw(3, 0)

Which only draws the first 3 vertices. It should be:


m_pImmediateContext->Draw(6, 0)

Looks like the formatting got screwed up on your code but from what I can see your doing:

I fixed that, seems like after the first edit it lost all carriage returns.

When I change it to 6 I get a DEVICE_DRAW_VERTEX_BUFFER_TOO_SMALL warning in the output window and it only shows 3. with this code


//Actual rendering
m_pImmediateContext->ClearRenderTargetView(m_pRenderTargetView, DirectX::Colors::CornflowerBlue);//Clear background to blue
	stride = sizeof(VERTEX);//Size of VERTEX
	offset = 0;//Offset in which we start reading VERTEX bytes

	VERTEX OurVertices[] =
	{
		{ 0.0f, 0.5f, 0.0f, { 0.0f, 1.0f, 0.0f, 1.0f } },
		{ 0.45f, -0.5, 0.0f, { 0.0f, 1.0f, 1.0f, 0.0f } },
		{ -0.45f, -0.5f, 0.0f, { 0.0f, 0.0f, 1.0f, 1.0f } },
		{ -0.5f, 0.5f, 0.0f, { 0.0f, 1.0f, 0.0f, 1.0f } },
		{ -0.1f, -0.5, 0.0f, { 0.0f, 1.0f, 1.0f, 0.0f } },
		{ -1.0f, -0.5f, 0.0f, { 0.0f, 0.0f, 1.0f, 1.0f } }
	};

	m_pImmediateContext->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);//Map the buffer, pVBuffer is the buffer and ms is where we will put the buffer
	memcpy(ms.pData, OurVertices, sizeof(OurVertices));//Copy data to mapped buffer
	m_pImmediateContext->Unmap(pVBuffer, NULL);//Unmap buffer, allowing GPU to use buffer

	m_pImmediateContext->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);//Tells GPU which vertices to read
	m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);//Tells the GPU what type of geomitry to render(Points, Line segments, line, triangle, triangle strip).
	m_pImmediateContext->Draw(6, 0);//Draw 3 vertices  and start at vertice 0
HR(m_pSwapChain->Present(0, 0));//Display background(From buffer)

I had tried doing that before because this is what logically makes sense, but it didn't work. But when I changed LN47, bd.ByteWidth = sizeof(VERTEX) * 3;//Size of vertex struct * 3(x3 b/c x,y,z) to times 6 it works out fine. If you could explain this whole process to me that would be cool.

ByteWidth is the whole size of your vertexbuffer. So you have 6 vertices defined in your OurVertices-array then you also have to allocate the vertexbuffer for same amount of space.

For explanation (simple):

Just imagine the OurVertices-array is a data-container on CPU-side. This can't directly be accessed by the GPU. To transfer the content you have to create a data-container on GPU-side and this is the vertexbuffer. The data is transfered through Map->memcpy->Unmap. Map opens a "pointer" to the allocated vertexbuffer and you can copy the data. Unmap closes the "pointer" and the gpu now knows it can access the containing data for rendering. The transfer is an expensive process and you should do it as few as possible. So for static geometry just once when creating the vertexbuffer and not on every frame. Dynamic buffers like particles should be updated when needed. You can also just update a part of the buffer. You can also delete the buffer on CPU-side, the vertexbuffer will still contain all data until it will be released.

As said above you have:

  1. bd.ByteWidth = sizeof(VERTEX) * 3;

Which sets the size of the whole vertex buffer, with this you are only able to store a maximum of 3 vertices. The error you are getting now is literally as it says, the buffer is too small to accommodate 6 vertices.

As said above you have:

  1. bd.ByteWidth = sizeof(VERTEX) * 3;

Which sets the size of the whole vertex buffer, with this you are only able to store a maximum of 3 vertices. The error you are getting now is literally as it says, the buffer is too small to accommodate 6 vertices.

How would I deal with a bunch of object(A bunch of diferent arrays)?

Create the same amount of vertexbuffers, one for each object. The vertex-struct for each object can be different but you have to draw all objects with a single draw-call.

Alternative: One big vertexbuffer, copy all objects into this (one after another in memorylayout like an array). But the vertex-struct has to be the same for all objects. Advantage is, you can draw all objects with one single draw-call if you use the trianglelist-topology. If not do a drawcall for every object but with different starting indices obvioulsly.

This topic is closed to new replies.

Advertisement