OpenGL实战教程(7) -- 第六站:光照

一、 光照模型

在大自然中,某些物体会发光,例如太阳、电灯等,而其它物体不会发光,反射来自其它物体的光。这些光通过各种方式传播,最后进入眼睛——于是一幅画面就眼前形成了。

OpenGL在处理光照时把光照系统分为三部分,分别是光源、材质和光照环境。
光源就是发光源,如太阳或者电灯等。
材质是指接受光照的物体表面,物体如何反射光线由物体表面决定,材质特点就决定了物体反射光线的特性。
光照环境是指环境亮度。

二、法线向量

根据光的反射定律,由光的入射方向和入射点的法线就可以得到光的出射方向。因此,对于指定的物体,在指定了光源后,即可算出光的反射方向,进而计算出光照效果的画面。
在指定法线向量时,只指定每一个顶点的法线向量即可,OpenGL会自行计算顶点之间的其它点的法线向量。
注意:使用glTranslate函数或者glRotate函数可以改变物体的外观,但法线向量并不会随之改变。然而,使用glScale*函数,对每一坐标轴进行不同程度的缩放,很有可能导致法线向量的不正确。
常用设定法向量函数:

glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);
glNormal3fv(const GLfloat *v);

三. 控制光源

1、开启光源
在OpenGL中,支持8个以上的光源。以GL_LIGHT0,GL_LIGHT1,…, GL_LIGHT7命名。
开启光源函数:
glEnable(GL_LIGHT0); // 开启第0号光源
关闭光源函数:
glDisable(GL_LIGHT0); // 关闭第0号光源

2、指定光源的属性
(1)GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR属性:
表示了光源所发出的光的反射特性(以及颜色)。每个属性由四个值表示,分别代表了颜色的R, G, B, A值。
GL_AMBIENT表示该光源所发出的光,经过非常多次的反射后,最终遗留在整个光照环境中的强度(颜色)。
GL_DIFFUSE表示该光源所发出的光,照射到粗糙表面时经过漫反射,所得到的光的强度(颜色)。
GL_SPECULAR表示该光源所发出的光,照射到光滑表面时经过镜面反射,所得到的光的强度(颜色)。

(2)GL_POSITION属性。表示光源所在的位置。由四个值(X, Y, Z, W)表示。如果第四个值W为零,则表示该光源位于无限远处,前三个值表示了它所在的方向。这种光源称为方向性光源,太阳可以近似的被认为是方向性光源。如果第四个值W不为零,则X/W, Y/W, Z/W表示了光源的位置。这种光源称为位置性光源

GLfloat position[] = { 1.0, 1.0, 1.0, 0.0 };
glLightfv(GL_LIGHT0, GL_POSITION, position);

(3)GL_SPOT_DIRECTION、GL_SPOT_EXPONENT、GL_SPOT_CUTOFF属性。表示将光源作为聚光灯使用(这些属性只对位置性光源有效)。
GL_SPOT_DIRECTION属性有三个值,表示一个向量,即光源发射的方向。
GL_SPOT_EXPONENT属性只有一个值,表示聚光的程度,为零时表示光照范围内向各方向发射的光线强度相同,为正数时表示光照向中央集中,正对发射方向的位置受到更多光照,其它位置受到较少光照。数值越大,聚光效果就越明显。
GL_SPOT_CUTOFF属性也只有一个值,表示一个角度,它是光源发射光线所覆盖角度的一半(见图2),其取值范围在0到90之间,也可以取180这个特殊值。取值为180时表示光源发射光线覆盖360度,即不使用聚光灯,向全周围发射。

GLfloat direction[]={ -1.0, 0.0 , -0.5};
glLightfv( GL_LIGHT0 , GL_SPOT_DIRECTION , direction);

4)GL_CONSTANT_ATTENUATION、GL_LINEAR_ATTENUATION、GL_QUADRATIC_ATTENUATION属性。指定光源所发出的光线的直线传播特性。控制光线在传播过程中的减弱趋势。

GLfloat LightRadius=0.5f;
glLightf(GL_LIGHT0 , GL_LINEAR_ATTENUATION, LightRadius);

四. 控制材质

材质则是通过glMaterial*函数来设置的。
void glMaterialf (GLenum face, GLenum pname, GLfloat param);
void glMaterialfv (GLenum face, GLenum pname, const GLfloat *params);
例:

   GLfloat sp[4] = { 1, 1, 1, 1.0 };
   glMaterialfv(GL_FRONT, GL_SPECULAR, sp);	
   GLfloat Diffuse[4]={1,0,0,1};
   glMaterialfv(GL_FRONT,GL_DIFFUSE,Diffuse);

五. 颜色追踪

在启用光照系统之后,指定颜色变得不太方便。首先创建一个数组,然后调用glMaterial函数将数组传给材质,以此决定物体的颜色。为了简便,可以开启颜色跟踪来简化代码。

 // 启动颜色跟踪
   glEnable(GL_CORLOR_MATERIAL);  
//决定对物体正面还是反面,对环境光、镜面光还是漫射光进行颜色跟踪
   glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);

第一个参数可以取GL_FRONT、GL_BACK、GL_FRONT_AND_BACK中的任意一种,
第二个参数可以取GL_AMBIENT、GL_DIFFUSE、GL_AMBIENT_AND_DIFFUSE、GL_SPECULAR中的任意一种。
启动颜色跟踪之后,我们就可以像以前一样,使用glColor函数来指定图元的颜色了。这时,OpenGL将自动根据从glColor函数传递的颜色来决定物体材质,省去了我们手工指定材质的麻烦。 例如,要在启用光照系统的前提下绘制一个红色的三角形,如下所示:

glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
glColor3ub(255,0,0);
glBegin(GL_TRIANGLES);
  glVertex3f(1,0,1);glVertex3f(1,1,1);glVertex3f(1,0,0);
glEnd();

六、例程


GLfloat Step6_angle = 0.0f;
void Step6_Lighting(void) 
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 创建透视效果视图 
	glMatrixMode(GL_PROJECTION); 
	glLoadIdentity(); 
	GLfloat fovy = 90.0f;
	GLfloat aspect = 1.0f;
	GLfloat zNear = 1.0f;
	GLfloat zFar = 20.0f;

	gluPerspective(fovy, aspect, zNear, zFar);
	glMatrixMode(GL_MODELVIEW); 
	glLoadIdentity(); 
	GLfloat eyeX = 0.0;
	GLfloat eyeY = 5.0;
	GLfloat eyeZ = -10.0;
	gluLookAt(eyeX, eyeY, eyeZ, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); // 定义太阳光源,它是一种白色的光源 
	{ 
		GLfloat sun_position[] = {0.0f, 0.0f, 0.0f, 1.0f}; 
		GLfloat sun_ambient[] = {0.0f, 0.0f, 0.0f, 1.0f}; 
		GLfloat sun_diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f}; 
		GLfloat sun_specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; 
		glLightfv(GL_LIGHT0, GL_POSITION, sun_position); 
		glLightfv(GL_LIGHT0, GL_AMBIENT, sun_ambient); 
		glLightfv(GL_LIGHT0, GL_DIFFUSE, sun_diffuse); 
		glLightfv(GL_LIGHT0, GL_SPECULAR, sun_specular); 
		glEnable(GL_LIGHT0); 
		glEnable(GL_LIGHTING); 
		glEnable(GL_DEPTH_TEST);
	}
	// 定义太阳的材质并绘制太阳 
	{ 
		GLfloat sun_m_ambient[] = {0.0f, 0.0f, 0.0f, 1.0f}; 
		GLfloat sun_m_diffuse[] = {0.0f, 0.0f, 0.0f, 1.0f}; 
		GLfloat sun_m_specular[] = {0.0f, 0.0f, 0.0f, 1.0f}; 
		GLfloat sun_m_emission[] = {0.5f, 0.0f, 0.0f, 1.0f}; 
		GLfloat sun_m_shininess = 0.0f; 
		glMaterialfv(GL_FRONT, GL_AMBIENT, sun_m_ambient); 
		glMaterialfv(GL_FRONT, GL_DIFFUSE, sun_m_diffuse); 
		glMaterialfv(GL_FRONT, GL_SPECULAR, sun_m_specular); 
		glMaterialfv(GL_FRONT, GL_EMISSION, sun_m_emission); 
		glMaterialf (GL_FRONT, GL_SHININESS, sun_m_shininess); 
		glutSolidSphere(2.0, 40, 32); 
	}
	// 定义地球的材质并绘制地球 
	{ 
		GLfloat earth_m_ambient[] = {0.0f, 0.0f, 0.5f, 1.0f}; 
		GLfloat earth_m_diffuse[] = {0.0f, 0.0f, 0.5f, 1.0f}; 
		GLfloat earth_m_specular[] = {0.0f, 0.0f, 1.0f, 1.0f}; 
		GLfloat earth_m_emission[] = {0.0f, 0.0f, 0.0f, 1.0f}; 
		GLfloat earth_m_shininess = 30.0f; 
		glMaterialfv(GL_FRONT, GL_AMBIENT, earth_m_ambient); 
		glMaterialfv(GL_FRONT, GL_DIFFUSE, earth_m_diffuse); 
		glMaterialfv(GL_FRONT, GL_SPECULAR, earth_m_specular); 
		glMaterialfv(GL_FRONT, GL_EMISSION, earth_m_emission); 
		glMaterialf (GL_FRONT, GL_SHININESS, earth_m_shininess); 
		glRotatef(Step6_angle, 0.0f, -1.0f, 0.0f);
		glTranslatef(5.0f, 0.0f, 0.0f); 
		glutSolidSphere(1.0, 40, 32); 
	} 
	glutSwapBuffers(); 
}

运行效果演示:

在这里插入图片描述

七、项目文件下载

在debug–x86下编译

下载源程序

发布了30 篇原创文章 · 获赞 9 · 访问量 914

猜你喜欢

转载自blog.csdn.net/x879014419/article/details/105219427
今日推荐