3Dの描画

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

3Dの描画

#1

投稿記事 by みけCAT » 14年前

開発環境はDev-C++4.9.9.2、gcc3.4.2です。
3Dの座標を2Dに描画しようとして、プログラムを組んでみました。
実行すると、draw3dlineでエラーが出ているようです。
たぶんhenkan3dzahyou内のエラーだと思います。
henkan3dzahyouの仕組みは
1.カメラが向いている方向のベクトルを計算します
2.変換したい座標からカメラが向いている方向の直線に下ろした垂線のベクトルを計算します
  (変換したい座標が終点)
  同時にカメラから垂線の足までのベクトルも用意します
3.カメラの横方向と縦方向のベクトルを用意します(描画する際の方向の基準です)
4.それぞれのベクトルのなす角のコサインを計算します
  msin:基準の横方向と垂線のなす角のコサイン
  scos:垂線と基準の縦方向のなす角のコサイン
  dcos:カメラと求めたい座標を結ぶ線とカメラが向いている方向のなす角のコサイン
  この時dcosが負だったら、座標がカメラの後ろにあるとしてエラーにします
5.コサインから必要なサインやタンジェントを計算します
6.実際に描画する中央の点と描画する点との距離を計算します
7.その距離と角度のサイン・コサインから実際に描画する座標を計算します
解決法がわかる方がいらっしゃいましたら教えていただければ幸いです。
よろしくお願いします。
添付ファイル
3dtest.zip
プログラムです。
(13.97 KiB) ダウンロード数: 242 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 3Dの描画

#2

投稿記事 by softya(ソフト屋) » 14年前

これってGDBとかでトレースしたんでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#3

投稿記事 by みけCAT » 14年前

softya(ソフト屋) さんが書きました:これってGDBとかでトレースしたんでしょうか?
すいません、GDBって何ですか?
[hr]とりあえず描画はされるようになりました。
しかし、x方向にカメラの首を振ると、描画がおかしくなってしまいました。
どこを直せばいいかわかりましたら教えていただければ幸いです。
よろしくお願いします。
添付ファイル
3dtest(2).zip
プログラムです。
(15.64 KiB) ダウンロード数: 222 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 3Dの描画

#4

投稿記事 by softya(ソフト屋) » 14年前

GDBはデバッガです。
もしかしてDev-C++だと統合環境として内部で動くGDBは隠蔽されているのかな?
と言う事で、Dev-C++でデバッガでトレースしましたか?

>しかし、x方向にカメラの首を振ると、描画がおかしくなってしまいました。
>どこを直せばいいかわかりましたら教えていただければ幸いです。
この件は、Dev-C++をインストールして確認してみるのでちょっと待ってくださいね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#5

投稿記事 by みけCAT » 14年前

とりあえずhenkan3dzahyou関数をこれに差し替えると(直ってはいませんが)改善した気がします。

コード:

int henkan3dzahyou(double* ox,double* oy,
		double x,double y,double z,const camera_t* camera) {
	double dx,dy,dz;/*カメラが向いている方向*/
	double hx,hy,hz;/*カメラが向いている方向への垂線*/
	double kx,ky,kz;/*基準の方向*/
	double sx,sy,sz;/*基準と垂直の方向*/
	double x1,y1,z1,k;/*垂線計算用*/
	double length;/*垂線の長さ*/
	double mcos,scos,dcos;/*コサインの値*/
	double msin;/*サインの値*/
	double dtan;/*タンジェントの値*/
	double klength;/*視野角ぎりぎりの時の長さ*/
	double dlength;/*描画に使う長さ*/
	debuginit;
	printstr("henkan3dzahyou開始");
	printbekutoru("カメラの座標",camera->x,camera->y,camera->z);
	printbekutoru("カメラの回転",camera->cx,camera->cy,camera->cz);
	printnum("カメラの視野(ピクセル)",camera->genkai);
	printnum("カメラの視野(角度)",camera->genkaiangle);
	printnum("カメラの描画の中心x",camera->centerx);
	printnum("カメラの描画の中心y",camera->centery);
	printbekutoru("変換する座標",x,y,z);
	/*カメラが向いている方向を計算*/
	dy=cos(camera->cy);
	dz=sin(camera->cy);
	dx=dy*sin(camera->cx);
	dy=dy*cos(camera->cx);
	printbekutoru("カメラの方向",dx,dy,dz);
	/*垂線を計算*/
	x1=x-camera->x;
	y1=y-camera->y;
	z1=z-camera->z;
	k=(x1*dx+y1*dy+z1*dz)/(dx*dx+dy*dy+dz*dz);
	hx=x1-k*dx;
	hy=y1-k*dy;
	hz=z1-k*dz;
	length=sqrt(hx*hx+hy*hy+hz*hz);
	printbekutoru("カメラから座標へ",x1,y1,z1);
	printnum("k",k);
	printbekutoru("垂線",hx,hy,hz);
	printnum("垂線の長さ",length);
	/*基準の方向を計算*/
	ky=-sin(camera->cx);
	kx=cos(camera->cx);
	ky=ky*cos(camera->cy);
	kz=ky*sin(camera->cy);
	printbekutoru("基準(横)",kx,ky,kz);
	/*回転は未実装*/
	/*基準と垂直の方向を計算*/
	sy=-sin(camera->cy);
	sz=cos(camera->cy);
	sy=sy*cos(camera->cx);
	sx=sy*sin(camera->cx);
	printbekutoru("基準(縦)",sx,sy,sz);
	/*回転は未実装*/
	/*コサインの値を計算*/
	mcos=(hx*kx+hy*ky+hz*kz)?
		(hx*kx+hy*ky+hz*kz)/*内積*/
		/(sqrt(hx*hx+hy*hy+hz*hz)*sqrt(kx*kx+ky*ky+kz*kz))/*大きさの積*/
		:0;
	scos=(hx*sx+hy*sy+hz*sz)?
		(hx*sx+hy*sy+hz*sz)/*内積*/
		/(sqrt(hx*hx+hy*hy+hz*hz)*sqrt(sx*sx+sy*sy+sz*sz))/*大きさの積*/
		:0;
	dcos=(x1*dx+y1*dy+z1*dz)?
		(x1*dx+y1*dy+z1*dz)/*内積*/
		/(sqrt(x1*x1+y1*y1+z1*z1)*sqrt(dx*dx+dy*dy+dz*dz))/*大きさの積*/
		:0;
	printnum("mcos",mcos);
	printnum("scos",scos);
	printnum("dcos",dcos);
#ifdef DEBUG
	if(dcos<0) {
		printstr("エラー");
		debugend;
		return 0;
	}
#else
	if(dcos<0)return 0;
#endif
	/*サインの値を計算*/
	msin=sqrt(1-mcos*mcos)*(scos>=0?1:-1);
	printnum("msin",msin);
	/*タンジェントの値を計算*/
	dtan=sqrt(1/(dcos*dcos)-1);
	printnum("dtan",dtan);
	/*基準の長さを計算*/
	klength=camera->genkai/tan(camera->genkaiangle);
	printnum("klength",klength);
	/*描画に使う長さを計算*/
	dlength=klength*dtan;
	printnum("dlength",dlength);
	/*実際に描画する座標を計算*/
	*ox=camera->centerx+dlength*mcos;
	*oy=camera->centery-dlength*msin;
	printnum("描画x",*ox);
	printnum("描画y",*oy);
	printstr("henkan3dzahyou終了");
	debugend;
	return 1;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#6

投稿記事 by みけCAT » 14年前

「x方向にカメラの首を振ると」というより、x方向とy方向を両方使ったときにおかしくなるようです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 3Dの描画

#7

投稿記事 by softya(ソフト屋) » 14年前

申し訳ない行列を使わない透視変換は何十年ぶりなので、ソースの解読に時間がかかりそうです。
行列の透視変換に変えてもOKでしょうか?
もし、このままが良いならもう少し時間を下さい。

あとご自分でカメラ45度とか分かりやすい数値で机上計算してみて、実際に動かした値と違うか付きあわせてみる手もありますよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#8

投稿記事 by みけCAT » 14年前

行列はわからないのでこのままでお願いします。
とりあえず回転のアルゴリズムを変えてみました。
改善しません。

コード:

int henkan3dzahyou(double* ox,double* oy,
		double x,double y,double z,const camera_t* camera) {
	double dx,dy,dz;/*カメラが向いている方向*/
	double hx,hy,hz;/*カメラが向いている方向への垂線*/
	double kx,ky,kz;/*基準の方向*/
	double sx,sy,sz;/*基準と垂直の方向*/
	double x1,y1,z1,k;/*垂線計算用*/
	double length;/*垂線の長さ*/
	double mcos,scos,dcos;/*コサインの値*/
	double msin;/*サインの値*/
	double dtan;/*タンジェントの値*/
	double klength;/*視野角ぎりぎりの時の長さ*/
	double dlength;/*描画に使う長さ*/
	debuginit;
	printstr("henkan3dzahyou開始");
	printbekutoru("カメラの座標",camera->x,camera->y,camera->z);
	printbekutoru("カメラの回転",camera->cx,camera->cy,camera->cz);
	printnum("カメラの視野(ピクセル)",camera->genkai);
	printnum("カメラの視野(角度)",camera->genkaiangle);
	printnum("カメラの描画の中心x",camera->centerx);
	printnum("カメラの描画の中心y",camera->centery);
	printbekutoru("変換する座標",x,y,z);
	/*カメラが向いている方向を計算*/
	dy=cos(camera->cx);
	dx=sin(camera->cx);
	dz=sin(camera->cy);
	dy=dy*cos(camera->cy);
	dx=dx*cos(camera->cy);
	printbekutoru("カメラの方向",dx,dy,dz);
	/*垂線を計算*/
	x1=x-camera->x;
	y1=y-camera->y;
	z1=z-camera->z;
	k=(x1*dx+y1*dy+z1*dz)/(dx*dx+dy*dy+dz*dz);
	hx=x1-k*dx;
	hy=y1-k*dy;
	hz=z1-k*dz;
	length=sqrt(hx*hx+hy*hy+hz*hz);
	printbekutoru("カメラから座標へ",x1,y1,z1);
	printnum("k",k);
	printbekutoru("垂線",hx,hy,hz);
	printnum("垂線の長さ",length);
	/*基準の方向を計算*/
	ky=-sin(camera->cx);
	kx=cos(camera->cx);
	printbekutoru("基準(横)",kx,ky,kz);
	/*回転は未実装*/
	/*基準と垂直の方向を計算*/
	sy=-sin(camera->cy);
	sz=cos(camera->cy);
	printbekutoru("基準(縦)",sx,sy,sz);
	/*回転は未実装*/
	/*コサインの値を計算*/
	mcos=(hx*kx+hy*ky+hz*kz)?
		(hx*kx+hy*ky+hz*kz)/*内積*/
		/(sqrt(hx*hx+hy*hy+hz*hz)*sqrt(kx*kx+ky*ky+kz*kz))/*大きさの積*/
		:0;
	scos=(hx*sx+hy*sy+hz*sz)?
		(hx*sx+hy*sy+hz*sz)/*内積*/
		/(sqrt(hx*hx+hy*hy+hz*hz)*sqrt(sx*sx+sy*sy+sz*sz))/*大きさの積*/
		:0;
	dcos=(x1*dx+y1*dy+z1*dz)?
		(x1*dx+y1*dy+z1*dz)/*内積*/
		/(sqrt(x1*x1+y1*y1+z1*z1)*sqrt(dx*dx+dy*dy+dz*dz))/*大きさの積*/
		:0;
	printnum("mcos",mcos);
	printnum("scos",scos);
	printnum("dcos",dcos);
#ifdef DEBUG
	if(dcos<0) {
		printstr("エラー");
		debugend;
		return 0;
	}
#else
	if(dcos<0)return 0;
#endif
	/*サインの値を計算*/
	msin=sqrt(1-mcos*mcos)*(scos>=0?1:-1);
	printnum("msin",msin);
	/*タンジェントの値を計算*/
	dtan=sqrt(1/(dcos*dcos)-1);
	printnum("dtan",dtan);
	/*基準の長さを計算*/
	klength=camera->genkai/tan(camera->genkaiangle);
	printnum("klength",klength);
	/*描画に使う長さを計算*/
	dlength=klength*dtan;
	printnum("dlength",dlength);
	/*実際に描画する座標を計算*/
	*ox=camera->centerx+dlength*mcos;
	*oy=camera->centery-dlength*msin;
	printnum("描画x",*ox);
	printnum("描画y",*oy);
	printstr("henkan3dzahyou終了");
	debugend;
	return 1;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 3Dの描画

#9

投稿記事 by softya(ソフト屋) » 14年前

んじゃ、こっちで一旦行列で組んでそれを展開したものを作ってみます。
展開したものは、ほとんど同じになると思いますので。
それと値を突き合わせれば、何処の透視変換の式の部分に問題があるか分かってくると思います。

あと、この透視変換はオリジナルですか、それとも何処かのサイトや本を参考にされましたか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#10

投稿記事 by みけCAT » 14年前

これは自分なりに考えて作っています。
カメラの向いている方向に垂直な基準の平面を置き、
カメラと対象の座標を結ぶ線とその平面の交点の座標を返そうとしています。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 3Dの描画

#11

投稿記事 by softya(ソフト屋) » 14年前

みけCAT さんが書きました:これは自分なりに考えて作っています。
カメラの向いている方向に垂直な基準の平面を置き、
カメラと対象の座標を結ぶ線とその平面の交点の座標を返そうとしています。
分かりました。
透視投影変換の基本通りですね。

ところで画角が150度と定義されているので、もしこのとおり働いていると超広角レンズな値ですがこのままでよろしいですか?
http://ja.wikipedia.org/wiki/%E7%94%BB%E8%A7%92
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#12

投稿記事 by みけCAT » 14年前

softya(ソフト屋) さんが書きました:ところで画角が150度と定義されているので、もしこのとおり働いていると超広角レンズな値ですがこのままでよろしいですか?
その値は適切な値がわからなかったので、適当に入れておきました。
リンク先を見たところ、50度くらいがいいということですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 3Dの描画

#13

投稿記事 by softya(ソフト屋) » 14年前

みけCAT さんが書きました:
softya(ソフト屋) さんが書きました:ところで画角が150度と定義されているので、もしこのとおり働いていると超広角レンズな値ですがこのままでよろしいですか?
その値は適切な値がわからなかったので、適当に入れておきました。
リンク先を見たところ、50度くらいがいいということですか?
人間の目に近い画角の50度ぐらいが適度な値だと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#14

投稿記事 by みけCAT » 14年前

だいぶいい感じになってきました。

コード:

int henkan3dzahyou(double* ox,double* oy,
		double x,double y,double z,const camera_t* camera) {
	double dx,dy,dz;/*カメラが向いている方向*/
	double hx,hy,hz;/*カメラが向いている方向への垂線*/
	double kx,ky,kz;/*基準の方向*/
	double sx,sy,sz;/*基準と垂直の方向*/
	double x1,y1,z1,k;/*垂線計算用*/
	double length;/*垂線の長さ*/
	double mcos,scos,dcos;/*コサインの値*/
	double msin;/*サインの値*/
	double dtan;/*タンジェントの値*/
	double klength;/*視野角ぎりぎりの時の長さ*/
	double dlength;/*描画に使う長さ*/
	debuginit;
	printstr("henkan3dzahyou開始");
	printbekutoru("カメラの座標",camera->x,camera->y,camera->z);
	printbekutoru("カメラの回転",camera->cx,camera->cy,camera->cz);
	printnum("カメラの視野(ピクセル)",camera->genkai);
	printnum("カメラの視野(角度)",camera->genkaiangle);
	printnum("カメラの描画の中心x",camera->centerx);
	printnum("カメラの描画の中心y",camera->centery);
	printbekutoru("変換する座標",x,y,z);
	/*カメラが向いている方向を計算*/
	dy=cos(camera->cx);
	dx=sin(camera->cx);
	dz=sin(camera->cy);
	dy=dy*cos(camera->cy);
	dx=dx*cos(camera->cy);
	printbekutoru("カメラの方向",dx,dy,dz);
	/*垂線を計算*/
	x1=x-camera->x;
	y1=y-camera->y;
	z1=z-camera->z;
	k=(x1*dx+y1*dy+z1*dz)/(dx*dx+dy*dy+dz*dz);
	hx=x1-k*dx;
	hy=y1-k*dy;
	hz=z1-k*dz;
	length=sqrt(hx*hx+hy*hy+hz*hz);
	printbekutoru("カメラから座標へ",x1,y1,z1);
	printnum("k",k);
	printbekutoru("垂線",hx,hy,hz);
	printnum("垂線の長さ",length);
	/*基準の方向を計算*/
	ky=-sin(camera->cx);
	kx=cos(camera->cx);
	kz=0;
	/*kz=sin(camera->cz);
	ky=ky*cos(camera->cz);
	kx=kx*cos(camera->cz);*/
	printbekutoru("基準(横)",kx,ky,kz);
	/*基準と垂直の方向を計算*/
	sy=-sin(camera->cy);
	sz=cos(camera->cy);
	sx=sy*sin(camera->cx);
	sy=sy*cos(camera->cx);
	printbekutoru("基準(縦)",sx,sy,sz);
	/*コサインの値を計算*/
	mcos=(hx*kx+hy*ky+hz*kz)?
		(hx*kx+hy*ky+hz*kz)/*内積*/
		/(sqrt(hx*hx+hy*hy+hz*hz)*sqrt(kx*kx+ky*ky+kz*kz))/*大きさの積*/
		:0;
	scos=(hx*sx+hy*sy+hz*sz)?
		(hx*sx+hy*sy+hz*sz)/*内積*/
		/(sqrt(hx*hx+hy*hy+hz*hz)*sqrt(sx*sx+sy*sy+sz*sz))/*大きさの積*/
		:0;
	dcos=(x1*dx+y1*dy+z1*dz)?
		(x1*dx+y1*dy+z1*dz)/*内積*/
		/(sqrt(x1*x1+y1*y1+z1*z1)*sqrt(dx*dx+dy*dy+dz*dz))/*大きさの積*/
		:0;
	printnum("mcos",mcos);
	printnum("scos",scos);
	printnum("dcos",dcos);
#ifdef DEBUG
	if(dcos<0) {
		printstr("エラー");
		debugend;
		return 0;
	}
#else
	if(dcos<0)return 0;
#endif
	/*サインの値を計算*/
	msin=sqrt(1-mcos*mcos)*(scos>=0?1:-1);
	printnum("msin",msin);
	/*タンジェントの値を計算*/
	dtan=sqrt(1/(dcos*dcos)-1);
	printnum("dtan",dtan);
	/*基準の長さを計算*/
	klength=camera->genkai/tan(camera->genkaiangle);
	printnum("klength",klength);
	/*描画に使う長さを計算*/
	dlength=klength*dtan;
	printnum("dlength",dlength);
	/*実際に描画する座標を計算*/
	*ox=camera->centerx+dlength*mcos;
	*oy=camera->centery-dlength*msin;
	printnum("描画x",*ox);
	printnum("描画y",*oy);
	printstr("henkan3dzahyou終了");
	debugend;
	return 1;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#15

投稿記事 by みけCAT » 14年前

カメラの回転を実装してみましたが、どこかがおかしいようです。
どこが間違っているでしょうか?

コード:

int henkan3dzahyou(double* ox,double* oy,
		double x,double y,double z,const camera_t* camera) {
	double dx,dy,dz;/*カメラが向いている方向*/
	double hx,hy,hz;/*カメラが向いている方向への垂線*/
	double kx,ky,kz;/*基準の方向*/
	double sx,sy,sz;/*基準と垂直の方向*/
	double x1,y1,z1,k;/*垂線計算用*/
	double length;/*垂線の長さ*/
	double mcos,scos,dcos;/*コサインの値*/
	double msin;/*サインの値*/
	double dtan;/*タンジェントの値*/
	double klength;/*視野角ぎりぎりの時の長さ*/
	double dlength;/*描画に使う長さ*/
	debuginit;
	printstr("henkan3dzahyou開始");
	printbekutoru("カメラの座標",camera->x,camera->y,camera->z);
	printbekutoru("カメラの回転",camera->cx,camera->cy,camera->cz);
	printnum("カメラの視野(ピクセル)",camera->genkai);
	printnum("カメラの視野(角度)",camera->genkaiangle);
	printnum("カメラの描画の中心x",camera->centerx);
	printnum("カメラの描画の中心y",camera->centery);
	printbekutoru("変換する座標",x,y,z);
	/*カメラが向いている方向を計算*/
	dy=cos(camera->cx);
	dx=sin(camera->cx);
	dz=sin(camera->cy);
	dy=dy*cos(camera->cy);
	dx=dx*cos(camera->cy);
	printbekutoru("カメラの方向",dx,dy,dz);
	/*垂線を計算*/
	x1=x-camera->x;
	y1=y-camera->y;
	z1=z-camera->z;
	k=(x1*dx+y1*dy+z1*dz)/(dx*dx+dy*dy+dz*dz);
	hx=x1-k*dx;
	hy=y1-k*dy;
	hz=z1-k*dz;
	length=sqrt(hx*hx+hy*hy+hz*hz);
	printbekutoru("カメラから座標へ",x1,y1,z1);
	printnum("k",k);
	printbekutoru("垂線",hx,hy,hz);
	printnum("垂線の長さ",length);
	/*基準の方向を計算*/
	ky=-sin(camera->cx);
	kx=cos(camera->cx);
	kz=sin(camera->cz);
	ky=ky*cos(camera->cz);
	kx=kx*cos(camera->cz);
	printbekutoru("基準(横)",kx,ky,kz);
	/*基準と垂直の方向を計算*/
	/*sy=-sin(camera->cy);
	sz=cos(camera->cy);
	sx=sy*sin(camera->cx);
	sy=sy*cos(camera->cx);*/
	/*ベクトルの外積を使ってみる*/
	sx=ky*dz-dy*kz;
	sy=kz*dx-dz*kx;
	sz=kx*dy-dx*ky;
	printbekutoru("基準(縦)",sx,sy,sz);
	/*コサインの値を計算*/
	mcos=(hx*kx+hy*ky+hz*kz)?
		(hx*kx+hy*ky+hz*kz)/*内積*/
		/(sqrt(hx*hx+hy*hy+hz*hz)*sqrt(kx*kx+ky*ky+kz*kz))/*大きさの積*/
		:0;
	scos=(hx*sx+hy*sy+hz*sz)?
		(hx*sx+hy*sy+hz*sz)/*内積*/
		/(sqrt(hx*hx+hy*hy+hz*hz)*sqrt(sx*sx+sy*sy+sz*sz))/*大きさの積*/
		:0;
	dcos=(x1*dx+y1*dy+z1*dz)?
		(x1*dx+y1*dy+z1*dz)/*内積*/
		/(sqrt(x1*x1+y1*y1+z1*z1)*sqrt(dx*dx+dy*dy+dz*dz))/*大きさの積*/
		:0;
	printnum("mcos",mcos);
	printnum("scos",scos);
	printnum("dcos",dcos);
#ifdef DEBUG
	if(dcos<0) {
		printstr("エラー");
		debugend;
		return 0;
	}
#else
	if(dcos<0)return 0;
#endif
	/*サインの値を計算*/
	msin=sqrt(1-mcos*mcos)*(scos>=0?1:-1);
	printnum("msin",msin);
	/*タンジェントの値を計算*/
	dtan=sqrt(1/(dcos*dcos)-1);
	printnum("dtan",dtan);
	/*基準の長さを計算*/
	klength=camera->genkai/tan(camera->genkaiangle);
	printnum("klength",klength);
	/*描画に使う長さを計算*/
	dlength=klength*dtan;
	printnum("dlength",dlength);
	/*実際に描画する座標を計算*/
	*ox=camera->centerx+dlength*mcos;
	*oy=camera->centery-dlength*msin;
	printnum("描画x",*ox);
	printnum("描画y",*oy);
	printstr("henkan3dzahyou終了");
	debugend;
	return 1;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#16

投稿記事 by みけCAT » 14年前

一旦プロジェクト全体を上げます。
添付ファイル
3dtest(3).zip
プログラムです。
(16.13 KiB) ダウンロード数: 226 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#17

投稿記事 by みけCAT » 14年前

計算方法を変えて少しは改善しましたが、完全ではありません。
「どこが悪いか」というより、基準のベクトルを計算するところが間違っていると思います。
どう直せばいいか教えていただきたいです。
y方向の回転がPI/2を超えると、画像の向きが逆になってしまうようです。
よろしくお願いします。

コード:

int henkan3dzahyou(double* ox,double* oy,
		double x,double y,double z,const camera_t* camera) {
	double dx,dy,dz;/*カメラが向いている方向*/
	double hx,hy,hz;/*カメラが向いている方向への垂線*/
	double kx,ky,kz;/*基準の方向*/
	double sx,sy,sz;/*基準と垂直の方向*/
	double kdx,kdy,kdz;/*基準の方向計算用*/
	double x1,y1,z1,k;/*垂線計算用*/
	double length;/*垂線の長さ*/
	double mcos,scos,dcos;/*コサインの値*/
	double msin;/*サインの値*/
	double dtan;/*タンジェントの値*/
	double klength;/*視野角ぎりぎりの時の長さ*/
	double dlength;/*描画に使う長さ*/
	debuginit;
	printstr("henkan3dzahyou開始");
	printbekutoru("カメラの座標",camera->x,camera->y,camera->z);
	printbekutoru("カメラの回転",camera->cx,camera->cy,camera->cz);
	printnum("カメラの視野(ピクセル)",camera->genkai);
	printnum("カメラの視野(角度)",camera->genkaiangle);
	printnum("カメラの描画の中心x",camera->centerx);
	printnum("カメラの描画の中心y",camera->centery);
	printbekutoru("変換する座標",x,y,z);
	/*カメラが向いている方向を計算*/
	dy=cos(camera->cx);
	dx=sin(camera->cx);
	dz=sin(camera->cy);
	dy=dy*cos(camera->cy);
	dx=dx*cos(camera->cy);
	printbekutoru("カメラの方向",dx,dy,dz);
	/*垂線を計算*/
	x1=x-camera->x;
	y1=y-camera->y;
	z1=z-camera->z;
	k=(x1*dx+y1*dy+z1*dz)/(dx*dx+dy*dy+dz*dz);
	hx=x1-k*dx;
	hy=y1-k*dy;
	hz=z1-k*dz;
	length=sqrt(hx*hx+hy*hy+hz*hz);
	printbekutoru("カメラから座標へ",x1,y1,z1);
	printnum("k",k);
	printbekutoru("垂線",hx,hy,hz);
	printnum("垂線の長さ",length);
	/*基準の方向を計算*/
	/*ky=-sin(camera->cx);
	kx=cos(camera->cx);
	kz=sin(camera->cz);
	ky=ky*cos(camera->cz);
	kx=kx*cos(camera->cz);*/
	kdx=sin(camera->cz);
	kdz=-cos(camera->cz);
	kdx=kdx*cos(camera->cx);
	kdy=-kdx*sin(camera->cx);
	if(dx==0 && dy==0) {/*真上か真下だったら*/
		kz=0;
		kx=cos(camera->cz);
		ky=sin(camera->cz)*(dz>0?-1:1);
	} else {/*外積の利用*/
		kx=kdx*dz-dy*kdz;
		ky=kdz*dx-dz*kdx;
		kz=kdx*dy-dx*kdy;
	}
	printbekutoru("基準(横)",kx,ky,kz);
	/*基準と垂直の方向を計算*/
	/*sy=-sin(camera->cy);
	sz=cos(camera->cy);
	sx=sy*sin(camera->cx);
	sy=sy*cos(camera->cx);*/
	/*ベクトルの外積を使ってみる*/
	sx=ky*dz-dy*kz;
	sy=kz*dx-dz*kx;
	sz=kx*dy-dx*ky;
	printbekutoru("基準(縦)",sx,sy,sz);
	/*コサインの値を計算*/
	mcos=(hx*kx+hy*ky+hz*kz)?
		(hx*kx+hy*ky+hz*kz)/*内積*/
		/(sqrt(hx*hx+hy*hy+hz*hz)*sqrt(kx*kx+ky*ky+kz*kz))/*大きさの積*/
		:0;
	scos=(hx*sx+hy*sy+hz*sz)?
		(hx*sx+hy*sy+hz*sz)/*内積*/
		/(sqrt(hx*hx+hy*hy+hz*hz)*sqrt(sx*sx+sy*sy+sz*sz))/*大きさの積*/
		:0;
	dcos=(x1*dx+y1*dy+z1*dz)?
		(x1*dx+y1*dy+z1*dz)/*内積*/
		/(sqrt(x1*x1+y1*y1+z1*z1)*sqrt(dx*dx+dy*dy+dz*dz))/*大きさの積*/
		:0;
	printnum("mcos",mcos);
	printnum("scos",scos);
	printnum("dcos",dcos);
#ifdef DEBUG
	if(dcos<0) {
		printstr("エラー");
		debugend;
		return 0;
	}
#else
	if(dcos<0)return 0;
#endif
	/*サインの値を計算*/
	msin=sqrt(1-mcos*mcos)*(scos>=0?1:-1);
	printnum("msin",msin);
	/*タンジェントの値を計算*/
	dtan=sqrt(1/(dcos*dcos)-1);
	printnum("dtan",dtan);
	/*基準の長さを計算*/
	klength=camera->genkai/tan(camera->genkaiangle);
	printnum("klength",klength);
	/*描画に使う長さを計算*/
	dlength=klength*dtan;
	printnum("dlength",dlength);
	/*実際に描画する座標を計算*/
	*ox=camera->centerx+dlength*mcos;
	*oy=camera->centery-dlength*msin;
	printnum("描画x",*ox);
	printnum("描画y",*oy);
	printstr("henkan3dzahyou終了");
	debugend;
	return 1;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 3Dの描画

#18

投稿記事 by softya(ソフト屋) » 14年前

ごめんなさい。
完全に3Dの生の処理を度忘れしていて時間がかかりました。
あと、行列の展開はやろうと思いましたが、やはり死にそうなので勘弁して下さい。

とりあえず、正しく動く例ということで参考にしてもらえばと思います。
変更したところ。
・行列演算にした。
・回転軸がx,yで逆だったので本来の回転軸にした。
・立方体の位置をdraw3dlineで補正している。

コード:

#include <math.h>
#include "3d.h"

#if 1
#define DEBUG
#endif

#ifdef DEBUG
#include <stdio.h>
FILE* fpdebug=NULL;
void _debuginit(void) {
	fpdebug=fopen("debug.txt","a");
}

void _debugend(void) {
	fclose(fpdebug);
	fpdebug=NULL;
}

void _printstr(const char* str) {
	if(fpdebug==NULL)return;
	fprintf(fpdebug,"%s\n",str);
}

void _printbekutoru(const char* exp,double x,double y,double z) {
	if(fpdebug==NULL)return;
	fprintf(fpdebug,"%s=(%f,%f,%f)\n",exp,x,y,z);
}

void _printnum(const char* exp,double num) {
	if(fpdebug==NULL)return;
	fprintf(fpdebug,"%s=%f\n",exp,num);
}
#define debuginit _debuginit()
#define debugend _debugend()
#define printstr(s) _printstr(s)
#define printbekutoru(e,x,y,z) _printbekutoru(e,x,y,z)
#define printnum(e,n) _printnum(e,n)
#else
#define debuginit
#define debugend
#define printstr(s)
#define printbekutoru(e,x,y,z)
#define printnum(e,n)
#endif

//	マトリクスの設定
void setMatrix( double matrix[][4],
				double mat00,	double mat01,	double mat02,	double mat03,
				double mat10,	double mat11,	double mat12,	double mat13,
				double mat20,	double mat21,	double mat22,	double mat23,
				double mat30,	double mat31,	double mat32,	double mat33 )
{
	matrix[0][0]=mat00;	matrix[0][1]=mat01;	matrix[0][2]=mat02;	matrix[0][3]=mat03;
	matrix[1][0]=mat10;	matrix[1][1]=mat11;	matrix[1][2]=mat12;	matrix[1][3]=mat13;
	matrix[2][0]=mat20;	matrix[2][1]=mat21;	matrix[2][2]=mat22;	matrix[2][3]=mat23;
	matrix[3][0]=mat30;	matrix[3][1]=mat31;	matrix[3][2]=mat32;	matrix[3][3]=mat33;
}

//	マトリックス・ポイント計算
void calcMatrixPoint( double matrix[][4],double out[],double in[])
{
	int  i,j;
	//	行列の演算。
	for( i=0 ; i<4; i++ ) {
		out[i] = 0;
		for( j=0 ; j<4; j++ ) {
			out[i] += in[j] * matrix[j][i];
		}
	}
}

//	コピーマトリックス
void copyMatrix( double dstMat[][4],double srcMat[][4])
{
	int  i,j;
	//	コピー
	for( i=0 ; i<4; i++ ) {
		for( j=0 ; j<4; j++ ) {
			dstMat[i][j] = srcMat[i][j];
		}
	}
}

//	マトリックス計算
void calcMatrix( double dstMat[][4],double srcMat[][4])
{
	int  i,j,k;
	double matrix[4][4];
	
	//	クリア
	for( i=0 ; i<4; i++ ) {
		for( j=0 ; j<4; j++ ) {
			matrix[i][j] = 0;
		}
	}
	//	行列の演算。
	for( i=0 ; i<4; i++ ) {
		for( j=0 ; j<4; j++ ) {
			for( k=0 ; k<4; k++ ) {
				matrix[i][j] += dstMat[i][k] * srcMat[k][j];
			}
		}
	}
	//	コピー
	copyMatrix(dstMat,matrix);
}

int henkan3dzahyou(double* ox,double* oy,
        double x,double y,double z,const camera_t* camera)
{
	double Mmatrix[4][4];//移動変換行列
	double Pmatrix[4][4];//射影変換行列
	double point3D[4];	//変換前座標
	double Mpoint3D[4];	//移動変換後座標
	double Ppoint3D[4];	//射影変換後座標
	int i,j;
	
	//	3D座標値を設定する。
	point3D[0] = x;
	point3D[1] = y;
	point3D[2] = z;
	point3D[3] = 1;
	
	//	カメラビュー変換。
	{
		double Umatrix[4][4];//単位行列
		double RXmatrix[4][4];//X回転行列
		double RYmatrix[4][4];//Y回転行列
		double RZmatrix[4][4];//Z回転行列
		
		//	単位マトリックス
		setMatrix( Umatrix,
					1,				0,					0,					0,
					0,				1,					0,					0,
					0,				0,					1,					0,
					0,				0,					0,					1	);
		//	X回転マトリックス
		setMatrix( RXmatrix,
					1,				0,					0,					0,
					0,				cos(camera->cx),	sin(camera->cx),	0,
					0,				-sin(camera->cx),	cos(camera->cx),	0,
					0,				0,					0,					1	);
		//	Y回転マトリックス
		setMatrix( RYmatrix,
					cos(camera->cy),0,					-sin(camera->cy),	0,
					0,				1,					0,					0,
					sin(camera->cy),0,					cos(camera->cy),	0,
					0,				0,					0,					1	);
		
		//	Z回転マトリックス
		setMatrix( RZmatrix,
					cos(camera->cz),sin(camera->cz),	0,					0,
					-sin(camera->cz),cos(camera->cz),	0,					0,
					0,				0,					1,					0,
					0,				0,					0,					1	);
		
		//	平行移動マトリックス
		setMatrix( Mmatrix,
					1,			0,			0,			0,
					0,			1,			0,			0,
					0,			0,			1,			0,
					camera->x,	camera->y,	camera->z,	1 );
		//	マトリックスの合成
		calcMatrix(Umatrix,RXmatrix);
		calcMatrix(Umatrix,RYmatrix);
		calcMatrix(Umatrix,RZmatrix);
		calcMatrix(Umatrix,Mmatrix);
		copyMatrix(Mmatrix,Umatrix);
	}
	//	行列の演算。
	calcMatrixPoint(Mmatrix,Mpoint3D,point3D);
	
	//	射影変換行列を設定する。
	{
		double depth,ctan;
		double cnear,cfar,width,height;
		
		cnear = 0.1;
		cfar = 1000.0;
		ctan = tan(camera->genkaiangle*0.5);
		width = 1.0 / ctan;
		height = 1.0 / ctan;
		depth = cfar / (cfar - cnear);
		setMatrix( Pmatrix,
						width,	0,		0,				0,
						0,		height,	0,				0,
						0,		0,		depth,			1,
						0,		0,		-depth * cnear,	0 );
	}
	//	行列の演算。
	calcMatrixPoint(Pmatrix,Ppoint3D,Mpoint3D);
	
	//	スクリーン座標変換。アスペクトは1:1
	*ox = camera->centery * Ppoint3D[0] / Ppoint3D[2] + camera->centerx;
	*oy = camera->centery * Ppoint3D[1] / Ppoint3D[2] + camera->centery;
	
    return 1;
}

int draw3dline(HDC hdc,double x1,double y1,double z1,
		double x2,double y2,double z2,const camera_t* camera,char *info) {
	double hx1,hy1,hx2,hy2;
	y1 -= 300;
	y2 -= 300;
	z1 += 200;
	z2 += 200;
	if(!henkan3dzahyou(&hx1,&hy1,x1,y1,z1,camera))return 0;
	if(!henkan3dzahyou(&hx2,&hy2,x2,y2,z2,camera))return 0;
	if(!MoveToEx(hdc,(int)hx1,(int)hy1,NULL))return 0;
	if(!LineTo(hdc,(int)hx2,(int)hy2))return 0;
	if( info != NULL ) {
		wsprintf(info,"ライン座標(%d,%d)-(%d,%d)",(int)hx1,(int)hy1,(int)hx2,(int)hy2);
	}
	return 1;
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#19

投稿記事 by みけCAT » 14年前

使ってみたのですが、いくつか気になる点があります。
・カメラの座標が他の描画の座標と逆(x,y,z全て)な気がします。
・立方体の中に入った時に目茶苦茶な線が描画されます。(添付のスクリーンショット参照)
 HSPのEasy3Dのヘルプでは
システム変数 stat が 0 の場合、位置がカメラの後ろとなるため座標変換できなかったことを表します。
 となるのですが、このエラーは起きないのですか?
 少なくともソースを見た限りでは、henkan3dzahyou関数は0を返さない(エラーを返さない)ように見えます。
少しソースを書き変えたのですが、そこがまずかったですか?
添付ファイル
3dmechakucha.jpg
スクリーンショットです。
3dmechakucha.jpg (38.49 KiB) 閲覧数: 12169 回
3dtest_2.zip
プログラムです。
(18.04 KiB) ダウンロード数: 215 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 3Dの描画

#20

投稿記事 by softya(ソフト屋) » 14年前

みけCAT さんが書きました:使ってみたのですが、いくつか気になる点があります。
・カメラの座標が他の描画の座標と逆(x,y,z全て)な気がします。
・立方体の中に入った時に目茶苦茶な線が描画されます。(添付のスクリーンショット参照)
 HSPのEasy3Dのヘルプでは
システム変数 stat が 0 の場合、位置がカメラの後ろとなるため座標変換できなかったことを表します。
 となるのですが、このエラーは起きないのですか?
 少なくともソースを見た限りでは、henkan3dzahyou関数は0を返さない(エラーを返さない)ように見えます。
少しソースを書き変えたのですが、そこがまずかったですか?
[修正]回転も直しました。
カメラが内部に入るときに戻り値処理が抜けていたので追加しました。

コード:

#include <math.h>
#include "3d.h"

#if 1
#define DEBUG
#endif

#ifdef DEBUG
#include <stdio.h>
FILE* fpdebug=NULL;
void _debuginit(void) {
	fpdebug=fopen("debug.txt","a");
}

void _debugend(void) {
	fclose(fpdebug);
	fpdebug=NULL;
}

void _printstr(const char* str) {
	if(fpdebug==NULL)return;
	fprintf(fpdebug,"%s\n",str);
}

void _printbekutoru(const char* exp,double x,double y,double z) {
	if(fpdebug==NULL)return;
	fprintf(fpdebug,"%s=(%f,%f,%f)\n",exp,x,y,z);
}

void _printnum(const char* exp,double num) {
	if(fpdebug==NULL)return;
	fprintf(fpdebug,"%s=%f\n",exp,num);
}
#define debuginit _debuginit()
#define debugend _debugend()
#define printstr(s) _printstr(s)
#define printbekutoru(e,x,y,z) _printbekutoru(e,x,y,z)
#define printnum(e,n) _printnum(e,n)
#else
#define debuginit
#define debugend
#define printstr(s)
#define printbekutoru(e,x,y,z)
#define printnum(e,n)
#endif

//	マトリクスの設定
void setMatrix( double matrix[][4],
				double mat00,	double mat01,	double mat02,	double mat03,
				double mat10,	double mat11,	double mat12,	double mat13,
				double mat20,	double mat21,	double mat22,	double mat23,
				double mat30,	double mat31,	double mat32,	double mat33 )
{
	matrix[0][0]=mat00;	matrix[0][1]=mat01;	matrix[0][2]=mat02;	matrix[0][3]=mat03;
	matrix[1][0]=mat10;	matrix[1][1]=mat11;	matrix[1][2]=mat12;	matrix[1][3]=mat13;
	matrix[2][0]=mat20;	matrix[2][1]=mat21;	matrix[2][2]=mat22;	matrix[2][3]=mat23;
	matrix[3][0]=mat30;	matrix[3][1]=mat31;	matrix[3][2]=mat32;	matrix[3][3]=mat33;
}

//	マトリックス・ポイント計算
void calcMatrixPoint( double matrix[][4],double out[],double in[])
{
	int  i,j;
	//	行列の演算。
	for( i=0 ; i<4; i++ ) {
		out[i] = 0;
		for( j=0 ; j<4; j++ ) {
			out[i] += in[j] * matrix[j][i];
		}
	}
}

//	コピーマトリックス
void copyMatrix( double dstMat[][4],double srcMat[][4])
{
	int  i,j;
	//	コピー
	for( i=0 ; i<4; i++ ) {
		for( j=0 ; j<4; j++ ) {
			dstMat[i][j] = srcMat[i][j];
		}
	}
}

//	マトリックス計算
void calcMatrix( double dstMat[][4],double srcMat[][4])
{
	int  i,j,k;
	double matrix[4][4];
	
	//	クリア
	for( i=0 ; i<4; i++ ) {
		for( j=0 ; j<4; j++ ) {
			matrix[i][j] = 0;
		}
	}
	//	行列の演算。
	for( i=0 ; i<4; i++ ) {
		for( j=0 ; j<4; j++ ) {
			for( k=0 ; k<4; k++ ) {
				matrix[i][j] += dstMat[i][k] * srcMat[k][j];
			}
		}
	}
	//	コピー
	copyMatrix(dstMat,matrix);
}

int henkan3dzahyou(double* ox,double* oy,
        double x,double y,double z,const camera_t* camera)
{
	double Mmatrix[4][4];//移動変換行列
	double Pmatrix[4][4];//射影変換行列
	double point3D[4];	//変換前座標
	double Mpoint3D[4];	//移動変換後座標
	double Ppoint3D[4];	//射影変換後座標
	int i,j;
	
	//	3D座標値を設定する。
	point3D[0] = x;
	point3D[1] = y;
	point3D[2] = z;
	point3D[3] = 1;
	
	//	カメラビュー変換。
	{
		double RXmatrix[4][4];//X回転行列
		double RYmatrix[4][4];//Y回転行列
		double RZmatrix[4][4];//Z回転行列
		double MVmatrix[4][4];//平行移動行列
		double rot;
		
		//	単位マトリックスを設定
		setMatrix( Mmatrix,
					1,			0,			0,			0,
					0,			1,			0,			0,
					0,			0,			1,			0,
					0,			0,			0,			1	);
		//	X回転マトリックス
		rot = -camera->cx;
		setMatrix( RXmatrix,
					1,			0,			0,			0,
					0,			cos(rot),	sin(rot),	0,
					0,			-sin(rot),	cos(rot),	0,
					0,			0,			0,			1	);
		//	Y回転マトリックス
		rot = -camera->cy;
		setMatrix( RYmatrix,
					cos(rot),	0,			-sin(rot),	0,
					0,			1,			0,			0,
					sin(rot),	0,			cos(rot),	0,
					0,			0,			0,			1	);
		
		//	Z回転マトリックス
		rot = -camera->cz;
		setMatrix( RZmatrix,
					cos(rot),	sin(rot),	0,			0,
					-sin(rot),	cos(rot),	0,			0,
					0,			0,			1,			0,
					0,			0,			0,			1	);
		
		//	平行移動マトリックス
		setMatrix( MVmatrix,
					1,			0,			0,			0,
					0,			1,			0,			0,
					0,			0,			1,			0,
					-camera->x,	camera->y,	-camera->z,	1 );
		//	マトリックスの合成
		calcMatrix(Mmatrix,RXmatrix);
		calcMatrix(Mmatrix,RYmatrix);
		calcMatrix(Mmatrix,RZmatrix);
		calcMatrix(Mmatrix,MVmatrix);
	}
	//	行列の演算。
	calcMatrixPoint(Mmatrix,Mpoint3D,point3D);
	
	//	射影変換行列を設定する。
	{
		double depth,ctan;
		double cnear,cfar,width,height;
		
		cnear = 0.1;
		cfar = 1000.0;
		ctan = tan(camera->genkaiangle*0.5);
		width = 1.0 / ctan;
		height = 1.0 / ctan;
		depth = cfar / (cfar - cnear);
		setMatrix( Pmatrix,
						width,	0,		0,				0,
						0,		height,	0,				0,
						0,		0,		depth,			1,
						0,		0,		-depth * cnear,	0 );
	}
	//	行列の演算。
	calcMatrixPoint(Pmatrix,Ppoint3D,Mpoint3D);
	
	//	投影できないかチェック
	if( Ppoint3D[2] < 0 ) {
		return 0;
	}
	
	//	スクリーン座標変換。アスペクトは1:1
	*ox = camera->centery * Ppoint3D[0] / Ppoint3D[2] + camera->centerx;
	*oy = camera->centery * Ppoint3D[1] / Ppoint3D[2] + camera->centery;
	
    return 1;
}

int draw3dline(HDC hdc,double x1,double y1,double z1,
		double x2,double y2,double z2,const camera_t* camera,char *info) {
	double hx1,hy1,hx2,hy2;
	y1 -= 300;
	y2 -= 300;
	z1 += 200;
	z2 += 200;
	if(!henkan3dzahyou(&hx1,&hy1,x1,y1,z1,camera))return 0;
	if(!henkan3dzahyou(&hx2,&hy2,x2,y2,z2,camera))return 0;
	if(!MoveToEx(hdc,(int)hx1,(int)hy1,NULL))return 0;
	if(!LineTo(hdc,(int)hx2,(int)hy2))return 0;
	if( info != NULL ) {
		wsprintf(info,"ライン座標(%d,%d)-(%d,%d)",(int)hx1,(int)hy1,(int)hx2,(int)hy2);
	}
	return 1;
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#21

投稿記事 by みけCAT » 14年前

とりあえず変な線が出る問題は直りました。
それからもう一点、現在のプログラムでは、カメラを回転させたときに、
カメラが首を振るというよりもむしろ(0,0,0)を中心として描画する位置が回転するようになっているように思われます。
よろしくお願いします。
[hr]
添付したサンプルについて
従来のサンプルに比べ、立方体に色がついた点が変わっています。
座標軸も表示しています。
また、3Dグラフの表示のサンプルに切り替えることもできます。
キーボードの2キー(テンキーではない)を押してください。
1を押すと直方体の表示に戻ります。
[hr]
自分のデバッグ用のコードは使われていないようなので、はずしていただけませんか?
描画コードの方を修正したので、draw3dline内での補正は不要です。
添付ファイル
3dtest_2(2).zip
プログラムです。
(20.49 KiB) ダウンロード数: 196 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#22

投稿記事 by みけCAT » 14年前

とりあえず対症療法的に書き換えてみたのですが、あっているでしょうか?
添付ファイル
3dtest_2(3).zip
プログラムです。
(20.56 KiB) ダウンロード数: 202 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#23

投稿記事 by みけCAT » 14年前

softya(ソフト屋) さんが書きました:[修正]回転も直しました。
x方向とz方向のカメラの移動は直っていますが、y方向は直っていないように思います。
肝心の回転も直っていないように思います。
描画されている(0,0,0)の位置が回転しても変わりません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 3Dの描画

#24

投稿記事 by softya(ソフト屋) » 14年前

みけCAT さんが書きました:とりあえず変な線が出る問題は直りました。
それからもう一点、現在のプログラムでは、カメラを回転させたときに、
カメラが首を振るというよりもむしろ(0,0,0)を中心として描画する位置が回転するようになっているように思われます。
よろしくお願いします。
[hr]
添付したサンプルについて
従来のサンプルに比べ、立方体に色がついた点が変わっています。
座標軸も表示しています。
また、3Dグラフの表示のサンプルに切り替えることもできます。
キーボードの2キー(テンキーではない)を押してください。
1を押すと直方体の表示に戻ります。
[hr]
自分のデバッグ用のコードは使われていないようなので、はずしていただけませんか?
新しいコードを元に直しました。
たしかに立方体のローカル系で回転してましたので修正しました(行列のかけ合わせの順番の問題でした)

コード:

#include <math.h>
#include "3d.h"

//  マトリクスの設定
static void setMatrix( double matrix[][4],
				double mat00,   double mat01,   double mat02,   double mat03,
				double mat10,   double mat11,   double mat12,   double mat13,
				double mat20,   double mat21,   double mat22,   double mat23,
				double mat30,   double mat31,   double mat32,   double mat33 )
{
	matrix[0][0]=mat00; matrix[0][1]=mat01; matrix[0][2]=mat02; matrix[0][3]=mat03;
	matrix[1][0]=mat10; matrix[1][1]=mat11; matrix[1][2]=mat12; matrix[1][3]=mat13;
	matrix[2][0]=mat20; matrix[2][1]=mat21; matrix[2][2]=mat22; matrix[2][3]=mat23;
	matrix[3][0]=mat30; matrix[3][1]=mat31; matrix[3][2]=mat32; matrix[3][3]=mat33;
}
 
//  マトリックス・ポイント計算
static void calcMatrixPoint( double matrix[][4],double out[],double in[])
{
	int  i,j;
	//  行列の演算。
	for( i=0 ; i<4; i++ ) {
		out[i] = 0;
		for( j=0 ; j<4; j++ ) {
			out[i] += in[j] * matrix[j][i];
		}
	}
}
 
//  コピーマトリックス
static void copyMatrix( double dstMat[][4],double srcMat[][4])
{
	int  i,j;
	//  コピー
	for( i=0 ; i<4; i++ ) {
		for( j=0 ; j<4; j++ ) {
			dstMat[i][j] = srcMat[i][j];
		}
	}
}
 
//  マトリックス計算
static void calcMatrix( double dstMat[][4],double srcMat[][4])
{
	int  i,j,k;
	double matrix[4][4];
	
	//  クリア
	for( i=0 ; i<4; i++ ) {
		for( j=0 ; j<4; j++ ) {
			matrix[i][j] = 0;
		}
	}
	//  行列の演算。
	for( i=0 ; i<4; i++ ) {
		for( j=0 ; j<4; j++ ) {
			for( k=0 ; k<4; k++ ) {
				matrix[i][j] += dstMat[i][k] * srcMat[k][j];
			}
		}
	}
	//  コピー
	copyMatrix(dstMat,matrix);
}
 
int henkan3dzahyou(double* ox,double* oy,
		double x,double y,double z,const camera_t* camera)
{
	double Mmatrix[4][4];//移動変換行列
	double Pmatrix[4][4];//射影変換行列
	double point3D[4];  //変換前座標
	double Mpoint3D[4]; //移動変換後座標
	double Ppoint3D[4]; //射影変換後座標
	int i,j;
	
	//  3D座標値を設定する。
	point3D[0] = x;
	point3D[1] = y;
	point3D[2] = z;
	point3D[3] = 1;
	
	//  カメラビュー変換。
	{
		double RXmatrix[4][4];//X回転行列
		double RYmatrix[4][4];//Y回転行列
		double RZmatrix[4][4];//Z回転行列
		double MVmatrix[4][4];//平行移動行列
		double rot;
		
		//	単位マトリックスを設定
		setMatrix( Mmatrix,
					1,			0,			0,			0,
					0,			1,			0,			0,
					0,			0,			1,			0,
					0,			0,			0,			1	);
		//	X回転マトリックス
		rot = -camera->cx;
		setMatrix( RXmatrix,
					1,			0,			0,			0,
					0,			cos(rot),	sin(rot),	0,
					0,			-sin(rot),	cos(rot),	0,
					0,			0,			0,			1	);
		//	Y回転マトリックス
		rot = -camera->cy;
		setMatrix( RYmatrix,
					cos(rot),	0,			-sin(rot),	0,
					0,			1,			0,			0,
					sin(rot),	0,			cos(rot),	0,
					0,			0,			0,			1	);
		
		//	Z回転マトリックス
		rot = -camera->cz;
		setMatrix( RZmatrix,
					cos(rot),	sin(rot),	0,			0,
					-sin(rot),	cos(rot),	0,			0,
					0,			0,			1,			0,
					0,			0,			0,			1	);
		
		//	平行移動マトリックス
		setMatrix( MVmatrix,
					1,			0,			0,			0,
					0,			1,			0,			0,
					0,			0,			1,			0,
					-camera->x,	-camera->y,	-camera->z,	1 );
		//	マトリックスの合成
		calcMatrix(Mmatrix,MVmatrix);
		calcMatrix(Mmatrix,RXmatrix);
		calcMatrix(Mmatrix,RYmatrix);
		calcMatrix(Mmatrix,RZmatrix);
	}
	//  行列の演算。
	calcMatrixPoint(Mmatrix,Mpoint3D,point3D);
	
	//  射影変換行列を設定する。
	{
		double depth,ctan;
		double cnear,cfar,width,height;
		
		cnear = 0.1;
		cfar = 1000.0;
		ctan = tan(camera->genkaiangle*0.5);
		width = 1.0 / ctan;
		height = 1.0 / ctan;
		depth = cfar / (cfar - cnear);
		setMatrix( Pmatrix,
						width,  0,	  0,			  0,
						0,	  height, 0,			  0,
						0,	  0,	  depth,		  1,
						0,	  0,	  -depth * cnear, 0 );
	}
	//  行列の演算。
	calcMatrixPoint(Pmatrix,Ppoint3D,Mpoint3D);
	
	//  投影できないかチェック
    if( Ppoint3D[2] < 0 ) {
        return 0;
    }
	
	//  スクリーン座標変換。アスペクトは1:1
	*ox = camera->centery * Ppoint3D[0] / Ppoint3D[2] + camera->centerx;
	*oy = camera->centery * Ppoint3D[1] / Ppoint3D[2] + camera->centery;
	
	return 1;
}

#ifdef ENABLE_INFO
int draw3dline(HDC hdc,double sx,double sy,double sz,
		double dx,double dy,double dz,const camera_t* camera,char *info) {
#else
int draw3dline(HDC hdc,double sx,double sy,double sz,
		double dx,double dy,double dz,const camera_t* camera) {
#endif
	double hx1,hy1,hx2,hy2;
	if(!henkan3dzahyou(&hx1,&hy1,sx,sy,sz,camera))return 0;
	if(!henkan3dzahyou(&hx2,&hy2,dx,dy,dz,camera))return 0;
	if(!MoveToEx(hdc,(int)hx1,(int)hy1,NULL))return 0;
	if(!LineTo(hdc,(int)hx2,(int)hy2))return 0;
#ifdef ENABLE_INFO
	if( info != NULL ) {
		wsprintf(info,"ライン座標(%d,%d)-(%d,%d)",(int)hx1,(int)hy1,(int)hx2,(int)hy2);
	}
#endif
	return 1;
}

int draw3dtext(HDC hdc,double x,double y,double z,
		const char* text,const camera_t* camera) {
	double hx,hy;
	if(!henkan3dzahyou(&hx,&hy,x,y,z,camera))return 0;
	if(!TextOut(hdc,(int)hx,(int)hy,text,lstrlen(text)))return 0;
	return 1;
}


by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#25

投稿記事 by みけCAT » 14年前

うまく動きました。ありがとうございます。

ところで、このプログラムを自分のソフトに組み込む(ソース添付あり/なし)ときは、
ライセンス表記などは必要でしょうか?
必要なら、どのようにすればいいでしょうか?
[hr]
3Dグラフの種類が増えました。
1~4番まで使えます。
5~9と0番は何も描画されません。
添付ファイル
3dtest_2(4).zip
プログラムです。
(20.99 KiB) ダウンロード数: 210 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 3Dの描画

#26

投稿記事 by softya(ソフト屋) » 14年前

別に表記してもらう必要はありませんよ。自由にお使いください。
ただ、線分クリッピングとかしていないので、色々やると支障が出るかも知れません。

行列は、まだ習われていないかも知れませんが、この機会に勉強されてはどうでしょか?
とりあえず使い方だけってのもありです。

参考。
「高校数学の基本問題」
http://www.geisya.or.jp/~mwm48961/koukou/index_m.htm

「3D座標変換 - ゲームプログラミングWiki」
http://www.c3.club.kyutech.ac.jp/gamewi ... A%D1%B4%B9
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#27

投稿記事 by みけCAT » 14年前

ありがとうございます。
解決にさせていただきます。
[hr]
「サンプルを共有するコミュニティ」http://dixq.net/forum/viewforum.php?f=83
の方に転載させていただいてもいいですか?
もしくは自分で投稿していただけるとありがたいですが。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 3Dの描画

#28

投稿記事 by softya(ソフト屋) » 14年前

みけCAT さんが書きました:ありがとうございます。
解決にさせていただきます。
[hr]
「サンプルを共有するコミュニティ」http://dixq.net/forum/viewforum.php?f=83
の方に転載させていただいてもいいですか?
もしくは自分で投稿していただけるとありがたいですが。
転記の方はお願いしてよろしいでしょうか。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 3Dの描画

#29

投稿記事 by みけCAT » 14年前

書き込ませていただきました。
ありがとうございます。
http://dixq.net/forum/viewtopic.php?f=83&t=7643
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

閉鎖

“C言語何でも質問掲示板” へ戻る