问题描述
这学期,我在我的大学修了计算机图形学课程.目前,我们开始研究一些更高级的东西,比如高度图、平均法线、镶嵌等.
This semester, I took a course in computer graphics at my University. At the moment, we're starting to get into some of the more advanced stuff like heightmaps, averaging normals, tesselation etc.
我来自面向对象的背景,所以我试图将我们所做的一切都放入可重用的类中.我已经成功创建了一个相机类,因为它主要依赖于对 gluLookAt() 的一次调用,它几乎独立于 OpenGL 状态机的其余部分.
I come from an object-oriented background, so I'm trying to put everything we do into reusable classes. I've had good success creating a camera class, since it depends mostly on the one call to gluLookAt(), which is pretty much independent of the rest of the OpenGL state machine.
但是,我在其他方面遇到了一些麻烦.使用对象来表示基元对我来说并没有真正成功.这是因为实际的渲染调用依赖于许多外部事物,例如当前绑定的纹理等.如果您突然想将特定类的表面法线更改为顶点法线,这会导致严重的头痛.
However, I'm having some trouble with other aspects. Using objects to represent primitives hasn't really been a success for me. This is because the actual render calls depend on so many external things, like the currently bound texture etc. If you suddenly want to change from a surface normal to a vertex normal for a particular class it causes a severe headache.
我开始怀疑 OO 原则是否适用于 OpenGL 编码.至少,我认为我应该让我的课程不那么细化.
I'm starting to wonder whether OO principles are applicable in OpenGL coding. At the very least, I think that I should make my classes less granular.
堆栈溢出社区对此有何看法?您在 OpenGL 编码方面的最佳做法是什么?
What is the stack overflow community's views on this? What are your best practices for OpenGL coding?
推荐答案
最实用的方法似乎是忽略大部分不直接适用的 OpenGL 功能(或者速度慢,或者没有硬件加速,或者不再是非常适合硬件).
The most practical approach seems to be to ignore most of OpenGL functionality that is not directly applicable (or is slow, or not hardware accelerated, or is a no longer a good match for the hardware).
OOP 与否,要渲染一些场景,这些场景是您通常拥有的各种类型和实体:
OOP or not, to render some scene those are various types and entities that you usually have:
几何(网格).大多数情况下,这是一个顶点数组和索引数组(即每个三角形三个索引,又名三角形列表").顶点可以是某种任意格式(例如,只有一个 float3 位置;一个 float3 位置 + float3 法线;一个 float3 位置 + float3 法线 + float2 texcoord;等等).所以要定义一个你需要的几何体:
Geometry (meshes). Most often this is an array of vertices and array of indices (i.e. three indices per triangle, aka "triangle list"). A vertex can be in some arbitrary format (e.g. only a float3 position; a float3 position + float3 normal; a float3 position + float3 normal + float2 texcoord; and so on and so on). So to define a piece of geometry you need:
- 定义它的顶点格式(可以是位掩码,格式列表中的枚举;...),
- 具有顶点数组,其组件交错(交错数组")
- 有三角形数组.
如果你在 OOP 领域,你可以称这个类为 Mesh.
If you're in OOP land, you could call this class a Mesh.
材料 - 定义几何体如何渲染的东西.例如,在最简单的情况下,这可能是对象的颜色.或者是否应该应用照明.或者对象是否应该进行 alpha 混合.或者要使用的纹理(或纹理列表).或者要使用的顶点/片段着色器.等等,可能性是无穷无尽的.首先将您需要的东西放入材料中.在 OOP 领域,该类可以被称为(惊喜!)Material.
Materials - things that define how some piece of geometry is rendered. In a simplest case, this could be a color of the object, for example. Or whether lighting should be applied. Or whether the object should be alpha-blended. Or a texture (or a list of textures) to use. Or a vertex/fragment shader to use. And so on, the possibilities are endless. Start by putting things that you need into materials. In OOP land that class could be called (surprise!) a Material.
场景 - 您有几何体、材料集合、时间来定义场景中的内容.在一个简单的情况下,场景中的每个对象都可以通过以下方式定义:- 它使用什么几何体(指向网格的指针),- 它应该如何呈现(指向 Material 的指针),- 它位于何处.这可以是 4x4 变换矩阵,或 4x3 变换矩阵,或向量(位置)、四元数(方向)和另一个向量(比例).让我们称之为 OOP 领域中的 Node.
Scene - you have pieces of geometry, a collection of materials, time to define what is in the scene. In a simple case, each object in the scene could be defined by: - What geometry it uses (pointer to Mesh), - How it should be rendered (pointer to Material), - Where it is located. This could be a 4x4 transformation matrix, or a 4x3 transformation matrix, or a vector (position), quaternion (orientation) and another vector (scale). Let's call this a Node in OOP land.
相机.好吧,相机只不过是放置的位置"(同样是 4x4 或 4x3 矩阵,或位置和方向),加上一些投影参数(视野、纵横比……).
Camera. Well, a camera is nothing more than "where it is placed" (again, a 4x4 or 4x3 matrix, or a position and orientation), plus some projection parameters (field of view, aspect ratio, ...).
基本上就是这样!你有一个场景,它是一堆引用网格和材质的节点,你有一个定义观察者所在位置的相机.
So basically that's it! You have a scene which is a bunch of Nodes which reference Meshes and Materials, and you have a Camera that defines where a viewer is.
现在,将实际 OpenGL 调用放在哪里只是一个设计问题.我想说,不要将 OpenGL 调用放入 Node、Mesh 或 Material 类中.相反,制作类似 OpenGLRenderer 的东西,它可以遍历场景并发出所有调用.或者,更好的是,制作一些独立于 OpenGL 的遍历场景的东西,并将较低级别的调用放入 OpenGL 依赖类中.
Now, where to put actual OpenGL calls is a design question only. I'd say, don't put OpenGL calls into Node or Mesh or Material classes. Instead, make something like OpenGLRenderer that can traverse the scene and issue all calls. Or, even better, make something that traverses the scene independent of OpenGL, and put lower level calls into OpenGL dependent class.
是的,以上所有内容几乎都是平台独立的.这样下去,你会发现 glRotate、glTranslate、gluLookAt 和朋友是很没用的.您已经拥有所有矩阵,只需将它们传递给 OpenGL.无论如何,实际游戏/应用程序中的大多数真正的实际代码就是这样工作的.
So yes, all of the above is pretty much platform independent. Going this way, you'll find that glRotate, glTranslate, gluLookAt and friends are quite useless. You have all the matrices already, just pass them to OpenGL. This is how most of real actual code in real games/applications work anyway.
当然,上面的内容可能会因更复杂的需求而变得复杂.特别是,材料可能非常复杂.网格通常需要支持许多不同的顶点格式(例如,为了效率而打包法线).场景节点可能需要按层次结构组织(这个很容易 - 只需向节点添加父/子指针).蒙皮网格和动画通常会增加复杂性.等等.
Of course the above can be complicated by more complex requirements. Particularly, Materials can be quite complex. Meshes usually need to support lots of different vertex formats (e.g. packed normals for efficiency). Scene Nodes might need to be organized in a hierarchy (this one can be easy - just add parent/children pointers to the node). Skinned meshes and animations in general add complexity. And so on.
但主要思想很简单:场景中有几何体、材质、物体.然后一小段代码就可以渲染它们.
But the main idea is simple: there is Geometry, there are Materials, there are objects in the scene. Then some small piece of code is able to render them.
在 OpenGL 情况下,设置网格很可能会创建/激活/修改 VBO 对象.在渲染任何节点之前,需要设置矩阵.设置材质会影响大部分剩余的 OpenGL 状态(混合、纹理、照明、组合器、着色器……).
In OpenGL case, setting up meshes would most likely create/activate/modify VBO objects. Before any node is rendered, matrices would need to be set. And setting up Material would touch most of remaining OpenGL state (blending, texturing, lighting, combiners, shaders, ...).
这篇关于OpenGL 编码(特别是 w.r.t. 面向对象)有哪些最佳实践?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!