OpenGL:如何使用深度排序的顶点数组设计高效的渲染系统?

New*_*bie 5 c++ opengl vbo vertex-array

人们总是告诉我至少使用顶点阵列.但我认为这不是一个好主意,因为我正在使用glPushMatrix()glTranslatef/glRotatef来定位3d世界中的对象.

那么,我应该停止使用glPushMatrix()并"手动"计算世界中旋转/移动的顶点位置,然后将它们的顶点数据推入顶点数组然后立即渲染它们吗?

但是,当我为屏幕上的所有对象使用不同的纹理表面时,所有这些都会变得更加混乱,这些对象也是深度排序的.

所以:

  1. 我还必须使用纹理表面ID存储每个对象.
  2. 我会按Z的位置对所有可见物体进行排序(游戏仅从上到下查看,所有物体都是平的).
  3. 我会通过这个排序的数组:
  4. 创建新缓冲区并仅将vertex/texcoord/color/normal复制到此缓冲区中:
  5. 每次纹理表面ID从先前的ID更改时,我将绑定到正确的纹理ID:
  6. 上传我收集的顶点数据.
  7. 释放用于临时顶点数组的缓冲区.
  8. 重复步骤4-7,直到我完成了我在第一个位置排序的所有数据.
  9. 释放我的排序数组数据,并重复步骤1-9.

我做得对吗?

另外,我应该如何为我要排序的对象设计数据结构?例如,std::vector用于存储每个对象的顶点数据是否合适?还是有更好的选择吗?我当时认为std::vector存储所有这些数据看起来像:

struct GameObject {
    int TexID;
    float z; // we will sort by this
    vector<VTCNStruct> VertexData; // store each point of the object here (including color/normal/texcoord points).
};

vector<GameObject> GameObjectBuffer; // push all sortable objects here
Run Code Online (Sandbox Code Playgroud)

此外,在步骤4:std::vector在这种情况下是否可以使用已经存在的?我有这个想法,我必须使用原始数组,比如new float[100]将顶点数组发送到我的GPU,或者我可以某种std::vector方式(有效地)以某种方式使用我已经存在的排序,而不是每次纹理ID更改时都创建新的缓冲区?

dat*_*olf 11

Pleae放弃在glBegin/glEnd 现在,它是过时和OpenGL的-4已被删除.你绝对应该使用顶点数组,如果使用顶点缓冲区对象,则更好.

使用立即模式(glBegin/glEnd),OpenGL驱动程序必须从函数调用构建一个顶点数组.由于不清楚有多少个顶点到达,它最终将重新分配内存多次(GPU直接执行glBegin/glEnd之间的调用的时间很长).

使用顶点数组的性能永远不会比立即数模式低.将多个对象的几何体放入单个顶点数组中是可以的,您可以通过顶点索引列表将它们分开.顶点索引列表也可以存储在缓冲区对象中.

然后在绘制对象之间调整模型视图矩阵.

排序顺序应该如下:

  1. 分为不透明和半透明的物体.排序不透明
  2. 通过GL对象(纹理,着色器,材质等)对opqaues进行排序,因为切换GL对象是最昂贵的.
  3. 对于每个不同的GL对象组,从远到近排序并按该顺序绘制
  4. 将半透明分类到远近,并按顺序绘制

你不应该尝试摆弄缓冲区上传/下载.只需上传顶点数据一次,然后调整索引数组及其提交顺序.没有必要担心可用的OpenGL内存,没有强制执行限制.如果您的数据不适合GPU RAM,则驱动程序负责将其交换到系统内存 - 这也是您首先应该按OpenGL对象排序的原因,因为每次切换OpenGL对象(glBindTexture,glBindBuffer等)时,驱动程序都可能需要交换,因此您希望将这些交换操作保持在最低限度.以索引数组的形式发送到GPU的数据量将远远少于立即模式调用发送的数据量:

  • 索引数组:每个顶点16位(16位大小索引最高性能).

  • 立即模式调用:每个顶点4*32位