380 likes | 545 Views
光线跟踪算法. 主要内容: 一、实验设计 二、静止多光源实现 三、材料属性对光照效果的影响 四、移动光源的实现. 实验设计. 问题一、影响光照效果的因素? 问题二、 OPENGL 光线跟踪函数的函数? 问题三、光线跟踪实现的基本步骤?. 一、 OPENGL 中影响光照效果的因素?. 1 、光源 光的种类: 环境光: light_ambient 散射光: light_diffuse 镜面光: light_specular 光源的分类: 方向性光源:无限远,所有光线是平行的 位置性光源:位置决定场景中的效果 区别:
E N D
光线跟踪算法 • 主要内容: • 一、实验设计 • 二、静止多光源实现 • 三、材料属性对光照效果的影响 • 四、移动光源的实现
实验设计 • 问题一、影响光照效果的因素? • 问题二、OPENGL光线跟踪函数的函数? • 问题三、光线跟踪实现的基本步骤?
一、OPENGL中影响光照效果的因素? • 1、光源 • 光的种类: • 环境光:light_ambient • 散射光:light_diffuse • 镜面光:light_specular • 光源的分类: • 方向性光源:无限远,所有光线是平行的 • 位置性光源:位置决定场景中的效果 • 区别: • GLfloat light_position[] 中的第四个参数
2、材料属性 • 材料的环境颜色:GL_AMBIENT • 材料的散射颜色:GL_DIFFUSE • 材料的镜面颜色:GL_SPECULAR • 材料的镜面指数:GL_SHININESS • 材料的发射颜色:GL_EMISSION
问题二、OPENGL光线跟踪函数的函数? • 光源: • void glLight{if}(GLenum light, GLenum pname, TYPEparam); • void glLight{if}v(GLenum light, GLenum pname, TYPE *param); • Light:指定光源 pname:光源属性 param:属性值 • 材料属性: • void glMaterial{if}(GLenum face, GLenum pname, TYPEparam); • void glMaterial{if}v(GLenum face, GLenum pname, TYPE *param); • Face:那个面受光照pname:光源属性 param:属性值
问题三、光线跟踪实现的基本步骤? • 一、创建光源 • 二、选择光照模型 • 三、定义材料属性 • 有了这些知识,我们就可以进行第一个简单的多光源实验。
静止多光源实现 • 自己的工作: • 按照光线跟踪实现的步骤进行。 • 设置光源参数,衰减因子,聚光灯参数,材料属性参数,调用glLightfv,glMaterialfv, glEnable等函数进行设置。 • 已有的: • 实现静态光源显示 • void reshape (int w, int h) • void display(void)
创建光源 • 1、设置光源参数 • 方向性光源,环境光颜色为蓝色 • GLfloat light_ambient[] = { 0.0, 0.0, 1.0, 1.0 }; • GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; • GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; • GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; • 位置性光源,环境光和散射光颜色为红色 • GLfloat light1_ambient[] = { 1.0, 0.0, 0.0, 1.0 }; • GLfloat light1_diffuse[] = { 1.0, 0.0, 0.0, 1.0 }; • GLfloat light1_specular[] = { 1.0, 1.0, 1.0, 1.0 }; • GLfloat light1_position[] = { 0.0, 2.0, 2.0, 1.0 };
2、衰减因子 • 定义衰减因子目的:增强真实效果 • glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0); • glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0); • glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5); • glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.5); • glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.5); • glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.2); • 三个参数的默认值为1,0,0
3,聚光灯参数 • 光源LIGHT1 • GLfloat spot_direction[] = { 1.0, -1.0, -1.0 }; • glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction); • glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0); • //默认值180 • glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 5.0); • //用于控制光的集中度,越高强度越集中
4,glLightfv的调用 • 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); • 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);
5,glEnable的调用 • 作用:启用光源 • glEnable(GL_LIGHTING); • glEnable(GL_LIGHT0); • glEnable(GL_LIGHT1);
6,光源保持静止 • void reshape (int w, int h) • { • glViewport (0, 0, (GLsizei) w, (GLsizei) h); • glMatrixMode (GL_PROJECTION); • glLoadIdentity(); • if (w <= h) glOrtho (-1.5, 1.5, 1.5*(GLfloat)h/(GLfloat)w, 1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0); • else glOrtho (-1.5*(GLfloat)w/(GLfloat)h,1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0); • glMatrixMode(GL_MODELVIEW); • glLoadIdentity(); • } • 首先确定视口和投影矩阵,接着在模型视图矩阵中加载单位矩阵,然后再设置光源。由于使用单位阵,乘模型视图矩阵之后原来制定的光源位置并没有发生变化。
选择光照模型 • 静态多光源实现过程中使用默认设置: • 即观察者位于无穷远且只有一面接受光照 • glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); • glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); • glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
定义材料属性 • 材料属性值设置 • GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; • GLfloat mat_shininess[] = { 50.0 }; • glMaterialfv的调用 • glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); • glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
display()函数 • void display(void) • { • glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清空缓冲区 • glutSolidSphere (1.0, 20, 16);//画圆,半径为1.0 • glFlush ();//保证绘图命令被实际执行 • }
效果展示 • 屏蔽位置性光源 • 只有方向性光源
屏蔽方向性光源 • 只有位置性光源
材料属性对光照效果的影响 遇到的问题: 如何将不同的材料属性赋予不同的球体?
如何将不同的材料属性赋予不同的球体? • 猜测可以通过调用glTranslatef()来实现 • 查阅发现: • glPushMatrix(); • glTranslatef (); • glMaterialfv(); • glutSolidSphere(); • glPopMatrix();
创建光源 • //环境光,散射光和镜面光参数 • GLfloat light_ambient[] = { 0.0, 0.0, 1.0, 1.0 }; • GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; • GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; • GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; • //glLightfv的调用 • 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); • //glEnable的调用 • glEnable(GL_DEPTH_TEST); • glEnable(GL_LIGHTING); • glEnable(GL_LIGHT0);
材料属性值设置 • GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 }; • GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 }; • GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 }; • GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; • GLfloat no_shininess[] = { 0.0 }; • GLfloat low_shininess[] = { 5.0 }; • GLfloat high_shininess[] = { 100.0 }; • GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0};
glMaterialfv的调用 第一个球:只有散射颜色和发射颜色 glPushMatrix(); • glTranslatef (-1.0, -0.5, -2.0); • glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); • glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); • glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat); • glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess); • glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission); • glutSolidSphere(1.0, 16, 16);//绘制小球 • glPopMatrix();
第二个球: • 只有散射颜色和镜面颜色,且镜面指数低 • glPushMatrix(); • glTranslatef (0.0, -0.5, -3.0); • glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); • glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); • glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); • glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess); • glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); • glutSolidSphere(1.0, 16, 16); • glPopMatrix();
第三个球: • 只有散射颜色和镜面颜色,且镜面指数为高 • glPushMatrix(); • glTranslatef (1.0, -0.5, -4.0); • glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); • glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); • glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); • glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); • glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); • glutSolidSphere(1.0, 16, 16); • glPopMatrix();
静态光源控制 • void reshape (int w, int h) • { • glViewport (0, 0, (GLsizei) w, (GLsizei) h); • glMatrixMode (GL_PROJECTION); • glLoadIdentity(); • if (w <= h) glOrtho (-1.5, 1.5,- 1.5*(GLfloat)h/(GLfloat)w,1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0); • else glOrtho (-1.5*(GLfloat)w/(GLfloat)h, • 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0); • glMatrixMode(GL_MODELVIEW); • glLoadIdentity(); • }
效果展示 • 第一个小球 • 只有散射颜色和发射颜色 • 第二个小球 • 只有散射颜色和镜面颜色,且镜面指数低 • 第三个小球 • 只有散射颜色和镜面颜色,且镜面指数为高
动态光源实现 • 采用什么方式实现动态光源? • 通过点击鼠标产生鼠标事件,进而移动光源
鼠标事件函数,目的通过点击鼠标控制旋转 • void mouse(int button, int state, int x, int y) • { • switch (button) • { • case GLUT_LEFT_BUTTON: • if (state == GLUT_DOWN) • { • spin = (spin + 30) % 360; • //全局变量spin的控制 • glutPostRedisplay(); • } • break; • default: break; • } • }
void display3(void) //模型和视图变换 • { • GLfloat position[] = { 0.0, 0.0, 1.5, 1.0 }; • glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); • glPushMatrix (); • glTranslatef (0.0, 0.0, -5.0); • glPushMatrix (); • glRotated ((GLdouble) spin, 1.0, 0.0, 0.0); • //全局变量spin初值为0,通过鼠标事件改变它的值,进而进行旋转 • glLightfv (GL_LIGHT0, GL_POSITION, position); • glTranslated (0.0, 0.0, 1.5); • glDisable (GL_LIGHTING); • glColor3f (0.0, 1.0, 1.0); • glutWireCube (0.1); //绘制立方体函数,目的是为了更好的显示效果 • glEnable (GL_LIGHTING); • glPopMatrix (); • glutSolidSphere (1.0, 20, 16);//绘制圆 • glPopMatrix (); • glFlush (); • }
void reshape3 (int w, int h)//投影和视口变换 • { • glViewport (0, 0, (GLsizei) w, (GLsizei) h); • //作用调整绘图像素矩阵,使它占据整个窗口 • glMatrixMode (GL_PROJECTION); • //表示吧当前矩阵指定用于投影变换,后续的变换调用影响的是投影矩阵 • glLoadIdentity();//对当前矩阵进行初始化 • gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0); • /*void gluPerspective(GLdouble fovy, GLdouble aspect,GLdouble near, GLdouble far); • 创建一个表示对称透视视图凭借头体的矩阵,并把它与当前矩阵相乘 • fovy yz平面上视野的角度,它的值必须在[0.0,180.0]. • aspect是这个平截头体的纵横比,即宽度除高度 • near and far 观察点与近侧剪裁平面及远侧裁剪平面的距离,值为正数*/ • glMatrixMode(GL_MODELVIEW); • //以后变换影响的是模型视图矩阵 • glLoadIdentity();//对当前矩阵进行初始化 • }
效果展示 • 光源在上面时
main()的实现 • int main(int argc, char** argv) • { • //初始化 • glutInit(&argc, argv); • glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); • glutInitWindowSize (500, 500);//窗口大小 • glutInitWindowPosition (100, 100);//窗口位置 • glutCreateWindow (argv[0]);//创建窗口 • init (); • glutDisplayFunc(display); • glutReshapeFunc(reshape); • glutInit(&argc, argv); • glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); • glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100); • glutCreateWindow (argv[0]); • init2 (); • glutDisplayFunc(display2); • glutReshapeFunc(reshape); • glutInit(&argc, argv); • glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); • glutInitWindowSize (500, 500); • glutInitWindowPosition (100, 100); • glutCreateWindow (argv[0]); • init3 (); • glutDisplayFunc(display3); • glutReshapeFunc(reshape3); • glutMouseFunc(mouse); • glutMainLoop(); • return 0; • }
体会: • OpenGL提供了一个很好图形应用程序接口,通过调用其中的函数库,我们可以达到事半功倍的效果! • 只有通过实习才能够更深刻的了解到每个函数的具体作用,才能够更好的运用。 • 图形学实验做好了可以给你以美感,是一种享受。