OpenGL中的光照
环境光:在环境中进行了充分的散射,无法分辨其方向的光。
散射光:来自某个方向。
镜面光:来自一个特定的方向,并且倾向于从表面某个特定的方向反射。
除了以上三种光外,材料可能具有一种发射颜色,它模拟那些源自某个物体的光。
为了实现明暗效果,必须启用光照计算,而且每种光源也必须被启用。对于单个光源,我们可以这样做:
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0)
注:一旦光照被启用,glColor*()指定的颜色值将不再使用。
指定法向量:
物体的法线向量决定了它相对于光源的方向。表面法线必须为单位长度。
void glNormal3<bsidf>(type x,type y,type z);
void glNormal3<bsidf>(type* v)
光源的指定
void glLight<if>(GLenum light,GLenum param,type value)
void glLight<if>v(GLenum light,GLenum param,type* value)
//为OpenGL光源light设置标量类型或向量类型的参数,即将参数param设为type
材质的指定
void glMaterial<if>(GLenum face,GLenum name,type value)
void glMaterial<if>v(GLenum face,GLenum name,type value)
//为材质的某一面face设置标量或向量参数。参数name类型为type
对于每个面,我们可以为其设置漫反射(GL_DIFFUSE)、镜面反射(GL_SPECULAR)以及环境反射(GL_AMBIENT)属性。通常漫反射和环境反射的属性是相同的,可以将两者一起设置。每个表面都可以向外辐射(GL_EMISSION).这一项不受光照计算的影响,所以无论光源如何,表面看起来都一样的。最后还有一个灰度系数(GL_SHININESS),该参数的值越大,材质的光泽度就越高。
旋转立方体的明暗计算
#include <gl/glut.h>
#include <math.h>
#include <iostream>
using namespace std;
int axis=0;
float theta[3];
GLfloat vertices[][3]={
{-1.0,-1.0,1.0},
{-1.0,1.0,1.0},
{1.0,1.0,1.0},
{1.0,-1.0,1.0},
{-1.0,-1.0,-1.0},
{-1.0,1.0,-1.0},
{1.0,1.0,-1.0},
{1.0,-1.0,-1.0}
}; //定义立方体的8个顶点
GLint index[][4]={
{0,3,2,1},
{2,3,7,6},
{3,0,4,7},
{1,2,6,5},
{4,5,6,7},
{5,4,0,1}
}; //定义每个面所需要那几个顶点
GLfloat normals[][3]={
0.0,0.0,-1.0,
0.0,1.0,0.0,
-1.0,0.0,0.0,
1.0,0.0,0.0,
0.0,0.0,1.0,
0.0,-1.0,0.0
}; //定义每个面的法向量
typedef struct lightingStruct
{
GLfloat ambient[4];
GLfloat diffuse[4];
GLfloat specular[4];
}lightingStruct;
lightingStruct whiteLighting={
{0.0,0.0,0.0,1.0},
{1.0,1.0,1.0,1.0},
{1.0,1.0,1.0,1.0}
};
lightingStruct coloredLighting={
{0.2,0.0,0.0,1.0},
{0.0,1.0,0.0,1.0},
{0.0,0.0,1.0,1.0}
};
typedef struct materialStruct{
GLfloat ambient[4];
GLfloat diffuse[4];
GLfloat specular[4];
GLfloat shininess;
}materialStruct;
materialStruct brassMaterials={
{0.33,0.22,0.03,1.0},
{0.78,0.57,0.11,1.0},
{0.99,0.91,0.81,1.0},
27.8
};
materialStruct redplasticMaterials={
{0.3,0.0,0.0,1.0},
{0.6,0.0,0.0,1.0},
{0.8,0.6,0.6,1.0},
32.0
};
materialStruct whiteShinyMaterials={
{1.0,1.0,1.0,1.0},
{1.0,1.0,1.0,1.0},
{1.0,1.0,1.0,1.0},
100.0
};
GLfloat light_0pos[4]={0.9,0.9,2.25,0.0};
materialStruct* currentMaterials;
lightingStruct* currentLighting;
void init()
{
glClearColor(0.0,0.0,0.0,0.0); //指定屏幕背景为黑色
glEnable(GL_LIGHTING); //启用光照
glEnable(GL_LIGHT0); //启用光源0
glEnable(GL_DEPTH_TEST);
currentMaterials=&redplasticMaterials;
glMaterialfv(GL_FRONT,GL_AMBIENT,currentMaterials->ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,currentMaterials->diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,currentMaterials->specular);
glMaterialfv(GL_FRONT,GL_SHININESS,¤tMaterials->shininess);
currentLighting=&whiteLighting;
glLightfv(GL_LIGHT0,GL_AMBIENT,currentLighting->ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,currentLighting->diffuse);
glLightfv(GL_LIGHT0,GL_SPECULAR,currentLighting->specular);
glLightfv(GL_LIGHT0,GL_POSITION,light_0pos);
glEnable(GL_COLOR_MATERIAL);
}
void polygon(int* index)
{
glBegin(GL_QUADS);
for(int i=0;i<4;i++)
glVertex3fv(vertices[index[i]]);
glEnd();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清理屏幕颜色为我们指定的颜色
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(theta[0],1.0,0.0,0.0);
glRotatef(theta[1],0.0,1.0,0.0);
glRotatef(theta[2],0.0,0.0,1.0);
for(int i=0;i<6;i++)
{
glNormal3fv(normals[i]);
polygon(index[i]);
}
glFlush(); //强制以上绘图操作执行
}
void reshape(int w,int h)
{
glMatrixMode(GL_PROJECTION); //设置为投影模式
glLoadIdentity();
glOrtho(-2.0,2.0,-2.0,2.0,-2.0,2.0);
glViewport(0,0,(GLsizei)w,(GLsizei)h);
}
void mouse(int button,int state,int x,int y)
{
if (button==GLUT_LEFT_BUTTON && state==GLUT_DOWN)
{
axis=0;
}
if (button==GLUT_MIDDLE_BUTTON && state==GLUT_DOWN)
{
axis=1;
}
if (button==GLUT_RIGHT_BUTTON && state==GLUT_DOWN)
{
axis=2;
}
}
void SpinIdle()
{
theta[axis]+=0.1;
if(theta[axis] >360.0) theta[axis] -=360.0;
glutPostRedisplay();
}
void key(unsigned char k,int x,int y)
{
switch (k)
{
case '1':
glutIdleFunc(NULL);
break;
case '2':
glutIdleFunc(SpinIdle);
break;
case '3':
currentMaterials=&redplasticMaterials;
break;
case '4':
currentMaterials=&whiteShinyMaterials;
break;
case '5':
currentMaterials=&brassMaterials;
break;
case '6':
currentLighting=&whiteLighting;
break;
case '7':
currentLighting=&coloredLighting;
break;
case 'q':
exit(0);
break;
}
glMaterialfv(GL_FRONT,GL_AMBIENT,currentMaterials->ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,currentMaterials->diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,currentMaterials->specular);
glMaterialfv(GL_FRONT,GL_SHININESS,¤tMaterials->shininess);
glLightfv(GL_LIGHT0,GL_AMBIENT,currentLighting->ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,currentLighting->diffuse);
glLightfv(GL_LIGHT0,GL_SPECULAR,currentLighting->specular);
glutPostRedisplay();
}
int main(int argc,char**argv)
{
glutInit(&argc,argv); //初始化glut
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); //设置窗口模式为单缓冲和RGB模式
glutInitWindowSize(500,500); //设置窗口大小
glutCreateWindow("test"); //设置窗口标题
glutDisplayFunc(display); //设置绘图回调函数
glutReshapeFunc(reshape); //设置窗口回调函数
glutMouseFunc(mouse);
glutIdleFunc(SpinIdle);
glutKeyboardFunc(key);
init();
glutMainLoop(); //开始循环,等待响应
return 0;
}
运行可以得到如下结果:
对明暗计算的控制
void glLightModel<if>(GLenum param,type value)
void glLightModel<if>v(GLenum param,type value)
//为param(GL_LIGHT_MODEL_AMBIENT,GL_LIGHT_MODEL_LOCAL_VIEWR,GL_LIGHT_MODEL_TWO_SIDE)设置光照模型。
许多情况下,背面不需要计算光照,OpenGL能够利用这种情况,不对背面进行任何的光照计算。如果确实需要两面的光照计算,则可以如下设置:
void glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE)
如果视点距离物体远,则当我们移动物体时,从物体上任一点指向视点的向量几乎没什么变化。所以,可以通知OpenGL视点与场景的距离无穷远:
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWR,GL_TRUE)
若果所有的光源都禁用,环境光将不复存在。但是,我们仍希望少量的环境光存在。则可以设置一个全局环境光源来达到效果:
glLightModeli(GL_LIGHT_MODEL_AMBIENT,global_ambient)
平滑着色
glShadeModel() //参数可设为GL_SMOOTH或GL_FLAT
法线的处理
光照计算要求法向量为单位向量,我们可以开启自动向量规范化:
glEnable(GL_NORMALIZE)
转载于:https://blog.51cto.com/6996127/1547790