We have discussed how to initialize the D3D11Device device initialization and so on. The drawing figure mentioned here will be extended in the project of the previous article and drawn on the screen. The smallest unit in 3D rendering is a triangle. No matter how big or small we see it, one or more triangles are formed by different directions and angles, of course, this will involve many geometric issues in mathematics. The most tragic thing is that I did not learn algebra and geometry well in college, and I forgot to learn it. However, the Directx SDK solves a lot of geometric problems for us, and the results can be obtained through their methods. After talking about so many purposes, I will tell you that you must master advanced application, you must learn the basic knowledge, so here we will learn how to draw a triangle on the screen and apply color.
A triangle consists of three points, which can also be called coordinates. In the coordinate system, three different points can form a unique triangle, that is, the only surface. I think 3D images are composed of many faces, that is why the smallest unit is triangle. To make the GPU (that is, the CPU in the video card) render a triangle, we must tell him the coordinates of the three points, so that it can be displayed on the screen. For example, in 2D, to draw a triangle in the following figure on the screen, we must tell the GPU the coordinates of the three vertices (0, 0), (0, 1), (1, 0, so that the GPU can draw them.
We already know how to tell GPU to vertices, but how can we tell them? In Direct3D 11, Vertex information, such as the coordinates of Three triangle vertices, is stored in a cache resource called Vertex Buffer ). We must create a large enough vertex cache so that it can carry the coordinate information of the three vertices of the triangle.
INPUT LAYOUT
A vertex contains not only one coordinate, but also one or more color values and texture coordinates. Input Layout defines how the information is stored in memory: different data types have different sizes. Of course, different sizes also determine different storage sequence. Similar to C, a vertex is generally defined using a structure. Here, we only need to define the coordinates of a triangle vertex, so we only need to use XMFLOAT3 to define a coordinate. The specific code is as follows:
// 3D Vector; 32 bit floating point components
Typedef struct _ XMFLOAT3
{
FLOAT x;
FLOAT y;
FLOAT z;
# Ifdef _ cplusplus
_ XMFLOAT3 (){};
_ XMFLOAT3 (FLOAT _ x, FLOAT _ y, FLOAT _ z): x (_ x), y (_ y), z (_ z ){};
_ XMFLOAT3 (const float * pArray );
_ XMFLOAT3 & operator = (CONST _ XMFLOAT3 & Float3 );
# Endif // _ cplusplus
} XMFLOAT3;
// The above is the structure information of XMFLOAT3, the coordinate structure in 3D
Struct SimpleVertex
{
XMFLOAT3 Pos; // Position
};
We have defined a SimpleVertex structure to store the vertex coordinates of a triangle. To enable the GPU to understand and obtain relevant information in the memory, we must use the Input Layout. In Direct 3D 11, an Input Layout is defined as the structure information that can be recognized by the GPU. Each vertex attribute can be described using a structure named D3D11_INPUT_ELEMENT_DESC. Different vertex information can be solved by defining an array, so that each vertex can be described. Let's take a look at the specific attributes of this structure.
Typedef struct D3D11_INPUT_ELEMENT_DESC {
LPCSTR SemanticName;
UINT SemanticIndex;
DXGI_FORMAT Format;
UINT InputSlot;
UINT AlignedByteOffset;
D3D11_INPUT_CLASSIFICATION InputSlotClass;
UINT InstanceDataStepRate;
} D3D11_INPUT_ELEMENT_DESC;
Attribute description:
SemanticName: A character used to describe the purpose or name. Any string that conforms to the C-language structure can be used and case-insensitive. For example, the "POSITION" string can be used to describe vertex coordinates.
SemanticIndex: This is used to describe the index. When the SemanticName is the same, you can use the index to describe which one is required currently. Because a vertex may contain multiple colors, texture coordinates, and so on. For example, multiple colors can be described using COLOR0 or COLOR1, or COLOR, fill SemanticIndex with 0 and 1.
Format: Specifies the Data Type of the data. For example, DXGI_FORMAT_R32G32B32_FLOAT describes three 32-bit float data types, that is, 12 bytes. DXGI_FORMAT_R16G16B16A16_UINT indicates four 16-bit uint data types, that is, the length of 8 bytes.
InputSlot: Input slot. As mentioned above, each Vertex information is identified by a Vertex Buffer input by the GPU. in Direct 3D 11, multiple Vertex information can be simultaneously input, there can be a maximum of 16, so that the GPU needs to know which Vertex Buffer information will be used, that is, the value will be between 0 and 15.
AlignedByteOffset: Memory offset, indicating the starting offset of the current cache memory of the GPU.
InputSlotClass: This is generally filled with D3D11_INPUT_PER_VERTEX_DATA. When using the instance data type, D3D11_INPUT_PER_INSTANCE_DATA will be used. This is relatively advanced and may be encountered in our future studies. It is not clear here, let's go first.
InstanceDataStepRate: this parameter is used when D3D11_INPUT_PER_INSTANCE_DATA is used. If not, it must be set to 0.
With the above information, we can define our own
D3D11_INPUT_ELEMENT_DESC. The Code is as follows:
1 // Define the input layout
2 D3D11_INPUT_ELEMENT_DESC layout [] =
3 {
4 {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
5 };
6 UINT numElements = ARRAYSIZE (layout );
Vertex Layout
The Vertex layout is mainly used to provide Calculation for Vertex Shader [Note: Maybe this description is incorrect]. To create a Vertex layout, the Vertex coloring machine needs to input a signature, we use the ID3DBlob interface object to describe it, while the ID3DBlob interface uses D3DX11CompileFromFile to retrieve the binary data of the vertex shader containing the signature. As long as we have this data, we can use the ID3D11Device: CreateInputLayout () method to create our Vertex Layout object and use the ID3D11DeviceContext: IASetInputLayout () method to activate it, the Code is as follows:
2 if (FAILED (g_pd3dDevice-> CreateInputLayout (layout, numElements, pVSBlob-> GetBufferPointer (),
3 pVSBlob-> GetBufferSize (), & g_pVertexLayout )))
4 return FALSE;
5 // Set the input layout
6 g_pImmediateContext-> IASetInputLayout (g_pVertexLayout );
Create a Vertex Buffer
Once we know the above content, we still need to do one thing. during initialization, we must create a Vertex Buffer and carry the data information of this Vertex. To create a Vertex Buffer, you must fill in two structures: D3D11_BUFFER_DESC and D3D11_SUBRESOURCE_DATA, and then use the ID3D11Device: CreateBuffer () method to create the Buffer. The D3D11_BUFFER_DESC Structure describes the content object to be created by the Vertex Buffer.
D3D11_SUBRESOURCE_DATA contains specific data information, which will be copied during creation. The cache creation and initialization are completed at the same time. After the creation, you can bind the cache to the device using the ID3D11DeviceContext: IASetVertexBuffers () method, then we can display the code on the screen as follows:
SimpleVertex vertices [] =
{
XMFLOAT3 (0.0f, 0.5f, 0.5f ),
XMFLOAT3 (0.5f,-0.5f, 0.5f ),
XMFLOAT3 (-0.5f,-0.5f, 0.5f ),
};
D3D11_BUFFER_DESC bd;
ZeroMemory (& bd, sizeof (bd ));
Bd. Usage = D3D11_USAGE_DEFAULT;
Bd. ByteWidth = sizeof (SimpleVertex) * 3;
Bd. BindFlags = D3D11_BIND_VERTEX_BUFFER;
Bd. CPUAccessFlags = 0;
Bd. MiscFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory (& InitData, sizeof (InitData ));
InitData. pSysMem = vertices;
If (FAILED (g_pd3dDevice-> CreateBuffer (& bd, & InitData, & g_pVertexBuffer )))
Return FALSE;
// Set vertex buffer
UINT stride = sizeof (SimpleVertex );
UINT offset = 0;
G_pImmediateContext-> IASetVertexBuffers (0, 1, & g_pVertexBuffer, & stride, & offset );
Primitive Topology (prototype Topology)
From the above we can know that if we want to present a triangle, we need to inform the GPU of the three vertices, so if the two triangles have to tell the GPU6 vertices, if a quadrilateral (composed of two triangles) has two vertices, PrimitiveTopology is used to solve this problem. In a quadrilateral, a quadrilateral can be drawn as long as the vertex information is passed in, which can be well understood.
For example, if you want to present A graph in 3a, as long as you tell the GPU that it is A vertex, the GPU will directly draw this quadrilateral. Of course, you should also pay attention to the sequence: a B C D, in fact, Vertex Buffer describes a B c and B c d. In this way, B C is shared, and of course it is the same in 3b. You only need to set the following code:
G_pImmediateContext-> IASetPrimitiveTopology (D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
The next step is to draw a triangle. the above operations are performed after device initialization. Vertex and pixel coloring devices are required to draw triangles. The specific code is as follows:
Void Render ()
{
// Clear the back buffer
Float ClearColor [4] = {0.0f, 0.125f, 0.3f, 1.0f}; // red, green, blue, alpha
G_pImmediateContext-> ClearRenderTargetView (g_pRenderTargetView, ClearColor );
// Render a triangle
G_pImmediateContext-> VSSetShader (g_pVertexShader, NULL, 0 );
G_pImmediateContext-> PSSetShader (g_pPixelShader, NULL, 0 );
G_pImmediateContext-> Draw (3, 0 );
// Present the information rendered to the back buffer to the front buffer (the screen)
G_pSwapChain-> Present (0, 0 );
}
The final result is as follows: