美文网首页
OpenGL光照

OpenGL光照

作者: f饭饭f | 来源:发表于2018-05-29 12:16 被阅读0次

    预备知识

    材料

    材料设置

    
    void glMaterialfv(
    
        GLenum face, //设置材质的面片,是前面,后面,还是双面
        GLenum pname, //材质的类型,是环境光材质,漫反射,反射,高光,辐射光等
        GLfloat *param //参数,跟光的参数一样,表示对应的值。
    ); 
    
    
    • face参数

    指出将材质应用于物体的哪面

    
    GL_FRONT
    
    GL_BACK
    
    GL_FRONT_AND_BACK
    
    
    • pname参数可选项
    
    GL_AMBIENT//环境光颜色
    
    GL_DIFFUSE//漫反射颜色 
    
    GL_SPECULAR//镜面反射颜色 
    
    GL_SHININESS//镜面反射指数高光 
    
    GL_EMISSION//辐射光颜色 
    
    
    • param

    颜色参数表示对该种色光的反射程度

    1表示完全反射,0表示完全吸收

    材质状态

    材质会被保存在状态里面,所以如果不改变材质的话,默认会用最近用过的材质。

    在使用某种材质的前文中需要设定好材质属性,再进行绘制。

    这一点和之前所学的glTranslatefglScalefglRotatef有一定相似之处

    思考

    发现在给物体设置材质的时候,在本次实验里面设定GL_FRONT还是GL_FRONT_AND_BACK没有差别,猜想是因为这次的物体在查看的时候显示出来的全是FRONT面

    光照

    光照设置

    
    void glLightfv(
    
        GLenum light, //指定光源
        GLenum pname, //材质的类型,是环境光材质,漫反射,反射,高光,辐射光等
        const GLfloat *param //参数,跟光的参数一样,表示对应的值。
    );
    
    
    • light参数

    OpenGL里面最多可设置八个光源,GL_LIGHT0、GL_LIGHT1、……、GL_LIGHT7

    light参数便是指定对某一光源进行属性设置

    • pname参数可选项
    
    GL_AMBIENT//环境光颜色,默认值(0,0,0,1)
    
    GL_DIFFUSE//漫反射颜色,默认值(1,1,1,1) 
    
    GL_SPECULAR//镜面反射颜色,默认值(1,1,1,1)
    
    GL_POSITION//光源位置,默认值(0,0,1,0)
    
    GL_SPOT_CUTOFF//角度,对于聚光灯设定
    
    GL_SPOT_DIRECTION//光照方向,对于聚光灯设定 
    
    GL_SPOT_EXPONENT//聚集度,对于聚光灯设定 
    
    
    • param

    设置pname项的具体参数

    其中GL_POSITION的第四个参数w

    若w=0,表示定向光源,也即光源位于无穷远处,照在物体上时可当成平行光

    若w=1,表示定点光源,光源位于特定的某个点处

    光源开启

    光源和材质不一样,材质只需要直接指定即可,但是光源需要“开启”,才能显示出作用

    在设置光源之前,需要开启光照模式

    
    glEnable(GL_LIGHTING);
    
    

    设置完某一光源后,想要在结果里面显示出有光源的效果,需要像打开灯的开关一样打开它

    
    glEnable(GL_LIGHT0);
    
    

    实验要求

    使用Visual Studio C++编译已有项目工程。

    模型尺寸不做具体要求。要求修改代码达到以下要求:

    1.通过设置材料使得桌面和四条腿的颜色各不相同,分别为:(1, 0, 0), (0, 1, 0), (1, 1, 0), (0, 1, 1), (0, 0, 1);

    2.通过设置材料使得茶壶为金黄色;

    3.添加按键处理,移动场景中的光源,并能改变光源的颜色(在两种颜色间切换,颜色自己定义);

    4.修改茶壶的镜面反射系数,使之对光源呈现高光;

    5.在场景中添加一个聚光光源,其照射区域正好覆盖茶壶,并能调整改聚光光源的照射角度和朝向。

    具体做法

    一)设置材质

    根据实验要求对茶壶,桌面,四条桌腿分别设置不同的材质

    //设置材质参数
        GLfloat specular[] = { 0.6f,0.6f,0.6f,1 };
        GLfloat diffuse0[] = { 0.85f,0.65f,0.2f,1 };
        GLfloat diffuse1[] = { 1,0,0,1 };
        GLfloat diffuse2[] = { 0,1,0,1 };
        GLfloat diffuse3[] = { 1,1,0,1 };
        GLfloat diffuse4[] = { 0,1,1,1 };
        GLfloat diffuse5[] = { 0,0,1,1 };
    

    茶壶的镜面反射与漫反射设置不同的颜色

    //茶壶
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);//正反面的镜面反射颜色
        glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 50);//镜面反射系数
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse0);//正反面的漫反射颜色
    

    桌面与每条桌腿自身的镜面反射与漫反射设置成相同颜色,不考虑高光

    //桌面
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, diffuse1);//正反面的镜面反射颜色
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse1);//正反面的漫反射颜色
    

    二)设置光照

    设定点光源与聚光灯的一系列参数

    /* 点光源 */
    GLfloat light0_pos[] = { 5,5,5,1 };//Position
    GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };//color
    GLfloat purple[] = { 1.0, 0, 1.0, 1.0 };//color
    /*聚光灯*/
    GLfloat light1_pos[] = { 0.0f, 5.0f, 0.0f, 1.0f };
    GLfloat light_dir[] = { 0,-1,0 };
    GLfloat angle = 5.0f;
    

    配置光源并打开

    • 点光源
    /* 点光源 */
        glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);//位置
        //环境光可在白光和紫光之间切换
        if (isWhite) {
            glLightfv(GL_LIGHT0, GL_AMBIENT, white);//环境光属性
        }
        else {
            glLightfv(GL_LIGHT0, GL_AMBIENT, purple);//环境光属性
        }
        glLightfv(GL_LIGHT0, GL_DIFFUSE, white);//漫反射属性
        glLightfv(GL_LIGHT0, GL_SPECULAR, white);//镜面反射属性
        glEnable(GL_LIGHT0);
        
    
    • 聚光灯
    /* 聚光灯 */
        glLightfv(GL_LIGHT1, GL_POSITION, light1_pos);//位置
        if (isWhite) {
            glLightfv(GL_LIGHT1, GL_AMBIENT, white);//环境光属性
        }
        else {
            glLightfv(GL_LIGHT1, GL_AMBIENT, purple);//环境光属性
        }
        glLightfv(GL_LIGHT1, GL_DIFFUSE, white);//漫反射属性
        glLightfv(GL_LIGHT1, GL_SPECULAR, white);//镜面反射属性
        glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, angle);//设置聚光灯角度
        glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, light_dir);//设置聚光灯方向
        glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2);//设置聚光灯聚集度
        glEnable(GL_LIGHT1);
    

    三)设置按键功能

    光照颜色切换

    使用l按键来切换,isWhite是事先定义好的一个全局变量

    //切换光照颜色,白色or紫色
    case 'l': {
        isWhite = !isWhite;
        break;
    }
    

    光源位置调整

    考虑到按键数量有限,若是给点光源位置,聚光灯位置,聚光灯朝向分别设置6个按键分别控制上下前后左右的调整,按键数可能不够也非常不好管理。所以想让这6个按键彼此共用,一方面需要管理的按键数量减少,另一方面能够尽可能保证按键与其功能有一定意义上的关联,便于记忆与理解。
    共用的话就需要做好切换,因此引入两个全局变量 isLight0isPos调整

    • isLight0在true与false间切换,true代表当前控制的是点光源,false表示聚光灯
    • isPos在true与false间切换,true代表当前控制的是position,false表示direction(由于只有聚光灯有direction,所以只有当isLight0=false;时才会进行对isPos的判断

    按键5与按键0分别进行isLight0isPos的控制

    //移动控制,移动环境光or聚光灯
    case '5': {
        isLight0 = !isLight0;
        break;
    }
    //移动控制,改变聚光灯角度or位置
    case '0': {
        isPos = !isPos;
        break;
    }
    

    数字键盘上的按键824613分别表示上下左右前后

    //光照左移
        case '4': {
            if (isLight0) //移动环境光
            {
                light0_pos[0] -= 0.2f;
            }
            else //移动聚光灯
            {
                if (isPos) {
                    light1_pos[0] -= 0.2f;
                }
                else
                {
                    light_dir[0] -= 0.05f;
                }
            }
            break;
        }          
    

    聚光灯角度调整

    聚光灯角度需要设计一个范围,只能在该范围内放大减小
    angle是预先定义好的全局变量
    用按键+-控制角度变大变小

    //增大聚光灯角度
        case '+': {
            if (angle <= 89.8) {
                angle += 0.2f;
            }
            break;
        }
        //减小聚光灯角度
        case '-': {
            if (angle >= 0.2) {
                angle -= 0.2f;
            }
            break;
        }
        }
    

    实验结果






    附源码参考

    // glutEx1.cpp : 定义控制台应用程序的入口点。
    //
    
    
    #include <stdlib.h>
    #include "glut.h"
    
    float fTranslate;
    float fRotate;
    float fScale     = 1.0f;    // set inital scale value to 1.0f
    
    bool bPersp = false;
    bool bAnim = false;
    bool bWire = false;
    bool isWhite = true;
    bool isLight0 = true;
    bool isPos = true;
    
    int wHeight = 0;
    int wWidth = 0;
    
    /* 点光源 */
    GLfloat light0_pos[] = { 5,5,5,1 };//Position
    GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };//color
    GLfloat purple[] = { 1.0, 0, 1.0, 1.0 };//color
    
    /*聚光灯*/
    GLfloat light1_pos[] = { 0.0f, 5.0f, 0.0f, 1.0f };
    GLfloat light_dir[] = { 0,-1,0 };
    GLfloat angle = 5.0f;
    
    void Draw_Leg();
    
    void Draw_Triangle() // This function draws a triangle with RGB colors
    {
        //设置材质参数
        GLfloat specular[] = { 0.6f,0.6f,0.6f,1 };
        GLfloat diffuse0[] = { 0.85f,0.65f,0.2f,1 };
        GLfloat diffuse1[] = { 1,0,0,1 };
        GLfloat diffuse2[] = { 0,1,0,1 };
        GLfloat diffuse3[] = { 1,1,0,1 };
        GLfloat diffuse4[] = { 0,1,1,1 };
        GLfloat diffuse5[] = { 0,0,1,1 };
    
        //茶壶
        glPushMatrix();
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);//正反面的镜面反射颜色
        glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 50);//镜面反射系数
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse0);//正反面的漫反射颜色
        glTranslatef(0, 0, 4+1);
        glRotatef(90, 1, 0, 0);
        glutSolidTeapot(1);
        glPopMatrix();
    
        //桌面
        glPushMatrix();
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, diffuse1);//正反面的镜面反射颜色
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse1);//正反面的漫反射颜色
        glTranslatef(0, 0, 3.5);
        glScalef(5, 4, 1);
        glutSolidCube(1.0);
        glPopMatrix();
    
        //桌腿1
        glPushMatrix();
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, diffuse2);//正反面的镜面反射颜色
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse2);//正反面的漫反射颜色
        //glMaterialfv(GL_BACK, GL_SPECULAR, diffuse2);//正反面的镜面反射颜色
        //glMaterialfv(GL_BACK, GL_DIFFUSE, diffuse2);//正反面的漫反射颜色
        glTranslatef(1.5, 1, 1.5);
        Draw_Leg();
        glPopMatrix();
    
        //桌腿2
        glPushMatrix();
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, diffuse3);//正反面的镜面反射颜色
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse3);//正反面的漫反射颜色
        glTranslatef(-1.5, 1, 1.5);
        Draw_Leg();
        glPopMatrix();
    
        //桌腿3
        glPushMatrix();
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, diffuse4);//正反面的镜面反射颜色
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse4);//正反面的漫反射颜色
        glTranslatef(1.5, -1, 1.5);
        Draw_Leg();
        glPopMatrix();
    
        //桌腿4
        glPushMatrix();
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, diffuse5);//正反面的镜面反射颜色
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse5);//正反面的漫反射颜色
        glTranslatef(-1.5, -1, 1.5);
        Draw_Leg();
        glPopMatrix();
    
    }
    
    void Draw_Leg()
    {
        glScalef(1, 1, 3);
        glutSolidCube(1.0);
    }
    
    void updateView(int width, int height)
    {
        glViewport(0,0,width,height);                       // Reset The Current Viewport
    
        glMatrixMode(GL_PROJECTION);                        // Select The Projection Matrix
        glLoadIdentity();                                   // Reset The Projection Matrix
    
        float whRatio = (GLfloat)width/(GLfloat)height;
        if (bPersp) {
            gluPerspective(45.0f, whRatio,0.1f,100.0f);
            //glFrustum(-3, 3, -3, 3, 3,100);
        } else {
            glOrtho(-3 ,3, -3, 3,-100,100);
        }
    
        glMatrixMode(GL_MODELVIEW);                         // Select The Modelview Matrix
    }
    
    void reshape(int width, int height)
    {
        if (height==0)                                      // Prevent A Divide By Zero By
        {
            height=1;                                       // Making Height Equal One
        }
    
        wHeight = height;
        wWidth = width;
    
        updateView(wHeight, wWidth);
    }
    
    void idle()
    {
        glutPostRedisplay();
    }
    
    float eye[] = {0, 0, 8};
    float center[] = {0, 0, 0};
    
    void key(unsigned char k, int x, int y)
    {
        switch(k)
        {
        case 27:
        case 'q': {exit(0); break; }
        //切换投影模式
        case 'p': {bPersp = !bPersp; break; }
        //旋转
        case ' ': {bAnim = !bAnim; break;}
        //切换线框模式
        case 'o': {bWire = !bWire; break;}
        //整体左移
        case 'a': {
            eye[0] += 0.2f;
            center[0] += 0.2f;
            break;
                  }
        //整体右移
        case 'd': {
            eye[0] -= 0.2f;
            center[0] -= 0.2f;
            break;
                  }
        //整体上移
        case 'w': {
            eye[1] -= 0.2f;
            center[1] -= 0.2f;
            break;
                  }
        //整体下移
        case 's': {
            eye[1] += 0.2f;
            center[1] += 0.2f;
            break;
                  }
        //整体前移
        case 'z': {
            eye[2] -= 0.2f;
            center[2] -= 0.2f;
            break;
                  }
        //整体后移
        case 'c': {
            eye[2] += 0.2f;
            center[2] += 0.2f;
            break;
                  }
        //切换光照颜色,白色or紫色
        case 'l': {
            isWhite = !isWhite;
            break;
            }
        //移动控制,移动环境光or聚光灯
        case '5': {
            isLight0 = !isLight0;
            break;
        }
        //移动控制,改变聚光灯角度or位置
        case '0': {
            isPos = !isPos;
            break;
        }
        //光照左移
        case '4': {
            if (isLight0) //移动环境光
            {
                light0_pos[0] -= 0.2f;
            }
            else //移动聚光灯
            {
                if (isPos) {
                    light1_pos[0] -= 0.2f;
                }
                else
                {
                    light_dir[0] -= 0.05f;
                }
            }
            break;
        }         
        //光照右移
        case '6': {
            if (isLight0) //移动环境光
            {
                light0_pos[0] += 0.2f;
            }
            else //移动聚光灯
            {
                if (isPos) {
                    light1_pos[0] += 0.2f;
                }
                else
                {
                    light_dir[0] += 0.05f;
                }
            }
            break;
        }
        //光照上移
        case '8': {
            if (isLight0) //移动环境光
            {
                light0_pos[1] += 0.2f;
            }
            else //移动聚光灯
            {
                if (isPos) {
                    light1_pos[1] += 0.2f;
                }
                else
                {
                    light_dir[1] += 0.05f;
                }
            }
            break;
        }
        //光照下移
        case '2': {
            if (isLight0) //移动环境光
            {
                light0_pos[1] -= 0.2f;
            }
            else //移动聚光灯
            {
                if (isPos) {
                    light1_pos[1] -= 0.2f;
                }
                else
                {
                    light_dir[1] -= 0.05f;
                }
            }
            break;
        }
        //光照前移
        case '1': {
            if (isLight0) //移动环境光
            {
                light0_pos[2] += 0.2f;
            }
            else //移动聚光灯
            {
                if (isPos) {
                    light1_pos[2] += 0.2f;
                }
                else
                {
                    light_dir[2] += 0.05f;
                }
            }
            break;
        }
        //光照后移
        case '3': {
            if (isLight0) //移动环境光
            {
                light0_pos[2] -= 0.2f;
            }
            else //移动聚光灯
            {
                if (isPos) {
                    light1_pos[2] -= 0.2f;
                }
                else
                {
                    light_dir[2] -= 0.05f;
                }
            }
            break;
        }
        //增大聚光灯角度
        case '+': {
            if (angle <= 89.8) {
                angle += 0.2f;
            }
            break;
        }
        //减小聚光灯角度
        case '-': {
            if (angle >= 0.2) {
                angle -= 0.2f;
            }
            break;
        }
        }
        updateView(wHeight, wWidth);
    }
    
    
    void redraw()
    {
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();                                   // Reset The Current Modelview Matrix
    
        gluLookAt(eye[0], eye[1], eye[2],
            center[0], center[1], center[2],
            0, 1, 0);               // 场景(0,0,0)的视点中心 (0,5,50),Y轴向上
    
        if (bWire) {
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        }
        else {
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        }
    
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_LIGHTING);
    
        /* 点光源 */
        glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);//位置
        //环境光可在白光和紫光之间切换
        if (isWhite) {
            glLightfv(GL_LIGHT0, GL_AMBIENT, white);//环境光属性
        }
        else {
            glLightfv(GL_LIGHT0, GL_AMBIENT, purple);//环境光属性
        }
        glLightfv(GL_LIGHT0, GL_DIFFUSE, white);//漫反射属性
        glLightfv(GL_LIGHT0, GL_SPECULAR, white);//镜面反射属性
        glEnable(GL_LIGHT0);
    
        /* 聚光灯 */
        glLightfv(GL_LIGHT1, GL_POSITION, light1_pos);//位置
        if (isWhite) {
            glLightfv(GL_LIGHT1, GL_AMBIENT, white);//环境光属性
        }
        else {
            glLightfv(GL_LIGHT1, GL_AMBIENT, purple);//环境光属性
        }
        glLightfv(GL_LIGHT1, GL_DIFFUSE, white);//漫反射属性
        glLightfv(GL_LIGHT1, GL_SPECULAR, white);//镜面反射属性
    
        glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, angle);//设置聚光灯角度
        glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, light_dir);//设置聚光灯方向
        glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2);//设置聚光灯聚集度
        glEnable(GL_LIGHT1);
    
        //  glTranslatef(0.0f, 0.0f,-6.0f);         // Place the triangle at Center
        glRotatef(fRotate, 0, 1.0f, 0);         // Rotate around Y axis
        glRotatef(-90, 1, 0, 0);
        glScalef(0.2, 0.2, 0.2);
        Draw_Triangle();                        // Draw triangle
    
        if (bAnim) fRotate    += 0.5f;
        glutSwapBuffers();
    }
    
    int main (int argc,  char *argv[])
    {
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
        glutInitWindowSize(480,480);
        int windowHandle = glutCreateWindow("Simple GLUT App");
    
        glutDisplayFunc(redraw);
        glutReshapeFunc(reshape);   
        glutKeyboardFunc(key);
        glutIdleFunc(idle);
    
        glutMainLoop();
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:OpenGL光照

          本文链接:https://www.haomeiwen.com/subject/svgojftx.html