Thursday, October 20, 2016

xna - Custom VertexDeclaration for Color, Texture, Normal


What is the best way to create a VertexDeclaration, that makes it able to render a Shape consisting of vertices and also be able to store a color for the shape (in case the texture can't be rendered - or in case we want color instead of a texture) - instead of having both a VertexPositionNormalTexture and a VertexPositionColor struct in the same class/struct.


I'm trying this approach:


public interface IShape : IVertexType { }


public struct ShapeFace
{
public int Count { get; set; }
public Color Color { get; set; }
public Vector3 Position { get; set; }
public Vector2 TextureCoordinates { get; set; }
public Vector3 Normal { get; set; }
public Vector3[] Vertices { get; set; }


// Perhaps I need this?
// public int[] Indexs { get; set; }
}

public struct Shape : IShape
{
public ShapeFace[] Faces { get; set; }

/* Need to implement VertexDeclaration here */
}


How do I implement the VertexDeclaration to understand what I want to do?


A shape contains faces, each face can have it's own texture OR color, normal mapping, texture coordinates, etc.


Example A cube has 6 faces, each face needs 2 triangles, each triangle has 3 points. 6 * 2 * 3 = 36 vertices. This way I can create a cube with 6 faces instead of 36 vertices, and render it in color or with a texture.


I really want to simplify it so that I can create some kind of struct that works this way.



Answer



First, a handy link from Riemers XNA tutorial.


I did this, in what seems a similar goal to you, in the process of making my voxel-based game. The link above was extremely handy (as well as a few other articles on that site).


I solved this myself without an interface, instead creating my own direct descendant of IVertexType, called VertexPositionColorNormal, as I wanted colors as well as lighting. I will later be adding texture details, as well as using a normal map rather than a single face value. The code I used is here:


public struct VertexPositionColorNormal : IVertexType

{
public Vector3 Position;
public Color Color;
public Vector3 Normal;

public readonly static VertexDeclaration VertexDeclaration
= new VertexDeclaration(
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
new VertexElement(sizeof(float) * 3, VertexElementFormat.Color, VertexElementUsage.Color, 0),
new VertexElement(sizeof(float) * 3 + 4, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0)

);

public VertexPositionColorNormal(Vector3 pos, Color c, Vector3 n)
{
Position = pos;
Color = c;
Normal = n;
}

VertexDeclaration IVertexType.VertexDeclaration

{
get { return VertexDeclaration; }
}
}

The important thing to note is that the VertexDeclaration has to give, very explicitly, the exact size in bytes of each vertex that you are going to send the hardware. If it doesn't, you'll get XNA whining over and over about how there is size mismatches or unexpected end of vertex data, or all sorts of other issues.


That is ALL the VertexType and VertexDeclaration should be doing, defining a vertex. Any management of a collection of vertices to make a box or any other model should be done in a different class that manages a collection of these Vertices in order to define a shape.


I keep the Struct for the VertexType/Declaration in my Chunk class file, but it could realistically go anywhere, it just makes sense for me to keep it here, as it is the highest level that deals directly with the vertices. Each Block contains an array of the 8 vertices that make it up, and the chunk class is responsible for combining these into single meshes in order to speed up rendering.


Another useful link is this one which details how (in OpenGL + C++, unfortunately) how to assemble the VertexBuffer with all these wonderful vertex types. Luckily for us, XNA handles a good portion of material in this regard, so it is very easy to maintain a list/array of the custom Vertices and send this data as a single buffer to the video card.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...