【问题标题】:OpenGL / OpenTK Drawing with Indices : Attempted to Read or Write Protected Memory Issue带索引的 OpenGL / OpenTK 绘图:尝试读取或写入受保护的内存问题
【发布时间】:2020-07-16 17:34:51
【问题描述】:

我正在尝试使用 C# 和 OpenGL 显示一个四边形(或两个三角形)。下面是我的网格类的代码。在其中,您既有 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 错误,要么我使用了错误的函数来渲染它。

OpenTK.dll 中出现“System.AccessViolationException”类型的未处理异常 尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

【问题讨论】:

    标签: c# opengl opentk vao


    【解决方案1】:

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

    【讨论】:

    • 太棒了,感谢您的帮助。你把事情解释得超级清楚。它现在按预期工作。
    猜你喜欢
    • 1970-01-01
    • 2010-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    相关资源
    最近更新 更多