Introduction of Computer Graphics 第七讲 纹理映射 Introduction of Computer Graphics
前 言 上讲内容 简单光照模型 光源 环境光 漫反射 镜面反射 光强衰减 颜色 透明度 阴影
前 言 上讲内容 面的明暗处理 OpenGL中的光照 平面明暗处理 Gouraud明暗处理 Phong明暗处理 光线跟踪算法 辐射度光照模型 前 言 上讲内容 面的明暗处理 平面明暗处理 Gouraud明暗处理 Phong明暗处理 光线跟踪算法 辐射度光照模型 BRDF光照模型 OpenGL中的光照
本讲内容 纹理映射 一般纹理映射 环境映射 凹凸映射 纹理映射新技术 过程纹理
本讲内容 OpenGL中的纹理映射 定义纹理 指定纹理的应用方式 激活纹理映射 指定纹理坐标和几何坐标,绘制场景 控制纹理
一、纹理映射
1.1 纹理映射 将纹理模式映射到物体模型表面,模拟物体表面细节和光照,称为纹理映射(Texture Mapping) 纹理空间 t s 1.1 纹理映射 将纹理模式映射到物体模型表面,模拟物体表面细节和光照,称为纹理映射(Texture Mapping) 纹理空间 纹理一般定义在单位正方形域0s1,0t1上,称为纹理空间 砖墙、地形、地毯、动物皮毛、木质纹理等,还有一些物体表面会有图案、饰纹、标记等。 可以用纹理映射的方式将图案“贴“到物体模型表面,称为”纹理映射“ 1 t 1 s
1.1 纹理映射 纹理模式 纹理函数 定义在纹理空间中的函数。例如: a,b表示亮度,[x]表示向下取整 1.1 纹理映射 纹理模式 纹理函数 定义在纹理空间中的函数。例如: a,b表示亮度,[x]表示向下取整 A为[0,1]上的随机变量,p,q为频率系数 理论上讲,任何定义在纹理空间上的函数都可以作为纹理函数 但实际应用中采用一些特殊的函数模拟现实生活中的一些纹理 f(s,t)模拟粗布纹理
1.1 纹理映射 纹理模式 纹理数组 用离散法,定义一个二维数组代表一个用于光栅图形显示的图形、位图或图像。 n n 1.1 纹理映射 纹理模式 纹理数组 用离散法,定义一个二维数组代表一个用于光栅图形显示的图形、位图或图像。 n 纹理数组是更常用的一种方法 n
1.1 纹理映射 纹理映射方法 纹理坐标系(s,t) 物体表面的表示在(u,v)坐标系 投影平面上的像素显示在(x,y)笛卡儿坐标系 1.1 纹理映射 纹理映射方法 纹理坐标系(s,t) 物体表面的表示在(u,v)坐标系 投影平面上的像素显示在(x,y)笛卡儿坐标系 两种映射方法 将纹理模式映射至物体表面,然后再进行投影变换映射至投影平面,称为纹理扫描 将投影平面的像素区域映射至物体表面,再映射至纹理空间,称为像素次序扫描 逆纹理映射变换 MT-1 纹理映射变换 MT 逆观察投影变换 Mvp-1 观察投影变换 Mvp 纹理空间: (s,t) 数组坐标 对象空间: (u,v) 表面参数 图像空间: (x,y) 像素坐标
1.1 纹理映射 纹理映射方法 不利因素:选中的纹理表面常常与像素边界不匹配,需要进行像素分割计算。 1.1 纹理映射 纹理映射方法 纹理扫描 通常用线性函数进行纹理映射变换,实现纹理空间到物体空间的映射。 不利因素:选中的纹理表面常常与像素边界不匹配,需要进行像素分割计算。 因此像素次序扫描方法成为最常用的纹理映射方法。
1.1 纹理映射 纹理映射方法 像素次序扫描 Mvp-1 投影像素区 MT-1 像素区 物体表面 纹理数组
1.1 纹理映射 纹理映射实例:将定义好的纹理图案映射到圆柱体表面 Z 对每个投影像素区所覆盖的纹理图案中的 Y X 1.1 纹理映射 纹理映射实例:将定义好的纹理图案映射到圆柱体表面 建立圆柱体表面参数方程 根据线性纹理映射变换, 可将纹理图案映射到物体表面 使用观察投影变换的逆变换,将像 素坐标转换为圆柱体表面参数 用线性纹理映射的逆变换 将投影像素区映射到纹理空间 对每个投影像素区所覆盖的纹理图案中的 光强值取平均,得到像素的光强度 Z X Y
1.2 环境映射 Environment Mapping,将空间光照模型作为纹理映射到物体表面 首先定义一个描述单个或一组物体周围环境的光强度数组(即环境纹理,包括光源强度、天空和其他背景物体),将环境纹理映射到一个封闭环境中表面; 然后根据观察方向将环境空间表面的环境纹理映射至物体表面,实现全局镜面反射和漫反射效果; 环境映射的封闭空间可以是球体,更经常使用立方体或圆柱体形状的封闭空间。
1.2 环境映射 1.2.1 构造环境映射空间 1976年,Blinn和Newell提出第一个环境映射算法,通过将环境纹理贴到球体的映射空间上 N N O 球体关键点S、N、M、O、P、Q 纬 度 O P Q /2 M M P M Q Z S /2 3/2 2 Y S 经 度 X
1.2 环境映射 1.2.1 构造环境映射空间 Blinn和Newell的球面环境纹理 球体关键点S、N、M、O、P、Q
1.2 环境映射 1.2.1 构造环境映射空间 1986年,Greene提出立方体环境纹理 绘制简单 均匀采样 可从照片直接生成 球体关键点S、N、M、O、P、Q
立方体环境纹理
1.2 环境映射 1.2.2 映射方法 首先将像素区域向物体表面投影; 然后将投影像素区域反射至环境映射中,为每个像素选取表面的光强度; 如果物体是透明的,还可将投影像素区域折射至环境映射中。 环境映射的封闭空间可以是球体,更经常使用立方体或圆柱体形状的封闭空间。 像素在环境映射中的投影 投影像素区域 像素区域 投影参考点
环境映射与光线跟踪的对比 环境映射光照效果与光线跟踪的比较。环境映射的方法效果相似,素速度快,但是没有自反射。
1.3 凹凸映射 Bump Mapping 用于模拟粗糙物体表面的光照细节,表现表面的凹凸效果; 1.3 凹凸映射 Bump Mapping 用于模拟粗糙物体表面的光照细节,表现表面的凹凸效果; 使用扰动函数,在光照模型的计算中使用扰动法向量;
1.3.1 凹凸映射方法 N b(u,v)n P’(u,v) n pv pu 扰动的表面法矢的计算公式为 P’v N’ 1.3.1 凹凸映射方法 P’v N’ 参数曲面上一点P(u,v)处的表面法矢 在表面法矢方向上增加一个小的扰动函数b(u,v), 则 而 P’u N b(u,v)n P’(u,v) n pv P(u,v) pu y Pu、Pv分别为P(u,v)处的u向切矢和v向切矢 因为扰动函数的值b很小,所以bnu项可忽略不计 z x 扰动的表面法矢的计算公式为
1.3.2 凹凸函数b(u,v)的定义 建立查找表,凹凸值b可根据查找表查得 可由线性插值和增量算法,很快计算出各点的凹凸值b 局部变化bu和bv可由有限次差分得到近似值 凹凸查找表可以是随机图案、规则网格图案或文字形状 Pu、Pv分别为P(u,v)处的u向切矢和v向切矢 因为扰动函数的值b很小,所以bnu项可忽略不计
纹理 凹凸查找表 Pu、Pv分别为P(u,v)处的u向切矢和v向切矢 因为扰动函数的值b很小,所以bnu项可忽略不计 凹凸映射
Pu、Pv分别为P(u,v)处的u向切矢和v向切矢 因为扰动函数的值b很小,所以bnu项可忽略不计
1.4 纹理映射新技术 1.4.1 位移映射 Displacement Mapping 也叫映射转移、置换贴图 原始三角片法矢 位移面 Displacement Mapping位移映射,也叫映射转移,是Matrox研发的技术 Displacement Mapping——置换贴图技术。置换贴图可以透过两张纹理的混合形成真正的凹凸模型,就是说Displacement Mapping透过一张基本纹理、一张光照纹理以及一张最为重要的高程纹理来完成模型外观的过程,模型本身也许只是一个圆筒,但是使用了Displacement Mapping以后,就可以生成一个栩栩如生的人头来,也可以让平面图形形成立体效果。这种技术在以往只是在Pixar的Photorealistic Renderman得以应用。当然,这个“建模”过程也是需要Vertex Shader来协助的,并非以往环境凹凸贴图那样只是一个单纯的贴图过程,而是一个极其复杂的过程。Matrox能够实现硬件支持,已经成为3D图形芯片的一次重大突破。 Cook 提出了位移映射(disp lacem en t m app ing)技术, 它能够产生非常复杂的几何细节, 却不需要对 这些细节逐个进行构造[ 13 ]. 它允许用户采用位移映射图或者移位绘制器(displacement shaders) 来描 述曲面的几何细节, 并对所映射的曲面添加真正的移位细节[ 14, 15 ]. 这一点是位移映射和凹凸纹理 (bump tex tu re) 的根本区别. 两者非常相似, 不同的是位移映射是真正添加几何细节, 而凹凸纹理则是 只对映射曲面不同部位的法向量做扰动[ 13, 16 ]. 位移映射技术的一个根本特征是只有在绘制的时候, 几 何细节才真正被加上去, 因此, 可以自适应地根据具体位置选择可见的几何细节的精细程度, 以减小场 景绘制的几何复杂度. GeForce6800中,CineFX结构最值得一提的特性之一就是其位移映射(displacement mapping)功能,这一功能意味者我们第一次只需要简单的将一个材质加载到寄存器中便可以将材质信息映射到顶点上。这一技术超越了像bump mapping等旧的那些不用许材质和周围环境相互作用的方法。通过替代绘图每一个材质都可以与各种各样的光源相互作用。在某种意义上来说,这种做法比起原有的那些技术只需要少量的计算。从画面质量的角度来看,这一技术可以更加真实的再现3D环境,它里面的各种光源以及一个场景里面的各种3D模型的相互作用。也是第一次这些模型的每一个细节都可以对各种光源做出反应。举个简单的例子来说就是一个模型在另外一个模型上可以正确的投影,看起来就像真的一样。 原始三角片
位移映射实例 左下角小图为没有使用位移贴图技术的模型,上部大图为应用了位移贴图技术后的模型。通过比较可以看出:位移贴图技术的应用使恐龙头部模型有了更高的真实度。
View-Dependent Displacement Mapping 2003 SIGGRAPH 微软亚洲研究院的王力锋等人提出的VDM(View-Dependent Displacement Mapping)基于视点的位移映射,沿视线方向有不同的细节纹理映射。 与传统位移映射不同, VDM 能够对自阴影、自遮挡和轮廓边缘细节进行正确的绘制,模型网格不需要细分. VDM 对每个像素进行处理,通过硬件加速,可以进行实时的复杂结构模型的渲染绘制 Bump Mapping Displacement Mapping VDM VDM解决了位移映射中的遮挡和轮廓问题,并通过硬件加速可实现实时绘制
VDM实例
1.4 纹理映射新技术 虚拟位移贴图 法线贴图 Virtual Displacement Mapping Normal Mapping 3DMax7中的新功能 根据高分辨率模型顶点的法矢量来对底分辨率的模型进行纹理映射,可在简单模型上获得复杂的纹理细节和光照效果 虚拟位移贴图 Virtual Displacement Mapping 准3D技术 依靠后期的PixelShader来将贴图进行一些局部形变,再配合阴影效果来实现3D效果。 这种技术比起传统的凹凸贴图以及法线贴图有更好的效果,但是又不会像位移贴图那样消耗过多的几何处理能力 虚拟位移贴图技术是一种效果非常好的准3D技术。这项技术类似于法线贴图(Normal Mapping),并没有像位移贴图(Displacement Mapping)那样实现真正的3D效果。主要依靠后期的PixelShader来将贴图进行一些局部形变,再配合阴影效果来实现3D效果。这种技术比起传统的凹凸贴图以及法线贴图有更好的效果,但是又不会像位移贴图那样消耗过多的几何处理能力,所以这种技术可以说是一种结合位移贴图技术和法线贴图的优点的技术。 X700支持的SmartShader HD技术,在虚拟位移贴图上能够实现比较好的效率,从而在消耗资源很小的情况下得到了非常好的效果。
1.5 过程纹理 1.5.1 三维纹理 二维纹理存在的问题 三维纹理映射 1.5 过程纹理 1.5.1 三维纹理 二维纹理存在的问题 物体曲面上曲率变化大的区域可能发生纹理的非均匀变形,导致不真实的视觉效果; 对由多个曲面片拼接而成的物体表面进行二维纹理映射时,很难保证相邻曲面片间纹理的连续性。 三维纹理映射 将纹理模式直接定义在三维空间,通过将物体嵌入到纹理空间实现纹理映射; 三维纹理的构造方法 当然,研究者们一直在探讨解决二维纹理的这些问题的方法,例如反走样算法,并且还在做不同纹理之间的光滑过渡等研究
1.5.1 三维纹理 三维纹理的定义方法 过程纹理 数字化离散采样——内存耗费巨大 数学模型 通过定义简单的过程迭代函数生成的三维纹理,称为过程纹理 (Procedural Texture) 过程纹理均为解析表达的数学模型,目的是用简单的参数来逼真地描述复杂的自然纹理细节 经验模型 虽然数字化离散采样方法在二维纹理中得到了广泛的应用,但在三维纹理的构造中,它需要庞大的三维数组,对高分辨率纹理来说,其内存耗费是非常巨大的。 因而在真实感图形系统中,往往采用第二种方法定义三维纹理,并开发出许多简单的过程迭代函数生成复杂的纹理,这类纹理称为“过程纹理”
1.5.2 过程纹理造型 Peachey的木纹函数 基本思想 采用一组共轴圆柱面定义体纹理; 通过下列简单操作实现真实感纹理的模拟: 扰动 (perturbing):对共轴的圆柱面进行扰动,扰动量可以为正弦函数或其他能描述木纹与正规圆柱面的偏离量的函数; 扭曲(twisting):在圆柱轴方向加一个小扭曲量; 倾斜(tilting):将圆柱轴沿某一方向倾斜。 1985年Peachey用一种简单的规则三维纹理函数首次成功的模拟了木制品的纹理效果。
Peachey的木纹函数
1.5.2 过程纹理造型 Perlin的三维噪声函数 基本思想 构造三维噪声函数noise(x,y,z); 噪声函数特点: 在空间连续分布 变化剧烈 在空间任何方向均不具有周期变化 三维噪声函数整数网格 在每一个整数网格点定义一随机 灰度值作为噪声函数的值 非整数网格点处的函数值由相邻 8个整数点的值通过三线性插值得到 噪声函数 一个好的噪声函数应具有的性质: (1)旋转统计不变性 (2)平移统计不变性 (3)频率带宽很窄
1.5.2 过程纹理造型 Perlin的三维噪声函数 模拟出逼真的自然纹理
1.5.2 过程纹理造型 Perlin的湍流(turbulence)函数 基本思想 用一系列三维噪声函数叠加构造三湍流函数近似模拟湍流现象; 用简单连续函数描述自然纹理的基本结构特征; 用湍流函数扰动基本函数中的某些参数,产生复杂的纹理细节。 用一系列三维噪声函数叠加构造三湍流函数近似模拟湍流现象; 可模拟大理石、火焰及云彩等自然纹理。 湍流是流体力学的概念 用简单函数描述自然纹理的基本结构特征,一般这些函数有变化很大的一阶导数。
1.5.2 过程纹理造型 气态过程纹理 用体密度函数在三维纹理空间建立气体的隐式描述; 用湍流函数进行扰动,计算扰动后每点的密度值; 例如:烟柱的纹理 烟柱的基本形状是垂直的圆柱,将圆柱变形后可得到一个具有真实感的烟柱。视觉上烟柱的动态特征是:上升时逐渐扩散,并慢慢地由规则形状变得紊乱。 将湍流函数设在圆柱中心。湍流量随烟柱高度的增加而增加,而其密度随之降低。 烟柱上升时,其形状应该是弯曲盘绕的,因此在计算点到圆柱中心的距离之前,可引入一个垂直的螺旋位移
过程纹理实例 采用随机分形方法 采用随机分形方法获得的地貌纹理
纹理合成
纹理合成
纹理混合 Progressively-variant textures
二、 OpenGL中的纹理映射
2.1 OpenGL的纹理映射过程 定义纹理 指定纹理的应用方式 激活纹理映射 指定纹理坐标和几何坐标,绘制场景 纹理映射只适用于RGBA模式,在颜色索引模式下使用纹理映射,结果是不可预料的
2.2 定义纹理 纹理可以是一维、二维或三维的; 每个纹素的数据格式(由1至4个数值组成) 颜色索引值 GL_COLOR_INDEX 2.2 定义纹理 纹理可以是一维、二维或三维的; 每个纹素的数据格式(由1至4个数值组成) 颜色索引值 GL_COLOR_INDEX RGB值 GL_RGB RGBA值 GL_RGBA R值 GL_RED G值 GL_GREEN B值 GL_BLUE Alpha值 GL_ALPHA 光照强度值 GL_LUMINANCE 光强Alpha值 GL_LUMINANCE_ALPHA 纹理映射只适用于RGBA模式,在颜色索引模式下使用纹理映射,结果是不可预料的
2.2 定义纹理 多重纹理映射 为纹理设置边界 为纹理定义多种分辨率; 在距离观察位置远时,映射低分辨率的纹理图像; 距离近时,映射高分辨率的纹理图像; 为纹理设置边界 实际应用中需要多种纹理拼接; 为纹理设置边界超出[0.0,1.0] 纹理参数范围的边界border, 通常为1个像素宽; 通过线性平均,实现纹理图像 间的光滑过渡。 把一个两倍于最大纹理尺寸的的纹理映射到一个正方形上,则可以首先把该正方形分成四个小正方形,然后将不同的纹理图象分别映射到这四个小正方形上 由于同一时刻只能处理一个纹理,边界处就可能产生不连续的问题。 可以将边界上的像素值设为与相邻纹理单元的边界像素值,然后在该纹理图象上做线性平均,使得纹理图象光滑过渡到相邻纹理。
2.2 定义纹理 定义一维纹理 纹理只在某一方向上变化,而在另一个方向上没有变化,相当于高度为1的二维纹理 使用glTexImage1D()函数定义一维纹理 函数原型 void glTexImage1D( GLenum target, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixel)
glTexImage1D()函数参数说明 target 必须设置为GL_TEXTURE_1D level 是使用多重纹理映射时的分辨率级数,若只有一个分辨率,该值为0 internalFormat 表明纹理映射方式,取值为1~4之间的整数值,或者是38个符号常量之一。 width 给定纹理尺寸,必须是2的幂次方2m(m为非负整数,如果有边界width 为2m+b ) border指定边界宽度b(为0或1) format 指定纹理的数据格式(如前,纹素的数据格式) type 指定纹理的数据类型(见本页备注) pixel为纹理图像数组的指针,指定纹理图像及其边界 internalFormat 参数的38种符号常量见参考书《OpenGL编程权威指南》p.318 type指定的纹理数据类型包括: GL_BYTE GL_UNSIGNED_BYTE GL_SHORT GL_UNSIGNED_SHORT GL_INT GL_UNSIGNED_INT GL_FLOAT GL_UNSIGNED_FLOAT
2.2 定义纹理 定义二维纹理 使用glTexImage2D()函数定义二维纹理 函数原型 void glTexImage2D( GLenum target, GLint internalFormat, GLsizei width, GLsizei heigth, GLint border, GLenum format, GLenum type, const GLvoid *pixel) 参数说明 target 必须设置为GL_TEXTURE_2D width和 heigth 给定二维纹理的尺寸,必须为2m+2b( width和 heigth 可分别对应不同的m值) width和 heigth为0,纹理映射无效
2.2 定义纹理 定义三维纹理 使用glTexImage3D()函数定义三维纹理 函数原型 void glTexImage3D(GLenum target, GLint internalFormat, GLsizei width, GLsizei heigth , GLsizei depth, GLint border, GLenum format ,GLenum type, const GLvoid *texels) 参数说明 target 必须设置为GL_TEXTURE_3D width 、 heigth 、depth给定三维纹理的尺寸,必须为2m+2b(三个参数可分别对应不同的m值) texels为三维纹理图像数组的指针
2.2 定义纹理 定义多重纹理映射 事先指定一系列分辨率逐渐减小的纹理图像; OpenGL会根据所映射的物体尺寸自动选择使用哪个分辨率的纹理图; 需要额外的计算,增加计算时间; 但可避免场景中小物体移动时纹理的闪烁
2.2 定义纹理 定义多重纹理映射 设置方法 在最大纹理尺寸和11纹理图之间提供所有尺寸的纹理图像; 纹理尺寸必须是2的幂次方; 例如 一个全分辨率的纹理为32 16,那么必须定义一组16 8、 84、 42、2 1、1 1分辨率的纹理图,用glTexImage*()函数设置各级纹理的level、width、heigth、image参数
2.2 定义纹理 定义多重纹理映射 实例 glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,32,32,0,GL_RGBA,GL_UNSIGNED_BYTE,image0); glTexImage2D(GL_TEXTURE_2D,1,GL_RGBA,16,16,0,GL_RGBA,GL_UNSIGNED_BYTE,image1); glTexImage2D(GL_TEXTURE_2D,2,GL_RGBA,8,8,0,GL_RGBA,GL_UNSIGNED_BYTE,image2); glTexImage2D(GL_TEXTURE_2D,3,GL_RGBA,4,4,0,GL_RGBA,GL_UNSIGNED_BYTE,image3); glTexImage2D(GL_TEXTURE_2D,4,GL_RGBA,2,2,0,GL_RGBA,GL_UNSIGNED_BYTE,image4); glTexImage2D(GL_TEXTURE_2D,5,GL_RGBA,1,1,0,GL_RGBA,GL_UNSIGNED_BYTE,image5);
2.2 定义纹理 定义多重纹理映射 自动生成多重纹理图像 调用gluBuild*DMipmaps()函数 函数原型 int gluBuild1DMipmaps(GLenum target, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixel); int gluBuild2DMipmaps( GLenum target, GLint internalFormat, GLsizei width, GLsizei heigth, GLint border, GLenum format, GLenum type, const GLvoid *pixel); 参数说明 参数与glTexImage1D()和glTexImage2D()的参数相同 调用该函数自动生成分辨率逐渐减小到11的多重图象。 如果原始最大分辨率纹理图像的尺寸不是2的幂,这两个函数会自动将图象缩放到接近于2的幂次方的尺寸上。 多重图象构造成功,返回1;否则返回错误代码
2.2 定义纹理 纹理的创建 直接创建法 从帧缓存中读取 利用函数直接设置各像素点的RGB值 只能生成简单的有一定规律的纹理图像, 将纹理从当前GL_READ_BUFFER中读出来,并将像素放入纹理内存 调用函数glCopyTexImage1D()、 glCopyTexImage2D() 从帧缓存中读取纹理,利用了glPixelTramnsfer*()的设置和其他的像素传递操作 函数原型 glCopyTexImage1D(GLenum target, GLint internalFormat, GLint x, GLint y, GLsizei width, GLint border); glCopyTexImage2D(GLenum target, GLint internalFormat, GLint x, GLint y, GLsizei width, GLsizei heigth, GLint border);
2.2 定义纹理 纹理的创建 调用库函数读取外部文件 OpenGL提供函数auxDIBImageLoad()函数读取纹理图像 函数原型 AUX_RGBImageRec auxDIBImageLoad (LPCTSTR filename); 参数说明 filename是纹理图像文件的名称。 该函数可以读取bmp和rgb两种格式的文件。 AUX_RGBImageRec是一个定义纹理数据的结构,其中最主要的三个域是SizeX、SizeY和Data, SizeX和SizeY是纹理的宽和高,Data存储具体的纹理数据。
2.2 定义纹理 纹理的创建 读取外部文件 根据外部图像文件的具体格式,编写函数将纹理图像读入内存; 非bmp和rgb格式的图像文件,必须采用这种方式读入; 要求对图像文件的格式非常了解。
2.3 指定纹理映射方式 纹理映射方式 替换GL_REPLACE 贴花 GL_DECAL 调整GL_MODULATE 融合GL_BLEND 将纹理作为不透明图像覆盖到片段 贴花 GL_DECAL 仅用于RGB和RGBA两种内部格式,片段和纹理颜色混合的比例由纹理的Alpha值确定 调整GL_MODULATE 用纹理图像的颜色调整片段的颜色和或颜色比例,综合光照和纹理的效果 融合GL_BLEND 使用指定的颜色,响应光照条件 替换:为物体设置的任何颜色和材质属性均无法透射过来,多用在光滑表面(如大理石地板、锡罐表面的标签)
2.3 指定纹理映射方式 pname param 设置纹理映射方式 使用glTexEnv*()函数中的变量设置映射方式 函数原型 void glTexEnv{if}(GLenum target, GLenum pname, TYPE param); void glTexEnv{if}v(GLenum target, GLenum pname, TYPE *param); 参数说明 target变量必须为GL_TEXTURE_ENV; pname和 param的对应取值 GL_DECAL 贴花 GL_MODULATE 调整 GL_BLEND 融合 pname param GL_TEXTURE_ENV_MODE GL_REPLACE 、 GL_DECAL、GL_MODULATE、GL_BLEND GL_TEXTURE_ENV_COLOR 指定RGBA四个分量的数组(GL_BLEND时才有意义)
2.3 指定纹理映射方式 设置纹理映射方式 贴花、调整和融合函数 internalFormat 贴花方式 调整方式 融合方式 1 无定义 C=LtCf A=Af C=(1-Lf )Ct +LtCc A=At 2 C=LtCf A=AtAf A=AtAf 3 C=Ct A=Af C=CtCf A=Af 4 C=(1- At )Cf +AtCt C=CtCf A=AtAf 贴花方式下,片段的颜色值会被纹理的颜色所替代,但并不改变透明度值,选择分量数为4时,片段的颜色根据纹理的 透明度同纹理颜色相融合,但片段的透明度值; 调整方式下,当选择分量数为1和2,片段颜色值根据纹理的亮度进行调整;选择3或4,则将每个引入的颜色分量与纹理中对应的分量值相乘。若要响应光照,必须使用调整方式 融合方式只有对1和2个分量时才起作用。该方式使用一个RGBA常量Cc融合片段和纹理的颜色 表中颜色值与标量的乘积等于三个颜色分量与该标量的乘积; 颜色值与颜色值的和(或乘积)等于三个颜色分量的和(或乘积) 说明:下标t表示纹理值。下标f表示片段值,下标c表示GL_TEXTURE_ENV_ COLOR指定的值,无下标表示最终的计算值;C表示RGB颜色值,L表示 光照值;分量数是纹理定义函数glTexImage*D()函数中component参数设置的值
2.4 激活纹理映射 使用glEnable()和glDisable()函数打开和关闭纹理 glEnable(GL_TEXTURE_1D ); //打开一维纹理 glEnable(GL_TEXTURE_2D); //打开二维纹理 glEnable(GL_TEXTURE_3D); //打开三维纹理 … glDisable(GL_TEXTURE_1D); //关闭一维纹理 glDisable(GL_TEXTURE_2D); //关闭二维纹理 glDisable(GL_TEXTURE_3D ); //关闭三维纹理
2.5 计算纹理坐标 为顶点指定相应的纹理坐标,确定将纹理图像中的哪个纹素映射到该顶点; 与几何坐标的计算一样,纹理坐标也是在两顶点之间进行线性插值; 片元尺寸超过纹理尺寸范围时,可以设置纹理重复和箝位方式,用多个纹理光滑拼接映射到物体表面; 正方形片元的纹理坐标及映射 V3 V4 t (0,1) (1,1) (0,0) (1,0) s V1 V2
2.5 计算纹理坐标 调用glTexCoord*()函数指定纹理坐标 函数原型 void glTexCoord{1234}{sifd}(TYPE coords); void glTexCoord{1234}v{sifd}(TYPE *coords); 参数说明 纹理坐标可由s,t,r,q表示,对应几何坐标x,y,z,w。一维纹理只使用s坐标,二维纹理使用s,t坐标。纹理坐标的 范围通常在[0,1],也可以使用该范围以外的值; 参数coords即为纹理坐标数组; glTexCoord*()函数指定的纹理坐标对应其后glVertex*()函数指定的顶点
2.5 计算纹理坐标 glTexCoord*()函数应用实例 glBegin(); glNormal3d(-5.0,0.0,0.0); glTexCoord2d(0.0, 0.0); glVertex3d(-5.0, -5.0, 0.0); glTexCoord2d(1.0, 0.0); glVertex3d(5.0, -5.0, 0.0); glTexCoord2d(1.0, 1.0); glVertex3d(5.0, 5.0, 0.0); glTexCoord2d(0.0, 1.0); glVertex3d(-5.0, 5.0, 0.0); glEnd(); 纹理坐标的定义和顶点几何坐标的定义都按逆时针排序
2.5 计算纹理坐标 片元为任意形状时的纹理坐标 Y (0,0) (1,0) (0.75,1) (0.25,1) (0,0) (1,0) (1,1) (0,1) t (0,1) (1,1) (0,0) (1,0) s X
2.5 计算纹理坐标 自动计算纹理坐标 调用glTexGen*()函数 函数原型 参数说明 void glTexGen{ifd}(GLenum coord, GLenum pname, TYPE param); void glTexGen{ifd}v(GLenum coord, GLenum pname, TYPE *param); 参数说明 coord必须为GL_S,GL_T,GL_R,GL_Q分别表示生成的是s,t,r,q坐标; pname可设置为GL_TEXTURE_GEN_MODE、GL_OBJECT_PLANE 或GL_EYE_PLANE param相对于 pname为GL_TEXTURE_GEN_MODE时,可以取GL_OBJECT_LINEAR、GL_EYE_LINEAR、GL_SPHERE_MAP; 相对于 pname为GL_OBJECT_PLANE 或GL_EYE_PLANE时, param为一个参数数组,用以指定纹理生成。 q坐标是纹理的缩放因子
2.5 计算纹理坐标 环境映射 OpenGL环境映射算法是基于球面环境纹理; 根据在场景中拍摄的环境图片,生成环境纹理图; 指定GL_SPHERE_MAP常数为环境映射创建纹理坐标,并且要在s和t方向上都要指定此常数; OpenGL环境映射算法会通过计算将环境纹理中对应点的颜色绘制到物体上; 设置方法 glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP); glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T);
2.5 计算纹理坐标 球面的纹理映射 glPushMatrix(); //打开二维纹理 glEnable(GL_TEXTURE_2D); //启动环境纹理贴图: glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); //读取和定义球的纹理 SphereTexture(); //绘制球 glutSolidSphere(1.9,50.0,50.0); glPopMatrix();
2.6 管理纹理 纹理对象 纹理对象的管理 创建纹理对象存储纹理数据,对纹理资源进行管理 支持纹理的快速重用 生成纹理名称 将纹理对象绑定到纹理数据(包括图像数组和纹理属性) 在渲染纹理化模型时,重新绑定纹理对象 删除纹理对象 创建纹理对象存储纹理数据,对纹理资源进行管理。可使纹理能快速重用
2.6 管理纹理 生成纹理名称 void glGenTextures(GLsizei n, Gluint *textureNames); 纹理名称可以是任何非0的无符号整数 返回在由textureNames所指定的数组中 GLboolean glIsTexture(Gluint textureName); 确定纹理名称textureName是否已被使用 若纹理名称textureName已经被glGenTextures()返回,但是还没有被绑定,会返回GL_FALSE 如果纹理名称textureName已经被绑定,还未被删除,则返回GL_TRUE 纹理名称可以是任何非0的无符号整数
2.6 管理纹理 绑定纹理 void glBindTexture(GLenum target, Gluint textureName); 创建纹理对象,并使用纹理对象 当绑定了一个纹理对象textureName时,该纹理对象被创建,并且接下来的所有的纹理设置和操作函数调用都是针对该纹理对象的 当重新绑定纹理对象textureName时,其数据成为当前的纹理状态 多重纹理应该为每个level的纹理创建一个纹理对象 TextureMapping2D.exe 当重新绑定纹理对象textureName时,其数据成为当前的纹理状态。随后对纹理映射的设置做出的所有改变都是作用于当前纹理对象的
2.6 管理纹理 删除纹理对象 void glDeleteTextures (GLsizei n, const Gluint *textureNames); 删除textureNames数组所指定的所有纹理对象 纹理名称可以是任何非0的无符号整数
2.7 控制纹理 OpenGL对场景中的纹理提供了控制函数 纹理控制函数glTexParameter*() 函数原型 参数说明 对纹理进行缩放 在某一坐标方向上重复或箝位纹理 纹理控制函数glTexParameter*() 函数原型 void glTexParameter{if}{v}(GLenum target, GLenum pname, TYPE param); 参数说明 target 为GL_TEXTURE_1D、 GL_TEXTURE_2D或GL_TEXTURE_3D 参数pname和param的对应关系如下页表中所示
控制函数glTexParameter*()中参数pname和param的对应关系 2.7 控制纹理 控制函数glTexParameter*()中参数pname和param的对应关系 pname参数 param取值 GL_TEXTURE_MAG_FILTER GL_NEAREST, GL_LINEAR GL_TEXTURE_MIN_FILTER GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR GL_TEXTURE_WRAP_S GL_CLAMP, GL_REPEAT GL_TEXTURE_WRAP_T 纹理一般定义在矩形区域,但是映射的目标对象并不一定能正好对应纹理的区域大小,因此要进行缩放。采用滤波进行纹理的放大和缩小
2.7 控制纹理 放大和缩小纹理 OpenGL采用滤波方法对纹理进行缩放 GL_TEXTURE_MAG_FILTER 放大纹理滤波 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); GL_TEXTURE_MAG_FILTER 放大纹理滤波 GL_TEXTURE_MIN_FILTER 缩小纹理滤波 GL_NEAREST 表示选择最接近像素中心的纹素进行放大或缩小; GL_LINEAR 表示选择距离像素中心最近的22维纹素数组加权平均后进行放大或缩小; 当纹理被映射到片段上时, (1)如果一个片段像素要对应几个纹素,就要缩小纹理; (2)如果一个纹素对应片段上几个像素时,说明片段比纹理要大,要放大纹理
GL_TEXTURE_MIN_FILTER 缩小纹理滤波的其他参数 2.7 控制纹理 GL_TEXTURE_MIN_FILTER 缩小纹理滤波的其他参数 参数值 含 义 GL_NEAREST_MIPMAP_NEAREST (使用一个MIPMAP进行缩小)选择最近的纹素进行缩小 GL_LINEAR_MIPMAP_NEAREST (使用一个MIPMAP)对纹素进行线性插值 GL_NEAREST_MIPMAP_LINEAR (使用两个MIPMAP图像)选择两个切换图像中最近的纹素值,然后对这两个值进行插值 GL_LINEAR_MIPMAP_LINEAR (使用两个MIPMAP图像)使用线性插值计算两个图像中每个图像的纹素值,然后在这个数值之间进行线性插值 使用GL_NEAREST_MIPMAP_LINEAR和GL_LINEAR_MIPMAP_LINEAR对两幅图像的纹素值进行线性插值。
2.7 控制纹理 重复纹理 处理纹理坐标的一种方式; 允许纹理超过[0.0,1.0]的范围,在映射过程中对纹理进行重复和箝位; t 当纹理被映射到片元上时, (1)如果一个片元像素要对应几个纹素,就要缩小纹理; (2)如果一个纹素对应片元上几个像素时,说明片元比纹理要大,要放大纹理 (0,0) s (1,0) (2,0) (3,0) (4,0)
2.7 控制纹理 重复纹理 调用glTexParameter*()函数重复纹理 在s或t坐标方向 上重复绘制纹理 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); 在s或t坐标方向 上重复绘制纹理 t 当纹理被映射到片元上时, (1)如果一个片元像素要对应几个纹素,就要缩小纹理; (2)如果一个纹素对应片元上几个像素时,说明片元比纹理要大,要放大纹理 s
2.7 控制纹理 箝位纹理 若多边形比纹理尺寸大,而又希望只映射一个纹理,就可以使用箝位; 将多边形上任何坐标值大于1.0的像素取为纹理1.0处的纹素值,任何小于0.0的箝位到0.0 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); 当纹理被映射到片元上时, (1)如果一个片元像素要对应几个纹素,就要缩小纹理; (2)如果一个纹素对应片元上几个像素时,说明片元比纹理要大,要放大纹理
2.7 控制纹理 重复和箝位纹理实例 单一纹理映射 重复纹理映射 箝位纹理映射
3.7 控制纹理 重复和箝位纹理实例 Reclmp.rar
作 业 绘制一个场景(必须有艺术设计的成分); 需要2个以上的点光源和2个以上的聚光灯的照明设计,每盏灯要有灯罩和灯泡模型; 作 业 绘制一个场景(必须有艺术设计的成分); 需要2个以上的点光源和2个以上的聚光灯的照明设计,每盏灯要有灯罩和灯泡模型; 场景模型必须有一部分是Bèzier曲面; 为模型表面映射纹理( Bèzier曲面映射二维纹理利用二维求值器计算纹理坐标),纹理映射方式为GL_MODULATE; 鼠标右键弹出菜单项,可以控制灯光的开关和是否为模型贴纹理; *实现模型动画及简单的碰撞检测; 可分组实现大作业,但小组必须完成*题。小组人数不得超过3人。上交的作业中要清楚写明每个组员的工作,以便老师给分。小组完成的工作要还需要进行答辩。