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; } }); } }
运行效果:
最后祝大家端午节快乐~~
相关文章推荐
- systrace跟踪 Android性能优化
- Android jni 使用C语言调用java中的log方法
- DataBinding用法
- android自定义控件,动态设置Button的样式
- Android实现自定义带文字和图片的Button
- 开源自定义控件
- 改变Android按钮背景颜色的高效方法
- Android 仿PhotoShop调色板应用(四) 不同区域颜色选择的颜色生成响应
- Android 仿PhotoShop调色板应用(三) 主体界面绘制
- Android 仿PhotoShop调色板应用(二) 透明度绘制之AlphaPatternDrawable
- Android 仿PhotoShop调色板应用(一)概述
- Android 颜色渲染(十) ComposeShader组合渲染
- Android 颜色渲染(九) PorterDuff及Xfermode详解
- Android 颜色渲染(八) SweepGradient扫描/梯度渲染
- Android 颜色渲染(七) RadialGradient 环形渲染实现水波纹效果
- Android 颜色渲染(六) RadialGradient 环形渲染
- Android 颜色渲染(五) LinearGradient线性渲染
- Android 颜色渲染(四) BitmapShader位图渲染
- Android 颜色渲染(三) Shader颜色渲染
- Android 颜色渲染(二) 颜色区域划分原理与实现思路