DxLibの3Dのコリジョン判定関数についての質問です

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
sadora3
記事: 175
登録日時: 11年前

DxLibの3Dのコリジョン判定関数についての質問です

#1

投稿記事 by sadora3 » 8年前

3Dゲームの当たり判定の話なのですが、「ステージモデルの壁」は「ポリゴンの法線のY成分が0に限りなく近いかどうか」で判断するのですよね。そこで法線ってどんな線なんだろうと思って、以下のようなプログラムを組んでみたのですが、真ん中の球としか法線が引かれないのですが、なぜでしょう?立方体のほうは反応無しです。
説明が下手ですみません。このままだと球としか壁判定が取れないような気がして・・・。

OS:Window7
コンパイラ:Microsoft Visual Studio 2010
ライブラリ:Dxライブラリ
言語:C

コード:

#include "DxLib.h"

#define rad(angle) (angle * DX_PI_F / 180.0f)
#define ROTATE_SPEED rad(2.0f)
#define ZOOM_RATE (9.0f)
#define TargetPos VGet(0.0f, 10.0f, 0.0f)

int ModelHandle;
int Add, y;
VECTOR SpherePos;
MV1_COLL_RESULT_POLY_DIM HitPolyDim;

struct CameraStatus{
	VECTOR Pos;
	float RotV, RotH;
	float Zoom;
} Camera = {VGet(0.0f, 0.0f, 0.0f), rad(-20.0f), 0.0f, 200.0f};

void F();
void RotateCamera();

int ProcessLoop(){
	if(ProcessMessage() != 0){	return -1;	}
	if(ClearDrawScreen() != 0){	return -1;	}
	return 0;
}

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(TRUE);
	SetBackgroundColor(255,255,255);
	if(DxLib_Init() == -1 || SetDrawScreen(DX_SCREEN_BACK) != 0){	return -1;	}

	ModelHandle = MV1LoadModel("SimpleModel.mqo");
	MV1SetPosition(ModelHandle, VGet(0.0f, 0.0f, 0.0f));
	MV1SetupCollInfo(ModelHandle, -1);
	Add = 1;
	y = 0;

	while(ProcessLoop() == 0 && !CheckHitKey(KEY_INPUT_ESCAPE)){
		F();
		RotateCamera();
		DrawFormatString(0, 420, GetColor(0,0,0), "ESCキーで終了");
		DrawFormatString(0, 440, GetColor(0,0,0), "カーソルキーで旋回");
		DrawFormatString(0, 460, GetColor(0,0,0), "Q,Eキーでズームイン・アウト");
		ScreenFlip();
	}

	DxLib_End();
	return 0;
}

void F(){
	y += Add;
	if(y < -300 || y > 300){	Add = -Add;	}

	MV1DrawModel(ModelHandle);
	SpherePos = VGet(-100.0f, (float)y, 0.0f);
	HitPolyDim = MV1CollCheck_Sphere(ModelHandle, -1, SpherePos, 100.0f);
	DrawSphere3D(SpherePos, 100.0f, 8, GetColor(255,255,0), GetColor(255,255,255), FALSE);

	if(HitPolyDim.HitNum >= 1){
		DrawFormatString(0, 0, GetColor(0,0,0), "Hit Poly Num   %d", HitPolyDim.HitNum);

		for(int i = 0; i < HitPolyDim.HitNum; i++){
			DrawTriangle3D(HitPolyDim.Dim[i].Position[0], HitPolyDim.Dim[i].Position[1], HitPolyDim.Dim[i].Position[2], GetColor(0,255,255), FALSE);
			DrawLine3D(SpherePos, HitPolyDim.Dim[i].Normal, GetColor(255,0,255));
		}
	}

	MV1CollResultPolyDimTerminate(HitPolyDim);
}

void RotateCamera(){
	if(CheckHitKey(KEY_INPUT_RIGHT)){
		Camera.RotH += ROTATE_SPEED;
	}
	else if(CheckHitKey(KEY_INPUT_LEFT)){
		Camera.RotH -= ROTATE_SPEED;
	}
	if(CheckHitKey(KEY_INPUT_DOWN) && Camera.RotV > rad(-45.0f)){
		Camera.RotV -= ROTATE_SPEED;
	}
	else if(CheckHitKey(KEY_INPUT_UP) && Camera.RotV < rad(0.0f)){
		Camera.RotV += ROTATE_SPEED;
	}

	if(CheckHitKey(KEY_INPUT_Q) && Camera.Zoom < 851.0f){
		Camera.Zoom += ZOOM_RATE;
	}
	else if(CheckHitKey(KEY_INPUT_E) && Camera.Zoom > 0.0f){
		Camera.Zoom -= ZOOM_RATE;
	}

	Camera.Pos = VAdd(VScale(VTransform(VGet(0.0f, 0.0f, 1.0f), MMult(MGetRotX(Camera.RotV), MGetRotY(Camera.RotH))), Camera.Zoom), TargetPos);

	if(Camera.RotH > rad(360)){
		Camera.RotH -= rad(360);
	}
	else if(Camera.RotH < 0.0f){
		Camera.RotH += rad(360);
	}

	SetCameraPositionAndTarget_UpVecY(Camera.Pos, TargetPos);
}
添付ファイル
SimpleModel.zip
(8.61 KiB) ダウンロード数: 232 回

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: DxLibの3Dのコリジョン判定関数についての質問です

#2

投稿記事 by h2so5 » 8年前

sadora3 さんが書きました:3Dゲームの当たり判定の話なのですが、「ステージモデルの壁」は「ポリゴンの法線のY成分が0に限りなく近いかどうか」で判断するのですよね。
この意味がよくわかりません。どこに書いてあるのでしょうか。

hide

Re: DxLibの3Dのコリジョン判定関数についての質問です

#3

投稿記事 by hide » 8年前

何がしたいのかが伝わってこないのでちょっと回答しづらいと思います。
コリジョン判定について知りたいのか、
法線について知りたいのか、
法線がどんな線なのか表示させたいのか、
sadora3さんがどこまでわかっているのか、
何がしたくてこの状態のプログラムになっているのかもう少し書いたほうがいいですね。

>>h2so5さん
http://homepage2.nifty.com/natupaji/DxL ... am_3D.html
たぶん本家のサンプルのやり方に準じているのだと思いますよ。

sadora3
記事: 175
登録日時: 11年前

Re: DxLibの3Dのコリジョン判定関数についての質問です

#4

投稿記事 by sadora3 » 8年前

>>h2so5さん
hideさんの仰るとおりのサンプルプログラムのコメントに、書いてありました。
抜粋すると、
「XZ平面に垂直かどうかはポリゴンの法線のY成分が0に限りなく近いかどうかで判断する」
と書いてありました。

>>hideさん
知りたいのは、法線がどんな線なのかの表示です。
私がどこまでわかっているのかは、3Dは始めたばかりでわからないことだらけです。カメラの旋回やモデルのアニメーションなど簡単なことしか出来ません。
何がしたくてこの状態のプログラムになっているかは、法線の表示をしたかったのですが、なんかおかしな挙動になってしまいました・・・。

ISLe()

Re: DxLibの3Dのコリジョン判定関数についての質問です

#5

投稿記事 by ISLe() » 8年前

法線というのは、垂直に交わるベクトル(成分)、のことです。

垂直に立ったポリゴン(壁)に対して垂直に交わるベクトルは、地面に対して平行になるので、「Y成分が限りなく0に近いかどうか」で判定できる根拠になるわけですね。

余談ですが、壁と坂を区別しないほうがプログラムはシンプルになります。
そのサンプルプログラムのやり方が一般的な方法とは思わないでください。

法線の垂直成分を摩擦に変換して考えれば、角度のある坂は滑り落ちるのも速く、垂直な壁はそのまま単純に落下するだけになります。
ついでに書いておくと、法線の水平成分は反発(反射)に変換。

sadora3
記事: 175
登録日時: 11年前

Re: DxLibの3Dのコリジョン判定関数についての質問です

#6

投稿記事 by sadora3 » 8年前

>>ISLe()さん
なるほどです。ところでHitPolyDim.Dim.Normalは何に対して垂直なのでしょうか?また座標はどこになるんでしょうか?私の書いたプログラムだとHitPolyDim.Dim.Normalの座標は全て(x,y,z)=(0,0,0)になってしまうのですが。
あと「法線の垂直成分を摩擦に変換」というのを詳しく教えてくれませんか!とても興味を持ちました!

ISLe()

Re: DxLibの3Dのコリジョン判定関数についての質問です

#7

投稿記事 by ISLe() » 8年前

法線を表すベクトルは成分なので、座標はありません。
ポリゴンの法線の場合、そのポリゴン(の表面)がどこを向いているかを表します。

そのポリゴンの表面はどこを取っても、法線の示す方向を向いているわけです。
なので、視覚的に法線を表示する場合、ポリゴンの中心を求めて原点にするとか、各頂点から伸ばすとか、あるいは、ポリゴン全体が半透明に浮き上がっているように表現したりとかします。


変換に関しては、説明が正確ではありませんでした。
法線の向きに対して運動量を分解し、摩擦や反射を加えて計算する、というのが正しいです。

こちらのプログラムは2Dで、当たり判定はポリゴンではなく点ですが、法線を使った計算部分は3Dに応用できます。
#実際にとある家庭用ゲームでの3Dシミュレータに使っているコードから抜粋してきたものです。
壁に沿って転がる玉 : ISLeのビデオゲーム工房

円と点で構成されているのは当たり判定の簡略化のためです。
円が点と接触した時点で、法線が表す向きと垂直な壁に接触したことになるという仕様です。

アバター
usao
記事: 1887
登録日時: 11年前

Re: DxLibの3Dのコリジョン判定関数についての質問です

#8

投稿記事 by usao » 8年前

オフトピック
>法線がどんな線なのか

>何に対して垂直なのでしょうか?また座標はどこになるんでしょうか?


「ググれ」と言ってはいけないのでしょうけど,
「法線」みたいな一般単語くらいはとりあえず調べたらどうなんでしょう…?

sadora3
記事: 175
登録日時: 11年前

Re: DxLibの3Dのコリジョン判定関数についての質問です

#9

投稿記事 by sadora3 » 8年前

>>ISLeさん
まだ法線についてよくわかりません。
というか「垂直に交わるベクトル」というのは分かるのですが、Dim.Normalの値がどうなるのか全く分かりません。
Dim.Normal.yが0なら壁なのですよね。そしてサンプルプログラムでは
if( HitDim.Dim[ i ].Normal.y < 0.000001f && HitDim.Dim[ i ].Normal.y > -0.000001f )
とやっていたことから、とんでもない精度の変数だということが分かりました。
今の自分が思っているDim.Normalの値を絵に書いてみましたが、あってますか?坂は45度だとします。zはたまたま0だったとします。
あと、円の中で玉が転がるプログラムすっごい面白いです!これ意味を理解しようと頑張ったのですが、C++は勉強してなかったので、C++の勉強から頑張ろうと思いました。

>>usaoさん
すみません。一応自分でも法線の意味を調べて、DXライブラリの3D関数リファレンスを見に行きました。
そこには
// 当たったポリゴンの法線
VECTOR Normal ;
これだけしか書いてなくて、戸惑ってこの掲示板に質問に来た次第です。
そのことも書くべきでしたね。失礼しました。
ちなみに自分が調べて出てきた法線の意味は「曲線に対して、点Pにおける接線に垂直な直線」でした。
添付ファイル
法線について.jpg

ISLe()

Re: DxLibの3Dのコリジョン判定関数についての質問です

#10

投稿記事 by ISLe() » 8年前

Dim.Normalの中身は単位ベクトル(のはず)です。
単位ベクトルというのは、長さが1のベクトルです。

長さが1ということは半径1の円周上の数値ということになります。
奥行きがない場合、水平要素はコサイン(cos)、垂直要素はサイン(sin)で求まります。

VECTOR型の各要素はfloatです。
これはDxLib.hに書かれています。
Visual Studioには宣言や定義をポップアップ表示したり、ソースコードにジャンプする機能もありますので活用しましょう。


sadora3 さんが書きました:C++は勉強してなかったので、C++の勉強から頑張ろうと思いました。

DXライブラリの中身を知らなくてもDXライブラリが使えるように、このソースコードを読むのにC++を知っている必要はありません。

最初にRollAlongWall::init関数が1回呼びだされ、以降フレームごとに、RollAlongWall::frameUpdate関数(内部更新用)とRollAlongWall::frameRender関数(描画用)が呼び出されます。
プログラムの開始時や終了時、フレームごとに呼び出す必要のあるDXライブラリの関数は気にしなくて良いように見えなくしてあります。

たいちう
記事: 418
登録日時: 13年前

Re: DxLibの3Dのコリジョン判定関数についての質問です

#11

投稿記事 by たいちう » 8年前

> ちなみに自分が調べて出てきた法線の意味は「曲線に対して、点Pにおける接線に垂直な直線」でした。

それは2次元の話ですね。
3次元に拡張して「曲面に対して、点Pにおける接平面に垂直な直線」、と理解すればよいかと。
数学的に一般化すると曲面ですが、プログラムで扱うのはポリゴンなどの平面であることが多いので、
その平面に垂直な直線です。


ある程度の数学の知識がないと3Dは無理だと思います。
ちょっとサンプルと違うことをしようとすると手詰まりになるような。
どの程度の数学の知識かというと、高校の数学Bで習う
「空間図形」とか「空間のベクトル」を応用できる程度。
教科書などを読むだけでは応用はなかなかできないので、
教科書の問題などを真面目に解いてみると良いでしょう。

このように基礎体力を付けたら、3Dのゲームの解説もずっと理解しやすくなっていると思います。

sadora3
記事: 175
登録日時: 11年前

Re: DxLibの3Dのコリジョン判定関数についての質問です

#12

投稿記事 by sadora3 » 8年前

>>ISLeさん
ああ!なるほど!単位ベクトルですか!だから私が書いたプログラムでは全て原点(0,0,0)にあったように見えたのですね。
分かってしまえば簡単ですね。
ところで「以降フレームごとに、RollAlongWall::frameUpdate関数(内部更新用)とRollAlongWall::frameRender関数(描画用)が呼び出されます」とありますが、では
canvas->frameRender();
の下にある処理は気にしなくていいということですか?というかframeUpdate関数とframeRender関数の内容だけ理解出来ればいいですか?
あとfor(;;)というのはwhile(1)と全く同じと考えていいですか?forの条件のところに真か偽かの値がないので、一回で終わってしまうようにも見えますが・・・。

>>たいちうさん
数学Bですか・・・。一応私は高校では理系にいた人間ですが、授業についていけずに、勉強さぼっちゃったのですよ。あの時マジメに勉強しておけばよかったと後悔しています。3Dプログラミングの勉強してて、数学の知識が必要になったとき、自分から進んで勉強する数学はとても楽しく感じました。なんで高校の頃からこの楽しさに気づけなかったんでしょうねw
あ、数学の知識が必要になってから勉強するのではなく、事前に全部やっておくべきという話ですか。これから数学の勉強頑張ろうと思います。

ISLe()

Re: DxLibの3Dのコリジョン判定関数についての質問です

#13

投稿記事 by ISLe() » 8年前

sadora3 さんが書きました:ああ!なるほど!単位ベクトルですか!だから私が書いたプログラムでは全て原点(0,0,0)にあったように見えたのですね。
分かってしまえば簡単ですね。
ええと違いますね。
sadora3さんの書いたコードでは、球の中心を始点にしています。

先の投稿に書きましたが、始点をどこにするかはプログラマが決めることです。
ポリゴンごとに始点を求めて、そこから法線(の方向に伸ばした線)を描画するのです。

sadora3 さんが書きました:ところで「以降フレームごとに、RollAlongWall::frameUpdate関数(内部更新用)とRollAlongWall::frameRender関数(描画用)が呼び出されます」とありますが、では
canvas->frameRender();
の下にある処理は気にしなくていいということですか?というかframeUpdate関数とframeRender関数の内容だけ理解出来ればいいですか?
気にしなくていいです。
WinMain関数が呼ばれる仕組みまで知らなくてもいいのと同じことです。
RollAlongWall.cppの中だけ見てください。

sadora3 さんが書きました:あとfor(;;)というのはwhile(1)と全く同じと考えていいですか?forの条件のところに真か偽かの値がないので、一回で終わってしまうようにも見えますが・・・。
一回で終わってしまうかどうかは実際に動かしてみればすぐに分かることだと思いますが。
動作としては同じですが、生成されるコードが同じかどうかは分からないので、個人的にはリテラルを含まないほうが好みです。

たいちう
記事: 418
登録日時: 13年前

Re: DxLibの3Dのコリジョン判定関数についての質問です

#14

投稿記事 by たいちう » 8年前

> あ、数学の知識が必要になってから勉強するのではなく、事前に全部やっておくべきという話ですか。

そんなことは書いてません。
sandora3さんにとって数学の知識が必要になったのだから、勉強してくださいということです。
数学全般をやる必要もなく、空間図形の部分をしっかり理解すればよいでしょう。

明確な目的があった方が勉強が捗るのは同感です。
高校時代にサボったのならば教科書は嫌いかもしれませんが、莫大な金をかけて作られた本です。
そこらの書籍やサイトよりは、空間図形についての基礎が理解しやすいのではないでしょうか。

アバター
usao
記事: 1887
登録日時: 11年前

Re: DxLibの3Dのコリジョン判定関数についての質問です

#15

投稿記事 by usao » 8年前

オフトピック
法線,ベクトル,座標…

これら【(場合によっては)省略された記述】として用いられている単語に関して,
質問者様自身が わかりきったことを省略 して書いておられるのであれば良いのですが,
「法線」自体が謎の物として質問項目になっているような状況下においては,
読み手は,どんな意味で書かれたものなのか がいまいち掴みにくいのではないでしょうか.

法線の座標
みたいに言われると,一体何を意味しているのかわかりません.

例えば,「法線」という単語を,法線という直線そのものではなく
 「法線ベクトル」:法線と平行な方向を持ったベクトル
の意で用いる箇所なのであれば,「法線ベクトル」と明示的に書くようにしてみたらどうでしょうか.
(それが単位ベクトルであることも話の前提になるような文を書く場合には「単位法線ベクトル」とか.)


ベクトルは,コード上では単にいくつかの値(3次元ならx,y,zの3個とか)をまとめて保持しているもの にしか見えないかもしれませんが,
それがどんな量(意味,というか)を表しているのかは,ベクトルごとに異なり得ます.
算出されている「法線ベクトル」というが 位置ベクトルなのか方向ベクトルなのかもっと別の何かの量なのか
ということをしっかり理解されているのかどうかも,文面を見た限り不安な印象を受けます.



>DXライブラリの3D関数リファレンスを見に行きました。
>そこには
>// 当たったポリゴンの法線
>VECTOR Normal ;
>これだけしか書いてなくて、戸惑ってこの掲示板に質問に来た次第です。

きっと,「ポリゴンの法線っていうのは,こういうものになりますよ」っていうライブラリとしての定義というか約束事が設けられているのだと思います.

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

Re: DxLibの3Dのコリジョン判定関数についての質問です

#16

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

ベクトルは方向と大きさしか無いので、座標という概念はありません。
原点からのベクトルを便宜的に座標として使うことはありますが、原点からのと注釈が付きます。

法線ベクトルは、面から垂直なベクトルで座標はありません。
ただ、人に分かりやすい表現で表示するにはISLeさんが書かれているような事をすれば良いでしょう。
VECTOR Normal ;
これで法線ベクトルとしては必要十分な情報です。ちなみにNormal は英単語で垂直なという意味があります。

とりあえず、DXライブラリで色々表示しながら数学を復習してもらって空間座標系の数学で3D空間をイメージできるようになると、変な混乱もなくなってくると思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 11年前

Re: DxLibの3Dのコリジョン判定関数についての質問です

#17

投稿記事 by sadora3 » 8年前

>>ISLeさん
RollAlongWall.cppの中だけ見ればいいのですね。ありがとうございます。
あと色々おかしなこと言っててすみませんでした。

>>たいちうさん
全部やる必要はないですか。数Bの空間図形ですね。分かりました。

>>usaoさん
うーん、すみません。よく理解出来ていなくておかしなこと言っていた気がします。でももう大丈夫です。
単語の意味をしっかり理解しないと会話のドッチボールが成立しなくなるんですよね・・・。

>>ソフト屋さん
助言ありがとうございます。ベクトルには座標があるものだと思ってました・・・。点P1から点P2みたいな。
これからプログラミングと数学の勉強頑張ろうと思います。

回答してくれた皆さん本当にありがとうございました。

閉鎖

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