转自://http://blog.csdn.net/longhuihu/article/details/8477614

纹理(texture)是一块矩形数据序列,存储的数据为颜色、亮度、alpha值。纹理数据的每个单位叫做texel,纹理数据可以被映射到任何几何形状的表面。

1、纹理映射基础

使用纹理是一个相对复杂的操作,一般需要以下几个步骤:
1、创建texture对象,并指定数据:
纹理数据可以是二维的图像,也可以是一维或三维的;

2、指定texture将被以何种方式与像素进行映射:
有四种函数可以用于对fragment color和texture color进行计算,一是直接使用纹理颜色进行替换,二是用纹理颜色对fragment颜色进行模运算,三是进行scale运算,四是依据纹理值,用一个颜色常量与fragment进行混合;

3、激活像素映射功能:
        调用glEnable()函数来激活,参数可以是GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D,GL_TEXTURE_CUBE_MAP,分别激活一维、二维、三维、立体纹理,如果先后激活多个那个生效的是较大维数的;

4、绘制场景,指定几何坐标和纹理坐标:
就像为顶点指定颜色一样,为对应顶点指定纹理坐标,对二维的纹理来说,坐标就是一对0~1的浮点数。就像颜色的flat shade一样,几何顶点之间的纹理坐标自动进行插值计算。这样,顶点之外的部分,纹理坐标超出了[0,1],其计算方式需要你来指定:重复,剪切...。2\

2、纹理数据

为纹理指定数据的api是glTexImage2D(GLenum target, GLint level, GLint internalFormat,GLsizei width, GLsizei height, GLint border,GLenum format, GLenum type, const GLvoid *texels);
taget:GL_TEXTURE_2D等常量
level:当你准备为同一纹理对象,提供多个分辨率的版本,level值派上用场。否则设为0即可
internalFormat:指定了纹理元素的数据成员,比如GL_RBGA,GL_ALPHA
width,height,border:指定了纹理的尺寸、边宽,OpenGL2.0以前,width和height必须是2的指数
format,type:传入数据的格式,类型,与glDrawPixels一致

可以直接读取frameBuffer数据作为纹理glCopyTexImage2D(GLenum target, GLint level,GLint internalFormat, GLint x, GLint y,GLsizei width, GLsizei height, GLint border);
GLint internalFormat, GLint x, GLint y,GLsizei width, GLsizei height, GLint border);
x,y:欲读取frameBuffer的坐标,其他参数与glTexImage2D相同

修改现有纹理对象的数据比重新创建纹理对象的代价要低,glTexSubImage2D(GLenum target, GLint level, GLint xoffset,GLint yoffset, GLsizei width, GLsizei height,
GLenum format, GLenum type,const GLvoid *texels);
xOffset,yOffset:为目标纹理的坐标

glCopyTexSubImage2D与glTexSubImage2D功能类似,数据来自framebuffer。

纹理可以以压缩形式存储,或直接从压缩的模式加载。
判断纹理是否压缩:glGetTexLevelParameteriv(GL_TEXTURE_2D, GL_TEXTURE_COMPRESSED,BOOL &compressed);
纹理的压缩模式OpenGL并没有做规定,具体的实现会定义,加载压缩纹理glCompressedTexImage*D()

3、Mipmaps

纹理对象同样要放在场景中显示,当物理远离视点是,纹理对象会被缩放过滤。在这个持续过程中,会出现闪烁现象。为了避免,可以为纹理对象提供一组不同分辨率的图像数据,叫做Mipmap。
你需要提供从最大尺寸到1x1之间所有2的冥次尺寸的图像;glTexImage2D() api从level=0开始设置,0代表最大尺寸。
可以使用API基于最大尺寸图像为纹理产生Mipmaps,glGenerateMipmap(GLenum target);
 
有时候可以对Mipmaps的level进行限制,比如不希望有尺寸特别小的mipmap,或者不希望纹理在极大和极小level之间进行切换,这些可以通过API glTexParameter*()完成,参数如下:
GL_TEXTURE_BASE_LEVEL:最大尺寸的level限制;
GL_TEXTURE_MAX_LEVEL:最小尺寸的mipmap level限制;通过这两个值可以减少需要提供的mipmap
GL_TEXTURE_MIN_LOD和GL_TEXTURE_MAX_LOD:则影响OpengGL具体渲染时对mimap level的选择
 

4、过滤

纹理texel和像素之间没有一一对应关系,有可能1个texel需要对应一片像素,也有可能一片texel最终对应到一个像素。这些操作叫做过滤,OpenGL允许设置一些选项,来控制过滤,API也是glTexParameteri。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST):将纹理放大滤镜设置为GL_NEAREST;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST):蒋纹理缩小滤镜设置为GL_NEAREST;
GL_NEAREST的意思是选择离纹理坐标最近的一个像素;其他值还有GL_LINEAR—坐标中心点附近的2x2像素进行加权计算。
 

5、纹理对象管理

每个纹理对象有一个无符号整形作为名字,为了避免重复,使用API glGenTextures(GLsizei n, GLuint *textureNames)来生成,glIsTexture()可以判断一个名字是不是使用中的纹理对象名字。
使用纹理对象前,需要先绑定glBindTexture(),之后glTexImage*(), glTexSubImage*()这些操作就针对绑定的Texture了。
glDeleteTextures可以删除不再使用的Texture。
 
某些OpenGL实现支持一组高效的texture,叫做resident,通常有专门的硬件来存储和操作这些texture,所以你应当尽量把texture放进这个组。如果程序中texture的数量超出了这个组的限制,那么有些texture就不能进入这个组,可以通过glGetTexParameter(GL_TEXTURE_RESIDENT)或glAreTexturesResident来判断texture是否在resident中。可以使用glPrioritizeTextures()给texture附加一个优先级,来增加进入resident的几率。
 

6、纹理函数

纹理的数据一般是作为颜色取代物体表面的颜色,但也可以使用别的纹理函数。
glTexEnv{if}v(GLenum target, GLenum pname, const TYPE *param):
targe:GL_TEXTURE_FILTER_CONTROL 或 GL_TEXTURE_ENV
pname:当target是GL_TEXTURE_ENV时,如果pname是GL_TEXTURE_ENV_MODE,param可以是GL_DECAL, GL_REPLACE, GL_MODULATE,GL_BLEND, GL_ADD, GL_COMBINE,指定了使用何种函数对fragement和纹理颜色进行结合计算;如果pname是GL_TEXTURE_ENV_COLOR,则指定一个颜色常量用于纹理操作。
当然texture的internalformat也会影响这里的计算。
 

7、纹理坐标

为顶点指定纹理坐标,就像为顶点指定坐标一样,一般用(s,t,r,q)来表示各分量,就像用(x,y,z,w)来表示顶点坐标一样。设置纹理坐标的API是glTexCoord{1234}{sifd}v(const TYPE *coords);
 
纹理是矩形区域,而几何物体表面未必能够映射为矩形,比如曲面。除了圆柱、圆锥这样规则的曲面外,其他的曲面映射到矩形texture时必然发生扭曲。比如球体,越接近两极扭曲越严重。曲面都是通过大量的小多边形来组成的,为这些多边形顶点指定纹理坐标可能会比较复杂。
 
如果指定[0,1]以外的纹理坐标值,就会发生clamp或repeat,前者将超出范围的坐标值调整为0或1;后者会对纹理进行重复铺开。clamp和repeat的模式可以通过glTexParameteri来设置。
 
OpenGL提供API自动为几何顶点产生纹理坐标:
void glTexGen{ifd}(GLenum coord, GLenum pname, TYPE param);
void glTexGen{ifd}v(GLenum coord, GLenum pname, const TYPE *param);
void glTexGen{ifd}v(GLenum coord, GLenum pname, const TYPE *param);
coord:GL_S, GL_T, GL_R, or GL_Q指定产生那个维度的坐标
pname:GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE, or GL_EYE_PLANE,GL_TEXTURE_GEN_MODE指定产生坐标的方式,值可以是GL_OBJECT_LINEAR, GL_EYE_LINEAR, GL_SPHERE_MAP,GL_REFLECTION_MAP, or GL_NORMAL_MAP;GL_OBJECT_PLANE和GL_EYE_PLANE则提供一个参考平面。
 
如果GL_TEXTURE_GEN_MODE指定为GL_OBJECT_LINEAR,在加上GL_OBJECT_PLANE用(P0,P1,P2,P3)表示,那么顶点的纹理坐标值的计算表达式:P0*x+P1*y+P2*z+p3*w,即顶点到平面的距离。如果GL_TEXTURE_GEN_MODE是GL_EYE_LINEAR那么顶点坐标会转换到眼坐标系,在进行计算。实际效果是,前者纹理相对于物体固定,后者纹理相对于场景固定。
 
GL_SPHERE_MAP:
这种生成纹理坐标的方式主要用于对环境产生反射,具体见参考书
 
Cube MAP:
这个是使用六个纹理对象,组成一个中心在原点的立方体,纹理坐标就是一个单位向量,指向立方体上的一点。这种情况下使用自动坐标生成,将生成模式设为GL_REFLECTION_MAP或GL_NORMAL_MAP。原书代码中有一个例子。
 

8、Multitexturing

OpenGL可以同时使用多个纹理,这些纹理被绑定到一个纹理单元序列,Texture Units,会被依次计算、应用到顶点。每个纹理单元有其独立的图像、Filter参数、坐标变换矩阵、坐标自动产生方法、Vertex-Array。
 
void glActiveTexture(GLenum texUnit)激活对应的纹理单元,之后所有的纹理操作都是针对这个纹理单元;参数GL_TEXTUREi,i取值0至k,最大值由具体实现决定。
 
此时glTexCoord相当于指定了GL_TEXTURE0的坐标,为其他单元指定坐标必须使用glMultiTexCoord。
 
 

9、纹理组合函数

接第六节,在使用单个或多个纹理单元时,纹理组合函数可以灵活控制fragment和纹理颜色的组合。组合函数可以操作3来源的颜色或alpha值进行计算,产生一个输出值。在使用多个纹理单元时,组合函数就形成了一个流水线。

 
void glTexEnv{if}(GLenum target, GLenum pname, TYPE param)对组合函数进行控制:target是GL_TEXTURE_ENV,pname是GL_TEXTURE_ENV_MODE,param是GL_DECAL, GL_REPLACE, GL_MODULATE,GL_BLEND, GL_ADD, or GL_COMBINE;当param是GL_COMBINE时,可以继续对组合函数进行配置。
 
通过pname=GL_COMBINE_RGB可以配置RGB部分的组合函数:GL_REPLACE, GL_MODULATE, GL_ADD,GL_ADD_SIGNED, GL_INTERPOLATE,GL_SUBTRACT, GL_DOT3_RGB, or GL_DOT3_RGBA;这些函数使用1至3个参数进行计算,这里分别表示为arg0,arg1,arg2。 于是GL_REPLACE可用表达式arg0表示,GL_ADD是arg0+arg1,GL_MODULATE是arg0*arg1。
 
上面arg0,arg1的来源可以通过pname=GL_SRC0_RGB,GL_SRC1_RGB,GL_SRC2_RGB来设定,param可以是GL_TEXTURE:纹理颜色值,GL_TEXTUREn:纹理单元n的颜色值,GL_CONSTANT:颜色常量,GL_PRIMARY_COLOR:fragement应用纹理之前的颜色,GL_PREVIOUS:前一轮组合函数的输出值,对于纹理单元0来说,等同于GL_PRIMARY_COLOR。一般来说我们把GL_SRC2_RGB(arg2)指定为常量,实际OpenGL默认就是这样的。
 
对于选定的颜色源,还可以指定使用它的哪一部分参与运算,pname=GL_OPERANDi_RGB,param可以是GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,  GL_SRC_ALPHA,  or  GL_ONE_MINUS_SRC_ALPHA,如果是GL_SRC_ALPHA,那么参与计算的RGB值就是(a,a,a)。pname=GL_OPERANDi_ALPHA,param可以是GL_SRC_ALPHA or GL_ONE_MINUS_SRC_ALPHA.
 
还可以设定一个scale因子,glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 1.0);glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0);

10、secondary color

上 一节中提到的primary color就是光照效果计算之后的fragment color,应用纹理后,雾效果之前,OpenGL可以给fragment增加一个secondary color以达到更逼真的高光效果。
 
没有光照的情况下,glSecondaryColor*()设置了颜色,glEnable(GL_COLOR_SUM)开启,则secondary color会被加到纹理之后的fragment上。
 
在有光照的情况下,将光照处理后的fragment颜色与纹理颜色组合后,会削弱高光效果。这时,可以在处理光照效果是计算两个颜色,一个叫primary color,没有包含specular分量,另一个就是secondary color,值就是specular分量。后者会在texture之后加到fragment。
 

11、Point Sprites

glPointSize()可以控制点的大小,但纯色的点显然不能满足要求,point sprite就是解决这个问题的。
 
可以对点图元里面的fragment应用纹理,需要调用glTexEnv*(GL_POINT_SPRITE, GL_COORD_REPLACE,GL_TRUE)激活这个功能。sprite的texture坐标s分量从在sprite最左侧fragement处为0,最右侧为1,线性增加,t分量增可以通过设置来改变方向,glPointParameter(GL_POINT_SPRITE_COORD_ORIGIN,GL_LOWER_LEFT or GL_UPPER_LEFT)。
 

12、Texture Matrix

就像顶点可以使用模型视图变换,纹理坐标也可以通过一个4x4的矩阵来进行变换。默认这个矩阵就是单位矩阵,调用glMatrixMode(GL_TEXTURE)后,就可以像操作模型矩阵一样操作纹理矩阵了。
 

13、Depth Texture

光照系统中,并没有为物体生成阴影,通过读取depth buffer作为texture,再加上多轮的渲染,可以生成阴影。
 
首先把视点移动到光源处,绘制场景,读取depth buffer作为texture保存。
 
第二次绘制场景,为图元生成纹理坐标,(s,t)用来引用texture的坐标位置,第三维度r则是顶点到光源的距离。
 
应用纹理时,比较fragment的纹理坐标r和texture (s,t)的值,可以决定对该fragment是否应用阴影纹理。

OpenGL编程指南第九章:纹理映射的更多相关文章

  1. Opengl编程指南第二章:状态管理、几何绘图

    //http://blog.csdn.net/longhuihu/article/details/7701874 1.绘图基础 清除窗口 glClearColor(0.0, 0.0, 0.0, 0.0 ...

  2. [转]OpenGL编程指南(第9版)环境搭建--使用VS2017

    1.使用CMake Configure中选择VS2017 Win64 , Finish: 点击Generate. 2.进入build目录 打开GLFW.sln , 生成解决方案. 打开vermilio ...

  3. OpenGL编程指南(第七版)

    OpenGL编程指南(第七版) 转自:http://blog.csdn.net/w540982016044/article/details/21287645 在接触OpenGL中,配置显得相当麻烦,特 ...

  4. VS15 openGL 编程指南 配置库 triangle例子

    最近去图书馆借了一本书<OpenGL编程指南(原书第八版)>,今天倒腾了一天才把第一个例子运行出来. 所以,给大家分享一下,希望能快速解决配置问题. 一.下载需要的库文件 首先,我们需要去 ...

  5. 编译opengl编程指南第八版示例代码通过

    最近在编译opengl编程指南第八版的示例代码,如下 #include <iostream> #include "vgl.h" #include "LoadS ...

  6. Knockout应用开发指南 第九章:高级应用举例

    原文:Knockout应用开发指南 第九章:高级应用举例 1   Contacts editor 这个例子和微软为演示jQuery Data Linking Proposal例子提供的例子一样的提供的 ...

  7. Java编程思想 第九章 接口

    第九章 接口 抽象类和抽象方法 抽象:从具体事物抽出.概括出它们共同的方面.本质属性与关系等,而将个别的.非本质的方面.属性与关系舍弃,这种思维过程,称为抽象. 这句话概括了抽象的概念,而在Java中 ...

  8. OpenGL编程指南(第九版) Tiangles 学习笔记

    ////////////////////////////////////////////////////////////////////////////// // // Triangles.cpp / ...

  9. opengl编程指南

    第一章 opengl简单介绍 1.1 什么是opengl opengl是图形硬件的一种软件接口.        1>渲染(rendering)是计算机依据模型创建图像的过程. 2>模型(m ...

随机推荐

  1. python __path__ 变量

    今天在读django源码的时候遇到了一个问题!它就是__path__这个系统变量 一.__path__变更初见: 由__path__这个变量的名字就知道,这个是一个系统变量,不是用户自定义的变量,于是 ...

  2. SimpleDateFormat线程不安全及解决的方法

    一. 为什么SimpleDateFormat不是线程安全的? Java源代码例如以下: /** * Date formats are not synchronized. * It is recomme ...

  3. scikit-learn:4.5. Random Projection

    參考:http://scikit-learn.org/stable/modules/random_projection.html The sklearn.random_projection modul ...

  4. CWidgetMgr---cpp

    #include "WidgetMgr.h" #include "XWidget.h" #include "Config.h" #inclu ...

  5. ognl概念和原理详解

    一.问题的提出   在mvc中,数据是在各个层次之间进行流转是一个不争的事实.而这种流转,也就会面临一些困境,这些困境,是由于数据在不同世界中的表现形式不同而造成的: 1. 数据在页面上是一个扁平的, ...

  6. spring oauth2相关资料

    理解OAuth 2.0  *****http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html Secure REST API with oauth2 ...

  7. SAP ECC6安装系列四:安装过程详解

    原作者博客 http://www.cnblogs.com/Michael_z/ ======================================== 续接上篇,我们终于按下了 “Next” ...

  8. AM335x 添加 HUAWEI MU609 Mini PCIe Module,并用pppd 启动相关设备

    kernel 的配置 kernel 3.2.0 make menuconfig Device Drivers ---> [*] USB support ---> <*> USB ...

  9. 确定文件的位置--浏览文件夹对话框folderBrowserDialog

    private void button1_Click(object sender, EventArgs e) { folderBrowserDialog1.ShowNewFolderButton = ...

  10. Java多线程之Lock的使用<转>

    import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util ...