OpenGL光照设置

光照模型
OpenGL光照模型分为三种光:Ambient Light 环境光, Diffuse Light漫反射光, Specular Light镜面反射光.

一、创建光源
void glLightfv (GLenum light, GLenum pname, const GLfloat *params)
light: OpenGL提供8个光源 GL_LIGHT0 ~ GL_LIGHT7
pname: 光源属性
GL_AMBIENT        环境光                默认 (0.0, 0.0, 0.0, 1.0)
GL_DIFFUSE            漫反射光                默认 (1.0, 1.0, 1.0, 1.0)
GL_SEPCULAR        镜面反射光                默认 (1.0, 1.0, 1.0, 1.0)
GL_POSITION        光源位置齐次坐标(x,y,z,w)        默认 (0.0, 0.0, 1.0, 0.0)
GL_SPOT_DIRECTION    点光源聚光方向矢量(x,y,z)        默认 (0.0, 0.0, -1.0)
GL_SPOT_EXPONENT    点光源聚光指数            默认 (0.0)
GL_SPOT_CUTOFF        点光源聚光截止角            默认 (180)
GL_CONSTANT_ATTENUATION 常量衰减因子        默认 (1.0)
GL_LINER_ATTENUATION 线性衰减因子            默认 (0.0)
GL_QUADRATIC_ATTENUATION 平方衰减因子        默认 (0.0)
params: 光源属性值
GLfloat light_position[] = { 0.0, 0.0, 0.0, 0.0 }; 
GLfloat light_ambient [] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat light_diffuse [] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; 
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); // 设置镜面反射光

光源的衰减
离光源越远则光强越弱。由于定向光源是模拟的无穷远得光源,所以不会根据距离改变而衰减,所以在定向光源中是禁用衰减的; 对于定位光源有衰减。OpenGL的光衰减是通过光源的发光量乘以衰减因子来实现衰减的。
衰减系数 = 1/(K0+K1*D+K2*D2)  
其中:  D = 光源位置与顶点之间的距离 
K0 = GL_CONSTANT_ATTENUATION       //常数衰减因子
K1 = GL_LINER_ATTENUATION               // 线性衰减因子
K2 = GL_QUADRATIC_ATTENUATION     // 二次衰减因子
OpenGL中默认的衰减因子为(1,0,0),即不进行衰减。

二、启用光源
glEnable(GL_LIGHTING);
glEnable(GL_LIGHTn);

三、材质
OpenGL用材质对光的红、绿、蓝三原色的反射率来近似定义材料的颜色。
物体的材质跟光源一样,也分为环境、漫反射和镜面反射成分,它们决定了材料对环境光、漫反射光和镜面反射光的反射程度。其中对环境光和漫反射光的反射程度决定了物体的颜色。
比如对于一朵红色的花,它对绿色和蓝色的反射能力比较弱,对红色分量的反射能力比较强,所以呈现出来是红色。材质的镜面反射率在RGB三个分量上通常是一致的,即反射的光跟光源的颜色基本是一致的,只不过强度会减弱。镜面反射光的强度还取决于观察点的位置,当观察点正好处于入射光的反射光线上,亮斑的亮度达到最大值。
这3个材质的属性都是反应的物体对外界光线的反射情况,有些物体本身可以发射弱光,OpenGL中是通过设置材料的辐射光来实现的,可以使物体看起来像是发射出设定的辐射光一样,以达到特殊的效果。物体的辐射光使用glMaterialfv(GL_FRONT, GL_EMISSION,   earth_mat_emission)来设置。
总体来说材质定义了物体对环境光、漫反射光、镜面光的反射(吸收)能力。我们看到的物体的颜色(或亮度)是光源的颜色(或亮度)经过物体的材质反射(吸收)之后发散出来的颜色(或亮度)。
定义材质的函数使用glMaterialfv
void  glMaterialfv (GLenum face, GLenum pname, const GLfloat *params);
face: 表示当前材质应用于哪个表面上 GL_FRONT、GL_BACK、GL_FRONT_AND_BACK
pname: 指定正在设置的材质属性
GL_AMBIENT        材质的环境光颜色            默认(0.2, 0.2, 0.2, 1.0)
GL_DIFFUSE            材质的漫反射光颜色        默认(0.8, 0.8, 0.8, 1.0)
GL_AMBIENT_AND_DIFFUSE 环境光和漫反射光颜色     默认(0.8, 0.8, 0.8, 1.0)
GL_SEPCULAR        材质镜面反射光颜色        默认(0.0, 0.0, 0.0, 1.0)
GL_SHININESS        镜面指数(光亮度)            默认(0.0)
GL_EMISSION        材质辐射光颜色            默认(0.0, 0.0, 0.0, 1.0)
GL_COLOR_INDEXS    材质环境、漫反射和镜面反射颜色 默认(0, 0, 1)
params: 属性值
GLfloat mat_ambient[] = { 0.3f, 0.3f, 0.3f, 1.0f };
GLfloat mat_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);

使用颜色材质:
除了glMaterialfv设置材质,还可以用glColorMaterial设置材质。glColorMaterial在绘图过程中根据glColor实时设置材质。
要使用glColorMaterial,需要启动颜色跟踪功能 glEnable(GL_COLOR_MATERIAL)

四、光照使用总结
1. 设置光源参数: 需要多次调用带有不同参数的glLightfv函数,设置环境光(Ambient Light)、漫射光(Diffuse Light)、镜面光(Specular Light)和光照位置(Position)等。
2. 开启光照,使用glEnable(GL_LIGHTING)和glEnable(GL_LIGHTXX)来开启光照和XX号光源,前者相当于光源的总开关,后者是对应的开启相应号数的光源。 
3. glMaterialfv或glColorMaterial设置材质
4. 法线的设置

下图是对光照应用的例子,红色球代表太阳,材质的辐射光为红光,绿色球代表地球,绕太阳公转,材质的辐射光为蓝光,镜面反射光为红色(蓝色地球上的红色区域):

void CWinGLView::OnDraw(CDC* /*pDC*/)
{
	// 创建透视效果视图 
	CRect rectSize;
	GetClientRect(&rectSize);
	double dbViewWidth = 800;
	int cx = rectSize.Width();
	int cy = rectSize.Height();
	glViewport(0, 0, cx, cy);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(80.0f, 1.0f, 1.0f, 20.0f);

	glClearColor(0.3, 0.7, 0.5, 0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  //清理颜色和深度缓存     

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.0, 12.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

	// 定义太阳光源,它是一种白色的光源   
	{
		GLfloat sun_light_position[] = { 0.0f, 0.0f, 0.0f, 1.0f }; //光源的位置在世界坐标系圆心,齐次坐标形式
		GLfloat sun_light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };  //RGBA模式的环境光,为0
		GLfloat sun_light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };  //RGBA模式的漫反射光,全白光
		GLfloat sun_light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; //RGBA模式下的镜面光 ,全白光
		glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position);
		glLightfv(GL_LIGHT0, GL_AMBIENT, sun_light_ambient);
		glLightfv(GL_LIGHT0, GL_DIFFUSE, sun_light_diffuse);
		glLightfv(GL_LIGHT0, GL_SPECULAR, sun_light_specular);

		//开启灯光
		glEnable(GL_LIGHT0);
		glEnable(GL_LIGHTING);
		glEnable(GL_DEPTH_TEST);
	}

	// 定义太阳的材质并绘制太阳    
	{
		GLfloat sun_mat_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };  //定义材质的环境光颜色,为0
		GLfloat sun_mat_diffuse[] = { 0.0f, 0.0f, 0.0f, 1.0f };  //定义材质的漫反射光颜色,为0
		GLfloat sun_mat_specular[] = { 0.0f, 0.0f, 0.0f, 1.0f };   //定义材质的镜面反射光颜色,为0
		GLfloat sun_mat_emission[] = { 0.8f, 0.0f, 0.0f, 1.0f };   //定义材质的辐射广颜色,为偏红色
		GLfloat sun_mat_shininess = 0.0f;
		glMaterialfv(GL_FRONT, GL_AMBIENT, sun_mat_ambient);
		glMaterialfv(GL_FRONT, GL_DIFFUSE, sun_mat_diffuse);
		glMaterialfv(GL_FRONT, GL_SPECULAR, sun_mat_specular);
		glMaterialfv(GL_FRONT, GL_EMISSION, sun_mat_emission);
		glMaterialf(GL_FRONT, GL_SHININESS, sun_mat_shininess);
		glutSolidSphere(3.0, 40, 32);
	}

	// 定义地球的材质并绘制地球    
	{
		GLfloat earth_mat_ambient[] = { 0.0f, 0.0f, 1.0f, 1.0f };  //定义材质的环境光颜色,骗蓝色
		GLfloat earth_mat_diffuse[] = { 0.0f, 0.0f, 0.5f, 1.0f };  //定义材质的漫反射光颜色,偏蓝色
		GLfloat earth_mat_specular[] = { 1.0f, 0.0f, 0.0f, 1.0f };   //定义材质的镜面反射光颜色,红色
		GLfloat earth_mat_emission[] = { 0.0f, 0.0f, 0.0f, 1.0f };   //定义材质的辐射光颜色,为0
		GLfloat earth_mat_shininess = 30.0f;
		glMaterialfv(GL_FRONT, GL_AMBIENT, earth_mat_ambient);
		glMaterialfv(GL_FRONT, GL_DIFFUSE, earth_mat_diffuse);
		glMaterialfv(GL_FRONT, GL_SPECULAR, earth_mat_specular);
		glMaterialfv(GL_FRONT, GL_EMISSION, earth_mat_emission);
		glMaterialf(GL_FRONT, GL_SHININESS, earth_mat_shininess);
		glRotatef(m_angle, 0.0f, -1.0f, 0.0f);
		glTranslatef(7.0f, 0.0f, 0.0f);
		glutSolidSphere(3.0, 40, 32);
	}
	glFlush();
	SwapBuffers(m_hDC);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值