(zt)OpenGL中的Alpha测试,深度测试,模板测试,裁减测试

转自http://www.cppblog.com/flashboy/archive/2009/09/01/94974.html

魔兽争霸,出于自身设置的操作系统是XP繁体中文版,运行魔兽争霸3的时候弹出如下对话框:
魔兽争霸 1
解决办法就是
在”运行”中输入”regedit”打开注册表,找到HKEY_LOCAL_MACHINE/SYSTEM/CURRENTCONTROLSET/CONTROL/NLS/LANGUAGE元帅default
和installlanguage,把内部的值改为0804,然后再一次开动电脑就足以玩魔兽了.
不过这样修改之后会促成原来在千头万绪中文版下提升安装的复杂性版IE7出现问题,不可以开拓IE7中的Internet选项.每回选”Internet选项”都闪了一个窗口然后就消灭了.解决办法就是把注册表中原来的installlanguage修改回来,修改后再行开动电脑就足以打开Internet选项了.当然,修改将来不能打魔兽了.鱼与熊掌无法兼得啊.
一经改动后要么不可能玩而且修改的注册表在重启以后又变回去了,那么使用以下措施:
安装好UitraEdit后,右键单击魔兽目录下game.dll,选打开格局,选UitraEdit,dll文件被打开后其中太乱,所以要用里面的探寻功效,就在菜单栏内的文书(F)、编辑选项(E)和方案(P)、视图(V)选项中间的寻找(s)选项,然后输入搜索那一串字符3D04080000742A3D04
专注是把 00 与 2A 间的74 改为题写的
EB,里面有许多74,看通晓了,最后切记要保存!
————修改完毕

 

世家好。现在因为加入工作的涉嫌,又是长日子未曾改进。趁着国庆的空闲,总算是又写出了一课。我倍感入门的学问已经快要介绍完毕,这课之后再有一课,就足以告一段落了。以后我说不定会写一些和谐在这方面的体味,做一份进阶课程。

现今将要获释的是第十二课的情节。

率先如故在此以前课程的总是:

先是课,编写第一个OpenGL程序
第二课,绘制几何图形
其三课,绘制几何图形的一些细节问题
第四课,颜色的抉择
第五课,三维的空中更换
第六课,动画的制作
第七课,使用光照来显现立体感
第八课,使用突显列表
第九课,使用混合来兑现半晶莹剔透效果
第十课,BMP文件与像素操作
第十一课,纹理的施用入门
第十二课,OpenGL片断测试  ——→  这一次课程的始末

片断测试其实就是测试每一个像素,唯有通过测试的像素才会被绘制,没有经过测试的像素则不开展绘图。OpenGL提供了多种测试操作,利用这多少个操作可以兑现部分不同平常的意义。
俺们在头里的学科中,曾经关系了“深度测试”的概念,它在绘制三维场景的时候特意有用。在不应用深度测试的时候,即便大家先绘制一个距离较近的实体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的实体覆盖掉,这样的效益并不是大家所企望的。
即便使用了纵深测试,则状况就会齐趋并驾:每当一个像素被绘制,OpenGL就记下那些像素的“深度”(深度可以通晓为:该像素距离观看者的相距。深度值越
大,表示距离越远),即便有新的像素即将覆盖原来的像素时,深度测试会检讨新的纵深是否会比原先的纵深值小。假诺是,则覆盖像素,绘制成功;假诺不是,则
不会覆盖原来的像素,绘制被收回。这样一来,尽管大家先绘制相比较近的物体,再绘制比较远的实体,则远的实体也不会覆盖近的物体了。
实际上,只要存在深度缓冲区,无论是否启用深度测试,OpenGL在像素被绘制时都会尝试将深度数据写入到缓冲区内,除非调用了glDepthMask(GL_FALSE)来禁止写入。这一个深度数据除了用于常规的测试外,还是可以有一对有趣的用途,比如绘制阴影等等。

除外深度测试,OpenGL还提供了剪裁测试、Alpha测试和模板测试。

1、剪裁测试
剪裁测试用于限制绘制区域。我们得以指定一个矩形的剪裁窗口,当启用剪裁测试后,只有在这一个窗口之内的像素才能被绘制,其余像素则会被放弃。换句话说,无论怎么绘制,剪裁窗口以外的像素将不会被涂改。
一对朋友或者玩过《魔兽争霸3》这款游戏。游戏时只要当选一个精兵,则画面下方的一个四方内就会现出该士兵的头像。为了保险该头像无论怎样绘制都不会越界而覆盖到外边的像素,就足以接纳剪裁测试。

可以经过下边的代码来启用或剥夺剪裁测试:
glEnable(GL_SCISSOR_TEST);  // 启用剪裁测试
glDisable(GL_SCISSOR_TEST); // 禁用剪裁测试

可以因此下边的代码来指定一个职务在(x,
y),宽度为width,中度为height的剪裁窗口。
glScissor(x, y, width, height);

小心,OpenGL窗口坐标是以左下角为(0, 0),右上角为(width,
height)的,这与Windows系统窗口有所不同。

再有一种办法可以确保像素只绘制到某一个特定的矩形区域内,这就是视口变换(在第五课第3节中有介绍)。但视口变换和剪裁测试是不同的。视口变换是将拥有情节缩放到适合的轻重缓急后,放到一个矩形的区域内;而剪裁测试不会展开缩放,超出矩形范围的像素直接忽略掉。

2、Alpha测试
在前面的学科中,大家清楚像素的Alpha值可以用来混合操作。其实Alpha值还有一个用途,这就是
Alpha测试。当每个像素即将绘制时,倘使开行了Alpha测试,OpenGL会检查像素的Alpha值,唯有Alpha值满意条件的像素才会进展绘图
(严峻的说,满足条件的像素会通过本项测试,举行下一种测试,只有拥有测试都经过,才能举办绘图),不满足条件的则不开展绘图。那一个“条件”可以是:始终
通过(默认情形)、始终不经过、大于设定值则经过、小于设定值则透过、等于设定值则透过、大于等于设定值则通过、小于等于设定值则通过、不对等设定值则通
过。
假若大家需要绘制一幅图片,而这幅图片的少数部分又是晶莹剔透的(想象一下,你先绘制一幅照片,然后绘制一个相框,则相框这幅图片有成百上千地点都是
透明的,这样就可以通过相框看到下边的相片),这时可以行使Alpha测试。将图片中装有需要透明的地点的Alpha值设置为0.0,不需要透明的地方Alpha值设置为1.0,然后设置Alpha测试的通过标准为:“大于0.5则透过”,这样便能达成目标。当然也可以安装需要透明的地点Alpha值为
1.0,不需要透明的地点Alpha值设置为0.0,然后设置条件为“小于0.5则通过”。Alpha测试的安装方法频繁不只一种,可以依照个体爱好和实
际情状需要展开分选。

可以透过下边的代码来启用或禁用Alpha测试:

glEnable(GL_ALPHA_TEST);  // 启用Alpha测试
glDisable(GL_ALPHA_TEST); // 禁用Alpha测试

可以经过下边的代码来设置Alpha测试条件为“大于0.5则通过”:

glAlphaFunc(GL_GREATER, 0.5f);

该函数的第二个参数表示设定值,用于开展相比较。第一个参数是相比较艺术,除了GL_LESS(小于则通过)外,仍可以挑选:
GL_ALWAYS(始终通过),
GL_NEVER(始终不经过),
GL_LESS(小于则透过),
GL_LEQUAL(小于等于则通过),
GL_EQUAL(等于则透过),
GL_GEQUAL(大于等于则经过),
GL_NOTEQUAL(不对等则经过)。

在我们来看一个实际例子。一幅照片图片,一幅相框图片,怎样将它们组成在协同啊?为了简单起见,我们使用前面两课一直利用的24位BMP文件来作为图片格
式。(因为发布到网络上,为了节省容量,我所发布的是JPG格式。我们下载后得以用Windows
XP自带的美术工具打开,并另存为24位BMP格式)

注:第一幅图片是出名网络游戏《魔兽世界》的一幅桌面背景,用在此处希望没有提到版权问题。固然有怎么着不妥,请立刻指出,我会霎时更换。

在24位的BMP文件格式中,BGR二种颜色各占8位,没有保存Alpha值,因而无法直接行使Alpha测试。注意到相框这幅图片中,所有需要透
明的职位都是反动,所以我们在先后中装置有着白色(或很类似白色)的像素Alpha值为0.0,设置任何像素Alpha值为1.0,然后设置Alpha测
试的标准化为“大于0.5则经过”即可。这种应用某种特殊颜色来代表透明颜色的技能,有时又被改成Color
Key技术。
行使前边第11课的一段代码,将图片读取为纹理,然后接纳下面这些函数来安装“当前纹理”中每一个像素的Alpha值。

/* 将如今纹理BGR格式转换为BGRA格式
 *
纹理中像素的RGB值如若与指定rgb相差不超过absolute,则将Alpha设置为0.0,否则设置为1.0
 */
void texture_colorkey(GLubyte r, GLubyte g, GLubyte b, GLubyte
absolute)
{
    GLint width, height;
    GLubyte* pixels = 0;

    // 拿到纹理的分寸信息
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,
&width);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,
&height);

    // 分配空间并获取纹理像素
    pixels = (GLubyte*)malloc(width*height*4);
    if( pixels == 0 )
        return;
    glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
pixels);

    // 修改像素中的Alpha值
    // 其中pixels[i*4], pixels[i*4+1], pixels[i*4+2],
pixels[i*4+3]
    //  
分别代表第i个像素的蓝、绿、红、Alpha四种分量,0意味着很小,255意味着最大
    {
        GLint i;
        GLint count = width * height;
        for(i=0; i<count; ++i)
        {
            if( abs(pixels[i*4] – b) <= absolute
             && abs(pixels[i*4+1] – g) <= absolute
             && abs(pixels[i*4+2] – r) <= absolute )
                pixels[i*4+3] = 0;
            else
                pixels[i*4+3] = 255;
        }
    }

    // 将修改后的像素重新设置到纹理中,释放内存
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
        GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
    free(pixels);
}

有了纹路后,我们打开纹理,指定合适的纹路坐标并绘制一个矩形,那样就足以在屏幕中将图纸绘制出来。大家先绘制相片的纹路,再绘制相框的纹理。程序代码如下:

void display(void)
{
    static int initialized   = 0;
    static GLuint texWindow  = 0;
    static GLuint texPicture = 0;

    //
执行初阶化操作,包括:读取相片,读取相框,将相框由BGR颜色转换为BGRA,启用二维纹理
    if( !initialized )
    {
        texPicture = load_texture(“pic.bmp”);
        texWindow  = load_texture(“window.bmp”);
        glBindTexture(GL_TEXTURE_2D, texWindow);
        texture_colorkey(255, 255, 255, 10);

        glEnable(GL_TEXTURE_2D);

        initialized = 1;
    }

    // 清除屏幕
    glClear(GL_COLOR_BUFFER_BIT);

    // 绘制相片,此时不需要举办Alpha测试,所有的像素都进展绘图
    glBindTexture(GL_TEXTURE_2D, texPicture);
    glDisable(GL_ALPHA_TEST);
    glBegin(GL_QUADS);
        glTexCoord2f(0, 0);     glVertex2f(-1.0f, -1.0f);
        glTexCoord2f(0, 1);     glVertex2f(-1.0f,  1.0f);
        glTexCoord2f(1, 1);     glVertex2f( 1.0f,  1.0f);
        glTexCoord2f(1, 0);     glVertex2f( 1.0f, -1.0f);
    glEnd();

    // 绘制相框,此时开展Alpha测试,只绘制不透明部分的像素
    glBindTexture(GL_TEXTURE_2D, texWindow);
    glEnable(GL_ALPHA_TEST);
    glAlphaFunc(GL_GREATER, 0.5f);
    glBegin(GL_QUADS);
        glTexCoord2f(0, 0);     glVertex2f(-1.0f, -1.0f);
        glTexCoord2f(0, 1);     glVertex2f(-1.0f,  1.0f);
        glTexCoord2f(1, 1);     glVertex2f( 1.0f,  1.0f);
        glTexCoord2f(1, 0);     glVertex2f( 1.0f, -1.0f);
    glEnd();

    // 互换缓冲
    glutSwapBuffers();
}

其中:load_texture函数是从第11课中照搬过来的(该函数还运用了一个power_of_two函数,一个BMP_Header_Length常数,同样照搬),无需举行修改。main函数跟其余课程的基本相同,不再另行。

序运行后,会发觉相框与照片的连通有些不自然,这是因为相框某些边缘部分尽管眼睛看上去是白色,但实则RGB值与纯白色相差并不少,由此先后总括其
Alpha值时以为其不需要透明。解决办法是密切处理相框中的每个像素,在急需透明的地方涂上纯白色,这也许是一件很需要耐心的做事。

   
大家或许会想:前边咱们学习过夹杂操作,混合可以兑现半晶莹剔透,自然也可以因此设定实现全透明。也就是说,Alpha测试可以实现的功能几乎都足以经过
OpenGL混合效用来兑现。那么为何还需要一个Alpha测试呢?答案就是,这与性能相关。Alpha测试只要简单的相比较大小就足以拿到终极结出,而
混合操作一般需要开展乘法运算,性能兼备下滑。其余,OpenGL测试的相继是:剪裁测试、Alpha测试、模板测试、深度测试。倘诺某项测试不经过,则
不会进展下一步,而唯有所有测试都因而的气象下才会实施混合操作。因而,在使用Alpha测试的景色下,透明的像素就不需要经过模板测试和纵深测试了;而
假如使用混合操作,尽管透明的像素也亟需开展模板测试和纵深测试,性能会持有减退。还有某些:对于这多少个“透明”的像素来说,倘若采纳Alpha测试,则
“透明”的像素不会透过测试,因而像素的纵深值不会被涂改;而使用混合操作时,即便像素的颜色没有被改动,但它的吃水值则有可能被涂改掉了。
据此,假若持有的像素都是“透明”或“不透明”,没有“半透明”时,应该尽可能利用Alpha测试而不是利用混合操作。当需要绘制半晶莹剔透像素时,才使用混合操作。

   3、模板测试
模板测试是具备OpenGL测试中相比较复杂的一种。

率先,模板测试需要一个模板缓冲区,这么些缓冲区是在初阶化OpenGL时指定的。如果应用GLUT工具包,可以在调用glutInitDisplayMode函数时在参数中增长GLUT_STENCIL,例如:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_STENCIL);

在Windows操作系统中,固然没有明确要求使用模板缓冲区,有时候也会分配模板缓冲区。但为了保险程序的通用性,最好仍然总而言之指定使用模板缓冲区。假诺确实并未分配模板缓冲区,则有着开展模板测试的像素全体都会透过测试。

通过glEnable/glDisable可以启用或剥夺模板测试。

glEnable(GL_STENCIL_TEST);  // 启用模板测试
glDisable(GL_STENCIL_TEST); // 禁用模板测试

OpenGL在模板缓冲区中为每个像素保存了一个“模板值”,当像素需要举办模板测试时,将设定的沙盘参考值与该像素的“模板值”举行相比,符合条件的通过测试,不符合条件的则被撤消,不开展绘图。
基准的设置与Alpha测试中的条件设置相似。但只顾Alpha测试中是用浮点数来进展相比,而模板测试则是用整数来开展比较。相比也有八种状态:始终通过、始终不通过、大于则经过、小于则经过、大于等于则透过、小于等于则通过、等于则通过、不对等则经过。

glStencilFunc(GL_LESS, 3, mask);

那段代码设置模板测试的标准化为:“小于3则透过”。glStencilFunc的前两个参数意义与glAlphaFunc的五个参数近似,第三个参
数的意思为:倘使进展相比较,则只相比mask中二进制为1的位。例如,某个像素模板值为5(二进制101),而mask的二进制值为00000011,因
为只相比最终两位,5的终极两位为01,其实是自愧不如3的,由此会由此测试。

如何设置像素的“模板值”呢?glClear函数可以将有着像素的模板值复位。代码如下:

glClear(GL_STENCIL_BUFFER_BIT);

能够同时复位颜色值和模板值:

glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

正如可以使用glClearColor函数来指定清空屏幕后的水彩这样,也可以应用glClearStencil函数来指定复位后的“模板值”。

每个像素的“模板值”会依照模板测试的结果和纵深测试的结果而进展改动。

glStencilOp(fail, zfail, zpass);

该函数指定了二种情景下“模板值”该怎么变迁。第一个参数表示模板测试未经过时该怎么变化;第二个参数表示模板测试通过,但深度测试未经过时该怎么着变化;第五个参数表示模板测试和深度测试均经过时该怎样转移。若是没有引用模板测试,则认为模板测试总是通过;如果没有启用深度测试,则以为深度测试总是
通过)
浮动可以是:
GL_KEEP(不改动,这也是默认值),
GL_ZERO(回零),
GL_REPLACE(使用测试条件中的设定值来替代当前模板值),
GL_INCR(增添1,但如若已经是最大值,则维持不变),
GL_INCR_WRAP(扩大1,但一旦已经是最大值,则从零重新开头),
GL_DECR(减弱1,但假设已经是零,则保持不变),
GL_DECR_WRAP(缩短1,但即便已经是零,则另行设置为最大值),
GL_INVERT(按位取反)。

在新本子的OpenGL中,允许为多边形的不俗和背面使用不同的模版测试条件和模板值改变模式,于是就有了
glStencilFuncSeparate函数和glStencilOpSeparate函数。这三个函数分别与glStencilFunc和
glStencilOp类似,只在最前面多了一个参数face,用于指定当前设置的是哪些面。可以采用GL_FRONT,
GL_BACK, GL_FRONT_AND_BACK。

留意:模板缓冲区与深度缓冲区有某些不一。无论是否启用深度测试,当有像素被绘制时,总会重新设置该像素的深度值(除非设置
glDepthMask(GL_FALSE);)。而模板测试假设不启用,则像素的模版值会保持不变,只有启用模板测试时才有可能修改像素的模板值。(这
一定论是自身自己的试行得出的,暂时没发现什么样资料上是这么写。要是有不正确的地方,欢迎指正)
另外,模板测试即使是从OpenGL
1.0就起来提供的效益,不过对于个人总计机而言,硬件实现模板测试的如同并不多,很多总结机序列直接使用CPU运算来成功模板测试。由此在有些老的显
卡,或者是多数集成显卡上,大量而往往的应用模板测试可能导致程序运行效用低下。即使是现阶段配备相比高端的私家统计机,也硬着头皮不要采取glStencilFuncSeparate和glStencilOpSeparate函数。

此前边所讲可以清楚,使用剪裁测试可以把绘制区域限制在一个矩形的区域内。但即使急需把绘制区域限量在一个失常的区域内,则需要使用模板测试。
诸如:绘制一个湖泊,以及周围的小树,然后绘制树木在湖水中的倒影。为了确保倒影被正确的限定在湖水表面,可以应用模板测试。具体的步调如下:
(1) 关闭模板测试,绘制地面和树木。
(2) 开启模板测试,使用glClear设置有着像素的模板值为0。
(3) 设置glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP,
GL_REPLACE);绘制湖泊水面。这样一来,湖泊水面的像素的“模板值”为1,而另外地方像素的“模板值”为0。
(4) 设置glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_KEEP, GL_KEEP,
GL_KEEP);绘制倒影。这样一来,唯有“模板值”为1的像素才会被绘制,因而只有“水面”的像素才有可能被倒影的像素替换,而其他像素则保持不变。

  
大家依旧来看一个实际的例子。这是一个相比较简单的气象:空间中有一个圆球,一个平面镜。大家站在某个特殊的观察点,可以看看球体在平面镜中的镜像,并且镜像处于平面镜的边缘,有局部因为平面镜大小的限量,而不可能突显出来。整个场合的法力如下图:

制图这么些现象的思路跟前边提到的湖面倒影是类似的。
只要平面镜所在的平面正好是X轴和Y轴所确定的平面,则球体和它在平面镜中的镜
像是关于这个平面对称的。我们用一个draw_sphere函数来绘制球体,先调用该函数以绘制球体本身,然后调用glScalef(1.0f,
1.0f, -1.0f); 再调用draw_sphere函数,就可以绘制球体的镜像。
此外索要小心的地点就是:因为是绘制三维的景观,我们开
启了纵深测试。可是站在寓目者的职位,球体的镜像其实是在平面镜的“背后”,也就是说,假如遵照常规的法子绘制,平面镜会把镜像覆盖掉,这不是大家想要的
效果。解决办法就是:设置深度缓冲区为只读,绘制平面镜,然后设置深度缓冲区为可写的情状,绘制平面镜“背后”的镜像。
有的朋友或者会问:假使在
绘制镜像的时候关闭深度测试,这镜像不就不会被平面镜遮挡了吗?为啥还要敞开深度测试,又需要把深度缓冲区设置为只读呢?实际状况是:尽管关闭深度测试
确实可以让镜像不被平面镜遮挡,然而镜像本身会现出若干题材。大家见到的镜像是一个圆球,但实则这多少个球体是由许多的多方形所组成的,这么些多边形有的代表
了我们所能看到的“正面”,有的则代表了我们不可能看出的“背面”。假设关闭深度测试,而有的“背面”多边形又比“正面”多边形先绘制,就会造成球体的北边
反而把尊重挡住了,这不是大家想要的效率。为了保险尊重可以屏蔽背面,应该打开深度测试。
制图部分的代码如下:

void draw_sphere()
{
    // 设置光源
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    {
        GLfloat
            pos[]     = {5.0f, 5.0f, 0.0f, 1.0f},
            ambient[] = {0.0f, 0.0f, 1.0f, 1.0f};
        glLightfv(GL_LIGHT0, GL_POSITION, pos);
        glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    }

    // 绘制一个圆球
    glColor3f(1, 0, 0);
    glPushMatrix();
    glTranslatef(0, 0, 2);
    glutSolidSphere(0.5, 20, 20);
    glPopMatrix();
}

void display(void)
{
    // 清除屏幕
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 设置观看点
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60, 1, 5, 25);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(5, 0, 6.5, 0, 0, 0, 0, 1, 0);

    glEnable(GL_DEPTH_TEST);

    // 绘制球体
    glDisable(GL_STENCIL_TEST);
    draw_sphere();

    // 绘制一个平面镜。在绘制的同时注意设置模板缓冲。
    //
另外,为了确保平面镜之后的镜像可以科学绘制,在绘制平面镜时需要将深度缓冲区设置为只读的。
    // 在绘制时临时关张光照效果
    glClearStencil(0);
    glClear(GL_STENCIL_BUFFER_BIT);
    glStencilFunc(GL_ALWAYS, 1, 0xFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    glEnable(GL_STENCIL_TEST);

    glDisable(GL_LIGHTING);
    glColor3f(0.5f, 0.5f, 0.5f);
    glDepthMask(GL_FALSE);
    glRectf(-1.5f, -1.5f, 1.5f, 1.5f);
    glDepthMask(GL_TRUE);

    //
绘制一个与原先球体关于平面镜对称的圆球,注意光源的岗位也要爆发对称改变
    //
因为平面镜是在X轴和Y轴所确定的平面,所以倘使Z坐标取反即可实现对称
    // 为了保险球体的绘图范围被限制在平面镜内部,使用模板测试
    glStencilFunc(GL_EQUAL, 1, 0xFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    glScalef(1.0f, 1.0f, -1.0f);
    draw_sphere();

    // 交换缓冲
    glutSwapBuffers();

    // 截图
    grab();
}

其中display函数的末梢调用了一个grab函数,它保存当前的图象到一个BMP文件。这么些函数本来是在第十课和第十一课中都怀有使用
的。不过我意识它有一个bug,现在拓展了改动:在函数最伊始的一对加上一句:glReadBuffer(GL_FRONT);即可。注意这么些函数最好是
在绘制完毕后(假使是利用双缓冲,则应当在交流缓冲后)登时调用。

 
我们莫不会有这般的感觉到:模板测试的设置是这样复杂,它可以实现的功效应该多多,肯定不止这么一个“限制像素的绘图范围”。事实上也是这般,但是现在大家暂时只讲这一个。

骨子里,假诺不需要绘制半晶莹剔透效果,有时候能够用混合功用来顶替模板测试。就绘制镜像这一个事例来说,可以应用下边的步调:
(1)
清除屏幕,在glClearColor中设置合适的值确保清除屏幕后像素的Alpha值为0.0
(2)
关闭混合功用,绘制球体本身,设置合适的颜料(或者光照与材质)以保证所有被绘制的像素的Alpha值为0.0
(3)
绘制平面镜,设置合适的颜色(或者光照与材质)以保险所有被绘制的像素的Alpha值为1.0
(4)
启用混合效用,用GL_DST_ALPHA作为源因子,GL_ONE_MINUS_DST_ALPHA作为对象因子,这样就兑现了只有原来Alpha为
1.0的像素才能被涂改,而原来Alpha为0.0的像素则保持不变。这时再绘制镜像物体,注意保管所有被绘制的像素的Alpha值为1.0。
在有的OpenGL实现中,模板测试是软件实现的,而掺杂功效是硬件实现的,这时候能够考虑这么的替代方法以增长运行效能。不过不用所有的沙盘测试都得以用混合效能来替代,并且这样的代表显得不自然,复杂而且便于出错。
此外始终注意:使用混合来模拟时,尽管某个像素原来的Alpha值为0.0,以致于在绘制后其颜色不会有任何变更,可是这些像素的深度值有可能会被修改,而
要是是行使模板测试,没有经过测试的像素其深度值不会时有暴发其他变化。而且,模板测试和混合功用中,像素模板值的改动章程是不雷同的。
  

  4、深度测试
在本课的开首,已经一句话来说述了深度测试。这里是完全的始末。

深度测试需要深度缓冲区,跟模板测试需要模板缓冲区是类似的。即使运用GLUT工具包,可以在调用glutInitDisplayMode函数时在参数中丰裕GLUT_DEPTH,这样来家喻户晓指定要求拔取深度缓冲区。

度测试和模板测试的实现原理很接近,都是在一个缓冲区保存像素的某部值,当需要举行测试时,将保存的值与另一个值举办比较,以确定是不是由此测试。两者的区
别在于:模板测试是设定一个值,在测试时用这么些设定值与像素的“模板值”举行相比,而深度测试是依据顶点的长空坐标总计出深度,用这一个深度与像素的“深度
值”举行相比较。也就是说,模板测试需要指定一个值作为相比参考,而深度测试中,这些相比较用的参考值是OpenGL遵照空间坐标自动测算的。

由此glEnable/glDisable函数可以启用或剥夺深度测试。
glEnable(GL_DEPTH_TEST);  // 启用深度测试
glDisable(GL_DEPTH_TEST); // 禁用深度测试

至于经过测试的条件,同样有八种,与Alpha测试中的条件设置同样。条件设置是通过glDepthFunc函数完成的,默认值是GL_LESS。
glDepthFunc(GL_LESS);

与模板测试对照,深度测试的接纳要反复得多。几乎拥有的三维场景绘制都使用了纵深测试。正因为这么,几乎所有的OpenGL实现都对纵深测试提供了
硬件支撑,所以即便两者的落实原理类似,但深度测试很可能会比模板测试快得多。当然了,二种测试在行使上很少有混合,一般不会出现使用一种测试去顶替另一
种测试的情况。

   小结:
本次课程介绍了OpenGL所提供的四种测试,分别是剪裁测试、Alpha测试、模板测试、深度测试。OpenGL会
对各样即将绘制的像素进行以上四种测试,每个像素只有经过一项测试后才会进入下一项测试,而唯有通过所有测试的像素才会被绘制,没有通过测试的像素会被丢弃掉,不开展绘图。每种测试都足以独立的打开或者关闭,假若某项测试被关闭,则以为所有像素都可以万事大吉通过该项测试。
剪裁测试是指:只有位于指定矩形内部的像素才能透过测试。
Alpha测试是指:只有Alpha值与设定值相比,满意特定关系原则的像素才能因此测试。
模板测试是指:只有像素模板值与设定值相比,满足特定关系原则的像素才能由此测试。
纵深测试是指:只有像素深度值与新的吃水值相比较,满意特定关系原则的像素才能通过测试。
地点所说的一定关系原则可以是高于、小于、等于、大于等于、小于等于、不等于、始终通过、始终不经过这八种。

板测试需要模板缓冲区,深度测试需要深度缓冲区。那些缓冲区都是在最先化OpenGL时指定的。假设应用GLUT工具包,则足以在
glutInitDisplayMode函数中指定。无论是否打开深度测试,OpenGL在像素被绘制时都会尝试修改像素的深度值;而只有打开模板测试
时,OpenGL才会尝试修改像素的模版值,模板测试被关闭时,OpenGL在像素被绘制时也不会修改像素的模板值。
接纳这一个测试操作可以决定像
素被绘制或不被绘制,从而实现部分特殊效果。利用混合效能可以实现半透明,通过安装也可以兑现完全透明,因此可以效仿像素颜色的绘图或不绘制。但只顾,这里仅仅是颜色的效仿。OpenGL可以为像素保存颜色、深度值和模板值,利用混合实现透明时,像素颜色不发生变化,但深度值则会容许转变,模板值受
glStencilFunc函数中第六个参数影响;利用测试操作实现透明时,像素颜色不发生变化,深度值也不暴发变化,模板值受
glStencilFunc函数中前多少个参数影响。
此外,修正了第十课、第十一课中的一个函数中的bug。在grab函数中,应该在最起初加上一句glReadBuffer(GL_FRONT);以管教读取到的内容正好就是凸显的情节。

 

正文来源CSDN博客,转载请标明出处:http://blog.csdn.net/Crazyjumper/archive/2007/12/26/1968567.aspx

 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website