VBO, использующие чередующиеся вершины в C#

Я пытаюсь использовать VBO для рисования моей модели на С# с использованием 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 байтам? (т. е. нужен ли мне «фиктивный» элемент заполнения, чтобы установить правильный размер? Все примеры, которые я нашел в Интернете, были на С++, поэтому меня особенно интересует, переносятся ли те же идеи/мотивы на С#.

3.) Действительно ли необходим [Serializable] [StructLayout(LayoutKind.Sequential)]? Я скопировал это из примера, который нашел в Интернете, так что...


person seveland    schedule 29.06.2011    source источник


Ответы (1)


1.) Если данные в структуре будут регулярно изменяться, то целесообразнее использовать класс, то есть ссылку на ячейку памяти. Если он в значительной степени статичен, как я себе представляю, лучше использовать структуры, то есть тип значения.

2.) Я слышал, что выравнивание блоков чередующихся данных вершин по границам, выровненным по байтам по 32 байтам, дает прирост производительности, хорошую когерентность строк кэша, но мне еще предстоит увидеть хороший пример какого-либо прироста производительности.

3.) да, это указывает, что поля типа должны быть расположены в памяти в том же порядке, в котором они объявлены в вашем исходном коде. Что, очевидно, важно для чередующихся данных.

person jaywayco    schedule 29.06.2011
comment
Что касается 2.), я читал то же самое - мой код работает одинаково с отступом или без него, поэтому я боялся, что могу сделать что-то не так или где-то упустить смысл. Также спасибо, что предупредили меня, что я случайно набрал биты :). - person seveland; 29.06.2011