VBOs Using Interleaved Vertices in C#
I am trying to use VBOs to draw my model in in C# using OpenTK. In my online research I read in many places that it is good practice to make the size of the interleaved data structure an exact multiple of 32 bytes, so I coded up the following:
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Byte4
{
public byte R, G, B, A;
public Byte4(byte[] input)
{
R = input[0];
G = input[1];
B = input[2];
A = input[3];
}
public uint ToUInt32()
{
byte[] temp = new byte[] { this.R, this.G, this.B, this.A };
return BitConverter.ToUInt32(temp, 0);
}
}
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct VertexInterleaved
{
// data section is exactly 36 bytes long??? - need padding to get multiple of 32?
public Vector3 vertex; // Vertex
public Vector3 normal; // Normal Vector
public Vector2 textureCoord; // First Texture Coordinates
public Byte4 rgbaColor; // RGBA value of this vertex
//public byte[] padding;
public static int VertexStride()
{
// if I'm using the padding I have to add the appropriate size to this...
return (8 * sizeof(float) + 4 * sizeof(byte));
}
}
public class VertexBufferObject
{
private uint[] _VBOid;
private int _vertexStride;
private int _totalIndices;
private int _totalVertices;
public VertexBufferObject ()
{
_VBOid = new uint[2];
GL.GenBuffers(2, _VBOid);
}
public bool DeleteVBO()
{
GL.DeleteBuffers(2, _VBOid);
}
private void BindBuffers()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, _VBOid[0]);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _VBOid[1]);
}
private void ReleaseBuffers()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
}
public void Buffer开发者_开发问答MeshData(Mesh3DCollection mesh3Ds)
{
_vertexStride = VertexInterleaved.VertexStride();
_totalIndices = mesh3Ds.TotalIndices();
_totalVertices = mesh3Ds.TotalVertices();
VertexInterleaved[] vboVertices = new VertexInterleaved[_totalVertices];
uint[] vboIndices = new uint[_totalIndices];
int vertexCounter = 0;
int indexCounter = 0;
foreach (Mesh3D m in mesh3Ds)
{
foreach (VertexInterleaved v in m.vertices)
{
vboVertices[vertexCounter] = v;
vertexCounter++;
}
foreach (uint i in m.indices)
{
vboIndices[indexCounter] = i;
indexCounter++;
}
}
BindBuffers();
GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr) (_totalIndices * sizeof(uint)), vboIndices, BufferUsageHint.StaticDraw);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(_totalVertices * _vertexStride), vboVertices, BufferUsageHint.StaticDraw);
ReleaseBuffers();
}
public void RenderVBO()
{
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.NormalArray);
GL.EnableClientState(ArrayCap.ColorArray);
BindBuffers();
GL.VertexPointer(3, VertexPointerType.Float, _vertexStride, (IntPtr) (0));
GL.NormalPointer(NormalPointerType.Float, _vertexStride, (IntPtr) (3 * sizeof(float)));
GL.TexCoordPointer(2, TexCoordPointerType.Float, _vertexStride, (IntPtr) (6 * sizeof(float)));
GL.ColorPointer(4, ColorPointerType.Byte, _vertexStride, (IntPtr) (8 * sizeof(float)));
GL.DrawElements(BeginMode.Quads, numIndices, DrawElementsType.UnsignedInt, startLocation);
ReleaseBuffers();
GL.DisableClientState(ArrayCap.VertexArray);
GL.DisableClientState(ArrayCap.NormalArray);
GL.DisableClientState(ArrayCap.ColorArray);
{
}
Specific Questions:
1.) Should my interleaved vertex data structure be a struct or a class? Does this make a difference as far as the VBO and/or memory footprint is concerned? (I decided to use a struct, even though it felt wrong, because the vertices aren't going to be altered once they're in memory.)
2.) Does this data structure really need to be a multiple of 32 bytes in size? (i.e., do I need a "dummy" padding member to force a correct size? All of the examples I found online were in C++, so I am particularly interested in whether the same ideas/motivations carry over to C#.
3.) Is the [Serializable] [StructLayout(LayoutKind.Sequential)] really necessary? I copied this from an example that I found online, so...
1.) If the data within the structure is going to change regularly then it is more advisable to use a class, that is a reference to the memory location. If it is pretty much static, as i imagine this will be, it is better to use structs, that is value type.
2.) I have heard that aligning blocks of interleaved vertex data on 32-byte-aligned boundaries has a performance gain, good cache line coherence but I have yet to see a good example of any performance gain.
3.)yes it is, it specifies that the fields of the type should be laid out in memory in the same order they are declared in your source code. Which is obviously important for interleaved data.
精彩评论