1. 程式人生 > >OpenGL ES (16): 紋理貼圖

OpenGL ES (16): 紋理貼圖

1.前言

圖片如下:紋理座標為 左上角為(0,0),右下角為(1,1)

我們繪製一個正方形,頂點座標資料如下:

此次程式碼不包含z軸,預設為0。

要做的事就是把圖片貼到正方形的表面,並繪製出正方形。

所以上面的紋理座標和頂點座標的順序要一致。這樣繪製的圖片才完整。

比如左上角紋理座標為(0,0) 對應頂點座標為(-0.5 , 0.5)。

因為多加了一組紋理座標,所以需要修改我們的著色器為:

String vertexShaderCode =
            "attribute vec4 vPosition;\n" +
                    "attribute vec2 vCoordinate;\n" +
                    "uniform mat4 vMatrix;\n" +
                    "\n" +
                    "varying vec2 aCoordinate;\n" +
                    "\n" +
                    "void main(){\n" +
                    "    gl_Position=vMatrix*vPosition;\n" +
                    "    aCoordinate=vCoordinate;\n" +
                    "}";

    String fragmentShaderCode =
            "precision mediump float;\n" +
                    "\n" +
                    "uniform sampler2D vTexture;\n" +
                    "varying vec2 aCoordinate;\n" +
                    "\n" +
                    "void main(){\n" +
                    "    gl_FragColor=texture2D(vTexture,aCoordinate);\n" +
                    "}";

上面著色器中有:

  • 頂點位置控制代碼:vPosition
  • 矩陣變換控制代碼:vMatrix
  • 紋理座標控制代碼:vCoodinate
  • 紋理影象控制代碼:vTexture

2.程式碼:

Activity 和 GLSurfaceView不給出,太簡單了。直接看Render

public class MyOtherRender implements GLSurfaceView.Renderer {

    String vertexShaderCode =
            "attribute vec4 vPosition;\n" +
                    "attribute vec2 vCoordinate;\n" +
                    "uniform mat4 vMatrix;\n" +
                    "\n" +
                    "varying vec2 aCoordinate;\n" +
                    "\n" +
                    "void main(){\n" +
                    "    gl_Position=vMatrix*vPosition;\n" +
                    "    aCoordinate=vCoordinate;\n" +
                    "}";

    String fragmentShaderCode =
            "precision mediump float;\n" +
                    "\n" +
                    "uniform sampler2D vTexture;\n" +
                    "varying vec2 aCoordinate;\n" +
                    "\n" +
                    "void main(){\n" +
                    "    gl_FragColor=texture2D(vTexture,aCoordinate);\n" +
                    "}";

    private int mProgram;

    private final float[] sPos={
            -1.0f,1.0f,    //左上角
            -1.0f,-1.0f,   //左下角
            1.0f,1.0f,     //右上角
            1.0f,-1.0f     //右下角
    };
//頂點座標
    private FloatBuffer bPos;
//紋理座標
    private FloatBuffer bCoord;
//使用的紋理
    private int textureId;
    //紋理座標資料
    private final float[] sCoord={
            0.0f,0.0f,
            0.0f,1.0f,
            1.0f,0.0f,
            1.0f,1.0f,
    };

    //所有的控制代碼
    private int vPositionHandle;
    private int vCoordinateHandle;
    private int vMatrixHandle;
    private int vTextureHandle;

    Context context;
    public MyOtherRender(Context context) {
        this.context = context;
    }

    Bitmap mBitmap = null;
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        GLES20.glEnable(GLES20.GL_TEXTURE_2D);
        //頂點座標
        ByteBuffer bb = ByteBuffer.allocateDirect(sPos.length * 4);
        bb.order(ByteOrder.nativeOrder());
        bPos = bb.asFloatBuffer();
        bPos.put(sPos);
        bPos.position(0);
        //紋理座標
        ByteBuffer cc = ByteBuffer.allocateDirect(sCoord.length * 4);
        cc.order(ByteOrder.nativeOrder());
        bCoord = cc.asFloatBuffer();
        bCoord.put(sCoord);
        bCoord.position(0);

        mBitmap = BitmapFactory.decodeResource(context.getResources() , R.drawable.bj);

        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
                vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
                fragmentShaderCode);
        mProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(mProgram, vertexShader);
        GLES20.glAttachShader(mProgram, fragmentShader);
        GLES20.glLinkProgram(mProgram);

    }

    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjectMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
        float ratio = (float) width / height;
        Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
        //設定相機位置
        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 7.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        //計算變換矩陣
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectMatrix, 0, mViewMatrix, 0);
    }


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

        //獲取所有控制代碼
        vPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        vCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "vCoordinate");
        vTextureHandle = GLES20.glGetUniformLocation(mProgram, "vTexture");
        vMatrixHandle = GLES20.glGetUniformLocation(mProgram, "vMatrix");

        GLES20.glUniformMatrix4fv(vMatrixHandle, 1, false, mMVPMatrix, 0);
        GLES20.glEnableVertexAttribArray(vPositionHandle);
        GLES20.glEnableVertexAttribArray(vCoordinateHandle);
        GLES20.glUniform1i(vTextureHandle, 0);
        textureId = createTexture();

        //傳入頂點座標 沒有給z軸設定座標
        GLES20.glVertexAttribPointer(vPositionHandle, 2, GLES20.GL_FLOAT, false, 0, bPos);
        //傳入紋理座標
        GLES20.glVertexAttribPointer(vCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, bCoord);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    }

    private int createTexture(){
        int[] texture=new int[1];
        if(mBitmap!=null&&!mBitmap.isRecycled()){
            //生成紋理
            GLES20.glGenTextures(1,texture,0);
            //生成紋理
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,texture[0]);
            //設定縮小過濾為使用紋理中座標最接近的一個畫素的顏色作為需要繪製的畫素顏色
            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);
            //設定環繞方向S,擷取紋理座標到[1/2n,1-1/2n]。將導致永遠不會與border融合
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
            //設定環繞方向T,擷取紋理座標到[1/2n,1-1/2n]。將導致永遠不會與border融合
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
            //根據以上指定的引數,生成一個2D紋理
            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmap, 0);
            return texture[0];
        }
        return 0;
    }

    //編譯著色器
    public static int loadShader(int type, String shaderCode){
        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }

}

紋理貼圖執行效果如上,但是有個問題就是,執行一段時間之後,程式會自動退出。求解?