▼Androidメモ▼
VBOによる最適化


OpenGL ES 2.0でVBOによる最適化を行うプログラムを作成する。
HelloGL20_14.png

ソースコード
GL20GeometryEx5.java
package net.npaka.gl20geometryex5;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;

//VBOによる最適化
public class GL20GeometryEx5 extends Activity {
private GLSurfaceView glView;

//アクティビティ生成時に呼ばれる
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);

//GLサーフェイスビュー
glView=new GLSurfaceView(this);
glView.setEGLContextClientVersion(2);
glView.setRenderer(new GLRenderer());
setContentView(glView);
}

//アクティビティレジューム時に呼ばれる
@Override
public void onResume() {
super.onResume();
glView.onResume();
}

//アクティビティポーズ時に呼ばれる
@Override
public void onPause() {
super.onPause();
glView.onPause();
}
}

GLRenderer.java
package net.npaka.gl20geometryex5;
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.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;

//レンダラー
public class GLRenderer implements
GLSurfaceView.Renderer {
//システム
private float aspect;//アスペクト比
private int angle; //回転角度

//バッファ
private int vertexBufferId;//頂点バッファID
private int indexBufferId; //インデックスバッファID
private int normalBufferId;//法線バッファID

//サーフェイス生成時に呼ばれる
@Override
public void onSurfaceCreated(GL10 gl10,EGLConfig eglConfig) {
//プログラムの生成
GLES.makeProgram();

//頂点配列の有効化
GLES20.glEnableVertexAttribArray(GLES.positionHandle);
GLES20.glEnableVertexAttribArray(GLES.normalHandle);

//デプスバッファの有効化
GLES20.glEnable(GLES20.GL_DEPTH_TEST);

//光源位置の指定
GLES20.glUniform4f(GLES.lightAmbientHandle,0.2f,0.2f,0.2f,1.0f);
GLES20.glUniform4f(GLES.lightDiffuseHandle,0.7f,0.7f,0.7f,1.0f);
GLES20.glUniform4f(GLES.lightSpecularHandle,0.0f,0.0f,0.0f,1.0f);

//頂点バッファの生成
float[] vertexs={
1.0f, 1.0f, 1.0f,//頂点0
1.0f, 1.0f,-1.0f,//頂点1
-1.0f, 1.0f, 1.0f,//頂点2
-1.0f, 1.0f,-1.0f,//頂点3
1.0f,-1.0f, 1.0f,//頂点4
1.0f,-1.0f,-1.0f,//頂点5
-1.0f,-1.0f, 1.0f,//頂点6
-1.0f,-1.0f,-1.0f,//頂点7
};
vertexBufferId=makeFloatVBO(vertexs);

//インデックスバッファの生成
byte[] indexs={
0,1,2,3,6,7,4,5,0,1,//面0
1,5,3,7, //面1
0,2,4,6, //面2
};
indexBufferId=makeByteVBO(indexs);

//法線バッファの生成
float[] normals={
1.0f, 1.0f, 1.0f,//頂点0
1.0f, 1.0f,-1.0f,//頂点1
-1.0f, 1.0f, 1.0f,//頂点2
-1.0f, 1.0f,-1.0f,//頂点3
1.0f,-1.0f, 1.0f,//頂点4
1.0f,-1.0f,-1.0f,//頂点5
-1.0f,-1.0f, 1.0f,//頂点6
-1.0f,-1.0f,-1.0f,//頂点7
};
float div=(float)Math.sqrt(
(1.0f*1.0f)+(1.0f*1.0f)+(1.0f*1.0f));
for (int i=0;i<normals.length;i++) normals[i]/=div;
normalBufferId=makeFloatVBO(normals);
}

//画面サイズ変更時に呼ばれる
@Override
public void onSurfaceChanged(GL10 gl10,int w,int h) {
//ビューポート変換
GLES20.glViewport(0,0,w,h);
aspect=(float)w/(float)h;
}

//毎フレーム描画時に呼ばれる
@Override
public void onDrawFrame(GL10 gl10) {
//画面のクリア
GLES20.glClearColor(1.0f,1.0f,1.0f,1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT|
GLES20.GL_DEPTH_BUFFER_BIT);

//射影変換
Matrix.setIdentityM(GLES.pMatrix,0);
GLES.gluPerspective(GLES.pMatrix,
45.0f, //Y方向の画角
aspect, //アスペクト比
1.0f, //ニアクリップ
100.0f);//ファークリップ

//光源位置の指定
Matrix.setIdentityM(GLES.mMatrix,0);
GLES20.glUniform4f(GLES.lightPosHandle,2.5f,2.5f,0.0f,1.0f);

//ビュー変換
GLES.gluLookAt(GLES.mMatrix,
0.0f,5.0f,5.0f, //カメラの視点
0.0f,0.0f,0.0f, //カメラの焦点
0.0f,1.0f,0.0f);//カメラの上方向

//モデル変換
Matrix.rotateM(GLES.mMatrix,0,angle++,0,1,0);

//行列をシェーダに指定
GLES.updateMatrix();

//ボックスの描画
drawBox();
}

//ボックスの描画
private void drawBox() {
//頂点バッファの指定
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER,vertexBufferId);
GLES20.glVertexAttribPointer(GLES.positionHandle,3,
GLES20.GL_FLOAT,false,0,0);

//法線バッファの指定
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER,normalBufferId);
GLES20.glVertexAttribPointer(GLES.normalHandle,3,
GLES20.GL_FLOAT,false,0,0);

//インデックスバッファの指定
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER,indexBufferId);

//面0の描画
setMaterial(0,1,0,1);
GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP,
10,GLES20.GL_UNSIGNED_BYTE,0);

//面1の描画
setMaterial(0,0,1,1);
GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP,
4,GLES20.GL_UNSIGNED_BYTE,10);

//面2の描画
setMaterial(1,0,0,1);
GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP,
4,GLES20.GL_UNSIGNED_BYTE,14);
}

//マテリアルの指定
private void setMaterial(float r,float g,float b,float a) {
//マテリアルの環境光色の指定
GLES20.glUniform4f(GLES.materialAmbientHandle,r,g,b,a);

//マテリアルの拡散光色の指定
GLES20.glUniform4f(GLES.materialDiffuseHandle,r,g,b,a);

//マテリアルの鏡面光色と鏡面指数の指定
GLES20.glUniform4f(GLES.materialSpecularHandle,r,g,b,a);
GLES20.glUniform1f(GLES.materialShininessHandle,0.6f);
}

//float配列をVBOに変換
private int makeFloatVBO(float[] array) {
//float配列をFloatBufferに変換
FloatBuffer fb=ByteBuffer.allocateDirect(array.length*4).order(
ByteOrder.nativeOrder()).asFloatBuffer();
fb.put(array).position(0);

//FloatBufferをVBOに変換
int[] bufferIds=new int[1];
GLES20.glGenBuffers(1,bufferIds,0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER,bufferIds[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
fb.capacity()*4,fb,GLES20.GL_STATIC_DRAW);
return bufferIds[0];
}

//byte配列をVBOに変換
private int makeByteVBO(byte[] array) {
//byte配列をByteBufferに変換
ByteBuffer bb=ByteBuffer.allocateDirect(array.length).order(
ByteOrder.nativeOrder());
bb.put(array).position(0);

//ByteBufferをVBOに変換
int[] bufferIds=new int[1];
GLES20.glGenBuffers(1,bufferIds,0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,bufferIds[0]);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER,
bb.capacity(),bb,GLES20.GL_STATIC_DRAW);
return bufferIds[0];
}
}

GLES.java
package net.npaka.gl20geometryex5;
import android.opengl.GLES20;
import android.opengl.Matrix;

//シェーダ操作
public class GLES {
//頂点シェーダのコード
private final static String VERTEX_CODE=
//光源
"uniform vec4 u_LightAmbient;"+ //光源の環境光色
"uniform vec4 u_LightDiffuse;"+ //光源の拡散光色
"uniform vec4 u_LightSpecular;"+//光源の鏡面光色
"uniform vec4 u_LightPos;"+ //光源の位置

//マテリアル
"uniform vec4 u_MaterialAmbient;"+ //マテリアルの環境光色
"uniform vec4 u_MaterialDiffuse;"+ //マテリアルの拡散光色
"uniform vec4 u_MaterialSpecular;"+ //マテリアルの鏡面光色
"uniform float u_MaterialShininess;"+//マテリアルの鏡面指数

//行列
"uniform mat4 u_MMatrix;"+ //モデルビュー行列
"uniform mat4 u_PMatrix;"+ //射影行列
"uniform mat4 u_NormalMatrix;"+//モデルビュー行列の逆転置行列

//頂点情報
"attribute vec4 a_Position;"+//位置
"attribute vec3 a_Normal;"+ //法線

//出力
"varying vec4 v_Color;"+
"void main(){"+
//環境光の計算
"vec4 ambient=u_LightAmbient*u_MaterialAmbient;"+

//拡散光の計算
"vec3 P=vec3(u_MMatrix*a_Position);"+
"vec3 L=normalize(vec3(u_LightPos)-P);"+
"vec3 N=normalize(mat3(u_NormalMatrix)*a_Normal);"+
"vec4 diffuseP=vec4(max(dot(L,N),0.0));"+
"vec4 diffuse=diffuseP*u_LightDiffuse*u_MaterialDiffuse;"+

//鏡面光の計算
"vec3 S=normalize(L+vec3(0.0,0.0,1.0));"+
"float specularP=pow(max(dot(N,S),0.0),u_MaterialShininess);"+
"vec4 specular=specularP*u_LightSpecular*u_MaterialSpecular;"+

//色の指定
"v_Color=ambient+diffuse+specular;"+

//位置の指定
"gl_Position=u_PMatrix*u_MMatrix*a_Position;"+
"}";

//フラグメントシェーダのコード
private final static String FRAGMENT_CODE=
"precision mediump float;"+
"varying vec4 v_Color;"+
"void main(){"+
"gl_FragColor=v_Color;"+
"}";

//システム
private static int program;//プログラムオブジェクト

//光源のハンドル
public static int lightAmbientHandle; //光源の環境光色ハンドル
public static int lightDiffuseHandle; //光源の拡散光色ハンドル
public static int lightSpecularHandle;//光源の鏡面光色ハンドル
public static int lightPosHandle; //光源の位置ハンドル

//マテリアルのハンドル
public static int materialAmbientHandle; //マテリアルの環境光色ハンドル
public static int materialDiffuseHandle; //マテリアルの拡散光色ハンドル
public static int materialSpecularHandle; //マテリアルの鏡面光色ハンドル
public static int materialShininessHandle;//マテリアルの鏡面指数ハンドル

//行列のハンドル
public static int mMatrixHandle; //モデルビュー行列ハンドル
public static int pMatrixHandle; //射影行列ハンドル
public static int normalMatrixHandle;//モデルビュー行列の逆転置行列ハンドル

//頂点のハンドル
public static int positionHandle;//位置ハンドル
public static int normalHandle; //法線ハンドル

//行列
public static float[] mMatrix=new float[16];//モデルビュー行列
public static float[] pMatrix=new float[16];//射影行列

//プログラムの生成
public static void makeProgram() {
//シェーダーオブジェクトの生成
int vertexShader=loadShader(GLES20.GL_VERTEX_SHADER,VERTEX_CODE);
int fragmentShader=loadShader(GLES20.GL_FRAGMENT_SHADER,FRAGMENT_CODE);

//プログラムオブジェクトの生成
program=GLES20.glCreateProgram();
GLES20.glAttachShader(program,vertexShader);
GLES20.glAttachShader(program,fragmentShader);
GLES20.glLinkProgram(program);

//光源のハンドルの取得
lightAmbientHandle=GLES20.glGetUniformLocation(program,"u_LightAmbient");
lightDiffuseHandle=GLES20.glGetUniformLocation(program,"u_LightDiffuse");
lightSpecularHandle=GLES20.glGetUniformLocation(program,"u_LightSpecular");
lightPosHandle=GLES20.glGetUniformLocation(program,"u_LightPos");

//マテリアルのハンドルの取得
materialAmbientHandle=GLES20.glGetUniformLocation(program,"u_MaterialAmbient");
materialDiffuseHandle=GLES20.glGetUniformLocation(program,"u_MaterialDiffuse");
materialSpecularHandle=GLES20.glGetUniformLocation(program,"u_MaterialSpecular");
materialShininessHandle=GLES20.glGetUniformLocation(program,"u_MaterialShininess");

//行列のハンドルの取得
mMatrixHandle=GLES20.glGetUniformLocation(program,"u_MMatrix");
pMatrixHandle=GLES20.glGetUniformLocation(program,"u_PMatrix");
normalMatrixHandle=GLES20.glGetUniformLocation(program,"u_NormalMatrix");

//頂点のハンドルの取得
positionHandle=GLES20.glGetAttribLocation(program,"a_Position");
normalHandle=GLES20.glGetAttribLocation(program,"a_Normal");

//プログラムオブジェクトの利用開始
GLES20.glUseProgram(program);
}

//シェーダーオブジェクトの生成
private static int loadShader(int type,String shaderCode) {
int shader=GLES20.glCreateShader(type);
GLES20.glShaderSource(shader,shaderCode);
GLES20.glCompileShader(shader);
return shader;
}

//透視変換の指定
public static void gluPerspective(float[] m,
float angle,float aspect,float near,float far) {
float top=near*(float)Math.tan(angle*(Math.PI/360.0));
float bottom=-top;
float left=bottom*aspect;
float right=top*aspect;
float[] frustumM=new float[16];
float[] resultM=new float[16];
Matrix.frustumM(frustumM,0,left,right,bottom,top,near,far);
Matrix.multiplyMM(resultM,0,m,0,frustumM,0);
System.arraycopy(resultM,0,m,0,16);
}

//ビュー変換の指定
public static void gluLookAt(float[] m,
float eyeX,float eyeY,float eyeZ,
float focusX,float focusY,float focusZ,
float upX,float upY,float upZ) {
float[] lookAtM=new float[16];
float[] resultM=new float[16];
Matrix.setLookAtM(lookAtM,0,
eyeX,eyeY,eyeZ,focusX,focusY,focusZ,upX,upY,upZ);
Matrix.multiplyMM(resultM,0,m,0,lookAtM,0);
System.arraycopy(resultM,0,m,0,16);
}

//行列をシェーダに指定
public static void updateMatrix() {
//射影行列をシェーダに指定
GLES20.glUniformMatrix4fv(pMatrixHandle,1,false,pMatrix,0);

//モデルビュー行列をシェーダに指定
GLES20.glUniformMatrix4fv(mMatrixHandle,1,false,mMatrix,0);

//モデルビュー行列の逆転置行列の指定
float[] normalM=new float[16];
normalM(normalM,mMatrix);
GLES20.glUniformMatrix4fv(normalMatrixHandle,1,false,normalM,0);
}

//行列の逆転置行列の計算(4)
public static void normalM(float[] rm,float[] m) {
float[] invertM=new float[16];
Matrix.invertM(invertM,0,m,0);
Matrix.transposeM(rm,0,invertM,0);
}
}


−戻る−