OpenGL学习笔记【11】——融合学习
今天学习了a的透明通道,书上说是融合,反正一个意思。奉上源代码:#include " gl\glaux.h "
#include < gl\glut.h >
void display( void )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清楚颜色数据和深度数据(清屏)
glColor3f(1.0,1.0,1.0);
glLoadIdentity(); //初始变换矩阵为单位矩阵
glPushMatrix();
glBegin(GL_QUADS);
//绘制两个矩形,他们位置相同,主要是看融合后的效果
glColor4f(0.0, 1.0, 0.0, 0.5);
glVertex3f(-2, 3, -2);
glVertex3f(-2, -1, -2);
glVertex3f(2, -1, -2);
glVertex3f(2, 3, -2);
glColor4f(1.0, 1.0, 0.0, 0.3);
glVertex3f(-2, 3, -2);
glVertex3f(-2, -1, -2);
glVertex3f(2, -1, -2);
glVertex3f(2, 3, -2);
glEnd();
glPopMatrix();
glDisable(GL_BLEND); //关闭融合
//绘制一个没有融合的举行,把颜色设置和计算后一样的颜色。
//看看是不是学对公式了。呵呵
glBegin(GL_QUADS);
glColor4f(0.65,1.0,0.35, 1);
glVertex3f(-4, 3, -3);
glVertex3f(-4, -1, -3);
glVertex3f(-2, -1, -3);
glVertex3f(-2, 3, -3);
glEnd();
glEnable(GL_BLEND);
glutSwapBuffers(); //交换缓冲区。显示图形
}
// 初始化
void init ( void )
{
glClearColor(1,1,1, 0); //清除颜色,也是背景颜色
glEnable(GL_BLEND); //启动混合
//源的融合因子用他颜色的a值,目标物体的融合因子用1-源物体的a值。
//这是用的最多的融合规则。
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_FLAT);
//glEnable(GL_LIGHTING);
//glEnable(GL_LIGHT0);
//glEnable(GL_COLOR_MATERIAL);
//glColorMaterial(GL_FRONT, GL_DIFFUSE);
//glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDisable(GL_DEPTH_TEST);
//glDepthMask( GL_FALSE ); //据说是深度检测只读。不会用。
}
// 当窗口大小改变时,会调用这个函数
void reshape(GLsizei w,GLsizei h)
{
glViewport(0,0,w,h); //设置视口
glMatrixMode(GL_PROJECTION); //设置矩阵模式为投影变换矩阵,
glLoadIdentity(); //变为单位矩阵
//gluPerspective(60, (GLfloat)w / h, 0, 1000); //设置投影矩阵
glOrtho(-6.0, 6.0, -6.0 * h / w, 6.0* h / w, -10, 10); //为了不变形,则要长和宽成比例
glMatrixMode(GL_MODELVIEW); //设置矩阵模式为视图矩阵(模型)
glLoadIdentity(); //变为单位矩阵
}
void Keyboard(unsigned char key, int x, int y)
{
}
// 闲置函数,当主循环空闲时就会调用这个函数
void MyIdle( void )
{
}
int main( int argc, char ** argv)
{
glutInit(&argc, argv); //Opnegl初始化
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA); //设置显示模式为双缓冲,RGEBA
glutInitWindowSize (800, 600); //窗口大小
glutInitWindowPosition (100, 100); //窗口位置
glutCreateWindow ("hello"); //创建一个标题为hello的窗口
init (); //初始化资源,这里一定要在创建窗口以后,不然会无效。
glutDisplayFunc(display); //窗口大小改变时的回调
glutReshapeFunc(reshape); //绘制图形时的回调
//glutKeyboardFunc(Keyboard);
//glutIdleFunc(MyIdle);
glutMainLoop(); //主循环。
return 0;
}
怎样开启alpha通道:开启alpha 也是调用OpenGL的函数,函数名为glEbable(GL_BLEND);blend我查字典是融合混合的意思。开启之后我们还要设置融合的参数设置,调用函数是:glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 这两句调用好了,我们就能看到融合效果了。画两个矩形试试。。
融合的顺序:因为融合需要两个或多个物体来算他们各自颜色的比例,从而组成一个新的颜色,例子就是玻璃窗看外面的树。玻璃窗式透明的,透过玻璃窗看树,树的颜色是玻璃窗和树本生颜色的融合。我们叫玻璃窗为源物体,树为目标物体。因此,在前面的物体时源物体,透过源物体看到的物体我称之为目标物体。他应该在源物体的后面。在程序中也一样,2D中先画的物体在后画物体的后面。所以后画的问题在融合中充当源物体的角色,先画的是目标物体。当我们绘制物体的时候,绘制一个时,我们会先把他作为源物体和他后面的物体做融合计算。当然如果只有一个就和背景颜色做融合计算。然后计算之后就是融合的值。然后我们画下一个物体的时候,他会跟这个已经融合计算的目标物体做新的融合计算。再次算出画这个物体呈现的颜色。大概就是这样了吧。例如物体A[0.6,0.6,1,0.8],在绘制的时候他会跟背景颜色[0.5,0.5,0.5,0]做融合,得到[0.58,0.58,0.9]的颜色值,作为他的颜色。然后绘制物体B[0.1,0.9,0.5,0.5],他和A相交的部分与A算出的颜色做融合计算得到[0.32,0.72, 0.7]就为B最后的颜色。他的计算就差不多了。
融合参数设置:用到融合的时候,颜色都是glColor4f(1.0,1.0,1.0,1.0);来表示的,前三个值表示物体的RGB颜色。最后一个值就是alpha通道,是不透明度。也就是说1表示完全不透明,0表示完全透明,中间就是不透明的比率了。之后不透明度还不够,我们是用一个融合的函数计算融合值,他与不透明度有关系,但是不透明度并不完全表示他的融合参数。我们怎么设置融合参数呢:就是用glBlendFunc(XXX, XXX);来设置的,他的主要参数包括在这个表内:
常数 |
相关因子 |
计算后得到的融合因子 |
GL_ZERO |
源因子或目的因子 |
(0,0,0,0) |
GL_ONE |
源因子或目的因子 |
(1,1,1,1) |
GL_DST_COLOR |
源因子 |
(Rd,Gd,Bd,Ad) |
GL_SRC_COLOR |
目的因子 |
(Rs,Gs,Bs,As) |
GL_ONE_MINUS_DST_COLOR |
源因子 |
(1,1,1,1)-(Rd,Gd,Bd,Ad) |
GL_ONE_MINUS_SRC_COLOR |
目的因子 |
(1,1,1,1)-(Rs,Gs,Bs,As) |
GL_SRC_ALPHA |
源因子或目的因子 |
(As,As,As,As) |
GL_ONE_MINUS_SRC_ALPHA |
源因子或目的因子 |
(1,1,1,1)-(As,As,As,As) |
GL_DST_ALPHA |
源因子或目的因子 |
(Ad,Ad,Ad,Ad) |
GL_ONE_MINUS_DST_ALPHA |
源因子或目的因子 |
(1,1,1,1)-(Ad,Ad,Ad,Ad) |
GL_SRC_ALPHA_SATURATE |
源因子 |
(f,f,f,1);f=min(As,1-Ad) |
表15-1 源因子和目的因子
这些设置参数有什么用:有这么多的参数,他们的作用就是计算确定融合因子的规则,融合因子就是计算融合颜色时候的比例。他的格式为[Sr,Sg,Sb,Sa]对应着物体相对颜色的比例,例如Sr就是对应着红色的比例,他和物体颜色计算的公式是[Rs*Sr Gs*Sg, Bs*Sb, As*Sa]。就这样就计算了一个物体融合后本来颜色的值,不过等等,还有他后面的目标物体呢?目标物体也是根据这个算出来的。公式一样,不过他的表示为[Rd*Dr, Gd*Dg, Bd*Db, Ad*Da]。也就是说,这样有两个融合因子,一个源物体的,一个是目标物体的。然后各自去和对应的颜色算值得到各自的比重,然后我们把他们加起来就是最后的颜色值了。
[Rs*Sr+Rd*Dr, Gs*Sg+Gd*Dg, Bs*Sb+Bd*Db, As*Sa+Ad*Da]
如何的计算看了,怎么读上面的表呢?第一栏是宏值,用他就能在函数里设定融合因子的规则了。第二列没有什么大的用处,就是说这个规则适用于哪类物体。第三列就是融合的规则了,他对应计算后的融合因子,例如:GL_SRC_APHA 这个融合方式,他的计算规制对应的是:(As,As,As,As)也就是他的融合因子为[Sr,Sg,Sb,Sa] = [As,As,As,As];就是他的a值例如物体A的颜色为[0.4,0.7,0.6,0.3]那他对应的融合因子就为[0.3,0.3,0.3,0.3]。然后在看一个GL_SRC_COLOR的融合计算,上一个颜色,计算的融合因子结果[0.4,0.7,0.6,0.3]。因为他的规则就是物体的颜色。然后我们再根据融合因子和物体颜色求出物体颜色分量。我们对源物体和目标物体都做这样的计算之后用上面的公式得出总的颜色结果,就是融合后的颜色。
这里举个例子:
源颜色为[1.0, 0.0, 0.0, 0.3] 目标物体颜色为[0.0, 1.0, 0.0, 0.8];
如果采用glBendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)这样的参数来处理融合因子:这计算的为:源融合因子计算结果:[0.3, 0.3, 0.3] 地想融合因子为[1,1,1] - [0.3,0.3,0.3] = [0.7,0.7,0.7];融合因子算出来了。通过上面的公式算出最后的颜色为
[1.0 * 0.3 + 0.0 * 0.7, 0.0*0.3+1.0*0.7,0.0*0.3+0.0*0.7 ] = [0.3,0.7,0];
要想3D情况中使用透明,也就是深度不同的情况能出现透明效果,必须要吧深度检测去掉,不然深度检测会剔除不可见物体,这不能达到透明效果了。不过对于z一样的情况下,去掉不去掉深度检测都一样。如果希望能既有深度检测,又有透明效果,可以先开启深度检测,绘制不透明物体,关闭深度检测,绘制透明物体。深度检测启动和禁用的方法不能在glBegin(); glEnd()中,必须在这连个函数的外面。关闭深度检测之后要注意,谁先画谁在后面。而不是看深度了。
遇到的问题:背景也会被融合,所以要注意背景的颜色。融合中可以用光照,裁剪,但是不要用深度检测。如果是在测试融合的结果的话,最好把光照光闭,刚才就因为开了光照总觉得颜色不对,还以为是我公式没有学对,其实是光照的效果。启动关闭融合的时候,不能在glBegin(); glEnd()。这里面只能是绘制图形相关的。以后少玩点游戏,大把时间都浪费掉了。