OpenGL ES 環境では、投影とカメラビューを使用して、物理的オブジェクトを目で見るのとよく似た方法で描画されたオブジェクトを表示できます。この物理的な表示のシミュレーションは、描画されたオブジェクト座標を数学的に変換して行います。
- 投影 - この変換では、表示される
GLSurfaceView
の幅と高さに基づいて、描画オブジェクトの座標が調整されます。この計算を行わないと、OpenGL ES によって描画されるオブジェクトは、ビュー ウィンドウの不均一な比率によって偏りになります。通常、投影変換は、OpenGL ビューの比率がレンダラのonSurfaceChanged()
メソッドで確定または変更されている場合にのみ計算する必要があります。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(mProgram, "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(mProgram, "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); }
投影とカメラビューの変換を正しく計算して適用すると、グラフィック オブジェクトは正しい比率で描画され、次のようになります。
シェイプを正しい比率で表示するアプリケーションが完成しました。次に、シェイプにモーションを追加します。