在OpenGL中当我们需要使用光照时,我们需要做如下的设置:
下面我们就依次进行:
在OpenGL中使用glEnable和glDisable来开启和关闭光照计算:
// 开启光照计算
glEnable(GL_LIGHTING);
//关闭光照计算
glDisable(GL_LIGHTING)
OpenGL的实现默认最少支持8个光源,这些光源的编号从0-7,依次是GL_LIGHT0、GL_LIGHT1 .... GL_LIGHT7,当我们使用是可以调用glLight来设置它们的参数,具体参数包括:
设置光源中的环境光成分,调用如下:
//设置0号光源的环境光为
float ambient[] = {0.4, 0.4, 0.4, 1.0}
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient)
散射光默认的取值是(0, 0, 0, 1)
设置光源中的散射光成分,默认的取值 GL_LIGHT0是(1,1,1,1), 其他光源的取值是(0,0,0,1),调用方式:
//设置0号光源的环境光为
float diffuse[] = {0.4, 0.4, 0.4, 1.0}
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse)
设置光源中的平行光成分,默认的取值与GL_DIFFUSE中一样,GL_LIGHT0默认是(1,1,1,1),其他光源是(0,0,0,1)
设置光源的位置,GL_POSITON中指定的位置在调用glLight之后会通过当前的模型视图矩阵转换到相机坐标系中,GL_POSITION中的位置是一个齐次坐标,最后一个参数w如果为0,代表该光源是一个平行光,平行光中衰减参数是无效的。初始OpenGL中的光源位置在(0,0,1,0),也就是该光源是一个平行光,并且方向指向Z轴负方向。
这个参数和以下两个参数都是用来设置聚光灯效果的光源的,GL_SPOT_DIRECTION简单来说就是设置聚光灯的方向,当聚光灯的开口角度不是360度的时候(类似于点光源),设置GL_SPOT_DIRECTION是有效的(也就是当GL_SPOT_CUTOFF是180度的时候设置GL_SPOT_DIRECTION并没有任何作用),默认的GL_SPOT_DIRECTION的取值是z轴负方向,也就是(0, 0, -1),在指定GL_SPORT_DIRECTION之后它会经过模型视图矩阵的变化变化到相机坐标系中。
这个参数主要用来设置聚光灯的光线集中度,聚光灯的光的强度在光锥中心最高,越靠近边缘光的强度就越弱,这个参数设置的越大,聚光灯的聚光效果越强,这个参数的初始取值是0,它的取值范围限定在【0,128】
这个参数主要用来设置聚光灯的辐射范围,默认值是180(类似与点光源),可以选择的取值范围是【0,90】以及180这个特殊值,可以参考下图:
这三个参数主要用来设置光的衰减参数,分别是常量衰减部分+线性部分+二次部分,具体衰减公式可以继续阅读下文。默认的取值是(1,0,0),也就是没有衰减。需要注意的是:这三个参数只对有位置的光源有用,对平行光源来说没有意义。
下文中主要列举了光源通过不同的参数设置所显现的不同效果:
glClearColor(0, 0, 0, 1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
ambient = [0.8, 0.8, 0.8]
glLightfv(GL_LIGHT1, GL_AMBIENT, ambient)
glEnable(GL_LIGHT1)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0, 0, -10)
glRotatef(xRot, 1, 0, 0)
glRotatef(yRot, 0, 1, 0)
glutSolidSphere(2, 32, 18)
glutSwapBuffers()
运行效果:
glClearColor(0, 0, 0, 1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
diffuse = [0.8, 0.8, 0.8]
glLightfv(GL_LIGHT0, GL_AMBIENT, diffuse)
glEnable(GL_LIGHT0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0, 0, -10)
glRotatef(xRot, 1, 0, 0)
glRotatef(yRot, 0, 1, 0)
glutSolidSphere(2, 32, 18)
glutSwapBuffers()
运行效果:
glClearColor(0, 0, 0, 1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
specular = [0.8, 0.8, 0.8]
glLightfv(GL_LIGHT1, GL_SPECULAR, specular)
glEnable(GL_LIGHT1)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0, 0, -10)
glRotatef(xRot, 1, 0, 0)
glRotatef(yRot, 0, 1, 0)
glutSolidSphere(2, 32, 18)
glutSwapBuffers()
运行效果:什么场景都看不见,主要是因为平行光依赖于视点与光线之间的角度关系
glClearColor(0, 0, 0, 1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
diffuse = [0.8, 0.8, 0.8]
position = [-1, 0, 0, 0]
glLightfv(GL_LIGHT0, GL_POSITION, position)
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse)
glEnable(GL_LIGHT0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0, 0, -10)
glRotatef(xRot, 1, 0, 0)
glRotatef(yRot, 0, 1, 0)
glutSolidSphere(2, 32, 18)
glutSwapBuffers()
运行效果:
可以看到光源的位置确实由正前方转到左方了
将4中的平行光修改为点光源
glClearColor(0, 0, 0, 1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
diffuse = [0.8, 0.8, 0.8]
position = [-1, 0, 0, 1]
glLightfv(GL_LIGHT0, GL_POSITION, position)
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse)
glEnable(GL_LIGHT0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0, 0, -10)
glRotatef(xRot, 1, 0, 0)
glRotatef(yRot, 0, 1, 0)
glutSolidSphere(2, 32, 18)
glutSwapBuffers()
我们将5中的点光源设置为聚光灯的模式,让它限定在一定范围内,代码如下:
glClearColor(0, 0, 0, 1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
diffuse = [0.8, 0.8, 0.8]
position = [0, 0, -1, 1]
glLightfv(GL_LIGHT0, GL_POSITION, position)
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse)
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 20.0)
glEnable(GL_LIGHT0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0, 0, -10)
glRotatef(xRot, 1, 0, 0)
glRotatef(yRot, 0, 1, 0)
glutSolidSphere(2, 32, 18)
glutSwapBuffers()