QT之OpenGL 2D纹理使用
1. 基础概念
纹理
通常用来给物体添加细节,它可以是2D
图片(甚至也有1D和3D
的纹理)。
1.1 纹理坐标
纹理坐标
是用来表述纹理位置的坐标,它的范围是(0,0)
到(1,1)
。示例如下:
float texCoords[] = {
0.0f, 0.0f, // 左下角
1.0f, 0.0f, // 右下角
0.5f, 1.0f // 上中
};
这个纹理坐标是对应的原始纹理为:
根据纹理坐标采样后的输出如下:
注:
- 在实际过程中,纹理坐标的设置范围可以超过
(0,0)
到(1,1)
,而超过的部分则会使用到纹理环绕方式处理
稍后说明
1.2 纹理像素
纹理像素
与屏幕物理像素
并不是一一对应的关系,如下所示:
将其放大如下:
当一个纹理产生后,其纹理像素就固定了,上面的图片其纹理像素是342*78
1.3 纹理单元
纹理单元
是用来给shader
中设置多个纹理使用的。在shader
中用uniform
来声明一个sampler2D
类型变量,这就表示在shader
中给纹理采样器(sampler2D
)分配了一个位置,这个位置就是纹理单元
。
OpenGL
至少保证有16
个纹理单元供你使用,也就是说你可以激活从GL_TEXTURE0
到GL_TEXTRUE15
。它们都是按顺序定义的,所以我们也可以通过GL_TEXTURE0 + 8
的方式获得GL_TEXTURE8
,这在当我们需要循环一些纹理单元的时候会很有用。
2. 纹理加载
在QT
中对OpenGL
的纹理有一个QOpenGLTexture
类。可以使用QOpenGLTexture
对纹理进行加载,其使用步骤如下:
- 加载纹理单元
- 设置
shader
中采样器的纹理单元
- 绑定纹理单元
- 解绑纹理单元
代码示例如下:
// 设置纹理,并将y轴进行镜像
m_texture = std::make_unique<QOpenGLTexture>(QImage(":/images/images/small.png").mirrored());
// 设置纹理单元
m_shaderProgram.bind();
m_shaderProgram.setUniformValue("texture", 0);
m_shaderProgram.release();
// 绑定纹理单元
m_texture->bind();
// 解绑纹理单元
m_texture->release();
3. 纹理环绕方式
纹理环绕方式
的产生是在纹理坐标
超过(0,0)
到(1,1)
时,对超出范围的处理方式,主要由以下四种方式:
GL_REPEAT
对纹理的默认行为。重复纹理图像。GL_MIRRORED_REPEAT
和GL_REPEAT
一样,但每次重复图片是镜像放置的。GL_CLAMP_TO_EDGE
纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。GL_CLAMP_TO_BORDER
超出的坐标为用户指定的边缘颜色。
4. 纹理过滤
从拉伸或者压缩的纹理图片中采样出来像素颜色的过程叫做纹理过滤
纹理过滤
是用来处理放大或缩小时,不同纹理像素之间最终显示的一种方式。
最长常见的是GL_NEAREST(也叫邻近过滤,Nearest Neighbor Filtering)
和
GL_LINEAR(也叫线性过滤,(Bi)linear Filtering)
,两者的区别如下
GL_NEAREST
是其就近的值作为最终的显示值。
GL_LINEAR
是对采样点附近的值进行混合处理,最终输出一个混合后的值,使得颜色过渡更柔和
两者产生的效果如下:
4.1 多级渐远过滤
多级渐远纹理(Mipmap),它简单来说就是一系列的纹理图像,后一个纹理图像是前一个的二分之一。多级渐远纹理背后的理念很简单:距观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个。由于距离远,解析度不高也不会被用户注意到。同时,多级渐远纹理另一加分之处是它的性能非常好。
示例图:
多级渐远过滤的方式:
GL_NEAREST_MIPMAP_NEAREST
使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样GL_LINEAR_MIPMAP_NEAREST
使用最邻近的多级渐远纹理级别,并使用线性插值进行采样GL_NEAREST_MIPMAP_LINEAR
在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样GL_LINEAR_MIPMAP_LINEAR
在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样
多级渐远过滤是用在缩小的过程中的!!!
最终的demo中并没有演示出这一效果!!!
5. demo效果演示
-
纹理加载demo
-
环绕方式及纹理过滤demo