OpenGL技术可能非常晦涩难懂。我知道!我已经用基于OpenGL的3D引擎写了多年(断断续续)。在我的情况下,问题的一部分是,我编写引擎来隐藏底层的3D API(OpenGL),所以一旦我使某些东西工作起来,我再也不看OpenGL代码了。
但是这里有一个技巧可以帮助我的大脑理解“OpenGL方式”。我认为这种思考方式是正确的(但不是全部)。
想想硬件图形/GPU卡。它们在硬件中实现了某些功能。例如,GPU可能只能同时更新(写入)一个纹理。尽管如此,GPU内存中必须包含许多纹理,因为CPU内存和GPU内存之间的传输非常缓慢。
因此,OpenGL API创建了“活动纹理”的概念。然后,当我们调用OpenGL API函数将图像复制到纹理时,我们必须这样做:
1: generate a texture and assign its identifier to an unsigned integer variable.
2: bind the texture to the GL_TEXTURE bind point (or some such bind point).
3: specify the size and format of the texture bound to GL_TEXTURE target.
4: copy some image we want on the texture to the GL_TEXTURE target.
如果我们想在另一个纹理上绘制图像,我们必须重复相同的过程。
当我们最终准备在显示器上呈现某些东西时,我们的代码需要使我们创建和复制图像的一个或多个纹理成为我们的片段着色器可以访问的。
事实证明,片段着色器可以通过访问多个“纹理单元”(每个纹理单元一个纹理)同时访问多个纹理。因此,我们的代码必须将我们想要可用于纹理单元的纹理绑定到我们的片段着色器期望它们绑定到的纹理单元中。
所以我们必须像这样做:
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, mytexture0);
glActiveTexture (GL_TEXTURE1);
glBindTexture (GL_TEXTURE_2D, mytexture1);
glActiveTexture (GL_TEXTURE2);
glBindTexture (GL_TEXTURE_2D, mytexture2);
glActiveTexture (GL_TEXTURE3);
glBindTexture (GL_TEXTURE_2D, mytexture3);
现在,我必须说我喜欢OpenGL的许多原因,但这种方法让我疯狂。这是因为多年来我编写的所有软件看起来都像这样:
error = glSetTexture (GL_TEXTURE0, GL_TEXTURE_2D, mytexture0);
error = glSetTexture (GL_TEXTURE1, GL_TEXTURE_2D, mytexture1);
error = glSetTexture (GL_TEXTURE2, GL_TEXTURE_2D, mytexture2);
error = glSetTexture (GL_TEXTURE3, GL_TEXTURE_2D, mytexture3);
只需指定要附加纹理的纹理单元、指示如何访问纹理的纹理类型以及要附加到纹理单元的纹理ID,就可以避免一遍又一遍地设置所有这些状态。此外,要将图像复制到指定纹理中,也不需要将其绑定为活动纹理,只需提供要复制的纹理ID即可。为什么它需要被绑定呢?
嗯,这是强制OpenGL按照目前的方式进行结构化的关键。因为硬件和软件驱动程序分别执行某些操作,并且由于在哪里执行的操作是一个变量(取决于GPU卡),所以他们需要某种方式来控制复杂性。他们的解决方案实际上是对于每种实体/对象仅有一个绑定点,并要求我们将我们的实体绑定到这些绑定点,然后调用操纵它们的函数。其次,绑定实体是使它们对GPU和在GPU中执行的各种着色器可用的方法。
至少这就是我保持“OpenGL方式”始终清晰的方法。老实说,如果有人真正、真正、真正地了解OpenGL必须以其方式进行结构化的所有原因,我会很高兴看到他们发表自己的回复。我认为这是一个重要的问题和主题,但是其基本原理很少被描述,更不用说以我这样微不足道的大脑可以理解的方式描述了。
b=5
就是将5
绑定到了b
上。c="asdf"
就是将"asdf"
绑定到了c
上。你可以通过“名字”将“内存”绑定为漂亮(或丑陋)的名字。 - n611x007