頂点配列

2010年1月7日

ファイル

29-array.tar.gz

使い方

たくさんの三角形を描画して、かかった時間をコンソール上に表示します。

キーボードのキー

  • "1": 普通の描画 (glBegin() ... glEnd() を使う)
  • "2": ディスプレイリストを使った描画
  • "3": "2" のディスプレイリストの作成を除いた時間を計測
  • "4": 頂点配列を使った描画
  • "5": "4" の頂点配列の作成を除いた時間を計測

見所

各描画方法の描画速度を比較してみましょう。

内容

頂点配列は、たくさんの頂点データを効率的に処理するためのしくみです。これを使って、普通に描画するよりどれだけ描画が速くなるものか、調べてみましょう。ここでは三角形をたくさん描く処理を行います。普通に描く場合は以下のようになります。

void drawNormal(void)
{
	int i, j;
	float r, g, b;
	float x, y;

	for(i = 0; i < N; i++){
		glBegin(GL_TRIANGLES);
		for(j = 0; j < 3; j++){
			r = fabs(getRandom());
			g = fabs(getRandom());
			b = fabs(getRandom());
			glColor3f(r, g, b);
			x = getRandom();
			y = getRandom();
			glVertex2f(x, y);
		}
		glEnd();
	}
}

ついでなので、ディスプレイリストによる描画も比較対象にしましょう。以下のようになります。

void drawDisplayListInit(void)
{
	glNewList(1, GL_COMPILE);
	drawNormal();
	glEndList();
}


void drawDisplayList(void)
{
	glCallList(1);
}

リストの作成と描画を分けているのは、リストを再利用できるとすればどれくらい速いかを見るためです。

さて、頂点配列を使うために、以下のような準備をします。

	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);

ここでは、頂点の色の配列と、頂点の配列を使うことを指定しています。配列を無効にする必要がある場合は glDisableClientState() を使います。

頂点配列を使った描画は以下のようになります。

void drawArrayInit(void)
{
	int i;

	for(i = 0; i < N*3; i++){
		color[i][0] = fabs(getRandom());
		color[i][1] = fabs(getRandom());
		color[i][2] = fabs(getRandom());
	}

	for(i = 0; i < N*3; i++){
		vertex[i][0] = getRandom();
		vertex[i][1] = getRandom();
		vertex[i][2] = 0.;
	}

	glColorPointer(3, GL_FLOAT, 0, color);
	glVertexPointer(3, GL_FLOAT, 0, vertex);

	for(i = 0; i < N; i++){
		triangleIndex[i][0] = 3*i;
		triangleIndex[i][1] = 3*i + 1;
		triangleIndex[i][2] = 3*i + 2;
	}
}


void drawArray(void)
{
	glDrawElements(GL_TRIANGLES, N*3, GL_UNSIGNED_INT, triangleIndex);
}

はじめに頂点の色のデータと、頂点のデータを作成しています。その後、glColorPointer(), glVertexPointer() で頂点データの格納場所を指定しています。

	glColorPointer(3, GL_FLOAT, 0, color);
	glVertexPointer(3, GL_FLOAT, 0, vertex);

第 1 引数は頂点データのサイズ (色の場合は RGB の 3 つ、頂点の場合は 3 次元なのでどちらも 3)、第 2 引数はデータの型、第 3 引数はデータの間隔 (ここでは詰めて入れているので 0)、最後がデータの格納場所を示すポインタです。

triangleIndex は三角形の頂点のインデックスで、glDrawElements() に渡します。glDrawElements() はインデックスを使って図形を描画します。

	glDrawElements(GL_TRIANGLES, N*3, GL_UNSIGNED_INT, triangleIndex);

第 1 引数が図形の種類、第 2 引数がデータの数、次がインデックスの型、最後がインデックスです。頂点データから 3 つずつデータを取って三角形を描画するのではなしに、わざわざインデックスを使うことにどんな意味があるのかというと、これを使えば、三角形どうしが頂点を共有するようなメッシュ状のものを描画するときに、頂点データを減らすことができます。

単純に頂点データを 3 つずつ取って三角形を描画させるということもできます。上の glDrawElements() の代わりに、次のように書きます。

	glDrawArrays(GL_TRIANGLES, 0, N*3);

第 2, 3 引数は、データの 0 番目から N*3 個のデータを使う、という意味です。

OpenGL プログラミング 目次へ