[Android]OpenGL ESのひな型コード
- 2014年06月19日
- CATEGORY- 1. 技術力{技術情報}
OpenGLを知りたいなら、まずは動くコードをいじる事から始めてください。
基礎とか理論とか学習から入ってしまうと、退屈すぎて挫折するかもしれません。
それでは早速コードから。
activityのレイアウトにOpenGLのビューを追加します。
[layout/activity_main.xml]
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <android.opengl.GLSurfaceView android:id="@+id/surfaceView1" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
activityでは、onCreate,onResume,onPauseでOpenGLのビューのメソッドを呼び出します。
[MainActivity.java]
package com.example.gles1_3; import android.app.Activity; import android.opengl.GLSurfaceView; import android.os.Bundle; public class MainActivity extends Activity { private GLSurfaceView glView; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); glView = (GLSurfaceView)findViewById(R.id.surfaceView1); glView.setEGLConfigChooser(8, 8, 8, 8, 8, 8); glView.setRenderer(new MyRenderer()); } protected void onResume() { super.onResume(); glView.onResume(); } protected void onPause() { super.onPause(); glView.onPause(); } }
描画の実装は、activityでnewしたMyRendererクラスで行います。
物体を正常に表示させる為の必要最低限なコードは以下のとおりで、これがひな型になります。
[MyRenderer.java]
package com.example.gles1_3; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLES11; import android.opengl.GLSurfaceView; import android.opengl.GLU; public class MyRenderer implements GLSurfaceView.Renderer { public void onDrawFrame(GL10 gl10) { // バッファクリア GLES11.glClear(GLES11.GL_COLOR_BUFFER_BIT | GLES11.GL_DEPTH_BUFFER_BIT); //物体データ float mVertices[] = { 0, 1, 0, -1, 0, 0, 1, 0, 0, }; float mNormals[] = { 0, 0, 1, 0, 0, 1, 0, 0, 1, }; //物体の頂点を転送 FloatBuffer vertBuf = ByteBuffer.allocateDirect(mVertices.length * 4) .order(ByteOrder.nativeOrder()).asFloatBuffer(); vertBuf.put(mVertices).position(0); GLES11.glVertexPointer(3,GLES11.GL_FLOAT,0,vertBuf); //物体の法線を転送 FloatBuffer normalBuf = ByteBuffer.allocateDirect(mNormals.length * 4) .order(ByteOrder.nativeOrder()).asFloatBuffer(); normalBuf.put(mNormals).position(0); GLES11.glNormalPointer(GLES11.GL_FLOAT, 0, normalBuf); //物体の色を設定 GLES11.glMaterialfv(GLES11.GL_FRONT_AND_BACK, GLES11.GL_DIFFUSE, new float[]{1,1,0,0},0); GLES11.glMaterialfv(GLES11.GL_FRONT_AND_BACK, GLES11.GL_AMBIENT, new float[]{.1f,.1f,.1f,.0f},0); GLES11.glMaterialfv(GLES11.GL_FRONT_AND_BACK, GLES11.GL_SPECULAR, new float[]{.5f,.5f,.5f,.5f},0); GLES11.glMaterialfv(GLES11.GL_FRONT_AND_BACK, GLES11.GL_SHININESS, new float[]{64.0f},0); //カメラの設定 GLES11.glMatrixMode(GLES11.GL_MODELVIEW); GLES11.glLoadIdentity(); GLU.gluLookAt(gl10, 0,0,3, 0,0,0, 0,1,0); //物体の配置を決める GLES11.glRotatef(0, 1.0f, 0.0f, 0.0f); //描画する GLES11.glDrawArrays(GLES11.GL_TRIANGLES,0,mVertices.length/3); } public void onSurfaceChanged(GL10 gl10, int mWidth, int mHeight) { // ビューポート設定 GLES11.glViewport(0, 0, mWidth, mHeight); // 透視変換設定 GLES11.glMatrixMode(GLES11.GL_PROJECTION); GLES11.glLoadIdentity(); GLES11.glFrustumf(-1,1,-1,1,1f,100f); } public void onSurfaceCreated(GL10 arg0, EGLConfig arg1) { // 各配列の有効化 GLES11.glEnableClientState(GLES11.GL_VERTEX_ARRAY); GLES11.glEnableClientState(GLES11.GL_NORMAL_ARRAY); // カリング設定 GLES11.glEnable(GLES11.GL_CULL_FACE); GLES11.glFrontFace(GLES11.GL_CCW); //ライトの設定 GLES11.glEnable(GLES11.GL_LIGHTING); int light = GLES11.GL_LIGHT0; GLES11.glEnable(light); GLES11.glLightfv(light,GLES11.GL_POSITION, new float[]{.0f,.0f,.5f,.0f},0); GLES11.glLightfv(light,GLES11.GL_DIFFUSE, new float[]{.6f,.6f,.6f,.0f},0); GLES11.glLightfv(light,GLES11.GL_AMBIENT, new float[]{.6f,.6f,.6f,.0f},0); GLES11.glLightfv(light,GLES11.GL_SPECULAR, new float[]{.5f,.5f,.5f,.0f},0); } }
このひな型コードには、物体データとして三角形が定義してあります。
なので実行するとこのように表示されます。
今度は物体データを差し替え、別の物体を表示させます。
データ作成にはモデリングソフトを使いますが、説明がメンドイので
予め下茹でしたものがこちらでございます。
[MyRenderer.java]
//物体データ float f0=0.000000f,f1=1.000000f,f2=0.723600f,f3=0.447215f,f4=0.525720f; float f5=0.276385f,f6=0.850640f,f7=0.894425f,f8=0.187597f,f9=0.794651f; float fa=0.577354f,fb=0.607065f,fc=0.794652f,fd=0.491122f,fe=0.356829f; float ff=0.982246f,fg=0.303536f,fh=0.187589f,fi=0.934171f,fj=0.794649f; float fk=0.187587f,fl=0.577359f; float mVertices[]={ f0,-f1, f0, f2,-f3, f4,-f5,-f3, f6, f2,-f3, f4, f0,-f1, f0, f2,-f3,-f4, f0,-f1, f0,-f5,-f3, f6,-f7,-f3, f0, f0,-f1, f0,-f7,-f3, f0,-f5,-f3,-f6, f0,-f1, f0,-f5,-f3,-f6, f2,-f3,-f4, f2,-f3, f4, f2,-f3,-f4, f7, f3, f0, -f5,-f3, f6, f2,-f3, f4, f5, f3, f6,-f7,-f3, f0,-f5,-f3, f6,-f2, f3, f4, -f5,-f3,-f6,-f7,-f3, f0,-f2, f3,-f4, f2,-f3,-f4,-f5,-f3,-f6, f5, f3,-f6, f2,-f3, f4, f7, f3, f0, f5, f3, f6,-f5,-f3, f6, f5, f3, f6,-f2, f3, f4, -f7,-f3, f0,-f2, f3, f4,-f2, f3,-f4,-f5,-f3,-f6,-f2, f3,-f4, f5, f3,-f6, f2,-f3,-f4, f5, f3,-f6, f7, f3, f0, f5, f3, f6, f7, f3, f0, f0, f1, f0, -f2, f3, f4, f5, f3, f6, f0, f1, f0,-f2, f3,-f4,-f2, f3, f4, f0, f1, f0, f5, f3,-f6,-f2, f3,-f4, f0, f1, f0, f7, f3, f0, f5, f3,-f6, f0, f1, f0, }; float mNormals[]={ f8,-f9, fa, f8,-f9, fa, f8,-f9, fa, fb,-fc, f0, fb,-fc, f0, fb,-fc, f0, -fd,-fc, fe,-fd,-fc, fe,-fd,-fc, fe,-fd,-fc,-fe,-fd,-fc,-fe,-fd,-fc,-fe, f8,-f9,-fa, f8,-f9,-fa, f8,-f9,-fa, ff,-f8, f0, ff,-f8, f0, ff,-f8, f0, fg,-fh, fi, fg,-fh, fi, fg,-fh, fi,-fj,-fk, fl,-fj,-fk, fl,-fj,-fk, fl, -fj,-fk,-fl,-fj,-fk,-fl,-fj,-fk,-fl, fg,-fh,-fi, fg,-fh,-fi, fg,-fh,-fi, fj, fk, fl, fj, fk, fl, fj, fk, fl,-fg, fh, fi,-fg, fh, fi,-fg, fh, fi, -ff, f8, f0,-ff, f8, f0,-ff, f8, f0,-fg, fh,-fi,-fg, fh,-fi,-fg, fh,-fi, fj, fk,-fl, fj, fk,-fl, fj, fk,-fl, fd, fc, fe, fd, fc, fe, fd, fc, fe, -f8, f9, fa,-f8, f9, fa,-f8, f9, fa,-fb, fc, f0,-fb, fc, f0,-fb, fc, f0, -f8, f9,-fa,-f8, f9,-fa,-f8, f9,-fa, fd, fc,-fe, fd, fc,-fe, fd, fc,-fe, };
物体データの、mVerticesとmNormalsをこのコードに差し替えます。
実行結果はこうなります。
あとは、描画の度に物体の位置や角度を変えてやればアニメーションになります。
まず、回転を保持するクラス変数rxを定義します。
float rx=0;
onDrawFrame()の物体の配置を決めるコードで少しずつ回転を加えます。
//物体の配置を決める GLES11.glRotatef(rx+=1, 1.0f, 0.0f, 0.0f);
僅か2行の変更ですが、このように物体に動きが加わる事で立体らしく見えてきます。
glRotatefは物体を回転させるメソッドですが、平行移動させるglTranslatefという
メソッドもあります。この2つを組み合わせ、空間の好きな位置に物体を配置します。
同じ物体を何個も表示させるには、描画メソッドのglDrawArraysを何度も呼びだすだけです。
ただし、位置はずらしてやらないと重なって一つの物体にしか見えません。
コードはこんな感じになります。
for (int i=0;i<10;i++) { //カメラの設定 GLES11.glMatrixMode(GLES11.GL_MODELVIEW); GLES11.glLoadIdentity(); GLU.gluLookAt(gl10, 0,5,20, 0,6,0, 0,1,0); //物体を配置する GLES11.glTranslatef(i,0,0); //描画する GLES11.glDrawArrays(GLES11.GL_TRIANGLES,0,mVertices.length/3); }
同様にループ内でglMaterialfvを呼びだしてやれば、物体毎に色を変える事もできます。
物体を配置する、色を変える、何個も表示させるといった実装を大雑把に説明しましたが、
それらを駆使するだけでもこんなCGを作る事ができます。
3D空間上をリアルタイムに物体が動く、動かせるという事が楽しく面白い。
そこを突破口に徐々に難しい事に挑戦していけば、すんなりと習得できるのではないでしょうか。
色々な環境に対応してるので応用範囲は広いですし、身に付けて損はない気がします。
- 2014年06月19日
- CATEGORY- 1. 技術力{技術情報}