我对opengl很陌生,而且我发现这种意外行为。
我实现了一个基本的场景图,并尝试添加重用着色器和网格数据的功能。
我有一个GeometryData对象,它包含对顶点数组对象,顶点缓冲区和索引缓冲区的引用。它有一个使用glDrawElements绘制模型的render方法。
GeometryData具有对Shader对象的引用,该对象具有对程序着色器句柄的引用。
问题在于,如果我渲染具有相同着色器实例的连续对象,则只渲染第一个,而其他对象不是出于某种原因,没有错误。如果我在连续对象绘制之间交替着色器分配,则所有这些都是正常绘制的。
我的GeometryData的Render方法如下:
public override void Render()
{
GL.BindVertexArray(vertexArray);
if (UseShader != null)
UseShader.Use();
var err = GL.GetError();
GL.DrawElements(PrimitiveType.Triangles, numIndices, DrawElementsType.UnsignedInt, IntPtr.Zero);
err = GL.GetError();
GL.BindVertexArray(0);
}
UseShader.Use()
方法就是这个
public void Use()
{
int current = GL.GetInteger(GetPName.CurrentProgram);
if (current != ProgramHandle)
GL.UseProgram(ProgramHandle);
// Use a uniform block for the project and modelview matrices
var index = GL.GetUniformBlockIndex(ProgramHandle, "Matrices");
GL.UniformBlockBinding(ProgramHandle, index, World.BINDING_POINT);
// assume interleaved vertex data
GL.VertexAttribPointer(positionLoc, 3, VertexAttribPointerType.Float, false, 2 * Vector3.SizeInBytes, Vector3.SizeInBytes);
GL.EnableVertexAttribArray(positionLoc);
GL.VertexAttribPointer(colorLoc, 3, VertexAttribPointerType.Float, false, 2 * Vector3.SizeInBytes, 0);
GL.EnableVertexAttribArray(colorLoc);
}
以下是一些截图。使用此循环创建框:
for (int i = -3; i <= 3; i+=3)
{
Transform child = new Transform();
child.Translation = new Vector3(i, 0, 0);
// this causes the second red box to not render
Geometry geom = new Geometry(i > 0 ? coloredShader : redShader, box);
// this causes all boxes to render normally
// Geometry geom = new Geometry(i == 0 ? coloredShader : redShader, box);
child.addChild(geom);
root.addChild(child);
}
带有交替着色器的图片(红色,彩色,红色)
使用相同着色器(红色,红色,彩色)连续两个对象的图片。未绘制第二个红色对象。我对场景所做的唯一更改是着色器分配。
经过进一步的检查和调试,似乎问题的根源是统一块。我使用统一块将投影和模型视图矩阵发送到着色器。我怀疑第二次调用glBufferSubData来更新模型视图矩阵不会更新制服,或者着色器没有从制服中读取该值而不先切换到另一个着色器。
我尝试从统一块中取出模型视图矩阵并将其分别发送到每个着色器。这使得所有对象都能正确呈现,但我仍然希望使用统一块来避免冗余上传。
答案 0 :(得分:0)
解决! 这真是太傻了。我需要在使用glBufferSubData更新统一块值后调用glFlush()。
public static void setModelView(ref Matrix4 modelView)
{
GL.BindBuffer(BufferTarget.UniformBuffer, uniformBuffer);
GL.BufferSubData(BufferTarget.UniformBuffer, (IntPtr)(16 * sizeof(float)), (IntPtr)(16 * sizeof(float)), ref modelView);
GL.Flush(); // I just added this line
GL.BindBuffer(BufferTarget.UniformBuffer, 0);
}