【Android】アンドロイドでOpenGLを使ってみる(2Dテクスチャ描画編)


前回(【Android】アンドロイドでOpenGLを使ってみる(準備編))からの続きでOpenGLを使ってみます。
OpenGLといったら3Dというイメージがありますが、
今回は2D機能だけを使い奥行きのないペラペラしたオブジェクトにテクスチャを貼ってみる方法を紹介してみます。



AndroidでOpenGLを使う良い解説本はないものかと本屋をウロウロしていると。

OpenGL ESを使ったAndroid 2D/3DゲームプログラミングOpenGL ESを使ったAndroid 2D/3Dゲームプログラミング
見つけました。さっそく買って読んでみたんですが、とっても解りやすいです(^ω^)

今回は2D機能だけですが、上記の本では3Dを使った描画処理も紹介しています。
(とっても使いやすいHyperMotion3Dは筆者の大西武さんのサイトからDLできます)

この本の内容を参考にしながら2Dテクスチャを使った描画処理を紹介してみます。

2次元スプライト用のクラスを作成する

私はまったくグラフィック関連の知識がないのでテクスチャと聞いてピンと来なかったのですが、
オブジェクト表面に貼り付けられるシールのようなものと考えればよいそうです。

テクスチャに貼り付ける画像はpngを用意します。
テクスチャ用png画像
みんな大好き比那名居天子さんです。
画像のサイズは2の累乗にしないといけないらしいので、512x256にしてあります。

HyperMotion3DのクラスSprite2Dを参考にしながら、
上記のpng画像の読込と描画を行うSampleSpriteクラスを作成します。

・SampleSprite.java
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import javax.microedition.khronos.opengles.GL11Ext;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;

public class SampleSprite {
	//テクスチャNo
	public int textureNo;
    //表示位置
	float  pos_x;
	float  pos_y;
	float  pos_z;
	//テクスチャ(画像)の位置とサイズ
	int    texX;
	int    texY;
	int    texWidth;
	int    texHeight;
	//配置する時の幅と高さ
	float  width;
	float  height;

	public void setTexture( GL10 gl, Resources res, int id ){
		InputStream is = res.openRawResource(id);
		Bitmap bitmap;
    	try{
    		bitmap = BitmapFactory.decodeStream(is);
    	}
    	finally{
    		try{
    			is.close();
    		}
    		catch(IOException e){	}
    	}
    	gl.glEnable(GL10.GL_ALPHA_TEST);
    	gl.glEnable(GL10.GL_BLEND);
    	gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
    	gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
    	//テクスチャIDを割り当てる
    	int[] textureID = new int[1];
    	gl.glGenTextures(1, textureID, 0);
    	textureNo = textureID[0];

    	//テクスチャIDのバインド
    	gl.glBindTexture(GL10.GL_TEXTURE_2D, textureNo);
     	//OpenGL ES用のメモリ領域に画像データを渡す。上でバインドされたテクスチャIDと結び付けられる。
    	GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
    	//テクスチャ座標が1.0fを超えたときの、テクスチャを繰り返す設定
    	gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT );
    	gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT );
    	//テクスチャを元のサイズから拡大、縮小して使用したときの色の使い方を設定
    	gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR );
    	gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR );

    	texX      = 0;
    	texY      = bitmap.getHeight();
    	texWidth  = bitmap.getWidth();
       	texHeight = -bitmap.getHeight();
     	pos_x     = 0;
     	pos_y     = 0;
     	pos_z     = 0;
     	width     = bitmap.getWidth();
     	height    = bitmap.getHeight();
	}

	public void draw( GL10 gl){
    	gl.glDisable(GL10.GL_DEPTH_TEST);
    	//背景色を白色で塗りつぶし
   		gl.glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
   		//テクスチャ0番をアクティブにする
   		gl.glActiveTexture(GL10.GL_TEXTURE0);
   		//テクスチャIDに対応するテクスチャをバインドする
   		gl.glBindTexture(GL10.GL_TEXTURE_2D, textureNo);
		//テクスチャの座標と幅と高さを指定
   		int rect[] = { texX,  texY,  texWidth, texHeight};
   		//テクスチャ画像のどの部分を使うかを指定
   		((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D,GL11Ext.GL_TEXTURE_CROP_RECT_OES, rect, 0);
   		//描画
   		((GL11Ext) gl).glDrawTexfOES( pos_x, pos_y, pos_z, width, height);

   	   	gl.glEnable(GL10.GL_DEPTH_TEST);
	}
}



なかなか長くなってしまいました(´ω`)
アルファとかブレンドなどグラフィック関連の言葉がわからず逐一調べてなんとなく理解…。

・setTexture関数
 リソースIDからBitmapのインスタンスを取得。
 その後はしばらくOpenGLの初期設定(内容は書いてある通りだと思います)
 60~68行目あたりで画像の座標、幅と高さをセットしています。

・draw関数
 描画処理です。
 setTexture関数でセットした通りの内容を描画してくれるはずです。

実際にGLSurfaceViewの中で2Dテクスチャを描画してみる


前回の記事で作成したからっぽのRendererクラスに処理を追加します。

・SampleRenderer.java
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;

public class SampleRenderer implements Renderer{

	private Context context;

	//2次元スプライト
	SampleSprite tenshi_img = new SampleSprite();

	public SampleRenderer(Context _context){
		context = _context;
	}

	@Override
	public void onDrawFrame(GL10 gl) {
	    // 描画用バッファをクリア
	    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
	    tenshi_img.draw(gl);
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		gl.glViewport(0, 0, width, height);
		gl.glMatrixMode(GL10.GL_PROJECTION);//プロジェクションモードに設定
		GLU.gluOrtho2D(gl, 0.0f, width, 0.0f, height);//平行投影用のパラメータをセット
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		//背景色をクリア
		gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
		//ディザを無効化
		gl.glDisable(GL10.GL_DITHER);
		//深度テストを有効化
		gl.glEnable(GL10.GL_DEPTH_TEST);
		//テクスチャ機能ON
		gl.glEnable(GL10.GL_TEXTURE_2D);
		//透明可能に
		gl.glEnable(GL10.GL_ALPHA_TEST);
		//ブレンド可能に
		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

		tenshi_img.setTexture(gl,context.getResources(),R.drawable.sample_img);

	}
}


・34~46
 OpenGLの設定です。
・48
 リソースIDを渡してテクスチャをセットしています。
・20~22
 画面をクリアして、テキスチャを描画。

【実行結果】
OpenGLで2Dテクスチャを描画してみる実行結果01
SampleSpriteクラスのsetTexture関数を変更すると、
画像の位置を変えたり画像を引き伸ばして表示できます。
     	pos_x     = 50; //右に移動
     	pos_y     = 200;   //上に移動
     	pos_z     = 0;
     	width     = bitmap.getWidth()*2; //縦に二倍引き伸ばし
     	height    = bitmap.getHeight();
	}



【実行結果】
OpenGLで2Dテクスチャを描画してみる実行結果02 ぐんにょり。


関連記事