Androidアプリ開発 OpenGL テクスチャを貼りつけたときのハイライト

前回、何に使うかわからない、と書いた(GL_SRC_ALPHA, GL_ONE)でのブレンド方法であるが、使い方を発見してしまった。
まず、OpenGL ESでは、テクスチャを貼ると、ハイライトが出ない(陰影は付くのではあるが)。スペキュラの値を調整してもテクスチャ画像の色より大きくなることがない。なので、白いハイライトは出ません。ということらしい。
以下のサイトに詳しく書いてある。

床井先生のところはすごく丁寧に書いてある。
無印のOpenGLならglLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR)といった設定をすれば、ハイライトが出るようになるらしいのだが、OpenGL ESには、残念ながらこの機能はない(もしかすると、サポートしている端末もあるかも知れない)。
しかし、そんなサポートされているかどうかわからない機能は危なくて使えない。
これに、変わる作戦として、テクスチャマッピングして一度描画してから、その後で同じポリゴンをテクスチャマッピングしないで描画する、といった方法がある。もちろん、単純に再描画したら上書きされてしまうので、2回目はアルファブレンドして描画する。

float half_white[] = {1.0f, 1.0f, 1.0f, 0.5f};
float transparent[] = {0.0f, 0.0f, 0.0f, 0.0f};
@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, yellow, 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_BLEND);
gl.glEnable(GL10.GL_TEXTURE_2D);
// スムースシェーディング
gl.glShadeModel(GL10.GL_SMOOTH);
// ソート
Collections.sort(models, new ModelComparator());
for ( Model m : models ){
// 最初はマッピングして描画
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.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
m.draw(gl);
if ( blendMode == 1 ){
// 2回目はハイライトのみ描画したい
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, transparent, 0);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, half_white, 0);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, half_white, 0);
gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, 80f);
gl.glDisable(GL10.GL_TEXTURE_2D);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
m.draw(gl);
}
m.rotate();
}
}


むむ、やってみたが、テクスチャマッピングしないと透けている部分も描画してしまうので、四角に絵を貼りつけたように見えてしまう。透明部分がない画像をテクスチャマッピングする分にはこの方法でOKかも知れない。
そこで、テクスチャマッピング有効で、ブレンド方法(GL_SRC_ALPHA, GL_ONE)で2回目の描画をしたらそれっぽく表示できた。

for ( Model m : models ){
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.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
m.draw(gl);
if ( blendMode == 1 ){
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, transparent, 0);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, half_white, 0);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, half_white, 0);
gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, 80f);
// gl.glDisable(GL10.GL_TEXTURE_2D);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
m.draw(gl);
}
m.rotate();
}
}


使い方間違ってる?

投稿者プロフィール

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