[ create a new paste ] login | about

Link: http://codepad.org/AIeLIExa    [ raw code | output | fork ]

C++, pasted on May 22:
/*前回と前々回では2Dグラフィックスの変換をおこないましたが,今回はこれを3次元へ拡張してみます.
以下のシンプルなプログラムを修正する形で進めていきましょう*/

#include<iostream>
#include<GL/glut.h>
#include<math.h>

const double PI = 3.14159265;

//変形させる対象(2次元座標系内の正方形)
double vertices[][2]={//頂点の座標
	{0.0, 0.5},
	{0.0, 0.0},
	{0.5, 0.0},
	{0.5, 0.5},
};

int nv=4; //頂点数

void display(void){
	glClear(GL_COLOR_BUFFER_BIT);

	//座標軸の表示
	glColor3f(1.0, 1.0, 1.0);
	glBegin(GL_LINES);
	glVertex2d(-1.0, 0.0);
	glVertex2d(1.0, 0.0);
	glVertex2d(0.0, -1.0);
	glVertex2d(0.0, 1.0);
	glEnd();

	//表示
	glColor3f(0.0, 1.0, 0.0);
	glBegin(GL_LINE_LOOP);

	for(int i = 0; i < nv; i++)
		glVertex2d(vertices[i][0], vertices[i][1]);

	glEnd();
	glFlush();
}

int main(int argc, char *argv[]){
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA);
	glutCreateWindow(argv[0]);
	glClearColor(0.0, 0.0, 0.0, 0.0);	
	glutDisplayFunc(display);
	glutMainLoop();
	return 0;
}
/*このソースコードでは,平面は x, y 座標を表す2次元の変数verticesで定義していました.
今回は3Dグラフィックですから,これにz軸の変数を増やすことから始めましょう.*/

//変形させる対象
double vertices[][3]={//3次元頂点の座標
	{0.0, 0.5, 0.0},
	{0.0, 0.0, 0.0},
	{0.5, 0.0, 0.0},
	{0.5, 0.5, 0.0},
};

/*計算機の画面は2次元ですから,この3次元点を2次元へ投影変換して表示します.
投影変換は透視投影と平行投影を学びましたが,まずは簡単な平行投影を実装してみましょう.
平行投影はZ座標値が変化しても描画される大きさが変化しない投影方法です
簡単には,この実装はz座標を無視して描画するだけです.
つまり,頂点の座標にZ値を持たない2次元の図形描画と同じ表示結果が得られます.*/



//表示
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_LINE_LOOP);
for(int i = 0; i < nv; i++)
	glVertex2d(vertices[i][0], vertices[i][1]);
glEnd();

/*しかし,これでは3次元なのか2次元なのか区別がつきません.
そこで,次に示す3次元空間での回転を実装することで図形が3次元空間で定義されていることを確認します.

3次元空間での回転は2次元の回転と違い,独立な直交軸周りでの回転は三種類定義できますが,
ここではY軸周りに回転させてみましょう

変換行列の大きさは3x3ではなく,4x4になります.
この点を踏まえ,以下に示す前回のプログラムをを参考にして各自つくってみてください.*/

//前回のソースファイル(少しだけ変えてあります)

#include<iostream>
#include<GL/glut.h>
#include<math.h>

const double PI = 3.14159265;

//変形させる対象
double vertices[][2]={//頂点の座標
	{0.0, 0.5},
	{0.0, 0.0},
	{0.5, 0.0},
	{0.5, 0.5},
};
const int nv = 4;//頂点数

//変換行列
double transformation_mat[3][3]={
	{0.0, 0.0, 0.0},
	{0.0, 0.0, 0.0},
	{0.0, 0.0, 0.0}
};

//引数を強制的に単位行列にする
void setIdentity33(double mat[3][3]){
	for(int i = 0; i < 3; i++){
		for(int j = 0; j < 3; j++)
			if(i == j) mat[i][j] = 1.0;
			else mat[i][j] = 0.0;
	}
}

void copy33(double out_mat[3][3], const double in_mat[3][3]){

	for(int i=0; i<3; i++){
		for(int j=0; j<3; j++){
			out_mat[i][j] = in_mat[i][j];
		}
	}

}

//3*3行列の掛け算
void makeTransformation2DMatrix(double out_mat[3][3], const double in_mat1[3][3], const double in_mat2[3][3]){
	for(int i=0; i<3; i++){
		for(int j=0; j<3; j++){
			out_mat[i][j] = 
								in_mat1[i][0] * in_mat2[0][j] + 
								in_mat1[i][1] * in_mat2[1][j] +	
								in_mat1[i][2] * in_mat2[2][j];
		}
	}
}


//3*3行列の掛け算。out_matとin_mat1,in_mat2は同じでも大丈夫
void multiply33by33(double out_mat[3][3], const double in_mat1[3][3], const double in_mat2[3][3]){
	double temp_mat1[3][3]={ 
		{0.0, 0.0, 0.0},
		{0.0, 0.0, 0.0},
		{0.0, 0.0, 0.0}
	};
	copy33(temp_mat1, in_mat1);
	double temp_mat2[3][3]={ 
		{0.0, 0.0, 0.0},
		{0.0, 0.0, 0.0},
		{0.0, 0.0, 0.0}
	};
	copy33(temp_mat2, in_mat2);	
	for(int i=0; i<3; i++){
		for(int j=0; j<3; j++){
			out_mat[i][j] = 
				temp_mat1[i][0] * temp_mat2[0][j] + 
				temp_mat1[i][1] * temp_mat2[1][j] +	
				temp_mat1[i][2] * temp_mat2[2][j];
		}
	}
}

//平行移動行列の生成。mat:結果、tx:x方向の移動量、ty:y方向の移動量
void makeTranslation2DMatrix(double mat[3][3], const double tx, const double ty){
	mat[0][0] = 1;	mat[0][1] = 0;	mat[0][2] = tx;
	mat[1][0] = 0;	mat[1][1] = 1;	mat[1][2] = ty;
	mat[2][0] = 0;	mat[2][1] = 0;	mat[2][2] = 1;
}

void set2DTranslation(const double tx, const double ty){
	
	double translation_mat[3][3]={ 
		{0.0, 0.0, 0.0},
		{0.0, 0.0, 0.0},
		{0.0, 0.0, 0.0}
	};
	makeTranslation2DMatrix(translation_mat, tx, ty);
	multiply33by33(transformation_mat, translation_mat, transformation_mat); 

}

//回転行列の生成。mat:結果、r:回転角
void makeRotation2DMatrix(double mat[3][3], const double r){
	mat[0][0] = cos(r); 	mat[0][1] = -1*sin(r);	mat[0][2] = 0;
	mat[1][0] = sin(r);	mat[1][1] = cos(r);	mat[1][2] = 0;
	mat[2][0] = 0;		mat[2][1] = 0;		mat[2][2] = 1;
}

void set2DRotation(const double r){
	
	double rotation_mat[3][3]={ 
		{0.0, 0.0, 0.0},
		{0.0, 0.0, 0.0},
		{0.0, 0.0, 0.0}
	};
	makeRotation2DMatrix(rotation_mat, r);
	multiply33by33(transformation_mat, rotation_mat, transformation_mat); 

}

//3*3行列Aと3*1行列vの掛け算Avの計算。vertex:v(破壊されて結果が入る)、mat:A
void transform2D(double vertex[], const double mat[3][3]){
	double temp_x = vertex[0];
	double temp_y = vertex[1];
	for(int i=0; i<2; i++){
		vertex[i] = temp_x*mat[i][0] + temp_y*mat[i][1] + 1.0 * mat[i][2];
	}

}

void display(void){
	glClear(GL_COLOR_BUFFER_BIT);

	//座標軸の表示
	glColor3f(1.0, 1.0, 1.0);
	glBegin(GL_LINES);
	glVertex2d(-1.0, 0.0);
	glVertex2d(1.0, 0.0);
	glVertex2d(0.0, -1.0);
	glVertex2d(0.0, 1.0);
	glEnd();

	//座標変換
	setIdentity33(transformation_mat);
	set2DTranslation(0.5,0.0);
	set2DRotation(PI/4);
	set2DTranslation(0.0,-1.0);
	for(int i = 0; i < nv; i++)
		transform2D(vertices[i], transformation_mat);

	//表示
	glColor3f(0.0, 1.0, 0.0);
	glBegin(GL_LINE_LOOP);
	for(int i = 0; i < nv; i++)
		glVertex2d(vertices[i][0], vertices[i][1]);
	glEnd();
	glFlush();
}

int main(int argc, char *argv[]){
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA);
	glutCreateWindow(argv[0]);
	glClearColor(0.0, 0.0, 0.0, 0.0);	
	glutDisplayFunc(display);
	glutMainLoop();
	return 0;
}

/*完成したら回転角を変更してコードの挙動を確かめてください.
例えば,Y軸回転させれば画面では図形の横幅が縮んで見えるはずです.
また,変換する頂点数を増やして形を変えたりしてみてください.*/

/*透視投影変換

次に透視投影をしてみましょう.
透視投影をするにはモデルの頂点座標に投影変換の行列を変換行列に掛けて,最終的な画面上の座標を求めます.
前述の平行投影ではZ座標を無視するということをしていますが,これはZ=a平面へ投影する変換行列を書けていることと等価なのです.
透視投影変換で注意すべきことは,カメラ座標系と世界座標系の位置関係です.
前述のプログラムのように,Zの要素を無視するだけであればZの値が0だろうが,100だろうが関係ありません.
しかし,透視投影変換では,Zの値によって小さなドットとなってしまうこともあれば,画面に収まりきれないほど大きくなる場合もあります.
ただし,何れの投影においても画面の大きさは有限ですから,座標系と投影変換行列で定義されるカメラの視点の関係に注意しなければならないことは同じです.

もちろん,描画物体がカメラの視線の前に置かれていない場合には画面に描画されません.
この場合,投影変換を修正してカメラの向きを変えることで画面に描画することは可能ですが,
扱いが煩雑になるので,通常は投影変換と描画物体の位置変換(もしくはカメラの位置)は別々に分けて考えます.
コンピュータビジョンでは内部パラメータ,外部パラメータという言葉で区別されます.

この演習では,簡単のためにカメラの画像平面(投影面)と視点位置を以下の図のように想定し,物体位置と視点と画像平面の比率を求めます.*/

//これを実装すると以下のようになります.

 
   double s = 1.0;
   double d = 1.9; 
   glColor3f(0.0, 1.0, 0.0);
   glBegin(GL_LINE_LOOP);
   for(int i = 0; i < nv; i++){
      glVertex2d(s / (d - vertices[i][2]) * vertices[i][0], s / (d - vertices[i][2]) * vertices[i][1]);
   }
   glEnd();


Output:
1
2
3
4
Line 19: error: GL/glut.h: No such file or directory
In function 'void display()':
Line 21: error: 'GL_COLOR_BUFFER_BIT' was not declared in this scope
compilation terminated due to -Wfatal-errors.


Create a new paste based on this one


Comments: