行列スタック


変換の保存

ある程度複雑なグラフィック処理になってくると
変換用の行列データを保存する必要に迫られるケースが増えてくるでしょう
例えば、特定のオブジェクトを描画する関数は変換をサポートするべきではありません
設計論から考えれば、オブジェクト描画関数はオブジェクト描画に専念するべきです

では、他の関数がオブジェクトを描画するとき、どのように変換を伝えるべきでしょうか?
ひとつは、関数が変換行列を引数で受け取る方法が考えられるでしょう
もしくは、グローバル領域などに変換用のデータを保存するも手段です
ですが、これらよりも合理的な行列保存手段が存在します

実は、変換対象の行列はスタックとして保存されています
処理は常にスタックの一番上の行列を対象に変換するという性質を持っています
glMultMatrix() などの行列操作関数は、実際には行列スタックの最上部に作用します

この性質を利用すれば、オブジェクトの描画前に適切な行列をスタック上部に配置し
その後にオブジェクトを描画する関数を呼び出すことによって変換と描画を組み合わせることができます
これは、オブジェクトを組み合わせて複雑なグラフィックを描画するときに適しています

行列スタックの最上部は glPushMatxi() 関数でコピーすることができ
不要になれば glPopMatrix() 関数で破棄することができます

void glPushMatrix(void);
void glPopMatrix(void);

これらの関数を使えば、描画と変換作業を効率よく分担することができます
また、行列スタックはハードウェア的に保存される可能性もあります
そうすれば、より高速な動作を期待することができるため、積極的に使うべきでしょう
デフォルトでは、最上部の行列は単位行列になっています
#include <windows.h>
#include <GL/gl.h>
#include <GL/glut.h>

int width , height;

void Draw( void ) {
	glBegin(GL_POLYGON);
		glEdgeFlag(GL_TRUE); glVertex2f(-0.9 , -0.5);
		glEdgeFlag(GL_TRUE); glVertex2f(-0.85 , 0.9);
		glEdgeFlag(GL_FALSE);glVertex2f(0 , 0.3);

		glEdgeFlag(GL_TRUE); glVertex2f(-0.9 , -0.5);
		glEdgeFlag(GL_FALSE);glVertex2f(0.9 , -0.5);
		glEdgeFlag(GL_TRUE); glVertex2f(0 , 0.3);

		glEdgeFlag(GL_TRUE); glVertex2f(0.85 , 0.9);
		glEdgeFlag(GL_FALSE);glVertex2f(0.9 , -0.5);		
		glEdgeFlag(GL_FALSE);glVertex2f(0 , 0.3);
	glEnd();
	glViewport(0 , 0 , width , height);
}

void disp( void ) {
	glClear(GL_COLOR_BUFFER_BIT);
	glPushMatrix();
		glTranslatef(-1 , 0 , 0);
		Draw();
	glPopMatrix();
	glPushMatrix();
		glTranslatef(1 , 0 , 0);
		Draw();
	glPopMatrix();
	glFlush();
}

void reshape(int w , int h) {
	width = w; height = h;
	disp();
}

int main(int argc , char ** argv) {
	glutInit(&argc , argv);
	glutInitWindowPosition(100 , 50);
	glutInitWindowSize(400 , 300);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);

	glutCreateWindow("Kitty on your lap");
	glutDisplayFunc(disp);
	glutReshapeFunc(reshape);


	glutMainLoop();
	return 0;
}


このプログラムの Draw() 関数は凹型のオブジェクトをウィンドウに描画します
ディスプレイコールバック disp() 関数で、Draw() 関数を呼び出してオブジェクトを描画しますが
関数を呼び出す前に glPushMatrix() を使って行列をコピーし、平行移動の行列演算を行います
そして、オブジェクトを描画した後に glPopMatrix() を呼び出して行列を削除しています

このように、行列スタックを利用することで変換処理を保存することができます
複雑な、複数の関係しあうオブジェクトの変換に有効となるでしょう



前のページへ戻る次のページへ