OpenGL从1.0开始--光照和表面绘制函数

对场景的对象进行透视投影,然后再可见面上产生自然光照效果,可以实现场景的真实感显示。多说无益,看一个示例是最直接的方法(示例代码来源于http://blog.csdn.net/timidsmile/article/details/7017197)。
这里写图片描述

#include <gl/glut.h>  
#define WIDTH 400  
#define HEIGHT 400  
static GLfloat angle = 0.0f;
void myDisplay(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity();  
    gluPerspective(90.0f, 1.0f, 1.0f, 20.0f);
    glMatrixMode(GL_MODELVIEW);  
    glLoadIdentity();
    gluLookAt(0.0, 5.0, -10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); 
    // 定义太阳光源,它是一种白色的光源  
    {
        GLfloat sun_light_position[] = { 0.0f, 0.0f, 0.0f, 1.0f };
        GLfloat sun_light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
        GLfloat sun_light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
        GLfloat sun_light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
        glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position); //指定第0号光源的位置   
        glLightfv(GL_LIGHT0, GL_AMBIENT, sun_light_ambient); //GL_AMBIENT表示各种光线照射到该材质上,经过很多次反射后最终遗留在环境中的光线强度(颜色)  
        glLightfv(GL_LIGHT0, GL_DIFFUSE, sun_light_diffuse); //漫反射后~~  
        glLightfv(GL_LIGHT0, GL_SPECULAR, sun_light_specular);//镜面反射后~~~  
        glEnable(GL_LIGHT0); //使用第0号光照  
        glEnable(GL_LIGHTING); //在后面的渲染中使用光照  
        glEnable(GL_DEPTH_TEST); //这句是启用深度测试,这样,在后面的物体会被挡着,例如房子后面有棵树,如果不启用深度测试,你先画了房子再画树,树会覆盖房子的;但启用深度测试后无论你怎么画,树一定在房子后面(被房子挡着)   
    }
    // 定义太阳的材质并绘制太阳  
    {
        GLfloat sun_mat_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
        GLfloat sun_mat_diffuse[] = { 0.0f, 0.0f, 0.0f, 1.0f };
        GLfloat sun_mat_specular[] = { 0.0f, 0.0f, 0.0f, 1.0f };
        GLfloat sun_mat_emission[] = { 0.5f, 0.0f, 0.0f, 1.0f };
        GLfloat sun_mat_shininess = 0.0f;
        glMaterialfv(GL_FRONT, GL_AMBIENT, sun_mat_ambient); //定义材料的前面采用 "多次反射"  
        glMaterialfv(GL_FRONT, GL_DIFFUSE, sun_mat_diffuse); //材料的前面为 漫反射  
        glMaterialfv(GL_FRONT, GL_SPECULAR, sun_mat_specular); //定义材料的前面为 镜面反射  
        glMaterialfv(GL_FRONT, GL_EMISSION, sun_mat_emission); //定义材料的前面为 镜面指数  
        glMaterialf(GL_FRONT, GL_SHININESS, sun_mat_shininess); //材料的前面 采用 的颜色  
        glutSolidSphere(2.0, 40, 32);
    }
    // 定义地球的材质并绘制地球  
    {
        GLfloat earth_mat_ambient[] = { 0.0f, 0.0f, 0.5f, 1.0f };
        GLfloat earth_mat_diffuse[] = { 0.0f, 0.0f, 0.5f, 1.0f };
        GLfloat earth_mat_specular[] = { 0.0f, 0.0f, 1.0f, 1.0f };
        GLfloat earth_mat_emission[] = { 0.0f, 0.0f, 0.0f, 1.0f };
        GLfloat earth_mat_shininess = 30.0f;
        glMaterialfv(GL_FRONT, GL_AMBIENT, earth_mat_ambient);
        glMaterialfv(GL_FRONT, GL_DIFFUSE, earth_mat_diffuse);
        glMaterialfv(GL_FRONT, GL_SPECULAR, earth_mat_specular);
        glMaterialfv(GL_FRONT, GL_EMISSION, earth_mat_emission);
        glMaterialf(GL_FRONT, GL_SHININESS, earth_mat_shininess);
        glRotatef(angle, 0.0f, -1.0f, 0.0f);
        glTranslatef(5.0f, 0.0f, 0.0f);
        //如果使用glutSolidSphere函数来绘制球体,则该函数会自动的指定这些法线向量,  
        //不必再手工指出。如果是自己指定若干的顶点来绘制一个球体,则需要自己指定法线向量。  
        glutSolidSphere(2.0, 40, 32);
    }
    glutSwapBuffers(); //交换缓冲区  
}
void myIdle(void)
{
    angle += 1.0f;
    if (angle >= 360.0f)
        angle = 0.0f;
    myDisplay();
}
int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
    glutInitWindowPosition(200, 200);
    glutInitWindowSize(WIDTH, HEIGHT);
    glutCreateWindow("OpenGL光照演示");
    glutDisplayFunc(&myDisplay);
    glutIdleFunc(&myIdle);
    glutMainLoop();
    return 0;
}

这个示例模拟的是地球绕太阳旋转的场景,红色的太阳发射出白光照亮了蓝色的地球。我们来详解里面的函数。
太阳是一种点光源。我们使用glLightfv设置光源的各种属性,包括光源位置GL_POSITION,光源颜色(环境光GL_AMBIENT, 漫反射光GL_DIFFUSE, 镜面反射光GL_SPECULAR),辐射强度衰减系数等。

glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position);//第一个参数为光源名,第二个参数指定属性,第三个参数为属性值

除了点光源外我们还可以设置方向光源(投射光源),即模拟台灯光照,中心光线最强,边缘光线强度最低。

glLightfv(GL_LIGHT0, GL_SPOT_POSITION, sun_light_position);//圆锥轴方向
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, 30.0);//光源到圆锥轴的夹角被限制在30度的范围内
glLightfv(GL_LIGHT0, GL_SPOT_EXPONENT, 2.5);//从中心到边缘的衰减系数

可在全局级指定若干个OpenGL光照参数。

glLightModel*(paramName,paramValve);//两个参数分别指定参数名和参数值

光照效果除了和光源颜色有关外,也和对象表面反射特性密不可分。表面的反射系数和其他可选特性用下列函数来设定:

glMaterialf(surfFace,surfProperty,propertyValue);

surfFace赋予符号常量GL_FRONT,GL_BACK,GL_FRONT_AND_BACK之一,指定需要描述的面,surfProperty指定属性名(散射颜色gL_EMISSION、GL_SHININESS等)。
在应用光源前,需要激活光源并点亮光源。

glEnable(lightName);//点亮光源
glEnable(GL_LIGHTING);//激活光源

我们还可以使用雾气效果来模拟真实环境。

glEnable(GL_FOG);//激活雾气
glFogf(atmoParameter,paramValue);//设置雾气属性,例如颜色GL_FOG_COLOR,雾气衰减GL_FOG_DENSITY等等

为了更好地处理图元表面的明暗变化,可以指定相应的表面绘制方法来进行插值处理。

glShadeModel(surfRenderingMethod);

参数指定表面绘制方法,如果是GL_FLAT指定常数强度表面绘制方法,即不进行任何处理。GL_SMOOTH指定Gouraud表面绘制方法,在这种模式下,需要对每个平面指定一个法向量。

glBegin(GL_TRIANGLES):
glNormal3fv(normalVector1);
glVertex3fv(vertex1);
glNormal3fv(normalVector2);
glVertex3fv(vertex2);
glNormal3fv(normalVector3);
glVertex3fv(vertex3);

我们可以将法向量单位化来加速OpenGL效率

glEnable(GL_NORMALIZE);

和顶点数组。颜色数组一样,我们也可以指定一个法向量数组:

glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(dataType,offset,normalArray);

猜你喜欢

转载自blog.csdn.net/wudiliyao/article/details/78646020