OpenGLを使用して図形を描画をする|Android開発

androidOpenGLを使って図形を描画をする手順です。

GLSurfaceView 継承クラスの作成

OpenGLで描画するためのビューを作成します。

  1. android.opengl.GLSurfaceViewを継承したクラス(ビュー)を定義する
  2. android.opengl.GLSurfaceView.Rendererを継承したクラスを定義する
  3. GLSurfaceViewを継承したクラスのコンストラクタでRendererを継承したクラスをsetRenderer()で設定する
  4. アクティビティまたはフラグメントでGLSurfaceViewを継承したクラス(ビュー)を追加する

Renderer の実装

  1. onSurfaceChanged()で描画の設定を行う
  2. onSurfaceChanged()でビューポート、フラスタムの設定を行う
  3. 描画が必要な時にコールされるonDrawFrame()で描画処理を行う

GLSurfaceView 継承クラスのサンプル

public class TestGLView extends GLSurfaceView {

    private Renderer mRenderer;

    private Draw2DObject mDrawObject;

    public TestGLView(Context context) {
        super(context);

        mRenderer = new LocalRenderer();
        setRenderer(mRenderer);

        mDrawObject = new Draw2DObject();
    }

    public class LocalRenderer implements Renderer {

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            // デプステストを設定. 隠れている面を表示しない. 後から書いた三角形で上書きしない.
            gl.glEnable(GL10.GL_DEPTH_TEST);
            gl.glDepthFunc(GL10.GL_LEQUAL);
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            // ここでビューポート、フラスタムの設定を行う.

            gl.glViewport(0, 0, width, height);
            // 投影変換モードへ.
            gl.glMatrixMode(GL10.GL_PROJECTION);
            // 投影変換の変換行列を単位行列で初期化.
            gl.glLoadIdentity();
            // フラスタムの設定.
            GLU.gluPerspective(gl, 50.0f, (float)width / height, 0.01f, 100.0f);
        }

        @Override
        public void onDrawFrame(GL10 gl) {
            // 描画時にコールされる.

            // バッファクリア.
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();

            // Z軸の視点を後ろにズラして手前が見えるようにする.
            gl.glTranslatef(0, 0, -3.f);

            mDrawObject.draw(gl);
        }
    }
}

参考

フラスタムの設定は下記サイトを参考にしました。
Androidアプリ開発 OpenGLで描画する [Android OpenGL]

Draw2DObjectについては、後述。

フラグメントでのビュー設定

public class GLTestFragment extends Fragment {

    private TestGLView mGLView;

    public GLTestFragment() {
    }

    public static GLTestFragment newInstance() {
        return new GLTestFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mGLView = new TestGLView(getActivity());
        return mGLView;
    }
}

描画処理

Renderer.onDrawFrame()で実際に描画するモデルを別クラスで定義したものが以下になります。

public class Draw2DObject {
    public final FloatBuffer mmVertexBuffer;

    public Draw2DObject() {
        float vertices[] = {
            -0.5f, -0.5f, 0.5f,
            0.5f, -0.5f, 0.5f,
            0.5f, 0.5f, 0.5f,
            -0.5f, 0.5f, 0.5f,
        };

        ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4); // floatは32biteなのでx4.
        vertexBuffer.order(ByteOrder.nativeOrder());
        mmVertexBuffer = vertexBuffer.asFloatBuffer();
        mmVertexBuffer.put(vertices);
        mmVertexBuffer.position(0);
    }

    public void draw(GL10 gl) {
        gl.glEnable(GL10.GL_TEXTURE_2D);

        // 頂点データでの描画をするよ.
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        // args:頂点を作る数(x,y,z=3), 型, 頂点間のバイトオフセット(連続データなら0), 配列
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mmVertexBuffer);

        // 描画処理.
    }
}

座標はX軸, Y軸, Z軸それぞれ-1.0~1.0の範囲で指定します。Z軸は画面手前が1.0、画面奥が-1.0になります。
描画処理の箇所はglDrawArrays()で描画します。glDrawArrays()のパラメータは描画モード, glVertexPointer()で指定した配列の開始インデックス, 頂点の数です。

描画モード

描画モード 描画内容
GL_POINTS 点を打つ
GL_TRIANGLES 3つの頂点で三角形を塗り潰す。それを繰り返し
GL_TRIANGLE_STRIP 連続する3つの頂点で塗り潰す(p1-p2-p3で塗り潰す、p2-p3-p4で塗り潰す...)
GL_TRIANGLE_FAN 始点を軸に扇状に三角形を塗り潰す(p1-p2-p3で塗り潰す、p1-p3-p4で塗り潰す...)
GL_LINES 2つの頂点で線を引く
GL_LINE_STRIP 頂点で線を引き続ける
GL_LINE_LOOP 各頂点を繋げる(始点と終点が結ばれる)

以下は各モードのサンプルになります。

GL_POINTS

gl.glDrawArrays(GL10.GL_POINTS, 0, 3);
GL_POINTS

見えにくいですが、白い点が3つあります。画像をクリックして拡大して見て頂ければ。

GL_TRIANGLES

gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
GL_TRIANGLES

GL_TRIANGLE_STRIP

gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
GL_TRIANGLE_STRIP

GL_TRIANGLE_FAN

gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, 4);
GL_TRIANGLE_FAN

GL_LINES

gl.glDrawArrays(GL10.GL_LINES, 0, 2);
GL_LINES
2本線を引く場合
gl.glDrawArrays(GL10.GL_LINES, 0, 4);
GL_LINES

GL_LINE_STRIP

gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, 4);
GL_LINE_STRIP

GL_LINE_LOOP

gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, 4);
GL_LINE_LOOP

点の大きさを変更する

gl.glPointSize(10.0f);
gl.glDrawArrays(GL10.GL_POINTS, 0, 3);
glPointSize

glPointSize()コール前の描画処理にも反映されます。

線の太さを変更する

gl.glLineWidth(8.0f);
gl.glDrawArrays(GL10.GL_LINES, 0, 2);
glLineWidth

glLineWidth()コール前の描画処理にも反映されます。

色を変更する

gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
glColor4f

glColor4f()コール前の描画処理にも反映されます。

X, Y 座標のみで描画する

glVertexPointer()の第1引数(頂点を構成する座標数)に2を設定します。

public class Draw2DObjectSimple {
    public final FloatBuffer mmVertexBuffer;

    public Draw2DObjectSimple() {
        float vertices[] = {
                0.0f, 0.5f,
                0.5f, -0.5f,
                -0.5f, -0.5f,
        };

        ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4); // floatは32biteなのでx4.
        vertexBuffer.order(ByteOrder.nativeOrder());
        mmVertexBuffer = vertexBuffer.asFloatBuffer();
        mmVertexBuffer.put(vertices);
        mmVertexBuffer.position(0);
    }

    public void draw(GL10 gl) {
        gl.glEnable(GL10.GL_TEXTURE_2D);

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glVertexPointer(2, GL10.GL_FLOAT, 0, mmVertexBuffer);
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
    }
}
このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

スポンサードリンク

関連コンテンツ

コメント

メールアドレスが公開されることはありません。 が付いている欄は必須項目です