OpenGL中添加Motion
书接上文,Android OpenGL二 —— 使用投影和相机变换
在屏幕上绘制对象,是OpenGL比较基本的特性。如果你只想做这些,你完全可以使用包括Canvas和Drawable类的Android的图形框架。
OpenGL ES为三维空间中的对象绘制,扩展了移动、变换等引人入胜的用户体验。
In this lesson, you take another step forward into using OpenGL ES by learning how to add motion to a shape with rotation
对图形做旋转操作
对绘制的对象做旋转操作相当简单。在你的渲染器中,另外创建一个关于旋转的转换矩阵,然后和你的投影和相机转换视图矩阵链接起来(有关投影和相机视图,请查看上一篇文章)。
private float[] mRotationMatrix = new float[16];
public void onDrawFrame(GL10 gl) {
float[] scratch = new float[16];
...
// 为三角形创建旋转变换
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.090f * ((int) time);
Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, -1.0f);
// 将旋转矩阵和投影、相机视图链接到一起
// 为了矩阵乘积的正确性,必须将*mMVPMatrix*放在首位
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
// 绘制三角形
mTriangle.draw(scratch);
}
添加了上述代码后,如果你的三角形还不能旋转,请确认你是否添加了 GLSurfaceView.RENDERMODE_WHEN_DIRTY设置。
启用连续绘制
如果你严格按照该系列博客编写代码,确保你已经注释掉将渲染模式设置为只要当图形改变时才绘制的代码,否则图形的旋转只用在requestRender()才会生效。如下:
public MyGLSurfaceView(Context context) {
...
// 只要当绘制数据发生变化时才绘制视图
//为了使三角形能够自动旋转,注释掉这句
//setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
这个绘制模式的设置,如非必要,请尽量打开。
响应触控事件
想要让你设计的OpenGL ES图形和用户做交互。只需要继承GLSurfaceView的类重写GLSurfaceView 的onTouchEvent()方法,用于监听触控事件。
设置触控监听
private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
private float mPreviousX;
private float mPreviousY;
@Override
public boolean onTouchEvent(MotionEvent e) {
// 触摸事件用各种输入设备传递,现在流行的触控屏就是典型的触摸事件输入设备。
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {//监听Move事件
case MotionEvent.ACTION_MOVE:
float dx = x - mPreviousX;
float dy = y - mPreviousY;
// 中轴线上,旋转的反方向
if (y > getHeight() / 2) {
dx = dx * -1 ;
}
// 反向旋转至中轴左边
if (x < getWidth() / 2) {
dy = dy * -1 ;
}
//设置计算好的转角
mRenderer.setAngle(
mRenderer.getAngle() +
((dx + dy) * TOUCH_SCALE_FACTOR));
requestRender();//通知渲染器,是时候绘制了。
}
mPreviousX = x;
mPreviousY = y;
return true;
}
再次提醒,如果发现无效的话,请检查如下代码是否取消注释。
public MyGLSurfaceView(Context context) {
...
// 绘制数据发生变化时,才绘制视图
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
暴露旋转角
上面的实例代码的正常运行,需要将旋转角通过公共的方法在渲染器中暴露出来。因为,渲染器代码试运行在主线程以外的线程中的,所以,变量需要加上volatile申明。下面是实例代码:
public class MyGLRenderer implements GLSurfaceView.Renderer {
...
public volatile float mAngle;
public float getAngle() {
return mAngle;
}
public void setAngle(float angle) {
mAngle = angle;
}
}
应用
为了使用通过触控输入的转角,现将生成angle和mAngle的代码注释掉,因为它们包含触控生成角度的代码。
public void onDrawFrame(GL10 gl) {
...
float[] scratch = new float[16];
// 为三角形创建旋转变换
// long time = SystemClock.uptimeMillis() % 4000L;
// float angle = 0.090f * ((int) time);
Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
// 将旋转矩阵和投影、相机视图链接到一起
// 为了矩阵乘积的正确性,必须将*mMVPMatrix*放在首位
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
// Draw triangle
mTriangle.draw(scratch);
}