【问题标题】:How to render instances using the new OperGL / OpenTk APIs如何使用新的 OperGL / OpenTk API 渲染实例
【发布时间】:2022-12-29 13:00:55
【问题描述】:

我正在尝试将本教程 (Advanced-OpenGL/Instancing) 和这些答案 (How to render using 2 VBO) (New API Clarification) 中的信息放在一起,以便渲染正方形的实例,通过将每个实例的模型矩阵提供给着色器数组缓冲区。我结束的代码如下。我切片并测试了任何部分,问题似乎是模型矩阵本身没有正确传递给着色器。我在 Visual Studio 中使用 OpenTK。

为了简单和调试,池只包含一个正方形,所以我仍然没有除数问题或其他我仍然无法处理的有趣问题。

我的顶点数据数组包含 3 个用于位置的浮点数和 4 个用于颜色的浮点数(步幅 = 7 时间浮点数大小)。

我的附加代码结果是:

  • 如果我在顶点着色器中删除 imodel 乘法,我得到的正是我所期望的,一个带有绿色边框(呈现为循环线)的红色正方形(呈现为 2 个三角形)。
  • 如果我更改着色器并乘以模型矩阵,我会在屏幕中心上方看到一条红线,它的长度会随时间变化。动画是有意义的,因为模拟正在旋转正方形,因此角度会定期更新,因此计算出的模型矩阵会发生变化。另一个很好的结果是因为我实际上是在向着色器发送动态数据。但是我无法旋转和平移我原来的正方形。

有什么线索吗? 非常感谢。

顶点着色器:

#version 430 core
layout (location = 0) in vec3  aPos;
layout (location = 1) in vec4  aCol;
layout (location = 2) in mat4 imodel;
out vec4 fColor;
uniform mat4 view;
uniform mat4 projection;

void main() {
    fColor = aCol;
    gl_Position = vec4(aPos, 1.0) * imodel * view * projection;
}

片段着色器:

#version 430 core
in vec4 fColor;
out vec4 FragColor;

void main() {
    FragColor = fColor;
}

OnLoad sn-p(初始化):

InstanceVBO = GL.GenBuffer();
GL.GenBuffers(2, VBO);

GL.BindBuffer(BufferTarget.ArrayBuffer, VBO[0]);
GL.BufferData(BufferTarget.ArrayBuffer,
    7 * LineLoopVertCount  * sizeof(float), 
    LineLoopVertData, BufferUsageHint.StaticDraw);

GL.BindBuffer(BufferTarget.ArrayBuffer, VBO[1]);
GL.BufferData(BufferTarget.ArrayBuffer,
    7 * TrianglesVertCount * sizeof(float),
    TrianglesVertData, BufferUsageHint.StaticDraw);

GL.BindBuffer(BufferTarget.ArrayBuffer, 0);

// VAO SETUP

VAO = GL.GenVertexArray();
GL.BindVertexArray(VAO);

// Position
GL.EnableVertexAttribArray(0);
GL.VertexAttribFormat(0, 3, VertexAttribType.Float, false, 0);
GL.VertexArrayAttribBinding(VAO, 0, 0);

// COlor
GL.EnableVertexAttribArray(1);
GL.VertexAttribFormat(1, 4, VertexAttribType.Float, false, 3 * sizeof(float));
GL.VertexArrayAttribBinding(VAO, 1, 0);

int vec4Size = 4;
GL.EnableVertexAttribArray(2);
GL.VertexAttribFormat(2, 4, VertexAttribType.Float, false, 0 * vec4Size * sizeof(float));
GL.VertexAttribFormat(3, 4, VertexAttribType.Float, false, 1 * vec4Size * sizeof(float));
GL.VertexAttribFormat(4, 4, VertexAttribType.Float, false, 2 * vec4Size * sizeof(float));
GL.VertexAttribFormat(5, 4, VertexAttribType.Float, false, 3 * vec4Size * sizeof(float));

GL.VertexAttribDivisor(2, 1);
GL.VertexAttribDivisor(3, 1);
GL.VertexAttribDivisor(4, 1);
GL.VertexAttribDivisor(5, 1);

GL.VertexArrayAttribBinding(VAO, 2, 1);

GL.BindVertexArray(0);

OnFrameRender SN-P:

shader.Use();
shader.SetMatrix4("view", cameraViewMatrix);
shader.SetMatrix4("projection", cameraProjectionMatrix);

int mat4Size = 16;

for (int i = 0; i < simulation.poolCount; i++)
{
    modelMatrix[i] = Matrix4.CreateFromAxisAngle(
        this.RotationAxis, simulation.pool[i].Angle);

    modelMatrix[i] = matrix[i] * Matrix4.CreateTranslation(new Vector3(
        simulation.pool[i].Position.X,
        simulation.pool[i].Position.Y,
        0f));

    //modelMatrix[i] = Matrix4.Identity;
}

// Copy model matrices into the VBO
// ----------------------------------------
GL.BindBuffer(BufferTarget.ArrayBuffer, InstanceVBO);
GL.BufferData(BufferTarget.ArrayBuffer,
    simulation.poolCount * mat4Size * sizeof(float),
    modelMatrix, BufferUsageHint.DynamicDraw);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
// ----------------------------------------

GL.BindVertexArray(VAO);

GL.BindVertexBuffer(1, InstanceVBO, IntPtr.Zero, mat4Size * sizeof(float));

GL.BindVertexBuffer(0, VBO[0], IntPtr.Zero, 7 * sizeof(float));
GL.DrawArraysInstanced(PrimitiveType.LineLoop, 0, LineLoopVertCount, simulation.poolCount);

GL.BindVertexBuffer(0, lifeFormVBO[1], IntPtr.Zero, lifeFormTrianglesFStride * sizeof(float));
GL.DrawArraysInstanced(PrimitiveType.Triangles, 0, TrianglesVertCount, simulation.poolCount);

GL.BindVertexArray(0);

【问题讨论】:

    标签: c# opengl opentk


    【解决方案1】:

    这里有很多错误。

    首先,您不会在 2 之后启用任何属性数组,即使您的着色器说您也在读取 3-5。同样,您不为 2 之后的任何数组设置属性绑定。

    但是你更大的问题是你使用glVertexAttribDivisor。那就是错误的功能对于你正在尝试做的事情。那是用于设置除数的旧 API。

    在单独的属性格式中,除数是缓冲区绑定的一部分,不是顶点属性。所以除数需要设置为glVertexBindingDivisor,它给出的索引就是你打算绑定缓冲区的索引。哪个应该是1。

    所以大概,你的代码应该是这样的:

    int vec4Size = 4;
    for(int ix = 0; ix < 4; ++ix)
    {
      int attribIx = 2 + ix;
      GL.EnableVertexAttribArray(attribIx);
      GL.VertexAttribFormat(attribIx, 4, VertexAttribType.Float, false, ix * vec4Size * sizeof(float));
      GL.VertexArrayAttribBinding(VAO, attribIx, 1); //All use the same buffer binding
    }
    
    GL.VertexBindingDivisor(1, 1);
    

    【讨论】:

    • 是的,谢谢,这就是我要找的。现在正方形被渲染了。但是,我仍然缺少一些东西,因为在旋转按预期工作时矩阵的平移部分会失真。由于翻译数据位于矩阵的第 4 列,我认为该列有些地方无法正常工作。使用相同的矩阵并通过统一发送它,正方形按预期进行转换。
    • 我解决了这个问题。当矩阵通过 VBO 进入着色器时,由于某些未知原因被转置。当矩阵作为统一传递时,它们保持直线。我必须手动转回。有什么方法可以避免这种无用的双重转置,这肯定会花费 ops 吗?
    【解决方案2】:

    在 opentk 中,矩阵按列发送,而不是像往常一样按行发送,因此有必要按列反转行,您可以这样做。

    private Matrix4[] TransposeMatrix(Matrix4[] inputModel)
    {
        var outputModel = new Matrix4[inputModel.Length];
        for(int i = 0; i < inputModel.Length; i++)
        {
            outputModel[i].Row0 = inputModel[i].Column0;
            outputModel[i].Row1 = inputModel[i].Column1;
            outputModel[i].Row2 = inputModel[i].Column2;
            outputModel[i].Row3 = inputModel[i].Column3;
        }
        return outputModel;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-12
      • 1970-01-01
      相关资源
      最近更新 更多