您的位置:首页 > 移动开发 > Android开发

OpenglES2.0 for Android:各种变换来一波

2016-06-09 09:04 253 查看

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 了

平移变换

先来看下平移变换矩阵 :



矩阵中的三个参数分别表示沿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, // 摄像机位置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;
}
});
}
}


运行效果:



最后祝大家端午节快乐~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: