OpenGL ES 環境では、投影とカメラビューを使用すると、物理オブジェクトと視覚的に近く見える描画オブジェクトを表示できます。この物体の視覚化は、描画オブジェクトの座標の数学的変換を使ってシミュレートされます。
- 投影 - この変換は、表示される
GLSurfaceView
の幅と高さに基づいて、描画オブジェクトの座標を調整します。この計算を行わないと、OpenGL ES によって描画されたオブジェクトのビュー ウィンドウの比率が不均衡になり、歪みが生じます。通常、レンダラのonSurfaceChanged()
メソッドで OpenGL ビューの比率が確立または変更される場合にのみ、投影変換を計算する必要があります。OpenGL ES の投影と座標マッピングの詳細については、描画オブジェクトの座標のマッピングをご覧ください。 - カメラビュー - この変換は、仮想カメラの位置に基づいて描画オブジェクトの座標を調整します。なお、OpenGL ES は実際のカメラ オブジェクトを定義しませんが、描画オブジェクトの表示を変換して、カメラをシミュレートするユーティリティ メソッドが用意されています。カメラビューの変換は、
GLSurfaceView
の確立時に 1 回だけ計算されるか、ユーザーの操作やアプリケーションの機能に基づいて動的に変更されます。
このレッスンでは、投影とカメラビューを作成し、GLSurfaceView
で描画した図形に適用する方法について説明します。
投影の定義
投影変換のデータは、GLSurfaceView.Renderer
クラスの onSurfaceChanged()
メソッドで計算されます。次のサンプルコードは GLSurfaceView
の高さと幅を取得、使用し、Matrix.frustumM()
メソッドを使用して投影変換の Matrix
を投入します。
Kotlin
// vPMatrix is an abbreviation for "Model View Projection Matrix" private val vPMatrix = FloatArray(16) private val projectionMatrix = FloatArray(16) private val viewMatrix = FloatArray(16) override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) { GLES20.glViewport(0, 0, width, height) val ratio: Float = width.toFloat() / height.toFloat() // this projection matrix is applied to object coordinates // in the onDrawFrame() method Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f) }
Java
// vPMatrix is an abbreviation for "Model View Projection Matrix" private final float[] vPMatrix = new float[16]; private final float[] projectionMatrix = new float[16]; private final float[] viewMatrix = new float[16]; @Override public void onSurfaceChanged(GL10 unused, int width, int height) { GLES20.glViewport(0, 0, width, height); float ratio = (float) width / height; // this projection matrix is applied to object coordinates // in the onDrawFrame() method Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7); }
このコードは投影行列 mProjectionMatrix
を投入します。これは、次のセクションで示す onDrawFrame()
メソッドでカメラビュー変換と結合できます。
注: 描画オブジェクトに投影変換を適用すると、通常はほとんど何も表示されません。一般に、画面に何かを表示するにはカメラビュー変換も適用する必要があります。
カメラビューの定義
描画オブジェクトの変換処理を完了するには、カメラビュー変換をレンダラの描画プロセスの一部として追加します。次のサンプルコードでは、Matrix.setLookAtM()
メソッドを使用してカメラビュー変換を計算し、以前に計算された投影行列と結合しています。組み合わされた変換行列は描画図形に渡されます。
Kotlin
override fun onDrawFrame(unused: GL10) { ... // Set the camera position (View matrix) Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, -3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f) // Calculate the projection and view transformation Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0) // Draw shape triangle.draw(vPMatrix)
Java
@Override public void onDrawFrame(GL10 unused) { ... // Set the camera position (View matrix) Matrix.setLookAtM(viewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); // Calculate the projection and view transformation Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0); // Draw shape triangle.draw(vPMatrix); }
投影とカメラ変換の適用
プレビュー セクションに表示される投影とカメラビューの変換行列を結合して使用するには、まず Triangle
クラスで以前に定義した頂点シェーダーに行列変数を追加します。
Kotlin
class Triangle { private val vertexShaderCode = // This matrix member variable provides a hook to manipulate // the coordinates of the objects that use this vertex shader "uniform mat4 uMVPMatrix;" + "attribute vec4 vPosition;" + "void main() {" + // the matrix must be included as a modifier of gl_Position // Note that the uMVPMatrix factor *must be first* in order // for the matrix multiplication product to be correct. " gl_Position = uMVPMatrix * vPosition;" + "}" // Use to access and set the view transformation private var vPMatrixHandle: Int = 0 ... }
Java
public class Triangle { private final String vertexShaderCode = // This matrix member variable provides a hook to manipulate // the coordinates of the objects that use this vertex shader "uniform mat4 uMVPMatrix;" + "attribute vec4 vPosition;" + "void main() {" + // the matrix must be included as a modifier of gl_Position // Note that the uMVPMatrix factor *must be first* in order // for the matrix multiplication product to be correct. " gl_Position = uMVPMatrix * vPosition;" + "}"; // Use to access and set the view transformation private int vPMatrixHandle; ... }
次に、グラフィック オブジェクトの draw()
メソッドを変更し、結合された変換行列を受け取って図形に適用します。
Kotlin
fun draw(mvpMatrix: FloatArray) { // pass in the calculated transformation matrix // get handle to shape's transformation matrix vPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix") // Pass the projection and view transformation to the shader GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, mvpMatrix, 0) // Draw the triangle GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount) // Disable vertex array GLES20.glDisableVertexAttribArray(positionHandle) }
Java
public void draw(float[] mvpMatrix) { // pass in the calculated transformation matrix ... // get handle to shape's transformation matrix vPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix"); // Pass the projection and view transformation to the shader GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, mvpMatrix, 0); // Draw the triangle GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount); // Disable vertex array GLES20.glDisableVertexAttribArray(positionHandle); }
投影とカメラビューの変換を正しく計算して適用すると、グラフィック オブジェクトは正しい比率で描画され、次のようになります。

図 1. 投影とカメラビューが適用された三角形の描画。
図形を正しい比率で表示するアプリケーションを作成できたので、続いて図形にモーションを追加しましょう。