Android Opengles2.0 多纹理融合

来源:互联网 发布:郑大网络远程教育中心 编辑:程序博客网 时间:2024/06/05 17:45

demo:
http://download.csdn.net/download/keen_zuxwang/10041401

1、创建顶点位置、纹理数组
2、创建、编译、加载shader程序,获得shader中各变量的句柄(如获取纹理采样sampler2D变量的句柄)
3、程序通过program给shader传递各参量,如:顶点位置、纹理坐标,激活、绑定纹理,传递模型/视图/投影矩阵等, 然后通过glDrawArrays()/glDrawElements()绘制图元(片元着色器通过这些参量计算出每个像素的值、然后通过底层EGL 渲染到相应的ANativeWindow)

1)、vertex shader:

attribute vec4 vPosition; //顶点位置attribute vec2 vCoord; //顶点纹理uniform mat4 vMatrix; //变化矩阵//传递量-->fragment shadervarying vec2 varyTexCoord; varying vec2 varyPostion;void main(){    gl_Position = vPosition; //vMatrix*vPosition    varyPostion = vPosition.xy;    varyTexCoord = vCoord;}

fragment shader:

precision mediump float; // 必须定义float精度(若有使用float 变量,或者定义float变量时指定精度)uniform sampler2D vTexture; // 2D纹理采样器变量uniform sampler2D vTexture0;uniform sampler2D vTexture1;uniform  float mratio; // 融合系数//定义左上角矩形融合区域,参考顶点位置坐标定义(顶点位置一般范围[-1,1])const vec2 leftBottom = vec2(-0.99, 0.79);const vec2 rightTop = vec2(-0.70, 0.99);varying vec2 varyTexCoord;varying vec2 varyPostion;void main() {    //矩形区域内的融合    if (varyPostion.x >= leftBottom.x && varyPostion.x <= rightTop.x      && varyPostion.y >= leftBottom.y && varyPostion.y <= rightTop.y) {        vec2 tex0 = vec2((varyPostion.x-leftBottom.x)/(rightTop.x-leftBottom.x),                     1.0-(varyPostion.y-leftBottom.y)/(rightTop.y-leftBottom.y));        vec4 color = texture2D(vTexture1, tex0);        gl_FragColor = color*color.a + texture2D(vTexture, 1.0-varyTexCoord)*(1.0-color.a); // 以color的透明度color.a 进行mix    }    //矩形区域外的融合    else {       vec4 color1 = texture2D(vTexture, varyTexCoord); //texture2D 纹理采样,获取纹理的像素信息       vec4 color2 = texture2D(vTexture0, varyTexCoord);       gl_FragColor = mix(color1, color2, mratio);    }}

2)、shader的工具类:

   //加载shader   //shader类型: GLES20.GL_VERTEX_SHADER & GLES20.GL_FRAGMENT_SHADER   //sourcesh: shader的脚本字符串资源   public static int loadShader(int shaderType, String source)    {        //创建shader        int shader = GLES20.glCreateShader(shaderType);        //若创建成功则加载shader        if (shader != 0)         {            //加载shader的源代码            GLES20.glShaderSource(shader, source);            //编译shader            GLES20.glCompileShader(shader);            //存放编译成功shader数量的数组            int[] compiled = new int[1];            //获取Shader的编译情况 Get Shader invalidate            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);            if (compiled[0] == 0)             {//若编译失败则显示错误日志并删除此shader                Log.e("ES20_ERROR", "Could not compile shader " + shaderType + ":");                Log.e("ES20_ERROR", GLES20.glGetShaderInfoLog(shader));                GLES20.glDeleteShader(shader);                shader = 0;                  }          }        return shader;    }   //创建shader程序program   public static int createProgram(String vertexSource, String fragmentSource)    {        //加载顶点着色器        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);        if (vertexShader == 0) {            return 0;        }        //加载片元着色器        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);        if (pixelShader == 0) {            return 0;        }        int program = GLES20.glCreateProgram();  //创建程序        //若程序创建成功则向程序中加入顶点着色器与片元着色器        if (program != 0)         {            //向程序中加入顶点着色器            GLES20.glAttachShader(program, vertexShader);            checkGlError("glAttachShader");            //向程序中加入片元着色器            GLES20.glAttachShader(program, pixelShader);            checkGlError("glAttachShader");            //链接程序            GLES20.glLinkProgram(program);            //存放链接成功program数量的数组            int[] linkStatus = new int[1];            //获取program的链接情况 Get Program invalidate            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);            //若链接失败则报错并删除程序            if (linkStatus[0] != GLES20.GL_TRUE)             {                Log.e("ES20_ERROR", "Could not link program: ");                Log.e("ES20_ERROR", GLES20.glGetProgramInfoLog(program));                GLES20.glDeleteProgram(program);                program = 0;            }        }        return program;    }   //检查错误   public static void checkGlError(String op)    {        int error;        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR)         {            Log.e("ES20_ERROR", op + ": glError " + error);            throw new RuntimeException(op + ": glError " + error);        }   }   //从assets加载shader   public static String loadFromAssetsFile(String fname,Resources r)   {    String result=null;         try    {        InputStream in=r.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;   }

3)、顶点、纹理、矩阵、shader操作类, 该类最终将在GLSurfaceView的GLSurfaceView.Renderer 类的OnDrawFrame()中调用glDrawArrays()/glDrawElements()绘制图元

public class IconObj {    private static final String TAG="Filter";    protected int mProgram;    protected int mHPosition;    protected int mHCoord;    protected int mMVPMatrix;    protected int mHTexture;    protected int mHTexture0;    protected int mHTexture1;    protected int mRatio;    public float ratio=0.5f;    private float[] matrix=new float[16];    private float[] mMatrix=new float[16];    //纹理缓存    protected FloatBuffer mVerBuffer;    //纹理缓存    protected FloatBuffer mTexBuffer;    //顶点绘制索引    protected ShortBuffer drawListBuffer;    //纹理id    private int textureId=-1;    private int textureId0=-1;    private int textureId1=-1;    //顶点位置坐标    private float pos[] = {        -0.9f, 0.9f,        -0.9f, 0.7f,        -0.7f, 0.7f,        -0.7f, 0.9f,    };    //纹理坐标    private float[] coord={        0.0f,  1.0f,        0.0f,  0.0f,        1.0f,  0.0f,        1.0f,  1.0f,    };    //顶点位置坐标    private final float[] sPos={        -1.0f,1.0f,    //左上角        -1.0f,-1.0f,   //左下角         1.0f,1.0f,     //右上角         1.0f,-1.0f     //右下角    };    //顶点纹理坐标      private final float[] sCoord={         0.0f,0.0f,         0.0f,1.0f,         1.0f,0.0f,         1.0f,1.0f,    };    private static short drawOrder[] = {0, 1, 2, 0, 2, 3};    Context context;    public IconObj(Context context){        this.context=context;        initBuffer();        createProgram();        textureId = initTexture(R.drawable.earth);        textureId0 = initTexture(R.drawable.bg);        textureId1 = initTexture(R.drawable.opengles);        Matrix.setIdentityM(mMatrix, 0);        matrix = flip(mMatrix, true, false);    }    //闀滃儚    public  float[] flip(float[] m,boolean x,boolean y){        if(x||y){            Matrix.scaleM(m,0,x?-1:1,y?-1:1,1);        }        return m;    }    protected void initBuffer(){        ByteBuffer a=ByteBuffer.allocateDirect(sPos.length*4);        a.order(ByteOrder.nativeOrder()); //变化成本地字节序        mVerBuffer=a.asFloatBuffer();        mVerBuffer.put(sPos);        mVerBuffer.position(0);        ByteBuffer b=ByteBuffer.allocateDirect(sCoord.length*4);        b.order(ByteOrder.nativeOrder());        mTexBuffer=b.asFloatBuffer();        mTexBuffer.put(sCoord);        mTexBuffer.position(0);        ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);        dlb.order(ByteOrder.nativeOrder());        drawListBuffer = dlb.asShortBuffer();        drawListBuffer.put(drawOrder);        drawListBuffer.position(0);    }    protected  void createProgram(){        String mVertexShader=ShaderUtil.loadFromAssetsFile("base_vertex.sh", context.getResources());        ShaderUtil.checkGlError("==ss==");           //加载片元着色器的脚本内容        String mFragmentShader=ShaderUtil.loadFromAssetsFile("base_fragment.sh", context.getResources());          //基于顶点着色器与片元着色器创建程序        ShaderUtil.checkGlError("==ss==");              mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);        //glGetAttribLocation获取属性句柄(或可称为属性索引),glGetUniformLocation获取着色器中的常量值,它一般存储各种着色器需要的数据,如:转换矩阵、光照参数或者颜色等        mHPosition= GLES20.glGetAttribLocation(mProgram, "vPosition");        mHCoord=GLES20.glGetAttribLocation(mProgram,"vCoord");        mMVPMatrix=GLES20.glGetUniformLocation(mProgram,"vMatrix");        mHTexture=GLES20.glGetUniformLocation(mProgram,"vTexture");        mHTexture0=GLES20.glGetUniformLocation(mProgram,"vTexture0");        mHTexture1=GLES20.glGetUniformLocation(mProgram,"vTexture1");        mRatio = GLES20.glGetUniformLocation(mProgram,"mratio");    }    public int initTexture(int drawableId)    {        //生成纹理ID        int[] textures = new int[1];        GLES20.glGenTextures        (                1,          //产生的纹理id的数量                textures,   //纹理id的数组                0           //偏移量        );            int textureId = textures[0];            Log.i(TAG, " initTexture textureId = " + textureId);        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST); // 纹素放大、缩小设置GL_LINEAR对应线性滤波,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); // 纹理边界处理,当纹理坐标超出[0,1]的范围时该怎么处理,GL_CLAMP_TO_EDGE --- 纹理坐标会被截断到[0,1]之间。坐标值大的被截断到纹理的边缘部分,形成了一个拉伸的边缘        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);        //加载图片        InputStream is = context.getResources().openRawResource(drawableId);        Bitmap bitmapTmp;        try {            bitmapTmp = BitmapFactory.decodeStream(is);        } finally {            try {                is.close();            }             catch(IOException e) {                e.printStackTrace();            }        }        //实际加载纹理        GLUtils.texImage2D        (                GLES20.GL_TEXTURE_2D,  //纹理类型,在OpenGL ES中必须为GL10.GL_TEXTURE_2D                0,                    //纹理的层次,0表示基本图像层,可以理解为直接贴图                bitmapTmp,            //纹理图像                0                     //纹理边框尺寸        );        bitmapTmp.recycle();          //纹理加载成功后释放图片         return textureId;    }    public void drawSelf() {        GLES20.glUseProgram(mProgram); // 使用shader program        //顶点属性一般包括位置、颜色、法线、纹理坐标        GLES20.glEnableVertexAttribArray(mHPosition); // 使能相应的顶点位置句柄/索引的顶点属性数组 --- 即为顶点位置属性attribute变量赋值        GLES20.glVertexAttribPointer(mHPosition,2, GLES20.GL_FLOAT, false, 0,mVerBuffer); // 指定(或绑定)该顶点位置句柄关联的顶点属性数组         GLES20.glEnableVertexAttribArray(mHCoord); // 使能相应的纹理坐标句柄的顶点属性数组        GLES20.glVertexAttribPointer(mHCoord, 2, GLES20.GL_FLOAT, false, 0, mTexBuffer); // 指定(或绑定)该纹理坐标句柄关联的顶点属性数组 --- 即为顶点纹理坐标属性attribute变量赋值          //GLES20.glUniformMatrix4fv(mMVPMatrix,1,false,matrix,0);        GLES20.glUniform1f(mRatio, ratio);        //绑定纹理        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);          GLES20.glUniform1i(mHTexture, 0);        //绑定纹理        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId0);          GLES20.glUniform1i(mHTexture0, 1);      //绑定纹理        GLES20.glActiveTexture(GLES20.GL_TEXTURE2);        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId1);          GLES20.glUniform1i(mHTexture1, 2);        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP,0,4);        //GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);        GLES20.glDisableVertexAttribArray(mHPosition);        GLES20.glDisableVertexAttribArray(mHCoord);    }}

GLSurfaceView.Renderer 接口实现中进行shader操作类的创建、绘制

        SeekBar seekBar = (SeekBar) findViewById(R.id.id_seekBar);        seekBar.setOnSeekBarChangeListener(new    SeekBar.OnSeekBarChangeListener() {            @Override            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {                // TODO Auto-generated method stub                if(iconObj != null) {                   iconObj.ratio = progress/100.0f;                }                ratio = progress/100.0f;            }            @Override            public void onStartTrackingTouch(SeekBar seekBar) {                // TODO Auto-generated method stub            }            @Override            public void onStopTrackingTouch(SeekBar seekBar) {                // TODO Auto-generated method stub            }    });    IconObj  iconObj;    @Override    public void onSurfaceCreated(GL10 gl, EGLConfig config) {        iconObj = new IconObj(context);    }    @Override    public void onSurfaceChanged(GL10 gl, int width, int height) {        GLES20.glViewport(0, 0, width, height); //视窗设置    }    @Override    public void onDrawFrame(GL10 gl) {        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //设置清除颜色        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);         //GL_COLOR_BUFFER_BIT 设置窗口颜色        //GL_DEPTH_BUFFER_BIT 设置深度缓存--把所有像素的深度值设置为最大值(一般为远裁剪面)        iconObj.drawSelf();    }

demo 效果:
这里写图片描述

这里写图片描述

这里写图片描述