08、Android OpenGL学习-响应触摸事件

89 阅读2分钟

让对象根据预设程序移动(如旋转三角形)对于吸引注意力很有用,但是如果您想让用户与您的 OpenGL ES 图形交互怎么办?使您的 OpenGL ES 应用程序触摸交互的关键是扩展 GLSurfaceView 的实现以覆盖 onTouchEvent() 以侦听触摸事件。

本课向您展示如何侦听触摸事件以让用户旋转 OpenGL ES 对象。

设置一个触摸监听

为了使您的 OpenGL ES 应用程序响应触摸事件,您必须在 GLSurfaceView 类中实现 onTouchEvent() 方法。下面的示例实现显示了如何侦听 MotionEvent.ACTION_MOVE 事件并将它们转换为形状的旋转角度。

private const val TOUCH_SCALE_FACTOR: Float = 180.0f / 320f
...
private var previousX: Float = 0f
private var previousY: Float = 0f

override fun onTouchEvent(e: MotionEvent): Boolean {
    // MotionEvent 报告来自触摸屏和其他输入控件的输入详细信息。
    // 在这种情况下,您只对触摸位置发生变化的事件感兴趣。

    val x: Float = e.x
    val y: Float = e.y

    when (e.action) {
        MotionEvent.ACTION_MOVE -> {

            var dx: Float = x - previousX
            var dy: Float = y - previousY

            // 中线上方反向旋转
            if (y > height / 2) {
                dx *= -1
            }

            // 向中线左侧反向旋转
            if (x < width / 2) {
                dy *= -1
            }

            renderer.angle += (dx + dy) * TOUCH_SCALE_FACTOR
            requestRender()
        }
    }

    previousX = x
    previousY = y
    return true
}

请注意,在计算出旋转角度后,此方法会调用 requestRender() 以告知渲染器该渲染帧了。这种方法在这个例子中是最有效的,因为除非旋转发生变化,否则不需要重新绘制框架。但是,它对效率没有任何影响,除非您还使用 setRenderMode() 方法请求渲染器仅在数据更改时重绘,因此请确保在渲染器中取消注释此行:

class MyGlSurfaceView(context: Context) : GLSurfaceView(context) {

    init {
        // 仅当绘图数据发生变化时才渲染视图
        renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
    }
}

暴露旋转角度

上面的示例代码要求您通过添加公共成员来通过渲染器公开旋转角度。由于渲染器代码在与应用程序的主用户界面线程不同的线程上运行,因此您必须将此公共变量声明为 volatile。下面是声明变量并公开 getter 和 setter 对的代码:

class MyGLRenderer4 : GLSurfaceView.Renderer {

    @Volatile
    var angle: Float = 0f
}

应用旋转

要应用触摸输入生成的旋转,请注释掉生成角度的代码并添加一个包含触摸输入生成的角度的变量:

override fun onDrawFrame(gl: GL10) {
    ...
    val scratch = FloatArray(16)

    // 为三角形创建一个旋转
    // long time = SystemClock.uptimeMillis() % 4000L;
    // float angle = 0.090f * ((int) time);
    Matrix.setRotateM(rotationMatrix, 0, angle, 0f, 0f, -1.0f)

    // 将旋转矩阵与投影和相机视图组合请注意,mvpMatrix 因子必须在第一位才能使矩阵乘积正确。
    Matrix.multiplyMM(scratch, 0, mvpMatrix, 0, rotationMatrix, 0)

    // Draw triangle
    triangle.draw(scratch)
}

完成上述步骤后,运行程序并在屏幕上拖动手指以旋转三角形: