OpenGL纹理API简介

2019-06-15  本文已影响0人  瀚_

纹素和纹理坐标

纹理对象通常是通过纹理图片读取到的,这个数据保存到一个二维数组中,这个数组中的元素成为纹素(texel),纹素包含颜色值和alpha值。纹理对象的大小的宽度和高度应该为2的整数幂,例如16,32,64。要想获取纹理对象中的纹素,需要使用纹理坐标(texture coordinate)指定。

纹理坐标应该与纹理对象大小无关,这样指定的纹理坐标当纹理对象大小变更时,依然能够工作,比如从256x256大小的纹理,换到512x256时,纹理坐标依然能够工作。因此纹理坐标使用规范化的值,大小范围为[0,1],纹理坐标使用uv表示,如下图所示:


纹理坐标.png

通过指定纹理坐标,可以映射到纹素。例如一个256x256大小的二维纹理,坐标(0.5,1.0)对应的纹素即是(128,256)。

纹理映射时只需要为物体的顶点指定纹理坐标即可,其余部分由片元着色器插值完成,如下图所示:


纹理映射.png

纹素到像素转换问题

Mipmaps

当物体在场景中离观察者很远,最终只用一个屏幕像素来显示时,这个像素该如何通过纹素确定呢?如果使用最近邻滤波来获取这个纹素,那么显示效果并不理想。需要使用纹素的均值来反映物体在场景中离我们很远这个效果,对于一个 256×256的纹理,计算平均值是一个耗时工作,不能实时计算,因此可以通过提前计算一组这样的纹理用来满足这种需求。这组提前计算的按比例缩小的纹理就是Mipmaps。Mipmaps纹理大小每级是前一等级的一半,按大小递减顺序排列为:

OpenGL中通过函数glGenerateMipmap(GL_TEXTURE_2D);来生成Mipmap,前提是已经指定了原始纹理。
如果直接在不同等级的MipMap之间切换,会形成明显的边缘,因此对于Mipmap也可以同纹素一样使用滤波方法在不同等级的Mipmap之间滤波。要在不同等级的MipMap之间滤波,需要将之前设置的GL_TEXTURE_MIN_FILTER选项更改为以下选项之一:

使用使用glGenerateMipmap(GL_TEXTURE_2D)产生Mipmap的前提是你已经加载了原始的纹理对象。使用MipMap时设置GL_TEXTURE_MIN_FILTER选项才能起作用,设置GL_TEXTURE_MAG_FILTER的Mipmap选项将会导致无效操作,OpenGL错误码为GL_INVALID_ENUM。

片元着色器中使用纹理对象

在顶点着色器中我们传递了纹理坐标,有了纹理坐标,获取最终的纹素使用是在片元着色器中完成的。由于纹理对象通过使用uniform变量来向片元着色器传递,实际上这里传递的是对应纹理单元(texture unit)的索引号。纹理单元、纹理对象对应关系如下图所示:


纹理单元和纹理对象对应关系图.png

着色器通过纹理单元的索引号索引纹理单元,每个纹理单元可以绑定多个纹理到不同的目标(1D,2D)。OpenGL可以支持的纹理单元数目,一般至少有16个,依次为GL_TEXTURE0 到GL_TEXTURE15,纹理单元最大支持数目可以通过查询GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS常量获取。这些常量值是按照顺序定义的,因此可以采用 GL_TEXTURE0 + i 的形式书写常量,其中整数i在[0, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)范围内。

纹理对象不仅包含纹理数据,还包含采样参数,这些采样参数称之为采样状态(sampling state)。而采样对象(sampler object)就是只包含采样参数的对象,将它绑定到纹理单元时,它会覆盖纹理对象中的采样状态,从而重新配置采样方式。

要使用纹理必须在使用之前激活对应的纹理单元,默认状态下0号纹理单元是激活的,因此即使没有显式地激活也能工作。激活并使用纹理的代码如下:

        ```
        glActiveTexture(GL_TEXTURE0)
        ```

纹理API

void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);

format: 像素格式
type: 解释参数pixels指向的数据,告诉OpenGL使用缓存区中的什么数据类型来存储颜色分量。像素数据的数据类型
pixels: 图形数据指针
像素格式.png 像素数据的数据格式.png
GLbyte *gltReadTGABits(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat);

szFileName: 纹理文件名
iWidth: 宽度地址
iHeight: 高度地址
iComponents: 组件地址
eFormat: 格式地址
void glTextImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, void *data)

target: `GLTETURE_1D`  `GL_TEXTURE_2D`  `GL_TEXTURE_3D`
level:  指定所加载的mip贴图层次,一般设置为0
internalformat: 每个纹理单元中存储多少颜色成分
format: 像素格式(如: GL_RGBA)
type: 像素数据的数据类型(GL_UNSIGNED_BYTE, 每个颜色分量都是一个8位无符号整数)
data: 指向纹理图像数据的指针
glTexParameteri(GLenum target, GLenum pname, GLint param);

参考:
https://blog.csdn.net/wangdingqiaoit/article/details/51457675

上一篇 下一篇

猜你喜欢

热点阅读