Заставить объекты двигаться в соответствии с заранее заданной программой, например вращающимся треугольником, полезно для привлечения внимания, но что, если вы хотите, чтобы пользователи взаимодействовали с вашей графикой OpenGL ES? Ключом к тому, чтобы сделать ваше приложение OpenGL ES интерактивным с помощью сенсорного управления, является расширение реализации GLSurfaceView
для переопределения onTouchEvent()
для прослушивания событий касания.
В этом уроке показано, как прослушивать события касания, чтобы пользователи могли вращать объект OpenGL ES.
Настройка сенсорного прослушивателя
Чтобы ваше приложение OpenGL ES реагировало на события касания, вы должны реализовать метод onTouchEvent()
в своем классе GLSurfaceView
. В приведенном ниже примере реализации показано, как прослушивать события 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 reports input details from the touch screen // and other input controls. In this case, you are only // interested in events where the touch position changed. 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 // reverse direction of rotation above the mid-line if (y > height / 2) { dx *= -1 } // reverse direction of rotation to left of the mid-line if (x < width / 2) { dy *= -1 } renderer.angle += (dx + dy) * TOUCH_SCALE_FACTOR requestRender() } } previousX = x previousY = y return true }
Ява
private final float TOUCH_SCALE_FACTOR = 180.0f / 320; private float previousX; private float previousY; @Override public boolean onTouchEvent(MotionEvent e) { // MotionEvent reports input details from the touch screen // and other input controls. In this case, you are only // interested in events where the touch position changed. float x = e.getX(); float y = e.getY(); switch (e.getAction()) { case MotionEvent.ACTION_MOVE: float dx = x - previousX; float dy = y - previousY; // reverse direction of rotation above the mid-line if (y > getHeight() / 2) { dx = dx * -1 ; } // reverse direction of rotation to left of the mid-line if (x < getWidth() / 2) { dy = dy * -1 ; } renderer.setAngle( renderer.getAngle() + ((dx + dy) * TOUCH_SCALE_FACTOR)); requestRender(); } previousX = x; previousY = y; return true; }
Обратите внимание, что после расчета угла поворота этот метод вызывает requestRender()
чтобы сообщить средству визуализации, что пришло время визуализировать кадр. Этот подход является наиболее эффективным в данном примере, поскольку кадр не нужно перерисовывать, пока не произойдет изменение поворота. Однако это не оказывает никакого влияния на эффективность, если вы также не запросите, чтобы средство рендеринга перерисовывалось только при изменении данных с помощью метода setRenderMode()
, поэтому убедитесь, что эта строка не закомментирована в средстве рендеринга:
Котлин
class MyGlSurfaceView(context: Context) : GLSurfaceView(context) { init { // Render the view only when there is a change in the drawing data renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY } }
Ява
public MyGLSurfaceView(Context context) { ... // Render the view only when there is a change in the drawing data setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); }
Выставляем угол поворота
В приведенном выше примере кода требуется, чтобы вы предоставили угол поворота через средство визуализации, добавив открытый член. Поскольку код средства рендеринга выполняется в отдельном потоке от основного потока пользовательского интерфейса вашего приложения, вы должны объявить эту общедоступную переменную как volatile
. Вот код для объявления переменной и предоставления пары геттер-сеттер:
Котлин
class MyGLRenderer4 : GLSurfaceView.Renderer { @Volatile var angle: Float = 0f }
Ява
public class MyGLRenderer implements GLSurfaceView.Renderer { ... public volatile float mAngle; public float getAngle() { return mAngle; } public void setAngle(float angle) { mAngle = angle; } }
Применить вращение
Чтобы применить вращение, генерируемое сенсорным вводом, закомментируйте код, который генерирует угол, и добавьте переменную, содержащую угол, созданный сенсорным вводом:
Котлин
override fun onDrawFrame(gl: GL10) { ... val scratch = FloatArray(16) // Create a rotation for the triangle // long time = SystemClock.uptimeMillis() % 4000L; // float angle = 0.090f * ((int) time); Matrix.setRotateM(rotationMatrix, 0, angle, 0f, 0f, -1.0f) // Combine the rotation matrix with the projection and camera view // Note that the mvpMatrix factor *must be first* in order // for the matrix multiplication product to be correct. Matrix.multiplyMM(scratch, 0, mvpMatrix, 0, rotationMatrix, 0) // Draw triangle triangle.draw(scratch) }
Ява
public void onDrawFrame(GL10 gl) { ... float[] scratch = new float[16]; // Create a rotation for the triangle // long time = SystemClock.uptimeMillis() % 4000L; // float angle = 0.090f * ((int) time); Matrix.setRotateM(rotationMatrix, 0, mAngle, 0, 0, -1.0f); // Combine the rotation matrix with the projection and camera view // Note that the vPMatrix factor *must be first* in order // for the matrix multiplication product to be correct. Matrix.multiplyMM(scratch, 0, vPMatrix, 0, rotationMatrix, 0); // Draw triangle mTriangle.draw(scratch); }
Выполнив описанные выше действия, запустите программу и проведите пальцем по экрану, чтобы повернуть треугольник: