AndroidがOpenGL ESを開発して3 D図形の実例を描きます。


OpenGL ESはOpenGLの三次元グラフィックAPIのサブセットであり、携帯電話、PDA、ゲームホストなどの組み込みデバイスに対して設計されている。OphoneはOpenGL ES 1.0をサポートしています。OpenGL 1.0はOpenGL 1.3仕様に基づいています。OpenGL ES 1.1はOpenGL 1.5仕様に基づいています。本稿ではOpenGL ESを利用した図形描画の基本的な手順を紹介します。
本論文の内容は三つの部分から構成されている。まずEGLを通してOpenGL ESのプログラミングインターフェースを獲得します。次に3 Dプログラムを構築する基本概念を紹介する。最後に、アプリケーションの例です。
OpenGL ESは本質的に図形描画パイプラインの状態マシンであり、EGLはこれらの状態を監視し、フレームバッファと他のレンダリング面を維持する外部層である。図1は、典型的なEGLシステムのレイアウト図である。EGLウィンドウズは、Microsoft Windows(WGL)やUNIX(GLX)でおなじみのOpenGLのNativeインターフェースに基づいています。後者に近いです。OpenGL ESグラフィックスパイプラインの状態はEGL管理のコンテキストに格納される。フレームバッファと他の描画レンダリング面は、EGL APIによって作成され、管理され、廃棄されます。EGLは同時に、デバイス表示と可能なデバイスレンダリング構成へのアクセスを制御し、提供する。

図1
OpenGL ESはレンダリングコンテキストとレンダリング面が必要です。レンダリングコンテキストにはOpenGL ESの状態情報が格納され、レンダリング面は図元の描画に使用されます。OpenGL ESを作成する前にEGLの操作が必要です。
クエリデバイスは、ハンドルを表示して初期化することができます。
描画面を作成し、OpenGL ESパターンを描画します。
レンダリングコンテキストを作成します。EGLは、あるレンダリング面に関連するOpenGL ESレンダリングコンテキストを作成する必要があります。
Ophoneの中でEGLは4つの種類を含んで、それぞれEGLODisplayです:ハンドルを表示して、EGLOConfigを表示します:配置種類;EGLOContect:コンテキストを描画します。のクラスとEGLOSurface:描画可能なビュークラスです。
EGLは、OpenGL ESとローカルウィンドウシステムとの中間層として考えられている。ローカルウィンドウシステムとはGNU/Linux上のXウィンドウシステム、またはMac OX's Quartzなどを指します。EGLがレンダリング面のタイプを決定する前に、EGLは下のウィンドウシステムと通信する必要がある。異なるオペレーティングシステムにおけるウィンドウシステムの違いにより、EGLは透明なウィンドウタイプ、すなわちEGLDisplayを提供する。それは各種のウィンドウシステムを抽象化した。まずEGLODisplayオブジェクトを作成、初期化します。

// EGLContext     getEGL  EGL  
EGL10 egl = (EGL10)EGLContext.getEGL();
//  EGLDisplay, EGL_DEFAULT_DISPLAY             
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
//   EGLDispla        
int[] version = new int[2];
egl.eglInitialize(dpy, version);
各EGLADisplayは使用前に初期化が必要です。EGLDisplayを初期化しながら、システムのEGLの実装バージョン番号を得ることができます。バージョン番号を通じて、対応するOpenGL ES APIを合理的に運用し、より多くのデバイスに適応し、最大限の移植性を提供するために、互換性の良いプログラムを作成することができる。初期化関数のプロトタイプ:
bollan egl Initialize(EGLADisplay、int[]major_minor)
その中のdisplayは有効なEGLADisplayの例である。関数の呼び出しが完了した場合、major_minorは現在のEGLバージョン番号を付与します。例えばEGL 1.0、major_minor[0]は1で、major_minor[1]は0です。EGLOSurfaceはEGLレンダリング面に関するすべての情報を含んでいます。EGLOSurfaceの設定情報を調べるには、二つの方法があります。一つは、すべての構成情報を調べ、その中から最適なものを選ぶことです。第二に、最適なマッチング結果がシステムによって与えられるように構成情報を指定することである。第二の方法を採用します。ユーザーはconfigSpecを通じて希望の構成を指定し、関数egl ChooseConfigはパラメータConfigsを通じて最適な構成リストを返します。得られたConfigsを利用して、eglCreateContectを呼び出してレンダリングコンテキストを作成し、この関数はEGLOContect構造に戻ります。レンダリング面EGLOSurfaceの作成は関数eglCreateWindowSurfaceによって行われます。一つのアプリケーションは複数のEGLOContextを作成することができます。egl Make Curentとは、あるレンダリングコンテキストをレンダリング面に結びつけることである。照会関数eglGetCurrenentCotext、eglGetCurent Display、eglGetCurentSurfaceは、それぞれ現在のシステムのレンダリングコンテキストを取得し、ハンドルとレンダリング面を表示するために使用されます。最後にEGGLO Contectの静的方法getGLはOpenGL ESのプログラミングインターフェースを獲得した。下記のプログラムセグメントは上記の内容をまとめました。

EGL10 egl = (EGL10)EGLContext.getEGL();
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); int[] version = new int[2];
egl.eglInitialize(dpy, version);
int[] configSpec = {
EGL10.EGL_RED_SIZE, 5,
EGL10.EGL_GREEN_SIZE, 6,
EGL10.EGL_BLUE_SIZE, 5,
EGL10.EGL_DEPTH_SIZE, 16,
EGL10.EGL_NONE
};
EGLConfig[] configs = new EGLConfig[1];
int[] num_config = new int[1];
egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config);
EGLConfig config = configs[0];
EGLContext context = egl.eglCreateContext(dpy, config,
EGL10.EGL_NO_CONTEXT, null);
EGLSurface surface = egl.eglCreateWindowSurface(dpy, config,
sHolder, null);
egl.eglMakeCurrent(dpy, surface, surface, context);
GL10 gl = (GL10)context.getGL();
3 D図形を構築するポイント
ポイントは3 Dモデル構築の基礎である。OpenGL ESの内部計算は点に基づいている。点で光源の位置、物体の位置も表すことができます。普通は浮動小数点のセットで点を表します。例えば正方形の4つの頂点は、次のように表されてもよい。

float vertices[] = {
-1.0f, 1.0f, 0.0f, //  
-1.0f, -1.0f, 0.0f, //  
1.0f, -1.0f, 0.0f, //  
1.0f, 1.0f, 0.0f, //  
};
性能を向上させるためには、浮動小数点配列をバイトバッファに保存する必要があります。ですから、次の操作があります。

ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
FloatBuffer vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
ここでByteOrder.native Order()は、本機のバイト順を取得するものである。OpenGL ESには操作パターンレンダリングパイプラインの関数があり、デフォルトではこれらの関数の使用状態は閉鎖されています。これらの関数を有効とオフにして、gl EnbeleClentState、gl DisplaleClientStateで完成できます。
//指定は指定行列を有効にする必要があります。
gl.gl EnbaleCientState(GL.GL_VERRT EX_ARRAY
//配列を有効にするタイプとバイトバッファを説明します。タイプはGL_です。FLOAT
gl.gl Ver texPointer(3,GL.GL_FLOAT,0,vertexBuffer);
//不要の場合は、頂点配列をオフにします。
gl.gl Discable CientState(GL.GL_VERRT EX_ARRAY

辺は2つの点を結ぶ線で、多角形の端です。
多角形
多角形は辺からなる単閉ループです。OpenGL ESの多角形は凸多角形でなければなりません。つまり多角形の内部で任意に2点を取ります。この2つの点を結ぶ線分は全部よく変わる内部にあります。この多角形は凸多角形です。多角形を描画するには、レンダリングの方向を指定し、時計回りと反時計回りに分けます。方向が多角形の向き、つまり正面と背面を決めるからです。それらの遮蔽された部分をレンダリングすることを回避することは、プログラム性能を効果的に向上させることができる。関数glFrontFaceは、レンダリング頂点の方向を定義しています。
//CCWの方向を設定するのは“正面”で、CCWはCounterClock Wiseで、反時計回り
glFrontFace(GL_CCW)
//CWの方向を設定するのは「正面」で、CWはCockWiseで、時計回りに
glFrontFace(GL_CW)
レンダリング
以上の概念を説明した後、今は最も主要な仕事をします。レンダリングは、物体座標で指定された図をフレームバッファに変換する画像です。画像と頂点座標は密接な関係があります。この関係は描画モードによって与えられる。よく使われる絵柄はGL_があります。POINTS、GL_LINE_STRIP、
GLLINE_LOOP、GL_LINE、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_ファンそれぞれ紹介します。
GLPOINTS:各頂点を一つの点として処理します。頂点nは点nを定義しています。

GLLINE:各頂点を独立した線分として、頂点2 n-1と2 nの間でn線分を定義し、全部でN/2線分を描きます。Nが奇数の場合、最後の頂点は無視されます。

GLLINE_STRIP:最初の頂点から最後の頂点まで順次接続された線分を描き、n番目とn+1番目の頂点で線分nを定義し、N-1線分を描きます。

GLLINE_LOOP:最初の頂点を定義してから最後の頂点まで順次接続する線分のセットを描き、最後の頂点を最初の頂点に接続します。n番目とn+1番目の頂点は線分nを定義し、最後の線分は頂点Nと1の間で定義され、全部でN線分を描画します。

GLTRIANGLES:3つの頂点ごとに独立した三角形とする。頂点3 n-2,3 n-1,3 nはn番目の三角形を定義し、全部でN/3三角形を描きます。

GLTRIANGLE_STRIP:三角形を描きます。奇数点n,頂点n,n+1,n+2についてn番目の三角形を定義した。偶数nについては、頂点n+1,n+2でn番目の三角形を定義し、N−2個の三角形を描く。

GLTRIANGLE_ファン:三角形を描く。三角形は最初の頂点とその後に与えられた頂点から決定される。頂点1、n+1、n+2は第nの三角形を定義し、全部でN−2の三角形を描きます。

描画関数:
void glDrawArays(int mode,int first,int count)
void glDrawElements(int mode,int count,int type,Buffer indices)
glDrawAraysは、各被配列の中でfirstから始まり、first+count C 1までの配列要素を使用して、modeを描画モードとして作成します。
glDrawElementsはcount個の要素を使用して図元シーケンスを定義し、typeはindices配列中のデータタイプであり、modeは描画モードであり、indices配列はトップを記憶する。
ポイントの索引値
使用例
上で説明した内容を利用してOphoneに3 D球形を描くプログラムを提供します。効果図は以下の通りです

図2球形の例
主な描画プログラム:

static private FloatBuffer vertex;//         
static private FloatBuffer normal;//          
float[] lightPos = new float[] {10.0f, 10.0f, 10.0f, 1.0f };//     
private static final int STEP = 24;//
private static final float RADIUS = 1.0f;//  
protected void init(GL10 gl) {
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//      
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos, 0);
gl.glEnable(GL10.GL_LIGHTING);//    
gl.glEnable(GL10.GL_LIGHT0); //    
gl.glClearDepthf(1.0f);//      
gl.glDepthFunc(GL10.GL_LEQUAL);//          ,GL_LEQUAL                                 
gl.glEnable(GL10.GL_DEPTH_TEST);//      
gl.glEnable(GL10.GL_CULL_FACE);
gl.glShadeModel(GL10.GL_SMOOTH);//      GL_SMOOTH
}
protected void drawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT |
GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, 0, 0, 7f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);//
drawSphere(gl, RADIUS, STEP, STEP); //    
}
public static void gluLookAt (GL10 gl, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)
これは全部で3組の座標を受け入れて、それぞれeye、センターとupです。eyeは私達の目が「世界座標系」の中の位置を表しています。センターは目の「見る」という点の座標を表しています。up座標は観察者自身の方向を表しています。観察点を私達の目に例えると、このupは私達が正立しているかそれとも逆の角度かを表しています。ここは正立方式です。だから{0,1,0}です。

private static void drawSphere(GL10 gl, float radius,
int stacks, int slices) {
vertex=allocateFloatBuffer( 4* 6 * stacks * (slices+1) );
normal=allocateFloatBuffer( 4* 6 * stacks * (slices+1) );
int i, j, triangles;
float slicestep, stackstep;
stackstep = ((float)Math.PI) / stacks;
slicestep = 2.0f * ((float)Math.PI) / slices;
for (i = 0; i < stacks; ++i)
{
float a = i * stackstep;
float b = a + stackstep;
float s0 = (float)Math.sin(a);
float s1 = (float)Math.sin(b);
float c0 = (float)Math.cos(a);
float c1 = (float)Math.cos(b);
float nv;
for (j = 0; j <= slices; ++j)
{
float c = j * slicestep;
float x = (float)Math.cos(c);
float y = (float)Math.sin(c);
nv=x * s0;
normal.put(nv);
vertex.put( nv * radius);
nv=y * s0;
normal.put(nv);
vertex.put( nv * radius);
nv=c0;
normal.put(nv);
vertex.put( nv * radius);
nv=x * s1;
normal.put(nv);
vertex.put( nv * radius);
nv=y * s1;
normal.put(nv);
vertex.put( nv * radius);
nv=c1;
normal.put(nv);
vertex.put( nv * radius);
}
}
normal.position(0);
vertex.position(0);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertex);
gl.glNormalPointer(GL10.GL_FLOAT, 0, normal);
gl.glEnableClientState (GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState (GL10.GL_NORMAL_ARRAY);
triangles = (slices + 1) * 2;
for(i = 0; i < stacks; i++)
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,
i * triangles, triangles);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
}
private static FloatBuffer allocateFloatBuffer(int capacity){
ByteBuffer vbb = ByteBuffer.allocateDirect(capacity);
vbb.order(ByteOrder.nativeOrder());
return vbb.asFloatBuffer();
}
まとめ:
OphoneにおけるOpenGL ESを用いた図形描画の基本概念と方法を紹介します。OpenGL ESにはテクスチャ、光照射、材質、混合、霧、蒙板、反射、3 Dモデルのロードなど他にも多くの内容があります。OpenGL ES関数を利用して、豊富なグラフィックスアプリケーションとゲームインターフェースを描画できます。