1. 程式人生 > >OpenGL ES (3):平面圖形-表面紋理貼圖

OpenGL ES (3):平面圖形-表面紋理貼圖

1.簡介

上一篇已經將一個平面圖形繪製出來了,這一次我們將在上一次繪製出來的圖形的表面上進行紋理貼圖。

圖片準備:(寬高須為2的N次方

最終圖片是以Bitmap形式。現在考慮如何把這張圖片對映到繪製的平面上?

所以這裡也需要一個數組float[] 用於設定紋理座標資料,紋理座標資料以圖片左上角為(0,0),右下角為(1,1)為基礎

上一篇文章已經知道,面數組為{0,1,2,3,4,5}繪製,所以要給組成面的每個頂點,對映一個紋理座標資料,如下:

float[]{

0f,0f , 0f,1f , 1f,1f,  //第一個面的三個點

0f,0f , 1f,1f , 1f,0f

}

這樣一張圖片就全部對映到繪製的平面上了。

2.程式碼

public class OtherShader implements GLSurfaceView.Renderer{
    FloatBuffer vertextBuffer;
//紋理座標資料
    FloatBuffer textureBuffer;
    ByteBuffer faceBuffer;
    private float roate;
//使用的紋理
    int texture;
    Context context;

    public OtherShader(Context context) {
        this.context = context;
        vertextBuffer = floatArray2Buffer(vertex);
        faceBuffer = ByteBuffer.wrap(face);
        textureBuffer = floatArray2Buffer(text);
    }

    float[] vertex = new float[]{
            -0.5f , 0.5f , 0f ,
            -0.5f , -0.5f , 0f ,
            0.5f , -0.5f , 0f ,
            -0.5f , 0.5f , 0f ,
            0.5f , -0.5f , 0f ,
            0.5f , 0.5f , 0f
    };

    byte[] face = new byte[]{
            0,1,2,
            3,4,5
    };

//紋理座標資料
    float[] text = {
            0f,0f , 0f,1f , 1f,1f,
            0f,0f , 1f,1f , 1f,0f
    };

    //將頂點顏色陣列轉換為IntBuffer,是OpenGl ES所需要的,可以不設定頂點顏色
    private IntBuffer intArray2Buffer(int[] rect1color) {
        IntBuffer intBuffer;
        //不用該方法得到IntBuffer,因為Android平臺限制,Buffer必須為native Buffer,所以要通過allocateDirect()建立
        //並且該Buffer必須是排序的,所以要order()方法進行排序
        //intBuffer = IntBuffer.wrap(rect1color);
        //因為一個int=4位元組
        ByteBuffer bb = ByteBuffer.allocateDirect(rect1color.length * 4);
        bb.order(ByteOrder.nativeOrder());
        intBuffer = bb.asIntBuffer();
        intBuffer.put(rect1color);
        intBuffer.position(0); //移到第一個點的資料
        return intBuffer;
    }

    //將頂點位置陣列轉換為FloatBuffer,是OpenGl ES所需要的
    private FloatBuffer floatArray2Buffer(float[] rect1) {
        FloatBuffer floatBuffer;
        //不用該方法得到FloatBuffer,因為Android平臺限制,Buffer必須為native Buffer,所以要通過allocateDirect()建立
        //並且該Buffer必須是排序的,所以要order()方法進行排序
        //floatBuffer = FloatBuffer.wrap(rect1);
        //因為一個int=4位元組
        ByteBuffer bb = ByteBuffer.allocateDirect(rect1.length * 4);
        bb.order(ByteOrder.nativeOrder());
        floatBuffer = bb.asFloatBuffer();
        floatBuffer.put(rect1);
        floatBuffer.position(0); //移到第一個點的資料
        return floatBuffer;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //關閉抗抖動
        gl.glDisable(GL10.GL_DITHER);
        //修正系統透視
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT , GL10.GL_FASTEST);
        //設定陰影平滑模式
        gl.glShadeModel(GL10.GL_SMOOTH);
        //啟用深度測試 記錄Z軸深度
        gl.glEnable(GL10.GL_DEPTH_TEST);
        //設定深度測試的型別
        gl.glDepthFunc(GL10.GL_LEQUAL);

        //*******啟用2D紋理*************
        gl.glEnable(GL10.GL_TEXTURE_2D);
        //載入紋理
        loadTexture(gl);
    }

    private void loadTexture(GL10 gl) {
        Bitmap bitmap = null;
        bitmap = BitmapFactory.decodeResource(context.getResources() , R.drawable.bj);
        int[] textures = new int[1];
        gl.glGenTextures(1 , textures , 0);
        texture = textures[0];
        gl.glBindTexture(GL10.GL_TEXTURE_2D , texture);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D , GL10.GL_TEXTURE_MIN_FILTER , GL10.GL_NEAREST);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D , GL10.GL_TEXTURE_MAG_FILTER , GL10.GL_LINEAR);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D , GL10.GL_TEXTURE_WRAP_S , GL10.GL_REPEAT);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D , GL10.GL_TEXTURE_WRAP_T , GL10.GL_REPEAT);
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D , 0 , bitmap , 0);
        if (bitmap != null){
            bitmap.recycle();
        }
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        //設定3D視窗的大小及位置
        gl.glViewport(0 , 0 , width , height );
        //將矩陣模式設定為投影矩陣
        gl.glMatrixMode(GL10.GL_PROJECTION);
        //初始化單位矩陣
        gl.glLoadIdentity();
        //計算透視窗寬高比
        float ratio = (float)width/height;
        //設定透視視窗的空間大小 預設為 -1,1,-1,1,-1,1
        //gl.glFrustumf(-ratio , ratio , -1 , 1  ,1 , 10);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        //清除螢幕快取和深度快取
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        //啟用頂點座標資料
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        //設定當前矩形堆疊為模型堆疊
        gl.glMatrixMode(GL10.GL_MODELVIEW);

        //啟用紋理貼圖座標陣列
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        //重置當前的模型檢視矩陣
        gl.glLoadIdentity();
       //如果需要用顏色填充平面,還需要禁用頂點顏色資料
        gl.glColor4f(0.2f , 1.0f , 0.2f , 0.0f);
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
        //繞y軸旋轉
        //gl.glRotatef(roate , 0f , 1f , 0f);
        //設定頂點位置資料
        gl.glVertexPointer(3 , GL10.GL_FLOAT , 0 , vertextBuffer);
        //設定貼圖陣列
        gl.glTexCoordPointer(2 , GL10.GL_FLOAT , 0 , textureBuffer);
        //根據頂點繪製平面 //執行貼圖

        gl.glBindTexture(GL10.GL_TEXTURE_2D , texture);
        gl.glDrawElements(GL10.GL_TRIANGLES, faceBuffer.remaining() , GL10.GL_UNSIGNED_BYTE , faceBuffer);


        //停止繪製
        gl.glFinish();
        //停用座標資料
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        //禁用紋理陣列
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

        roate+=1;
        if (roate == 360){
            roate = 0;
        }
    }


}