OpenGL 顶点数组对象不记录 VBO 和 IBO 绑定
OpenGL vertex array object not recording VBO and IBO bindings
我正在编写一个简单的场景图,我有一个网格 class 跟踪顶点数组对象、顶点缓冲区对象和索引缓冲区对象。
当我初始化网格对象并用数据填充它们时,似乎最后创建的顶点缓冲区是绘图时使用的那个,即使我绑定了一个不同的顶点数组对象。
渲染时,如果我只绑定顶点数组,除了最后一个初始化的网格之外的任何网格都具有最后一个初始化网格的顶点(但正确的索引,使它们看起来不正确)。
我让它工作的唯一方法是在绑定顶点数组对象后立即再次绑定顶点缓冲区对象。这与我在任何地方阅读的 每个 文档或评论相矛盾。
// Geometry class
class Geometry
{
public override void Render()
{
this.Mesh.bind(); // bind mesh
this.Material.bind(); // bind shader. This also uses attribute locations stored in the shader object to enable vertex attributes
this.Data.Render();
this.Mesh.unbind(); // bind 0 to vertex array
this.Material.unbind(); // use program 0
}
}
// base mesh class
class Mesh
{
public override void init()
{
// ... truncated code for creating vertices ..
vertexArray = GL.GenVertexArray();
GL.BindVertexArray(vertexArray);
GL.GenBuffers(2, buffers);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffers[0]);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * Vertex.SizeInBytes), vertices, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, buffers[1]);
GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indices.Count * sizeof(uint)), indices.ToArray(), BufferUsageHint.StaticDraw);
numPoints = vertices.Length;
numIndices = indices.Count;
GL.BindVertexArray(0);
}
public void bind()
{
GL.BindVertexArray(vertexArray);
// I had to add this line to make meshes render correctly
GL.BindBuffer(BufferTarget.ArrayBuffer, buffers[0]);
}
public void unbind()
{
GL.BindVertexArray(0);
}
public override void Render()
{
GL.DrawElements(PrimitiveType.Triangles, numIndices, DrawElementsType.UnsignedInt, IntPtr.Zero);
}
public override void Update(float t, float deltaT, int xDelta, int yDelta, int zDelta, MouseState mouse, KeyboardState keyboard)
{
}
}
您的网格初始化方法缺少一些相当重要的东西。即,调用 glVertexAttribPointer。此方法设置您的 VAO 将在何处以及如何获取顶点数据。您创建缓冲区并向它们提交数据,您永远不会为缓冲区设置属性绑定。
它是与 VAO 状态一起保存并在绑定 VAO 时自动使用的属性绑定,关于绑定到缓冲区目标(如元素数组缓冲区和数组缓冲区)的缓冲区的信息不是已保存。
编辑:
您似乎在每次渲染时都重新绑定属性,这不是您应该做的,这才是导致您出现问题的原因。
在初始化时绑定一次属性。然后只需绑定 VAO 并进行渲染。简单。
它如此工作的原因是因为您在 material.bind 中设置了属性绑定。如果您这样做时相关缓冲区未绑定,则会出现问题。因此,只有当您的缓冲区被绑定时它才会起作用,这就是为什么当您在 mesh.bind 中添加绑定行时它起作用的原因,这是之前发生的调用。但同样,您不应该在每次渲染调用时都这样做。
我正在编写一个简单的场景图,我有一个网格 class 跟踪顶点数组对象、顶点缓冲区对象和索引缓冲区对象。
当我初始化网格对象并用数据填充它们时,似乎最后创建的顶点缓冲区是绘图时使用的那个,即使我绑定了一个不同的顶点数组对象。
渲染时,如果我只绑定顶点数组,除了最后一个初始化的网格之外的任何网格都具有最后一个初始化网格的顶点(但正确的索引,使它们看起来不正确)。
我让它工作的唯一方法是在绑定顶点数组对象后立即再次绑定顶点缓冲区对象。这与我在任何地方阅读的 每个 文档或评论相矛盾。
// Geometry class
class Geometry
{
public override void Render()
{
this.Mesh.bind(); // bind mesh
this.Material.bind(); // bind shader. This also uses attribute locations stored in the shader object to enable vertex attributes
this.Data.Render();
this.Mesh.unbind(); // bind 0 to vertex array
this.Material.unbind(); // use program 0
}
}
// base mesh class
class Mesh
{
public override void init()
{
// ... truncated code for creating vertices ..
vertexArray = GL.GenVertexArray();
GL.BindVertexArray(vertexArray);
GL.GenBuffers(2, buffers);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffers[0]);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * Vertex.SizeInBytes), vertices, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, buffers[1]);
GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indices.Count * sizeof(uint)), indices.ToArray(), BufferUsageHint.StaticDraw);
numPoints = vertices.Length;
numIndices = indices.Count;
GL.BindVertexArray(0);
}
public void bind()
{
GL.BindVertexArray(vertexArray);
// I had to add this line to make meshes render correctly
GL.BindBuffer(BufferTarget.ArrayBuffer, buffers[0]);
}
public void unbind()
{
GL.BindVertexArray(0);
}
public override void Render()
{
GL.DrawElements(PrimitiveType.Triangles, numIndices, DrawElementsType.UnsignedInt, IntPtr.Zero);
}
public override void Update(float t, float deltaT, int xDelta, int yDelta, int zDelta, MouseState mouse, KeyboardState keyboard)
{
}
}
您的网格初始化方法缺少一些相当重要的东西。即,调用 glVertexAttribPointer。此方法设置您的 VAO 将在何处以及如何获取顶点数据。您创建缓冲区并向它们提交数据,您永远不会为缓冲区设置属性绑定。
它是与 VAO 状态一起保存并在绑定 VAO 时自动使用的属性绑定,关于绑定到缓冲区目标(如元素数组缓冲区和数组缓冲区)的缓冲区的信息不是已保存。
编辑:
您似乎在每次渲染时都重新绑定属性,这不是您应该做的,这才是导致您出现问题的原因。
在初始化时绑定一次属性。然后只需绑定 VAO 并进行渲染。简单。
它如此工作的原因是因为您在 material.bind 中设置了属性绑定。如果您这样做时相关缓冲区未绑定,则会出现问题。因此,只有当您的缓冲区被绑定时它才会起作用,这就是为什么当您在 mesh.bind 中添加绑定行时它起作用的原因,这是之前发生的调用。但同样,您不应该在每次渲染调用时都这样做。