2010年3月27日土曜日

OpenGLによるグラフィックス描画

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

=\frac{1}{2^{2} }  + \frac{1}{2^{4} } +   \frac{1}{2^{6} } +   \frac{1}{2^{8} } +  \frac{1}{2^{10} } +  \frac{1}{2^{12} } + \frac{1}{2^{14} } +    \frac{1}{2^{16} }

=\frac{1}{4 }  + \frac{1}{16 } +   \frac{1}{64 } +   \frac{1}{256 } +  \frac{1}{1024 } +  \frac{1}{4096 } + \frac{1}{16384 } +    \frac{1}{65536 }

=\frac{1}{4 }  + \frac{1}{16 } +   \frac{1}{64 } +   \frac{1}{256 } +  \frac{1}{1024 } +  \frac{1}{4096 } + \frac{1}{16384 } +    \frac{1}{65536 }

=0.25 + 0.0625 + 0.015625 + 0.00390625 +とここまでやったが急に面倒くさくなってきたのでプログラムで結果をだすことにした。 -Naozary Unknown 10/03/12 0:10



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バイトが小数部を示すと考えてよいようだ。

0 件のコメント:

コメントを投稿