OpenGL-混合

1.混合概念

混合就是把两种颜色混在一起。具体一点就是,把某一像素位置原来的颜
色和将要画上去的颜色,通过某种方式混在一起,从而实现特殊效果。

使用OpenGL 混合功能 :glEnable(GL_BLEND);
关闭OpenGL混合功能 : glDisable(GL_BLEND);
注意: RGBA 模式下,可以使用混合功能,颜色索引模式下无法使用

2. 源原因子和目标因子

混合需要把原来的颜色和将要画上去的颜色找出来,经过某种方式处理
后得到一种新的颜色。 将要画上去的颜色为源颜色,原来的颜色称为
目标颜色。

OpenGL 会把源颜色和目标颜色各自取出,并乘以一个系数(源颜色乘
以的系数为 源因子,目标颜色乘以的系数称为 目标因子),然后相加的
到新的颜色

数学公式表示:
(Rs*Sr+Rd*Dr, Gs*Sg+Gd*Dg, Bs*Sb+Bd*Db, As*Sa+Ad*Da)
源颜色的四个分量(指红色,绿色,蓝色,alpha 值)是(Rs, Gs, Bs, 
As)
目标颜色的四个分量是(Rd, Gd, Bd, Ad)
源因子为(Sr, Sg, Sb, Sa)
目标因子为(Dr, Dg, Db, Da)。

源因子和目标因子可以通过 glBlendFunc 函数来进行设置。
两个参数:
	1. 源因子
	2. 目标因子
参数种类:
	GL_ZERO: 使用0.0作为因子 实际上 不使用这种颜色参与运算
	GL_ONE: 用1.0作为因子 实际上相当于完全使用这种颜色参与运算
	GL_SRC_ALPHA: 使用源颜色的alpha 值作为因子
	GL_DST_ALPHA: 表示使用目标颜色的 alpha 值来作为因子
	GL_ONE_MINUS_SRC_ALPHA: 表示用1.0减去源颜色的 alpha 值来作为因子。
	GL_ONE_MINUS_DST_ALPHA:表示用 1.0 减去目标颜色的 alpha 值来作为因子。

注意:
	源颜色和目标颜色,是和绘制的顺序有关的。比如先绘制一个红色的
	物体,再在其上绘制绿色的物体。则绿色是源颜色,红色是目标颜色
	。若反过来,则红色就是源颜色,绿色才是目标颜色。因此,绘制注
	意顺序,使得绘制的源颜色与设置的源因子对应,目标颜色与设置的
	目标因子对应。

3. 二维图形混合举例

void myDisplay(void)
{
	glClear(GL_COLOR_BUFFER_BIT);
	// 使用混合功能
	glEnable(GL_BLEND);
	// glBlendFunc 设置混合因子
	// GL_ONE  源因子1.0
	// GL_ZERO 目标因子0
	glBlendFunc(GL_ONE,GL_ZERO);
	glColor4f(1,0,0,0.5);
	gRectf(-1,-1,0.5,0.5);
	glColor4f(0,1,0,0.5);
	glRectf(-0.5,-0.5,1,1);
	
	glutSwapBuffers();
	
}

4. 三维混合

深度缓冲区:
	它是一段数据,它记录了每一个像素距离观察者有多近。
	
	启动深度缓冲测试情况下:如果将要绘制的像素比原来的像素更近,
	则像素将被绘制,否则,像素就会被忽略掉,不进行绘制。

实现半透明效果的问题:
	绘制了一个近距离的半透明物体,则它在深度缓冲区保留了一些信息
	,使得远处的物体将无法再被绘制出来,虽然半透明的物体仍然半
	透明,但透过它看到的却不是正确的内容了。

解决办法:
	需要在绘制半透明物体时将深度缓冲区设置为只读,这样,虽然透明
	物体被绘制上去,但是深度缓冲区还保持原来的状态。
	如果再有一个物体出现在半透明物体之后,在不透明物体之前,则它
	可以被绘制,因为此时深度缓冲区记录的那个是不透明无的深度。
	以后再绘制不透明物体时候,只需要在将深度缓冲区设置为可读可写
	形式即可。

	一部分透明粉i一部分不透明的物体,只需要把物体分为两个部分,
	一部分全是半透明的,一部分全是不透明的。

	绘制原则:
		必须先绘制不透明的物体,然后绘制透明的物体。
		假设 背景为蓝色, 近处一块红色玻璃,中间一个绿色物体,
		如果先绘制红色半透明玻璃,它先和蓝色背景混合,则以后绘制中
		间的绿色物体,当单独于红色玻璃混合已经不能实现了。

绘制顺序:
	1.先绘制所有不透明的物体。若两个物体都是不透明的,则先后顺序
		没有关系。
	2..然后将深度缓冲区设置为只读,绘制所有半透明的物体,若两个物
	    体都是半透明的,则先后根据自己的意愿(注意,先绘制的将成
	    为目标颜色,后绘制的将成为源颜色,绘制顺序将会对结果造成一
	    些影响,最后将深度缓冲区设置为可读可写形式。)

深度缓冲区设置只读:
	glDepthMask(GL_FALSE);
深度缓冲区设置可读写:
	glDepthMask(GL_TRUE)

示例代码

// 设置光源
void setLight(void)
{
	static const GLfloat light_position[] = {1.0f, 1.0f, -1.0f, 1.0f};
	static const GLfloat light_ambient[] = {0.2f, 0.2f, 0.2f, 1.0f};
	static const GLfloat light_diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
	static const GLfloat light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};

	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
	
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHTING);
	glEnable(GL_DEPTH_TEST);
	
}
// 设置材质
void setMatirial(const GLfloat mat_diffuse[4], GLfloat mat_shininess)
{
	static const GLfloat mat_specular[] = {0.0f, 0.0f, 0.0f, 1.0f};
	static const GLfloat mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};

	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
	glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
	glMaterialf (GL_FRONT, GL_SHININESS, mat_shininess);
}
void myDisplay(void)
{
	// 定义一些材质颜色
	const static GLfloat red_color[] = {1.0f, 0.0f, 0.0f, 1.0f};
	const static GLfloat green_color[] = {0.0f, 1.0f, 0.0f, 0.3333f};
	const static GLfloat blue_color[] = {0.0f, 0.0f, 1.0f, 0.5f};
	// 清除屏幕
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// 启动混合并设置混合因子
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	// 设置光源
	setLight();
	// 以(0, 0, 0.5)为中心,绘制一个半径为.3 的不透明红色球体(离观察者最远)
	setMatirial(red_color, 30.0);
	glPushMatrix();
	glTranslatef(0.0f, 0.0f, 0.5f);
	glutSolidSphere(0.3, 30, 30);
	glPopMatrix();
	// 下面将绘制半透明物体了,因此将深度缓冲设置为只读
	glDepthMask(GL_FALSE);
	// 以(0.2, 0, -0.5)为中心,绘制一个半径为.2 的半透明蓝色球体(离观察者最近)
	setMatirial(blue_color, 30.0);
	glPushMatrix();
	glTranslatef(0.2f, 0.0f, -0.5f);
	glutSolidSphere(0.2, 30, 30);
	glPopMatrix();
	// 以(0.1, 0, 0)为中心,绘制一个半径为.15 的半透明绿色球体(在前两个球体之间)
	setMatirial(green_color, 30.0);
	glPushMatrix();
	glTranslatef(0.1, 0, 0);
	glutSolidSphere(0.15, 30, 30);
	glPopMatrix();
	// 完成半透明物体的绘制,将深度缓冲区恢复为可读可写的形式
	glDepthMask(GL_TRUE);
	glutSwapBuffers();
}

结果如图:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值