簡體   English   中英

OpenTK (OpenGL) 如何正確使用多個對象的 BufferSubData 和 DrawElements

[英]OpenTK (OpenGL) How to correctly use BufferSubData and DrawElements with multiple Objects

我試圖實現一個僅使用一個 VBO 和一個 EBO 來存儲所有對象頂點和索引的渲染器。 為此,我找到了一些教程,最后得出了一個相當不錯的結果。

問題是它只適用於一個單一的對象。 一旦我想添加另一個,渲染就會顯示奇怪的行為。

你能幫我解決這個問題嗎?

您可以在此處找到完整代碼: https : //github.com/BanditBloodwyn/TerritorySimulator 重要的類是:

  • Rendering.Core.Rendering.Renderer.cs
  • Rendering.Core.Classes.Shapes.GLShape.cs
  • Rendering.Core.RenderGUI.RenderGUI.cs

這是Renderer中的初始化方法:

    public void Initialize(GLShape[] shapeArray)
    {
        Shapes = shapeArray;

        GL.Enable(EnableCap.DepthTest);
        GL.ClearColor(0.0f, 0.0f, 0.10f, 1.0f);

        InitializeBuffers(Shapes);
        InitializeVertexArrayObject(Shapes);
        SetupShader();
        BindBuffers();
    }

子方法如下所示。

    private void InitializeBuffers(GLShape[] shapeArray)
    {
        int vertexBufferSize = shapeArray.Sum(shape => shape.VertexBufferSize);
        int indexBufferSize = shapeArray.Sum(shape => shape.IndexBufferSize);

        // Vertex buffer
        vertexBufferObject = GL.GenBuffer();
        GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
        GL.BufferData(BufferTarget.ArrayBuffer, vertexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);

        IntPtr offset = (IntPtr)0;
        foreach (GLShape shape in shapeArray)
        {
            GL.BufferSubData(BufferTarget.ArrayBuffer, offset, shape.VertexBufferSize, shape.Vertices);
            offset += shape.VertexBufferSize;
        }

        // Element buffer
        elementBufferObject = GL.GenBuffer();
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
        GL.BufferData(BufferTarget.ElementArrayBuffer, indexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);

        offset = (IntPtr)0;
        foreach (GLShape shape in shapeArray)
        {
            GL.BufferSubData(BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, shape.Indices);
            offset += shape.IndexBufferSize;
        }
    }

    private void InitializeVertexArrayObject(GLShape[] shapeArray)
    {
        foreach (GLShape shape in shapeArray)
        {
            shape.VertexArrayObject = GL.GenVertexArray();
            GL.BindVertexArray(shape.VertexArrayObject);
        }
    }

    private void SetupShader()
    {
        // shader
        string vertexPath = Path.Combine(Environment.CurrentDirectory, @"GLSL\", "Vertex.vert");
        string fragmentPath = Path.Combine(Environment.CurrentDirectory, @"GLSL\", "Fragment.frag");
        shader = new Shader(vertexPath, fragmentPath);
        shader.Use();

        int vertexLocation = shader.GetAttribLocation("aPosition");
        GL.EnableVertexAttribArray(vertexLocation);
        GL.VertexAttribPointer(
            vertexLocation, 
            3, 
            VertexAttribPointerType.Float, 
            false, 
            5 * sizeof(float), 
            0);

        int texCoordLocation = shader.GetAttribLocation("aTexCoord");
        GL.EnableVertexAttribArray(texCoordLocation);
        GL.VertexAttribPointer(
            texCoordLocation, 
            2, 
            VertexAttribPointerType.Float, 
            false, 
            5 * sizeof(float), 
            3 * sizeof(float));

        shader.SetInt("texture0", 0);
        shader.SetInt("texture1", 1);
    }

    private void BindBuffers()
    {
        GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
    }

渲染函數本身看起來像這樣。

    public void Render()
    {
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

        if (Shapes == null || Shapes.Length == 0)
            return;

        IntPtr offset = (IntPtr)0;
        foreach (GLShape shape in Shapes)
        {
            foreach (var texture in shape.Textures)
            {
                if (LayerConfiguration.ShowEarthTexture)
                    texture.Key.Use(texture.Value);
                else
                    texture.Key.MakeTransparent(texture.Value);
            }

            ApplyModelTransforms(shape, out Matrix4 model);
            shader.SetMatrix4("model", model);
            shader.SetMatrix4("view", Camera.GetViewMatrix());

            GL.DrawElements(PrimitiveType.Triangles, shape.Indices.Length, DrawElementsType.UnsignedInt, offset);
            offset += shape.IndexBufferSize;
        }

        shader.SetMatrix4("projection", Camera.GetProjectionMatrix());
        shader.Use();
    }

一旦我想添加另一個,渲染就會顯示奇怪的行為

當然,因為第二個和以下對象的索引是錯誤的。 您需要將先前網格的頂點總和添加到索引中。 第一個網格的索引必須添加 0,第二個網格的索引必須添加第一個網格的頂點數,第三個網格的索引必須添加頂點的總和第一個和第二個網格,...

offset = (IntPtr)0;
uint firstVertexIndex = 0;
foreach (GLShape shape in shapeArray)
{
    var indexArray = shape.Indices.Select(index => index + firstVertexIndex).ToArray();
                
    GL.BufferSubData(
        BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, indexArray);
    offset += shape.IndexBufferSize;
    firstVertexIndex += (uint)(shape.VertexBufferSize / (5 * sizeof(float)));
}

完整方法InitializeBuffers

private void InitializeBuffers(GLShape[] shapeArray)
{
    int vertexBufferSize = shapeArray.Sum(shape => shape.VertexBufferSize);
    int indexBufferSize = shapeArray.Sum(shape => shape.IndexBufferSize);

    // Vertex buffer
    vertexBufferObject = GL.GenBuffer();
    GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
    GL.BufferData(BufferTarget.ArrayBuffer, vertexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);

    IntPtr offset = (IntPtr)0;
    foreach (GLShape shape in shapeArray)
    {
        GL.BufferSubData(BufferTarget.ArrayBuffer, offset, shape.VertexBufferSize, shape.Vertices);
        offset += shape.VertexBufferSize;
    }

    // Element buffer
    elementBufferObject = GL.GenBuffer();
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
    GL.BufferData(BufferTarget.ElementArrayBuffer, indexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);

    offset = (IntPtr)0;
    uint firstVertexIndex = 0;
    foreach (GLShape shape in shapeArray)
    {
        var indexArray = shape.Indices.Select(index => index + firstVertexIndex).ToArray();
                
        GL.BufferSubData(BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, indexArray);
        offset += shape.IndexBufferSize;
        firstVertexIndex += (uint)(shape.VertexBufferSize / (5 * sizeof(float)));
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM