Springheadで採用している接触モデルについて説明します. 第7.3節で述べたように,PHSceneIf::Stepによってシミュレーションを1ステップ進めると, 初めに形状の交差判定と接触拘束の生 成が行われます. 交差する二つの形状の交差断面と,接触拘束の関係についてFig. 7.7に示します. 図では簡単のために二次元で描いていますが,実際には接触断面を表す多角形の各頂点に接触拘束が作られ ます. 接触拘束も他の拘束と同様にソケットとプラグで構成されます. 一方で,他の拘束とは違い接触拘束は交差判定アルゴリズムによって動的に生成・破棄されます. このため,接触し合う剛体のどちらにソケットあるいはプラグが取り付けられるかは状況依存であり, 外部から選択することはできません.
プラグおよびソケットの向きは次のようにして決まります. まず,x軸は接触法線と平行に向きます.ただしどちらが正の向きかは状況依存です. 次に,y軸は接触点における二つの剛体の相対速度ベクトルを接触断面へ投影した向きに向きます. 最後にz軸はx,y軸に直 交するように決まります.
以下では各接触拘束が課す条件について具体的に述べます. まず,法線方向の進入速度の大小に応じて衝突モデルと静的接触モデルのいずれかが選択されます.
ここではソケットから見たプラグの相対速度のx軸(接触法線)成分で,近づき合う向きを負とします. また,
は衝突モデルへ切り替わる臨界速度です.
衝突モデルでは,1ステップ後の相対速度が跳ね返り係数
にもとづいて決まり,それを満たすような接触力が計算されます.
ここで,跳ね返り係数は衝突する形状の物性値に定義された跳ね返り係数の平均値です.
静的接触モデルでは,形状同士の進入深度が1ステップで所定の割合で減少するような接触力を求めます. つまり,1ステップ後の進入深度を
とすると
となります. ここでは接触拘束の誤差修正率です. また,
は許容進入深度です.
最後に,接触力が満たすべき条件について述べます. まず,法線方向には反発力のみ作用することから,接触力のx軸成分には
が課せられます. 一方で接触力のy軸成分,z軸成分
は摩擦力を表します. 摩擦力に関しては,その向きの相対速度にもとづき静
止摩擦か動摩擦かが判定され,それに応じて最大摩擦力の制約が課されます.
ここで,静止摩擦係数および動摩擦係数
は跳ね返り係数と同様に各形状の物性値の平均値が用いられます. また,
は静止摩擦と動摩擦が切り替わる臨界速度です. z軸方向についても同様の制約が課されます.
接触モデルの関係するインタフェースには以下があります.
CDShapeIf | ||
void |
SetElasticity(float e) |
跳ね返り係数を設定 |
float |
GetElasticity() |
跳ね返り係数を取得 |
void |
SetStaticFriction(float mu0) |
静摩擦係数を設定 |
float |
GetStaticFriction() |
静摩擦係数を取得 |
void |
SetDynamicFriction(float mu) |
動摩擦係数を設定 |
float |
GetDynamicFriction() |
動摩擦係数を取得 |
PHSceneIf | ||
void |
SetContactTolerance(double tol) |
許容交差深度を設定 |
double |
GetContactTolerance() |
許容交差深度を取得 |
void |
SetImpactThreshold(double vth) |
最小衝突速度を設定 |
double |
GetImpactThreshold() |
最小衝突速度を取得 |
void |
SetFrictionThreshold(double vf) |
最小動摩擦速度を設定 |
double |
GetFrictionThreshold() |
最小動摩擦速度を取得 |
備考
• 接触断面の向きについては,形状同士の進入速度をもとに決定しますが,ここでは詳しく述べません.
• 摩擦力に関してはy軸,z軸が個別に扱われますが,実際の摩擦力はy成分とz成分の合力として与えられますので, 合力が最大摩擦力を超過する可能性があります.このようにSpringheadの摩擦モデルはあくまで近似的なものですので 注意して下さい.
特定の剛体に作用する接触力を直接取得するためのインタフェースは用意されていません. このため,ユーザサイドである程度の計算を行う必要があります. 以下に,ある剛体に作用する接触力の合力を求める例を示します.
// given PHSceneIf* scene // given PHSolidIf* solid Vec3d fsum; //< sum of contact forces applied to "solid" Vec3d tsum; //< sum of contact torques applied to "solid" int N = scene->NContacts(); Vec3d f, t; Posed pose; for(int i = 0; i < N; i++){ PHContactPointIf* con = scene->GetContact(i); con->GetConstraintForce(f, t); if(con->GetSocketSolid() == solid){ con->GetSocketPose(pose); fsum -= pose.Ori() * f; tsum -= pose.Pos() % pose.Ori() * f; } if(con->GetPlugSolid() == solid){ con->GetPlugPose(pose); fsum += pose.Ori() * f; tsum += pose.Pos() % pose.Ori() * f; } }
まず,シーン中の接触拘束の数をPHSceneIf::NConstactsで取得し, forループ中で番目の接触拘束をPHSceneIf::GetContactで取得します. 次
にPHConstraintIf::GetConstraintForceで接触力の並進力fとモーメントtを取得しますが, 接触拘束の場合モーメントは
ですので用いません. また,得られる拘束力はソケット/プラグ座標系で表したもので,作用点はソケット/プラグ座標系の
原点です. これを考慮して剛体に作用する力とモーメントへ変換し,合力に足し合わせていきます. 剛体がソケット側である場合は作用・反作用を考慮して符号を反転することに注意して下さい.
多くのアプリケーションでは,すべての剛体の組み合わせに関して接触を取り扱う必要はありません. このような場合は必要な剛体の対に関してのみ接触を有効化することで計算コストを削減できます. Springheadでは,剛体の組み合わせ毎に交差判定および接触力計算 を行うかを切り替えることができます. これにはPHSceneIf::SetContactModeを用います.
PHSceneIf | |
void |
SetContactMode(PHSolidIf* lhs, PHSolidIf* rhs, int mode) |
void |
SetContactMode(PHSolidIf** group, size_t length, int mode) |
void |
SetContactMode(PHSolidIf* solid, int mode) |
void |
SetContactMode(int mode) |
一番目は剛体lhsとrhsの対に関してモードを設定します. 二番目は配列[group, group + length)に格納された剛体の全組み合わせに関して設定します. 三番目は剛体solidと他の全剛体との組み合わせに関して設定しま す. 四番目はシーン中のすべての剛体の組み合わせに関して設定します.
設定可能なモードは以下の内の一つです.
PHSceneDesc::ContactMode | |
MODE_NONE |
交差判定および接触力計算を行わない |
MODE_LCP |
交差判定を行い,拘束力計算法を用いる |
MODE_PENALTY |
交差判定を行い,ペナルティ反力法を用いる |
デフォルトではすべての剛体対に関してMODE_LCPが選択されています. 例として,床面との接触以外をすべてオフにするには
// given PHSolidIf* floor scene->SetContactMode(PHSceneDesc::MODE_NONE); scene->SetContactMode(floor, PHSceneDesc::MODE_LCP);
とします.