OpenGL ES 纹理设置
纹理过滤
纹理拉伸:重复拉伸和截取拉伸
用于指定纹理坐标超过(00.0,1.0)范围时所发生的行为,使用glTexParameterf函数指定,GL_TEXTURE_WRAP_S 定义 s 坐标超出范围[0.0, 1.0]的情况,GL_TEXTURE_WRAP_T 设定 t 坐标。
- GL_REPEAT 重复纹理,超过1的部分其实只看它的小数部分,也就是说比如纹理坐标为2.4,那么相当于取样0.4处的纹理值。
- GL_CLAMP_TO_EDGE 采样纹理边缘,不想要任何格式的重复,应该使用 GL_CLAMP_TO_EDGE,超过1的部分都当成1.
- GL_MIRRORED_REPEAT 重复纹理和镜像,在重复的基础上呈现镜像效果。
在立方体纹理的例子上,修改一下vertices数组,增加一个变量i
float vertices[] = new float[] {
// 顶点 颜色 纹理坐标
//前面
0, 0, 1, 1,1,1,0, 0.5f*i, 0.5f*i,
1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i,
-1, 1, 1, 1,0,0,0, 0.0f*i, 0.0f*i,
0, 0, 1, 1,1,1,0, 0.5f*i, 0.5f*i,
-1, 1, 1, 1,0,0,0, 0.0f*i, 0.0f*i,
-1,-1, 1, 1,0,0,0, 0.0f*i, 1.0f*i,
0, 0, 1, 1,1,1,0, 0.5f*i, 0.5f*i,
-1,-1, 1, 1,0,0,0, 0.0f*i, 1.0f*i,
1,-1, 1, 1,0,0,0, 1.0f*i, 1.0f*i,
0, 0, 1, 1,1,1,0, 0.5f*i, 0.5f*i,
1,-1, 1, 1,0,0,0, 1.0f*i, 1.0f*i,
1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i,
//后面
0, 0,-1, 1,1,1,0, 0.5f*i, 0.5f*i,
1, 1,-1, 1,0,0,0, 1.0f*i, 0.0f*i,
1,-1,-1, 1,0,0,0, 0.0f*i, 0.0f*i,
0, 0,-1, 1,1,1,0, 0.5f*i, 0.5f*i,
1,-1,-1, 1,0,0,0, 0.0f*i, 0.0f*i,
-1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i,
0, 0,-1, 1,1,1,0, 0.5f*i, 0.5f*i,
-1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i,
-1, 1,-1, 1,0,0,0, 1.0f*i, 1.0f*i,
0, 0,-1, 1,1,1,0, 0.5f*i, 0.5f*i,
-1, 1,-1, 1,0,0,0, 1.0f*i, 1.0f*i,
1, 1,-1, 1,0,0,0, 1.0f*i, 0.0f*i,
//左面
-1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
-1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i,
-1, 1,-1, 1,0,0,0, 0.0f*i, 0.0f*i,
-1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
-1, 1,-1, 1,0,0,0, 0.0f*i, 0.0f*i,
-1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i,
-1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
-1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i,
-1,-1, 1, 1,0,0,0, 1.0f*i, 1.0f*i,
-1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
-1,-1, 1, 1,0,0,0, 1.0f*i, 1.0f*i,
-1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i,
//右面
1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i*i,
1,-1, 1, 1,0,0,0, 0.0f*i, 0.0f*i,
1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
1,-1, 1, 1,0,0,0, 0.0f*i, 0.0f*i,
1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i,
1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i,
1, 1,-1, 1,0,0,0, 1.0f*i, 1.0f*i,
1, 0, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
1, 1,-1, 1,0,0,0, 1.0f*i, 1.0f*i,
1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i,
//上面
0, 1, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i,
1, 1,-1, 1,0,0,0, 0.0f*i, 0.0f*i,
0, 1, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
1, 1,-1, 1,0,0,0, 0.0f*i, 0.0f*i,
-1, 1,-1, 1,0,0,0, 0.0f*i, 1.0f*i,
0, 1, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
-1, 1,-1, 1,0,0,0, 0.0f*i, 1.0f*i,
-1, 1, 1, 1,0,0,0, 1.0f*i, 1.0f*i,
0, 1, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
-1, 1, 1, 1,0,0,0, 1.0f*i, 1.0f*i,
1, 1, 1, 1,0,0,0, 1.0f*i, 0.0f*i,
//下面
0,-1, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
1,-1, 1, 1,0,0,0, 1.0f*i, 0.0f*i,
-1,-1, 1, 1,0,0,0, 0.0f*i, 0.0f*i,
0,-1, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
-1,-1, 1, 1,0,0,0, 0.0f*i, 0.0f*i,
-1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i,
0,-1, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
-1,-1,-1, 1,0,0,0, 0.0f*i, 1.0f*i,
1,-1,-1, 1,0,0,0, 1.0f*i, 1.0f*i,
0,-1, 0, 1,1,1,0, 0.5f*i, 0.5f*i,
1,-1,-1, 1,0,0,0, 1.0f*i, 1.0f*i,
1,-1, 1, 1,0,0,0, 1.0f*i, 0.0f*i
};
设置i=2时,相当于纹理坐标设置的范围为(0,2)之间,定义纹理过滤方式为重复模式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_REPEAT);
效果图
设置纹理过滤模式为重复镜像模式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_MIRRORED_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_MIRRORED_REPEAT);
效果图
纹理采样
纹理采样就是根据偏远的纹理坐标到纹理图中提取对应位置颜色的过程,但一般而言,片元数量和纹理图中的像素数量并不一定相同,比如将较小的纹理图映射到较大的图元或者将较大的纹理图映射到较小的图元时就会出现这样的状况,通过纹理坐标在纹理图中并不一定能找到与之完全对应的像素,这时候就要采取相应的策略在纹理图中选取颜色了。
最近点采样
最近点采样的原理就是根据片元的纹理坐标在纹理图中的位置距离那个像素近就选择哪个像素的颜色值作为该片元的颜色采样值。最近点采样计算很简单,但存在的问题就是将较小的纹理图映射到较大的图元上容易产生明显的锯齿,同时将较大的纹理缩小的一定的程度后也就不好用了。加载纹理时设置最近点采样的方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_NEAREST);
线性纹理采样
线性纹理采样的结果并不仅来自纹理图中的一个像素,在进行纹理采样时会考虑到该片元对应的纹理坐标周围的几个像素,然后根据周围几个像素的比例进行加权得到最终的采样结果。由于线性采样对多个像素进行了加权平均,仅此将较小的图元纹理映射到较大的图元时,不会有锯齿现象,而是平滑过渡。加载纹理时设置线性纹理采样的方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
因此一般来说对于缩小映射采用最近点采样,对于放大映射来说采用线性采样。GL_TEXTURE_MIN_FILTER表示缩小的映射,GL_TEXTURE_MAG_FILTER表示放大映射。
MIPMAP纹理
尽管用线性采样很适合处理放大的情况,但是对于缩小到一定的大小后,它就不好用了,一个纹理在渲染表面所占的大小减少的越多,就会有越多的纹理元素拥挤到一个片元上,一般情况下使用线性采样,每个片元值使用了四个纹理像素,我们就会失去很多的细节。
使用MIPMAP技术,可以用来生成一组优化过的不同大小的纹理,并且会使用所有的纹理元素来生成每个级别的纹理。当加载纹理的时候,不单单是加载一个纹理,而是加载一系列从大到小的纹理当mipmapped纹理状态中。在渲染时,OpenGL会根据每个片元的纹理元素数量为每个片元选择最合适的级别的纹理。
使用glGenerateMipmap函数自动生成多级纹理,对绑定的纹理调用glGenerateMipmap函数会产生从原始图像开始的多级纹理链。后续的每个纹理是上一个纹理图像的一半,一直持续到最后底部的1x1的纹理。
public static native void glGenerateMipmap(
int target
);
加载MIP纹理的方式允许在设置纹理采样方式时采用MIP方式,即param参数除了GL_NEAREST和GL_LINEAR以外,还可以使用GL_NEAREST_MIPMAP_NEAREST、GL_NEAREST_MIPMAP_LINEAR、GL_LINEAR_MIPMAP_NEAREST、GL_LINEAR_MIPMAP_LINEAR。
public static native void glTexParameterf(
int target,
int pname,
float param
);
使用GL_LINEAR_MIPMAP_LINEAR模式效果最佳。
测试各种类型的纹理采样方式