TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
 Specialized Dev Zones Research Center eBook Library .NET Java C++ Web Dev Architecture Database Security Open Source Enterprise Mobile Special Reports 10-Minute Solutions DevXtra Blogs Slideshow

Direct3D, Part 3: Using Meshes to Save and Load Complex Scenes : Page 2

Direct3D's Mesh class lets you manage, save, and load complex scenes quickly and easily.

 by Rod Stephens
 Mar 5, 2008
 Page 2 of 4
Building a Mesh
The program example d3dMakeMesh builds and displays a Mesh. The following paragraphs describe the most important parts of the code, but I encourage you to download the example program and refer back to the first and second part of this series to fill in the blanks.

Here's some of the code that the program uses to set its vertex and index information for the "brick courtyard with pool" scene:

``````   ' Make a scene.
Dim vertices As New List(Of CustomVertex.PositionNormalTextured)
Dim indices As New List(Of Short)
Dim num_faces As Integer = 0

' Make the ground.
Dim ground_face_start As Integer = num_faces
For x As Integer = -10 To 5 Step 5
x, x + 5, -10, -5, 0, 1, 0, 1)
x, x + 5, 5, 10, 0, 1, 0, 1)
Next x
AddHorzRectangle(vertices, indices, -10, -5, -5, 0, 0, 1, 0, 1)
AddHorzRectangle(vertices, indices, -10, -5, 0, 5, 0, 1, 0, 1)
AddHorzRectangle(vertices, indices, 5, 10, -5, 0, 0, 1, 0, 1)
AddHorzRectangle(vertices, indices, 5, 10, 0, 5, 0, 1, 0, 1)

' Inside of pool.
New Vector3(-5, Y_WATER, 5), New Vector3(-5, Y_GROUND, 5), _
New Vector3(0, Y_GROUND, 5), New Vector3(0, Y_WATER, 5), _
0, 0, 0, 0.2, 1, 0.2, 1, 0)
...
num_faces = indices.Count \ 3
Dim ground_face_stop As Integer = num_faces - 1

' Water.
Dim water_face_start As Integer = num_faces
New Vector3(-5, Y_WATER, -5), New Vector3(-5, Y_WATER, 5), _
New Vector3(5, Y_WATER, 5), New Vector3(5, Y_WATER, -5), _
0, 0, 0, 1, 1, 1, 1, 0)
num_faces = indices.Count \ 3
Dim water_face_stop As Integer = num_faces - 1
...
``````
The program first creates two generic Lists named vertices and indices and then defines a variable called num_faces to keep track of the number of faces created so far.

Next, the code creates faces to define the scene's brick-covered ground. It sets the variable ground_face_start to the index of the first face that makes up the ground. It then calls the helper method AddHorzRectangle to create data representing horizontal rectangles. This method adds PositionNormalTextured objects to the vertices collection to represent points with normal and texture information. It also adds index information to the indices collection.

The code then calls the AddRectangle method to add non-horizontal rectangles to the vertex and index data. After adding all the faces needed to draw the ground, it saves the index of the last face in the variable ground_face_stop.

The code then repeats these steps to create data representing a pool of water and two blocks of wood.

The next step is to create a Mesh so you can save the scene. To do that, you first create a new Mesh object, copy the values in the vertices and indices collections into arrays, and then call the Mesh's SetVertexBuffer and SetIndexBuffer methods:

``````   ' Build the mesh.
m_Mesh = New Mesh(num_faces, vertices.Count, 0, _
CustomVertex.PositionNormalTextured.Format, m_Device)

' Convert the lists into arrays.
Dim vertices_arr() As CustomVertex.PositionNormalTextured = _
vertices.ToArray()
Dim indices_arr() As Short = indices.ToArray()

' Set the vertex and face data.
m_Mesh.SetVertexBufferData(vertices_arr, LockFlags.None)
m_Mesh.SetIndexBufferData(indices_arr, LockFlags.None)
``````
You need to assign the correct subset for each face. The sample application calls LockAttributeBufferArray to get an array holding the faces' subset numbers. Then it uses the ground_face_start, ground_face_stop, water_face_start, and other variables to determine which faces belong to each subset. This example uses four subsets for faces, corresponding to the brick, water, wood side grain, and wood end grain faces in the scene. After setting the faces' subset numbers, the code calls UnlockAttributeBuffer to save the changes. Here's the code:

``````   ' Assign each face's subset.
Dim subset() As Integer = _
For i As Integer = ground_face_start To ground_face_stop
subset(i) = 0
Next i
For i As Integer = water_face_start To water_face_stop
subset(i) = 1
Next i
For i As Integer = wood_face_start To wood_face_stop
subset(i) = 2
Next i
For i As Integer = woodend_face_start To woodend_face_stop
subset(i) = 3
Next i
m_Mesh.UnlockAttributeBuffer(subset)
``````
Your code can specify the vertices and faces in the Mesh in any order you like; however, not all orders are equally efficient. For example, it would be best to draw all of the faces for a particular subset at one time, so you don't need to load their material and texture repeatedly. Meshes also often represent large areas tiled with a collection of triangles; so drawing them in large strips or fans may be much more efficient than drawing the faces individually.