纹理可以理解为一个二维数组,它可以存储大量的数据,这些数据可以发送到着色器上。一般情况下我们所说的纹理是表示一副2D图,此时纹理存储的数据就是这个图的像素数据。
所谓的纹理贴图,就是使用Opengl将这个纹理数据渲染出来,这个过程有点像装修工人给墙体贴瓷砖,而瓷砖好比作纹理。
纹理坐标
如果为了将一副纹理图贴到Opengl绘制的一个矩形上,那么就需要解决一个问题,如何知道矩形的具体某个点对应纹理图的某个点呢?为了解决这个问题就引出了纹理坐标, 通过矩形的顶点坐标与纹理坐标关联,这样就明确了每个顶点应该显示纹理图的那部分像素数据。
纹理坐标在x和y轴上,范围为0到1之间。使用纹理坐标获取纹理颜色叫做采样(Sampling)。纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角,如下图所示:
纹理环绕
纹理坐标的值介于0到1之间,如果我们把纹理坐标设置成大于1那么会发生什么呢?OpenGL默认的行为是重复这个纹理图像,那么利用这个默认的特性我们能做些什么呢?那么比较火的抖音四分屏、九分屏滤镜不就是可以用这个特性巧妙地实现吗。
以下是通过改变纹理坐标实现四分屏和九分屏的一个小技巧:
当然,当纹理坐标超过1这个范围时,Opengl也提供了其他的选择,例如:
以上特性可以通过函数glTexParameteri
设置:
纹理过滤
纹理过滤实际就是纹理在放大缩小的过程中像素的处理方式。其中在Opengl ES常用的两种纹理过滤方式是GL_NEAREST(邻近过滤)和GL_LINEAR(也叫线性过滤)。
- GL_NEAREST是OpenGL默认的纹理过滤方式。当设置为GL_NEAREST的时候,OpenGL会选择中心点最接近纹理坐标的那个像素。
- GL_LINEAR(也叫线性过滤,(Bi)linear Filtering)它会基于纹理坐标附近的纹理像素,计算出一个插值,近似出这些纹理像素之间的颜色。一个纹理像素的中心距离纹理坐标越近,那么这个纹理像素的颜色对最终的样本颜色的贡献越大。
GL_NEAREST产生了颗粒状的图案,我们能够清晰看到组成纹理的像素,而GL_LINEAR能够产生更平滑的图案,很难看出单个的纹理像素。
同理,纹理过滤特性也是通过函数glTexParameteri
设置:
纹理单元
纹理单元的主要目的是让我们在着色器中可以使用多于一个的纹理。通过把纹理单元赋值给采样器,我们可以一次绑定多个纹理,只要我们首先激活对应的纹理单元。 例如使用Opengl ES对视频解码后的YUV进行渲染就需要用到纹理单元的相关知识点。
Opengl中纹理的使用
在Opengl中使用纹理主要有以下几个步骤:
- 创建纹理
glGenTextures
- 激活纹理
glActiveTexture
- 绑定纹理
glBindTexture
,传递特定的纹理id进行绑定 - 上传纹理数据
glTexImage2D
- 解除纹理绑定,
glBindTexture
,传递0进行解除绑定
纹理坐标映射关系
在了解纹理贴图之前我们先回顾一下三个坐标系统,分别是纹理坐标系统、手机屏幕坐标系统、Opengl坐标系统。这三个坐标系统的的原点各不相同,纹理坐标系统我们上面已经介绍过了,这里不再重复。而手机屏幕坐标系统则是原点位于左上角,X轴向右为正,Y轴向下为正的坐标系统。 而Opengl坐标系统则是原点位于中心,X轴向右为正,Y轴向下为正,其值介于-1到1之间的一套坐标系统。
既然纹理贴图就像装修工人贴瓷砖一样,那么直接将纹理坐标和Opengl的顶点坐标一一对应起来即可,也就是如下图:
我们按照这个映射关系建立贴图:
运行发现图是贴上去了,但是看到的贴图却是倒置的,如下:
这是为什么呢?
因为纹理的生成是由图片像素来生成的,而图像的存储是从左上角开始的,但是纹理坐标原点却是在左下角的(笔者也不知道为什么要这么奇葩),所以就产生了倒置现象,因此正确的映射关系应该是以图片的左上角为原点做映射才对,而这也刚好与手机屏幕坐标系统匹配。
也就说正确的映射关系是需要先将以左下角为原点的纹理坐标进行倒置,然后再建立映射关系,这也是为什么有些博客说纹理坐标的原点是在左上角的原因(其实这是不对的,纹理坐标就是在图片的左下角,说在左上角的就是一个技巧),那么纹理坐标倒置后再映射如图:
!
废话少说,放码过来...
仔细看注释多理解...
往期笔记
Opengl ES之EGL环境搭建Opengl ES之着色器
Opengl ES之三角形绘制
Opengl ES之四边形绘制
关注我,一起进步,人生不止coding!!!