Objekte gemäß einem voreingestellten Programm wie dem rotierenden Dreieck bewegen zu können, ist nützlich, um Aufmerksamkeit zu erregen. Aber was ist, wenn Nutzer mit Ihrer OpenGL ES-Grafik interagieren sollen?
Wenn du deine OpenGL ES-App interaktiv gestalten möchtest, musst du deine Implementierung von GLSurfaceView
erweitern, damit onTouchEvent()
überschrieben wird, um Touch-Ereignisse zu erfassen.
In dieser Lektion erfahren Sie, wie Sie auf Touch-Ereignisse warten, damit Nutzer ein OpenGL ES-Objekt drehen können.
Touch-Listener einrichten
Damit Ihre OpenGL ES-Anwendung auf Touch-Ereignisse reagiert, müssen Sie die Methode onTouchEvent()
in Ihrer GLSurfaceView
-Klasse implementieren. Die folgende Beispielimplementierung zeigt, wie auf MotionEvent.ACTION_MOVE
-Ereignisse gewartet und diese in einen Drehwinkel einer Form übersetzt werden.
Kotlin
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 }
Java
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; }
Nach der Berechnung des Drehwinkels ruft diese Methode requestRender()
auf, um dem Renderer mitzuteilen, dass es Zeit ist, den Frame zu rendern. Dieser Ansatz ist in diesem Beispiel die effizienteste, da der Frame nur neu gezeichnet werden muss, wenn sich die Rotation ändert. Dies wirkt sich jedoch nicht auf die Effizienz aus, es sei denn, Sie legen fest, dass der Renderer nur neu zeichnen soll, wenn sich die Daten mit der Methode setRenderMode()
ändern. Achten Sie also darauf, dass diese Zeile im Renderer nicht als Kommentar gekennzeichnet ist:
Kotlin
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 } }
Java
public MyGLSurfaceView(Context context) { ... // Render the view only when there is a change in the drawing data setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); }
Drehwinkel angeben
Für den obigen Beispielcode müssen Sie den Drehwinkel durch den Renderer freigeben, indem Sie ein öffentliches Mitglied hinzufügen. Da der Renderer-Code in einem anderen Thread als dem Hauptthread der Benutzeroberfläche Ihrer Anwendung ausgeführt wird, müssen Sie diese öffentliche Variable als volatile
deklarieren.
Mit dem folgenden Code wird die Variable deklariert und das Getter- und Setter-Paar wird verfügbar gemacht:
Kotlin
class MyGLRenderer4 : GLSurfaceView.Renderer { @Volatile var angle: Float = 0f }
Java
public class MyGLRenderer implements GLSurfaceView.Renderer { ... public volatile float mAngle; public float getAngle() { return mAngle; } public void setAngle(float angle) { mAngle = angle; } }
Rotation anwenden
Um die durch die Berührungseingabe generierte Rotation anzuwenden, kommentieren Sie den Code aus, der einen Winkel generiert, und fügen Sie eine Variable hinzu, die den durch Berührung erzeugten Winkel enthält:
Kotlin
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) }
Java
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); }
Wenn Sie die oben beschriebenen Schritte ausgeführt haben, führen Sie das Programm aus und ziehen Sie Ihren Finger über den Bildschirm, um das Dreieck zu drehen:
![](https://developer.android.google.cn/static/images/opengl/ogl-triangle-touch.png?authuser=6&hl=de)
Abbildung 1: Dreieck, das mit Berührung gedreht wird (Kreis zeigt die Berührungsposition)