C#中使用交错顶点的VBO

本文关键字:顶点 VBO | 更新日期: 2023-09-27 18:00:36

我正试图使用VBO在C#中使用OpenTK绘制我的模型。在我的在线研究中,我在很多地方读到,使交错数据结构的大小精确为32字节的倍数是一种很好的做法,所以我编码了以下内容:

[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 BufferMeshData(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);
    {
}

具体问题:

1.)我的交错顶点数据结构应该是结构还是类?就VBO和/或内存占用而言,这有什么不同吗?(我决定使用一个结构,尽管它感觉不对,因为顶点一旦进入内存就不会被更改。)

2.)这个数据结构的大小真的需要是32字节的倍数吗?(也就是说,我需要一个"伪"填充成员来强制正确的大小吗?我在网上找到的所有例子都是用C++编写的,所以我特别感兴趣的是相同的想法/动机是否会延续到C#中。

3.)[可序列化][StructLayout(LayoutKind.Sequential)]真的有必要吗?我从网上找到的一个例子中复制了这个,所以…

C#中使用交错顶点的VBO

1.)如果结构中的数据将定期更改,则更建议使用一个类,即对内存位置的引用。如果它几乎是静态的,就像我想象的那样,最好使用structs,也就是值类型。

2.)我听说在32-字节对齐的边界上对齐交错顶点数据块有性能增益和良好的缓存线一致性,但我还没有看到任何性能增益的好例子。

3.)是的,它指定该类型的字段应该按照在源代码中声明的顺序在内存中布局。这对于交错数据来说显然很重要。