业精于勤,荒于嬉
全部博文(763)
分类: C/C++
2010-01-30 10:22:36
请注意:我对我写这个教程时的状态不是很满意,所以如果你有些地方有疑惑,请不要在意。如果哪里错了,也别担心,我会在第2节里继续解释它。
谁是 Mr. Buzzy? 那是我的厨房搅拌机!(英文里搅拌机和混合色是同样的)我们当然不是在谈论我的厨房搅拌机或者混合3d软件,我们在说OpenGL的混合。然而,这个部分可能要说2,3个教程。影响混合的效果是一些很小的细节,这就需要很多的说明。在以后的教程中会有详细的说明。
我还记得我第一使用混合时候的代码。幸运的是,我没有写自己的代码,但效果真的很酷。那是一个SGL的显卡。非常强大的处理能力,比不上现在的苹果,但当时,真的是很壮观的。
最主要的原因是因为有一个激动人心的时刻,在当时,我们还没有人见过混合时执行纹理映射,同时还有灯光及坐标转换。
无论如何,让我们把学习融合。混合,是相结合的过程中两个图像一起,使图像显示的前端部分透明。例如,只说你有一块红色的有机玻璃,并期待通过。世界上会出现红色的,因为颜色的有机玻璃将改变颜色的所有对象,通过它您可以查看。
因此,使混合工作,我们需要一个对象在前台是部分透明的(即阿尔法值小于1.0的RGBA颜色定义)和一些背后的,将被“混合型”的对象。
这是混合的关键,你需要两个对象,前面的对象是透明的,透明的部分即刻看到后面的物体。
我应该告诉你们,混合的正式名称是“阿尔法合成”。 我不会要求可以认为(从来没有),但您可能会看到这个词了。计算机图形学上涨了很长的路,因为我研究过,但正式的时候,我学过这个,我认为,融合是一种形式的阿尔法合成和Alpha合成的一种方法是单一或联合起草的图像和Alpha通道。
使用入门
下载第7章的教程:
我们将使用这个工程,并使用纹理映射过的金字塔和立方体在背景上,为了显示混合的效果。打开Xcode。
在 OpenGL中的混合
为了混合在OpenGL中工作起来,我们需要改变OpenGL中的“状态”以让我们可以使用混合。我敢肯定你知道如何做到这点。
glEnable(GL_BLEND);
添加到drawView函数,我们绘制之前,这样就可以使用半透明了,关闭这个状态使用glDisable()。
好了,混合接通(记得要关掉它,如果你不需要它) 。一个伟大的事情OpenGL的是,可以执行的混合使用不同的混合方法来产生不同的混合效果。这些所谓的混合功能。我就第一个节和讨论他们在下面详细说明。
好,回到drawView函数,我们要定义一个矩形,来放到我们两个物体之前。
const GLfloat blendRectangle[] = {
1.0, 1.0, -2.0,
-1.0, 1.0, -2.0,
-1.0, -1.0, -2.0,
1.0, -1.0, -2.0
};
我们想使两个。因此,在借鉴代码将使用glPushMatrix ( )和glPopMatrix ( )一对把它们独立。
向下,到绘制金字塔和立方体的方法那里。为了正确的显示混合效果,我们必须先绘制一个不透明的物体。然后在绘制透明的。就像一个老画家一样。
现在,考虑下OpenGL的当前状态。我们当前有纹理映射,我们要这个纹理去做图吗?不是的,所以我们要关闭纹理映射。
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
然后,开始混合:
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glEnable打开混合。光混合是不够的,我们要告诉OpenGL混合是如何工作的,否则默认状态下,不会做任何事情。 这就是glBlendFunc ( )发挥作用。不必担心这个,现在我要讨论的混合功能的详细阐述;现在,让我们刚刚得到的工作,然后我们可以实验。
恩,纹理关闭了,混合打开了,混合模式也提交给OpenGL了,现在是时候绘制两个矩形了。
glPushMatrix();
{
glTranslatef(0.0, 1.0, -4.0);
glVertexPointer(3, GL_FLOAT, 0, blendRectangle);
glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(1.0, 0.0, 0.0, 0.4);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
glPopMatrix();
glPushMatrix();
{
glTranslatef(0.0, -1.0, -4.0);
glColor4f(1.0, 1.0, 0.0, 0.4);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
glPopMatrix();
glDisable(GL_BLEND);
除了调用glDisable ()在结束时,没有什么新的这里。我们仅仅是我们的blendRectangle定义,定位它在显示器上,颜色,并提请它。然后,我们需要禁用OpenGL 的融合,否则将结合我们的金字塔和立方体下次将使用此功能(您可以尝试以后如果你愿意的话) 。
那就是了,点击“Build and Go” :
注意颜色的金字塔和立方体的转变,他们跨越两个颜色的矩形?这是融合工作。颜色与两位前矩形是部分透明的( 40 %透明的) ,结合或混合的颜色的物体,以创建一个新的色彩。
因此,黄色的矩形看起来比红色的矩形亮。
如果你只得到了一个红色及黄色的矩形,那么有可能你绘制函数的地方插错了位置。我们需要绘制透明物体在不透明物体之后。或者你改变混合模式。
这是它最基本的混合。没有什么特别的,但是我们了解了混合的部分。
在继续之前的快速小结
因此,使用混合的时候,我们需要一个透明的对象在我们屏幕的前面。我们先绘制实心的对象,这时候我们可以调用glEnable(),使用glBlendFunc()来设置混合,最后从后到前得到我们转换过的对象。
现在我们需要进入混合真正复杂的地方。设置混合因子。
混合因子
我刚刚删除了我刚刚写的内容。这个可以决定像素的最终颜色,基本上是数学矩阵(尽管它并没有被提到)。不,我不认为是一个正确的事情。
对我来说是时候了,让你得到更多的创造性和使用性的东西,但是你需要第一个理论:混合是怎么工作的。
如我先前所说的,你需要一个半透明的物体,并且有个背景上的东西进行混合工作。你也可以简单的和背景混合,不过我们每次都使用glClear()来清除了背景,所以你可能什么都得不到。
所以,在显示器上得每个像素,OpenGL都找到两件事:
1.这是源像素。这是我们当前绘制得新像素,从部分透明得对象(在红色和黄色矩形)
2. 这是目标像素。这是我们当前显存中得像素。这个就是正在绘制得半透明物体。在我们例子里,这个是一个混合对象,包含了实心对象(金字塔及立方体)和背景。
3.这是源像素混合因子指示符。这个是glBlendFunc()的第一个参数。它告诉OpenGL如何处理这个新的像素。
4.这个是目标像素混合因子指示符。这个是glBlendFunc()的第二个参数,并且告诉OpenGL如何处理目标像素。
找到上述四个信息以后。OpenGL可以计算出新的源及目标的混合因子,进而放入目标内存中。简单的说,我只是删除了所有的垃圾。
钥匙是 glBlendFunc()中的两个参数。
在上面的例子里,我们使用了下面的代码设置混合功能:
glBlendFunc(GL_ONE, GL_ONE);
这两个参数都是相同的: GL_ONE. 第一个参数表示了源或者传入像素的值,第二个参数表示了目标像素的值。
这里有一系列不同的混合因子说明符可以传入glBlendFunc()。这里需要你知道的是,它们单独并没有作用,必须要结合使用才可以表示我们的混合效果。
这是最重要的一点。我知道我有没有列出的选择,但是我需要你首先记住这一条理论。
如果你想获得最佳的混合效果,你需要明确你的想法,因为这里,新的颜色与部分透明的对象(我们的矩形)和原来的实心的对象是相互影响的。这是两者的结合混合因素控制而成的效果。
要明白这点,我们可以通过一些例子去了解。这两个参数到底表示什么意思并不重要!我想告诉你,当你改变参数的时候,发生了什么。
这个函数,默认打开了混合。
glEnable():
glBlendFunc(GL_ONE, GL_ZERO);
我们将第二个参数改为 GL_ZERO. 记得吗,第二个参数是影响到我们在缓冲区的实心的物体的,而不是部分透明物体,它使我们有了如下的效果:
哦,我们的背景物体发生了什么?不要太多解释,你知道GL_ZERO是最重要的线索。
这不是因为“没有混合”,而是因为目标像素被乘以了RGBA颜色(0,0,0,0),导致没有任何渲染。这个源(两个矩形)因为是GL_ONE所以被乘以了(1,1,1,1).这个像素就被完全的显示出来。
如果你没有对glBlendFunc()做任何修改,这是和现在是相同的,因为这是默认的状态。
再次改变两个参数位下面:
glBlendFunc(GL_ZERO, GL_ONE);
不用怀疑,那两个矩形消失的(这可是你做的,你把它们乘以了0)
好了,你已经知道了GL_ZERO和GL_ONE表示的是什么意思了。现在我们看看glBlendFunc()中支持的参数列表:
GL_ZERO
GL_ONE
GL_SRC_COLOR
GL_ONE_MINUS_SRC_COLOR
GL_DST_COLOR
GL_ONE_MINUS_DST_COLOR
GL_SRC_ALPHA
GL_ONE_MINUS_SRC_ALPHA
GL_DST_ALPHA
GL_ONE_MINUS_DST_ALPHA
GL_SRC_ALPHA_SATURATE
我会在之后的教程中详细的去解释它。感兴趣的朋友可以自己去网上查阅。
混合的例子
我也通过几个例子来说明这些参数。只是为了让你了解不同的混合效果。
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
请注意,前面的两个矩形更加的透明了?似乎实心的物体更亮了,而透明矩形更暗了,我们没做什么事情,是你的眼睛欺骗了你。
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
我们的矩形消失了?恩,不正确。它们的alpha是目标的-1。所以我们的目标的alpha原来是1.0 。所以 1.0 -1.0 = 0.0
需要注意的一件事是:这个背景颜色被glClearColor设置,alpha是1.0。那么我们修改clear颜色。
glClearColor(0.0, 0.0, 0.0, 0.0);
只改变这行,我们看看效果:
你能看出这是怎么一回事吗?虽然看起来移动到了实心物体的背景,但这真的是混合在工作。从前面的例子知道,无论OpenGL在渲染那一个像素,其中只要有一个alpha为1.0,这个矩形就是100%透明了。现在背景有一个alpha为0.0,所以1.0-0.0=1.0。
让我们来看看有没有更接近的。
我们红色矩形的颜色定义是: (1.0, 0.0, 0.0, 0.4). 所以如果背景是0 alpha, 这个渲染或混合的颜色就是 (1.0, 0.0, 0.0, 0.4). 背景颜色是黑色是最简单的,让我们来把它改为蓝色。
glClearColor(0.0, 0.0, 1.0, 0.0);
我们将得到如下的图片:
蓝色的背景是显然的。现在立方体及金字塔的混合如前一样。但是透明矩形已经发生了变化,看起来像是灰色的。
我将通过最后一个例子及计算。告诉大家如何得到最后的像素的。
glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
最后一个混合组合….
让我们看看什么是最常见的参数配对:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
在我们这的测试结果,看起来像如下:
添加额外的混合
你不需要为一个对象的每个像素设置混合。你可以在部分透明的物体上跌加几层。添加下面的函数,在绘制第二个矩形之后。
glPushMatrix();
{
glTranslatef(0.0, 0.0, -3.0);
glScalef(1.0, 0.3, 1.0);
glColor4f(1.0, 1.0, 1.0, 0.6);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
glPopMatrix();
我们要做的是增加了第三个矩形,OpenGL将混合到一起
当然,我做了一个还没介绍的函数: glScalef().
Scaling – 一些我还没有介绍的东西!
Scaling 就是为对象进行放大缩小, 这里有三个参数: xscale, yscale, and zscale.
在上面的例子中, xscale 和 zscale 是1。所以保持原尺寸。大于1就是放大,小于1就是缩小。上面是0.3,那么就是缩小到原来的30%。立方体和金字塔就在双层混合后的结果。
很简单。它应该包括之前的处理。