什么是纹理(Texture)?
概念
通常说的纹理,指的是一张二维的图片 ,把它像贴纸一样贴在图元上面,让图元看起来像贴纸所要表现的效果那样;
艺术家和程序员更喜欢使用纹理(Texture)。纹理是一个2D图片(甚至也有1D和3D的纹理),它可以用来添加物体的细节;可以想象成纹理是一张绘有砖块的纸,无缝折叠贴合到3D的房子上,这样房子看起来就像有砖墙外表了。因为可以在一张图片上插入非常多的细节,这样就可以让物体非常精细而不用指定额外的顶点。
除了图像以外,纹理也可以被用来储存大量的数据 ,这些数据可以发送到着色器上;
纹理坐标
加载纹理只是在几何图形上应用纹理的第一步,最低限度必须同时提供纹理坐标,并设置纹理坐标环绕模式和纹理过滤 ;
可以选择对纹理进行Mip贴图,以提高纹理贴图性能和/或视觉质量;
范围:x和y轴上0到1 之间的范围(2D纹理图片);
采样(Sampling):使用纹理坐标获取纹理颜色;
起止:纹理坐标起始于(0,0)也就是纹理图片的左下角,终结于纹理图片的右上角(1,1);
纹理坐标用s、t、r、q 表示,一一对应顶点坐标的x、y、z、w,实际就是映射关系;
OpenGL像素的格式和数据类型
像素格式
描述说明
GL_RGB
描述红、绿、蓝顺序排列的颜⾊
GL_RGBA
按照红、绿、蓝、Alpha顺序排列的颜⾊
GL_BGR
按照蓝、绿、红顺序排列颜⾊
GL_BGRA
按照蓝、绿、红、Alpha顺序排列颜⾊
GL_RED
每个像素只包含了⼀个红⾊分量
GL_GREEN
每个像素只包含了⼀个绿⾊分量
GL_BLUE
每个像素只包含了⼀个蓝⾊分量
GL_RG
每个像素依次包含了一个红色和绿色的分量
GL_RED_INTEGER
每个像素包含了一个整数形式的红⾊分量
GL_GREEN_INTEGER
每个像素包含了一个整数形式的绿色分量
GL_BLUE_INTEGER
每个像素包含了一个整数形式的蓝色分量
GL_RG_INTEGER
每个像素依次包含了一个整数形式的红⾊、绿⾊分量
GL_RGB_INTEGER
每个像素包含了一个整数形式的红⾊、蓝⾊、绿色分量
GL_RGBA_INTEGER
每个像素包含了一个整数形式的红⾊、蓝⾊、绿⾊、Alpah分量
GL_BGR_INTEGER
每个像素包含了一个整数形式的蓝⾊、绿⾊、红色分量
GL_BGRA_INTEGER
每个像素包含了一个整数形式的蓝⾊、绿⾊、红色、Alpah分量
GL_STENCIL_INDEX
每个像素只包含了一个模板值
GL_DEPTH_COMPONENT
每个像素只包含一个深度值
GL_DEPTH_STENCIL
每个像素包含一个深度值和一个模板值
像素数据类型
说明
GL_UNSIGNED_BYTE
每种颜色分量都是一个8位无符号整数
GL_BYTE
8位有符号整数
GL_UNSIGNED_SHORT
16位无符号整数
GL_SHORT
16位有符号整数
CL_UNSIGNED_INT
32位无符号整数
GL_INT
32位有符号整数
GL_FLOAT
单精度浮点数
GL_HALF_FLOAT
半精度浮点数
GL_UNSIGNED_BYTE_3_2_3
包装的RGB值
GL_UNSIGNED_BYTE_2_3_3_REV
包装的RGB值
GL_UNSIGNED_SHORT_5_6_5
包装的RGB值
GL_UNSIGNED_SHORT_5_6_5_REV
包装的RGB值
GL_UNSIGNED_SHORT_4_4_4_4
包装的RGB值
GL_UNSIGNED_SHORT_4_4_4_4_REV
包装的RGB值
GL_UNSIGNED_SHORT_5_5_5_1
包装的RGB值
GL_UNSIGNED_SHORT_1_5_5_5_REV
包装的RGB值
GL_UNSIGNED_INT_8_8_8_8
包装的RGB值
GL_UNSIGNED_INT_8_8_8_8_REV
包装的RGB值
GL_UNSIGNED_INT_10_10_10_2
包装的RGB值
GL_UNSIGNED_INT_2_10_10_10_REV
包装的RGB值
GL_UNSIGNED_INT_24_8
包装的RGB值
GL_UNSIGNED_INT_10F_11F_REV
包装的RGB值
GL_FLOAT_24_UNSIGNED_INT_24_8_REV
包装的RGB值
UNSIGNED_BYTE_3_3_2,表示8位中3个分量占的个数,第一个分量3、第二个分量3、第三个分量2;UNSIGNED_BYTE_2_3_3_REV,表示8位中3个分量占的个数,但分量是反过来的,第一个分量2、第二个分量3、第三个分量3。
纹理常用API
常用函数
void glPixelStorei ( GLenum pname, GLint param) ;
void glPixelStoref ( GLenum pname, GLfloat param) ;
glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 ) ;
void glReadPixels ( GLint x, GLint y, GLSizei width, GLSizei
height, GLenum format, GLenum type, const void * pixels) ;
glReadBuffer ( mode) ; —> 指定读取的缓存
glWriteBuffer ( mode) ; —> 指定写⼊入的缓存
void glTexImage1D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, void * data) ;
void glTexImage2D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, void * data) ;
void glTexImage3D ( GLenum target, GLint level, GLint internalformat, GLSizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, void * data) ;
void glTexSubImage1D ( GLenum target, GLint level, GLint xOffset, GLsizei width, GLenum format, GLenum type, const GLvoid * data) ;
void glTexSubImage2D ( GLenum target, GLint level, GLint xOffset, GLint yOffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid * data) ;
void glTexSubImage3D ( GLenum target, GLint level, GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width, GLsizei height, GLsizei depth, Glenum type, const GLvoid * data) ;
void glCopyTexSubImage1D ( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsize width) ;
void glCopyTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yOffset, GLint x, GLint y, GLsizei width, GLsizei height) ;
void glCopyTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yOffset, GLint zOffset, GLint x, GLint y, GLsizei width, GLsizei height) ;
void glCopyTexImage1D ( GLenum target, GLint level, GLenum internalformt, GLint x, GLint y, GLsizei width, GLint border) ;
void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformt, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) ;
纹理对象
一、生成纹理对象
void glGenTextures ( GLsizei n, GLuint * textTures) ;
void glBindTexture ( GLenum target, GLunit texture) ;
void glDeleteTextures ( GLsizei n, GLuint * textures) ;
GLboolean glIsTexture ( GLuint texture) ;
二、设置纹理参数
glTexParameterf ( GLenum target, GLenum pname, GLFloat param) ;
glTexParameteri ( GLenum target, GLenum pname, GLint param) ;
glTexParameterfv ( GLenum target, GLenum pname, GLFloat * param) ;
glTexParameteriv ( GLenum target, GLenum pname, GLint * param) ;
三、设置过滤方式
过滤方式
说明
GL_NEAREST_MIPMAP_NEAREST
使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样
GL_LINEAR_MIPMAP_NEAREST
使用最邻近的多级渐远纹理级别,并使用线性插值进行采样
GL_NEAREST_MIPMAP_LINEAR
在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样
GL_LINEAR_MIPMAP_LINEAR
在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样
邻近过滤(GL_NEAREST)
线性过滤(GL_LINEAR)
两种纹理过滤⽅式⽐较
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
不能将放大过滤的选项设置为多级渐远纹理过滤选项之一 ,这样没有任何效果,因为多级渐远纹理主要是使用在纹理被缩小 的情况下的:纹理放大不会使用多级渐远纹理 ,为放大过滤设置多级渐远纹理的选项会产生一个GL_INVALID_ENUM错误代码。
四、设置环绕方式
环绕方式
描述说明
GL_REPEAT
对纹理的默认行为,重复纹理图像
GL_MIRRORED_REPEAT
和GL_REPEAT一样,但每次重复图片是镜像放置的
GL_CLAMP_TO_EDGE
纹理坐标会被约束到0和1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果
GL_CLAMP_TO_BORDER
超出的坐标为用户指定的边缘颜色
当纹理坐标超出默认范围时,每个选项都有不同的视觉效果输出,来看下面的效果对比:
glTextParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAR_S, GL_CLAMP_TO_EDGE) ;
glTextParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAR_T, GL_CLAMP_TO_EDGE) ;
Mip贴图(Mipmapping)
所谓mipmaps,就是一系列的纹理图片,每一张纹理图的大小都是前一张的1/4,直到剩最后一个像素为止;
Mipmapping是一个功能强大的纹理技术,它可以提高渲染的性能以及提升场景的视觉质量 ,它可以用来解决一般纹理贴图出现的两个常见问题: ① 闪烁 ,当屏幕上被渲染物体的表面与它所应用的纹理图像相比显得非常小时,就会出现闪烁,尤其当相机和物体在移动的时候,这种负面效果更容易出现。 ② 性能问题,加载了大量纹理数据之后,还要对其缩小,在屏幕上显示的只是一小部分,纹理越大,所造成的影响越大 ;
mipmap是把纹理按照2的倍数进行缩放,直到图像1x1的大小,然后把这些图都存储起来,当要使用就选择一个合适的图像。但是这会增加一些额外的内存,在正方形的纹理贴图中使用mipmap技术,大概要比原来多出三分之一的内存空间;
设置Mip 贴图
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0 ) ;
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0 ) ;
常量
描述
GL_NEAREST
在Mip基层上执⾏最邻近过滤
GL_LINEAR
在Mip基层执⾏线性过滤
GL_NEAREST_MIPMAP_NEAREST
在最邻近Mip层,并执⾏最邻近过滤
GL_NEAREST_MIPMAP_LINEAR
在Mip层之间执⾏线性插补,并执行最邻近过滤
GL_LINEAR_MIPMAP_NEAREST
选择最邻近Mip层,并执行线性过滤
GL_LINEAR_MIPMAP_LINEAR
在Mip层之间执⾏线性插补,并执行线性过滤,⼜称三线性Mip贴图
压缩纹理
压缩格式
基本内部格式
GL_COMPRESSED_RGB
GL_RGB
GL_COMPRESSED_RGBA
GL_RGBA
GL_COMPRESSED_SRGB
GL_RGB
GL_COMPRESSED_SRGB_ALPHA
GL_RGBA
GL_COMPRESSED_RED
GL_RED
GL_COMPRESSED_RG
GL_RG
glHint ( GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST) ;
glHint ( GL_TEXTURE_COMPRESSION_HINT, GL_NICEST) ;
glHint ( GL_TEXTURE_COMPRESSION_HINT, GL_DONT_CARE) ;
void glCompressedTexImage1D ( GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imageSize, void * data) ;
void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLint heigth, GLint border, GLsizei imageSize, void * data) ;
void glCompressedTexImage3D ( GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei heigth, GLsizei depth, GLint border, GLsizei imageSize, void * data) ;
glGetTexLevelParameter函数提取的压缩纹理格式
参数
返回
GL_TEXTURE_COMPRESSED
如果纹理被压缩,返回1,否则返回0
GL_TEXTURE_COMPRESSED_IMAGE_SIZE
压缩后的纹理的⼤小(以字节为单位)
GL_TEXTURE_INTERNAL_FORMAT
所使⽤的压缩格式
GL_NUM_COMPRESSED_TEXTURE_FORMATS
受⽀持的压缩纹理格式数量
GL_COMPRESSED_TEXTURE_FORMATS
⼀个包含了一些常量值的数组,每个常量值对应于⼀种受⽀持的压缩纹理格式
GL_TEXTURE_COMPRESSION_HINT
压缩纹理理提示的值(GL/NICEST/GL_FASTEST)
GL_EXT_texture_compression_s3tc压缩格式
格式
描述
GL_COMPRESSED_RGB_S3TC_DXT1
RGB数据被压缩,alpha值始终是1.0
GL_COMPRESSED_RGBA_S3TC_DXT1
RGBA数据被压缩,alpha值返回1.0或者0.0
GL_COMPRESSED_RGAB_S3TC_DXT3
RGB值被压缩,alpha值⽤用4位存储
GL_COMPRESSED_RGBA_SETC_DXT5
RGB数据被压缩,alpha值是⼀些8位值的加权平均值
纹理使用示例:“金字塔”纹理渲染
“金字塔”的纹理坐标解析
三角形X的坐标如下:vBackLeft(-1.0,-1.0,-1.0),vBackRight(1.0,-1.0,-1.0),vFrontRight(1.0,-1.0,1.0);
三角形Y的坐标如下:vBackLeft(-1.0,-1.0,-1.0),vFrontRight(1.0,-1.0,1.0),vFrontLeft(-1.0,-1.0,1.0);
顶点坐标为:vBackLeft(-1.0,-1.0,-1.0),vBackRight(1.0,-1.0,-1.0),vFrontLeft(-1.0,-1.0,1.0),vFrontRight(1.0,-1.0,1.0),vApex(0,1.0,0);
对应的纹理坐标为:vBackLeft(0,0),vBackRight(1,0),vFrontLeft(0,1),vFrontRight(1.0,1.0),vApex(0.5,1);
在SetupRC中分配绑定纹理 :
glGenTextures ( 1 , & textureID) ;
glBindTexture ( GL_TEXTURE_2D, textureID) ;
LoadTGATexture ( "stone.tga" , GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, GL_CLAMP_TO_EDGE) ;
MakePyramid ( pyramidBatch) ;
cameraFrame. MoveForward ( - 8.f ) ;
bool LoadTGATexture ( const char * szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode) {
GLbyte * pBits;
int width, height, componentes;
GLenum eFormat;
pBits = gltReadTGABits ( szFileName, & width, & height, & componentes, & eFormat) ;
if ( pBits == NULL ) {
return false;
}
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode) ;
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode) ;
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter) ;
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter) ;
glTexImage2D ( GL_TEXTURE_2D, 0 , componentes, width, height, 0 , eFormat, GL_UNSIGNED_BYTE, pBits) ;
free ( pBits) ;
if ( minFilter == GL_LINEAR_MIPMAP_LINEAR ||
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
minFilter == GL_NEAREST_MIPMAP_LINEAR ||
minFilter == GL_NEAREST_MIPMAP_NEAREST) {
glGenerateMipmap ( GL_TEXTURE_2D) ;
}
return 1 ;
}
void MakePyramid ( GLBatch& pyramidBatch) {
pyramidBatch. Begin ( GL_TRIANGLES, 18 , 1 ) ;
M3DVector3f vApex = { 0.0f , 1.0f , 0.0f } ;
M3DVector3f vFrontLeft = { - 1.0f , - 1.0f , 1.0f } ;
M3DVector3f vFrontRight = { 1.0f , - 1.0f , 1.0f } ;
M3DVector3f vBackLeft = { - 1.0f , - 1.0f , - 1.0f } ;
M3DVector3f vBackRight = { 1.0f , - 1.0f , - 1.0f } ;
pyramidBatch. MultiTexCoord2f ( 0 , 0.0f , 0.0f ) ;
pyramidBatch. Vertex3fv ( vBackLeft) ;
pyramidBatch. MultiTexCoord2f ( 0 , 1.0f , 0.0f ) ;
pyramidBatch. Vertex3fv ( vBackRight) ;
pyramidBatch. MultiTexCoord2f ( 0 , 1.0f , 1.0f ) ;
pyramidBatch. Vertex3fv ( vFrontRight) ;
pyramidBatch. MultiTexCoord2f ( 0 , 0.0f , 1.0f ) ;
pyramidBatch. Vertex3fv ( vFrontLeft) ;
pyramidBatch. MultiTexCoord2f ( 0 , 0.0f , 0.0f ) ;
pyramidBatch. Vertex3fv ( vBackLeft) ;
pyramidBatch. MultiTexCoord2f ( 0 , 1.0f , 1.0f ) ;
pyramidBatch. Vertex3fv ( vFrontRight) ;
pyramidBatch. MultiTexCoord2f ( 0 , 0.5f , 1.0f ) ;
pyramidBatch. Vertex3fv ( vApex) ;
pyramidBatch. MultiTexCoord2f ( 0 , 0.0f , 0.0f ) ;
pyramidBatch. Vertex3fv ( vFrontLeft) ;
pyramidBatch. MultiTexCoord2f ( 0 , 1.0f , 0.0f ) ;
pyramidBatch. Vertex3fv ( vFrontRight) ;
pyramidBatch. MultiTexCoord2f ( 0 , 0.5f , 1.0f ) ;
pyramidBatch. Vertex3fv ( vApex) ;
pyramidBatch. MultiTexCoord2f ( 0 , 1.0f , 0.0f ) ;
pyramidBatch. Vertex3fv ( vBackLeft) ;
pyramidBatch. MultiTexCoord2f ( 0 , 0.0f , 0.0f ) ;
pyramidBatch. Vertex3fv ( vFrontLeft) ;
pyramidBatch. MultiTexCoord2f ( 0 , 0.5f , 1.0f ) ;
pyramidBatch. Vertex3fv ( vApex) ;
pyramidBatch. MultiTexCoord2f ( 0 , 1.0f , 0.0f ) ;
pyramidBatch. Vertex3fv ( vFrontRight) ;
pyramidBatch. MultiTexCoord2f ( 0 , 0.0f , 0.0f ) ;
pyramidBatch. Vertex3fv ( vBackRight) ;
pyramidBatch. MultiTexCoord2f ( 0 , 0.5f , 1.0f ) ;
pyramidBatch. Vertex3fv ( vApex) ;
pyramidBatch. MultiTexCoord2f ( 0 , 0.0f , 0.0f ) ;
pyramidBatch. Vertex3fv ( vBackRight) ;
pyramidBatch. MultiTexCoord2f ( 0 , 1.0f , 0.0f ) ;
pyramidBatch. Vertex3fv ( vBackLeft) ;
pyramidBatch. End ( ) ;
}
glBindTexture ( GL_TEXTURE_2D, textureID) ;
shaderManager. UseStockShader ( GLT_SHADER_TEXTURE_REPLACE, transformPipeline. GetModelViewProjectionMatrix ( ) , 0 ) ;
pyramidBatch. Draw ( ) ;