第十六节—纹理常用API
本文为L_Ares个人写作,包括图片皆为个人亲自操作,以任何形式转载请表明原文出处。
之前的学习中绘制图形全部都是使用的颜色来渲染的,但是实际的需求中很多都是需要图片来进行渲染,本节的纹理就是可以利用图片将图形的外观发生改变。
首先,我们学习拿一张图片作为纹理。先了解一张图片的存储空间是怎么计算的:
一张图片的存储空间 = 图片的宽 * 图片的高 * 每个像素的字节数
OpenGL中纹理图片需要.tga
格式的文件,.tga
格式的文件存储方式是1个字节1个字节的存储,这样更节约存储空间。
下面开始介绍一些OpenGL中常用的纹理相关的函数。
1. 改变像素存储的方式
void glPixelStorei(GLenum pname,GLint param);
2. 回复像素存储的方式
void glPixelStoref(GLenum pname,GLint param);
以上两个了解即可,一般不需要做出改变。
3. 读取像素
将颜色缓存区的内容作为像素图直接读取
void glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
参数:
x
: 从哪个位置开始读取,x坐标,一般选择矩形左下角的窗口坐标。
y
: 从哪个位置开始读区,y坐标,一般选择矩形左下角的窗口坐标。
width
: 读取的这张图片的宽是多少,矩形的宽,以像素为单位。
height
: 读取的这张蹄片的高是多少,矩形的高,以像素为单位。
format
: 读取图片要用的像素模式。详情见下图1.1。(用的一般都是RGBA)
type
: 解释下一个参数pixels指向的数据,就是选择颜色缓存区中的哪种数据类型来存储颜色分量。也就是像素数据的数据类型,详见下图1.2。
*pixels
: 指向图形数据的指针。就是你要把数据读取到哪里。
备注:
用的很少。
可以指定读取的缓存:glReadBuffer(mode);
可以指定写入的缓存:glWriteBuffer(mode);
4. 载入纹理
载入一维纹理(很少用):
void glTexImage1D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
载入二维纹理(常用):
void glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
载入三维纹理(很少用):
void glTexImage3D (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
载入二维纹理的参数:
target
: 给定一个标记,确定要载入几维的纹理。GL_TEXTURE_1D
,GL_TEXTURE_2D
,GL_TEXTURE_3D
level
: 指定所加载的mip贴图层次。纹理是可以堆叠的,一般都一张不堆叠,所以一般都设置成0,但是可以设置纹理在第几层。
internalFormat
: 每个纹理单元中存储多少颜色成分。
width
: 加载纹理的宽度。老版OpenGL这个数值必须是2的整数次方,现在没这个规定了,但是大家还是按照老规矩来做了。
height
: 加载纹理的高度。要求同上
border
: 允许为纹理贴图添加一个边框,给定一个边界限度,一般没人用。
format
: 载入纹理要用的像素模式。详见图1.1
type
: 像素数据的数据类型。详见图1.2
*pixels
: 指向纹理图像数据的指针。就是你要把数据载入到哪里。
5. 更新纹理
更新一维纹理(很少用):
void glTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
更新二维纹理(常用):
void glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
更新三维纹理(很少用):
void glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
参数和载入纹理是一样的意思,唯独增加了xoffset
和yoffset
,这个很明显是偏移量。
6. 插入替换纹理
插入替换一维纹理(很少用):
void glCopyTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei 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);
参数也是和载入纹理一样的意思,offset也是偏移量,而GLSizei
数据类型的参数表示的是更新多大的纹理,更新的纹理的位置坐标。
7. 复制纹理
复制一维纹理:
void glCopyTexImage1D (GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border);
复制二维纹理:
void glCopyTexImage2D (GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
没有复制三维纹理,因为无法从2D颜色缓存区中读取到体积这种变量。
这里的x,y指的是在颜色缓存区中,开始读取纹理数据的位置。
8. 纹理对象
这几个函数是一定要写的,都是固定的,记下来就好了。
- 分配纹理对象。
指定纹理对象的数量(n)和指针(*textures),指针指向的是无符号整型数组,由纹理对象标识符填充。
void glGenTextures (GLsizei n, GLuint *textures);
- 绑定纹理状态
void glBindTexture (GLenum target, GLuint texture);
参数:
target: GL_TEXTURE_1D
,GL_TEXTURE_2D
,GL_TEXTURE_3D
texture: 需要绑定的纹理对象。
- 删除绑定纹理对象
纹理对象以及纹理对象指针,指针指向一个无符号纹理对象数组,由纹理对象标示符填充。
void glDeleteTextures (GLsizei n, const GLuint *textures);
- 测试纹理对象是否有效
判断依据就是上面指定的标识符,也就是如果texture是一个已经分配了空间的纹理对象,那么这个函数就会返回GL_TRUE
,否则返回GL_FALSE
GLboolean glIsTexture (GLuint texture);
9. 设置纹理的相关参数
void glTexParameterf (GLenum target, GLenum pname, GLfloat param);
void glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params);
void glTexParameteri (GLenum target, GLenum pname, GLint param);
void glTexParameteriv (GLenum target, GLenum pname, const GLint *params);
参数:
target
: 指定这些参数要使用在哪种纹理模式上。GL_TEXTURE_1D
,GL_TEXTURE_2D
,GL_TEXTURE_3D
pname
: 你想设置纹理的哪一个属性。指定要设置的纹理参数名。
param
: 你想设置的纹理的那个属性要设置的值。指定纹理参数值。
10. 设置过滤方式
纹理有两种过滤方式,如下图所示的图1.3是邻近过滤(GL_NEAREST),如图1.4是线性过滤(GL_LINEAR)
1.3.png 1.4.png邻近过滤取的是离该像素点最近的颜色的值,而线性过滤取的是该像素点周围颜色的综合值(混合),纹理坐标在哪里,哪个颜色的值占比就多一点。
一般情况下,当纹理缩小时,选择使用邻近过滤:
glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
当纹理放大的时候,选择使用线性过滤
glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_ LINEAR);
当然这个只是建议,可以随意设置。
11. 设置环绕方式
当纹理坐标超出了默认范围时,可以选择不同的环绕方式来填充。一共有四种环绕方式,如下图1.5所示:
1.5.png举例一下:
void glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
参数:
target
: 指定这些参数要使用在哪种纹理模式上。GL_TEXTURE_1D
,GL_TEXTURE_2D
,GL_TEXTURE_3D
pname
:这里用的是str坐标,设置对应轴上的环绕方式,s对应x,t对应y,r对应z,q对应w ,可以选择:GL_TEXTURE_WRAP_S
,GL_TEXTURE_WRAP_T
,GL_TEXTURE_WRAP_R
。
param
: 如图1.5,自己选一个。
总结一下本节,一定要记住一套API:
- 读取文件
2.载入纹理
3.纹理对象
本节关于OpenGL的API的学习就到此结束。