OpenGL ES学习(6)——认识纹理

1.纹理映射

想要实现更加绚丽的物体,需要使用纹理映射。

1.1基本原理

为图元中的每个顶点指定恰当的纹理坐标,通过纹理坐标在纹理图中可以确定选中的纹理区域,最后将选中纹理区域的内容根据纹理坐标映射到指定图元上。

OpenGL ES学习(6)——认识纹理_第1张图片

  • 纹理,简单的可以理解为贴纸,但在OpenGL ES的3D下纹理是复杂数据的集合
  • 图元,可以理解为基础图形;OpenGL ES图元有点、线、三角形
  • 纹理坐标,S为横轴(0,1),T为纵轴(0,1),浮点数表示

纹理映射的过程实际就是为图中右侧三角形图元中的每个片元着色,而用于着色的颜色需要从左侧的纹理图中提取:

  1. 图元中的每个顶点在顶点着色器中通过varying变量将纹理坐标传入片元着色器;
  2. 易变量不是直接传入后继片元着色器,OpenGL ES渲染管线根据片元所属图元各个顶点对应顶点着色器对varying插值计算,产生对应到每个片元的负责记录纹理坐标的varying值;
  3. 每个片元在片元着色器中根据接收到的记录纹理坐标的varying到纹理图中提取对应位置的颜色即可。

1.2 相关代码

    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);
}     

效果图

OpenGL ES学习(6)——认识纹理_第2张图片

2.纹理拉伸

上面图示中纹理坐标S、T 轴都在(0,1)范围内,但当设置纹理坐标大于1时候,纹理拉伸就会起作用。
OpenGL ES的纹理拉伸有:重复拉伸截取拉伸

2.1 重复拉伸

重复拉伸下,当顶点纹理坐标大于1时实际起作用的纹理坐标为纹理坐标小数部分。如纹理坐标为3.3,则起作用的为0.3。
OpenGL ES学习(6)——认识纹理_第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轴的拉伸方式为重复

2.2 截取拉伸

截取拉伸下,当纹理坐标大于1时都看作1,这就会造成边缘被拉伸。
OpenGL ES学习(6)——认识纹理_第4张图片

代码示例

 //设置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);

3.纹理采样

介绍两种不同的纹理采样:最近点采样线性采样

纹理采样,根据片元的纹理坐标到纹理图中提取对应位置颜色过程。

3.1 最近点采样

OpenGL ES学习(6)——认识纹理_第5张图片
根据纹理坐标可以计算出片元对应的纹理坐标点位于纹理图中的哪个像素(小方格)中,最近点采样就直接取此像素的颜色值为采样值。

最近点采样简单,计算量也小,但是容易产生锯齿。

代码示例

//设置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);

3.2 线性采样

OpenGL ES学习(6)——认识纹理_第6张图片
线性采样的结果颜色不是来自一个像素,其在采样时候会考虑到片元对应的纹理坐标点附近的几个像素。根据涉及像素在采样范围内的面积比例加权计算出最终结果。

线性采样很好的解决了锯齿现象,但是线条边缘有时会模糊。

代码示例

 //设置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);

3.3 MIN和MAG采样

MIN(GLES20.GL_TEXTURE_MIN_FILTER):一幅尺寸较大的纹理图映射到一个显示到屏幕上尺寸小的图元时使用;

MAG(GLES20.GL_TEXTURE_MAG_FILTER):一幅尺寸较小的纹理图映射到一个显示到屏幕上尺寸大的图元时使用;

实际开发中,MIN一般设置为最近点采样,MAG一般设置为线性采样。

3.4 mipmap纹理

OpenGL ES 透视投影存在近大远小效果,当纹理映射显示山体等场景时候就会有问题。这是因为整个山体采用了一幅纹理图,远处的山体纹理被缩小进行映射。mipmap纹理的思想就是将远处的使用分辨率较小的纹理,近处的使用分辨率较大的纹理。

OpenGL ES渲染管线担起了处理这种问题的责任。仅需要提供一幅原始纹理图,系统会在纹理加载时自动生成一系列由大到小的纹理图。每幅图是前一幅的1/2,直至缩小到1x1。
OpenGL ES学习(6)——认识纹理_第7张图片

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系列纹理

4.初识多重纹理和过程纹理

OpenGL ES 2.x开始支持多重纹理和过程纹理两个高级特性。

  • 对同一个图元采用多幅纹理图,称为多重纹理。
  • 在多重纹理变化的边界根据某种规则进行平滑过渡,称为过程纹理。

【参考】

  1. https://www.khronos.org/opengles/
  2. 《OpenGL ES应用开发实践指南 Android卷 Kevin Brothaler》
  3. https://en.wikipedia.org/wiki/OpenGL_ES
  4. https://developer.android.google.cn/guide/topics/graphics/opengl
  5. https://developer.android.google.cn/training/graphics/opengl
  6. Android3D游戏开发技术宝典OpenGL ES 2.0

你可能感兴趣的:(Android学习中的笔记,OpenGL,ES,学习,贴图,android,OpenGL,ES,2.0,纹理)