想要实现更加绚丽的物体,需要使用纹理映射。
为图元中的每个顶点指定恰当的纹理坐标,通过纹理坐标在纹理图中可以确定选中的纹理区域,最后将选中纹理区域的内容根据纹理坐标映射到指定图元上。
纹理映射的过程实际就是为图中右侧三角形图元中的每个片元着色,而用于着色的颜色需要从左侧的纹理图中提取:
private void initTexture() {
int[] textures = new int[1];
GLES20.glGenTextures(
1, //产生的纹理id数量
textures,//纹理id的数组
0);//偏移量
//获取产生的纹理id
textureId = textures[0];
//绑定纹理id
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
//设置MIN采样方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
//设置MAG采样方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
//设置S轴拉伸方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
//设置T轴拉伸方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
//通过输入流加载图片
InputStream is = getResources().openRawResource(R.drawable.wall);
Bitmap bitmapTemp = null;
try {
bitmapTemp = BitmapFactory.decodeStream(is);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//实际加载纹理进显存
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmapTemp, 0);
//纹理加载成功后释放内存中的纹理图
bitmapTemp.recycle();
}
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D sTexture;
void main(){
gl_FragColor=texture2D(sTexture,vTextureCoord);
}
上面图示中纹理坐标S、T 轴都在(0,1)范围内,但当设置纹理坐标大于1时候,纹理拉伸就会起作用。
OpenGL ES的纹理拉伸有:重复拉伸和截取拉伸。
重复拉伸下,当顶点纹理坐标大于1时实际起作用的纹理坐标为纹理坐标小数部分。如纹理坐标为3.3,则起作用的为0.3。
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);//设置S轴的拉伸方式为重复
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);//设置T轴的拉伸方式为重复
截取拉伸下,当纹理坐标大于1时都看作1,这就会造成边缘被拉伸。
//设置S轴拉伸方式为截取
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
//设置T轴拉伸方式为截取
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
介绍两种不同的纹理采样:最近点采样和线性采样。
纹理采样,根据片元的纹理坐标到纹理图中提取对应位置颜色过程。
根据纹理坐标可以计算出片元对应的纹理坐标点位于纹理图中的哪个像素(小方格)中,最近点采样就直接取此像素的颜色值为采样值。
最近点采样简单,计算量也小,但是容易产生锯齿。
//设置MIN采样方式为最近采样
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
//设置MAG采样方式为最近采样
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
线性采样的结果颜色不是来自一个像素,其在采样时候会考虑到片元对应的纹理坐标点附近的几个像素。根据涉及像素在采样范围内的面积比例加权计算出最终结果。
线性采样很好的解决了锯齿现象,但是线条边缘有时会模糊。
//设置MIN采样方式为线性采样
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
//设置MAG采样方式为线性采样
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
MIN(GLES20.GL_TEXTURE_MIN_FILTER):一幅尺寸较大的纹理图映射到一个显示到屏幕上尺寸小的图元时使用;
MAG(GLES20.GL_TEXTURE_MAG_FILTER):一幅尺寸较小的纹理图映射到一个显示到屏幕上尺寸大的图元时使用;
实际开发中,MIN一般设置为最近点采样,MAG一般设置为线性采样。
OpenGL ES 透视投影存在近大远小效果,当纹理映射显示山体等场景时候就会有问题。这是因为整个山体采用了一幅纹理图,远处的山体纹理被缩小进行映射。mipmap纹理的思想就是将远处的使用分辨率较小的纹理,近处的使用分辨率较大的纹理。
OpenGL ES渲染管线担起了处理这种问题的责任。仅需要提供一幅原始纹理图,系统会在纹理加载时自动生成一系列由大到小的纹理图。每幅图是前一幅的1/2,直至缩小到1x1。
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_NEAREST);
GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);//自动生成mipmap系列纹理
OpenGL ES 2.x开始支持多重纹理和过程纹理两个高级特性。