サンプルプログラム工場

AAKAKA Appで使われているプログラムのサンプルコードをそのまま公開!

サンプルプログラム工場 > android > Androidの頂点属性のインデックスの固定化をしてキューブを描くサンプル#tryGLES2004
Google Play AAKAKAxSOFTへ

Androidの頂点属性のインデックスの固定化をしてキューブを描くサンプル#tryGLES2004

実行ファイル(APK)やサンプル(zip)をダウンロードする
tryGLES2004の実行イメージtryGLES2004の実行イメージ

頂点情報の位置をこちらから指定して固定化する
 0なら頂点座標 1なら頂点色 2なら法線 のようにする
glBindAttribLocationを使うと頂点内容のインデックスを
 こちらから指定することができる

OpenGL ES2.0を使ってキューブを描く
VBOを使って頂点データの最適化をする
頂点座標と頂点カラーを持たせる

シェーダーのソースとJavaのソースを定数を使ってつなぐ

大事なところ
 glGetUniformLocationをglBindAttribLocationに変更

関連項目
 VBO
 Vertex Buffer Object
 glVertexAttribPointer
 glDrawElements
 glEnableVertexAttribArray
 glBindAttribLocation
 頂点内容の固定化

開発環境
 Eclipse IDE バージョン: 3.7 Indigo Service Release 1
 ターゲットプラットフォーム: 2.3.3
 API レベル: 10

キーワード:頂点内容のインデックス

package trial.sample.trygles2004;

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

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

import android.app.Activity;
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;

public class TryGLES2004Activity extends Activity {
	
	
	
	private RenderSurfaceView mRenderView;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
	this.mRenderView = (RenderSurfaceView)this
			.findViewById(R.id.rendersurface1);
    }
    
    @Override
    public void onResume() {
    	super.onResume();
    	this.mRenderView.onResume();
    }
    
    @Override
    public void onPause() {
    	super.onPause();
    	this.mRenderView.onPause();
    }
}


///////////////////////////////////////////////////////////////////////////
//GLSurfaceViewの拡張
class RenderSurfaceView extends GLSurfaceView {

	public RenderSurfaceView(Context context, AttributeSet attrs) {
		super(context, attrs);

		this.setEGLContextClientVersion(2);
		// レンダラ―の設定
		this.setRenderer(new SurfaceRenderer());
	}

	public RenderSurfaceView(Context context) {
		super(context);

		// OpenGL ES2.0を使うためにバージョンを指定する
		this.setEGLContextClientVersion(2);
		this.setRenderer(new SurfaceRenderer());
	}
}


///////////////////////////////////////////////////////////////////////////
//ビュー用のレンダラ―
class SurfaceRenderer implements GLSurfaceView.Renderer {

	// 頂点内容のインデックス をこちらから指定する
	public static final int ATTRIBUTE_POSITION_LOCATION = 0;
	public static final int ATTRIBUTE_COLOR_LOCATION = 1;
	public static final String ATTRIBUTE_POSITION = "a_position";
	public static final String ATTRIBUTE_COLOR = "a_color";
	public static final String UNIFORM_MODELVIEWMATRIX = "u_modelViewMatrix";
	public static final String UNIFORM_PROJECTIONMATRIX = "u_projectionMatrix";
	public static final String VARYING_COLOR = "v_color";
	
	private float mAspect;	// アスペクト比
	private float mModelRot; // モデルの回転
	
	// 描画するためのもの
	private int mVertexShaderID;	// 頂点シェーダーID
	private int mFragmentShaderID;	// フラグメントシェーダーID
	private int mProgramID; // プログラムオブジェクトID
	
	// シェーダーに値を送るためのハンドル
	private int mLocModelView;
	private int mLocProj;
	
	// VBO の管理番号
	private int mVertexBufferID; // 頂点バッファ
	private int mIndexBufferID; // インデックスバッファ
	
	
	// 各行列
	private float[] mModelView = new float[16];	// モデルビュー
	private float[] mProj = new float[16];	// プロジェクション
	
	///////////////////////////////////////////////////////////////////////////
	/** 最初に呼ばれる */
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {

		// シェーダーを初期化する
		this.initShader();
		
		// こちから指定した 頂点内容のインデックス を有効にする
		// 頂点配列を有効にする
		GLES20.glEnableVertexAttribArray(ATTRIBUTE_POSITION_LOCATION);
		// 頂点カラー を有効にする
		GLES20.glEnableVertexAttribArray(ATTRIBUTE_COLOR_LOCATION);
		
		// デプスバッファを有効にする
		GLES20.glEnable(GLES20.GL_DEPTH_TEST);

		// VBO を初期化する
		this.initVBO();
	}
	
	// /////////////////////////////////////////////////////////////////////////
	// VBOを登録する
	private void initVBO() {
		
		// 頂点座標 + 頂点カラー
		// 頂点バッファから VBO を作る
		float[] vertices = {
			// 座標(x, y, z) 頂点色(r, g, b, a)
			1.0f, 1.0f, 1.0f, 1.f, 1.f, 1.f, 1.f,
			1.0f, 1.0f,-1.0f, 1.f, 0.f, 0.f, 1.f,
			-1.0f, 1.0f, 1.0f, 0.f, 1.f, 0.f, 1.f,
			-1.0f, 1.0f,-1.0f, 0.f, 0.f, 1.f, 1.f,
			1.0f,-1.0f, 1.0f, 1.f, 1.f, 0.f, 1.f,
			1.0f,-1.0f,-1.0f, 1.f, 0.f, 1.f, 1.f,
			-1.0f,-1.0f, 1.0f, 0.f, 1.f, 1.f, 1.f,
			-1.0f,-1.0f,-1.0f, 0.f, 0.f, 0.f, 1.f,
		};
		FloatBuffer vertexBuffer = this.makeFloatBuffer(vertices);
		// 頂点データ(座標、法線、色、テクスチャ座標)には
		// GL_ARRAY_BUFFERを指定する
		this.mVertexBufferID = this.makeVBO(
				vertexBuffer, 4, GLES20.GL_ARRAY_BUFFER);
		
		// インデックスバッファから VBO を作る
		byte[] indices = {
				0,1,2,3,
				2,3,6,7,
				6,7,4,5,
				4,5,0,1,
				1,5,3,7,
				0,2,4,6,
		};
		ByteBuffer indexBuffer = this.makeByteBuffer(indices);
		// インデックスの登録には
		// GL_ELEMENT_ARRAY_BUFFERを使う
		this.mIndexBufferID = this.makeVBO(
				indexBuffer, 1, GLES20.GL_ELEMENT_ARRAY_BUFFER);
	}
	
	// /////////////////////////////////////////////////////////////////////////
	// 各バッファから VBO へ変換する
	private int makeVBO(Buffer buffer, int size, int target) {
		
		int[] hardwareIDContainer= { -1 };
		
		// ハードウェア側の準備
		GLES20.glGenBuffers(1, hardwareIDContainer, 0);
		GLES20.glBindBuffer(target, 
				hardwareIDContainer[0]);
		GLES20.glBufferData(target,
				buffer.capacity() * size, buffer, GLES20.GL_STATIC_DRAW);
		
		return hardwareIDContainer[0];
	}
	
	// /////////////////////////////////////////////////////////////////////////
	// シェーダーを初期化する
	private void initShader() {
		// 頂点カラー 付き頂点シェーダーのコンパイル
		String vertexCode = 
			"uniform mat4  " + UNIFORM_MODELVIEWMATRIX + ";"+    
			"uniform mat4  " + UNIFORM_PROJECTIONMATRIX + ";"+ 
			"attribute vec4 " + ATTRIBUTE_POSITION + ";"+
			"attribute vec4 " + ATTRIBUTE_COLOR + ";"+
			"varying vec4 " + VARYING_COLOR + ";" +
			"void main(){"+       
			"    gl_Position = " + UNIFORM_PROJECTIONMATRIX + " * " + 
				UNIFORM_MODELVIEWMATRIX + " * " + ATTRIBUTE_POSITION + ";"+  
			"    " + VARYING_COLOR + " = " + ATTRIBUTE_COLOR +";"+
			"}";
		this.mVertexShaderID = this.compileShader(
				GLES20.GL_VERTEX_SHADER, vertexCode);
		
		// 頂点カラー 付きフラグメントシェーダーのコンパイル
		String fragmentCode = 
			"precision mediump float;"+
			"varying vec4  " + VARYING_COLOR + ";" +
			"void main(){"+   
			"    gl_FragColor = " + VARYING_COLOR + ";"+
			"}";
		this.mFragmentShaderID = this.compileShader(
				GLES20.GL_FRAGMENT_SHADER, fragmentCode);
		
		// プログラムオブジェクトを作る
		this.mProgramID = GLES20.glCreateProgram();
		GLES20.glAttachShader(this.mProgramID, this.mVertexShaderID);
		GLES20.glAttachShader(this.mProgramID, this.mFragmentShaderID);
		
		// 頂点内容のインデックス をシェーダー変数と関連付ける
		// 頂点座標
		GLES20.glBindAttribLocation(this.mProgramID, ATTRIBUTE_POSITION_LOCATION, ATTRIBUTE_POSITION);
		// 頂点カラー
		GLES20.glBindAttribLocation(this.mProgramID, ATTRIBUTE_COLOR_LOCATION, ATTRIBUTE_COLOR);
		
		GLES20.glLinkProgram(this.mProgramID);
		
		// シェーダーに値を送るためのハンドルを取り出す
		this.mLocModelView = GLES20.glGetUniformLocation(
				this.mProgramID, UNIFORM_MODELVIEWMATRIX);
		this.mLocProj = GLES20.glGetUniformLocation(
				this.mProgramID, UNIFORM_PROJECTIONMATRIX);
	
		// プログラムオブジェクトを使い始める
		GLES20.glUseProgram(this.mProgramID);
	}
	
	
	///////////////////////////////////////////////////////////////////////////
	/** サーフェイスのサイズ変更時とかに呼ばれる */
	public void onSurfaceChanged(GL10 gl, int width, int height) {
	
		// ビューポートの再設定
		GLES20.glViewport(0, 0, width, height);
		
		// アスペクト比
		this.mAspect = (float)width / (float)height;
	}
	
	
	///////////////////////////////////////////////////////////////////////////
	/** マイフレーム呼ばれるやつ */
	public void onDrawFrame(GL10 gl) {
		// 画面をクリア
		GLES20.glClearColor(0.4f, 0.4f, 0.4f, 1.f);
		GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
	
		// プロジェクション行列
		Matrix.setIdentityM(this.mProj, 0);
		this.Perspective(this.mProj, 45.f, this.mAspect, 1.0f, 100.f);
		// シェーダーに送信
		GLES20.glUniformMatrix4fv(this.mLocProj, 1, false, this.mProj, 0);
		
		
		// ビュー行列
		Matrix.setIdentityM(this.mModelView, 0);
		Matrix.setLookAtM(this.mModelView, 0,
				0.0f, 0.0f, 5.0f,
				0.0f, 0.0f, 0.0f,
				0.0f, 1.0f, 0.0f);
		
		
		// モデル変換
		Matrix.rotateM(this.mModelView, 0, this.mModelRot, 1.0f, 1.0f, 0.0f);
		
		
		// シェーダーにモデルビュー行列を送信
		GLES20.glUniformMatrix4fv(this.mLocModelView, 1, false, this.mModelView, 0);
		this.mModelRot++;


		
		// VBO での描画
		// 頂点バッファのセット
		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.mVertexBufferID);
		
		// 頂点内容のインデックス で、各値の場所を指定する
		GLES20.glVertexAttribPointer(ATTRIBUTE_POSITION_LOCATION, 3, GLES20.GL_FLOAT, false, 7 * 4, 0);
		GLES20.glVertexAttribPointer(ATTRIBUTE_COLOR_LOCATION, 4, GLES20.GL_FLOAT, false, 7 * 4, 3 * 4);
		
		// インデックスバッファの指定
		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.mIndexBufferID);
		// キューブを描く
		// 面を描く
		GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, 4,
				GLES20.GL_UNSIGNED_BYTE, 0);
		// 面を描く
		GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, 4,
				GLES20.GL_UNSIGNED_BYTE, 4);
		// 面を描く
		GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, 4,
				GLES20.GL_UNSIGNED_BYTE, 8);
		// 面を描く
		GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, 4,
				GLES20.GL_UNSIGNED_BYTE, 12);
		// 面を描く
		GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, 4,
				GLES20.GL_UNSIGNED_BYTE, 16);
		// 面を描く
		GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, 4,
				GLES20.GL_UNSIGNED_BYTE, 20);
	}
	
	
	// /////////////////////////////////////////////////////////////////////////
	// プロジェクション行列を作る
	private void Perspective(float[] out, float fov, float aspect, 
			float near, float far) {
		float top = near * (float)Math.tan(Math.toRadians(fov));
		float bottom = -top;
		float left = bottom * aspect;
		float right = top * aspect;
		Matrix.frustumM(out, 0, left, right, bottom, top, near, far);
	}
	
	
	
	///////////////////////////////////////////////////////////////////////////
	// FloatBufferを作って値をセットする
	private FloatBuffer makeFloatBuffer(float[] values) {
		// バッファを作る
		FloatBuffer fb = ByteBuffer.allocateDirect(values.length * 4)
				.order(ByteOrder.nativeOrder())
				.asFloatBuffer();
		// 作ったバッファに値をセットしておく
		fb.put(values)
				.position(0);
		return fb;
	}

	
	///////////////////////////////////////////////////////////////////////////
	// IntBufferを作って値をセットする
	private ByteBuffer makeByteBuffer(byte[] values) {
		ByteBuffer buf = ByteBuffer.allocateDirect(values.length)
				.order(ByteOrder.nativeOrder());
		buf.put(values)
				.position(0);
		return buf;
	}
	

	///////////////////////////////////////////////////////////////////////////
	// シェーダーのソースコードをコンパイルする
	private int compileShader(int type, String code) {
		final int shaderId = GLES20.glCreateShader(type);
		if (shaderId == 0) {
			// シェーダーの領域確保に失敗した
			Log.d("compileShader", "領域確保に失敗");
			return -1;
		}
		// シェーダーをコンパイル
		GLES20.glShaderSource(shaderId, code);
		GLES20.glCompileShader(shaderId);

		// コンパイルが成功したか調べる
		int[] res = new int[1];
		GLES20.glGetShaderiv(shaderId, GLES20.GL_COMPILE_STATUS, res, 0);
		if (res[0] == 0) {
			// 失敗してる
			Log.d("compileShader", GLES20.glGetShaderInfoLog(shaderId));
			return -1;
		}
		return shaderId;
	}
}
APKファイルをダウンロード サンプルプロジェクトをダウンロード

, , , , ,

AndroidのEditTextにアプリ起動直後にソフトウェアキーボードを出すサンプ... AndroidのEditTextに入力できる文字列をInputFilterで制限するサンプル#tr...

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>