OpenGLを使用して図形を描画をする|Android開発
android
でOpenGL
を使って図形を描画をする手順です。
GLSurfaceView 継承クラスの作成
OpenGL
で描画するためのビューを作成します。
android.opengl.GLSurfaceView
を継承したクラス(ビュー)を定義するandroid.opengl.GLSurfaceView.Renderer
を継承したクラスを定義するGLSurfaceView
を継承したクラスのコンストラクタでRenderer
を継承したクラスをsetRenderer()
で設定する- アクティビティまたはフラグメントで
GLSurfaceView
を継承したクラス(ビュー)を追加する
Renderer の実装
onSurfaceChanged()
で描画の設定を行うonSurfaceChanged()
でビューポート、フラスタムの設定を行う- 描画が必要な時にコールされる
onDrawFrame()
で描画処理を行う
GLSurfaceView 継承クラスのサンプル
public class TestGLView extends GLSurfaceView {
private Renderer mRenderer;
private Draw2DObject mDrawObject;
public TestGLView(Context context) {
super(context);
mRenderer = new LocalRenderer();
setRenderer(mRenderer);
mDrawObject = new Draw2DObject();
}
public class LocalRenderer implements Renderer {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// デプステストを設定. 隠れている面を表示しない. 後から書いた三角形で上書きしない.
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glDepthFunc(GL10.GL_LEQUAL);
}
@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, 50.0f, (float)width / height, 0.01f, 100.0f);
}
@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();
// Z軸の視点を後ろにズラして手前が見えるようにする.
gl.glTranslatef(0, 0, -3.f);
mDrawObject.draw(gl);
}
}
}
参考
フラスタムの設定は下記サイトを参考にしました。
Androidアプリ開発 OpenGLで描画する [Android OpenGL]
Draw2DObject
については、後述。フラグメントでのビュー設定
public class GLTestFragment extends Fragment {
private TestGLView mGLView;
public GLTestFragment() {
}
public static GLTestFragment newInstance() {
return new GLTestFragment();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mGLView = new TestGLView(getActivity());
return mGLView;
}
}
描画処理
Renderer.onDrawFrame()
で実際に描画するモデルを別クラスで定義したものが以下になります。
public class Draw2DObject {
public final FloatBuffer mmVertexBuffer;
public Draw2DObject() {
float vertices[] = {
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
};
ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4); // floatは32biteなのでx4.
vertexBuffer.order(ByteOrder.nativeOrder());
mmVertexBuffer = vertexBuffer.asFloatBuffer();
mmVertexBuffer.put(vertices);
mmVertexBuffer.position(0);
}
public void draw(GL10 gl) {
gl.glEnable(GL10.GL_TEXTURE_2D);
// 頂点データでの描画をするよ.
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// args:頂点を作る数(x,y,z=3), 型, 頂点間のバイトオフセット(連続データなら0), 配列
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mmVertexBuffer);
// 描画処理.
}
}
座標はX軸, Y軸, Z軸それぞれ-1.0~1.0の範囲で指定します。Z軸は画面手前が1.0、画面奥が-1.0になります。
描画処理の箇所はglDrawArrays()
で描画します。glDrawArrays()
のパラメータは描画モード, glVertexPointer()で指定した配列の開始インデックス, 頂点の数です。
描画モード
描画モード | 描画内容 |
---|---|
GL_POINTS | 点を打つ |
GL_TRIANGLES | 3つの頂点で三角形を塗り潰す。それを繰り返し |
GL_TRIANGLE_STRIP | 連続する3つの頂点で塗り潰す(p1-p2-p3で塗り潰す、p2-p3-p4で塗り潰す...) |
GL_TRIANGLE_FAN | 始点を軸に扇状に三角形を塗り潰す(p1-p2-p3で塗り潰す、p1-p3-p4で塗り潰す...) |
GL_LINES | 2つの頂点で線を引く |
GL_LINE_STRIP | 頂点で線を引き続ける |
GL_LINE_LOOP | 各頂点を繋げる(始点と終点が結ばれる) |
以下は各モードのサンプルになります。
GL_POINTS
gl.glDrawArrays(GL10.GL_POINTS, 0, 3);
見えにくいですが、白い点が3つあります。画像をクリックして拡大して見て頂ければ。
GL_TRIANGLES
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
GL_TRIANGLE_STRIP
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
GL_TRIANGLE_FAN
gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, 4);
GL_LINES
gl.glDrawArrays(GL10.GL_LINES, 0, 2);
2本線を引く場合
gl.glDrawArrays(GL10.GL_LINES, 0, 4);
GL_LINE_STRIP
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, 4);
GL_LINE_LOOP
gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, 4);
点の大きさを変更する
gl.glPointSize(10.0f);
gl.glDrawArrays(GL10.GL_POINTS, 0, 3);
glPointSize()
コール前の描画処理にも反映されます。
線の太さを変更する
gl.glLineWidth(8.0f);
gl.glDrawArrays(GL10.GL_LINES, 0, 2);
glLineWidth()
コール前の描画処理にも反映されます。
色を変更する
gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
glColor4f()
コール前の描画処理にも反映されます。
X, Y 座標のみで描画する
glVertexPointer()
の第1引数(頂点を構成する座標数)に2を設定します。
public class Draw2DObjectSimple {
public final FloatBuffer mmVertexBuffer;
public Draw2DObjectSimple() {
float vertices[] = {
0.0f, 0.5f,
0.5f, -0.5f,
-0.5f, -0.5f,
};
ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4); // floatは32biteなのでx4.
vertexBuffer.order(ByteOrder.nativeOrder());
mmVertexBuffer = vertexBuffer.asFloatBuffer();
mmVertexBuffer.put(vertices);
mmVertexBuffer.position(0);
}
public void draw(GL10 gl) {
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, mmVertexBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
}
}