サンプルプログラム工場

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

サンプルプログラム工場 > android > AndroidのOpenGLでCOLLADA(dae)ファイルを読み込んで表示するサンプル#tryDrawCOLLADA00
Google Play AAKAKAxSOFTへ

AndroidのOpenGLでCOLLADA(dae)ファイルを読み込んで表示するサンプル#tryDrawCOLLADA00

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

AndroidでCOLLADAを読み込んでOpenGL(GLES20)で表示する。
COLLADA形式(.daeファイル)のファイルを読み込んでOpenGL(GLES20)で表示できるようにする。
COLLADAファイルはXMLなので、DefaultHandlerを拡張して読み込むのが楽らしい。
各タグを読み込んでモデルデータの形式を読み込んでいるわけではなく、モデルデータに「頂点座標、法線」しかない前提でHandlerが作ってある。
実際にゲームなどで使う場合は

 <input semantic=”VERTEX” source=”#Cube-mesh-vertices” offset=”0″/>
 <input semantic=”NORMAL” source=”#Cube-mesh-normals” offset=”1″/>

この当たりのモノを読み込んだ上で

タグ内の解釈をかえる様にするとどのモデルでも使える様になると思う。

タグ内の内容は上の例だと

頂点座標インデックス1 法線インデックス1 頂点座標インデックス2 法線インデックス2 頂点座標インデックス3 法線インデックス3 

みたいな形に並んでいる。

頂点数=法線数ではなくて、大抵は頂点の数が少ない。
なので、

タグ内のインデックスに沿って、OpenGLで表示できる様に頂点を復元する必要がある。

検索した事
 OpenGL daeファイル 表示
 OpenGL COLLADA 読み込み
 Android GLES20 COLLADA 表示
 COLLADA DOM

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

package aakaka.junkcode.sample.trydrawcollada00;

import java.io.InputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.opengl.Matrix;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.support.v4.app.NavUtils;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    
}


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

	private GLRenderer mRenderer;
	public GLSurfaceViewExt(Context context, AttributeSet attrs) {
		super(context, attrs);

		this.initGLSurfaceView(context);
	}

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

		this.initGLSurfaceView(context);
	}

	public void initGLSurfaceView(Context contex) {
		this.setEGLContextClientVersion(2);
		this.setEGLConfigChooser(true);
		// レンダラ―の設定
		this.mRenderer = new GLRenderer(contex.getResources());
		this.setRenderer(this.mRenderer);
	}
	

}




//////////////////////////////////////////////////////////////
//レンダラー
class GLRenderer implements GLSurfaceView.Renderer {

	private GLState mGlState = new GLState();
	private Collada3dObjectHandler mHandler;
	private ArrayList<Collada3dObject> m3dObjectArray;
	private Resources mResources;	// リソース

	// ////////////////////////////////////////////////////////////
	// コンストラクタ
	public GLRenderer(final Resources resource) {
		this.mResources = resource;
		this.mGlState.setDefault();
	}


	// ////////////////////////////////////////////////////////////
	// 最初に呼ばれる
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {

		GLES20.glEnable(GLES20.GL_DEPTH_TEST);
		GLES20.glEnable(GLES20.GL_CULL_FACE);
		GLES20.glCullFace(GLES20.GL_BACK);
		
		// COLLADAファイルのロード
		this.mHandler = new Collada3dObjectHandler();
		
		try {
			InputStream is = this.mResources.openRawResource(R.raw.try_mesh2);
			this.m3dObjectArray = this.mHandler.parseFile(is);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	
	// ////////////////////////////////////////////////////////////
	// サーフェイスのサイズ変更時とかに呼ばれる 
	public void onSurfaceChanged(GL10 gl, int width, int height) {

		// ビューポートの再設定
		GLES20.glViewport(0, 0, width, height);
		this.mGlState.setProjection(45.0f, (float)width / (float)height, 0.1f, 100.0f);
	}

	float mRotate = 0.0f;
	// ////////////////////////////////////////////////////////////
	// 毎フレーム呼ばれるやつ
	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);

		float[] m = new float[16];
		Matrix.setIdentityM(m, 0);
		Matrix.rotateM(m, 0, this.mRotate, 0, 1, 0);
		this.mRotate += 0.5f;
		if (360.0f < this.mRotate)
			this.mRotate -= 360.0f;
		this.mGlState.setWorldMatrix(m);

		// オブジェクトをロードする
		this.m3dObjectArray.get(0).draw(this.mGlState);
	}
}









// ////////////////////////////////////////////////////////////
// Collada 3d Object
class Collada3dObject {

	// 頂点内容のインデックス をこちらから指定する
	public static final int ATTRIBUTE_POSITION_LOCATION = 0;
	public static final int ATTRIBUTE_NORMAL_LOCATION = 1;
	public static final int ATTRIBUTE_COLOR_LOCATION = 1;
	public static final String ATTRIBUTE_POSITION = "a_pos";
	public static final String ATTRIBUTE_NORMAL = "a_normal";
	public static final String ATTRIBUTE_COLOR = "a_color";
	
	public static final String UNIFORM_MVP_MATRIX = "u_mvpMatrix";	// モデルビュープロジェクション
	public static final String UNIFORM_NORMAL_MATRIX = "u_normalMatrix";	// ノーマルマトリックス
	public static final String UNIFORM_COLOR = "u_color";
	public static final String VARYING_COLOR = "v_color";
	
	// 頂点カラー 付き頂点シェーダーのコンパイル
	private static final String VERTEX_CODE =
			"uniform mat4 u_mvpMatrix;" +
			"uniform mat4 u_normalMatrix;" +
			"uniform vec4 u_color;" + 
			"attribute vec4 a_pos;" +
			"attribute vec4 a_normal;" +
			"varying vec4 v_color;" +
			"void main(){"+
			"	vec3 lightDir = vec3(0.0, 0.0, 1.0);" +
			"	vec3 normal = vec3(normalize(a_normal));" +
			"	normal = normalize(mat3(u_normalMatrix) * normal);" +
			"   gl_Position = u_mvpMatrix * a_pos;" +
			"	float power = dot(normal, lightDir);" +
			"	v_color = vec4(u_color.x * power, u_color.y * power, u_color.z * power, 1.0);" +
			//"	v_color = vec4(normal.x, normal.y, normal.z, 1.0);" +
			"}";

	// 頂点カラー 付きフラグメントシェーダーのコンパイル
	private static final String FRAGMENT_CODE =
			"precision mediump float;"+
			"varying vec4 v_color;" +
			"void main(){"+
			"    gl_FragColor = v_color;" + 
			"}";
	
	private FloatBuffer mVertexBuffer;	// 頂点バッファ
	private IntBuffer mIndexBuffer;	// インデックスバッファ

	// 描画するためのもの
	private int mVertexShaderID;	// 頂点シェーダーID
	private int mFragmentShaderID;	// フラグメントシェーダーID
	private int mProgramID; // プログラムオブジェクトID

	// シェーダーに値を送るためのハンドル
	private int mLocMVPMatrix;
	private int mLocNormalMatrix;
	private int mLocColor;

	// VBO の管理番号
	private int mVertexBufferID; // 頂点バッファ
	private int mIndexBufferID;	// インデックスバッファ
	
	private float[] mFaceColor = { 0.9f, 0.3f, 0.8f, 1 };


	public Collada3dObject(float[] vertices, int[] indices) {

		// 頂点バッファを設定する
		this.mVertexBuffer = this.makeFloatBuffer(vertices);
		
		// インデックスバッファを作る
		this.mIndexBuffer = this.makeIntBuffer(indices);

		// 頂点配列を有効にする
		GLES20.glEnableVertexAttribArray(ATTRIBUTE_POSITION_LOCATION);
		GLES20.glEnableVertexAttribArray(ATTRIBUTE_NORMAL_LOCATION);
		
		// シェーダーを初期化する
		this.initShader();

		// VBO を初期化する
		this.initVBO();

	}
	
	// ////////////////////////////////////////////////////////////
	// 表示する
	public void draw(final GLState glState) {
		// VBO での描画
		// 頂点バッファのセット
		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.mVertexBufferID);
		
		// 頂点内容のインデックス で、各値の場所を指定する
		int vertexSize = (3 + 3) * 4;
		GLES20.glVertexAttribPointer(ATTRIBUTE_POSITION_LOCATION, 3, GLES20.GL_FLOAT, false, vertexSize, 0);
		GLES20.glVertexAttribPointer(ATTRIBUTE_NORMAL_LOCATION, 3, GLES20.GL_FLOAT, false, vertexSize, 3 * 4);

		// シェーダーにモデルビュープロジェクション行列を送信
		GLES20.glUniformMatrix4fv(this.mLocMVPMatrix, 1, false, glState.getModelViewProjectionMatrix(), 0);
		
		// シェーダーにモデルビュー行列を送信
		GLES20.glUniformMatrix4fv(this.mLocMVPMatrix, 1, false, glState.getModelViewProjectionMatrix(), 0);
		
		// シェーダーにノーマル行列を送信
		GLES20.glUniformMatrix4fv(this.mLocNormalMatrix, 1, false, glState.getNormalMatrix(), 0);
		
		// シェーダーに色を送信
		GLES20.glUniform4fv(this.mLocColor, 1, this.mFaceColor, 0);
		

		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.mIndexBufferID);

		// 面を描く
		GLES20.glDrawElements(GLES20.GL_TRIANGLES, this.mIndexBuffer.capacity(), GLES20.GL_UNSIGNED_INT, 0);
		
	}
	
	// ////////////////////////////////////////////////////////////
	// 色をセットする
	public void setColor(float r, float g, float b, float a) {
		this.mFaceColor[0] = r;
		this.mFaceColor[1] = g;
		this.mFaceColor[2] = b;
		this.mFaceColor[3] = a;
	}
	
	
	// /////////////////////////////////////////////////////////////////////////
	// VBOを登録する
	private void initVBO() {
		this.mVertexBufferID = this.makeVBO(this.mVertexBuffer, 4, GLES20.GL_ARRAY_BUFFER);
		this.mIndexBufferID = this.makeVBO(this.mIndexBuffer, 4, 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() {
		
		// シェーダーのコンパイル
		this.mVertexShaderID = this.compileShader(
				GLES20.GL_VERTEX_SHADER, VERTEX_CODE);

		this.mFragmentShaderID = this.compileShader(
				GLES20.GL_FRAGMENT_SHADER, FRAGMENT_CODE);

		// プログラムオブジェクトを作る
		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_NORMAL_LOCATION, ATTRIBUTE_NORMAL);


		GLES20.glLinkProgram(this.mProgramID);

		// シェーダーに値を送るためのハンドルを取り出す
		this.mLocMVPMatrix = GLES20.glGetUniformLocation(this.mProgramID, UNIFORM_MVP_MATRIX);
		
		// シェーダーに値を送るためのハンドルを取り出す
		this.mLocNormalMatrix = GLES20.glGetUniformLocation(this.mProgramID, UNIFORM_NORMAL_MATRIX);
		
		// シェーダーに値を送るためのハンドルを取り出す
		this.mLocColor = GLES20.glGetUniformLocation(this.mProgramID, UNIFORM_COLOR);
		
		

		// プログラムオブジェクトを使い始める
		GLES20.glUseProgram(this.mProgramID);
	}
	
	
	///////////////////////////////////////////////////////////////////////////
	// FloatBufferを作って値をセットする
	private FloatBuffer makeFloatBuffer(float[] values) {
		// バッファを作る
		FloatBuffer fb = ByteBuffer.allocateDirect(values.length * 4)
				.order(ByteOrder.nativeOrder())
				.asFloatBuffer();
		// 作ったバッファに値をセットしておく
		fb.put(values)
		.position(0);
		return fb;
	}
	
	private IntBuffer makeIntBuffer(int[] values) {
		// バッファを作る
		IntBuffer ib = ByteBuffer.allocateDirect(values.length * 4)
				.order(ByteOrder.nativeOrder())
				.asIntBuffer();
		// 作ったバッファに値をセットしておく
		ib.put(values).position(0);
		return ib;
	}

	///////////////////////////////////////////////////////////////////////////
	// シェーダーのソースコードをコンパイルする
	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;
	}
}












// ////////////////////////////////////////////////////////////
// COLLADAをロードするためのもの
// Blender 2.63aで、すべてのフェイスを三角形に分割してCOLLADAエクスポーターで
// エクスポートされたdaeファイルだけよみこめる。
class Collada3dObjectHandler extends DefaultHandler {
	
	private float[] mVertexArray;	// まとめられた頂点情報
	private int[] mIndexArray;	// 頂点配列
	
	private float[]	mPositionArray;	// 座標
	private float[] mNormalArray;	// 法線
	private int[]	mIndices;	// 頂点のインデックス(座標、法線、etc)
	
	// 今、どのタグ内に入っているか
	private boolean	mInPosition;	// 頂点座標検索中
	private boolean mInNormal;	// 法線検索中
	private boolean mInPolylist;	// インデックスリスト
	private boolean mInP;
	
	// XMLの内容が分割されてくることがあるので、この中にためて後で処理する
	// startElement → characters → characters → endElement
	// エレメント内の内容が大きすぎる(文字数が多すぎる)場合はcharactersが複数回やってくる
	// それをこの中にまとめておいてendElementで全部処理する
	private StringBuilder mBuffer = new StringBuilder();
	
	public void startDocument() throws SAXException {
		super.startDocument();
	}
	
	// ////////////////////////////////////////////////////////////
	// タグの開始時によびだされる
	public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
		super.startElement(uri, localName, name, attributes);
		
		mBuffer.setLength(0);
		
		// ////////////////////////////////////////////////////////////
		// 
		if (localName.equalsIgnoreCase("float_array") && attributes.getValue("id").contains("position")) {
			this.mInPosition = true;
		} else if (localName.equalsIgnoreCase("float_array") && attributes.getValue("id").contains("normal")) {
			this.mInNormal = true;
		} else if (localName.equalsIgnoreCase("polylist") && this.mPositionArray != null) {
			this.mInPolylist = true;
		} else if (localName.equalsIgnoreCase("p") && this.mInPolylist) {
			this.mInP = true;
		}
	}
	
	// ////////////////////////////////////////////////////////////
	// タグが終了したときに呼び出される
	public void endElement(String uri, String localName, String name) throws SAXException {
		super.endElement(uri, localName, name);
		
		// 頂点座標
		if (this.mInPosition) {
			
			String[] tmp = this.getCharacter().split("\\s");
			
			// メモリを確保
			float[] positionArray = new float[tmp.length];
			this.mPositionArray = positionArray;

			// 頂点データを文字列から数値へ変換
			for (int i = 0, len = this.mPositionArray.length; i < len; i++) {
				positionArray[i] = Float.parseFloat(tmp[i]);
			}
			
			this.mInPosition = false;
		
		// 法線情報
		} else if (this.mInNormal) {
			
			// 頂点を求める
			String[] tmp = this.getCharacter().split("\\s");
			
			// メモリを確保
			float[] normalArray = new float[tmp.length];
			this.mNormalArray = normalArray;
			
			// 頂点データを文字列から数値へ変換
			for (int i = 0, len = normalArray.length; i < len; i++) {
				normalArray[i] = Float.parseFloat(tmp[i]);
			}
			
			this.mInNormal = false;
		// インデックス
		} else if (this.mInP) {
			// 頂点数を求める
			String[] tmp = this.getCharacter().split("\\s");
			
			// メモリ確保
			int[] indices = new int[tmp.length];
			this.mIndices = indices;

			// すべて含めたインデックス情報
			for (int i = 0, len = indices.length; i < len; i++) {
				indices[i] = Integer.parseInt(tmp[i]);
			}
			
			this.mInPolylist = false;
			this.mInP = false;
		}

	}
	
	// ////////////////////////////////////////////////////////////
	// バッファの内容を取り出す
	private String getCharacter() {
		return this.mBuffer.toString().trim();
	}
	
	// ////////////////////////////////////////////////////////////・
	// タグごとに1回から複数回呼び出される
	// タグの内容が長すぎた場合(頂点数が1000超えてるとか)
	// "-0.1379497 -0.1587564 -0.5478345 -0.1247865 -0.3548731"という文字列が
	// 1回目"-0.1379497 -0.1587564 -0.5478345 -0.1"
	// 2回目"247865 -0.3548731"
	// のように分割された送られてくる。
	// なのでStringBuilderにためてendElementが呼ばれた段階で内容を解析する
	public void characters(char[] ch, int start, int length) throws SAXException {
		super.characters(ch, start, length);
		
		// この中にデータをためていく
		this.mBuffer.append(ch, start, length);
		
	}
	
	// ////////////////////////////////////////////////////////////
	// 解析された頂点データをOpenGLで使える様にまとめる
	private void packVertex() {
		
		// ////////////////////////////////////////////////////////////
		// 法線を反映させた情報
		int capacity = this.mIndices.length / 2;
		float[] vertexArray = new float[capacity * (3 + 3)];
		int[] indexArray = new int[capacity];
		int cursor = 0;
		
		float[] positionArray = this.mPositionArray;
		float[] normalArray = this.mNormalArray;
		
		for (int i = 0; i < capacity; i++) {
			
			int basePos = this.mIndices[i * 2 + 0] * 3;
			vertexArray[cursor++] = positionArray[basePos + 0];
			vertexArray[cursor++] = positionArray[basePos + 1];
			vertexArray[cursor++] = positionArray[basePos + 2];
			
			basePos = this.mIndices[i * 2 + 1] * 3;
			vertexArray[cursor++] = normalArray[basePos + 0];
			vertexArray[cursor++] = normalArray[basePos + 1];
			vertexArray[cursor++] = normalArray[basePos + 2];
			
			indexArray[i] = i;
		}
		
		this.mVertexArray = vertexArray;
		this.mIndexArray = indexArray;
	}
	
	
	// ////////////////////////////////////////////////////////////
	// ファイルからオブジェクト情報を取り出す
	public ArrayList<Collada3dObject> parseFile(InputStream input) {
		try {
			SAXParserFactory spf = SAXParserFactory.newInstance();
			SAXParser sp = spf.newSAXParser();
			XMLReader xr = sp.getXMLReader();
			xr.setContentHandler(this);
			xr.parse(new InputSource(input));
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		// 頂点情報をまとめる
		this.packVertex();
		
		
		ArrayList<Collada3dObject> res = new ArrayList<Collada3dObject>();
		res.add(new Collada3dObject(this.mVertexArray, this.mIndexArray));
		
		return res;
	}
}






// ////////////////////////////////////////////////////////////
// 描画に必要なモノ
class GLState {
	
	private float[] mWorldMatrix = new float[16];
	private float[] mViewMatrix = new float[16];
	private float[] mProjectionMatrix = new float[16];
	private float[] mModelViewProjectionMatrix = new float[16];
	private float[] mModelViewMatrix = new float[16];
	private float[] mInvertModelViewMatrix = new float[16];
	private float[] mNormalMatrix = new float[16];
	

	// ////////////////////////////////////////////////////////////
	// 初期設定
	void setDefault() {
		Matrix.setIdentityM(this.mWorldMatrix, 0);
		this.setEye(0, 0, 3, 0, 0, 0, 0, 1, 0);
		this.setProjection(45.0f, 480 / 640.0f, 0.1f, 100.0f);
	}
	
	// ////////////////////////////////////////////////////////////
	// モデルビューの逆行列
	public float[] getInvertModelViewMatrix() {
		Matrix.invertM(this.mInvertModelViewMatrix, 0, this.getModelViewMatrix(), 0);
		return this.mInvertModelViewMatrix;
	}

	// ////////////////////////////////////////////////////////////
	// Normal Matrixを返す(ライティング計算するときに必要よ)
	public float[] getNormalMatrix() {
		Matrix.transposeM(
				this.mNormalMatrix, 0,
				this.getInvertModelViewMatrix(), 0);
		return this.mNormalMatrix;
	}
	
	// ////////////////////////////////////////////////////////////
	// ワールドへ移動する行列をセット
	void setWorldMatrix(float[] m) {
		System.arraycopy(m, 0, this.mWorldMatrix, 0, 16);
		//Matrix.multiplyMM(this.mModelViewMatrix, 0, this.mViewMatrix, 0, this.mWorldMatrix, 0);
	}
	
	// ////////////////////////////////////////////////////////////
	// モデルビュー行列を返す
	public float[] getModelViewMatrix() {
		Matrix.multiplyMM(
				this.mModelViewMatrix, 0,
				this.mViewMatrix, 0,
				this.mWorldMatrix, 0);
		return this.mModelViewMatrix;
	}
	
	
	// ////////////////////////////////////////////////////////////
	// モデルビュープロジェクションマトリックス
	float[] getModelViewProjectionMatrix() {
		
		Matrix.multiplyMM(
				this.mModelViewProjectionMatrix, 0,
				this.mProjectionMatrix, 0,
				this.getModelViewMatrix(), 0);
				
		return this.mModelViewProjectionMatrix;
	}
	
	////////////////////////////////////////////////////////////
	// 透視投影変換
	public void setProjection(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(this.mProjectionMatrix, 0, 
				left, right, bottom, top, near, far);
	}
	
	////////////////////////////////////////////////////////////
	// 視点変換
	public void setEye(
			final float eyeX, final float eyeY, final float eyeZ,
			final float centerX, final float centerY, final float centerZ,
			final float upX, final float upY, final float upZ) {

		Matrix.setLookAtM(this.mViewMatrix, 0,
				eyeX, eyeY, eyeZ,
				centerX, centerY, centerZ,
				upX, upY, upZ);
	}
}






サンプルプロジェクトをダウンロード APKファイルをダウンロード

, , , , , , ,

AndroidのOpenGLで3D空間上のオブジェクトを指でドラッグするサンプル#try... Androidでローカルファイルにデータを保存するサンプル#tryLocalFile00

コメントを残す

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


*

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