c++ - OpenGL 编码(特别是 w.r.t. 面向对象)有哪些最佳实践?

标签 c++ opengl oop

这个学期,我在我的大学修了一门计算机图形学类(class)。目前,我们开始研究一些更高级的东西,比如高度图、平均法线、镶嵌等。

我来自面向对象的背景,所以我试图把我们所做的一切都放在可重用的类中。我已经成功创建了一个相机类,因为它主要依赖于对 gluLookAt() 的一次调用,它几乎独立于 OpenGL 状态机的其余部分。

但是,我在其他方面遇到了一些麻烦。使用对象来表示基元对我来说并没有真正成功。这是因为实际的渲染调用依赖于许多外部事物,例如当前绑定(bind)的纹理等。如果您突然想将特定类的表面法线更改为顶点法线,这会导致严重的头痛。

我开始怀疑 OO 原则是否适用于 OpenGL 编码。至少,我认为我应该让我的类(class)不那么细化。

堆栈溢出社区对此有何看法? OpenGL 编码的最佳实践是什么?

最佳答案

最实用的方法似乎是忽略大多数不直接适用的 OpenGL 功能(或者速度慢,或者没有硬件加速,或者不再与硬件匹配)。

OOP 与否,要渲染一些场景,这些场景是您通常拥有的各种类型和实体:

几何 (网格)。大多数情况下,这是一个顶点数组和索引数组(即每个三角形三个索引,又名“三角形列表”)。顶点可以是某种任意格式(例如,只有一个 float3 位置;一个 float3 位置 + float3 法线;一个 float3 位置 + float3 法线 + float2 texcoord;等等)。因此,要定义一个几何图形,您需要:

  • 定义它的顶点格式(可以是位掩码,格式列表中的枚举;...),
  • 具有顶点数组,其组件交错(“交错数组”)
  • 有三角形数组。

  • 如果你在 OOP 领域,你可以称这个类为网格。

    Material - 定义某些几何体如何渲染的东西。例如,在最简单的情况下,这可能是对象的颜色。或者是否应该应用照明。或者对象是否应该进行 alpha 混合。或者要使用的纹理(或纹理列表)。或者要使用的顶点/片段着色器。等等,可能性是无穷无尽的。首先将您需要的东西放入 Material 中。在 OOP 领域,该类可以被称为(惊喜!)一个 Material 。

    场景 - 您有几何体、 Material 集合、定义场景中的内容的时间。在一个简单的情况下,场景中的每个对象都可以通过以下方式定义:
    - 它使用什么几何体(指向网格的指针),
    - 它应该如何呈现(指向 Material),
    - 它位于何处。这可以是 4x4 变换矩阵,或 4x3 变换矩阵,或 vector (位置)、四元数(方向)和另一个 vector (比例)。让我们将其称为 OOP 领域中的节点。

    相机 .好吧,相机只不过是“放置的位置”(同样是 4x4 或 4x3 矩阵,或位置和方向),加上一些投影参数(视野、纵横比……)。

    所以基本上就是这样!你有一个场景,它是一堆引用网格和 Material 的节点,你有一个定义查看器所在位置的相机。

    现在,将实际 OpenGL 调用放在哪里只是一个设计问题。我想说,不要将 OpenGL 调用放入 Node、Mesh 或 Material 类中。相反,制作类似 OpenGLRenderer 的东西,它可以遍历场景并发出所有调用。或者,更好的是,制作一些独立于 OpenGL 的场景,并将较低级别的调用放入 OpenGL 依赖类中。

    所以是的,以上所有内容几乎都是独立于平台的。这样下去,你会发现 glRotate、glTranslate、gluLookAt 和 friend 是很没用的。您已经拥有所有矩阵,只需将它们传递给 OpenGL。无论如何,这就是真实游戏/应用程序中大多数真实代码的工作方式。

    当然,上述内容可能因更复杂的要求而变得复杂。特别是, Material 可能非常复杂。网格通常需要支持许多不同的顶点格式(例如,为了效率而打包法线)。场景节点可能需要按层次结构组织(这个很容易 - 只需向节点添加父/子指针)。蒙皮网格和动画通常会增加复杂性。等等。

    但主要思想很简单:场景中有几何体、 Material 、物体。然后一些小的代码能够呈现它们。

    在 OpenGL 的情况下,设置网格很可能会创建/激活/修改 VBO 对象。在渲染任何节点之前,需要设置矩阵。设置 Material 会影响大部分剩余的 OpenGL 状态(混合、纹理、照明、组合器、着色器等)。

    关于c++ - OpenGL 编码(特别是 w.r.t. 面向对象)有哪些最佳实践?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/166356/

    相关文章:

    c++ - 将 glutTimerFunc 与 glutMouseFunc 一起使用

    python - 从Python中的静态方法调用非静态方法

    c++ - 当有多个查询时,检查某些子数组是否已排序的有效方法是什么?

    c - WinAPI - 同步交换缓冲区

    c++ - 重新定位形状/对象 - OpenGL

    java - 拥有具有相应设置方法的私有(private)变量的目的是什么?

    oop - 如何将一个类的 itcl 对象传递给另一个类的对象并使用所传递对象的功能?

    c++ - 使用引用比使用指针的优势是否证明偶尔出现 "null-references"是合理的?

    c++ - 问题在内联汇编中定义函数并从 C++ 调用

    c# - 向外部调用程序 C++ 返回一个值