OpenGL ES ビューにおいて描画する図形を定義することは、優れたハイエンド グラフィックスを作成するための第一歩です。OpenGL ES で描画を行う場合、グラフィック オブジェクトを定義する際に必要とされる基本的な知識がないと、困難になる可能性があります。
このレッスンでは、Android デバイス画面を基準とした OpenGL ES 座標系、図形と図形面の定義の基本、三角形と四角形の定義について説明します。
三角形を定義する
OpenGL ES では、3 次元空間上の座標を使用して描画オブジェクトを定義できます。そのため、三角形を描画する前に座標を定義する必要があります。OpenGL で定義する場合、座標の浮動小数点数の頂点配列を定義するのが一般的な方法です。最大限に効率化するには、この座標を ByteBuffer
に書き込みます。ByteBuffer は OpenGL ES グラフィックス パイプラインに渡されて処理されます。
Kotlin
// number of coordinates per vertex in this array const val COORDS_PER_VERTEX = 3 var triangleCoords = floatArrayOf( // in counterclockwise order: 0.0f, 0.622008459f, 0.0f, // top -0.5f, -0.311004243f, 0.0f, // bottom left 0.5f, -0.311004243f, 0.0f // bottom right ) class Triangle { // Set color with red, green, blue and alpha (opacity) values val color = floatArrayOf(0.63671875f, 0.76953125f, 0.22265625f, 1.0f) private var vertexBuffer: FloatBuffer = // (number of coordinate values * 4 bytes per float) ByteBuffer.allocateDirect(triangleCoords.size * 4).run { // use the device hardware's native byte order order(ByteOrder.nativeOrder()) // create a floating point buffer from the ByteBuffer asFloatBuffer().apply { // add the coordinates to the FloatBuffer put(triangleCoords) // set the buffer to read the first coordinate position(0) } } }
Java
public class Triangle { private FloatBuffer vertexBuffer; // number of coordinates per vertex in this array static final int COORDS_PER_VERTEX = 3; static float triangleCoords[] = { // in counterclockwise order: 0.0f, 0.622008459f, 0.0f, // top -0.5f, -0.311004243f, 0.0f, // bottom left 0.5f, -0.311004243f, 0.0f // bottom right }; // Set color with red, green, blue and alpha (opacity) values float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f }; public Triangle() { // initialize vertex byte buffer for shape coordinates ByteBuffer bb = ByteBuffer.allocateDirect( // (number of coordinate values * 4 bytes per float) triangleCoords.length * 4); // use the device hardware's native byte order bb.order(ByteOrder.nativeOrder()); // create a floating point buffer from the ByteBuffer vertexBuffer = bb.asFloatBuffer(); // add the coordinates to the FloatBuffer vertexBuffer.put(triangleCoords); // set the buffer to read the first coordinate vertexBuffer.position(0); } }
デフォルトでは、[0,0,0] (X,Y,Z) は GLSurfaceView
フレームの中心、[1,1,0] はフレームの右上隅、[-1,-1,0] はフレームの左下隅とみなされます。この座標系の図については、OpenGL ES デベロッパー ガイドをご覧ください。
この図形の座標は反時計回りで定義されているので、ご注意ください。描画順は重要です。描画順によって、どちらが図形の前面(通常、描画する面)か、背面(OpenGL ES 陰面消去機能により描画しないようにできる)かが定義されます。面と陰面消去の詳細については、OpenGL ES デベロッパー ガイドをご覧ください。
正方形を定義する
OpenGL における三角形の定義は簡単ですが、もっと複雑な場合はどうでしょうか。たとえば正方形の場合、定義方法はいくつかありますが、OpenGL ES で正方形を描画するには、2 つの三角形を同時に描画する方法が一般的です。

図 1. 2 つの三角形を使った正方形の描画。
繰り返しますが、この図形を表す 2 つの三角形について、反時計回りで頂点を定義し、その値を ByteBuffer
に設定する必要があります。各三角形が共有する 2 つの座標を 2 回定義せずに済ませるには、描画リストを使用して、この頂点の描画方法を OpenGL ES グラフィックス パイプラインに伝えます。この図形を描画するためのコードは次のとおりです。
Kotlin
// number of coordinates per vertex in this array const val COORDS_PER_VERTEX = 3 var squareCoords = floatArrayOf( -0.5f, 0.5f, 0.0f, // top left -0.5f, -0.5f, 0.0f, // bottom left 0.5f, -0.5f, 0.0f, // bottom right 0.5f, 0.5f, 0.0f // top right ) class Square2 { private val drawOrder = shortArrayOf(0, 1, 2, 0, 2, 3) // order to draw vertices // initialize vertex byte buffer for shape coordinates private val vertexBuffer: FloatBuffer = // (# of coordinate values * 4 bytes per float) ByteBuffer.allocateDirect(squareCoords.size * 4).run { order(ByteOrder.nativeOrder()) asFloatBuffer().apply { put(squareCoords) position(0) } } // initialize byte buffer for the draw list private val drawListBuffer: ShortBuffer = // (# of coordinate values * 2 bytes per short) ByteBuffer.allocateDirect(drawOrder.size * 2).run { order(ByteOrder.nativeOrder()) asShortBuffer().apply { put(drawOrder) position(0) } } }
Java
public class Square { private FloatBuffer vertexBuffer; private ShortBuffer drawListBuffer; // number of coordinates per vertex in this array static final int COORDS_PER_VERTEX = 3; static float squareCoords[] = { -0.5f, 0.5f, 0.0f, // top left -0.5f, -0.5f, 0.0f, // bottom left 0.5f, -0.5f, 0.0f, // bottom right 0.5f, 0.5f, 0.0f }; // top right private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices public Square() { // initialize vertex byte buffer for shape coordinates ByteBuffer bb = ByteBuffer.allocateDirect( // (# of coordinate values * 4 bytes per float) squareCoords.length * 4); bb.order(ByteOrder.nativeOrder()); vertexBuffer = bb.asFloatBuffer(); vertexBuffer.put(squareCoords); vertexBuffer.position(0); // initialize byte buffer for the draw list ByteBuffer dlb = ByteBuffer.allocateDirect( // (# of coordinate values * 2 bytes per short) drawOrder.length * 2); dlb.order(ByteOrder.nativeOrder()); drawListBuffer = dlb.asShortBuffer(); drawListBuffer.put(drawOrder); drawListBuffer.position(0); } }
この例では、OpenGL でより複雑な図形を作成する方法を説明しています。一般に、複数の三角形を組み合わせてオブジェクトを描画します。次のレッスンでは、こうした図形を画面に描画する方法を説明します。