Androidアプリ開発 OpenGL アルファブレンド

アルファテストを使うことで「アルファ値が小さい部分を描画しない」といったことができるようになった。アルファブレンドでも同じようなことができる。
アルファテストでは、描画する/しないのどちらかであったが、アルファブレンドでは、半透明な感じにすることができる。
アルファブレンドは、GL_BLENDを有効にすると機能する。アルファブレンドしたら、アルファテストは必要ないので、コメントアウトしている。また、ブレンドして混ぜる必要があるので奥にある面も描画しないといけない。なので、デプステストもコメントアウトして無効にしている。

@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_BLEND);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE);
/*
// アルファテスト
gl.glEnable(GL10.GL_ALPHA_TEST);
gl.glAlphaFunc(GL10.GL_GEQUAL, 0.1f);
*/
// 陰面消去
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();		// マトリックスを戻す
}


いきなり面白い絵になった。
重なっている部分が明るく表示されている。現実にはあり得ない感じの絵になっている。「レントゲン写真のよう」とも表現できるか。
どうして明るくなるかというと、色をブレンドしたから。ブレンドするといっても単純にRGBAの値を足し算しているだけなので、数値はどんどん高くなる。色の数値は、最大で1.0なので、1.0より大きくなることはない。ちょうどカメラでいうところの「白飛び」した状態になる。
単純に足し算するのではなく、描画済の色のアルファ値を差し引いた分の濃度で上書きするといったことも可能ではある。ブレンド方法は、glBlendFuncで指定できる。
今現在は、glBlendFunc(GL_ONE, GL_ONE)となっており、単純に足し算する方法。これを以下のように変更してみる。
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
そうすると、透明な部分だけが透けて見える感じになる。半透明にはならない。
ちょっと計算式があって面倒なので、詳細な説明は、以下のサイトを参考にして欲しい。それぞれの引数は、ソース、ディスティネーションの係数を意味しているのだが、私もよくわかっていなかったりする。

http://blog.jyoken.net/?eid=553888

で、GL_ONE_MINUS_SRC_ALPHAに変更すると、半透明ではなく、透明な部分だけが見えるようにはなるのではあるが、デプステストをやっていないので、後の方で描画している奥のドロイド君が手前に表示されてしまっている。
上記のサイトでも解説されているように、アルファブレンドする場合は、奥のオブジェクトから順番に描画してやらないとだめである。
ちょっとおおがかりになってきそうなので、回を改めることにする。

投稿者プロフィール

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