標籤:
OpenglES2.0 for Android:各種變換來一波監聽螢幕事件在進行各種變換之前,我們先來瞭解一下如何監聽螢幕的事件。我們下面的變換都需要用立方體來示範,所以我們繼續使用上一節的繪製立方體的內容首先建立一個項目 OpengESChange ,將上一節中關於繪製立方體的代碼複製過來 。在前面我們一直在使用android.opengl.GLSurfaceView在第一篇中我們已經知道了這個類的作用,為了監聽螢幕事件,我們建立一個類繼承自該類,重寫其onTouchEvent方法。此時該類 代碼如下 : (MySurfaceView.java ):
package com.cumt.opengeschange;import com.cumt.render.MyRender;import android.content.Context;import android.opengl.GLSurfaceView;import android.view.MotionEvent;public class MySurfaceView extends GLSurfaceView {private MyRender myRender;public MySurfaceView(Context context) {super(context);// TODO Auto-generated constructor stubmyRender = new MyRender(context);this.setEGLContextClientVersion(2);this.setRenderer(myRender);// 設定渲染模式為主動渲染this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);}@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubreturn super.onTouchEvent(event);}}
在onTouchEvent方法中我們就可以檢測到各種事件了 我們也可以使用GLSurfaceView的setOnTouchListener來監聽視圖的觸控事件 ,代碼如下(MySurfaceView.java ):
package com.cumt.opengeschange;import com.cumt.render.MyRender;import android.content.Context;import android.opengl.GLSurfaceView;import android.view.MotionEvent;import android.view.View;public class MySurfaceView extends GLSurfaceView {private MyRender myRender;public MySurfaceView(Context context) {super(context);// TODO Auto-generated constructor stubmyRender = new MyRender(context);this.setEGLContextClientVersion(2);this.setRenderer(myRender);// 設定渲染模式為主動渲染this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);this.setOnTouchListener(new OnTouchListener() {public boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubreturn false;}});}}
此時MainActivity也有稍微的改動 (MainActivity.java ):
package com.cumt.opengeschange;import android.app.Activity;import android.content.pm.ActivityInfo;import android.os.Bundle;import android.view.Window;import android.view.WindowManager;public class MainActivity extends Activity {private MySurfaceView glSurfaceView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 設定為全屏requestWindowFeature(Window.FEATURE_NO_TITLE);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);// 設定為橫屏模式setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);glSurfaceView = new MySurfaceView(this);setContentView(glSurfaceView);}@Overrideprotected void onPause() {// TODO Auto-generated method stubsuper.onPause();glSurfaceView.onPause();}@Overrideprotected void onResume() {// TODO Auto-generated method stubsuper.onResume();glSurfaceView.onResume();}}
此時我們的前期工作已經OK 了
平移變換先來看下平移變換矩陣 :
矩陣中的三個參數分別表示沿X ,Y,Z軸方向的位移
平移矩陣M 乘 當前P點的向量,即可得到平移後的P ‘ 點的向量 。
現在我們想要在原來繪製立方體的基礎上實現這樣的功能 :手指在螢幕上向左或向右移動時,我們的立方體向左或向右移動一段距離 。首先我們需要修改MatrixState中的代碼 ,建立一個平移變換矩陣 並初始化為單位矩陣,然後建立一個方法共外部調用以設定平移,最後修改我們原先的getFinalMatrix方法,在該方法中乘上該平移矩陣。過程如下代碼所示 (MatrixState.java ):
package com.cumt.utils;import android.opengl.Matrix;//儲存系統矩陣狀態的類public class MatrixState {private static float[] mProjMatrix = new float[16];// 4x4矩陣 儲存投影矩陣private static float[] mVMatrix = new float[16];// 攝像機位置朝向9參數矩陣/* * 第一步 :建立平移變換矩陣 */private static float[] mtMatrix = new float[16];// 平移變換矩陣/* * 第二步: 初始化為單位矩陣 */static{//初始化為單位矩陣Matrix.setIdentityM(mtMatrix, 0);}/* * 第三步 : 平移變換方法共外部使用 */public static void translate(float x,float y,float z)//設定沿xyz軸移動 { Matrix.translateM(mtMatrix, 0, x, y, z); }// 設定攝像機public static void setCamera(float cx, // 攝像機位置xfloat cy, // 攝像機位置yfloat cz, // 攝像機位置zfloat tx, // 攝像機目標點xfloat ty, // 攝像機目標點yfloat tz, // 攝像機目標點zfloat upx, // 攝像機UP向量X分量float upy, // 攝像機UP向量Y分量float upz // 攝像機UP向量Z分量) {Matrix.setLookAtM(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);}// 設定透視投影參數public static void setProjectFrustum(float left, // near面的leftfloat right, // near面的rightfloat bottom, // near面的bottomfloat top, // near面的topfloat near, // near面距離float far // far面距離) {Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);}// 擷取具體物體的總變換矩陣static float[] mMVPMatrix = new float[16];public static float[] getFinalMatrix() {/* * 第四步 : 乘以平移變換矩陣 */Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mtMatrix, 0);Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);return mMVPMatrix;}}
這裡我們使用靜態程式碼片段初始化平移矩陣為單位矩陣,如果使用者沒有設定平移變換矩陣,也不會影響原圖形。
然後我們在MySurfaceView中監聽使用者的螢幕移動事件 ,代碼如下 (MySurfaceView.java):
package com.cumt.opengeschange;import com.cumt.render.MyRender;import com.cumt.utils.MatrixState;import android.content.Context;import android.opengl.GLSurfaceView;import android.view.MotionEvent;import android.view.View;public class MySurfaceView extends GLSurfaceView {private MyRender myRender;private float mPreviousX;//上次的觸控位置X座標public MySurfaceView(Context context) {super(context);// TODO Auto-generated constructor stubmyRender = new MyRender(context);this.setEGLContextClientVersion(2);this.setRenderer(myRender);// 設定渲染模式為主動渲染this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);this.setOnTouchListener(new OnTouchListener() {public boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubfloat x = event.getX();//當前的觸控位置X座標switch (event.getAction()) {case MotionEvent.ACTION_MOVE://檢測到移動事件時float dx = x - mPreviousX;if(dx > 0){MatrixState.translate(0.1f, 0, 0);}else{MatrixState.translate(-0.1f, 0, 0);}}mPreviousX=x;return true;}});}}
來看下運行效果 :
旋轉變換看下旋轉矩陣 :
表示將點 P 繞向量 U 旋轉 θ 度 。在OpenGL中我們使用void android.opengl.Matrix.rotateM(float[] m,int mOffset,float a,float x, float y, float z)方法來設定旋轉 ,第一個參數表示返回的旋轉矩陣,mOffset表示位移量,一般設定為0 ,a 表示角度 ,x y z表示旋轉軸對應向量的X,Y,Z分量
下面我們來實現這樣一個功能 : 每點擊螢幕一次,讓我們的立方體沿著其 Y 軸旋轉30度
首先在我們原來的 MatrixState類中新增一個方法來設定旋轉 ,新增代碼如下 :
//旋轉變換public static void rotate(float angle, float x, float y, float z) {// 設定繞xyz軸移動Matrix.rotateM(mtMatrix, 0, angle, x, y, z);}
然後就在MySurfaceView類中設定監聽事件和旋轉 ,此時MySurfaceView.java代碼如下 :
package com.cumt.opengeschange;import com.cumt.render.MyRender;import com.cumt.utils.MatrixState;import android.content.Context;import android.opengl.GLSurfaceView;import android.view.MotionEvent;import android.view.View;public class MySurfaceView extends GLSurfaceView {private MyRender myRender;public MySurfaceView(Context context) {super(context);// TODO Auto-generated constructor stubmyRender = new MyRender(context);this.setEGLContextClientVersion(2);this.setRenderer(myRender);// 設定渲染模式為主動渲染this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);this.setOnTouchListener(new OnTouchListener() {public boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubswitch (event.getAction()) {case MotionEvent.ACTION_DOWN://檢測到點擊事件時MatrixState.rotate(30, 0, 1, 0);}return true;}});}}
我們運行看下效果:
縮放變換縮放矩陣 :
上面矩陣中三個參數分別表示縮放變換中的沿X,Y,Z軸方向的縮放率。
我們來實現下面的效果:點擊螢幕後進行一定比例的縮放操作 首先在MatrixState.java中加入如下代碼 :
//縮放變換public static void scale(float x,float y,float z) { Matrix.scaleM(mtMatrix,0, x, y, z); }
然後就在MySurfaceView類中設定監聽事件和縮放 ,此時MySurfaceView.java代碼如下 :
package com.cumt.opengeschange;import com.cumt.render.MyRender;import com.cumt.utils.MatrixState;import android.content.Context;import android.opengl.GLSurfaceView;import android.view.MotionEvent;import android.view.View;public class MySurfaceView extends GLSurfaceView {private MyRender myRender;public MySurfaceView(Context context) {super(context);// TODO Auto-generated constructor stubmyRender = new MyRender(context);this.setEGLContextClientVersion(2);this.setRenderer(myRender);// 設定渲染模式為主動渲染this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);this.setOnTouchListener(new OnTouchListener() {public boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubswitch (event.getAction()) {case MotionEvent.ACTION_DOWN://檢測到點擊事件時MatrixState.scale(0.4f, 1.5f, 0.6f);//xyz三個方向按各自的縮放因子進行縮放}return true;}});}}
運行效果:
最後祝大家端午節快樂~~
OpenglES2.0 for Android:各種變換來一波