サンプルプログラム工場

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

サンプルプログラム工場 > android > AndroidのOpenGL(GLES20)で頂点属性(色、座標)を変更して表示するサンプル@tryGLES2003
Google Play AAKAKAxSOFTへ

AndroidのOpenGL(GLES20)で頂点属性(色、座標)を変更して表示するサンプル@tryGLES2003

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

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

・大事なところ
頂点のデータを追加したら
glEnableVertexAttribArrayでその部分を
有効にするのを忘れない。

・関連項目
VBO
Vertex Buffer Object
glVertexAttribPointer
glDrawElements
glEnableVertexAttribArray
glGetUniformLocation

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

キーワード:頂点カラー

package trial.sample.trygles2003;

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 TryGLES2003Activity 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 {

	private float mAspect;	// アスペクト比
	private float mModelRot; // モデルの回転
	
	// 描画するためのもの
	private int mVertexShaderID;	// 頂点シェーダーID
	private int mFragmentShaderID;	// フラグメントシェーダーID
	private int mProgramID; // プログラムオブジェクトID
	
	// シェーダーに値を送るためのハンドル
	private int mLocModelView;
	private int mLocProj;
	private int mLocPos;
	// 頂点カラー 用のハンドル
	private int mLocColor;
	
	// 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(this.mLocPos);
		// 頂点カラー を有効にする
		// ※ここで色配列を有効にするのを忘れると色が反映されない
		GLES20.glEnableVertexAttribArray(this.mLocColor);
		
		// デプスバッファを有効にする
		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 u_modelView;"+    
			"uniform mat4 u_proj;"+ 
			"attribute vec4 a_pos;"+
			"attribute vec4 a_color;"+
			"varying vec4 v_color;" +
			"void main(){"+       
			"    gl_Position = u_proj * u_modelView * a_pos;"+  
			"    v_color = a_color;"+
			"}";
		this.mVertexShaderID = this.compileShader(
				GLES20.GL_VERTEX_SHADER, vertexCode);
		
		// 頂点カラー 付きフラグメントシェーダーのコンパイル
		String fragmentCode = 
			"precision mediump float;"+
			"varying vec4 v_color;" +
			"void main(){"+   
			"    gl_FragColor = v_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.glLinkProgram(this.mProgramID);
		
		// シェーダーに値を送るためのハンドルを取り出す
		this.mLocModelView = GLES20.glGetUniformLocation(
				this.mProgramID, "u_modelView");
		this.mLocProj = GLES20.glGetUniformLocation(
				this.mProgramID, "u_proj");
		// 頂点はglGetAttribLocationを使ってセットする
		this.mLocPos = GLES20.glGetAttribLocation(
				this.mProgramID, "a_pos");
		// 頂点カラー を送る様にする
		this.mLocColor = GLES20.glGetAttribLocation(
				this.mProgramID, "a_color");
		
		// プログラムオブジェクトを使い始める
		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);
		// バッファ内の頂点座標 頂点カラー の位置を設定する
		// strideは頂点一つのサイズ(floatが3個なら3×4(floatのバイト数))
		// offsetは一つの頂点内で何バイト目から指定のものが始まるか
		GLES20.glVertexAttribPointer(this.mLocPos, 3, GLES20.GL_FLOAT, false, 7 * 4, 0);
		GLES20.glVertexAttribPointer(this.mLocColor, 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 OpenGL GLES20でVertexBufferObject(VBO)を使うサンプル@tryGLES2002 HTML5のcanvasを指定の背景色で塗りつぶすサンプル@tryHtml5Canvas00a

コメントを残す

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


*

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