SSブログ

Androidアプリ開発 OpenGL アルファブレンド 物体のソート [Android OpenGL]

アルファブレンドで正しくドロイド君を表示させるため、視点からの距離でソートするように修正していく。ついでなので、四角形にしてちゃんと表示できるようにも変更しよう。

まず、Modelの頂点データを修正して、三角形をふたつ作る。また、物体の中心位置をフィールドx,y,zで覚えておくようにする。これでソートする。

public class Model {

	private FloatBuffer buffer;			// 頂点用バッファ
	private FloatBuffer normalBuffer;	// 法線用バッファ
	private FloatBuffer textureBuffer;	// テクスチャ用バッファ
	private float x, y, z;

	public Model(float x, float y, float z) {
		this.x = x;
		this.y = y;
		this.z = z;
		float vertex[] = {
				-1.0f, -1.0f, 0.0f,
				 1.0f, -1.0f, 0.0f,
				 1.0f,  1.0f, 0.0f,
				 1.0f,  1.0f, 0.0f,
				-1.0f,  1.0f, 0.0f,
				-1.0f, -1.0f, 0.0f,
		};
		ByteBuffer vb = ByteBuffer.allocateDirect(vertex.length * 4);
		vb.order(ByteOrder.nativeOrder());
		buffer = vb.asFloatBuffer();
		buffer.put(vertex);
		buffer.position(0);

		float normal[] = {
				 0.0f, 0.0f, 1.0f,
				 0.0f, 0.0f, 1.0f,
				 0.0f, 0.0f, 1.0f,
				 0.0f, 0.0f, 1.0f,
				 0.0f, 0.0f, 1.0f,
				 0.0f, 0.0f, 1.0f,
		};
		ByteBuffer nb = ByteBuffer.allocateDirect(normal.length * 4);
		nb.order(ByteOrder.nativeOrder());
		normalBuffer = nb.asFloatBuffer();
		normalBuffer.put(normal);
		normalBuffer.position(0);

		float texture[] = {
				 0.0f, 1.0f,
				 1.0f, 1.0f,
				 1.0f, 0.0f,
				 1.0f, 0.0f,
				 0.0f, 0.0f,
				 0.0f, 1.0f,
		};
		ByteBuffer tb = ByteBuffer.allocateDirect(texture.length * 4);
		tb.order(ByteOrder.nativeOrder());
		textureBuffer = tb.asFloatBuffer();
		textureBuffer.put(texture);
		textureBuffer.position(0);
	}


次、視点との距離を計算するメソッドを作成する。

	public float distance(float ex, float ey, float ez){
		double dx = this.x - ex;
		double dy = this.y - ey;
		double dz = this.z - ez;
		return (float)Math.sqrt(dx * dx + dy * dy + dz * dz);
	}


次、drawでマトリックスのプッシュ、移動、ポップを行うようにする。移動は、フィールドの座標値で行う。頂点が増えたので、glDrawArraysの頂点数を6に増加させる。

	public void draw(GL10 gl) {
		gl.glPushMatrix();		// マトリックス記憶
		gl.glTranslatef(x, y, z);
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, buffer);
		gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
		gl.glNormalPointer(GL10.GL_FLOAT, 0, normalBuffer);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
		gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 6);
		gl.glPopMatrix();		// マトリックスを戻す
	}


次、モデルのリストを作成する。

public class SampleGLSurfaceView extends GLSurfaceView implements OnGestureListener {
	private ArrayList<Model> models = new ArrayList<Model>();
	private float angle = 0.0f;
	private float eyepos[] = new float[3];
	private Context context;



次、onSurfaceCreatedで、モデルを4つ作成してリストに入れる。

		@Override
		public void onSurfaceCreated(GL10 gl, EGLConfig config) {
			gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
			gl.glClearDepthf(1.0f);
			eyepos[0] = 0;
			eyepos[1] = 0;
			eyepos[2] = 3;
			Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher);
			// テクスチャを生成
			int textures[] = new int[1];
			gl.glGenTextures(1, textures, 0);
			gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
			GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
			models.add(new Model(1, 0, 0));
			models.add(new Model(-1, 0, 0));
			models.add(new Model(1, 0, -2));
			models.add(new Model(-1, 0, -2));
		}


次、ソート時の比較用クラスを作成する。

		class ModelComparator implements Comparator<Model> {
			public int compare(Model s, Model t) {
				float ds = s.distance(eyepos[0], eyepos[1], eyepos[2]);
				float dt = t.distance(eyepos[0], eyepos[1], eyepos[2]);
				if ( ds == dt ) return 0;
				else if ( ds < dt ) return 1;
				else return -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.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_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
			/*
			// アルファテスト
			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);
			
			// ソートして描画
			Collections.sort(models, new ModelComparator());
			for ( Model m : models ){
				m.draw(gl);
			}
		}


ほえー、けっこう大変だったが、我ながら手際よくできたと思っている。



結果はごらんのとおり。

変更部分が結構多かったので、念のためソース全体を載せておく。

SampleGLSurfaceView.java

package cx.fam.asai.TestOpenGL;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

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

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.opengl.GLUtils;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;

public class SampleGLSurfaceView extends GLSurfaceView implements OnGestureListener {
	private ArrayList<Model> models = new ArrayList<Model>();
	private float angle = 0.0f;
	private float eyepos[] = new float[3];
	private Context context;
	// レンダラークラス
	class OpenGLRenderer implements Renderer {
		float lightpos[] = {0.0f, 0.0f, 4.0f, 0.0f};
		float red[] = {1.0f, 0.0f, 0.0f, 1.0f};
		float green[] = {0.0f, 1.0f, 0.0f, 1.0f};
		float blue[] = {0.0f, 0.0f, 1.0f, 1.0f};
		float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
		float gray[] = {0.5f, 0.5f, 0.5f, 1.0f};
		float yellow[] = {1.0f, 1.0f, 0.0f, 1.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, 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_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
			/*
			// アルファテスト
			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);
			
			// ソートして描画
			Collections.sort(models, new ModelComparator());
			for ( Model m : models ){
				m.draw(gl);
			}
		}

		class ModelComparator implements Comparator<Model> {
			public int compare(Model s, Model t) {
				float ds = s.distance(eyepos[0], eyepos[1], eyepos[2]);
				float dt = t.distance(eyepos[0], eyepos[1], eyepos[2]);
				if ( ds == dt ) return 0;
				else if ( ds < dt ) return 1;
				else return -1;
			}
		}
		
		@Override
		public void onSurfaceChanged(GL10 gl, int width, int height) {
			gl.glViewport(0, 0, width, height);
	        gl.glMatrixMode(GL10.GL_PROJECTION);
	        gl.glLoadIdentity();
			GLU.gluPerspective(gl, 50f, (float)width / height, 0.01f, 100f);
		}

		@Override
		public void onSurfaceCreated(GL10 gl, EGLConfig config) {
			gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
			gl.glClearDepthf(1.0f);
			eyepos[0] = 0;
			eyepos[1] = 0;
			eyepos[2] = 3;
			Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher);
			// テクスチャを生成
			int textures[] = new int[1];
			gl.glGenTextures(1, textures, 0);
			gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
			GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
			models.add(new Model(1, 0, 0));
			models.add(new Model(-1, 0, 0));
			models.add(new Model(1, 0, -2));
			models.add(new Model(-1, 0, -2));
		}
	}

	private OpenGLRenderer renderer;

	// サーフェースビューのコンストラクタ
	public SampleGLSurfaceView(Context context) {
		super(context);
		this.context = context;
        setEGLConfigChooser(8, 8, 8, 8, 16, 0);
		renderer = new OpenGLRenderer();
		setRenderer(renderer);
	}

	@Override
	public boolean onDown(MotionEvent arg0) {
		return false;
	}

	@Override
	public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
			float arg3) {
		return false;
	}

	@Override
	public void onLongPress(MotionEvent arg0) {
	}

	@Override
	public boolean onScroll(MotionEvent event1, MotionEvent event2, float distx, float disty) {
		eyepos[0] += distx * 0.01;
		eyepos[1] += disty * 0.01;
		return true;
	}

	@Override
	public void onShowPress(MotionEvent arg0) {
	}

	@Override
	public boolean onSingleTapUp(MotionEvent arg0) {
		return false;
	}

}


Model.java

package cx.fam.asai.TestOpenGL;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

public class Model {

	private FloatBuffer buffer;			// 頂点用バッファ
	private FloatBuffer normalBuffer;	// 法線用バッファ
	private FloatBuffer textureBuffer;	// テクスチャ用バッファ
	private float x, y, z;

	public Model(float x, float y, float z) {
		this.x = x;
		this.y = y;
		this.z = z;
		float vertex[] = {
				-1.0f, -1.0f, 0.0f,
				 1.0f, -1.0f, 0.0f,
				 1.0f,  1.0f, 0.0f,
				 1.0f,  1.0f, 0.0f,
				-1.0f,  1.0f, 0.0f,
				-1.0f, -1.0f, 0.0f,
		};
		ByteBuffer vb = ByteBuffer.allocateDirect(vertex.length * 4);
		vb.order(ByteOrder.nativeOrder());
		buffer = vb.asFloatBuffer();
		buffer.put(vertex);
		buffer.position(0);

		float normal[] = {
				 0.0f, 0.0f, 1.0f,
				 0.0f, 0.0f, 1.0f,
				 0.0f, 0.0f, 1.0f,
				 0.0f, 0.0f, 1.0f,
				 0.0f, 0.0f, 1.0f,
				 0.0f, 0.0f, 1.0f,
		};
		ByteBuffer nb = ByteBuffer.allocateDirect(normal.length * 4);
		nb.order(ByteOrder.nativeOrder());
		normalBuffer = nb.asFloatBuffer();
		normalBuffer.put(normal);
		normalBuffer.position(0);

		float texture[] = {
				 0.0f, 1.0f,
				 1.0f, 1.0f,
				 1.0f, 0.0f,
				 1.0f, 0.0f,
				 0.0f, 0.0f,
				 0.0f, 1.0f,
		};
		ByteBuffer tb = ByteBuffer.allocateDirect(texture.length * 4);
		tb.order(ByteOrder.nativeOrder());
		textureBuffer = tb.asFloatBuffer();
		textureBuffer.put(texture);
		textureBuffer.position(0);
	}
	
	public float distance(float ex, float ey, float ez){
		double dx = this.x - ex;
		double dy = this.y - ey;
		double dz = this.z - ez;
		return (float)Math.sqrt(dx * dx + dy * dy + dz * dz);
	}
	
	public void draw(GL10 gl) {
		gl.glPushMatrix();		// マトリックス記憶
		gl.glTranslatef(x, y, z);
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, buffer);
		gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
		gl.glNormalPointer(GL10.GL_FLOAT, 0, normalBuffer);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
		gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 6);
		gl.glPopMatrix();		// マトリックスを戻す
	}
}





サイト内を検索

nice!(0)  コメント(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。



Copyright Atsushi Asai Google+朝井淳
[改訂第4版]SQLポケットリファレンス

[改訂第4版]SQLポケットリファレンス

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/02/18
  • メディア: 単行本(ソフトカバー)

イラストで理解 SQL はじめて入門

イラストで理解 SQL はじめて入門

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2019/05/16
  • メディア: 単行本(ソフトカバー)

[データベースの気持ちがわかる]SQLはじめの一歩 (WEB+DB PRESS plus)

[データベースの気持ちがわかる]SQLはじめの一歩 (WEB+DB PRESS plus)

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2015/03/03
  • メディア: 単行本(ソフトカバー)

Access クエリ 徹底活用ガイド ~仕事の現場で即使える

Access クエリ 徹底活用ガイド ~仕事の現場で即使える

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2018/05/25
  • メディア: 大型本

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。