Direct3D Tutorial 2:rendering a Triangle_direct3d 11 tutorial 2: Rendering a triangle

Source: Internet
Author: User

Profile

In the previous tutorial, we built a minimal Direct3D 11 application that was used to output a single color on a window. In this tutorial, we will extend the application to render a single-color triangle on the screen. We'll associate the triangle with the process of setting up the data mechanism.

The output of this tutorial is to render a triangle in the center of the window.

Resource Directory

(SDK root) \samples\c++\direct3d11\tutorials\tutorial02

Github-learndirectx-dx3d11 tutorial02 (source has been uploaded to GitHub)

Elements of a triangle

A triangle is defined by its three points, also known as vertices. A set of three vertices with a unique position defines a unique triangle. In order for the GPU to render a triangle, we must tell it the position of the three vertices of the triangle. To give a 2D example, suppose we want to render a triangle in example 1. We pass three vertices to the GPU along with the position (0,0) (0,1) and (1,0), and then the GPU has enough information to render the triangles we want.

Figure 1.2D triangles defined by three vertices

So now we know we have to pass three locations to the GPU to render triangles. How do we pass this information to the GPU? In Direct3D 11, vertex information such as location is stored in the buffer resource. It is not surprising that the buffer used to store vertex information is called a vertex buffer. We must create a sufficiently large vertex buffer for three vertices and populate it with the vertex position. In Direct3D 11, the application must specify the buffer size (in bytes) when creating the buffer resource. We know that the buffer must be large enough to hold three vertices, but how many bytes per vertex do we need? To answer this question, you need to understand the vertex layout.

Input layout

Vertex has a position. Typically, it also has other properties, such as normals, one or more colors, texture coordinates (for texture mapping), and so on. Vertex layouts Define the location of these properties in memory: The data type used for each property, the size of each property, and the order of the properties in memory. Because properties typically have different types, similar to fields in a C structure, vertices are usually represented by structs. The size of the vertices can be easily obtained from the size of the structure.

In this tutorial, we only work with vertex locations. Therefore, we use a single field of the XMFLOAT3 type to define the vertex structure. This type is a vector of three floating-point components, typically a data type for a 3D position.

struct simplevertex{    XMFLOAT3 Pos;  Position};

  

We now have a structure that represents our vertices. It is responsible for storing the vertex information in system memory in our application. However, when we supply a vertex buffer with vertices to the GPU, we just give it a piece of memory. The GPU must also know the vertex layout in order to extract the correct properties from the buffer. To accomplish this, you need to use the input layout.

In Direct3D 11, the input layout is a Direct3D object that describes the structure of vertices in a way that the GPU can understand. You can use the D3D11_INPUT_ELEMENT_DESC structure to describe each vertex property. An application defines an array of one or more d3d11_input_element_desc and then uses that array to create an input layout object that describes the vertex as a whole. Now we'll cover the fields of d3d11_input_element_desc in detail.

Semanticname

Semanticname is a string that contains words that describe the nature or purpose (or semantics) of this element. The word can be any form of a C identifier, or any form we choose. For example, a good semantic name for vertex positions is POSITION. Semantic names are case-insensitive.

Semanticindex

Semanticindex added the semantic name. Vertices can have multiple properties of the same nature. For example, it can have 2 2 group color. Instead of using the semantic name with the number appended, such as " color0 " and " color1 "These two elements can share a single semantic name" color "with different semantic indexes 0 and 1

format

format defines the data type to use for this element. For example, dxgi_format_r32g32b32_float There are three formats 32 bit floating-point number, leaving element length 12 bytes. dxgi_format_r16g16b16a16_uint The format has four 16 Span style= "FONT-FAMILY:CALIBRI;" >8 bytes.

Inputslot

As described earlier, direct3d by using a vertex buffer. gpu direct3d one Span style= "FONT-FAMILY:CALIBRI;" >gpu provide multiple vertex buffers, accurately 16 Span style= "font-family: the song Body;" > Each vertex buffer is bound to 0 to 15 field tell gpu which vertex buffer it should get for this element.

Alignedbyteoffset

Vertices are stored in the vertex buffer, The top-level buffer is just a piece of memory. alignedbyteoffset gpu start getting the memory location for this element's data.

Inputslotclass

The value of this field is typically d3d11_input_per_vertex_data inputslotclass set to d3d11_input_per_instance_data instancing is an advanced direct3d d3d11_input_per_vertex_data

Instancedatasteprate

This field is used for instantiation. Since we do not use the instantiation, this field must be set to 0.

Now we can define the D3D11_INPUT_ELEMENT_DESC array and create the input layout:

Define the input layoutd3d11_input_element_desc layout[] ={    {"POSITION", 0, dxgi_format_r32g32b32_float, 0, 0, D3D 11_input_per_vertex_data, 0},  }; UINT numelements = ARRAYSIZE (layout);

  

Vertex layout

In the next tutorial, we'll explain the technical objects and associated shaders. For now, we will focus on creating Direct3D 11 vertex layout objects for this technology. However, we will understand that the vertex shader is tightly coupled to this vertex layout. The reason is that creating a vertex layout object requires the input signature of the vertex shader. We use the Id3dblob object returned from D3dx11compilefromfile to retrieve the binary data representing the input signature of the vertex shader. With this data, we can call Id3d11device:: Createinputlayout () to create a vertex layout object and set it to the active vertex layout using Id3d11devicecontext:: Iasetinputlayout (). The code to complete all of these operations is as follows:

Create the input layoutif (FAILED (g_pd3ddevice->createinputlayout (Layout, numelements, pvsblob-> GetBufferPointer (),         pvsblob->getbuffersize (), &g_pvertexlayout)))    return false;//Set the input Layoutg_pimmediatecontext->iasetinputlayout (g_pvertexlayout);

  

Create a vertex buffer

One thing we need to do during initialization is to create a vertex buffer that holds the vertex data. To create a vertex buffer in Direct3D 11, we fill in two structures d3d11_buffer_desc and D3d11_subresource_data, and then call Id3d11device:: Createbuffer ().

D3d11_buffer_desc describes the vertex buffer object to create, and D3d11_subresource_data describes the actual data that will be copied to the vertex buffer during creation. The creation and initialization of the vertex buffers is done at once, so we do not need to initialize the buffers in the future. The data that will be copied to the vertex buffer is the vertex, which is an array of three simple structures. Select the coordinates in the vertex array so that you see a triangle in the middle of the application window when using the shader rendering. After creating the vertex buffer, we can call Id3d11devicecontext:: Iasetvertexbuffers () to bind it to the device. The complete code is as follows:

Create vertex Buffersimplevertex vertices[] ={    XMFLOAT3 (0.0f, 0.5f, 0.5f),    XMFLOAT3 (0.5f, -0.5f, 0.5f), 
   
    XMFLOAT3 ( -0.5f, -0.5f, 0.5f),};D 3D11_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 ( AMP;BD, &initdata, &g_pvertexbuffer)))    return false;//Set vertex bufferuint stride = sizeof (Simplevertex ); UINT offset = 0;g_pimmediatecontext->iasetvertexbuffers (0, 1, &g_pvertexbuffer, &stride, &offset);
   

  

Original topology

The original topology is how the GPU obtains the three vertices needed to render a triangle. As we've discussed above, in order to render a single triangle, the application needs to send three vertices to the GPU. Therefore, there are three vertices in the vertex buffer. What if we want to render a two triangle? One way is to send 6 vertices to the GPU. The top three vertices define the first triangle, and the next three vertices define the second triangle. This topology is called a triangle list. Triangle lists have the advantage of being easy to understand, but in some cases they are very inefficient. This occurs when a continuously rendered triangle shares a vertex. For example, the left side of Figure 3a shows a square consisting of two triangles: ABC and CB D. (By convention, triangles are usually defined by their vertices in a clockwise order.) If we use a triangle list to send these two triangles to the GPU, our vertex buffers will:

A b c C B D

Note that B and C appear two times in the vertex buffers because they are shared by two triangles.

Figure 3a contains a square consisting of two triangles; Figure 3b contains a Pentagon consisting of three triangles.

If we can tell the GPU to render the second triangle, we can make the vertex buffer smaller, rather than get all three vertices from the vertex buffer, use the 2 vertices in the previous triangle, and get only 1 vertices from the vertex buffer. It turns out that this is supported by Direct3D, a topological structure called a triangular stripe. When you render a triangle stripe, the first triangle is defined by the top three vertices in the vertex buffer. The next triangle is defined by the last two vertices of the previous triangle plus the next vertex in the vertex buffer. In the example of a block in Figure 3 A, using a triangular stripe, the vertex buffer looks like this:

A B C D

Top three vertices a B C defines the first triangle. The second triangle is defined by B and C, which is the last two vertices of the first triangle plus d. Therefore, by using a triangular stripe topology, the vertex buffer size changes from 6 vertices to 4 vertices. Similarly, for three triangles, in example 3b triangles, using a triangle list will require a vertex buffer, for example:

A b c c B D C D E

With triangular bands, the size of the vertex buffers is significantly reduced:

A B C D E
As you may have noticed, in the triangle strip example, the second triangle is defined as B C D. These three vertices do not form a clockwise order. This is a natural phenomenon that uses triangular bands. to overcome this problem, the GPU automatically exchanges the order of two vertices from the previous triangle. it does this only for the second triangle, the fourth triangle, the sixth triangle, the eighth triangle, and so on. This ensures that each triangle is defined by the vertex in the correct winding order (in this case, clockwise). In addition to triangle lists and triangle bands, Direct3D 11 supports many other types of original topologies. we won't discuss them in this tutorial.

In our code, we have a triangle, so what we specify is not important. However, we have to specify some content, so we chose the triangle list.

Set Primitive Topologyg_pimmediatecontext->iasetprimitivetopology (d3d11_primitive_topology_trianglelist);

  

Render Triangles

The last item missing is the code that performs the actual rendering of the triangle. We created two shaders for rendering, vertex shader and pixel shader. The vertex shader is responsible for converting each vertex of the triangle to the correct position. The pixel shader is responsible for calculating the final output color of each pixel of the triangle. This will be described in more detail in the next tutorial. To use these shaders, we must call Id3d11devicecontext:: Vssetshader () and Id3d11devicecontext:: Pssetshader (). The last thing we do is call Id3d11devicecontext:: Draw (), which commands the GPU to render using the current vertex buffer, the vertex layout, and the original topology. The first parameter of Draw () is the number of vertices to send to the GPU, and the second parameter is the index of the first vertex to start sending. Because we render a triangle and we render it from the beginning of the vertex buffer, we use 3 and 0 respectively as two parameters. The entire triangle rendering code looks like this:

Render a triangle G_pimmediatecontext->vssetshader (G_pvertexshader, NULL, 0);g_pimmediatecontext-> Pssetshader (G_ppixelshader, NULL, 0); G_pimmediatecontext->draw (3, 0);

  

Direct3D Tutorial 2:rendering a Triangle_direct3d 11 tutorial 2: Rendering a triangle

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.