510 likes | 751 Views
基于 OpenGL 的三维光照简介. 上节课主要内容. 三维绘制流程 三维绘制中的变换 照相机系统和相机模型. Quake II (Id Software). 主要授课内容. 一般的 OpenGL 介绍 绘制元素:点、线、三角形 绘制模式 光照 纹理映射 绘制属性设置. 应该掌握的内容. 应该能写一个基本的交互图形绘制程序,包括: 三维物体绘制流程 光照 纹理映射 能为以后的高级课题打下基础. 光照的基本原理. • 光照参数 光源 物体表面材质 空气衰减 相机成像. 光照模拟. OpenGL?. 图形绘制 API
E N D
上节课主要内容 • 三维绘制流程 • 三维绘制中的变换 • 照相机系统和相机模型
Quake II (Id Software) 主要授课内容 • 一般的OpenGL介绍 • 绘制元素:点、线、三角形 • 绘制模式 • 光照 • 纹理映射 • 绘制属性设置
应该掌握的内容 • 应该能写一个基本的交互图形绘制程序,包括: • 三维物体绘制流程 • 光照 • 纹理映射 • 能为以后的高级课题打下基础
光照的基本原理 • 光照参数 • 光源 • 物体表面材质 • 空气衰减 • 相机成像
OpenGL? • 图形绘制API • 高质量的、专业级的绘制引擎 • 跨平台 • 跨操作系统 • 1990年由SGI公司推出
顶点操作 求值器 显示列表 逐个象素操作 帧缓冲 CPU 光栅化 纹理 后象素处理 OpenGL 架构
OpenGL 的绘制功能 • 支持的几何元素 • 点、线、多边形 • 图像元素 • 图像与位图 • 对于几何和图像有不同的渲染管道 • 通过纹理映射连接起来 • 绘制状态机 • 颜色, 材质, 光源等.
编程起步 • 头文件 • #include <GL/gl.h> • #include <GL/glu.h> • #include <GL/glut.h> • 库文件:opengl.lib, glaux.lib, glu32.lib • 支持类型(系统之间兼容) • GLfloat, GLint, GLenum, etc.
GLUT • 一个教学、培训用的跨平台的API • 主要功能 • 配置与开窗口 • 初始化 OpenGL 状态 • 重要的Callback 函数 • Render:绘制 • Resize:窗口大小变化的时候重新设置视区等 • input: 键盘、鼠标等. • 输入事件处理循环
Glut例程 void main( int argc, char** argv ) { //RGB模式、双缓冲区 int mode = GLUT_RGB|GLUT_DOUBLE; //初始化图形模式 glutInitDisplayMode( mode ); //创建窗口 glutCreateWindow( argv[0] ); init(); //绘制回调函数 glutDisplayFunc( display ); // Resize回调函数 glutReshapeFunc( resize ); //鼠标输入回调函数 glutKeyboardFunc( key ); //Idle函数 glutIdleFunc( idle ); //事件处理循环 glutMainLoop(); }
OpenGL 初始化 设置OpenGL状态 void init( void ) { //屏幕清为黑色 glClearColor( 0.0, 0.0, 0.0, 1.0 ); //深度清为最远处(0.0-1.0) glClearDepth( 1.0 ); //打开光源0 glEnable( GL_LIGHT0 ); //打开光照 glEnable( GL_LIGHTING ); //深度测试 glEnable( GL_DEPTH_TEST ); }
GLUT 回调函数 • 当某个事件发生时,所调用的函数 • 窗口的尺寸变换、重绘函数 • 用户输入 • 动画 • “注册” 回调函数 glutDisplayFunc( display ); glutIdleFunc( idle ); glutKeyboardFunc( keyboard );
绘制回调函数 void display( void ) { //对颜色缓冲区清零 glClear( GL_COLOR_BUFFER_BIT ); //绘制三角形带 glBegin( GL_TRIANGLE_STRIP ); glVertex3fv( v[0] ); glVertex3fv( v[1] ); glVertex3fv( v[2] ); glVertex3fv( v[3] ); glEnd(); //交换缓冲区 glutSwapBuffers(); }
Idle 回调函数 可用于动画制作,连续更新画面 glutIdleFunc( idle ); void idle( void ) { //时间变化 t += dt; glutPostRedisplay(); }
用户输入回调函数 • 处理键盘输入 glutKeyboardFunc( keyboard ); void keyboard( unsigned char key, int x, int y ) { switch( key ) { case ‘q’ : case ‘Q’ : exit( EXIT_SUCCESS ); break; case ‘r’ : case ‘R’ : rotate = GL_TRUE; glutPostRedisplay(); break; } }
基本绘制流程 • 几何基本元素 • OpenGL状态管理 • OpenGL 缓冲器管理
GL_LINES GL_POLYGON GL_LINE_STRIP GL_LINE_LOOP GL_POINTS GL_TRIANGLES GL_QUADS GL_TRIANGLE_FAN GL_TRIANGLE_STRIP GL_QUAD_STRIP OpenGL 几何元素 • 所有的几何元素由顶点给出
简单的绘制例子 void drawRhombus( GLfloat color[] ) { glBegin( GL_QUADS ); glColor3fv( color ); glVertex2f( 0.0, 0.0 ); glVertex2f( 1.0, 0.0 ); glVertex2f( 1.5, 1.118 ); glVertex2f( 0.5, 1.118 ); glEnd(); }
OpenGL 命令格式 glVertex3fv( v ) 数据类型 向量 元素数目 b - byte ub - unsigned byte s - short us - unsigned short i - int ui - unsigned int f - float d - double omit “v” for scalar form glVertex2f( x, y ) 2 - (x,y) 3 - (x,y,z) 4 - (x,y,z,w)
指定几何元素 • 绘制基本元素的指定方式 glBegin( primType ); glEnd(); • primType决定顶点的组织方式 • GLfloat red, green, blue; • Glfloat coords[3]; • glBegin( primType ); • for ( i = 0; i < nVerts; ++i ) { • glColor3f( red, green, blue ); • glVertex3fv( coords ); • } • glEnd();
OpenGL状态机 • 所有绘制数学都封装在OpenGL状态中 • 绘制风格 • 绘制方程 • 光照 • 纹理映射
OpenGL 状态处理 • 绘制结果由当前状态设定 for each ( primitive to render ) { update OpenGL state render primitive } • 逐个顶点设置状态的方式 glColor*() / glIndex*() glNormal*() glTexCoord*()
状态控制的一般方式 • 设置状态 glPointSize( size ); //点的尺寸 glLineStipple( repeat, pattern );//线绘风格 glShadeModel( GL_SMOOTH );//渲染模型 • 打开或关闭某个属性 glEnable( GL_LIGHTING );//打开光照 glDisable( GL_TEXTURE_2D );//关闭二维纹理
OpenGL中的变换 • 建模 • 相机变换 • 相机定位 • 投影 • 相机运动 • 投影到屏幕
OpenGL例子(Look At相机) Void DisplayScene () { glClear (GL_COLOR_BUFFER_BIT); glColor3f (1.0f, 0.0f, 0.0f); glLoadIdentity (); gluLookAt (0.0, 0.0, 10.0, 0.0, 0.0, -100.0, 0.0, 1.0, 0.0); glBegin (GL_TRIANGLE); glVertex3f (10.0f, 0.0f, 0.0f); glVertex3f (0.0f, 10.0f, 0.0f); glVertex3f (-10.0f, 0.0f, 0.0f); glEnd(); glFlush (); }
设置相机的另一种方法: 变换场景 • gluLookAt函数显式地定义相机。另外一种方法式将场景进行旋转(glRotate)和平移(glTranslate)同时,将相机置于缺省的世界坐标系统. • 旋转和平移的累积效果构成了最终的相机变换. • 当然, glTranslate和 glRotate也可用作其他用途
OpenGL例子(变换场景) //viewing a scene centered at origin from +X direction: Void DisplayScene () glClear (GL_COLOR_BUFFER_BIT); glColor3f (1.0f, 0.0f, 0.0f); glLoadIdentity (); glTranslatef (0.0, 0.0, -10.0); glRotatef (-90.0, 0.0, 1.0, 0.0); // glBegin (GL_TRIANGLE); glVertex3f (10.0f, 0.0f, 0.0f); glVertex3f (0.0f, 10.0f, 0.0f); glVertex3f (-10.0f, 0.0f, 0.0f); glEnd(); glFlush (); }
ModelView 矩阵 • ModelView变换式建模矩阵M和相机变换V的乘积 C = VM • 所有在OpenGL中的变换函数只能设置modelview 矩阵. 因此, ModelView 在物体被操作之前被调用. • 例如: glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glScalef (2.0f, 2.0f, 2.0f); DrawScene ();
ModelView 矩阵堆栈 • 矩阵堆栈的顶部矩阵就是当前的ModelView 矩阵 (C). • glPushMatrix ():将当前的矩阵加入到矩阵堆栈 • glPopMatrix ():将顶部矩阵删除,并将所有其他矩阵往上移动一位。 • 矩阵堆栈的好处:允许一系列位置(代表了坐标系统)保留下来,并在需要的时候使用它们。 M1 M2 M3
矩阵阵列 • 建模变换: • glLoadIdentity : C I • glLoadMatrix(m) : C m • glMultiMatrix(m) : C C m • glRotatef(q,x,y,z) : C C RL(q) • glTranslatef(x,y,z) : C C T(x,y,z) • glScalef(x,y,z) : C C S(x,y,z) • 最后定义的变换最先被执行.
投影变换 • 投影变换设置视域体,从而定义裁剪面和投影矩阵以及投影方式。 • 投影矩阵在ModelView矩阵之后被实行,因此,视域体是定义 在相机坐标系统中的。 • 透视投影与平行投影
平行(正交)投影 • 定义正交视域体: glOrtho (left, right, bottom, top, near, far); 或者:glOrtho2D (left, right, bottom, top); • 定义投影矩阵: glMatrixMode (GL_PROJECTION); glLoadIdentity ( ); glOrtho (left, right, bottom, top, near, far) 视域体 • (Left, righ, bottom, top) 定义视域体的最小、最大的 X 和Y坐标; (near, far) 定义视域体的近和远平面到X-Y平面的距离. Y 成像平面 X VCS Z
透视投影 • 视域四堎锥的定义: glFrustum (left, right, bottom, top, near, far) • 视域体的形成是:将原点与前面的四个顶点连接起来,并由Z方向的近平面和远平面限制。 • 投影矩阵 glMatrixMode (GL_PROJECTION); glLoadIdentity (); glFrustum(left, right, bottom, top, near, far) 视域四堎锥 Y 成像平面 X 原点 Z
透视投影(II) • 视域体的定义 glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective (angle, aspect, near, far) angle: y方向张的视角 aspect:方正率 (成像平面的宽度/高度). Y X Z
视区 • 视区是窗口的绘制区域,特殊的视区是全屏幕 • 缺省视区是窗口本身 • 视区矩阵将投影后的成像平面投到视区 glViewport (GLint left, GLint bottom, GLint width, GLint height) • (left, bottom, width, height) 定义在窗口系统中(象素级) 窗口 (right, top) 视区 (left, bottom)
用户定义矩阵 • 可随意装入矩阵: GLfloat m[16] = {1.0, 0.0, 0.0, ……}; glLoadMatrixf (m); • 矩阵乘法: glMultMatrixf (m);
深度缓冲与动画生成 • 双缓冲区机制与动画 • 用深度缓冲进行消隐
Per Vertex Poly. Frag FB Raster CPU DL Texture Pixel 1 1 2 2 4 4 Front Buffer Back Buffer 8 8 16 16 Display 双缓冲机制
利用双缓冲进行动画设置 • 需要初始化一个颜色双缓冲glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE ); • 清除颜色缓冲区 glClear( GL_COLOR_BUFFER_BIT ); • 绘制场景 • 将前缓冲器与后缓冲器交换 glutSwapBuffers(); • 重复 2 – 4步,获得动画效果
1 1 2 2 4 4 Color Buffer Depth Buffer 8 8 16 16 Display 深度缓冲器与消隐
OpenGL中的深度缓冲 • 深度缓冲器设置 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ); • 打开深度测试 glEnable( GL_DEPTH_TEST ); • 对颜色和深度缓冲器清零 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); • 绘制场景 • 交换颜色缓冲器
动画示例 void main( int argc, char** argv ) { glutInit( &argc, argv ); glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ); glutCreateWindow( “Tetrahedron” ); init(); glutIdleFunc( idle ); glutDisplayFunc( display ); glutMainLoop(); }
动画示例(续) • void init( void ){ glClearColor( 0.0, 0.0, 1.0, 1.0 );}void idle( void ){ glutPostRedisplay();}
动画示例(续) • void drawScene( void ) • { GLfloat vertices[] = { … }; GLfloat colors[] = { … }; glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glBegin( GL_TRIANGLE_STRIP ); /* calls to glColor*() and glVertex*() */ glEnd(); glutSwapBuffers(); • }