带索引的 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.
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);
}
顶点数组对象中说明了所有必要的规范,因此在绘制调用之前绑定 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();
}
我正在尝试使用 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.
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);
}
顶点数组对象中说明了所有必要的规范,因此在绘制调用之前绑定 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();
}