3D 描画を行うアプリを作成します。
ソースはこちらで公開しています。
https://github.com/matsushima-terunao/android_test
apk はこちら。
https://github.com/matsushima-terunao/android_test/raw/master/opengl/bin/opengl.apk
アクティビティーには描画を行うビューをセットし、イベントを委譲します。
ビューには描画を行うレンダラーをセットします。
実際に描画を行うレンダラークラスをここで実装します。
onSurfaceCreated() は画面作成時、および再作成(アプリ切り替えなど)時に呼び出されます。ここでは初期化処理やライティングなどの初期化処理を行います。
onSurfaceChanged() は画面変更(縦横切り替え)時に呼び出されます。ここではビューポートや視野の設定を行います。
onDrawFrame() は描画要求ごとに呼び出され、実際の描画処理はここで行います。
表示するモデルの作成と描画を行います。
→ 1-4. Android で OpenGL その2
← 1-2. UI 部品を使ったアプリ作成
↑ 一覧
ソースはこちらで公開しています。
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 部品を使ったアプリ作成
↑ 一覧
0 件のコメント:
コメントを投稿