Jump to content
  • Advertisement
Sign in to follow this  
SteveHatcher

How does DirectX know what to draw?

This topic is 2144 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi Guys,

 

I am having difficulty understanding how direct3d knows what geometry I want to draw to the screen each time a Draw() command is called. For instance, lets say I create a triangle with the following code:

Vertex TriangleVertex[] =
	{
		Vertex(0.0f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f),
		Vertex(0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f),
		Vertex(-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f),
	};

	D3D11_BUFFER_DESC TriangleVertexBufferDesc;
	ZeroMemory(&TriangleVertexBufferDesc, sizeof(TriangleVertexBufferDesc));

	TriangleVertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	TriangleVertexBufferDesc.ByteWidth = sizeof(Vertex)* 3;
	TriangleVertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	TriangleVertexBufferDesc.CPUAccessFlags = 0;
	TriangleVertexBufferDesc.MiscFlags = 0;

	D3D11_SUBRESOURCE_DATA TriangleVertexBufferData;

	ZeroMemory(&TriangleVertexBufferData, sizeof(TriangleVertexBufferData));
	TriangleVertexBufferData.pSysMem = TriangleVertex;
	hr = d3d11Device->CreateBuffer(&TriangleVertexBufferDesc, &TriangleVertexBufferData, &triangleVertBuffer);

	UINT stride = sizeof(Vertex);
	UINT offset = 0;

	d3d11DevCon->IASetVertexBuffers(0, 1, &triangleVertBuffer, &stride, &offset);

	hr = d3d11Device->CreateInputLayout(layout, numElements, VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), &vertLayout);
	d3d11DevCon->IASetInputLayout(vertLayout);
	d3d11DevCon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

Up to this stage its somewhere in the system as as ID3D11Buffer* named triangleVertBuffer.

 

Then to draw just the triangle I simply need to put it through any size shape or position manipulations, so for this case lets say we leave it alone:

	triangleWorld = XMMatrixIdentity();
	WVP = triangleWorld * camView * camProjection;
	cbPerObj.WVP = XMMatrixTranspose(WVP);
	d3d11DevCon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0);
	d3d11DevCon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer);
	d3d11DevCon->Draw(3, 0);

Which gives me my lovely triangle. So now I want to add another shape defined by a totally different set of vertices. Lets say the code above is exactly the same except I replace every "Triangle"  with "Square" for the naming, and update the appropriate bitewidths. What I am confused with is after we call IASetVertexBuffer(), we don't use that name again. So how do I tell directX which shapes I want to draw. Right now the draw command seems to just splash everything on the screen.

 

Just in case its needed my HLSL code is

cbuffer cbPerObject
{
	float4x4 WVP;
};

struct VS_OUTPUT
{
	float4 Pos : SV_POSITION;
	float4 Color : COLOR;
};

VS_OUTPUT VS(float4 inPos : POSITION, float4 inColor : COLOR)
{
    VS_OUTPUT output;
    output.Pos = mul(inPos, WVP);
    output.Color = inColor;

    return output;
}

float4 PS(VS_OUTPUT input) : SV_TARGET
{
    return input.Color;
}

Thanks

 

 

Share this post


Link to post
Share on other sites
Advertisement

The triangle geometry is in the vertex buffer. If you want more geometry, you have two options; either make the vertex buffer bigger and add more stuff to it, or create an another vertex buffer with other geometry and switch between the buffers using IASetVertexBuffers. Just because the sample only calls that once, does not mean that you cannot call it more than once biggrin.png In fact, most real-world code switches vertex buffers multiple times per frame.

Edited by Nik02

Share this post


Link to post
Share on other sites

Hi, thanks a lot for the reply.

 

So to make sure I understand: when I get to my render() function, set the buffer to the geometry I want:

IASetVertexBuffers(0, 1, &triangleVertBuffer, &stride, &offset);

Then send the geometry through its transformations then draw. I updated my code and that seems to work well.

 

Out of interest, what is the actual implementation of making the vertex buffer bigger and adding more stuff to it? Is there an advantage to doing it one way or the other?

 

Thank you very much.

Share this post


Link to post
Share on other sites

When you Create the vertex buffer, you effectively ask the system to allocate a block of memory that can be accessed by the GPU as vertex data. When you then Set the buffer, you tell the GPU to take the vertex data for subsequent draw calls from that buffer (or multiple buffers).

 

When you issue the Draw* call, the device executes the pipeline that runs the input assembler, the shaders and the rasterizer. The wvp matrix in your code is just data which can be read by the vertex shader (which is why you put that into a constant buffer); your vertex shader operations handle it as a matrix with which to multiply the vertex positions to transform your stuff. The vertex shader could just as well run almost anything else, but the usage in your code is a common case. In a nutshell, you don't perform the transformation in the CPU-side code - the GPU does - but you supply the coefficients for the vertex shader for the transformation as well as the shader program itself.

 

You can't reallocate an existing buffer; if you want more space, create the buffer with larger size to begin with.

 

Using as few buffers as possible is most efficient, since the act of switching buffers (and therefore issuing multiple draw calls) has its own price. The API calls (almost any method of the immediate context) are relatively expensive, so use them as sparingly as you can. 

Edited by Nik02

Share this post


Link to post
Share on other sites

Thanks for that, that's one of the few descriptions I have actually understood when searching through the web of this info. Right Now I am just setting the buffer then drawing from that as I understand it more. Down the track I will look at the other method, but for my first project I will keep it simple.

Share this post


Link to post
Share on other sites

Keeping it simple is a good strategy.

 

Later, when you find bottlenecks, it is time to optimize.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!