Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> OpenglES2.0 for Android:各種變換來一波

OpenglES2.0 for Android:各種變換來一波

編輯:關於Android編程

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 stub
		myRender = new MyRender(context);
		this.setEGLContextClientVersion(2);
		this.setRenderer(myRender);
		// 設置渲染模式為主動渲染
		this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		return 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 stub
		myRender = 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 stub
				return 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;

	@Override
	protected 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);
	}

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		glSurfaceView.onPause();
	}

	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		glSurfaceView.onResume();
	}
}


此時我們的前期工作已經OK 了

平移變換

先來看下平移變換矩陣 : vc/ytcTOu9LGPC9kaXY+CjxkaXY+PGJyPgo8L2Rpdj4KPGRpdj48aW1nIHNyYz0="/uploadfile/Collfiles/20160611/20160611095137238.png" alt="\">
平移矩陣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, // 攝像機位置x
			float cy, // 攝像機位置y
			float cz, // 攝像機位置z
			float tx, // 攝像機目標點x
			float ty, // 攝像機目標點y
			float tz, // 攝像機目標點z
			float 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面的left
			float right, // near面的right
			float bottom, // near面的bottom
			float top, // near面的top
			float 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 stub
		myRender = 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 stub
				float 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 stub
		myRender = 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 stub
				switch (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 stub
		myRender = 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 stub
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN://檢測到點擊事件時
					MatrixState.scale(0.4f, 1.5f, 0.6f);//xyz三個方向按各自的縮放因子進行縮放
				}
				return true;
			}
		});
	}
}


運行效果:


最後祝大家端午節快樂~~

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved