如何将 OpenGL 项目从旧的 glVertexAttribPointer 方法转换为新的 glVertexAttribBinding 方法?

Ho do you convert an OpenGL project from older glVertexAttribPointer methods to newer glVertexAttribBinding methods?

我有一个 OpenGL 项目,该项目以前使用基于 OpenGL 3.0 的方法来绘制数组,我正在尝试将其转换为使用更新的方法(至少从 OpenGL 4.3 开始可用)。但是,到目前为止我还没有能够让它发挥作用。

我将用于解释的这段代码创建了点分组并在它们之间画线。它还可以填充生成的多边形(使用三角形)。我将给出一个使用点绘图例程的示例。这是它过去如何工作的伪代码:

[原始]第一次生成点时(发生一次):

// ORIGINAL, WORKING CODE RUN ONCE DURING SETUP:
    // NOTE: This code is in c# and uses a library called SharpGL
    // to invoke OpenGL calls via a context herein called "gl"

    float[] xyzArray = [CODE NOT SHOWN -- GENERATES ARRAY OF POINTS]

    // Create a buffer for the vertex data
    // METHOD CODE NOT SHOWN, but uses glGenBuffers to fill class-member buffer IDs
    GenerateBuffers(gl);  // Note: we now have a VerticesBufferId

    // Set the vertex buffer as the current buffer and fill it
    gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, this.VerticesBufferId);
    gl.BufferData(OpenGL.GL_ARRAY_BUFFER, xyzArray, OpenGL.GL_STATIC_DRAW);

[原始]在绘图的循环中:

// ORIGINAL, WORKING CODE EXECUTED DURING EACH DRAW LOOP:
    // NOTE: This code is in c# and uses a library called SharpGL
    // to invoke OpenGL calls via a context herein called "gl"

    // Note: positionAttributeId (below) was derived from the active
    // shader program via glGetAttribLocation 
    gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, this.VerticesBufferId);
    gl.EnableVertexAttribArray(positionAttributeId);
    gl.VertexAttribPointer(positionAttributeId, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero);
    
    // Missing code sets some uniforms in the shader program and determines
    // the start (iStart) and length (pointCount) of points to draw

    gl.DrawArrays(OpenGL.GL_LINE_STRIP, iStart, pointCount);

该代码现在已经运行了很长一段时间,但我正在尝试转向更现代的技术。我的大部分代码根本没有改变,这是替换上面代码的新代码:

[After Mods] 首次生成点时(发生一次):

// MODIFIED CODE RUN ONCE DURING SETUP:
    // NOTE: This code is in c# and uses a library called SharpGL
    // to invoke OpenGL calls via a context herein called "gl"

    float[] xyzArray = [CODE NOT SHOWN -- GENERATES ARRAY OF POINTS]

    // Create a buffer for the vertex data
    // METHOD CODE NOT SHOWN, but uses glGenBuffers to fill class-member buffer IDs
    GenerateBuffers(gl);  // Note: we now have a VerticesBufferId.

    // Set the vertex buffer as the current buffer
    gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, this.VerticesBufferId);
    gl.BufferData(OpenGL.GL_ARRAY_BUFFER, xyzArray, OpenGL.GL_STATIC_DRAW);

// ^^^ ALL CODE ABOVE THIS LINE IS IDENTIAL TO THE ORIGINAL ^^^
    // Generate Vertex Arrays
    // METHOD CODE NOT SHOWN, but uses glGenVertexArrays to fill class-member array IDs
    GenerateVertexArrays(gl);  // Note: we now have a PointsArrayId

    // My understanding: I'm telling OpenGL to associate following calls
    // with the vertex array generated with the ID PointsArrayId...
    gl.BindVertexArray(PointsArrayId);

    // Here I associate the positionAttributeId (found from the shader program)
    // with the currently bound vertex array (right?)
    gl.EnableVertexAttribArray(positionAttributeId);

    // Here I tell the bound vertex array about the format of the position
    // attribute as it relates to that array -- I think.
    gl.VertexAttribFormat(positionAttributeId, 3, OpenGL.GL_FLOAT, false, 0);

    // As I understand it, I can define my own "local" buffer index
    // in the following calls (?).  Below I use 0, which I then bind
    // to the buffer with id = this.VerticesBufferId (for the purposes
    // of the currently bound vertex array)
    gl.VertexAttribBinding(positionAttributeId, 0);
    gl.BindVertexBuffer(0, this.VerticesBufferId, IntPtr.Zero, 0);

    gl.BindVertexArray(0); // we no longer want to be bound to PointsArrayId

[After Mods] 在绘制的循环中:

// MODIFIED CODE EXECUTED DURING EACH DRAW LOOP::
    // NOTE: This code is in c# and uses a library called SharpGL
    // to invoke OpenGL calls via a context herein called "gl"

    // Here I tell OpenGL to bind the VertexArray I established previously
    // (which should understand how to fill the position attribute in the
    // shader program using the "zeroth" buffer index tied to the 
    // VerticesBufferId data buffer -- because I went through all the trouble
    // of telling it that above, right?)
    gl.BindVertexArray(this.PointsArrayId);

    // \/ \/ \/ NOTE: NO CODE CHANGES IN THE CODE BELOW ThIS LINE  \/ \/ \/
    // Missing code sets some uniforms in the shader program and determines
    // the start (iStart) and length (pointCount) of points to draw

    gl.DrawArrays(OpenGL.GL_LINE_STRIP, iStart, pointCount);

修改后,例程没有在屏幕上绘制任何内容。没有抛出异常或指示(我可以告诉)执行命令时出现问题。它只会留下一个空白屏幕。

一般问题:

  1. 我转换到较新的顶点数组方法看起来正确吗?你看到逻辑上有什么错误吗?
  2. 我是否应该执行特定的 glEnable 调用以使此方法代替旧方法工作?
  3. 我可以在同一个着色器程序中混用这两种填充属性的方法吗? (例如,除了上述之外,我还填写了三角形数据并通过相同的着色器程序使用它。如果我没有将该过程切换到新方法,是否会导致问题)?

如果这里还有什么我遗漏的,请告诉我,我将不胜感激。

进一步调查,我发现了我的错误:

使用glVertexAttribPointer时,可以将步幅参数设置为0(零),OpenGL会自动确定步幅;但是,使用 glVertexAttribFormat 时,您必须自己设置步幅。

一旦我在 glVertexAttribFormat 中手动设置步幅值,一切都按预期进行。