"Translation" Managed DirectX (chapter III)

Source: Internet
Author: User

Using a simple rendering technique

Translation: Clayman


So far, our rendering efficiency has been low. Each time the scene is rendered, a new vertex list is assigned, and everything is stored in the system memory. Modern graphics cards are integrated with enough video memory to hold vertex data in memory for a significant new boost: data stored in the system's memory and copied to the video card when each frame is rendered, resulting in a huge loss. This allocation can help us improve performance only when we remove each frame.

use vertex buffering ( Using Vertex Buffers )

Direct3D already includes this mechanism: vertex buffering (vertex buffer). Vertex buffering, just like his name means: A piece of memory that stores vertices. The flexibility of vertex buffering is perfect for changing geometry in shared scenes. How to let the triangle program we wrote in chapter one use vertex buffering.

Creating a vertex buffer is as simple as having three constructors to accomplish this task, and we'll look at it in turn:

Public vertexbuffer (device device, int sizeofbufferinbytes, usage usage, vertexformats vertexformat, pool pool);

Public vertexbuffer (Type typevertextype, int numverts, device device, Usage usage,vertexformats VertexFormat, Pool PO OL);

The following are the meanings of each parameter:

n device--the device used to create the vertex buffer, the vertex buffer created can only be used by this device;

n sizeofbufferinbytes--the size, in bytes, of the vertex buffer created. Vertex buffers created with constructors with this parameter can hold any type of vertex;

n typevertextype--Use this parameter if you want to create a vertex buffer that stores only one type of vertex. Its value can be a vertex structure type in the CustomVertex class, or it can be a custom vertex type. And this value cannot be null;

n numvert--you specify the storage type of the vertex buffer, you must also specify the maximum number of vertices to buffer storage. This value must be greater than 0;

N usage--defines how vertex buffering is used. Will not be available to all members of the usage type, only a few are the correct parameters:

Donotclip,dynamic, Npatches, Points, Ptpatches, softwareprocessing, WriteOnly;

n vertexformat--defines the format of the vertices stored in the vertex buffer. , if created as a universal buffer, use Vertexformat.none;

N pool--locates the memory pool location used by vertex buffers and can specify several memory pool locations:

Default, Managed, Systemmemory, Scratch.

Observing the program in chapter one, moving the triangle data into the vertex buffer should be easy. First, declare the vertex buffer variable:

private device device = NULL;

private vertexbuffer vb = null;

Then add the code that creates the triangle:

device = new (0,devicetype.hardware, this. Creatflags.softwrevertexproccessing, presentparams);

customvertex.positioncolored[] verts = new CustomVertex. positioncolored[3];

Verts[0]. SetPosition (New Vector3 (0.0f,1.0f,1.0f));

Verts[0]. Color = System.Drawing.Color.Aqua.ToArgb ();

verts[1] " " "

verts[2] " " "

vb = new VertexBuffer (typeof (Vustomvertex.positioncolored), 2,device,usage.dynamic| Usage.writeonly, CustomVertex.PositionColored.Format, pllo.default);

VB. SetData (vets,0,lockflags.none);

 

The only change is to define the two lines of code after the triangle. First, create a vertex buffer to hold three vertices. For performance reasons, the buffers created are dynamic, read-only, and are located in the default memory pool. Next, we put the vertices of the triangles into the buffer, using a simple SetData method. This method receives any type of object as the first argument, and the second parameter is the lower amount of the data address to be placed in the vertex buffer. We are going to populate all the vertex buffers, so set to 0. The last parameter describes how to lock the buffer when writing data. We'll discuss the locking mechanism later; now, don't worry about how he's locked up.

Now compile the program, it's natural to get a compile error: Because the drawuserprimitives in the OnPaint method needs to get the Verts variable. There needs to be a way to tell Direct3D that we're going to draw the contents of the vertex buffer instead of the previously declared array. Call the device's SetStreamSource to let the Direct3D draw to read the vertex buffer. This method has the following two types of overloads:

Public void SetStreamSource (int streamnumber, vertexbuffer streamdata, int offsetinbytes, int stride);

Public void SetStreamSource (int streamnumber, vertexbuffer streamdata, int offsetinbytes);

 

The difference between the two functions is that there is one more parameter that represents the (data) flow stride size (stride size of the stream). The first parameter is the number of streams that are used by this piece of data. Now set it to 0, and we'll discuss using multiple streams in the next chapter. The second parameter is the vertex buffer as the data source, and the third is the offset, in bytes, of the data that needs DirectX to draw in the vertex buffer. The stride is the size of each vertex in the buffer. This parameter is not required if a vertex buffer is created with a specific type.

Now how to modify the drawing:

device. SetStreamSource (0, VB, 0);

device. Drawprimitives (primitivetype.trianglelise, 0, 1);

 

As we just described, we use the vertex buffer as the data stream 0, at the same time set the offset to 0, using all the data. It is important to note that we have also changed the function of the actual drawing. Now that all the data is in the vertex buffer, you don't need to call the Drawuserprimitives method. Because Drawuserprimitives is only used to draw user-defined data that is passed directly to it. The more general drawprimitives will draw the geometry from the source of the data stream. Drawprimitives has three parameters, the first one we've discussed. The second represents the starting vertex in the stream, and the last represents the number of geometry to be drawn.

Even this small sample that draws only one triangle has a 10% performance boost after using vertex buffering (based on the picture update rate, which is framerate frame rates). We'll talk about performance and frame rate in a few more moments. Unfortunately, when you try to change the window size, the triangle disappears immediately. (Note: When I actually test the triangle and the meter disappears, only when the window is scaled to a certain scale, the triangle disappears)

There are several situations that can lead to this behavior, two of which we have discussed earlier. Recalling the previous chapter, we know that the device resets automatically when the window size is changed. However, when the created resource is in the default memory pool (such as vertex Buffering), resetting the device will release the buffer. So when the window size is changed, the device is reset and the vertex buffer is released. Managed DirectX has a great new special is that it automatically rebuilds the vertex buffers after resetting the device. However, there is no data in the vertex buffer, so nothing is drawn.

We can capture the vertex buffer an event called "created", which occurs when the vertex buffer is rebuilt and the data is ready to be populated. Now is the time to update our program with this event, and modify the code as follows:

private void Onvertexbuffercreate (object sender, EventArgs e)

    {

vertexbuffer buffer = (vertexbuffer) sender;

customvertex.positioncolored[] verts = new CustomVertex. positioncolored[3];

Verts[0]. SetPosition (New Vector3 (0.0f,1.0f,1.0f));

Verts[0]. Color = System.Drawing.Color.Aqua.ToArgb ();

verts[1] " " "

verts[2] " " "

buffer. SetData (verts,0,lockflags.none);

    }

to subscribe to an event handler:

Vb. Created + = new Eventhandleer (this. Onvertexbuffercreate);

Onvertexbuffercreate (Vb,null);

This code subscribes to the event handler for vertex buffering and guarantees that the Onvertexbuffercreate method will be called whenever a vertex buffer is created. Because the first time you create a vertex buffer, you have not subscribed to the handler, so you need to call it manually.

Well, by using video memory and vertex buffering, we've changed the original slow sample to an efficient program. Of course, it's still pretty boring. So, let's create a box next.

All the geometry in a three-dimensional scene is made up of triangles, so how do you render a box or a cube? Well, each cube is made up of six squares, and two triangles can form a square (oh, this all to say, it seems that the foreigner's math really does not) in fact, we just need to get the cube 8 vertex coordinates can be. Add code:

customvertex.positioncolored[] verts = new CUSTOMVERTEX.POSITIONCOLORED[36];

//Front face

Verts[0] = new Customvertex.positioncolored ( -1.0f, 1.0f, 1.0f, Color.Red.ToArgb ());

verts[2] = "", Verts[3], verts[4], verts[5] = " " "

//Back face (remember the facing *away* from the camera, so vertices should be clockwise order)

verts[6] = new Customvertex.positioncolored ( -1.0f, 1.0f, -1.0f, Color.Blue.ToArgb ());

verts[7], verts[8], verts[9], verts[10], verts[11]= ""

(Note: See the source in the attachment, note the order of the vertex Declaration)

As mentioned earlier, the box consists of 12 triangles, each with three vertices, forming a collection of vertices. There are a few more places to change.

vb = new VertexBuffer (typeof (Customvertex.positioncolored), 36,device,usage.dynamic | Usage.writeonly,customvertex.positioncolored.format,pool.default);

Evice. Transform.world = Matrix.rotationyawpitchroll (angle/(float) Math.PI, angle/(float) math.pi*2.0f, angle/(float) MATH.PI);

device. Drawprimitives (primitivetype.trianglelist,0,12);

The biggest change here is redefining the size of the vertex buffers. At the same time, we changed the angle of rotation of the box to make him go a little bit crazier. Finally, change the number of entities you want to render. In fact, since the box is completely three-dimensional, there is no need to see his back. Use the default culling mode in Direct3D (counterclockwise): Delete the line that states that the culling mode was previously asserted. Okay, now run the program.

Very impressive, we now have a color box that spins wildly in the screen. But if you need to render a series of boxes, no one wants to declare a series of vertex buffers. There is an easy way to do this.

Now we're going to draw three boxes side-by-shoulder. Since the camera settings now make the first box take up the entire screen, we need to move the camera a little bit backwards:

device. Transform.view = MATRIX.LOOKATLH (new Vector3 (0,0,18.0f), New Vector3 (), New Vector3 (0,1,0));

As you can see, we just moved him back a little bit to see more of the scene. To draw more boxes, we can use the existing vertex buffers again, just to tell Direct3D to draw the same vertices again. On device. Add code after Drawprimitives:

device. Transform.world = Matrix.rotationyawpitchroll (angle/(float) Math.PI, angle/(float) math.pi/2.0f, angle/(float) math.pi*4.0f) *matrix.translation (5.0f,0.0f,0.0f);

device. Drawprimitives (primitivetype.trianglelist,0,12);

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.