Part9 使用蒙板、剪裁空间(应用:实现反射效果)

原创 2007年10月11日 01:21:00
一、蒙板
        蒙板是这样的一种机制,他用来控制深度在蒙板其后的物体,在蒙板区域的某个位置是否被显示。这个功能可以使用混色通过控制ALPHA通道的值来完成,但是这样的效果并不好,会产生蒙板上物体比较虚的效果。使用蒙板以后我们可以使得透过深度较靠前的物体看到深度较靠后物体的一个部分。 这个机制可以用两种方法来实现。
       第一种方式是使用模拟的方式,它的原理是使用混色当中的象素叠加操作。所以我们在操作的一开始必须要打开混色开关,glEnable(GL_BLEND);然后我们在需要的地方放置我们的蒙板,模板是一个黑白贴图,在需要透视的后方物体的地方这个贴图使用白色,而需要遮挡的地方我们使用黑色。在载入并绑定蒙板贴图以后我们控制混色方案为glBlendFunc(GL_DST_COLOR,GL_ZERO);这样贴图的黑色部分被贴至指定位置,而白色部分则没有被贴图。接着载入并绑定与蒙板对应的贴图,并且更换混色方案为glBlendFunc(GL_ONE,GL_ONE),然后贴图,这样的效果是仅仅将原先蒙板贴到场景中的部分贴上图。至此一个蒙板的使用完成。 
        第二钟方式使用了OpenGL当中的蒙板缓存。使用这种机制的方法是首先在创建场景时打开蒙板缓存。然后在需要的时候用glEnable允许蒙板缓存的使用。在完成以上的初始化工作以后我们可以开始使用蒙板缓存,在正式使用之前我们需要用蒙板缓存指定接下来允许进行绘图的地方。因此我们就需要向蒙板缓存当中写入关于这个区域的数据而写入的过程类似与绘制的过程。在写入这些数据之前为了保证这个写入的过程不会改写深度缓存和颜色缓存,我们必须要用glColorMask指定所有的颜色掩码为GL_FALSE来保证没有任何颜色被写入到颜色缓存,而对于深度缓存的操作则非常的简单直接用glDisable关闭之就可以了。然后开始写入蒙板缓存,写入的代码如下:
glStencilFunc(GL_ALWAYS,1,1);
glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
我们首先来解释这两个函数的用法:
第一个函数glStencilFunc,它的原型如下:
void glStencilFunc(
  GLenum func,
  GLint 
ref,                   //参考值
  GLuint mask            //掩码  通常为1
);
对于参数func我们可以用下面的表来解释:

常量
含义
GL_NEVER
从不通过蒙板测试
GL_ALWAYS
总是通过蒙板测试
GL_LESS
只有参考值<(蒙板缓存区的值&mask)时才通过
GL_LEQUAL
只有参考值<=(蒙板缓存区的值&mask)时才通过
GL_EQUAL
只有参考值=(蒙板缓存区的值&mask)时才通过
GL_GEQUAL
只有参考值>=(蒙板缓存区的值&mask)时才通过
GL_GREATER
只有参考值>(蒙板缓存区的值&mask)时才通过
GL_NOTEQUAL
只有参考值!=(蒙板缓存区的值&mask)时才通过
第二个函数glStencilOp,它的原型如下:
void glStencilOp(
  GLenum fail,                   
//蒙板测试失败时的动作
  GLenum zfail,                  //深度测试失败时的动作
  GLenum zpass               //蒙板测试和深度测试都通过时的动作
);
这里可以采取的动作可以用下面的表来表示

常量
描述
GL_KEEP
保持当前的蒙板缓存区值
GL_ZERO
把当前的蒙板缓存区值设为0
GL_REPLACE
用glStencilFunc函数所指定的参考值替换蒙板参数值
GL_INCR
增加当前的蒙板缓存区值,但限制在允许的范围内
GL_DECR
减少当前的蒙板缓存区值,但限制在允许的范围内
GL_INVERT
将当前的蒙板缓存区值进行逐位的翻转
在解释完这里的两个函数以后我们对于这里设定蒙板的一系列操作就非常清楚了。首先我们使得蒙板测试无论如何都会通过,并且我们设置当通过蒙板测试以后就用参考值1来代替原来缓存当中相应位置的值,这样在绘制一个蒙板区域以后这个区域的蒙板缓存的值全部为1,而不是这个区域的蒙板缓存的值保持为0。
        现在来看怎样在这个蒙板区域当中绘制模型。在按照上面的方法建立好蒙板缓存以后,我们打开深度缓存并且把颜色掩码改回GL_TRUE允许向颜色缓冲区写入数据。然后我们又要使用上面的两个函数对深度缓冲的操作方式进行修改。具体的代码如下:
glStencilFunc(GL_EQUAL,1,1);
glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);
这段代码的意义是,只有参考值与深度缓冲区的值都为1才能通过测试,也就是说只有深度缓冲区在上次操作时设定过的区域才能允许绘图,而第二个函数调用表明,无论测试通过与否深度缓冲区的值都不会被改变。这样整个蒙板的实现就完成了。需要注意的时在使用完模板后为了其他区域的正常渲染我们需要使用glDisable禁用蒙板。
二、剪裁空间
        我们可以使用一个剪裁空间来控制允许绘图的空间区域。在OpenGL当中一般允许同时定义这样的6个空间。要使用剪裁空间我们需要首先用GL_CLIP_PLANE调用glEnable来打开状态,然后用glClipPlane函数来设定空间方程。我们知道一个方程Ax+By+Cz+D = 0可以定义一个空间,而所谓定义剪裁空间方程是指,使用这个方程来乘以当前视图模型矩阵M的倒数,也就是说凡满足(A,B,C,D)/M>=0的顶点点就允许被绘制,而其他的顶点就会被忽略。下面是一个定义剪裁空间的程序段,这个代码段允许在Y<=0的空间区域内绘图:
GLdouble eqr[] = ...{0,-1,0,0};
glEnable(GL_CLIP_PLANE0);
glClipPlane(GL_CLIP_PLANE0, eqr);
glDisable(GL_CLIP_PLANE0);

//前面提到的所谓允许6个剪裁空间就是类似于光照的操作使用GL_CLIP_PLANEi i从0-5
//glClipPlane的第二个参数指向一个包括4个元素的数组,这4个元素对应于方程的4个参数
三、应用:实现反射效果
       使用上面讲的蒙板和剪裁平面我们可以很容易的实现物体在另一个平面上的反射效果。这里的核心是对于物体,当部分位于平面以下时我们要利用剪裁空间的操作将位于平面以下的部分忽略掉,而对于反射物同样要通过剪裁平面剪裁掉位于平面之上的部分,另外还要利用蒙板来限制反射物的显示位置。而这种实现反射物的方法使用的是将反射物与反射平面进行ALPHA通道的混合来实现。下面是具体的代码:
void DrawWall()
...{
    glBindTexture(GL_TEXTURE_2D,TexHandle[WALL]);
    glBegin(GL_QUADS);
        glNormal3f(
0,1,0);
        glTexCoord2f(
0,0); glVertex3f(-2,0,2);
        glTexCoord2f(
1,0); glVertex3f(2,0,2);
        glTexCoord2f(
1,1); glVertex3f(2,0,-2);
        glTexCoord2f(
0,1); glVertex3f(-2,0,-2);
    glEnd();
}


void DrawBall()
...{
    glBindTexture(GL_TEXTURE_2D,TexHandle[BALL]);
    gluQuadricNormals(quadric,GL_SMOOTH);
    gluQuadricTexture(quadric,GL_TRUE);
    gluSphere(quadric,
0.35,32,32);
}


int DrawGLScene(GLvoid)                                    // Here's Where We Do All The Drawing
...{
    GLdouble eqr[] 
= ...{0,-1,0,0};                   //关于反射物体的剪裁空间方程
    GLdouble eqr1[] = ...{0,1,0,0};                  //关于球体的剪裁空间方程
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
            GL_STENCIL_BUFFER_BIT);                        
// Clear Screen / Depth / Stencil Buffer
    glLoadIdentity();                                    // Reset The Current Modelview Matrix
    glTranslatef(0,-0.6,zoom);
    
//指定蒙板区域
                     glColorMask(GL_FALSE | GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_STENCIL_TEST);
    glStencilFunc(GL_ALWAYS,
1,1);
    glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
    DrawWall();
    glEnable(GL_DEPTH_TEST);
    
                     
//使用蒙板
    glStencilFunc(GL_EQUAL,1,1);
    glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);
    glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
    glEnable(GL_CLIP_PLANE0);
    glClipPlane(GL_CLIP_PLANE0, eqr);
    glPushMatrix();
        glScalef(
1,-1,1);
        glTranslatef(
0,height,0);
        glRotatef(xRot,
1,0,0);
        glRotatef(yRot,
0,1,0);
        DrawBall();
    glPopMatrix();
    glDisable(GL_CLIP_PLANE0);
    glDisable(GL_STENCIL_TEST);
                     
                    
//混合地面与反射物体
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glColor4f(
1,1,1,0.8);
    DrawWall();
    glDisable(GL_BLEND);

                     
//绘制球体
    glClipPlane(GL_CLIP_PLANE0,eqr1);
    glEnable(GL_CLIP_PLANE0);
    glTranslatef(
0,height,0);
    glRotatef(xRot,
1,0,0);
    glRotatef(yRot,
0,1,0);
    DrawBall();
    glDisable(GL_CLIP_PLANE0);

    
return TRUE;                                        // Everything Went OK
}

【Anroid界面实现】WindowManager类使用详解——用户首次打开APP的使用教学蒙板效果实现

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 在上一篇的文章中,我们介绍了如何实现桌面悬浮窗口,在这个效果的实现过程中,最重要的一个类就是Wind...
  • bz419927089
  • bz419927089
  • 2014年10月24日 11:54
  • 6283

Android 图片合成:添加蒙板效果 不规则相框 透明度渐变效果的实现

先贴一张效果图,这是一张手机截屏: 左上方的风景图:背景图片 右上方的人物图:前景图片 左边心型透明图:相框图片 右边心型黑色图:蒙板图片 功能:把前景图应用蒙板,添加相...
  • liu_zhen_wei
  • liu_zhen_wei
  • 2013年06月25日 10:37
  • 19062

iOS CoreAnimation专题——技巧篇(三)Layer Masking - 图层蒙版

如果你使用过Photoshop,你一定听说过蒙版的概念。 而在CoreAnimation中,框架同样为我们提供了这样的功能,CALayer拥有一个属性叫做mask,作为这个CALayer对象的蒙版,m...
  • u013282174
  • u013282174
  • 2016年08月12日 09:24
  • 2466

Unity3D NGUI蒙版效果实现方法

Unity3D NGUI蒙版效果实现方法之前在做项目过程中需要用到类似Flash中蒙板效果的功能,虽然是个很简单的功能点,但发现网上缺很难找到相关介绍,所以在这里为大家节省一些研究时间,讲一下如何使用...
  • quintus0331
  • quintus0331
  • 2016年09月11日 17:02
  • 2409

Android 指引蒙版的实现

实现这个功能的关键是: 你需要知道哪个button处需要给个指引的高亮显示,这个涉及到坐标的运算,免得位置放偏。先给大家看看做的效果图:把没有做好的也放上去,这样更容易看出问题和需要注意的地方。(图一...
  • huang_xiao_yu
  • huang_xiao_yu
  • 2016年10月25日 19:19
  • 3678

PopupWindow的各种用法(二)——使用PopupWindow做一个指引蒙板(带启动页,仿ViewPager滚动的引导页)

引言:接下来和大家分享一下用一个PopupWindow来做一个指引蒙板的效果。鉴于网上对于“指引蒙板”的实现例子不是太多(或者是我找不到更多的),而且好像有很多的例子都是用一个Frame布局+Frag...
  • u011070603
  • u011070603
  • 2015年08月06日 18:16
  • 1369

Android常用控件之GridView的蒙板用处和写法

内容GridView常用语显示照片墙,例如上传图片时当选中一个图片时,会出现一些特殊效果,此时要用到checkBox和蒙板。 布局文件,必须将GridView放在RelativeLayout或Fra...
  • NiZhuanXingHeIT
  • NiZhuanXingHeIT
  • 2015年08月27日 19:43
  • 1295

文字与图片渐变效果(图层CALayer与属性蒙版mask )

首先,我们需要稍微理清一下CAGradientLayer、CALayer,UIView和mask的大概关系。 在iOS中,能看得见摸的着的基本都是UIView,如按钮、图片等。UIView之所以能看...
  • pilqc2009
  • pilqc2009
  • 2016年02月25日 06:40
  • 982

全屏蒙板添加

div class="address_runyuan" style="margin:0 auto;width:1200px;"> style> .runyuanAddr{ text-alig...
  • qiphon3650
  • qiphon3650
  • 2017年07月31日 15:25
  • 185

怎么用CorelDRAW 实现蒙版效果

CorelDRAW能够实现很多意想不到的小效果,其中包括了位图图像软件的处理功能,蒙版效果就是其中的一项。作为矢量图形处理软件,从理论上讲它并不具备蒙板技术,然而只是我们平常没有用到而已,利用图框精确...
  • coreldraw2016
  • coreldraw2016
  • 2016年08月08日 14:13
  • 1448
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Part9 使用蒙板、剪裁空间(应用:实现反射效果)
举报原因:
原因补充:

(最多只允许输入30个字)