Open GL DrawArrays 只绘制一个 triangle/line/point (OpenTK / C#)

Open GL DrawArrays only draws one triangle/line/point (OpenTK / C#)

在这个基本的渲染测试中,我已经从一个文件中加载了 32 个顶点的数据。当它绘制时,它只会绘制一个图元并忽略数组的其余部分。例如,如果我调用 GL.DrawArrays(PrimitiveType.Triangles, i, 3) 它将绘制元素 i.

该数组确实包含了不止一个三角形的数据,因为这里的示例代码会在您每次单击时绘制一个不同的三角形,但每次也只会绘制 一个渲染。如果我使用不同的 int first 参数对 DrawArrays 进行多次调用,它还会为每次调用绘制一个额外的三角形。 (我很确定将所有数据放入 GPU 缓冲区的目的并不是为了让您可以进行无数次绘制调用。)

我试过使用 drawelements 作为 drawarrays 的替代品,但无论我为参数设置什么,我都会得到 System.AccessViolationException。我能找到的所有教程总是只绘制一个三角形 and/or 使用 drawelements,所以我无法找到代码示例来帮助我弄清楚绘制多个图元有什么不同或可能有什么不同。

Form1 只是一个带有 glcontrol 的空白表单。我正在使用 NuGet 包 OpenTK 3.1.0 和 OpenTK.GLControl 3.1.0.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenTK.Graphics.OpenGL4;
using OpenTK;

namespace _3dRenderingTesting
{
    public partial class Form1 : Form
    {
        int program;
        int myVAO;
        int i = 0;
        private void glControl1_MouseClick(object sender, MouseEventArgs e)
        {
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            GL.Enable(EnableCap.DepthTest);
            GL.UseProgram(program);
            GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
            GL.DrawArrays(PrimitiveType.Triangles, i, 3);
            glControl1.SwapBuffers();
            i++;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            program = compileShaders();
            getMeshFromFile();
        }

        public Form1()
        {
            InitializeComponent();
        }

        private int compileShaders()
        {
            string vShader;
            using (System.IO.StreamReader file = new System.IO.StreamReader(@"vertexshader.txt"))
            {
                vShader = file.ReadToEnd();
            }

            string fShader = "";
            using (System.IO.StreamReader file = new System.IO.StreamReader(@"fragmentshader.txt"))
            {
                fShader = file.ReadToEnd();
            }

            int vertexShader = GL.CreateShader(ShaderType.VertexShader);
            GL.ShaderSource(vertexShader, vShader);
            GL.CompileShader(vertexShader);

            int fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
            GL.ShaderSource(fragmentShader, fShader);
            GL.CompileShader(fragmentShader);

            int program = GL.CreateProgram();
            GL.AttachShader(program, vertexShader);
            GL.AttachShader(program, fragmentShader);

            GL.LinkProgram(program);
            GL.DeleteShader(vertexShader);
            GL.DeleteShader(fragmentShader);
            return program;
        }

        private int vertBuffer;
        private int vertLength;

        private void getMeshFromFile()
        {
            List<string> fileContents = new List<string>();
            List<float> fVerts = new List<float>();
            List<int> fFaces = new List<int>();
            System.IO.StreamReader file = new System.IO.StreamReader(@"C:\Users\abc\Desktop Vertex Sphere.obj");
            while (!file.EndOfStream)
            {
                string ts = file.ReadLine().Trim().ToLower();
                //find all lines that begin with "v"
                //these are vertices
                if (ts.Length > 0)
                {
                    if (ts.Substring(0, 1) == "v")
                    {
                        const string reduceMultiSpace = @"[ ]{2,}";
                        string[] tSplit = System.Text.RegularExpressions.Regex.Replace(ts.Replace(" ", ",").Replace("\t", ","), reduceMultiSpace, ",").Split(',');
                        if (tSplit.Length < 4)
                        {
                            MessageBox.Show("Vertex list failure (< 3 vertices)");
                            Application.Exit();
                        }
                        fVerts.Add(float.Parse(tSplit[1]));
                        fVerts.Add(float.Parse(tSplit[2]));
                        fVerts.Add(float.Parse(tSplit[3]));
                    }
                    if (ts.Substring(0, 1) == "f")
                    {
                        const string reduceMultiSpace = @"[ ]{2,}";
                        string[] tSplit = System.Text.RegularExpressions.Regex.Replace(ts.Replace(" ", ",").Replace("\t", ","), reduceMultiSpace, ",").Split(',');
                        if (tSplit.Length < 4)
                        {
                            MessageBox.Show("Face list failure (< 3 vertices)");
                            Application.Exit();
                        }
                        fFaces.Add(int.Parse(tSplit[1]));
                        fFaces.Add(int.Parse(tSplit[2]));
                        fFaces.Add(int.Parse(tSplit[3]));
                    }
                }
            }
            file.Close();

            float[] fVArray = new float[fVerts.Count];
            for (int i = 0; i < fVerts.Count; i++) fVArray[i] = fVerts[i];

            GL.CreateBuffers(1, out vertBuffer);
            GL.BindBuffer(BufferTarget.ArrayBuffer, vertBuffer);
            GL.NamedBufferStorage(vertBuffer, sizeof(float) * fVerts.Count, fVArray, BufferStorageFlags.MapWriteBit | BufferStorageFlags.MapReadBit);
            vertLength = fVerts.Count;

            GL.CreateVertexArrays(1, out myVAO);
            GL.BindVertexArray(myVAO);
            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 3 * sizeof(float), 0); 
            GL.EnableVertexAttribArray(0);
        }
    }
}

顶点文件:

v 0 -1 0
v -0.4924088 0.7946551 -0.3550447
v 0.5536816 0.7946597 -0.2489026
v -0.06729457 -0.74536 0.6632572
v -0.9165487 0.3333308 -0.220973
v 0.06729444 0.7453622 -0.6632546
v 0.2669053 0.3333269 0.9042426
v -0.06128498 0.7946486 0.6039683
v 0.8958825 -0.1875861 -0.4027478
v -5.442639E-06 1 9.193043E-06
v -0.6496407 -0.3333396 0.6832653
v 0.6080519 -0.7453524 -0.2733544
v -0.5536865 -0.7946557 0.2489048
v -0.8958843 0.1875851 0.4027444
v 0.4430935 -0.3333268 -0.8322027
v 0.9422514 0.3333381 -0.03236934
v -0.5407486 -0.7453555 -0.3899181
v -0.09915181 -0.1875999 0.9772283
v 0.4924095 -0.7946548 0.3550446
v -0.9422525 -0.333336 0.03236436
v 0.0612843 -0.7946532 -0.6039625
v 0.91655 -0.3333305 0.2209681
v 0.4991637 -0.3333373 0.7998261
v -0.4430951 0.3333244 0.8322028
v -0.2669008 -0.3333296 -0.9042429
v -0.7967249 -0.1875918 -0.5744899
v 0.5407484 0.7453554 0.3899185
v 0.7967286 0.1875919 0.5744848
v 0.09915482 0.1876006 -0.9772278
v 0.6496406 0.3333421 -0.6832644
v -0.6080542 0.7453504 0.2733551
v -0.4991595 0.3333374 -0.7998286

简单的 v&f 着色器:

#version 450 core
layout (location = 0) in vec4 position;

void main(void)
{
    gl_Position = position;
}
#version 450 core
out vec4 FragColor;

void main(void)
{
    FragColor = vec4(1.0,1.0,1.0,1.0);
}

ELEMENT_ARRAY_BUFFER 表示在 Vertex Array Object, so the vertex array object has to be bound, before the element array buffer can be bound. See Index buffers

# create vertex buffer
GL.CreateBuffers(1, out vertBuffer);
GL.NamedBufferStorage(vertBuffer, sizeof(float) * fVerts.Count, fVArray,
                      BufferStorageFlags.MapWriteBit | BufferStorageFlags.MapReadBit);
vertLength = fVerts.Count;

# create index buffer
GL.CreateBuffers(1, out indexBuffer);
GL.NamedBufferStorage(indexBuffer, sizeof(int) * fFaces.Count, fFaces , 
                      BufferStorageFlags.None);
indexCount = fFaces.Count;

# bind vertex array object
GL.CreateVertexArrays(1, out myVAO);
GL.BindVertexArray(myVAO);

# specify array of generic vertex attribute data for currently bound vertex array object
GL.BindBuffer(BufferTarget.ArrayBuffer, vertBuffer);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 3 * sizeof(float), 0); 
GL.EnableVertexAttribArray(0);

# associate index buffer to currently bound vertex array object
GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBuffer);

绘图:

GL.DrawElements(BeginMode.Triangles, indexCount, DrawElementsType.UnsignedInt, 0);