【发布时间】:2017-11-09 03:32:23
【问题描述】:
我是 openGL 的新手,我正在开发一个应用程序,我需要在其中绘制多个线条,每个线条带有多个顶点。总共有 300,000 个顶点。
为了尝试有效地执行此操作,我使用 VBO 来存储顶点数据。
我使用单个 VBO 来存储所有线条的所有顶点。然后我使用GLDrawElements 来绘制整个 VBO,向它传递一个索引数组来指定要绘制的索引,并利用primitiveRestart 来指定 Linestrips 开始/结束的位置(参见下面的代码)。
这并没有像我希望的那样快速执行。我只能以大约 10Hz 的频率渲染。我在想也许是因为我传递了大量索引,每次渲染都必须将它们复制到 GPU。
我无法确定尝试提高性能的正确方向。着色器是正确的方法吗?有没有办法在渲染期间不将索引数组写入 GPU(DrawElements 需要)。
任何帮助确定正确的探索方向将不胜感激。
我正在使用 openTK 在 C# 中编写此代码。
//Enabled Primitive Restart
GL.Enable(EnableCap.PrimitiveRestart);
GL.PrimitiveRestartIndex(PrimitiveRestartIndex);
//Generate Linestrip data to buffer (array of vertices)
int[] FrameData = ScanBuffer.getBufferData();
//Create the buffer on the GPU
ScanBuffer.vbo_id = new int[1];
GL.GenBuffers(1, ScanBuffer.vbo_id);
//Buffer the data
GL.BindBuffer(BufferTarget.ArrayBuffer, ScanBuffer.vbo_id[0]);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(int) * FrameData.Length), FrameData, BufferUsageHint.StaticDraw);
GL.VertexPointer(2, VertexPointerType.Int, 0, 0);
GL.EnableClientState(ArrayCap.VertexArray);
//Generate the vertex index array
uint[] IndexData = ScanBuffer.getIndexData();
//Draw the VBO
GL.BindBuffer(BufferTarget.ArrayBuffer, ScanBuffer.vbo_id[0]);
GL.VertexPointer(2, VertexPointerType.Int, 0, 0);
GL.DrawElements(BeginMode.LineStrip, IndexData.Length, DrawElementsType.UnsignedInt, IndexData);
更新
我能够找到一个可行的解决方案,使用数组元素缓冲区来存储我的索引。我得到了大约 10 倍的性能提升。缓冲区和渲染命令如下所示。
缓冲区
vertexData = generateVertexData();
indexData = generateIndexData();
//Bind to the VAO
GL.BindVertexArray(vaoID[0]);
//Bind + Write Index Data to the Buffer
GL.BindBuffer(BufferTarget.ElementArrayBuffer, veoID[0]);
GL.BufferData(BufferTarget.ElementArrayBuffer, new IntPtr(sizeof(uint) * IndexData.Count()), IndexData.ToArray(), BufferUsageHint.StaticDraw);
//Bind + Write Scan Vertex Data to the Buffer
GL.BindBuffer(BufferTarget.ArrayBuffer, vboID[0]);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(int) * VertexData.Count()), VertexData.ToArray(), BufferUsageHint.StaticDraw);
GL.VertexPointer(2, VertexPointerType.Int, 0, 0);
GL.EnableClientState(ArrayCap.VertexArray);
//Remove Binding
GL.BindVertexArray(0);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
渲染循环
//Enabled Primitive Restart
GL.Enable(EnableCap.PrimitiveRestart);
GL.PrimitiveRestartIndex(PrimitiveRestartIndex);
GL.LineWidth(1);
GL.Color3(Color.Red);
GL.BindBuffer(BufferTarget.ArrayBuffer, vboID[0]);
GL.VertexPointer(2, VertexPointerType.Int, 0, 0);
//-Draw using a VEO-
GL.BindBuffer(BufferTarget.ElementArrayBuffer, veoID[0]);
GL.DrawElements(BeginMode.LineStrip, scanVertexBufferLength, DrawElementsType.UnsignedInt, 0);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
GL.BindVertexArray(0);
GL.Disable(EnableCap.PrimitiveRestart);
【问题讨论】:
-
您的数据是静态的还是动态的。如果是静态数据,您应该只上传一次数据,而不是每帧。
-
它是静态的。我认为这是我缺少的一件事。我只上传一次顶点数据,但我上传的索引数组每次都上传。有没有办法只上传一次该数组?
-
好吧……我在代码编译之间写了我的答案,最后我在你找到自己的答案后提交了它似乎