Рисование OpenGL / OpenTK с индексами: попытка чтения или записи защищенной памяти - PullRequest
1 голос
/ 04 апреля 2020

Я пытаюсь отобразить четырехугольник (или два треугольника) с C# и OpenGL. Ниже приведен мой код для моего класса me sh. В нем есть как создание VBO, так и VAO, а также функция, которую я использую для рендеринга me sh.

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

    }
}

Здесь я вызываю функцию для рендеринга me sh.

        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 неверно, либо использую неправильные функции для его рендеринга.

Необработанное исключение типа 'System.AccessViolationException' произошло в OpenTK.dll Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена.

1 Ответ

1 голос
/ 04 апреля 2020

EnableClientState и VertexAttribPointer не взаимодействуют друг с другом. Если вы хотите использовать возможности на стороне клиента, вы должны использовать 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);
}

Вся необходимая спецификация указана в объекте Vertex Array, поэтому достаточно связать 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();
}
...