3D 描画を行うアプリを作成します。
ソースはこちらで公開しています。
https://github.com/matsushima-terunao/android_test
apk はこちら。
https://github.com/matsushima-terunao/android_test/raw/master/opengl/bin/opengl.apk

MainActivity.java


アクティビティーには描画を行うビューをセットし、イベントを委譲します。

package com.example.ringmuns;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

	private MyView view;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.view = new MyView(this);
		setContentView(view); // アクティビティーにビューを設定
	}

	@Override
	protected void onResume() {
		super.onResume();
		view.onResume();
	}

	@Override
	protected void onPause() {
		super.onPause();
		view.onPause();
	}
}

MyView.java


ビューには描画を行うレンダラーをセットします。

package com.example.ringmuns;

import android.content.Context;
import android.opengl.GLSurfaceView;

public class MyView extends GLSurfaceView {

	private MyRenderer renderer;

	public MyView(Context context) {
		super(context);
		renderer = new MyRenderer();
		setRenderer(renderer); // レンダラーの設定
	}
}

MyRenderer.java


実際に描画を行うレンダラークラスをここで実装します。
onSurfaceCreated() は画面作成時、および再作成(アプリ切り替えなど)時に呼び出されます。ここでは初期化処理やライティングなどの初期化処理を行います。
onSurfaceChanged() は画面変更(縦横切り替え)時に呼び出されます。ここではビューポートや視野の設定を行います。
onDrawFrame() は描画要求ごとに呼び出され、実際の描画処理はここで行います。

package com.example.ringmuns;

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

import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;

public class MyRenderer implements Renderer {

	private MyModel model = new MyModel(); // モデル

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		gl.glEnable(GL10.GL_DEPTH_TEST); // デプスバッファを有効
		gl.glDepthFunc(GL10.GL_LEQUAL); // デプスバッファ比較: 以下
//		gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_POSITION, new float[]{-20.0f, -20.0f, 100.0f, 1.0f}, 0); // 照明の位置
//		gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_DIFFUSE, new float[]{1.0f, 1.0f, 1.0f, 1.0f}, 0); // 拡散光
//		gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_AMBIENT, new float[]{0.2f, 0.2f, 0.2f, 1.0f}, 0); // 環境光
//		gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_SPECULAR, new float[]{0.5f, 0.5f, 0.5f, 1.0f}, 0); // 鏡面光
		gl.glEnable(GL10.GL_LIGHTING); // ライティング有効
		gl.glEnable(GL10.GL_LIGHT0); // ライティング0有効
	}

	@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, 45f, (float)width / height, 1f, 50f); // 視野の設定
	}

	@Override
	public void onDrawFrame(GL10 gl) {
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // バッファクリア: カラーバッファ, デプスバッファ
		gl.glMatrixMode(GL10.GL_MODELVIEW); // 行列の選択: モデルビュー
		gl.glLoadIdentity(); // 単位行列に置き換え
		gl.glTranslatef(0, 0, -10f); // 移動: z方向
		gl.glRotatef(30f, 0, 1, 0); // 回転: y軸
		gl.glRotatef(30f, 1, 0, 0); // 回転: x軸
		model.draw(gl);
	}
}

MyModel.java


表示するモデルの作成と描画を行います。

package com.example.ringmuns;

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

import javax.microedition.khronos.opengles.GL10;

public class MyModel {

	private FloatBuffer vertexBuffer;

	private static final float[] vertices = {
		// front
		-1.0f, -1.0f,  1.0f,
		 1.0f, -1.0f,  1.0f,
		-1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		// back
		 1.0f, -1.0f, -1.0f,
		-1.0f, -1.0f, -1.0f,
		 1.0f,  1.0f, -1.0f,
		-1.0f,  1.0f, -1.0f,
		// left
		-1.0f, -1.0f, -1.0f,
		-1.0f, -1.0f,  1.0f,
		-1.0f,  1.0f, -1.0f,
		-1.0f,  1.0f,  1.0f,
		// right
		 1.0f, -1.0f,  1.0f,
		 1.0f, -1.0f, -1.0f,
		 1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f, -1.0f,
		// top
		-1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		-1.0f,  1.0f, -1.0f,
		 1.0f,  1.0f, -1.0f,
		// bottom
		-1.0f, -1.0f, -1.0f,
		 1.0f, -1.0f, -1.0f,
		-1.0f, -1.0f,  1.0f,
		 1.0f, -1.0f,  1.0f,
	};

	/**
	 * モデルを構築。
	 */
	public MyModel() {
		// 頂点定義の FloatBuffer を作成
		ByteBuffer buf = ByteBuffer.allocateDirect(vertices.length * 4);
		buf.order(ByteOrder.nativeOrder());
		vertexBuffer = buf.asFloatBuffer();
		vertexBuffer.put(vertices);
		vertexBuffer.position(0);
	}

	/**
	 * モデルを描画。
	 * 
	 * @param gl
	 */
	public void draw(GL10 gl) {
		gl.glFrontFace(GL10.GL_CCW); // 全面: 反時計回り
		gl.glEnable(GL10.GL_CULL_FACE); // 片面を表示しない
		gl.glCullFace(GL10.GL_BACK); // 裏面を表示しない
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // 頂点配列を有効
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); // xyz, float, padding なし, vertexBuffer
		/* 頂点法線ベクトル
		gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); // 法線配列を有効
		gl.glNormalPointer(GL10.GL_FLOAT, 0, vertexBuffer); // xyz, float, padding なし, vertexBuffer
		/**/
		for (int face = 0; face < 6; ++ face) {
			//* 面法線ベクトル
			float vx1 = vertexBuffer.get((face * 4 + 1) * 3 + 0) - vertexBuffer.get((face * 4 + 0) * 3 + 0);
			float vx2 = vertexBuffer.get((face * 4 + 2) * 3 + 0) - vertexBuffer.get((face * 4 + 0) * 3 + 0);
			float vy1 = vertexBuffer.get((face * 4 + 1) * 3 + 1) - vertexBuffer.get((face * 4 + 0) * 3 + 1);
			float vy2 = vertexBuffer.get((face * 4 + 2) * 3 + 1) - vertexBuffer.get((face * 4 + 0) * 3 + 1);
			float vz1 = vertexBuffer.get((face * 4 + 1) * 3 + 2) - vertexBuffer.get((face * 4 + 0) * 3 + 2);
			float vz2 = vertexBuffer.get((face * 4 + 2) * 3 + 2) - vertexBuffer.get((face * 4 + 0) * 3 + 2);
			float nx = vy1 * vz2 - vy2 * vz1;
			float ny = vz1 * vx2 - vz2 * vx1;
			float nz = vx1 * vy2 - vx2 * vy1;
			float nr = (float)Math.sqrt(nx * nx + ny * ny + nz * nz);
			gl.glNormal3f(nx / nr, ny / nr, nz / nr); // 面法線ベクトル
			/**/
			gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, face * 4, 4); // 0120 1231? // プリミティブを描画
		}
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // 頂点配列を無効
		gl.glDisable(GL10.GL_CULL_FACE); // 片面を表示しないを無効
	}
}



→ 1-4. Android で OpenGL その2
← 1-2. UI 部品を使ったアプリ作成
↑ 一覧