みけCATのにっき(仮)
つれづれなるまゝに、日くらし、PCにむかひて、心に移りゆくよしなし事を、そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。
(本当か!?)
出典

D.X.ライブラリは反逆なのか?

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

D.X.ライブラリは反逆なのか?

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

ベクトルの外積。それは、電磁気学で3Dでカメラを指定した方向に向けるときに使われる重要な計算。
その性質として、
c=a×b、d=b×a とするとき、以下の性質がある。

 1.c・a=0、c・b=0
 2.c=-d
 3.cの向きは、aをbに向けて、180°より小さい方の角の方向に回転させたとき、
   右ネジの進む方向に向く。
   aとbの角が0°または180°のときは、c=0となるので、向きは考慮外である。
 4.|c| は、aとbとで作られる平行四辺形の面積に等しい。
http://yosshy.sansu.org/gaiseki.htm
というのがある。
今回、AxBの向きはAをBの方向に回転させたとき、右ねじの進む向きという性質に注目した。
右ねじの進む向きといえば、物理の電気でおなじみ、右ねじの法則ですね。
右ねじの進む向きは、右手の指を曲げたとき、親指以外の指の向いている方向に回すと親指の方向に進む、ですね。
miginezi.jpg
右ねじの法則
miginezi.jpg (27.73 KiB) 閲覧数: 461 回
softyaさんに作っていただいたライブラリをもとにしたライブラリでは、きちんとこの性質が成り立っています。
描画部のコードは

CODE:

void vectorGaiseki(double* x,double* y,double* z,
		double xa,double ya,double za,
		double xb,double yb,double zb) {
	*x=ya*zb-yb*za;
	*y=za*xb-zb*xa;
	*z=xa*yb-xb*ya;
}

void doPaint(HDC hDC) {
	camera_t camera;
	char textbuf[1024];
	unsigned int oldColor;
	double x[4],y[4],z[4];
	double dx[4],dy[4],dz[4];
	HPEN hOldPen,hVec1Pen,hVec2Pen,hVec3Pen;
	hVec1Pen=CreatePen(PS_SOLID,1,RGB(255,0,0));
	hVec2Pen=CreatePen(PS_SOLID,1,RGB(0,255,0));
	hVec3Pen=CreatePen(PS_SOLID,1,RGB(0,0,255));
	camera.x=5;
	camera.y=5;
	camera.z=-50;
	camera.cx=camera.cy=camera.cz=0;
	camera.genkai=320;
	camera.genkaiangle=dec2rad(50);
	camera.centerx=320;
	camera.centery=240;
#if 1
	updateCameraLookAt(&camera,0,0,0,0,1,0);
#else
	updateCamera(&camera);
#endif
	x[0]=y[0]=z[0]=0;
	x[1]=10;y[1]=0;z[1]=0;
	x[2]=0;y[2]=10;z[2]=0;
	vectorGaiseki(&x[3],&y[3],&z[3],x[1],y[1],z[1],x[2],y[2],z[2]);
	henkan3dzahyou(&dx[0],&dy[0],&dz[0],x[0],y[0],z[0],&camera);
	henkan3dzahyou(&dx[1],&dy[1],&dz[1],x[1],y[1],z[1],&camera);
	henkan3dzahyou(&dx[2],&dy[2],&dz[2],x[2],y[2],z[2],&camera);
	henkan3dzahyou(&dx[3],&dy[3],&dz[3],x[3],y[3],z[3],&camera);
	hOldPen=SelectObject(hDC,hVec1Pen);
	MoveToEx(hDC,(int)dx[0],(int)dy[0],NULL);
	LineTo(hDC,(int)dx[1],(int)dy[1]);
	SelectObject(hDC,hVec2Pen);
	MoveToEx(hDC,(int)dx[0],(int)dy[0],NULL);
	LineTo(hDC,(int)dx[2],(int)dy[2]);
	SelectObject(hDC,hVec3Pen);
	MoveToEx(hDC,(int)dx[0],(int)dy[0],NULL);
	LineTo(hDC,(int)dx[3],(int)dy[3]);
	SelectObject(hDC,hOldPen);
	DeleteObject(hVec1Pen);
	DeleteObject(hVec2Pen);
	DeleteObject(hVec3Pen);
	oldColor=SetTextColor(hDC,RGB(255,0,0));
	wsprintf(textbuf,"A=(%d,%d,%d)",(int)x[1],(int)y[1],(int)z[1]);
	TextOut(hDC,10,10,textbuf,lstrlen(textbuf));
	SetTextColor(hDC,RGB(0,255,0));
	wsprintf(textbuf,"B=(%d,%d,%d)",(int)x[2],(int)y[2],(int)z[2]);
	TextOut(hDC,10,40,textbuf,lstrlen(textbuf));
	SetTextColor(hDC,RGB(0,0,255));
	wsprintf(textbuf,"AxB=(%d,%d,%d)",(int)x[3],(int)y[3],(int)z[3]);
	TextOut(hDC,10,70,textbuf,lstrlen(textbuf));
	SetTextColor(hDC,oldColor);
}
実行すると
gaiseki_softya.png
softyaさん由来のライブラリ上での外積
gaiseki_softya.png (44.67 KiB) 閲覧数: 475 回
しかし・・・
DXライブラリ上では、この性質が成り立たない
これが実験コードです。

CODE:

#include "DxLib.h"

void vectorGaiseki(float* x,float* y,float* z,
		float xa,float ya,float za,
		float xb,float yb,float zb) {
	*x=ya*zb-yb*za;
	*y=za*xb-zb*xa;
	*z=xa*yb-xb*ya;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
	if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //初期化処理

	VECTOR vec[4];

	vec[0].x=vec[0].y=vec[0].z=0;
	vec[1].x=10;vec[1].y=0;vec[1].z=0;
	vec[2].x=0;vec[2].y=10;vec[2].z=0;
	vectorGaiseki(&vec[3].x,&vec[3].y,&vec[3].z,
		vec[1].x,vec[1].y,vec[1].z,vec[2].x,vec[2].y,vec[2].z);
	
	SetCameraPositionAndTarget_UpVecY(VGet(5,5,-50),VGet(0,0,0));
	DrawLine3D(vec[0],vec[1],GetColor(255,0,0));
	DrawLine3D(vec[0],vec[2],GetColor(0,255,0));
	DrawLine3D(vec[0],vec[3],GetColor(0,0,255));
	DrawFormatString(10,10,GetColor(255,0,0),
		"A=(%.0f,%.0f,%.0f)",vec[1].x,vec[1].y,vec[1].z);
	DrawFormatString(10,40,GetColor(0,255,0),
		"B=(%.0f,%.0f,%.0f)",vec[2].x,vec[2].y,vec[2].z);
	DrawFormatString(10,70,GetColor(0,0,255),
		"AxB=(%.0f,%.0f,%.0f)",vec[3].x,vec[3].y,vec[3].z);

	WaitKey();
	
	DxLib_End();
	return 0;
}
実行すると
gaiseki_dxlib.png
DXライブラリでの外積
gaiseki_dxlib.png (42.9 KiB) 閲覧数: 472 回
このように、DXライブラリではy軸の向きが逆転する影響で、外積の向きも逆になってしまいました。

( ˘⊖˘)。o(待てよ、たしかDXライブラリには独自の外積を求める関数があったよな)
|Dev-C++| ┗(☋` )┓三

CODE:

#include "DxLib.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
	if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //初期化処理

	VECTOR vec[4];

	vec[0].x=vec[0].y=vec[0].z=0;
	vec[1].x=10;vec[1].y=0;vec[1].z=0;
	vec[2].x=0;vec[2].y=10;vec[2].z=0;
	vec[3]=VCross(vec[1],vec[2]);
	
	SetCameraPositionAndTarget_UpVecY(VGet(5,5,-50),VGet(0,0,0));
	DrawLine3D(vec[0],vec[1],GetColor(255,0,0));
	DrawLine3D(vec[0],vec[2],GetColor(0,255,0));
	DrawLine3D(vec[0],vec[3],GetColor(0,0,255));
	DrawFormatString(10,10,GetColor(255,0,0),
		"A=(%.0f,%.0f,%.0f)",vec[1].x,vec[1].y,vec[1].z);
	DrawFormatString(10,40,GetColor(0,255,0),
		"B=(%.0f,%.0f,%.0f)",vec[2].x,vec[2].y,vec[2].z);
	DrawFormatString(10,70,GetColor(0,0,255),
		"AxB=(%.0f,%.0f,%.0f)",vec[3].x,vec[3].y,vec[3].z);

	WaitKey();
	
	DxLib_End();
	return 0;
}
( ◠‿◠ )☛残念、表示は全く変わらないぞ
▂▅▇█▓▒░('ω')░▒▓█▇▅▂うわあああああああああああ

結論
DXライブラリは数学への反逆をした!処刑だ!!
な~んてね。(CV:大亀あすか)

アバター
tana
記事: 33
登録日時: 13年前

Re: D.X.ライブラリは反逆なのか?

投稿記事 by tana » 11年前

う~ん……
右手座標か左手座標かの違い?

アバター
GRAM
記事: 164
登録日時: 13年前

Re: D.X.ライブラリは反逆なのか?

投稿記事 by GRAM » 11年前

外積ってのは電磁気学に限らずありとあらゆる科学に用いられる計算なので、
これが逆ってのはぶっちゃけヒドイなって僕は思います。
(そうでないという思う方もいるでしょうが)
まぁとはいえ、別に描画に限った話なので、最後の変換行列の符号を一か所入れ替えるだけなわけですが。
左家座標系で考えると少なくとも物理学の公式がそのまま使えない点は、非常にデメリットだと思います。
というのも外積に限らず、掛け算の交換法則が成り立たない類のものはおよそ逆になります。
だからこそ右手座標系のOpenGLのほうが使いやすいわけですが。

>>tanaさん
そうですが、ゲーム以外では(数値計算の結果の表示等では)非常に面倒な問題を起こします。(参考書の計算式がそのまま当てはまらないから)

ISLe
記事: 2650
登録日時: 13年前

Re: D.X.ライブラリは反逆なのか?

投稿記事 by ISLe » 11年前

DXライブラリというかDirect3Dの仕様ですね。
そんなこと言ったら、なんで画面のY座標は上端が0で下に向かってプラスなんだよ、って話にもなりませんかね。

数学的な使い方をするならOpenGLのほうが良いですよ。

アバター
GRAM
記事: 164
登録日時: 13年前

Re: D.X.ライブラリは反逆なのか?

投稿記事 by GRAM » 11年前

ISLe さんが書きました: そんなこと言ったら、なんで画面のY座標は上端が0で下に向かってプラスなんだよ、って話にもなりませんかね。
それについて付け加えるなら、「ならない」です。
2Dについて言えば、べつに物理法則は崩壊しないので大丈夫です。
要はyの正の方向が下だとして座標系を書き換えても式自体の変更はいりません。
当然のことながら物理定数の書き換えは座標系の変換によっておこりますが。

一方右手系と左手系の場合の話は座標系の解釈を変更すると、あらゆる既存の計算式の書き換えが必要なので厄介です。
簡単な例でいえば、右手系で 磁界がy正の方向、電流がz負の方向に流れていたとします。
その場合力の方向はx正の方向です。
これはI x B = Fに一致します。
外見上同じものを左手系で表したとします。
磁界がy正の方向、電流がz正の方向に流れています。(zの向きが逆なので)
その場合でも力の方向は当然x正の方向です。
一方で電流と磁界の外積をとると
I x B = Fはx負の方向です。これは現実の物理現象と明らかに異なるので、B x I と式そのものを変換する必要があります。

まぁDirectXを大学で使ってるのは見たことがないですが…(そもそもそういう用途ではないし)
ゲームなどではどっちかっていうと、奥行きが正になるということが重要視されているのですかね?
まぁそれはそれでありだとも思いますが。
最後に編集したユーザー GRAM on 2012年11月09日(金) 00:38 [ 編集 2 回目 ]