ちょっと話題の記事

Open GL ES入門

2012.09.30

こむろです。会社が秋葉原へ移転したため、ここ最近はiPhone5フィーバーに浮かれる方々をたくさん目にする機会がありましたが、私は、そのお祭りに参加できないド○モユーザーなので、羨望のまなざしで見ていました。こんにちは。

前回までのテーマとはがらっと変わり、AndroidやiPhoneに採用されている3Dグラフィックス描画のAPIの一つであるOpen GL ESの入門を少しずつ書いていこうと思います。前回までの連載っぽいのはどうした?と思われる方がいるかもしれませんが、コーナーが突然終わることは、深夜のラジオ番組のコーナーではよくあることです。

アニメーションや3Dグラフィックス表現は、目に見えて派手な結果がついてくるので、技術者としても楽しく学べるのではないかと思っています。ただ、一見すると、非常にハードルが高く、非常に膨大な知識を必要とするように見えてしまうので、なかなか手が出しづらい分野なのかもしれません。自分自身もそうでしたので、ここでは、コードを中心にして、少しずつボトムアップしていけるような内容にして行きたいと思います

Open GL ESとは?

Open GL ESとは、AndroidやiPhoneなどの携帯端末に搭載されいている、3Dグラフィックス用のAPIです。元々PC等で利用されているOpen GLという3Dグラフィックス描画用のAPIが存在します。いくつか機能を絞ったサブセットとして提供されています。

プラットフォームに依存しない設計であるため、基本的な考え方や操作方法の知識は、流用が可能です(微妙にプラットフォームごとの実装による違いはあるようですが)

APIバージョンについて

1.x系と2.0系では、大きく性質が異なります。大きな違いはその描画方法です。

1.x系は、固定機能パイプラインにて描画が行われます。決められた手順に従って、パラメータを転送すると簡単にグラフィックスの描画ができます。ただし、自由度が比較的低いため、高度な3Dグラフィックスを描画しようとすると、難しくなります。滑らかな皮膚や細かな描写が必要とする3Dグラフィックスの描画には向いていません

2.0系は、プログラマブルシェーダというものを利用して描画が行われます。固定機能パイプラインに比べ、非常に自由度が高いグラフィックスの描画が可能になります。反面、開発者が考慮しなければならない事柄が非常に膨大になります。

2.0は「素人お断り感」が非常に強いため、非常に高いハードルになっているようです。私のように3Dグラフィックスの知識も初等幾何学もうろ覚え、という方は1.x系から始めた方が無難だと思います。

Androidにおける利用可能なOpen GL ES API version

Androidは、Open GL ES 1.0、1.1、2.0が利用可能です。それぞれOSのバージョンによって使用可能なAPI Versionに制限がかかります

Android 1.5〜2.1 OpenGL ES 1.1/1.0
Android 2.2〜 OpenGL ES 2.0/1.1/1.0

APIの操作の特徴

Open GLは、状態を変更し、各種パラメータを転送することで描画を行っています。「今からグラフィックスの頂点座標を転送するよ」や「これからテクスチャの頂点座標を転送します」など、状況に合わせて状態を切り替えながら描画を行うためのパラメータを転送していくようです

最大の注意点

座標系が異なります!

通常のウィンドウ座標系だと次のように、左上を原点に絶対ピクセル数で表現されています。それ故に端末によってx座標、y座標のピクセル最大値が異なります

Open GL ESの描画座標系は原点は、画面の中心になります。また、全てfloatの1.0に正規化されます。

この座標系を意識していないと、全く描画されません。正規化された座標系の中で、-1から1の範囲で描画をすれば、どの端末でも同じように描画されるようです

サンプル

簡単なサンプルを動かしてみます

このクラスの中で色々と描画する命令を記述します[OpenGLSampleRenderer.java]

package jp.co.classmethod.sample.openglsamle;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView.Renderer;

public class OpenGLSampleRenderer implements Renderer {

	@Override
	public void onDrawFrame(GL10 gl) {
		// Frame毎に呼び出される描画メソッド
		
		// 描画内容をクリアする
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		// 大きさが変更されたときなどに呼び出される
		
		// 描画範囲を指定する
		gl.glViewport(0, 0, width, height);
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		
	}
}

Rendererは、GLSurfaceViewにセットします[MainActivity.java]

package jp.co.classmethod.sample.openglsamle;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        GLSurfaceView glSurfaceView = new GLSurfaceView(this);
        glSurfaceView.setRenderer(new OpenGLSampleRenderer());
        setContentView(glSurfaceView);
    }
}

このコードを実行すると次のような画面が表示されます

何も描画していないので当然何も描画されませんが、onDrawFrame()の箇所に、Logを差し込んでやると、以下のようにログが出力され続けているのが分かります

[Text] 09-30 22:15:39.469: D/jp.co.classmethod.sample.openglsamle.OpenGLSampleRenderer(18865): onDrawFrame : 1349010939476 09-30 22:15:39.489: D/jp.co.classmethod.sample.openglsamle.OpenGLSampleRenderer(18865): onDrawFrame : 1349010939490 09-30 22:15:39.509: D/jp.co.classmethod.sample.openglsamle.OpenGLSampleRenderer(18865): onDrawFrame : 1349010939518 09-30 22:15:39.539: D/jp.co.classmethod.sample.openglsamle.OpenGLSampleRenderer(18865): onDrawFrame : 1349010939542 09-30 22:15:39.559: D/jp.co.classmethod.sample.openglsamle.OpenGLSampleRenderer(18865): onDrawFrame : 1349010939567 [/Text]

とりあえず、これでOpen GL ESを利用する上での最低限の準備は整いました。次回からは少しずつ2次元グラフィックスの描画の基本のコードを解説していきます