OpenGL 纹理坐标 和 顶点坐标映射关系 详解

看了关于纹理坐标的但是感觉都没有说清楚 特整理如下:

参考文章:http://blog.csdn.NET/meegomeego/article/details/8295660

http://blog.csdn.Net/tiankefeng19850520/article/details/18620779?utm_source=tuicool&utm_medium=referral

http://blog.sina.com.cn/s/blog_62dfaf550100g2l1.html

http://blog.sina.com.cn/s/blog_62dfaf550100g2y4.html

http://blog.csdn.net/cjkwin/article/details/6016224

纹理坐标定义

在绘制纹理映射场景时,不仅要给每个顶点定义几何坐标,而且也要定义纹理坐标。经过多种变换后,几何坐标决定顶点在屏幕上绘制的位置,而纹理坐标决定纹理图像中的哪一个纹素赋予该顶点。并且顶点之间的纹理坐标插值与基础篇中所讲的平滑着色插值方法相同。
纹理图像是方形数组,纹理坐标通常可定义成一、二、三或四维形式,称为s,t,r和q坐标,以区别于物体坐标(x, y, z, w)和其他坐标。一维纹理常用s坐标表示,二维纹理常用(s, t)坐标表示,目前忽略r坐标。q坐标像w一样,一般情况下其值几乎均为1,主要用于建立齐次坐标。OpenGL坐标定义的函数是:
void gltexCoord{1234}{sifd}[v](TYPE coords);

  设置当前纹理坐标,此后调用glVertex*()所产生的顶点都赋予当前的纹理坐 标。对于gltexCoord1*(),s坐标被设置成给定值,t和r设置为0,q设置为1;用gltexCoord2*()可以设置s和t坐标值,r设 置为0,q设置为1;对于gltexCoord3*(),q设置为1,其它坐标按给定值设置;用gltexCoord4*()可以给定所有的坐标。使用适 当的后缀(s,i,f或d)和TYPE的相应值(GLshort、GLint、glfloat或GLdouble)来说明坐标的类型。注意:整型纹理坐标可以直接应用,而不是象普通坐标那样被映射到[-1, 1]之间。


1. 创建纹理图像

 

OpenGL要求纹理的高度和宽度都必须是2的n次方大小,只有满足这个条件,这个纹理图片才是有效的。     一旦获取了像素值,我们就可以将这些数据传给OpenGL,让OpenGL生成一个纹理贴图:

    glGenTextures(1,@Texture);
    glBindTexture(GL_TEXTURE_2D,Texture);
    glTexImage2D(GL_TEXTURE_2D,0,3,Bit.Width,Bit.Height,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);

   glGenTextures和glBindTexture函数用于创建和绑定纹理对象,glTexImage2D函数将Pixels数组中的像素值传给当前绑定的纹理对象,于是便创建了纹理。glTexImage函数的参数分别是纹理的类型,纹理的等级,每个像素的字节数,纹理图像的宽度和高度,边框大小,像素数据的格式,像素值的数据类型,像素数据。

2. OpenGL中的贴图方式

    OpenGL为我们提供了三种纹理——GL_TEXTURE_1D、GL_TEXTURE_2D和GL_TEXTURE_3D。它们分别表示1维纹理、2维纹理和3维纹理。无论是哪一中纹理,使用方法都是相同的:即先创建一个纹理对象和一个存储纹理数据的n维数组,在调用glTexImageN D函数来传入相应的纹理数据。除此之外,我们可以一些函数来设置纹理的其他特性。

2.1 设置贴图模式

    OpenGL提供了3种不同的贴图模式:GL_MODULATE,GL_DECAL和GL_BLEND。默认情况下,贴图模式是GL_MODULATE,在这种模式下,OpenGL会根据当前的光照系统调整物体的色彩和明暗。第二种模式是GL_DECAL,在这种模式下所有的光照效果都是无效的,OpenGL将仅依据纹理贴图来绘制物体的表面。最后是GL_BLEND,这种模式允许我们使用混合纹理。在这种模式下,我们可以把当前纹理同一个颜色混合而得到一个新的纹理。我们可以调用glTexEnvi函数来设置当前贴图模式:

    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,TextureMode);

    其中TextureMode就是想要设置的纹理模式,可以为GL_MODULATE,GL_DECAL和GL_BLEND中的任何一种。

    另外,对于GL_BLEND模式,我们可以调用

    glTexEnvfv(GL_TEXUTRE_ENV,GL_TEXTURE_ENV_COLOR,@ColorRGBA);

    其中,ColorRGBA为一个表示RGBA颜色的4维数组。

2.2 纹理滤镜

    在纹理映射的过程中,如果图元的大小不等于纹理的大小,OpenGL便会对纹理进行缩放以适应图元的尺寸。我们可以通过设置纹理滤镜来决定OpenGL对某个纹理采用的放大、缩小的算法

    调用glTexParameter来设置纹理滤镜。如:

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILETER, MagFilter);//设置放大滤镜
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, MinFilter); //设置缩小滤镜

   上述调用中,第一个参数表明是针对何种纹理进行设置,第二个参数表示要设置放大滤镜还是缩小滤镜。第三个参数表示使用的滤镜。可以为下面的值之一:

表6.3-1 可使用的纹理滤镜
滤镜 描述
GL_NEAREST 取最邻近像素
GL_LINEAR 线性内部插值
GL_NEAREST_MIPMAP_NEAREST 最近多贴图等级的最邻近像素
GL_NEAREST_MIPMAP_LINEAR 在最近多贴图等级的内部线性插值
GL_LINEAR_MIPMAP_NEAREST 在最近多贴图等级的外部线性插值
GL_LINEAR_MIPMAP_LINEAR 在最近多贴图等级的外部和内部线性插值

3 纹理映射

3.1 纹理坐标

    要使用当前的纹理绘制图元,我们必须在绘制每个顶点之前为该顶点指定纹理坐标。只需调用

    glTexCoord2d(s:Double;t:Double);

    函数即可。其中,s、t是对于2D纹理而言的s、t坐标。对于任何纹理,它的纹理坐标都如同下图所示(对于iOSGLKTextureInfo 默认参数而言!!!)的那样:

iOS GLKTextureInfo 默认 纹理S坐标 从左到右0-1 纹理T坐标从下到上0-1

OpenGL基本概念入门——纹理贴图

    对于任何纹理,无论纹理的真正大小如何,其顶端(左下角)的纹理坐标恒为(0,0),右上角的纹理坐标恒为(1,1)。也就是说,纹理坐标应是一个介于0到1之间的一个小数。

这里的坐标由:

下面的参数决定在iOS 的 GLKTextureInfo 中 

GLKTextureInfo *textureInfo = [GLKTextureLoadertextureWithContentsOfFile:filePathoptions:optionserror:nil];

默认值为 所以对于iOS 中  GLKTextureInfo 默认的纹理坐标是 T坐标从下到上为0-1 S坐标为从左至右为0-1

 GL_TEXTURE_WRAP_S / GL_TEXTURE_WRAP_T: GL_CLAMP_TO_EDGE

 Any texture parameter not specified above will be set to OpenGL's default value.


glTexParameter*()函数的参数

参数(pname)值(param)
GL_TEXTURE_WRAP_S
从左至右纹理环绕模式
GL_TEXTURE_WRAP_T
从下至上纹理环绕模式
GL_TEXTURE_WRAP_R
从里至外纹理环绕模式
GL_CLAMP:截取
GL_REPEAT:重复
GL_MIRRORED_REPEAT:镜像重复
GL_CLAMP_TO_EDGE:忽略边框截取
GL_CLAMP_TO_BORDER:代边框的截取
GL_TEXTURE_MAG_FILTERGL_NEAREST或GL_LINEAR
GL_TEXTURE_MIN_FILTERGL_NEAREST 速度快,效果差
GL_LINEAR  计算量大。效果好
GL_NEAREST_MIPMAP_NEAREST 速度快,效果差
GL_LINEAR_MIPMAP_NEAREST
GL_NEAREST_MIPMAP_LINEAR
GL_LINEAR_MIPMAP_LINEAR 计算量大。效果好
GL_TEXTURE_BORDER_COLOR
GL_TEXTURE_PRIORITY(0,1)纹理优先级
GL_TEXTURE_BASE_LEVEL浮点值
GL_TEXTURE_MAX_LEVEL浮点值
GL_TEXTURE_MIN_LOD浮点值
GL_TEXTURE_MAX_LEVEL浮点值
GL_TEXTURE_LOD_BIAS
GL_TEXTURE_COMPARE_MODE
纹理比较模式
GL_COMPARE_R_TO_TEXTURE 深度比较
GL_DEPTH_TEXTURE_MODEGL_RED:R
GL_LUMINANCE:亮度
GL_INSENSITY
GL_ALPHA:A
GL_TEXTURE_COMPARE_FUNC
纹理比较方式
GL_LEQUAL,GL_GEQUAL,GL_LESS,GL_GREATER,GL_EQUAL,
GL_NOTEQUAL,GL_ALWAYS,GL_NEVER
GL_GENERATE_MIAMAP
自动生成多重细节层
GL_TRUE,GL_FALSE



3.2 纹理缠绕

    前面提到,纹理坐标应位于0-1之间。那么当纹理坐标大于这个值会出现什么情况呢?

    我们可以对OpenGL进行设置,以决定当纹理坐标不位于这一区间时应采取的操作。我们可以指定两种操作:GL_CLAMP和GL_REPEAT。对于GL_CLAMP,超出纹理坐标的区域会使用纹理图像的边界颜色来代替,如图6.4-2所示。

OpenGL基本概念入门——纹理贴图2

    而GL_REPEAT方式则是对纹理坐标进行重置而得到重复的图像。观察图6.4-3,你就能很容易地发现这一点。

 

OpenGL基本概念入门——纹理贴图2

    可以调用glTexParameter设置缠绕方式:

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,WrapMode);//在s方向上的缠绕方式
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,WrapMode);//在t方向上的缠绕方式

    其中,WrapMode可取GL_CLAMP或者GL_REPEAT。

4.纹理对象

创建和使用文理对象

    在OpenGL中,我们使用glGenTextures创建纹理对象:

    glGenTextures(Count:Integer;TexObjs:Pointer);

    其中,Count是我们要创建的纹理数目,当我们只想创建一个纹理时,只需调用

    var Texture:GLUint;
    ...
    glGenTextures(1,@Texture);

    这样,Texture变量中就存储了我们创建的纹理的ID号。

    创建之后,我们使用glBindTexture将创建的纹理绑定到当前纹理。这样所有的纹理函数都将针对当前纹理。

    glBindTexture(Texture:GLUint);

    这样,我们就可以调用glTexParameter、glTexImage2D等函数来设置这个纹理对象了。

删除纹理对象

    在纹理资源使用完毕后(一般是程序退出或场景转换时),一定要删除纹理对象,释放资源。

    调用

    glDeleteTextures(Count:Integer;TexObj:Pointer);

    来删除纹理对象。例如

    glDeleteTextures(1,@Texture);

5. 多贴图纹理

    多贴图纹理(Mip Mapping)为一个纹理对象生成不同尺寸的图像。在需要时,根据绘制图形的大小来决定采用的纹理等级或者在不同的纹理等级之间进行线性内插。使用多贴图纹理的好处在于消除纹理躁动。这种情况在所绘制的景物离观察者较远时常常发生(如图6.6-1和6.6-2)。由于多贴图纹理现在的渲染速度已经很快,以至于和普通纹理没有什么区别,我们现在一般都使用多贴图纹理。

 

                                         OpenGL基本概念入门——纹理贴图2

    使用多贴图纹理并不麻烦。首先,我们需要创建不同等级(尺寸)的纹理图片。我们需要调用n次glTexImage2D函数,生成不同等级的纹理贴图。例如:
   
 glTexImage2D(GL_TEXTURE_2D,0,3,8,8,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
    glTexImage2D(GL_TEXTURE_2D,1,3,4,4,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
    glTexImage2D(GL_TEXTURE_2D,2,3,2,2,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
    glTexImage2D(GL_TEXTURE_2D,3,3,1,1,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);

    这些函数调用的第二个参数表示当前纹理的等级。0级的分辨率最大。之后,每一级的分辨率是上一级分辨率的一半。这样的函数调用应一直进行下去,直至图像的高度和宽度都为1。

    但有时候,这样做总并不是很方便。我们可以借助一个glu函数帮我们自动生成这些多贴图纹理。只需要把生成纹理图像的函数调用由glTexImage2D改为gluBuild2DMipMaps即可:

    gluBuild2DMipMaps(GL_TEXTURE_2D,3,Bit.Width,Bit.Height,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);

    此外,还必须把纹理的滤镜改为MIP_MAP滤镜。例如:

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);


©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页