AndoroidでOpenGLによるグラフィックス描画
・OpenGLで画像を描画する際には、サーフェイスと呼ばれる、専用のメモリ領域を確保する必要がある。
・描画手順
1.描画用バッファ(サーフェイス)のクリア
2.サーフェイスへの画像の描画
3.サーフェイス内容から画面への描画
【AndroidManifest.xml】
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="
com.naozary.gl.test"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name="
.Test_GLSurfaceView01"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
【Test_GLSurfaceView01.java】
package com.naozary.gl.test;
import android.app.Activity;
import android.os.Bundle;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.view.Window;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.util.Log;
/**
* Activity, Rendererを継承したクラス
*/
public class Test_GLSurfaceView01 extends Activity implements GLSurfaceView.Renderer
{
// GLSurfaceView
private GLSurfaceView gLSurfaceView;
// 三角形ポリゴン
private TestPolygon01 trianglePolygon;
/**
* @Override
* アクティビティ生成時に呼ばれる
*/
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.d(this.getClass().getName() ,"enter " + new Throwable().getStackTrace()[0].getMethodName() + "()");
// Log.d("Test_GLSurfaceView01" ,"*** enter onCreate ***");
// タイトルバーを消す
requestWindowFeature( Window.FEATURE_NO_TITLE );
// GLSurfaceView を生成
gLSurfaceView = new GLSurfaceView(this);
// レンダラーを生成してセット
gLSurfaceView.setRenderer(this);
// レイアウトのリソース参照は渡さず、直接Viewオブジェクトを渡す
//setContentView(R.layout.main);
setContentView(gLSurfaceView);
// ポリゴンの初期化
trianglePolygon = new TestPolygon01();
// Log.d("Test_GLSurfaceView01" ,"*** exit onCreate ***");
Log.d(this.getClass().getName() ,"exit " + new Throwable().getStackTrace()[0].getMethodName() + "()");
// Log.d(this.getClass().getName() ,Thread.currentThread().getStackTrace()[0].getMethodName());
// Log.d(this.getClass().getName() ,Thread.currentThread().getStackTrace()[1].getMethodName());
}
/**
* @Override
* 描画のために毎フレーム呼び出されるイベント
*/
public void onDrawFrame(GL10 gl)
{
Log.d(this.getClass().getName() ,"enter " + new Throwable().getStackTrace()[0].getMethodName() + "()");
// 描画用バッファをクリア
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// カメラ位置をセット
GLU.gluLookAt(
gl,
0.0f, 0.0f, 3.0f, // カメラ位置xyz
0.0f, 0.0f, 0.0f, // カメラの注視する点xyz
0.0f, 1.0f, 0.0f // カメラ視点上方向を表すベクトルxyz
);
// 頂点配列を使うことを宣言
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// 色情報配列を使うことを宣言
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
// 2Dテクスチャを無効に
gl.glDisable(GL10.GL_TEXTURE_2D);
// モデルビュー行列を指定
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 現在選択されている行列(モデルビュー行列)に、単位行列をセット
gl.glLoadIdentity();
// ポリゴンの描画メソッドを呼ぶ
trianglePolygon.draw(gl);
Log.d(this.getClass().getName() ,"exit " + new Throwable().getStackTrace()[0].getMethodName() + "()");
}
/**
* @Override
* サーフェイスのサイズ変更時に呼ばれる
* @param gl
* @param width 変更後の幅
* @param height 変更後の高さ
*/
public void onSurfaceChanged(GL10 gl, int width, int height)
{
Log.d(this.getClass().getName() ,"enter " + new Throwable().getStackTrace()[0].getMethodName() + "()");
// ビューポートをサイズに合わせてセットしなおす
gl.glViewport(0, 0, width, height);
// アスペクトレート
float ratio = (float) width / height;
// 射影行列を選択
gl.glMatrixMode(GL10.GL_PROJECTION);
// 現在選択されている行列(射影行列)に、単位行列をセット
gl.glLoadIdentity();
// 透視投影用の錐台のパラメータをセット
gl.glFrustumf(-ratio, ratio, -1.0f, 1.0f, 1.0f, 10.0f);
Log.d(this.getClass().getName() ,"exit " + new Throwable().getStackTrace()[0].getMethodName() + "()");
}
/**
* @Override
* サーフェイスが生成される際・または再生成される際に呼ばれる
*/
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
Log.d(this.getClass().getName() ,"enter " + new Throwable().getStackTrace()[0].getMethodName() + "()");
// ディザを無効化
gl.glDisable(GL10.GL_DITHER);
// カラーとテクスチャ座標の補間精度を、最も効率的なものに指定
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
// バッファ初期化時のカラー情報をセット
gl.glClearColor(0,0,0,1);
// 片面表示を有効に
gl.glEnable(GL10.GL_CULL_FACE);
// カリング設定をCCWに
gl.glFrontFace(GL10.GL_CCW);
// 深度テストを有効に
gl.glEnable(GL10.GL_DEPTH_TEST);
// スムースシェーディングにセット
gl.glShadeModel(GL10.GL_SMOOTH);
Log.d(this.getClass().getName() ,"exit " + new Throwable().getStackTrace()[0].getMethodName() + "()");
}
/**
* @Override
* ポーズ状態からの復旧時や、アクティビティ生成時などに呼ばれる
*/
protected void onResume()
{
Log.d(this.getClass().getName() ,"enter " + new Throwable().getStackTrace()[0].getMethodName() + "()");
super.onResume();
gLSurfaceView.onResume();
Log.d(this.getClass().getName() ,"exit " + new Throwable().getStackTrace()[0].getMethodName() + "()");
}
/**
* @Override
* アクティビティ一時停止時や、終了時に呼ばれる
*/
protected void onPause()
{
Log.d(this.getClass().getName() ,"enter " + new Throwable().getStackTrace()[0].getMethodName() + "()");
super.onPause();
gLSurfaceView.onPause();
Log.d(this.getClass().getName() ,"exit " + new Throwable().getStackTrace()[0].getMethodName() + "()");
}
}
【TestPolygon01.java】
package com.naozary.gl.test;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.util.Log;
/**
* 三角形ポリゴンのクラス
*/
public class TestPolygon01
{
// 頂点座標バッファ
private IntBuffer vertexBuffer;
// 色情報バッファ
private IntBuffer colorBuffer;
public TestPolygon01()
{
Log.d(this.getClass().getName() ,"enter " + new Throwable().getStackTrace()[0].getMethodName() + "()");
// 固定小数点値で1.0
int one = 0x10000;
// 頂点座標
int vertices[] = {
-one, one, 0,
-one, -one, 0,
one, -one, 0
};
// 頂点カラー
int colors[] = {
one, 0, 0, one,
0, one, 0, one,
0, 0, one, one
};
// ネイティブヒープ(ガベージコレクタが働かない領域)にバッファを作成
// サイズは、verticesの要素数×4バイト(int型なので)
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
// 作成したバッファをセットし、バッファに頂点情報を書き込む
vertexBuffer = vbb.asIntBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
cbb.order(ByteOrder.nativeOrder());
colorBuffer = cbb.asIntBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
Log.d(this.getClass().getName() ,"exit " + new Throwable().getStackTrace()[0].getMethodName() + "()");
}
/**
* @Override
* 描画
*/
public void draw(GL10 gl)
{
Log.d(this.getClass().getName() ,"enter " + new Throwable().getStackTrace()[0].getMethodName() + "()");
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertexBuffer);
gl.glColorPointer(4, GL10.GL_FIXED, 0, colorBuffer);
// 描画
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
Log.d(this.getClass().getName() ,"exit " + new Throwable().getStackTrace()[0].getMethodName() + "()");
}
}
【表示結果】
■ログ(呼び出しタイミング)
03-10 11:41:18.910: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onCreate()
03-10 11:41:19.060: DEBUG/com.naozary.gl.test.TestPolygon01(732): enter <init>()
03-10 11:41:19.111: INFO/jdwp(732): received file descriptor 24 from ADB
03-10 11:41:19.170: ERROR/GLLogger(732): couldn't load <libhgl.so> library (Cannot find library)
03-10 11:41:19.190: DEBUG/com.naozary.gl.test.TestPolygon01(732): exit <init>()
03-10 11:41:19.200: WARN/System.err(732): Can't dispatch DDM chunk 46454154: no handler defined
03-10 11:41:19.209: WARN/System.err(732): Can't dispatch DDM chunk 4d505251: no handler defined
03-10 11:41:19.231: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onCreate()
03-10 11:41:19.260: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onResume()
03-10 11:41:19.289: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onResume()
03-10 11:41:19.610: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onSurfaceCreated()
03-10 11:41:19.651: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onSurfaceCreated()
03-10 11:41:19.720: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onSurfaceChanged()
03-10 11:41:19.730: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onSurfaceChanged()
03-10 11:41:19.740: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onDrawFrame()
03-10 11:41:19.781: DEBUG/com.naozary.gl.test.TestPolygon01(732): enter draw()
03-10 11:41:19.790: INFO/ARMAssembler(732): generated scanline__00000097:03010144_00000000_00000000 [ 20 ipp] (73 ins) at [0x195140:0x195264] in 8937169 ns
03-10 11:41:19.800: DEBUG/com.naozary.gl.test.TestPolygon01(732): exit draw()
03-10 11:41:19.800: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onDrawFrame()
03-10 11:41:19.800: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onDrawFrame()
03-10 11:41:19.820: DEBUG/com.naozary.gl.test.TestPolygon01(732): enter draw()
03-10 11:41:19.820: DEBUG/com.naozary.gl.test.TestPolygon01(732): exit draw()
03-10 11:41:19.820: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onDrawFrame()
03-10 11:41:19.820: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onDrawFrame()
03-10 11:41:19.830: DEBUG/com.naozary.gl.test.TestPolygon01(732): enter draw()
03-10 11:41:19.830: DEBUG/com.naozary.gl.test.TestPolygon01(732): exit draw()
03-10 11:41:19.830: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onDrawFrame()
03-10 11:41:19.839: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onDrawFrame()
03-10 11:41:19.839: DEBUG/com.naozary.gl.test.TestPolygon01(732): enter draw()
03-10 11:41:19.839: DEBUG/com.naozary.gl.test.TestPolygon01(732): exit draw()
03-10 11:41:19.839: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onDrawFrame()
・
・繰り返し
・
・
03-10 11:41:32.201: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onDrawFrame()
03-10 11:41:32.230: DEBUG/com.naozary.gl.test.TestPolygon01(732): enter draw()
03-10 11:41:32.240: DEBUG/com.naozary.gl.test.TestPolygon01(732): exit draw()
03-10 11:41:32.250: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onDrawFrame()
03-10 11:41:32.259: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onDrawFrame()
03-10 11:41:32.272: DEBUG/com.naozary.gl.test.TestPolygon01(732): enter draw()
03-10 11:41:32.350: DEBUG/com.naozary.gl.test.TestPolygon01(732): exit draw()
03-10 11:41:32.370: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onDrawFrame()
03-10 11:41:32.401: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onDrawFrame()
03-10 11:41:32.411: DEBUG/com.naozary.gl.test.TestPolygon01(732): enter draw()
03-10 11:41:32.420: DEBUG/com.naozary.gl.test.TestPolygon01(732): exit draw()
03-10 11:41:32.420: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onDrawFrame()
03-10 11:41:32.430: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onDrawFrame()
03-10 11:41:32.430: DEBUG/com.naozary.gl.test.TestPolygon01(732): enter draw()
03-10 11:41:32.490: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): enter onPause()
03-10 11:41:32.500: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onPause()
03-10 11:41:32.521: DEBUG/com.naozary.gl.test.TestPolygon01(732): exit draw()
03-10 11:41:32.531: DEBUG/com.naozary.gl.test.Test_GLSurfaceView01(732): exit onDrawFrame()
03-10 11:41:43.160: DEBUG/dalvikvm(732): GC freed 4641 objects / 212952 bytes in 232ms
■メモ
1.頂点座標を以下のようにしてみた。(Test_TestPolygon01.javaのコンストラクタ)
// 頂点座標
int vertices[] = {
-one * 2, one * 2, 0,
-one, -one, 0,
one, -one, 0
};
【表示結果】
2.頂点座標を以下のようにしてみた。(Test_TestPolygon01.javaのコンストラクタ)
// 頂点座標
int vertices[] = {
-one * 2, one * 2, 0,
-one, -one, 0,
one, -one, 0
};
【表示結果】
3.頂点座標を以下のようにしてみた。(Test_TestPolygon01.javaのコンストラクタ)
// 頂点座標
int vertices[] = {
-one, one, 0,
-one, -one, 0,
one * 2 , -one * 2, 0
};
【表示結果】
4.頂点カラーを以下のようにしてみた。(Test_TestPolygon01.javaのコンストラクタ)
// 頂点カラー
int colors[] = {
one, one, 0, one, // RGBのRとGに1を指定
0, one, 0, one,
0, 0, one, one
};
【表示結果】
5.頂点カラーを以下のようにしてみた。(Test_TestPolygon01.javaのコンストラクタ)
// 頂点カラー
int colors[] = {
one, one, one, one, // RGBのR、G、Bに1を指定(白色になる)
0, one, 0, one,
0, 0, one, one
};
【表示結果】
6.カメラ位置をを以下のようにしてみた。(Test_GLSurfaceView01.javaのonDrawFrameメソッド)
// カメラ位置をセット
GLU.gluLookAt(
gl,
0.0f, 0.0f, 6.0f, // カメラ位置xyz
0.0f, 0.0f, 0.0f, // カメラの注視する点xyz
0.0f, 1.0f, 0.0f // カメラ視点上方向を表すベクトルxyz
);
【表示結果】
6.カメラ位置をを以下のようにしてみた。(Test_GLSurfaceView01.javaのonDrawFrameメソッド)
// カメラ位置をセット
GLU.gluLookAt(
gl,
0.0f, 0.0f, 1.0f, // カメラ位置xyz
0.0f, 0.0f, 0.0f, // カメラの注視する点xyz
0.0f, 1.0f, 0.0f // カメラ視点上方向を表すベクトルxyz
);
【表示結果】
■その他の気になるところのメモ
// 固定小数点値で1.0
int one = 0x10000;
の部分が気になっていた。
そこで、
int部分の下位2バイトが小数部を示すと仮定して考えてみた。
小数の二進数表現
0.1000 1/2 = 0.5
0.0100 1/(2*2) = 0.25
0.0010 1/(2*2*2) = 0.125
0.0001 1/(2*2*2*2) = 0.0625 0x5555 = (0101 0101 0101 0101)
2


=0.25 + 0.0625 + 0.015625 + 0.00390625 +
import com.naozary.test.nio.test01;
public class calcpoint {
public static void main(String[] args){
int s = 1;
// System.out.println("s = " + (2 << 1));
float r = 0;
StringBuffer sb = new StringBuffer();
for(int i=0;i<=7;i++){
s = (s * 4);
// System.out.println("1/s = " + (1/(float)s));
r += 1 / (float)s;
if(i!=0)sb.append(" + ");
sb.append("1/" + s);
}
sb.append(" = ");
// System.out.println("r = " + r);
sb.append(r);
System.out.println(sb.toString());
}
}
結果
1/4 + 1/16 + 1/64 + 1/256 + 1/1024 + 1/4096 + 1/16384 + 1/65536 = 0.33332825
よって、0x5555 = 0.3333
とりあえず、int部分の下位2バイトが小数部を示すと考えてよいようだ。