android opengles 纹理

1. 纹理映射

1.1 纹理映射就是将图片贴到绘制的图像上
1.2 纹理坐标的坐标系 横轴为S 纵轴为T
1.3 opengles对纹理做了归一化处理,坐标范围都是0.0~1.0
demo:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.os.Bundle;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(new MSur(this));
    }
}

class MSur extends GLSurfaceView {
    Render render;

    public MSur(Context context) {
        super(context);

        this.setEGLContextClientVersion(2);
        render = new Render(context);

        setRenderer(render);
        this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
    }
}

class Render implements GLSurfaceView.Renderer {
    private int vCount;
    private Context ctx;
    private FloatBuffer fbv;
    private FloatBuffer mTexCoorBuffer;
    static float[] mMMatrix = new float[16];
    int mProgram;// 自定义渲染管线程序id
    int muMVPMatrixHandle;// 总变换矩阵引用id
    int maPositionHandle; // 顶点位置属性引用id
    int maTexCoorHandle; // 顶点颜色属性引用id

    int msTexHandle;//纹理引用id
    int textureId;//系统分配的纹理id

    public static float[] mProjMatrix = new float[16];// 4x4矩阵 投影用
    public static float[] mVMatrix = new float[16];// 摄像机位置朝向9参数矩阵
    public static float[] mMVPMatrix;// 最后起作用的总变换矩阵

    public Render(Context ctx) {
        super();
        this.ctx = ctx;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES20.glClearColor(0, 0, 0, 1.0f);

        initVertex();

        initShader();

        GLES20.glEnable(GLES20.GL_DEPTH_TEST);

        initTexture();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {

        GLES20.glViewport(0, 0, width, height);
        float ratio = (float) width / height;

        Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 1, 10);

        Matrix.setLookAtM(mVMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

        draw();
    }

    public void draw() {
        GLES20.glUseProgram(mProgram);
        Matrix.setRotateM(mMMatrix, 0, 0, 0, 1, 0);

        mMVPMatrix = new float[16];
        Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);

        GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
                false, 3 * 4, fbv);
        //TODO 5 将纹理坐标传入glsl
        GLES20.glVertexAttribPointer(maTexCoorHandle,
                2,
                GLES20.GL_FLOAT,
                false,
                2*4,
                mTexCoorBuffer);

        GLES20.glEnableVertexAttribArray(maPositionHandle);
        GLES20.glEnableVertexAttribArray(maTexCoorHandle);

        //TODO 6 绑定纹理
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        //如果只有一个纹理 可以不做这一步
        GLES20.glUniform1i(msTexHandle, 0/*GLES20.GL_TEXTURE0=0  GLES20.GL_TEXTURE1=1*/);
        //TODO  7 显示
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
    }

    //初始化数据
    private void initVertex() {
        float v[] = { 1f, -1f, 0, 0, 1f, 0, -1f, -1f, 0 };
        vCount = v.length / 3;
        ByteBuffer bb = ByteBuffer.allocateDirect(v.length * 4);
        bb.order(ByteOrder.nativeOrder());
        fbv = bb.asFloatBuffer();
        fbv.put(v);
        fbv.position(0);

        //TODO 4 初始化纹理坐标
        float texCoor[]=new float[]{0, 1, 0.5f, 0, 1, 1};
        //创建顶点纹理坐标数据缓冲
        ByteBuffer cbb = ByteBuffer.allocateDirect(texCoor.length*4);
        cbb.order(ByteOrder.nativeOrder());//设置字节顺序
        mTexCoorBuffer = cbb.asFloatBuffer();//转换为Float型缓冲
        mTexCoorBuffer.put(texCoor);//向缓冲区中放入顶点着色数据
        mTexCoorBuffer.position(0);//设置缓冲区起始位置
    }

    //初始化纹理
    public void initTexture(){
        //TODO 2 生成纹理ID
        int[] textures = new int[1];
        GLES20.glGenTextures
        (
                1,          //产生的纹理id的数量
                textures,   //纹理id的数组
                0           //偏移量
        );
        textureId=textures[0];
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);

        //纹理采样
        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_LINEAR);
        //纹理拉伸
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);


        //通过输入流加载图片
        InputStream is = this.ctx.getResources().openRawResource(R.raw.wall);
        Bitmap bitmapTmp;
        try
        {
            bitmapTmp = BitmapFactory.decodeStream(is);
        }
        finally
        {
            try
            {
                is.close();
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
        }

        //TODO 3 实际加载纹理
        GLUtils.texImage2D
                (
                        GLES20.GL_TEXTURE_2D,   //纹理类型,在OpenGL ES中必须为GL10.GL_TEXTURE_2D
                        0,                    //纹理的层次,0表示基本图像层,可以理解为直接贴图
                        bitmapTmp,            //纹理图像
                        0                     //纹理边框尺寸
                );
        bitmapTmp.recycle();          //纹理加载成功后释放图片
    }

    //初始化shader
    private void initShader() {
        String vertex = loadSH("vertex.sh");
        String shader = loadSH("frag.sh");

        int verS = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
        if (verS != 0) {
            GLES20.glShaderSource(verS, vertex);
            GLES20.glCompileShader(verS);
        }

        int fragS = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
        if (fragS != 0) {
            GLES20.glShaderSource(fragS, shader);
            GLES20.glCompileShader(fragS);
        }
        mProgram = GLES20.glCreateProgram();
        if (mProgram != 0) {
            GLES20.glAttachShader(mProgram, verS);
            GLES20.glAttachShader(mProgram, fragS);
            GLES20.glLinkProgram(mProgram);
        }

        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
        //TODO 1 关联glsl的纹理坐标
        maTexCoorHandle= GLES20.glGetAttribLocation(mProgram, "aTexCoor");
        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        msTexHandle = GLES20.glGetUniformLocation(mProgram, "sTexture");
    }
    //将sh文件加载进来
    private String loadSH(String fname) {
        String result = null;
        try {
            InputStream in = ctx.getAssets().open(fname);
            int ch = 0;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            while ((ch = in.read()) != -1) {
                baos.write(ch);
            }
            byte[] buff = baos.toByteArray();
            baos.close();
            in.close();
            result = new String(buff, "UTF-8");
            result = result.replaceAll("\\r\\n", "\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

frag.sh:

precision mediump float;
varying vec2 vTextureCoord; //接收从顶点着色器过来的参数
uniform sampler2D sTexture;//纹理内容数据
void main()                         
{           
   //给此片元从纹理中采样出颜色值            
   gl_FragColor = texture2D(sTexture, vTextureCoord); 
}   

vertex.sh:

uniform mat4 uMVPMatrix; //总变换矩阵
attribute vec3 aPosition;  //顶点位置
attribute vec2 aTexCoor;    //顶点纹理坐标
varying vec2 vTextureCoord;  //用于传递给片元着色器的变量
void main()     
{                                   
   gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点位置
   vTextureCoord = aTexCoor;//将接收的纹理坐标传递给片元着色器
} 

2. 纹理拉伸

当设置纹理的s,t大于1.0时,纹理就会产生拉伸现象
拉伸的方式有三种:
2.1 设置S轴的拉伸方式为重复
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_REPEAT);

2.2 设置S轴的拉伸方式为镜像重复
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_MIRRORED_REPEAT);

2.3 设置S轴的拉伸方式为截取
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);

s轴与t轴需要分别设置

3. 纹理采样

纹理采样:根据片元的纹理坐标到纹理提取对应位置的颜色
渲染时,通过纹理坐标不一定能在纹理图中找到完全对应的像素,此时需要一些策略,常用的有最近点采样和线性采样

3.1 最近点采样 GLES20.GL_NEAREST
纹理由一个一个像素点组成,最近采样点就是直接获取s,t坐标对应的像素点的颜色值
优点:速度快,简单
缺点:将小纹理图映射到大图元时,会产生锯齿现象
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);

3.2 线性采样 GLES20.GL_LINEAR
对采样范围内的多个像素进行加权平均,使纹理平滑过渡从而避免锯齿现象
优点:有效避免锯齿现象
缺点:运算量变大,虽然解决了锯齿,但是颜色差距过大,会产生颜色边界模糊现象
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);

3.3 GLES20.GL_TEXTURE_MAG_FILTERGLES20.GL_TEXTURE_MIN_FILTER
大纹理图映射到小图元时 使用GL_TEXTURE_MAG_FILTER
小纹理图映射到大图元时 使用GL_TEXTURE_MIN_FILTER

4. mipmap

若需要设置一个大场景,如地图时,在远处看的很清楚,但是在近处会模糊,因为在近处纹理被拉大。
因此需要在远处使用分辨率低的纹理,在近处使用分辨率大的图元,这就是mipmap。mipmap由系统自动完成,只需要提供一张原始图,加载时系统会自动生成一系列纹理,每个纹理图都是前一个的1/2,直到最后一个1x1像素
GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);

5. 多重纹理与过程纹理

多重纹理:一个图元使用多个纹理,使用GLES20.glUniform1i
过程纹理:多个纹理间的平滑过渡

6. 纹理压缩

常规的纹理是将图片解压后送入纹理缓冲区,图像文件会很大。gles采用压缩的方式,通用的格式为ETC1,不支持透明,gles3.0的通用格式ETC2/EAC开始支持。加载时可以直接将压缩文件送到纹理缓冲区使用。
加载使用:ETC1Util.loadTexture

补充:gles3.0新特性

  1. 增加了色彩通道,可以对映射到图元的rgba分量进行单独的控制
  2. 增加3D纹理
  3. 2D纹理数组,一个着色器中需要多个纹理时,简化开发
  4. 采样器配置对象sampler,加载每一个纹理时,都需要设置拉伸方式和采样方式,采用采样适配器可以统一设置,避免重复,提高效率

参考《opengles 3.x 游戏开发 上卷》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android中使用OpenGL ES 3.0加载纹理有以下步骤: 1. 初始化OpenGL ES环境:在OpenGL ES操作前,需要初始化OpenGL ES环境,创建GLSurfaceView实例,并设置渲染器。 2. 创建纹理对象:使用OpenGL ES函数glGenTextures生成纹理对象ID,并绑定到当前活动的纹理单元。 3. 加载纹理图像:通过Android的Bitmap对象加载纹理图像,可以使用BitmapFactory类的decodeResource方法从资源中加载或使用Bitmap类的createBitmap方法动态创建。调用glTexImage2D将图像数据传输到纹理对象中。 4. 设置纹理过滤器:可以使用glTexParameteri函数设置纹理的放大缩小过滤器,如GL_LINEAR或GL_NEAREST。 5. 设置纹理包裹模式:可以使用glTexParameteri函数设置纹理的包裹模式,如GL_CLAMP_TO_EDGE或GL_REPEAT。 6. 加载纹理坐标:通过定义纹理坐标数组,确定纹理映射到对象的哪个部分。在顶点着色器中使用纹理坐标进行纹理采样。 7. 绘制纹理:在绘制OpenGL场景时,通过在顶点着色器和片段着色器中使用纹理坐标,并利用纹理采样器将纹理应用到对象上。 8. 释放纹理资源:当纹理不再使用时,需要调用glDeleteTextures函数释放纹理对象。 总之,使用OpenGL ES 3.0加载纹理需要创建纹理对象、加载纹理图像、设置纹理过滤器与包裹模式、加载纹理坐标,并在绘制时通过纹理采样器将纹理应用到对象上。记得释放纹理资源,以避免内存泄漏。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值