您的位置:首页 > 运维架构

OpenGL学习(五) 光照与材质

2014-09-02 11:46 489 查看
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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  OpenGL 光照