OpenGL 光照和材质
前言:很难受呀,一天又过去了,没有达到预期的进度,等下写完这篇博客,抓紧研究鼠标实现轨迹球!
长路漫漫啊……
注:此篇文章建立在MFC环境搭建完成后
1.渲染处理
在OpenGL中,可以定义顶点的颜色,但如何定义线段的颜色,如何定义平面的颜色,这就需要OpenGL通过各个顶点的颜色采用两种不同的渲染处理方法。
明暗渲染处理:void glShadeMode(GLenum mode),直译为阴影模式。
GL_SMOOTH: 平滑地采用光滑变化的明暗渲染方式;
GL_FLAT:采用第一个顶点的颜色绘制一个图元面,每增加一个图元面颜色重新定义;
可以看一下两者的区别:右图glShadeModel(GL_FLAT) ;左图glShadeModel(GL_SMOOTH);
2.光照
简单来说,物体显示的光是由三类光合成的:
泛光:通常称为环境光;
漫反射光:光照射到物体上反射出的光;
镜面反射光:也叫高光,物体某一点比较亮的区域;
启动和关闭光照:
启动:glEnable(GL_LIGHTING);
关闭:glDisable(GL_LIGHTING);
启动与关闭具体某一盏灯:
启动:glEnable(GL_LIGHTi); 关闭:glDisable(GL_LIGHTi); i为非负整数。
例如:
glEnable(GL_LIGHTING); //启动光照
glEnable(GL_LIGHT0); //启用第一盏灯
OpenGL通过函数定义光照属性:
void glLightfv(GLenum light,GLenum pname,const GLfloat *p);
第一参数为灯的序号,第二个参数是状态变量,第三个参数设置光的色彩,使用数组地址填充;
附上一张第二个参数对应表:
附上我今天使用光照和材质的设置:
void CStepinGLView::LightM(void)
{
glClearColor(1.0,1.0,1.0,0.0);
//设置光照
const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_position[] = { 5.0f, 5.0f, 5.0f, 0.0f };
const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f };
const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat high_shininess[] = { 100.0f };
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
}
函数定义光的位置采用数组齐次坐标(x,y,z,w);如果w为0,则该光源为定向光源,照射方向是原点指向(-x,-y,-z),位置在无穷远;如果w不为0,OpenGL认为是点光源,光源位置(x/w,y/w,z/w)。
关于光照的衰减方式和聚光的定义,这里就不探讨了。
3.物体的材质
物体材质的定义同样是相对光线的,也就是如果定义了光照,OpenGL就默认材质;如果定义了材质,没有光线启动,材质也不会 启动;
材质分为两种:一种是完全被动的,也就是被动地接受或只是材质与光线的作用;
二是材质色彩占主导,结合材质变换和光线影响;
启用和关闭材质:
glEnable(GL_COLOR_MATERIAL);
glDisable(GL_COLOR_MATERIAL);
定义材质属性函数:
void glMateriafv(GLenum face,GLenum pname,const GLfloat *p);
第一个参数face为状态变量:GL_FRONT:材质的前面;GL_BACK:材质的后面;GL_FRONT_AND_BACK:材质的双面;
第二个参数pname为状态变量:GL_AMBIENT:设置材质反射环境光的色彩;GL_DIFFUSE:设置材质反射漫反射光色彩;GL_AMBIENT_AND_DIFFUSE:设置反射环境光和漫反射光色彩;GL_SPECULAR:设置材质反射镜面光色彩;
OpenGL还通过第二个参数定义材质的其他属性:
GL_SHININESS:设置光强度,范围[0.0,128.0],数值越小,反射越强,物体高光越明显;
GL_EMISSION:设置辐射光的色彩,缺省值(0.0,0.0,0.0,1.0)。
注:辐射光是材质发出的光,和环境光一样不会衰减,并且不等同于光源,是可见的。
定义辐射光材质:
GLfloat mEmi[4] = {0.3f,0.3f,0.3f,1.0f};
glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,mEmi);
4.法线
OpenGL在采用光照计算时,将用到前面讲到的右手定则定义的法线,但是对于一个复杂的曲面来说,在采用光照时,最好定义出法线,这样有利于光照的计算。
启用和关闭法线:
glEnable(GL_NORMALIZE);
glDisabel(GL_NORMALIZE);
法线定义:
glNormal3f(x,y,z);
5.全局的光照模型
这个我看不太懂,就先附上图片,以后用到再进行讨论;
对于光照和材质就先说那么多吧,附上我写的一段代码:
void CStepinGLView::DrawScene(void)
{
//移动物体到显示区
glTranslatef(0.0f,0.0f,-7.0f);
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
//视角变换
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,3.0,7.0, 0.0,0.0,0.0, 0.0,1.0,0.0);/*前三个参数是眼睛的位置,中间三个参数是物体所在的位置,后面三个参数表示向量,头顶朝上的方向*/
//矩阵堆栈函数,和glPopMatrix()相对应
//glColor3f(102,139,139);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
glPushMatrix();
LightM();
glPopMatrix();
glPushMatrix();
glColor3f(0.5f, 0.25f, 0.0f);
glRotatef(rtri,0.0f,0.1f,0.0f);
//DrawOccluder();
glScalef(0.5f,0.5f,0.5f);
glShadeModel(GL_SMOOTH);
glutSolidTeapot(0.5f);
glPopMatrix();
glPushMatrix();
glRotated(-65,1.0,0.0,0.0);
DrawWater();
glPopMatrix();
glDisable(GL_LIGHTING);
glDisable(GL_COLOR_MATERIAL);
}
程序运行截图:
PS:写到最后,发现忘了讲解gluLookAt()函数了,下篇博文见吧!