DX Mesh creation with Normals

Started by
7 comments, last by Buckeye 15 years, 9 months ago
Hi! I create a DirectX9 mesh from a VertexBuffer and an IndexBuffer. To define the normals of each vertex, I have to create the mesh's VertexBuffer with the CustomVertex.PositionNormal declaration. This means that the Normal declaration is per vertex, but in the DirectX model file (*.x), the Normals are declared for each index. How can I declare different Normals for each triangle so they'll have hard edges? Thank you! Christian
Advertisement
I don't really understand your question, but if all you want is to compute normals for the mesh, this code worked for me (assuming MDX):

if ((mesh.VertexFormat & VertexFormats.Normal) == 0){    Mesh temp = mesh.Clone(mesh.Options.Value, mesh.VertexFormat | VertexFormats.Normal, device);    temp.ComputeNormals();    mesh.Dispose();    mesh = temp;}


I think I got it from the MDX documentation.
There is no built in functionality to set up a mesh for per-face/flat lighting, you'll have to implement this yourself.

A simple enough set of loops can traverse through indexed geometry and duplicate the appropriate vertices and setting each of the three vertices to have the same (face) normal.

Remember that as soon as one attribute of the vertex changes you have to split it - you can't have shared positions but different normals for example.

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

After reading jollyjeffers's post and re-reading your post, I see that I misunderstood your question.

It sounds like what you want is flat shading, in which case you just need to do this:

device.RenderState.ShadeMode = ShadeMode.Flat;
yup, forcing flat shading will work but bare in mind that you may not get identical results to face-normals stored by a modelling application. They'll likely be very close so depends what sort of code complexity trade-off you want!

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Thank you for your quick answers! I want to have both, smooth edges and hard edges in the same model. I developed a polygon class that uses SmoothingGroups like in 3ds max. Two adjoining polygons that share the same SmoothingGroup should have interpolated normals applied to each shared vertex.

Otherwise, the shared vertices should have an independent normal for each polygon (e.g. triangle). This is what causes the trouble because I don't know how to apply the normals when creating the Mesh from the VertexBuffer and the IndexBuffer.

This is my code so far (the CustomVertex.PositionOnly should be replaced by CustomVertex.PositionNormal, but this won't solve the problem...):

public static Mesh ConvertToMesh(PolyObj obj){  List<Vector3D> vertexBuffer = obj.CreateVertexBuffer();  List<int> indexBuffer = obj.CreateIndexBuffer();    // Create a new Mesh from the VertexBuffer  Mesh mesh = new Mesh(indexBuffer.Count / 3, vertexBuffer.Count,    MeshFlags.Managed, CustomVertex.PositionOnly.Format, Renderer.Direct3DDevice);  // Write into the VertexBuffer  using (VertexBuffer vb = mesh.VertexBuffer)  {    GraphicsStream data = vb.Lock(0, 0, LockFlags.None);    foreach (Vector3D v in vertexBuffer)    {      Vector3 dxv = new Vector3((float)v.X, (float)v.Y, (float)v.Z);      data.Write(new CustomVertex.PositionOnly(dxv));    }    vb.Unlock();  }  // Set the IndexBuffer  using (IndexBuffer meshIndexBuffer = mesh.IndexBuffer)  {    meshIndexBuffer.SetData(indexBuffer.ToArray(), 0, LockFlags.None);  } // using        return mesh;}
I'm not positive if I understand you right. But it sounds like you want to adjust the normals that are provided in the x-file according to which faces are adjacent to which, and you have a list or array of face indices vs. smoothing group. I'm not sure how your smoothing group info is organized, but I presume it's some sort of list that tells you the smoothing group (if any) to which a face (triangle) belongs.

First: are you generating a mesh that has 3 vertices per face? Not just 3 indices per face! That is, there are no shared vertices between faces. You'll have to do that if you want different vertex normals for vertices which are at the same position for adjacent triangles but the triangles are not in the same smoothing group.

As a result, my suggestion is rather generalized. I've only worked in C++ but, hopefully, you can translate my comments.

1. load the vertices and indices from the x-file.
2. generate an adjacency table for the mesh. The adjacency table tells you which faces are adjacent to which. That is, for each face, there are three face indices for each of the three possible edges. If an index is 0xffff (or 0xffffffff), then that's a hard edge; otherwise, it's the face index for the triangle adjacent to that edge.
3. go through your smoothing group list. For each face, calculate the appropriate normal for each of the 3 vertices in the face by checking which (if any) adjacent faces on the two edges to which each vertex belongs are in the same group. Store the calculated normals in a separate array (e.g., vertex index with it's normal) so you don't use an already smoothed normal in your calc.
4. go back through your list of calculated normals, stuffing the normals into the vertex buffer at the appropriate vertex position.

I hope that has something to do with what you're asking about. [smile]

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Alright, so the trick is to create 3 different vertices at the same position but with different normals to achieve hard edges. That makes sense I guess.
Thank you!
Christian
Quote:so the trick is to create 3 different vertices at the same position but with different normals to achieve hard edges

Yes. The number of vertices = 3 * number of faces. You'll probably start out with an index buffer that looks like ( 0, 1, 2, 3, 4, ... ) until you optimize it.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

This topic is closed to new replies.

Advertisement