SSブログ

Androidアプリ開発 OpenGL VBO(Vertex Buffer Object)で高速化 [Android OpenGL]

本日は、VBOの話をしようと思う。
VBOはVertex Buffer Object。頂点データをバッファオブジェクトでGPU側で管理する方法。Android端末には、CPUとGPUが搭載されており、どちらも計算を行うのだが、GPUはグラフィックス周りの計算に特化している。
OpenGLによる3Dグラフィックスは、GPUを使って計算処理されることが多い。

GPUはグラフィックスの計算に特化しているので、グラフィックス処理ならCPUより高速に実行できる。ハードウェア回路で必要な計算ができるようになっている。
CPUとGPUの違いは、グラフィックス処理に特化しているかどうかだけ。基本的なしくみは変わらない。CPU、GPUの内部には計算のためにレジスタが存在しているが、レジスタの数は多くないし、容量も少ない。大量のデータは、メモリに保存されていて、計算する際にレジスタに持ってくる。

CPUとメモリの関係は、「ポインタが理解できない理由」に詳しく書いてあるので、興味があればどうぞ。

C言語 ポインタが理解できない理由 [改訂新版] (プログラミングの教科書)

C言語 ポインタが理解できない理由 [改訂新版] (プログラミングの教科書)

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2011/04/08
  • メディア: 単行本(ソフトカバー)



多くのデスクトップPCでは、CPUが使うメモリとGPUが使うメモリが別になっている。特にゲームをするために、ビデオカードを拡張している場合は、ビデオカードにGPUとGPUが使うメモリが搭載されている。
ノートPCや廉価版のPCでは、CPUにGPUが統合されたオールインワンのCPUが使われている場合がある。このタイプのCPUでは、メモリは同じ。GPUが使うメモリはメインメモリの一部が割り当てられる感じになる。

GPUが使うメモリは「フレームバッファ」または単に「バッファ」と呼ばれる。ビデオメモリとかVRAMと呼ばれる場合もある。

Android端末にもGPUは搭載されている。OpenGLの3D機能を使えば、おのずとGPUが使われる。しかし、OpenGLを使わない普通のCanvasでの描画では、GPUは使用されていない模様。なんともったいない。

ちょっと調べてみる

http://techbooster.jpn.org/andriod/application/7054/

によると、Android 3.0以降なら、Cnavas描画でもGPUアクセラレーションが可能であるらしい。
AndroidManifest.xmlでandroid:hardwareAcceleratedの設定が必要なのか。
2.3だと無視されるのかなぁ...
AREarthroidで実験してみたが、あまり変化はない。3Dの部分はそのままだからなぁ...
2.3だと、Canvas#isHardwareAcceleratedメソッドが存在しないエラーになる。3.0以降じゃないとだめ。

VBO

やっと、本題のVBOである。
VBOを使わない場合、頂点データや法線データは、メインメモリ上にある。描画する際は、GPUを使うので、頂点データは、GPU側のメモリにコピーされる。コピーは描画の度に行われる。
VBOを使うと、メインメモリからGPU側のバッファに移動されて常駐するようになる。描画の度にコピーする必要がなくなるので、その分高速に描画できる。
バッファに頂点データというオブジェクトを作るので、Vertex Buffer Objectとなる。

VBOを使うと描画を高速化できる」というわけ。

ただし、OpenGL 1.1の機能になるため、Android端末のバージョンによっては使用できない。

さて、実際のコードはどうなるのかというと、AREarthroidから一部を抜いてみよう。

    	int[] vboIds = new int[4];
    	GL11 gl11 = (GL11) gl;
    	gl11.glGenBuffers(4, vboIds, 0);	// バッファを4つ作成
    	vertexBufferObjectId = vboIds[0];
    	normalBufferObjectId = vboIds[1];
    	textureBufferObjectId = vboIds[2];
    	elementBufferObjectId = vboIds[3];
    	// 頂点データをGPUにアップロード
    	gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexBufferObjectId);
    	vertexByteBuffer.position(0);
    	gl11.glBufferData(GL11.GL_ARRAY_BUFFER, vertexByteBuffer.capacity(), vertexByteBuffer, GL11.GL_STATIC_DRAW);
    	// 法線
    	gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, normalBufferObjectId);
    	normalByteBuffer.position(0);
    	gl11.glBufferData(GL11.GL_ARRAY_BUFFER, normalByteBuffer.capacity(), normalByteBuffer, GL11.GL_STATIC_DRAW);
    	// テクスチャ
    	gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, textureBufferObjectId);
    	textureByteBuffer.position(0);
    	gl11.glBufferData(GL11.GL_ARRAY_BUFFER, textureByteBuffer.capacity(), textureByteBuffer, GL11.GL_STATIC_DRAW);
    	// 面データもアップロード
    	gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, elementBufferObjectId);
    	indexBuffer.position(0);
    	gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity() * SHORT_SIZE, indexBuffer, GL11.GL_STATIC_DRAW);
    	// CPU側メモリのバッファはもういらない
    	vertexBuffer = null;
    	vertexByteBuffer = null;
    	normalBuffer = null;
    	normalByteBuffer = null;
    	textureBuffer = null;
    	textureByteBuffer = null;
    	indexBuffer = null;


まず、glGenBuffersでバッファオブジェクトを作成する。バッファオブジェクトは番号で識別されるので、これを受けるためのint配列を渡してやる。最初の引数は作成するオブジェクトの個数。第二引数が、番号の配列。第三引数はオフセット。

    	gl11.glGenBuffers(4, vboIds, 0);	// バッファを4つ作成


これで、4つのオブジェクトが作成される。オブジェクトの番号が配列vboIdsに入って戻ってくる。このまま使っても問題はないが、わかりやすくするために、フィールド変数で記憶する。

    	vertexBufferObjectId = vboIds[0];
    	normalBufferObjectId = vboIds[1];
    	textureBufferObjectId = vboIds[2];
    	elementBufferObjectId = vboIds[3];


vertexBufferObjectIdが、頂点データの入ったオブジェクトの番号。
normalBufferObjectIdが、法線データの入ったオブジェクトの番号。
以下は省略。

次に、バッファオブジェクトにデータを突っ込んでいく。CPU側のメモリからGPU側のメモリにデータをコピーする。

    	// 頂点データをGPUにアップロード
    	gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexBufferObjectId);
    	vertexByteBuffer.position(0);
    	gl11.glBufferData(GL11.GL_ARRAY_BUFFER, vertexByteBuffer.capacity(), vertexByteBuffer, GL11.GL_STATIC_DRAW);


glBindBufferで、どのバッファを使うのかを番号で指定する。
vertexByteBufferが頂点データの入ったCPU側メモリのバッファ。先頭からデータが入るように、position(0)でポインタの位置を先頭にしている。
glBufferDataで、vertexByteBufferのデータがGPU側のVBOに転送される。
GL_STATIC_DRAWは、バッファオブジェクトの用途。

同様な手法で、法線データ、テクスチャマッピングデータ、面データもVBOにしてGPU側にアップロードする。面データは、バッファの種類が異なるので注意。

VBOはこれで完成。CPU側メモリのバッファは不要になるので、nullをセット。

次に、VBOを使って描画する方法。

VBOを使わない場合は、glVertexPointerでCPU側メモリのバッファを指定すればよかったが、VBOの場合は、glBindBufferでVBOの番号を指定してから、glVertexPointerでポインタを設定する。

		// 頂点バッファ設定
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		if ( useVBO ){
			gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexBufferObjectId);
			gl11.glVertexPointer(3, GL10.GL_FLOAT, 12, 0);
		}
		else {
			gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
		}


useVBOはVBOを使用しているかどうがのフラグ。if文のtrueブロックがVBOを使った場合の処理になる。
法線データ、テクスチャ、面データも同様に処理を行う。
glDrawArraysなどの描画関数呼び出しは変更しなくてOK。
glDrawElementsは、indexBufferの指定が、オブジェクトになるので、GL11にあるglDrawElementsを使う。

		if ( useVBO ){
			gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, elementBufferObjectId);
			gl11.glDrawElements(GL10.GL_TRIANGLES, elementCount * 3, GL10.GL_UNSIGNED_SHORT, 0);
		}
		else {
			gl.glDrawElements(GL10.GL_TRIANGLES, indexBuffer.capacity(), GL10.GL_UNSIGNED_SHORT, indexBuffer);
		}


バッファオブジェクトは、使用されなくなったら、メモリから削除できる。削除は、glDeleteBuffersで行うことができる。

    	gl11.glDeleteBuffers(4, vboIds, 0);


引数は、glGenBuffersと同じ。
GLThreadから呼び出さないと無効なので注意。

AREarthroid




かんたんAndroidアプリ作成入門 (プログラミングの教科書)

かんたんAndroidアプリ作成入門 (プログラミングの教科書)

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2013/04/16
  • メディア: 単行本(ソフトカバー)




サイト内を検索

タグ:Android OpenGL
nice!(0)  コメント(0) 
共通テーマ:携帯コンテンツ

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。



Copyright Atsushi Asai Google+朝井淳
[改訂第4版]SQLポケットリファレンス

[改訂第4版]SQLポケットリファレンス

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/02/18
  • メディア: 単行本(ソフトカバー)

イラストで理解 SQL はじめて入門

イラストで理解 SQL はじめて入門

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2019/05/16
  • メディア: 単行本(ソフトカバー)

[データベースの気持ちがわかる]SQLはじめの一歩 (WEB+DB PRESS plus)

[データベースの気持ちがわかる]SQLはじめの一歩 (WEB+DB PRESS plus)

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2015/03/03
  • メディア: 単行本(ソフトカバー)

Access クエリ 徹底活用ガイド ~仕事の現場で即使える

Access クエリ 徹底活用ガイド ~仕事の現場で即使える

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2018/05/25
  • メディア: 大型本

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。