带索引的 OpenGL / OpenTK 绘图:尝试读取或写入受保护的内存问题

OpenGL / OpenTK Drawing with Indices : Attempted to Read or Write Protected Memory Issue

我正在尝试使用 C# 和 OpenGL 显示四边形(或两个三角形)。下面是我的网格代码 class。在其中,您可以创建 VBO 和 VAO,以及我用来渲染网格的函数。

using System;
using System.Collections.Generic;
using System.Text;
using OpenTK.Graphics.OpenGL;
using BuildMe.Core;
using OpenTK;

namespace BuildMe.Render
{
    class Mesh
    {

        private Vector3[] verts;
        private uint[] indices;
        private int instances;
        private int VAO;

        public uint[] Indices { get => indices; set => indices = value; }
        public int Instances { get => instances; set => instances = value; }
        public Vector3[] Verts { get => verts; set => verts = value; }

        public Mesh(Vector3[] verts, uint[] indices, int instances)
        {
            this.verts = verts;
            this.indices = indices;
            this.instances = instances;
            this.VAO = CreateVAO();
            StoreVAOData();
        }

        private int CreateVAO()
        {
            int VAO = GL.GenVertexArray();
            RenderLoop.VAOs.Add(VAO);
            return (VAO);
        }

        private void StoreVAOData()
        {
            GL.BindVertexArray(VAO);

            LoadVerts();
            LoadIndices();

            GL.BindVertexArray(0);
        }

        private void LoadVerts()
        {
            int vbo = GL.GenBuffer();
            GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
            GL.BufferData(BufferTarget.ArrayBuffer, Vector3.SizeInBytes * verts.Length, verts, BufferUsageHint.StaticDraw);
            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, Vector3.SizeInBytes, 0);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
            RenderLoop.VBOs.Add(vbo);
        }

        private void LoadIndices()
        {
            int vbo = GL.GenBuffer();
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, vbo);
            GL.BufferData(BufferTarget.ElementArrayBuffer, sizeof(int) * indices.Length, indices, BufferUsageHint.StaticDraw);
            GL.VertexAttribPointer(0, 1, VertexAttribPointerType.UnsignedInt, false, sizeof(int), 0);
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
            RenderLoop.VBOs.Add(vbo);
        }

        public int GetVAO()
        {
            return (VAO);
        }

        public void Render()
        {
            GL.BindVertexArray(this.GetVAO());
            GL.EnableVertexAttribArray(0);
            GL.EnableVertexAttribArray(1);
            GL.DrawElements(PrimitiveType.Triangles, this.Indices.Length, DrawElementsType.UnsignedInt, 0);
            GL.DisableVertexAttribArray(0);
            GL.DisableVertexAttribArray(1);
            GL.BindVertexArray(0);
        }

    }
}

这里是我调用函数渲染网格的地方。

        private void Render(object sender, FrameEventArgs e)
        {
            GL.EnableClientState(ArrayCap.VertexArray);
            GL.EnableClientState(ArrayCap.IndexArray);
            GL.Color3(Color.Green);
            foreach (Mesh mesh in SceneMeshes)
                mesh.Render();
        }

这是我遇到的错误,如果有帮助的话。但我认为这只是意味着我要么声明了 VBO 错误,要么我使用了错误的函数来渲染它。

An unhandled exception of type 'System.AccessViolationException' occurred in OpenTK.dll Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

EnableClientStateVertexAttribPointer 没有相互作用。如果要使用客户端功能,则必须使用 VertexPointer(请参阅 glVertexPointer):

GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, Vector3.SizeInBytes, 0);

GL.VertexPointer(3, VertexAttribPointerType.Float, Vector3.SizeInBytes, 0);

GL.EnableClientState(ArrayCap.IndexArray); 没有达到您的预期。 ArrayCap.IndexArray 用于颜色索引属性。
索引缓冲区绑定到目标 BufferTarget.ElementArrayBuffer。它不是属性,不必启用。
此外,索引缓冲区在顶点数组对象中说明。指令 GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); 会破坏绑定:

private void LoadIndices()
{
    int ibo = GL.GenBuffer();
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo);
    GL.BufferData(BufferTarget.ElementArrayBuffer, sizeof(int) * indices.Length, indices, BufferUsageHint.StaticDraw);
    // GL.VertexAttribPointer(...) <--- REMOVE
    // GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); // <--- REMOVE
    RenderLoop.VBOs.Add(ibo);
}

客户端功能在 Vertex Array Object 中说明。所以可以写成LoadVerts():

private void LoadVerts()
{
    int vbo = GL.GenBuffer();
    GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
    GL.BufferData(BufferTarget.ArrayBuffer, Vector3.SizeInBytes * verts.Length, verts, BufferUsageHint.StaticDraw);
    // GL.VertexAttribPointer(...); <---- REMOVE
    GL.VertexPointer(3, VertexAttribPointerType.Float, Vector3.SizeInBytes, 0); // <--- ADD
    GL.EnableClientState(ArrayCap.VertexArray); // <--- ADD
    GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
    RenderLoop.VBOs.Add(vbo);
}

顶点数组对象中说明了所有必要的规范,因此在绘制调用之前绑定 VAO 就足够了:

public void Render()
{
    GL.BindVertexArray(this.GetVAO());
    GL.DrawElements(PrimitiveType.Triangles, this.Indices.Length, DrawElementsType.UnsignedInt, 0);
    GL.BindVertexArray(0);
}
private void Render(object sender, FrameEventArgs e)
{
    GL.Color3(Color.Green);
    foreach (Mesh mesh in SceneMeshes)
        mesh.Render();
}