660 likes | 1.17k Views
OpenGL 高级课题与纹理映射技术. 耿卫东 陈为. 本次课程的主要内容. OpenGL 高级课题 显示列表和顶点数组 Alpha 混合和反走样 雾化 反馈和选择 象素测试与操作 累积和模板缓冲器 纹理映射 OGRE 中的纹理映射. 顶点操作. 求值器. 显示列表. 逐个象素操作. 帧缓冲. CPU. 光栅化. 纹理. 后象素处理. OpenGL 架构. 顶点变换与光照计算. 像素级光照计算. OpenGL 其他高级课题. 纹理映射. 帧缓冲区操作. 裁剪 测试. Alpha 测试. 模板 测试. 象素. 深度
E N D
OpenGL高级课题与纹理映射技术 耿卫东 陈为
本次课程的主要内容 • OpenGL高级课题 • 显示列表和顶点数组 • Alpha混合和反走样 • 雾化 • 反馈和选择 • 象素测试与操作 • 累积和模板缓冲器 • 纹理映射 • OGRE中的纹理映射
顶点操作 求值器 显示列表 逐个象素操作 帧缓冲 CPU 光栅化 纹理 后象素处理 OpenGL 架构 顶点变换与光照计算 像素级光照计算 OpenGL其他高级课题 纹理映射 帧缓冲区操作
裁剪 测试 Alpha 测试 模板 测试 象素 深度 测试 混合 抖动 逻辑 操作 帧缓冲区 关于帧缓冲区(frame buffer)
Alpha: 第四维颜色分量 • 透明度的度量 • 模拟透明物体 • 玻璃、水等 • 合成图像 • 反走样 • 混合状态下有效 glEnable( GL_BLEND );
Alpha测试 • 基于alpha值选择象素 • glAlphaFunc( func, value ) • glEnable( GL_ALPHA_TEST ); • 在纹理映射时用alpha值作为蒙板
混合 方程 混合后 的象素 象素 (src) 帧缓冲器 象素 (dst) 混合 • 结合输出与帧缓冲器中原有的象素值glBlendFunc( src, dst )
裁剪包围盒 • 其他的裁剪测试 • glScissor( x, y, w, h ) • 包围盒外的象素被裁剪掉 • 便于更新视域的一小块区域 • 影响glClear()操作
模板缓冲区(stencil buffer) • 用模板缓冲区的值控制绘制 • 无法通过模板测试的象素将不被绘制 • 例子:在模板缓冲区中创建一个蒙板,并仅绘制那些不在蒙板区域内的物体
控制模板缓冲区 • glStencilFunc( func, ref, mask ) • 用func比较缓冲区的值与 ref • 只对那些mask值为1的象素进行操作 • func是一个标准比较函数 • glStencilOp( fail(模板失败), zfail(模板通过,z失败), zpass(两者都通过) ) • 基于模板测试和深度测试的结果相应调整模板缓冲区的值: GL_KEEP, GL_INCR
创建模板 • glInitDisplayMode( …|GLUT_STENCIL|… ); • glEnable( GL_STENCIL_TEST ); • glClearStencil( 0x0 ); • glStencilFunc( GL_ALWAYS, 0x1, 0x1 ); • glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE ); • 绘制蒙板
使用模板 • 当stencil = 1绘制物体 • glStencilFunc( GL_EQUAL, 0x1, 0x1 ) • 当stencil != 1绘制 • glStencilFunc( GL_NOTEQUAL, 0x1, 0x1 ); • glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
抖动 • glEnable( GL_DITHER ); • 抖动用于加强视觉效果 • 用于模拟更多颜色 • 打印设置 • 目前,该功能很少被用到
象素上的逻辑操作 • 使用位逻辑操作结合多个象素值 • glLogicOp( mode ); • 命令模式 • GL_XOR • GL_AND • 目前,该功能很少被用到
累积缓冲器 • 颜色缓冲器合成的问题 • 有限颜色分辨率 • 截断 • 精度损失 • 累积缓冲区扮演着“浮点”颜色缓冲区的角色 • 合成到积累缓冲区 • 将结果转换到帧缓冲区
累积缓冲区存取 • glAccum( op, value ) • 操作 • 在积累缓冲区中的操作: GL_ADD, GL_MULT • 读缓冲区操作: GL_ACCUM, GL_LOAD • 写缓冲区操作: GL_RETURN • glAccum(GL_ACCUM, 0.5)将写缓冲区的每一个值乘以0.5,然后加到累积缓冲区中
累积缓冲区的应用 • 颜色合成:透明 • 全屏反走样:A-buffer算法 • 景深:Depth Cue • 滤波: • 运动模糊: Motion blur
反走样(Anti-aliasing) • 消除锯齿状 glEnable( mode ) • GL_POINT_SMOOTH • GL_LINE_SMOOTH • GL_POLYGON_SMOOTH • 象素的Alpha值由象素被覆盖 大小决定 • 可以是RGBA或颜色索引模式
全屏反走样: 视点抖动 • 当我们略微移动视点时,图像随之平移 • 每一幅图像有不同的走样情况 • 用积累缓冲区对图像作平均,将消除这些走样
景深 • 沿平行焦平面的方向移动视点 后平面 焦平面 前平面 眼睛位置1 眼睛位置2
雾化 • glFog{if}( property, value ) • 景深效果处理 • 指定线性雾化渐变区域大小 • GL_FOG_LINEAR • 环境效果 • 模拟真实雾化效果 • GL_FOG_EXP • GL_FOG_EXP2
高级成像 • 成像子集 • 只有当GL_ARB_imaging有定义时才有效 • 颜色矩阵 • 卷积 • 颜色表 • 直方图 • MinMax • 高级混合
立即模式、显示列表和保留模式 • 立即模式(immediate mode) • 图元直接发送到绘制流水线并显示 • 不需要显卡内存 • 显示列表(display list) • 图元保存在显示列表中、显示列表保存在显卡中 • 保留模式(retained mode) • 所有数据预先置入显存
立即模式与显示列表 立即模式 顶点操作 和 图元组装 多项式 求值器 显示 列表 象素 操作 帧 缓冲 CPU 光栅化 列出显示 纹理 内存 象素 操作
显示列表 • 创建显示列表 GLuint id; void init( void ) { id = glGenLists( 1 ); glNewList( id, GL_COMPILE ); /* other OpenGL routines */ glEndList(); } • 调用显示列表 void display( void ) { glCallList( id ); }
显示列表 • 不是所有的OpenGL程序都能存储在显示列表当中 • 显示列表创建后,状态仍然能够被改变 • 显示列表可以嵌套调用 • 显示列表一旦创建,不能进行编辑 • 令列表(A) 调用其他列表(B, C, 或D) • 删除A并按照要求调用B, C或D
显示列表层次 • 考虑一个汽车模型 • 创建底盘显示列表 • 创建轮胎显示列表 glNewList( CAR, GL_COMPILE ); glCallList( CHASSIS ); glTranslatef( … ); glCallList( WHEEL ); glTranslatef( … ); glCallList( WHEEL ); … glEndList();
Color data Vertex data 保留模式 • 将顶点、颜色数组一次性送至显存处理 glVertexPointer( 3, GL_FLOAT, 0, coords ) glColorPointer( 4, GL_FLOAT, 0, colors ) glEnableClientState( GL_VERTEX_ARRAY ) glEnableClientState( GL_COLOR_ARRAY ) glDrawArrays( GL_TRIANGLE_STRIP, 0, numVerts ); • 所有有效数组被用于绘制
保留模式的优点 • 比直接绘制模式效率更高 • 显示列表可以在多个OpenGL操作描述表之间共享,降低内存要求 • 顶点数组便于内存访问的方式组织数据 • D3D和最近的OpenGL支持保留模式
高级图元 • Bernstein 多项式求值器 • GLU NURBS(Non-Uniform Rational B-Splines,非均匀有理B样条)的基础 • GLU二次曲面物体 • 球面 • 圆柱(或圆锥) • 圆盘(或圆)
反馈模式(很少用) • 未绘制的光栅化后的顶点数据返回应用程序 • 确定哪些图元最终被绘制到屏幕上 • 需要指定反馈缓冲区 • glFeedbackBuffer( size, type, buffer ) • 选择绘制反馈模式 • glRenderMode( GL_FEEDBACK );
选择模式(很少用) • 决定哪些图元在视域当中 • 需要一个缓冲区放置返回结果glSelectBuffer( size, buffer ) • 选择绘制的选择模式 • glRenderMode( GL_SELECT )
选择模式(续) • 用名字区别各个图元 • “名字”用整数而非字符串表示 • 名字建立在堆上 • 允许层次化图元 • 名字选择程序 • glLoadName( name ) • glPushName( name ) • glInitNames()
拾取 • 拾取是选择的特殊情况 • 编程步骤 • 限制鼠标周围的一小块区域为当前绘制区域 在投影矩阵上使用gluPickMatrix() • 进入选择模式; 重绘屏幕 • 被视见体裁剪的每个图元引起一个选择命中 • 退出选择模式; 分析命中记录
纹理映射(texture mapping) • 纹理映射的基本原理 • 凹凸纹理映射(bump mapping) • 位移映射(displacement mapping) • 环境纹理映射(environment mapping) • 基于光照映射的快速绘制(light mapping) • 高级纹理映射技术总结
纹理映射 • 将一个一维、二维、三维的图像映射到几何物体上的过程 • 纹理映射的用途 • 仿真自然界的材质 • 减少几何复杂度 • 图像warping • 反射效果模拟 • 。。。
y z x t s Texture Mapping 屏幕 几何 图像:即纹理
图像和几何在不同的管道中处理,最后在光栅处理器中融合。图像和几何在不同的管道中处理,最后在光栅处理器中融合。 复杂的纹理不影响几何的复杂性。 几何管道 顶点 光栅处理器 象素管道 图像 纹理映射与 图形绘制流程
纹理 • 256 x 256的图像映射到 一个长方形,并进行透视投影。
纹理映射 I • 三步 • 设置纹理 • 读入或者生成图像 • 将图像赋到某个纹理上 • 打开纹理映射功能 • 将纹理坐标赋到顶点上 • 设置纹理参数 • Wrapping(重复pattern的方式), filtering(纹理采样的滤波方式):
纹理对象 • 类似于纹理图像序列的显示列表(可加快速度) • 每个纹理对象对应一个图像 • 可以由多个图形上下文共享 • 生成纹理名字 glGenTextures(n,*texIds ); • 绑定纹理图像(id为纹理对象名字) glBindTexture( target, id );
设置纹理图像 • 从CPU内存的一块图像定义一个纹理对象 • glTexImage2D( target, level, components, w, h, border, format, type, *texels ); • 图像的尺寸是 2的幂次 • 纹理颜色由象素处理管道处理
纹理图像的转换 • 如果图像的维数不是2的幂次 • gluScaleImage( format, w_in, h_in, type_in, *data_in, w_out, h_out, type_out, *data_out ); • *_in源图像 • *_out目标图像 • Format:图像格式(GL_RGB) • Type:图像数据格式 • 在缩放过程中进行插值和滤波
设定纹理的其他方法 • 将帧缓冲器的内容设定为纹理图像的来源 • glCopyTexImage1D(...) • glCopyTexImage2D(...) • 设置某个纹理的一部分 • glTexSubImage1D(...) • glTexSubImage2D(...) • glTexSubImage3D(...) • 拷贝部分纹理 glCopyTexSubImage2D(...)
纹理映射 • 基于参数化的纹理坐标 • glTexCoord*()指定每个顶点处的纹理 纹理空间 物体空间 t 1, 1 (s, t) = (0.2, 0.8) 0, 1 A a c (0.4, 0.2) b B C (0.8, 0.4) s 0, 0 1, 0
生成纹理坐标 • 纹理映射区域通常是平面或曲面,计算任意空间曲面与纹理域的对应关系本质上是一个参数化的过程 • 避免出现扭曲、变形的效果 • 最好是保角映射或保面积映射 • 平面方程 • 数学曲面 • 物体表面属性 • 过程式纹理函数生成
OpenGL中生成纹理坐标 • 自动生成纹理坐标 • glTexGen{ifd}[v]() • 指定一个平面 • 基于到平面的距离生成纹理坐标 • 生成模式 • GL_OBJECT_LINEAR • GL_EYE_LINEAR • GL_SPHERE_MAP