我正在尝试在 opentk 中实现索引缓冲区对象,但不知道在绘图时如何实际使用它

Posted

技术标签:

【中文标题】我正在尝试在 opentk 中实现索引缓冲区对象,但不知道在绘图时如何实际使用它【英文标题】:i'm trying to implement index buffer object in opentk but don't know how to actually use it when drawing things 【发布时间】:2019-09-06 08:49:29 【问题描述】:

我正在尝试使用索引缓冲区,但不知道如何

对于我什至应该尝试什么,我真的陷入了困境。 这些教程都没有真正显示与我的代码相似的任何内容,这主要是我遇到问题的原因。我可能不得不重写立方体顶点数组创建器。 (换一种说法,也许我不应该把 opengl 塞进一些现成的代码中)现在我只启用了顶面来看看发生了什么。

/// <summary>
/// Draws the specified Cube Onsccreen.
/// </summary>
public void Draw()

    GL.UseProgram(VSID);
    Vector3 ObjectPosition = new Vector3((new Vector(1, 1) * (Position - Offset)))
    
        Z = Layer * 0.1f
    ;
    Matrix4 Scale = Matrix4.CreateScale(Width + highlight, Height + highlight, Height + highlight);
    Matrix4 Translation = Matrix4.CreateTranslation(ObjectPosition);
            
    Matrix4 ViewPoint = Matrix4.CreateOrthographic(Game.window.Width , Game.window.Height, -1, 1000);
    ViewPoint = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI-Zoom,Game.window.Width/Game.window.Height,0.0001f,1000);
    Matrix4 Rotation = Matrix4.CreateRotationZ((float)Angle);
    Matrix4 CameraRotX = Matrix4.CreateRotationX((float)Math.PI / 180 * 40f);
    Matrix4 CameraRotZ = Matrix4.CreateRotationZ(Game.CameraAngle);

    Matrix4 Combined = Scale * Rotation  * Translation * ViewPoint * CameraRotZ * CameraRotX;

    GL.ProgramUniformMatrix4(VSID, GL.GetUniformLocation(VSID, "QuadMatrix"), false, ref Combined);
    GL.ProgramUniform4(VSID, GL.GetUniformLocation(VSID, "ColorIn"), Color);
    GL.ProgramUniform1(VSID, GL.GetUniformLocation(VSID, "SS"), 0);

    GL.Enable(EnableCap.Texture2D);
    GL.Enable(EnableCap.IndexArray);

    GL.ActiveTexture(TextureUnit.Texture0);
    GL.BindTexture(TextureTarget.Texture2D, Texture);
    GL.BindVertexArray(QID);
    GL.DrawArrays(PrimitiveType.Triangles, 0, indices.Length);


public static void CreateVisuals()

    int VS = Shaders.Load("Shaders.vs", ShaderType.VertexShader);
    int FS = Shaders.Load("Shaders.fs", ShaderType.FragmentShader);

    VSID = Visuals.Create(VS, FS);


public static void CreateCube()

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

    int VID =GL.GenBuffer();
    float[] Verticles = 
    
        -0.5f,  0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
        -0.5f, -0.5f,  0.5f,
         0.5f, -0.5f,  0.5f,
        -0.5f,  0.5f, -0.5f,
         0.5f,  0.5f, -0.5f,
        -0.5f, -0.5f, -0.5f,
         0.5f, -0.5f, -0.5f
    ;

    GL.BindBuffer(BufferTarget.ArrayBuffer, VID);
    GL.BufferData(BufferTarget.ArrayBuffer, sizeof(float) * Verticles.Length, Verticles,BufferUsageHint.StaticDraw);
    GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
    GL.EnableVertexAttribArray(0);
            
    int UVID = GL.GenBuffer();
    float[] UVs =
    
        0, 1,
        1, 1,
        0, 0,
        0, 0,
        1, 1,
        1, 0
    ;

    GL.BindBuffer(BufferTarget.ArrayBuffer, UVID);
    GL.BufferData(BufferTarget.ArrayBuffer, sizeof(float) * UVs.Length, UVs, BufferUsageHint.StaticDraw);
    GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 0, 0);
    GL.EnableVertexAttribArray(1);

    indices = new uint[]
    
        0, 1, 2,
        2, 1, 3 /*,
        0, 1, 5,
        0, 1, 4,
        1, 3, 5,
        3, 5, 7,
        2, 3, 7,
        2, 6, 7,
        0, 2, 6,
        0, 4, 6,
        4, 5, 6,
        5, 6, 7 //*/
    ;
    IBO = GL.GenBuffer();

    GL.BindBuffer(BufferTarget.ElementArrayBuffer, IBO);
    GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(sizeof(uint) * indices.Length), indices, BufferUsageHint.StaticDraw);
    GL.VertexAttribPointer(IBO,1,VertexAttribPointerType.UnsignedInt,false,0,0);
    GL.EnableVertexAttribArray(2);

不是绘制一个简单的四边形,而是以错误的顺序绘制了 2 个三角形。它实际上只是使用空间中的坐标而不是这些坐标的索引 目前看起来像这样:

【问题讨论】:

【参考方案1】:

Index buffer 的名称(值)在Vertex Array Object 的状态向量中表示。 要“使用”它,您需要对顶点数组对象进行 binbd 处理并调用 glDrawElements 而不是 glDrawArrays

GL.BindVertexArray(QID);
GL.DrawElements(PrimitiveType.Triangles, 0, DrawElementsType.UnsignedInt, NULL);

您必须“复制”顶点位置。见Rendering meshes with multiple indices。顶点坐标及其属性(如纹理坐标)形成一个元组。您可以将 3D 顶点坐标和 2D 纹理坐标想象为单个 5D 坐标。

至少你必须为立方体的两条边使用单独的顶点和属性。这意味着您至少需要 8+2*2=12 组不同的顶点属性。

         x    y    z      u  v
0  :    -0.5  0.5  0.5    0  0
1  :     0.5  0.5  0.5    1  0
2  :    -0.5 -0.5  0.5    0  1
3  :     0.5 -0.5  0.5    1  1
4  :    -0.5 -0.5 -0.5    0  0
5  :     0.5 -0.5 -0.5    1  0
6  :    -0.5  0.5 -0.5    0  1 
7  :     0.5  0.5 -0.5    1  1
8  :    -0.5  0.5  0.5    1  1
9  :    -0.5  0.5 -0.5    1  0
10 :     0.5  0.5  0.5    0  1
11 :     0.5  0.5 -0.5    0  0

注意,索引为 0、2、4 和 6 的顶点属性集的 u 坐标相同为 0。索引为 1、3、5 和 7 的顶点属性集的 u 坐标相同为1. 如果要将纹理包装到四边形,则必须改变 u 和 v 坐标。因此,您必须添加分离的顶点属性集 8、9、10 和 11。

通过这种顶点坐标和纹理坐标的设置,您可以定义立方体的 12 个三角形面:

0 - 2 -  1    2 -  3 -  1
8 - 9 -  2    9 -  4 -  2
2 - 4 -  3    4 -  5 -  3
3 - 5 - 10    5 - 11 - 10
4 - 6 -  5    6 -  7 -  5
6 - 0 -  7    0 -  1 -  7

【讨论】:

这确实是有道理的,我正在修复它,但这并没有改变我实际上不能使用索引缓冲区的事实,因为这是一个编码问题,还没有看到很好的解释。 .. @jklw10 我已经扩展了答案。见第一部分。 k 我将其标记为正确答案,因为它是最广泛的。也请您帮助索引【参考方案2】:

所以我的问题是我从 2d 到 3d,从简单的四边形到索引缓冲对象,当你从使用的顶点绘制直线时

GL.DrawArrays();

但是当您使用索引缓冲区对象时,您应该使用

GL.DrawElements();

因为您在这里将索引保存到元素缓冲区中:

GL.BindBuffer(BufferTarget.ElementArrayBuffer, IBO);

【讨论】:

这在我的回答的第一部分中提到了。

以上是关于我正在尝试在 opentk 中实现索引缓冲区对象,但不知道在绘图时如何实际使用它的主要内容,如果未能解决你的问题,请参考以下文章

OpenTK - 累积缓冲区的可用性

OpenTK 屏幕外帧缓冲区扭曲并使用相同的材​​料不正确地渲染?

C# OpenTK - 不渲染的简单示例

如何在 WebGL 中实现阴影映射?

在 ncurses 中实现文本滚动的推荐方法是啥?

我正在尝试在我的应用程序中实现搜索栏,以便我可以搜索从 parse.com 检索到的对象