Androidアプリ開発 OpenGL アルファテスト

テクスチャマップでドロイド君のアイコンを貼りつけることができた。なかなかCGらしくなってきたので、楽しくなってオブジェクトを4つに増やしてみた。視点の移動で動かせるので、回転はやめたり、ライトを普通の白にしたりとコードを整理してみた。

@Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// ライティングをON
gl.glEnable(GL10.GL_LIGHTING);
// 光源を有効にして位置を設定
gl.glEnable(GL10.GL_LIGHT0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightpos, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, white, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, white, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, white, 0);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
// カメラ位置を設定
GLU.gluLookAt(gl, eyepos[0], eyepos[1], eyepos[2], 0, 0, 0, 0, 1, 0);
// デプステスト
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glDepthMask(true);
// 陰面消去
gl.glEnable(GL10.GL_CULL_FACE);
gl.glCullFace(GL10.GL_BACK);
// スムースシェーディング
gl.glShadeModel(GL10.GL_SMOOTH);
// マテリアル
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, gray, 0);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, gray, 0);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, gray, 0);
gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, 80f);
// テクスチャ
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glPushMatrix();		// マトリックス記憶
gl.glTranslatef(1, 0, 0);
model.draw(gl);
gl.glPopMatrix();		// マトリックスを戻す
// ふたつめの描画
gl.glPushMatrix();		// マトリックス記憶
gl.glTranslatef(-1, 0, 0);
model.draw(gl);
gl.glPopMatrix();		// マトリックスを戻す
// 3つめの描画
gl.glPushMatrix();		// マトリックス記憶
gl.glTranslatef(1, 0, -2);
model.draw(gl);
gl.glPopMatrix();		// マトリックスを戻す
// 4つめの描画
gl.glPushMatrix();		// マトリックス記憶
gl.glTranslatef(-1, 0, -2);
model.draw(gl);
gl.glPopMatrix();		// マトリックスを戻す
}

これで、「ぐりぐり」してみたのが、以下の動画である。

なかなか、楽しい。
しかし、アイコン画像の透明な部分が「黒で塗りつぶされて」しまっている。手前のドロイド君の足のあたりから、奥のドロイド君が見えるはずなのだが、そうはなってくれない。
アイコン画像は、png形式でアルファチャネルを持っている。実際のラウンチャ画面でも透明な部分は壁紙が透けて見えているではないか。
OpenGLでは、アルファチャネルの値がどうなっていても色の計算が行われる。アルファ値により描画しない(ピクセルを打たない)といったことができる。この機能は、「アルファテスト」と呼ばれるもの。
デプステストが、デプスバッファに書き込まれている「深度」により描画する/しないを試験していたのに対して、アルファテストは、今から描画しようとしているポリゴンのアルファ値と設定されている閾値を比較して、描画する/しないを決定する。
アルファテストをするのは簡単。glEnable(GL_ALPHA_TEST)でアルファテスト機能を有効にして、glAlphaFunc(GL_GEQUAL, 0.1f)で描画するアルファ値の条件を設定すればよいだけ。
GEQUAL, 0.1で、0.1以上のアルファ値である場合に描画される。
アルファテストでは、半透明は実現できない。描画する/しないのどちらかになる。
それでは、やってみよう。

@Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// ライティングをON
gl.glEnable(GL10.GL_LIGHTING);
// 光源を有効にして位置を設定
gl.glEnable(GL10.GL_LIGHT0);
:
:
// デプステスト
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glDepthMask(true);
// アルファテスト
gl.glEnable(GL10.GL_ALPHA_TEST);
gl.glAlphaFunc(GL10.GL_GEQUAL, 0.1f);
// 陰面消去
gl.glEnable(GL10.GL_CULL_FACE);
gl.glCullFace(GL10.GL_BACK);


おお、ちゃんと透けてるではないか。
本来のCGなら「ちゃんとモデルを作れ」っていう話なのかも知れないが、リソースの少ないandroidなら、こういうのもあり?ということにしておく。

投稿者プロフィール

asai
asai
システムエンジニア
喋れる言語:日本語、C言語、SQL、JavaScript