OpenGL ES (3):平面圖形-表面紋理貼圖
阿新 • • 發佈:2018-12-15
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; } } }