質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

2689閲覧

3d カプセル同士の当たり判定を行いう方法が知りたい

退会済みユーザー

退会済みユーザー

総合スコア0

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/06/19 06:15

////////// 部の線分と線分の最短距離の の関数ですが参考サイトの情報などからカプセル同士の当たり判定に必要なプログラム上でのコードはわかったのですが実際にはどうすれば3d物体(ポリゴン)の当たり判定が実装できるのでしょうか?実装方法が知りたいです。
参考サイト: http://marupeke296.com/COL_3D_No27_CapsuleCapsule.html

#ifndef __IKD_OX_PRIMITIVE_H__ #define __IKD_OX_PRIMITIVE_H__ // プリミティブ定義 // v1.00 // 初出 // v1.01 // ベクトルの平行判定を外積に置き換え #include <math.h> #include <iostream> #include "stdio.h" #include "Vector.hpp" #define _OX_EPSILON_ 0.000001f // 誤差 // 3成分float struct Float3 { public: float x; float y; float z; Float3() { x = 0.0f; y = 0.0f; z = 0.0f; } Float3( float x, float y, float z ) : x( x ), y( y ), z( z ) {} ~Float3() {} Float3 operator +( const Float3 &r ) const { return Float3( x + r.x, y + r.y, z + r.z ); } Float3 operator -( const Float3 &r ) const { return Float3( x - r.x, y - r.y, z - r.z ); } Float3 operator -() const { return Float3( x * -1.0f, y * -1.0f, z * -1.0f ); } Float3 operator *( const Float3 &r ) const { return Float3( x * r.x, y * r.y, z * r.z ); } Float3 operator /( const Float3 &r ) const { return Float3( x / r.x, y / r.y, z / r.z ); } Float3 operator *( float r ) const { return Float3( x * r, y * r, z * r ); } Float3 operator /( float r ) const { return Float3( x / r, y / r, z / r ); } friend Float3 operator *( float l, const Float3 &r ) { return Float3( r.x * l, r.y * l, r.z * l ); } friend Float3 operator /( float l, const Float3 &r ) { return Float3( r.x / l, r.y / l, r.z / l ); } float dot( const Float3 &r ) const { float f = (x * r.x + y * r.y + z * r.z); //printf("dot: %f\n", f); return x * r.x + y * r.y + z * r.z; } Float3 cross( const Float3 &r ) const { return Float3( y * r.z - z * r.y, z * r.x - x * r.z, x * r.y - y * r.x ); } /*ベクトルの長さを取得*/ float length() const { return sqrtf( lengthSq() ); } /*各要素を掛け算して足す*/ float lengthSq() const { return (x * x) + (y * y) + (z * z); } void norm() { const float len = length(); if ( len > 0.0f ) { x /= len; y /= len; z /= len; } } Float3 getNorm() const { const float len = length(); if ( len > 0.0f ) { return Float3( x / len, y / len, z / len ); } return Float3( 0.0f, 0.0f, 0.0f ); } // 鋭角関係? //bool isSharpAngle(Vec3& r) { //float isSharpAngle(Float3& r)const { bool isSharpAngle(Float3 &r)const { //return (dot((Float3)r) >= 0.0f); float f = dot(r); //return f; if( f <= 0.0f) { printf("鈍角: %f\n", f); //printf("鈍角: %.2f\n",f); return false; }else { //printf("鋭角: %.2f\n", f); printf("鋭角: %f\n", f); return true;// } } void print_Line() { printf("x: %.2f\n", x); printf("y: %.2f\n", y); printf("z: %.2f\n\n\n", z); // printf("v.x: %.2f\n", v.x); // printf("v.y: %.2f\n", v.y); //printf("v.z: %.2f\n", v.z); } }; // 点 typedef Float3 Point; // ベクトル struct Vec3 : public Float3 { Vec3() {} Vec3( float x, float y, float z ) : Float3( x, y, z ) {} Vec3( const Float3 &r ) : Float3( r ) {} ~Vec3() {} Vec3& operator = ( const Float3 &r ) { x = r.x; y = r.y; z = r.z; return *this; } // 標準化 void norm() { const float len = length(); if ( len > 0.0f ) { x /= len; y /= len; z /= len; } } // 垂直関係にある? bool isVertical( const Vec3 &r ) const { float d = dot( r ); return ( -_OX_EPSILON_ < d && d < _OX_EPSILON_ ); // 誤差範囲内なら垂直と判定 } // 平行関係にある? bool isParallel( const Vec3 &r ) const { float d = cross( r ).lengthSq(); //printf("d: %.2f\n",d); //if (-_OX_EPSILON_ <= r.LengthSq() <= _OX_EPSILON_) return ( -_OX_EPSILON_ < d && d < _OX_EPSILON_ ); // 誤差範囲内なら平行と判定 } /* // 鋭角関係? bool isSharpAngle( const Vec3 &r ) const { return ( dot( r ) >= 0.0f ); } */ void print_Line() { printf("x: %.2f\n", x); printf("y: %.2f\n", y); printf("z: %.2f\n\n\n",z); // printf("v.x: %.2f\n", v.x); // printf("v.y: %.2f\n", v.y); //printf("v.z: %.2f\n", v.z); } }; // 直線 struct Line { Point p; Vec3 v; // 方向ベクトル Line() : p( 0.0f, 0.0f, 0.0f ), v( 1.0f, 0.0f, 0.0f ) {} Line( const Point &p, const Vec3 &v ) : p( p ), v( v ) {} ~Line() {} // 点上の座標を取得 // ベクトルに掛け算する係数 Point getPoint( float t ) const { return p + t * v; } void print_Line() { printf("p.x: %.2f\n", p.x); printf("p.y: %.2f\n", p.y); printf("p.z: %.2f\n\n\n", p.z); printf("v.x: %.2f\n",v.x); printf("v.y: %.2f\n",v.y); printf("v.z: %.2f\n",v.z); } }; // 線分 struct Segment : public Line { Segment() {} Segment( const Point &p, const Vec3 &v ) : Line( p, v ) { } Segment( const Point &p1, const Point &p2 ) : Line( p1, p2 - p1 ) {} // 終点を取得 Float3 getEndPoint() const { return p + v; } }; // 球 struct Sphere { Point p; float r; // 半径 Sphere() : p( 0.0f, 0.0f, 0.0f ), r( 0.5f ) {} Sphere( const Point &p, float r ) : p( p ), r( r ) {} ~Sphere() {} }; // カプセル struct Capsule { Segment s; float r; // 半径 Capsule() : r( 0.5f ) {} Capsule( const Segment &s, float r ) : s( s ), r( r ) {} Capsule( const Point &p1, const Point &p2, float r ) : s( p1, p2 ), r( r ) {} ~Capsule() {} }; // AABB struct AABB { Point p; // 中心点 Float3 hl; // 各軸の辺の長さの半分 AABB() {} AABB( const Point &p, const Float3 &hl ) : p( p ), hl( hl ) {} // 辺の長さを取得 float lenX() const { return hl.x * 2.0f; }; float lenY() const { return hl.y * 2.0f; }; float lenZ() const { return hl.z * 2.0f; }; float len( int i ) { return *( (&hl.x) + i ) * 2.0f; } }; ///////////////////////////////////////////////////線分と線分の最短距離 // 0~1の間にクランプ void clamp01(float& v) { if (v < 0.0f) v = 0.0f; else if (v > 1.0f) v = 1.0f; } // 2線分の最短距離 // s1 : S1(線分1) // s2 : S2(線分2) // p1 : S1側の垂線の足(戻り値) // p2 : S2側の垂線の足(戻り値) // t1 : S1側のベクトル係数(戻り値) // t2 : S2側のベクトル係数(戻り値) // 戻り値: 最短距離 float calcSegmentSegmentDist(const Segment& s1, const Segment& s2, Point& p1, Point& p2, float& t1, float& t2) { // S1が縮退している? if (s1.v.lengthSq() < _OX_EPSILON_) { // S2も縮退? if (s2.v.lengthSq() < _OX_EPSILON_) { // 点と点の距離の問題に帰着 float len = (s2.p - s1.p).length(); p1 = s1.p; p2 = s2.p; t1 = t2 = 0.0f; return len; } else { // S1の始点とS2の最短問題に帰着 float len = calcPointSegmentDist(s1.p, s2, p2, t2); p1 = s1.p; t1 = 0.0f; clamp01(t2); return len; } } // S2が縮退している? else if (s2.v.lengthSq() < _OX_EPSILON_) { // S2の始点とS1の最短問題に帰着 float len = calcPointSegmentDist(s2.p, s1, p1, t1); p2 = s2.p; clamp01(t1); t2 = 0.0f; return len; } /* 線分同士 */ // 2線分が平行だったら垂線の端点の一つをP1に仮決定 if (s1.v.isParallel(s2.v) == true) { t1 = 0.0f; p1 = s1.p; float len = calcPointSegmentDist(s1.p, s2, p2, t2); if (0.0f <= t2 && t2 <= 1.0f){ return len; } } else { // 線分はねじれの関係 // 2直線間の最短距離を求めて仮のt1,t2を求める float len = calcLineLineDist(s1, s2, p1, p2, t1, t2); if ( 0.0f <= t1 && t1 <= 1.0f && 0.0f <= t2 && t2 <= 1.0f ) { return len; } } // 垂線の足が外にある事が判明 // S1側のt1を0~1の間にクランプして垂線を降ろす clamp01(t1); p1 = s1.getPoint(t1); float len = calcPointSegmentDist(p1, s2, p2, t2); if (0.0f <= t2 && t2 <= 1.0f){ return len; } // S2側が外だったのでS2側をクランプ、S1に垂線を降ろす clamp01(t2); p2 = s2.getPoint(t2); len = calcPointSegmentDist(p2, s1, p1, t1); if (0.0f <= t1 && t1 <= 1.0f){ return len; } // 双方の端点が最短と判明 clamp01(t1); p1 = s1.getPoint(t1); return (p2 - p1).length(); } #endif

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

線分と線分の最短距離から、Capsuleの半径(r)を比較して、
**「線分と線分の最短距離 <= Capsule.r」**の場合、衝突していると言えます。

ここからは私の経験で語りますが、これはまだ90%ぐらいしか取得出来ず、100%にするには、
2つのCapsuleの始点と終点、それぞれで点と線分の距離を使って、水平の位置を割り出さないと、バグが発生するケースがあったと思います。

投稿2020/07/08 00:47

編集2020/07/08 03:57
stdio

総合スコア3307

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2020/07/08 01:13

> 「Capsule.r <= 線分と線分の最短距離」 ・不等号が逆に思えます. ・閾値は,両カプセルの半径の和 ではないでしょうか. > 100%にするには...~...部分がプログラムを読んでいる限りありません 必要ないと思います. 前段が「線分」同士の最短距離なのであれば. (「線分」からの距離がr以内である領域というのはカプセルの形)
stdio

2020/07/08 03:59

> 「Capsule.r <= 線分と線分の最短距離」 ご指摘ありがとうございます。修正致しました。 > 100%にするには...~...部分がプログラムを読んでいる限りありません こちらに関してはすみません、私の経験です... なぜか前半だけでは衝突しないというバグが発生したので、このような対応を取ったケースがあるということです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問