OpenGL概念问题

4
我刚开始在Win32 C++中学习OpenGL编程,所以请不要太苛刻 :) 我已经浏览了NeHe教程和“红书”的一些内容,但我感到很困惑。到目前为止,我已经成功地建立了一个OpenGL窗口,绘制了一些三角形等等,没有问题。但现在我想建立一个模型,并从不同的角度来查看它。那么我们该怎么做呢?
  1. 将模型加载到内存中(在堆上保存三角形/四边形坐标的结构体),在每个场景渲染时,使用 glVertex3f 等方法将所有内容绘制到屏幕上。

  2. 只需使用 glVertex3f 等方法一次性加载/绘制模型,然后我们就可以在每个场景中更改视图位置。

  3. 其他...?

对我而言,选项1似乎是到目前为止最可行的选择,但它似乎有点愚蠢!我们必须决定哪些对象是可见的,仅绘制那些对象。这不是非常慢吗?选项2可能更具吸引力 :)
编辑:感谢所有的帮助,我已经决定:从文件中读取我的模型,然后使用 glBufferData 将其加载到GPU内存中,然后使用 glVertexPointer glDrawArrays 将数据传递给渲染函数。
2个回答

7
首先需要理解的是,OpenGL实际上并不理解“模型”这个术语,所有OpenGL看到的都是一串顶点流,并根据当前模式使用这些顶点流将三角形绘制到屏幕上。
每帧绘图迭代都遵循以下大纲:
清除所有缓冲区 对于每个窗口元素(主场景、HUD、小地图等): 设置裁剪区域和视口 条件性清除深度和/或模板 设置投影矩阵 设置初始视图的模型视图矩阵 对于每个模型: 将模型变换应用于矩阵堆栈 绑定模型数据(纹理、顶点等) 发出模型绘制命令
交换缓冲区 OpenGL不会记住上面发生的一切。有一个称为显示列表的工具,但它们无法存储所有类型的命令-而且它们已经被弃用并从最近的OpenGL版本中删除。立即模式命令glBegin、glEnd、glVertex、glNormal和glTexCoord也已被删除。
因此,想法是上传一些数据(纹理、顶点数组等)到OpenGL缓冲区对象中。然而,只有纹理被直接理解为它们所代表的内容(图像)。所有其他类型的缓冲区都需要您告诉OpenGL如何处理它们。这是通过调用gl{Vertex、Color、TexCoord、Normal、Attrib}Pointer来设置数据访问参数和glDraw{Arrays、Elements}触发OpenGL获取要提供给光栅化器的顶点流来完成的。

啊,好的,这个整体想法在这些年里有了一些变化。旧的教程仍然使用那些立即模式命令。我想我会去当地书店找一本最近的教程,因为这一切变得非常复杂(而我曾经认为自己在掌握Windows GDI后是王者...) - the_source
@the_source:基本思想从未改变,但得到简化的是数据发送到OpenGL的方式。在最近的OpenGL实现中,glBegin … glEnd块被直接转换为顶点数组,但在OpenGL层面之下(这意味着您不能通过即时模式调用来自动获取可用的VA)。每次调用glVertex就像将下一个顶点属性向量推送到顶点数组的末尾,并在过程中扩展它。 - datenwolf
@the_source 说的有点跑题,但既然你在谈论书籍,如果你真的想找一本关于现代GL而没有过时功能的书,我会推荐最新版的《超级圣经》,更多信息请参见这个问题。红皮书肯定有点过时了。但正如datenwolf所说,从旧风格中学习OpenGL并不会有任何害处,因为基本概念不会改变太多。 - Christian Rau
谢谢Christian,那个链接非常有帮助! - the_source

4

您应该将数据上传到GPU内存一次,然后尽可能少地使用命令来绘制每帧。

以前,这是使用显示列表完成的。现在,一切都与顶点缓冲对象(又称VBO)有关,因此请了解一下。

这里有一个关于VBO的教程,链接,在OpenGL之前它们只是扩展,而不是核心部分。


谢谢,所以实际上是选项1,但是我们将模型存储在GPU内存中,而不是堆上?我们仍然必须每帧绘制所有内容吗? - the_source
@the_source:有点像。你不需要指定每个顶点(这是我的主要观点),但你仍然需要在每一帧绘制场景。只是告诉GPU渲染它已经存在于本地内存中的数据比让CPU每帧逐个发送每个顶点要快得多。 - Macke
确实,你不需要每帧都将数据发送到GPU,但你必须要渲染它 :) - jcoder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接