让对象按预设程序进行移动确实可以吸引一些注意,比如旋转三角形。但如果你想用OpenGL ES制图实现用户交互,又该怎么做呢?让你的OpenGL ES应用具有触摸交互的关键在于扩展对 GLSurfaceView 类的实现,重写 onTouchEvent() 来监听触摸事件。
本文主要向你展示如何监听触摸事件,从而让用户来旋转一个OpenGL ES对象。
建立一个触摸监听器 - Setup a Touch Listener
为了让你的OpenGL ES应用程序对触摸事件做出响应,你需要实现 GLSurfaceView 类的 onTouchEvent() 方法。下面的一个实现的例子演示了如何监听 MotionEvent.ACTION_MOVE 事件,并把他们转换成图形旋转的一个角度。
- @Override
- public boolean onTouchEvent(MotionEvent e) {
- // MotionEvent提供了触摸的输入的细节以及其他输入控制信息。
- //在这种情况下,你只需要关心触摸位置改变的事件。
- float x = e.getX();
- float y = e.getY();
- switch (e.getAction()) {
- 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.mAngle +180.0f / 320
- requestRender();
- }
- mPreviousX = x;
- mPreviousY = y;
- return true;
- }
需要注意的是,计算好旋转角度后,这个方法调用了 requestRender() 来通知渲染器渲染画面。由于这个画面在没有旋转的变化时无需重绘,因此在本例中使用这种做法最高效。然而,如果你没有用 setRenderMode() 方法请求渲染器仅在数据改变时才重绘,那么这种做法就不会对效率有影响了。因此,确保取消掉渲染器里对这一行代码的注释。
- public MyGLSurfaceView(Context context) {
- ...
- //仅当绘图数据改变时绘制视图
- setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
- }
显示旋转的角度 - Expose the Rotation Angle
上面的示例代码需要你在渲染器中添加一个公共成员来显示旋转角度。由于渲染器的代码所运行的线程独立于应用程序的用户界面主线程之外,因此,你必须将这个公共变量声明为 volatile。参见下面的代码:
- public class MyGLRenderer implements GLSurfaceView.Renderer {
- ...
- public volatile float mAngle;
应用旋转 - Apply Rotation
要让触摸输入产生旋转,就需要注释掉生成角度的代码,改用触摸输入生成的角度 mAngle:
- public void onDrawFrame(GL10 gl) {
- ...
- //为三角形创建旋转
- // long time = SystemClock.uptimeMillis() % 4000L;
- // float angle = 0.090f * ((int) time);
- Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
- //将旋转矩阵与投影和相机视图相结合
- Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
- //绘制三角形
- mTriangle.draw(mMVPMatrix);
- }
当你完成了以上步骤,运行程序,就可以在屏幕上拖动来旋转那个三角形了。
图1.三角形在触摸下旋转(圆圈表示触摸位置)