Chinaunix首页 | 论坛 | 博客
  • 博客访问: 397018
  • 博文数量: 466
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2015-03-16 13:59
文章分类

全部博文(466)

文章存档

2015年(466)

我的朋友

分类: C/C++

2015-03-16 15:02:02

请注意:我对我写这个教程时的状态不是很满意,所以如果你有些地方有疑惑,请不要在意。如果哪里错了,也别担心,我会在第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” :


西蒙iphone-OpenGL ES 教程 -10 - 勇者之尊 - 等待


注意颜色的金字塔和立方体的转变,他们跨越两个颜色的矩形?这是融合工作。颜色与两位前矩形是部分透明的( 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. 记得吗,第二个参数是影响到我们在缓冲区的实心的物体的,而不是部分透明物体,它使我们有了如下的效果:

西蒙iphone-OpenGL ES 教程 -10 - 勇者之尊 - 等待


哦,我们的背景物体发生了什么?不要太多解释,你知道GL_ZERO是最重要的线索。

这不是因为“没有混合”,而是因为目标像素被乘以了RGBA颜色(0,0,0,0),导致没有任何渲染。这个源(两个矩形)因为是GL_ONE所以被乘以了(1,1,1,1).这个像素就被完全的显示出来。

如果你没有对glBlendFunc()做任何修改,这是和现在是相同的,因为这是默认的状态。

再次改变两个参数位下面:

    glBlendFunc(GL_ZERO, GL_ONE);

  
西蒙iphone-OpenGL ES 教程 -10 - 勇者之尊 - 等待


不用怀疑,那两个矩形消失的(这可是你做的,你把它们乘以了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);

  
西蒙iphone-OpenGL ES 教程 -10 - 勇者之尊 - 等待


请注意,前面的两个矩形更加的透明了?似乎实心的物体更亮了,而透明矩形更暗了,我们没做什么事情,是你的眼睛欺骗了你。

    glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);


西蒙iphone-OpenGL ES 教程 -10 - 勇者之尊 - 等待


我们的矩形消失了?恩,不正确。它们的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);

只改变这行,我们看看效果:

  
西蒙iphone-OpenGL ES 教程 -10 - 勇者之尊 - 等待


你能看出这是怎么一回事吗?虽然看起来移动到了实心物体的背景,但这真的是混合在工作。从前面的例子知道,无论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);

我们将得到如下的图片:


西蒙iphone-OpenGL ES 教程 -10 - 勇者之尊 - 等待


蓝色的背景是显然的。现在立方体及金字塔的混合如前一样。但是透明矩形已经发生了变化,看起来像是灰色的。

我将通过最后一个例子及计算。告诉大家如何得到最后的像素的。

    glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);

  
西蒙iphone-OpenGL ES 教程 -10 - 勇者之尊 - 等待


最后一个混合组合….
让我们看看什么是最常见的参数配对:

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

在我们这的测试结果,看起来像如下:

  
西蒙iphone-OpenGL ES 教程 -10 - 勇者之尊 - 等待

添加额外的混合
你不需要为一个对象的每个像素设置混合。你可以在部分透明的物体上跌加几层。添加下面的函数,在绘制第二个矩形之后。

    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将混合到一起

  
西蒙iphone-OpenGL ES 教程 -10 - 勇者之尊 - 等待


当然,我做了一个还没介绍的函数: glScalef().

Scaling – 一些我还没有介绍的东西!
Scaling 就是为对象进行放大缩小, 这里有三个参数: xscale, yscale, and zscale.

在上面的例子中, xscale 和 zscale 是1。所以保持原尺寸。大于1就是放大,小于1就是缩小。上面是0.3,那么就是缩小到原来的30%。立方体和金字塔就在双层混合后的结果。

很简单。它应该包括之前的处理。
 

阅读(443) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~