计算机图形学——实验三 光照与材质处理实验

简介: 实验三 光照与材质处理实验了解简单光照明模型的基本原理,利用VS+OpenGL实现物体的光照和材质处理。1. 光照模型当光照射到一个物体表面上时,会出现三种情形。首先,光可以通过物体表面向空间反射,产生反射光;其次,对于透明物体,光可以穿透该物体并从另一端射出,产生透射光;最后,部分光被物体表面吸收而转换成热。在上述三部分光中,仅仅是透射光和反射光能够进入人眼产生视觉效果。此外,物体本身还有可能发光。这里我们暂时不考虑透明物体,这样场景中可能存在以下几种类型的光,即环境光、散射光、镜面光和辐射光。1

实验三 光照与材质处理实验

实验项目性质:设计性实验

所属课程名称:3D游戏图形学

实验计划学时:3学时

    • 实验目的和要求

    了解简单光照明模型的基本原理,利用VS+OpenGL实现物体的光照和材质处理。

      • 实验原理
        1. 光照模型

        当光照射到一个物体表面上时,会出现三种情形。首先,光可以通过物体表面向空间反射,产生反射光;其次,对于透明物体,光可以穿透该物体并从另一端射出,产生透射光;最后,部分光被物体表面吸收而转换成热。在上述三部分光中,仅仅是透射光和反射光能够进入人眼产生视觉效果。此外,物体本身还有可能发光。这里我们暂时不考虑透明物体,这样场景中可能存在以下几种类型的光,即环境光、散射光、镜面光和辐射光。

        1)环境光(Ambient Light)

        环境光有光源,但是由于被周围的环境,如地面、天空、墙壁等多次反射,变得无法确定其方向。环境光均匀地从周围环境入射至景物表面并等量地向各个方向反射出去。一般说来,房间里的环境光成分要多些,户外的相反要少得多,因为大部分光按相同的方向照射,而在户外很少有其他物体反射的光。

        2)漫反射光(Diffuse Light)

        漫反射光来自某个方向,它垂直于物体时比倾斜时更明亮。一旦它照射到物体上,则在各个方向上均匀地发散出去。于是,无论视点在哪里它都一样亮。来自特定位置和特定方向的任何光,都可能有散射成分。

        3)镜面光(Specular Light)

        镜面光也具有方向性,但被物体强烈地反射到另一个特定的方向。如一个点光源照射一个金属球时会在球面上形成一块特别亮的区域,呈现所谓“高光(Highlight)”,它是光源在金属球面上产生的镜面反射光。对于较光滑物体,其镜面反射光的高光区域小而亮;相反,粗糙表面的镜面反射光呈发散状态,其高光区域大而不亮。

        4)辐射光

        辐射光是最简单的一种光,它直接从物体发出并且不受任何光源影响。在OpenGL 中,任何一种光源都由三种光照成分组成:环境光、漫反射光和镜面光,当然光源本身还有可能发出辐射光。由于我们知道光是一种波,而颜色仅仅是我们可以看见的一种光波,所以每种光照成分都是由RGBA 值定义的。

          1. 材质属性

          当我们使用光照来描述多边形,总是说它由具有某些反射属性的材质组成,而不说它具有特殊的颜色。这样我们指定物体的颜色,就必须指定物体材质对环境光、漫射光和镜面光源的反射属性。通常,我们用材质对光的红、绿、蓝三原色的反射率来近似定义材质属性。像光源一样,材质颜色也分成环境、漫反射和镜面反射成分,它们决定了材质对环境光、漫反射光和镜面反射光的反射程度。

          在进行光照计算时,物体的最终颜色是由其材质属性的RGB 值 和光照属性的RGB 值共同决定的。例如,如果当前的环境光源的RGB 值为(0.5,1.0,0.5),而物体的材质的环境反射成分的RGB 值为(0.5,0.5,0.5),那么物体最终的颜色为:

          (0.5×0.5,1.0×0.5,0.5×0.5)=(0.25,0.5,0.25)

          即将每个环境光源的成分与材质的环境反射率相乘。这样,物体表面的颜色为三项RGB值的叠加:材质对环境光的反射率与环境光结合的RGB 值;材质对漫反射光的反射率与漫反射光结合的RGB 值;材质对镜面光的反射率与镜面反射光结合的RGB 值。注意,当叠加的RGB 中任何一个颜色分量的值大于1.0,那么就用1.0 计算。

            • 实验内容
              1. 对实验二绘制的椅子增加光照效果,设置不同的光源,包括环境光、点光源(聚光灯)、方向光源,使椅子具有多种彩色光影。
              2. 除了环境光,保留一个点光源,点光源用小球来表示,使其围绕椅子旋转(椅子不要旋转),呈现在不同位置照射椅子的效果。

              参考代码: spmulight

                • 实验设计思路

                1. 创建一个OpenGL工程,对实验二中绘制的椅子进行材质与灯光的添加,主要参考代码为spmulight, 此时是灯光光源位置不变,椅子在空间中旋转,会使得椅子具有彩色光影。

                2. 与1相比是将光源使其围绕椅子旋转,使用上述代码进行修改,对display函数进行光源的移动与旋转,使光源围绕椅子得到照射椅子后的不同效果。

                  • 实验代码

                  1.

                  #include <GL/glut.h>
                  #include <stdlib.h>
                  float size = 0.25; //缩放
                  void myinit(void);
                  void myReshape(int width, int height);
                  void display(void);
                  static GLfloat spin = 0.0;
                  // 初始化材质特性、 光源、 光照模型和深度缓冲区
                  void myinit(void)
                  {
                    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
                    glShadeModel(GL_SMOOTH);
                    glEnable(GL_DEPTH_TEST);
                    GLfloat mat_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
                    GLfloat mat_diffuse[] = { 0.8, 0.8, 0.8, 1.0 };
                    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
                    GLfloat mat_shininess[] = { 50.0 };
                    GLfloat light0_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
                    GLfloat light0_position[] = { 1.0, 1.0, 1.0, 0.0 };
                    GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
                    GLfloat light1_diffuse[] = { 1.0, 0.0, 0.0, 1.0 };
                    GLfloat light1_specular[] = { 1.0, 0.6, 0.6, 1.0 };
                    GLfloat light1_position[] = { -3.0, -3.0, 3.0, 1.0 };
                    GLfloat spot_direction[] = { 3.0, 3.0, -3.0 };
                    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, mat_shininess);
                    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
                    glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
                    glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
                    glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
                    glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
                    glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
                    glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 30.0);
                    glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction);
                    glEnable(GL_LIGHTING);
                    glEnable(GL_LIGHT0);
                    glEnable(GL_LIGHT1);
                    glDepthFunc(GL_LESS);
                    glEnable(GL_DEPTH_TEST);
                  }
                  void Draw_Leg() // This function draws one of the table leg
                  {
                    //绘制一个桌子腿
                    glPushMatrix();
                    glScalef(1.0f, 1.0f, 3.0f);
                    glutSolidCube(1.0 * size);
                    glPopMatrix();
                  }
                  void Draw_Table() // This function draws a Table
                  {
                    glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。
                    glScalef(5.0f, 4.0f, 1.0f); //缩放函数
                    glColor3f(1.0, 0.0, 1.0);
                    glutSolidCube(1 * size);  //绘制线立方体
                    glPopMatrix(); //pop出来
                    glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。
                    glScalef(4.0f, 1.0f, 4.0f); //缩放函数
                    glTranslatef(0.0 * size, 1.5 * size, 0.5 * size);
                    glColor3f(0.0, 0.0, 1.0);
                    glutSolidCube(1 * size);  //绘制线立方体
                    glPopMatrix(); //pop出来
                    glPushMatrix();         //左下角的柱子
                    glTranslatef(-1.5 * size, -1 * size, -1.5 * size); //尺寸是相对于中心的坐标原点,按照实验指导上的大小进行的
                    Draw_Leg();
                    glPopMatrix();
                    glPushMatrix();         //右下角的柱子
                    glTranslatef(1.5 * size, -1 * size, -1.5 * size);
                    Draw_Leg();
                    glPopMatrix();
                    glPushMatrix();         //右上角的柱子
                    glTranslatef(1.5 * size, 1 * size, -1.5 * size);
                    Draw_Leg();
                    glPopMatrix();
                    glPushMatrix();         //左上角的柱子
                    glTranslatef(-1.5 * size, 1 * size, -1.5 * size);
                    Draw_Leg();
                    glPopMatrix();
                  }
                  void display(void)
                  {
                    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                    glPushMatrix();
                    glTranslated(-3.0f, -1.0f, -9.0f);
                    glScalef(0.3, 0.3, 0.3);
                    glDisable(GL_LIGHTING);
                    glColor3f(0.8, 0.8, 0.8);
                    glutSolidSphere(0.5f, 50.0f, 50.0f);
                    glEnable(GL_LIGHTING);
                    glPopMatrix();
                    glPushMatrix();
                    glLoadIdentity();
                    glTranslatef(1.0f, 0.0f, -6.0f);
                    glRotatef(spin, 0.0, 5.0, 0.0);
                    glColor3f(0.0f, 1.0f, 1.0f);
                    Draw_Table();
                    glPopMatrix();
                    glEnd();
                    glutSwapBuffers(); //交换双缓存
                    glFlush();
                  }
                  void myReshape(int width, int height)
                  {
                    glViewport(0, 0, width, height);
                    glMatrixMode(GL_PROJECTION);
                    glLoadIdentity();
                    gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
                    glMatrixMode(GL_MODELVIEW);
                    glLoadIdentity();
                  }
                  void keyboard(unsigned char key, int x, int y)
                  {
                    switch (key) {
                    case' x':
                      exit(0);
                      break;
                    default:
                      break;
                    }
                  }
                  void spinDisplay(void)
                  {
                    spin = spin + 0.05;
                    if (spin > 360.0)
                      spin = spin - 360.0;
                    glutPostRedisplay();
                  }
                  void mouse(int button, int state, int x, int y)
                  {
                    switch (button) {
                    case GLUT_LEFT_BUTTON:
                      if (state == GLUT_DOWN)
                        glutIdleFunc(spinDisplay); //设备空闲时调用的函数
                      break;
                    case GLUT_MIDDLE_BUTTON:
                    case GLUT_RIGHT_BUTTON:
                      if (state == GLUT_DOWN)
                        glutIdleFunc(NULL);
                      break;
                    default:
                      break;
                    }
                  }
                  // 主函数, 初始化窗口大小、 RGBA 显示模式和处理输入事件
                  int main(int argc, char* argv[])
                  {
                    glutInit(&argc, argv);
                    //glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB) ;
                    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); //使用双缓存模式
                    glutInitWindowSize(640, 480);
                    glutInitWindowPosition(0, 0);
                    glutCreateWindow("位置光源和多光源演示");
                    glutReshapeFunc(myReshape);
                    glutDisplayFunc(display);
                    myinit();
                    glutMouseFunc(mouse);
                    glutKeyboardFunc(keyboard);
                    glutMainLoop();
                    return 0;
                  }

                  image.gif

                  2.

                  #include <GL/glut.h>
                  #include <stdlib.h>
                  float size = 0.25; //缩放
                  void myinit(void);
                  void myReshape(int width, int height);
                  void display(void);
                  static GLfloat spin = 0.0;
                  static GLfloat i = 0.0;
                  // 初始化材质特性、 光源、 光照模型和深度缓冲区
                  void myinit(void)
                  {
                    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
                    glShadeModel(GL_SMOOTH);
                    glEnable(GL_DEPTH_TEST);
                    GLfloat mat_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
                    GLfloat mat_diffuse[] = { 0.8, 0.8, 0.8, 1.0 };
                    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
                    GLfloat mat_shininess[] = { 50.0 };
                    GLfloat light0_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
                    GLfloat light0_position[] = { 1.0, 1.0, 1.0, 0.0 };
                    GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
                    GLfloat light1_diffuse[] = { 1.0, 0.0, 0.0, 1.0 };
                    GLfloat light1_specular[] = { 1.0, 0.6, 0.6, 1.0 };
                    GLfloat light1_position[] = { -3.0, -3.0, 3.0, 1.0 };
                    GLfloat spot_direction[] = { -3.0, -1.0, -9.0f };
                    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, mat_shininess);
                    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
                    glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
                    glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
                    glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
                    glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
                    glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
                    glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction);
                    glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 100.0);
                    glEnable(GL_LIGHTING);
                    glEnable(GL_LIGHT0);
                    glEnable(GL_LIGHT1);
                    glDepthFunc(GL_LESS);
                    glEnable(GL_DEPTH_TEST);
                  }
                  void Draw_Leg() // This function draws one of the table leg
                  {
                    //绘制一个桌子腿
                    glPushMatrix();
                    glScalef(1.0f, 1.0f, 3.0f);
                    glutSolidCube(1.0 * size);
                    glPopMatrix();
                  }
                  void Draw_Table() // This function draws a Table
                  {
                    glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。
                    glScalef(5.0f, 4.0f, 1.0f); //缩放函数
                    glColor3f(1.0, 0.0, 1.0);
                    glutSolidCube(1 * size);  //绘制线立方体
                    glPopMatrix(); //pop出来
                    glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。
                    glScalef(4.0f, 1.0f, 4.0f); //缩放函数
                    glTranslatef(0.0 * size, 1.5 * size, 0.5 * size);
                    glColor3f(0.0, 0.0, 1.0);
                    glutSolidCube(1 * size);  //绘制线立方体
                    glPopMatrix(); //pop出来
                    glPushMatrix();         //左下角的柱子
                    glTranslatef(-1.5 * size, -1 * size, -1.5 * size); //尺寸是相对于中心的坐标原点,按照实验指导上的大小进行的
                    Draw_Leg();
                    glPopMatrix();
                    glPushMatrix();         //右下角的柱子
                    glTranslatef(1.5 * size, -1 * size, -1.5 * size);
                    Draw_Leg();
                    glPopMatrix();
                    glPushMatrix();         //右上角的柱子
                    glTranslatef(1.5 * size, 1 * size, -1.5 * size);
                    Draw_Leg();
                    glPopMatrix();
                    glPushMatrix();         //左上角的柱子
                    glTranslatef(-1.5 * size, 1 * size, -1.5 * size);
                    Draw_Leg();
                    glPopMatrix();
                  }
                  void display(void) {
                    GLfloat position[] = { 1.0, 1.0, 1.0, 1.0 };
                    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                    glPushMatrix();
                    glTranslatef(1.0f, 0.0f, -6.0f);
                    glRotated(-90, 1, 0, 0);
                    glRotated(-30, 1, 0 , 0);
                    glColor3f(0.0f, 1.0f, 1.0f);
                    Draw_Table();
                    glPopMatrix();
                    glPushMatrix();
                    glLoadIdentity();
                    glRotatef(spin, 0.0, 0.0, 5.0);
                    glLightfv(GL_LIGHT0, GL_POSITION, position);
                    glTranslated(-3.0f, -1.0f, -9.0f);
                    glScalef(0.4, 0.4, 0.4);
                    glDisable(GL_LIGHTING);
                    glColor3f(0.8, 0.8, 0.8);
                    glutSolidSphere(0.5f, 50.0f, 50.0f);
                    glEnable(GL_LIGHTING);
                    glPopMatrix();
                    glEnd();
                    glutSwapBuffers(); //交换双缓存
                    glFlush();
                  }
                  void myReshape(int width, int height) {
                    glViewport(0, 0, width, height);
                    glMatrixMode(GL_PROJECTION);
                    glLoadIdentity();
                    gluPerspective(45.0f,(GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
                    glMatrixMode(GL_MODELVIEW);
                    glLoadIdentity();
                  }
                  void keyboard(unsigned char key,int x,int y){
                    switch (key) {
                    case'x':
                      exit(0);
                      break;
                    default:
                      break;
                    }
                  }
                  void spinDisplay(void) {
                    spin = spin + 0.1;
                    if (spin > 360.0)
                      spin = spin - 360.0;
                    glutPostRedisplay();
                  }
                  void mouse(int button, int state, int x,int y){
                    switch (button) {
                    case GLUT_LEFT_BUTTON:
                      if (state == GLUT_DOWN)
                        glutIdleFunc(spinDisplay); //设备空闲时调用的函数
                      break;
                    case GLUT_MIDDLE_BUTTON:
                    case GLUT_RIGHT_BUTTON :
                      if (state == GLUT_DOWN)
                        glutIdleFunc(NULL);
                      break;
                    default:
                      break;
                    }
                  }
                  //主函数, 初始化窗口大小、RGBA 显示模式和处理输入事件
                  int main(int argc, char* argv[]) {
                    glutInit(&argc,argv);
                    //glutIni tDi splayMode (GLUT. SINGLE| GLUT_ RGB);
                    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); //使用双缓存模式
                    glutInitWindowSize(640,480);
                    glutInitWindowPosition(0, 0);
                    glutCreateWindow("光源围绕椅子");
                    glutReshapeFunc(myReshape);
                    glutDisplayFunc(display);
                    myinit();
                    glutMouseFunc(mouse);
                    glutKeyboardFunc(keyboard);
                    glutMainLoop();
                    return 0;
                  }

                  image.gif

                    • 实验结果及心得体会

                    1.

                    image.gif编辑image.gif编辑

                    2.

                    image.gif编辑image.gif编辑

                    此次实验,对三维立体图形进行灯光与材质的附加,使得物体更加具有观感,其中,最重要的是对灯光的模拟,例如环境光、镜面光等,对函数进行赋予参数,得到灯光的渲染。通过本次实验,学习了图形学中的灯光和材质的附加过程,收获颇多,对今后本课程的学习有了较大的帮助。

                    相关文章
                    WRF模式案例运行初体验--飓风示例全过程记录
                    本文主要记录一下首次学习WRF并运行官网案例的全过程。
                    WRF模式案例运行初体验--飓风示例全过程记录
                    |
                    BI C语言 索引
                    Python科学计算库Numpy数值运算基础详解(超详细 附源码)
                    Python科学计算库Numpy数值运算基础详解(超详细 附源码)
                    868 0
                    |
                    Linux iOS开发 索引
                    【已解决】ModuleNotFoundError: No module named ‘matplotlib‘
                    【已解决】ModuleNotFoundError: No module named ‘matplotlib‘
                    |
                    10月前
                    |
                    IDE 编译器 开发工具
                    【2026最新】Dev C++下载安装使用全流程教程(附最新版安装包+图文步骤)
                    Dev C++ 是一款轻量免费的 Windows C/C++ 集成开发环境,内置 MinGW 编译器,支持 C++11 等标准。安装简便、启动快速,适合新手学习、竞赛与算法训练,是入门 C/C++ 的理想工具。
                    4852 9
                    |
                    4月前
                    |
                    IDE JavaScript 前端开发
                    【全网最详细】VS2022下载、安装、使用一篇搞定(附社区版安装包)
                    Visual Studio 2022(VS2022)是微软推出的首个原生64位IDE,突破4GB内存限制,性能更强。支持C/C++、C#、Python、JavaScript等多语言,提供免费社区版(功能完整)、专业版和企业版。推荐初学者与个人开发者使用社区版,安装灵活、学习成本低,是高效开发的理想选择。(239字)
                    |
                    自然语言处理 JavaScript 数据管理
                    HarmonyOS Next 实战卡片开发 01
                    本文详细介绍了 HarmonyOS Next 中的卡片开发,涵盖基本概念、类型、创建、配置、能力支持、生命周期及通信等内容。Form Kit 提供将应用重要信息前置到服务卡片的功能,减少跳转层级,适用于嵌入系统应用(如桌面),支持拉起页面与发送消息等交互。卡片分为静态与动态两种类型,分别适用于不同刷新需求场景。
                    733 0
                    HarmonyOS Next 实战卡片开发 01
                    |
                    机器学习/深度学习 人工智能 vr&ar
                    光流法相关论文-LK光流法,HS光流法,Farneback光流法,FlowNet: 端到端的深度光流估计, RAFT: 结构化的光流估计
                    光流法相关论文-LK光流法,HS光流法,Farneback光流法,FlowNet: 端到端的深度光流估计, RAFT: 结构化的光流估计
                    1848 0
                    |
                    数据采集 前端开发 开发者
                    Selenium中如何实现翻页功能
                    在使用Python的Selenium库进行网页爬虫开发时,翻页操作是常见需求。本文详细介绍如何通过Selenium实现翻页,包括定位翻页控件、执行翻页动作以及等待页面加载等关键步骤,并提供了基于“下一页”按钮和输入页码两种方式的具体示例代码。此外,还特别提醒开发者注意页面加载完全、动态内容加载及反爬机制等问题,确保爬虫稳定高效运行。
                    2057 3
                    |
                    存储 安全 网络协议
                    邮件协议揭秘:SMTP与IMAP的双重功能解析
                    SMTP和IMAP是电子邮件系统的核心协议,SMTP负责邮件发送,通过SSL/TLS保证安全,而IMAP则处理邮件接收和管理,支持服务器存储及状态同步。这两种协议相辅相成,为现代邮件系统提供了坚实基础。它们广泛应用于各种邮件客户端,确保了兼容性、功能丰富性和安全性,满足用户对电子邮件的多样化需求。
                    1406 3
                    |
                    SQL Oracle 关系型数据库
                    Oracle数据库基础教程:从安装到基本操作的全面介绍
                    Oracle数据库基础教程:从安装到基本操作的全面介绍