概述
现在我们已经完成了简单图形和颜色的绘制,如果我们想在图像上增加一些精致的细节,那么就需要使用纹理(texture)。
纹理就是一个图像、照片,甚至由一个数学算法生成的分形数据。
纹理坐标
每个二维纹理都有其自己的坐标空间,其范围是从一个拐角的(0,0)到另一个拐角的(1,1)。按照惯例,一个维度叫做S,而另一个称为T。当我们想要把一个纹理应用于一个三角形或一组三角形的时候,我们要为每个顶点指定一组ST纹理坐标,以便OpenGL知道需要用那个纹理的哪个部分画到每个三角形上。这些纹理坐标有时也会被称为UV纹理坐标。
对一个OpenGL纹理来说,它没有内在的方向性,因此我们可以使用不同的坐标把它定向到任何我们喜欢的方向上。然而,在具体使用中,我们要考虑应用中纹理的方向,大多数计算机图像都有一个默认的方向,它们通常被规定为Y轴向下,Y的值随着向图像的底部移动而增加。因此我们需要要将纹理的Y方向翻转来满足这个图形所示的纹理坐标,也就是 S 轴向右,T 轴向下。
环绕方式
在纹理映射中,纹理坐标的范围为[0.0,1.0]。当纹理坐标超出这个值时,OpenGL会根据你设置的环绕模式来处理这种情况。我们可以分别为每个纹理坐标轴(s,t,r)设置一个环绕模式,通过glTexParameteri 第二个参数为GL_TEXTURE_WRAP_S,GL_TEXTURE_WRAP_T或者GL_TEXTURE_WRAP_R.环绕的模式有GL_REPEAT,GL_CLAMP,GL_CLAMP_TO_EDGE, GL_WRAP_TO_BORDER。
GL_CLAMP_TO_EDGE:超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果
GL_REPEAT:对纹理的默认行为。重复纹理图像。
GL_MIRRORED_REPEAT:重复纹理图像会产生镜像效果。
通过下面代码设置 wrap mode:
1 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT); |
纹理过滤
当纹理的大小被扩大或者缩小时,我们还需要使用纹理过滤明确说明会发生什么。当我们在渲染表面上绘制一个纹理时,那个纹理的纹理元素可能无法精确地映射到OpenGL生成的片段上。有两种情况:缩小和放大。当我们尽力把几个纹理元素挤进一个片段时,缩小就发生了;当我们把一个纹理元素扩展到许多片段时,方法就发生了。针对每一种情况,我们可以配置OpenGL使用一个纹理过滤器。
首先,讲述两个基本的过滤模式:最近邻过滤和双线性插值。
- GL_NEAREST 邻近过滤,是OpenGL默认的纹理过滤方式。当设置为GL_NEAREST的时候,OpenGL会选择中心点最接近纹理坐标的那个像素。
- GL_LINEAR 线性过滤,它会基于纹理坐标附近的纹理像素,计算出一个插值,近似出这些纹理像素之间的颜色。
代码
顶点着色器代码:
1 | attribute vec4 a_Position; |
片段着色器代码:
1 | precision mediump float; |
1 | public class TestRender implements GLSurfaceView.Renderer { |
在上面的顶点数据中,处理 x 和 y 的位置,我们也定义了纹理坐标 S 和 T。
1 | public class TextureHelper { |
1 | public class ShaderHelper { |
1 | public class Utils { |
图片绘制效果:
裁剪纹理
可以看到图片有些拉伸,下面我们把图片进行一些裁剪,修改一下顶点坐标:
1 | private static final float[] vertexData = { |
裁剪后的效果:
纹理混合
如果理解了纹理贴图,那么多重纹理混合其实很简单了,比如双层纹理混合就是传入两张纹理图像,然后在OpenGL ES中生成纹理,我们在片段着色器中对两个纹理的颜色就是混合(比如相加、相乘等),这样最后显示的效果就是双层纹理混合的效果。
更新顶点着色器代码:
1 | attribute vec4 a_Position; |
更新片段着色器代码:
1 | precision mediump float; |
1 | protected static final String U_TEXTURE_UNIT_2 = "u_TextureUnit2"; |
1 | // 加载纹理 |
纹理1 和纹理2的坐标相同,所以顶点坐标就不用更新了,绘制的方法也是和上面是相同的。
效果图:
上面呈现的是两种图片混合的效果,如果想让第二个图片叠加在第一个图片上面,可以通过修改着色器代码:
1 | precision mediump float; |