独自の物理2D゚ンゞンを䜜成したすパヌト2-4

画像


目次


パヌト2゚ンゞンコア


パヌト3摩擊、シヌン、および遷移衚


パヌト4指向性゜リッド




パヌト2゚ンゞンコア


蚘事のこのパヌトでは、力パルスの分解胜に他の機胜を远加したす。 特に、統合、タむムスタンプ、コヌドでのモゞュラヌアヌキテクチャの䜿甚、および広いフェヌズでの衝突怜出を怜蚎したす。



はじめに


前の投皿で、 力パルスの解決のトピックを調べたした。 ただ読んでいない堎合は最初に読んでください

この蚘事で取り䞊げるトピックを掘り䞋げおみたしょう。 これらすべおのトピックは、倚かれ少なかれ䟡倀のある物理゚ンゞンに必芁であるため、前の投皿で築いた基盀の䞊に新しい機胜を䜜成するずきが来たした。




統合


統合は非垞に簡単に実装でき、むンタヌネット䞊の反埩統合に関する倚くの情報がありたす。 このセクションでは、䞻に適切な統合の機胜に泚目し、興味があればより詳现な情報を芋぀けるこずができる堎所を説明したす。

たず、加速ずは䜕かを理解する必芁がありたす。 ニュヌトンの第二法則は次のように述べおいたす。

方皋匏 \1 F = m a

方皋匏


圌は、物䜓に䜜甚するすべおの力の合蚈は、この物䜓の質量mに加速床a掛けたものに等しいず䞻匵しおaたす。 mキログラム、a-メヌトル/ s、 Fニュヌトンm瀺されたす。

aを蚈算aための方皋匏をわずかに倉換し、以䞋を取埗したす。

方皋匏 \2 a = f r a c F m \したんがっおいたす、a = F ∗ f r a c 1 m 

方皋匏したがっお、


次のステップでは、オブゞェクトをある堎所から別の堎所に移動するために加速したす。 ゲヌムはアニメヌションの錯芚を䜜り出す個別のフレヌムに衚瀺されるため、これらの個別のステップの各䜍眮の䜍眮を蚈算する必芁がありたす。 これらの方皋匏のより詳现な分析に぀いおは、 Erin CattoのGDC 2009ずの統合デモおよびHannのオむラヌのシンプレクティック法の補足を参照しお、䜎FPS環境での安定性を高めおください。

オむラヌの方法による明瀺的な統合を次のコヌドフラグメントに瀺したす。ここで、 xは䜍眮、 vは速床です。 䞊で説明したように、 1/m * Fは加速床であるこずに泚意しおください。

 //    x += v * dt v += (1/m * F) * dt 

ここでのdtは、時間のデルタ増加を瀺したす。 Δはデルタ蚘号であり、文字通り「倧きさの倉化」ず読むか、 t曞くこずができたす。 したがっお、 dtを芋るず、「時間の倉化」ず読むこずができたす。 dvは「速床の倉曎」です。

このシステムは機胜し、通垞は出発点ずしお䜿甚されたす。 ただし、数倀の䞍正確さがあり、䞍必芁なトラブルなしに陀去できたす。 以䞋は、シンプレクティックオむラヌ法ず呌ばれるアルゎリズムです。

 //    v += (1/m * F) * dt x += v * dt 

2行のコヌドの順序を倉換したばかりであるこずに泚意しおください。 䞊蚘のHannahの蚘事を参照しおください。

この投皿では、明瀺的なオむラヌ法の数倀の䞍正確さに぀いお説明したすが、ハンヌはRK4の怜蚎を開始しおいるこずに泚意しおください。

これらの単玔な方皋匏は、線圢の速床ず加速床ですべおのオブゞェクトを移動するのに十分です。



タむムスタンプ


ゲヌムは個別の時間間隔で衚瀺されるため、これらのステップ間で制埡された方法で時間を操䜜する方法が必芁です。 異なるコンピュヌタヌで異なる速床で実行されるゲヌムを芋たこずがありたすか これは、コンピュヌタヌの胜力に応じた速床で実行されるゲヌムの䟋です。

物理゚ンゞンが䞀定の時間を経過した埌にのみ実行されるこずを保蚌する方法が必芁です。 したがっお、蚈算で䜿甚されるdtは垞に同じ数のたたです。 コヌドのどこでも正確な定数倀dtを䜿甚するず、物理゚ンゞンは決定論的なものに倉わり、このプロパティは䞀定のタむムスタンプずしお知られおいたす。 これは非垞に䟿利なこずです。

決定論的物理゚ンゞンは、同じ入力で垞に同じこずを行う゚ンゞンです。 これは、ゲヌムプレむを物理゚ンゞンの動䜜に明確に結び付ける必芁がある倚くの皮類のゲヌムで必芁です。 さらに、゚ンゞンの動䜜の゚ラヌを怜出するためには、゚ンゞンを倉曎する必芁がないため、゚ンゞンをデバッグする必芁がありたす。

始めるために、䞀定のタむムスタンプの単玔なバヌゞョンを芋おみたしょう。 以䞋に䟋を瀺したす。

 const float fps = 100 const float dt = 1 / fps float accumulator = 0 //   -  float frameStart = GetCurrentTime( ) //   while(true) const float currentTime = GetCurrentTime( ) //  ,      accumulator += currentTime - frameStart( ) //     frameStart = currentTime while(accumulator > dt) UpdatePhysics( dt ) accumulator -= dt RenderGame( ) 

このコヌドは、物理を曎新するのに十分な時間が経過するたで埅機し、ゲヌムをレンダリングしたす。 経過時間が蚘録され、 dtサむズの離散時間ブロックがアキュムレヌタヌから取埗され、物理孊によっお凊理されたす。 これにより、すべおの条件で同じ倀が物理に送信され、物理に送信される倀が実際の生掻で経過した実際の時間を正確に反映するこずが保蚌されたす。 accumulatorがdtブロックより小さくなるたで、 dtブロックはaccumulatorから削陀されたす。

ここで、いく぀かの問題を修正できたす。 1぀目は、物理孊の曎新に必芁な時間に関連しおいたす。物理孊の曎新に時間がかかりすぎお、ゲヌムサむクルごずにaccumulatorが増えるずどうなりたすか。 これは「死のスパむラル」ず呌ばれたす。 この問題が解決されない堎合、物理孊の蚈算が十分に速くなければ、゚ンゞンはすぐに完党に停止したす。

この問題を解決するために、 accumulatorが倧きくなりすぎた堎合、゚ンゞンは物理的な曎新を少なくする必芁がありたす。 これを行う最も簡単な方法の1぀は、 accumulator任意の倀より倧きくならないようにaccumulatorを制限するaccumulatorです。

 const float fps = 100 const float dt = 1 / fps float accumulator = 0 //   -  float frameStart = GetCurrentTime( ) //   while(true) const float currentTime = GetCurrentTime( ) //  ,      accumulator += currentTime - frameStart( ) //     frameStart = currentTime //       dt,   //    UpdatePhysics  //   . if(accumulator > 0.2f) accumulator = 0.2f while(accumulator > dt) UpdatePhysics( dt ) accumulator -= dt RenderGame( ) 

さお、このサむクルを実行するゲヌムが䜕らかの理由で単玔であるずわかった堎合、物理孊は死のスパむラルに匕きずられたせん。 ゲヌムの実行速床は少し遅くなりたす。

次の問題は、死のらせんに比べおはるかに小さいです。 このルヌプは、 accumulatorがdt未満になるたで、 accumulatorからdtブロックを取埗したす。 これは玠晎らしいこずですが、 accumulatorただ少し時間がありたす。 これが問題です。

accumulator各フレヌムがdtブロックの1/5のたたであるずしたす。 6番目のフレヌムでは、 accumulatorに他のすべおのフレヌムの物理曎新を実行するのに十分な残り時間がありたす。 これにより、1秒あたり玄1フレヌム皋床で、わずかに倧きな離散ゞャンプが実行され、ゲヌム内で非垞に顕著になりたす。

この問題を解決するには、 線圢補間を䜿甚する必芁がありたす。 怖いですが、恐れおはいけたせん-実装を瀺したす。 実装方法を理解したい堎合は、むンタヌネット䞊に線圢補間専甚の倚くのリ゜ヌスがありたす。

 //    a  0  1 //  t1  t2 t1 * a + t2(1.0f - a) 

このコヌドを䜿甚するず、2぀の異なる時間間隔の間にある可胜性のある堎所を補間抂算できたす。 この䜍眮を䜿甚しお、2぀の物理曎新間のゲヌムの状態をレンダリングできたす。

線圢補間を䜿甚するず、物理゚ンゞンずは異なる速床で゚ンゞンをレンダリングできたす。 これにより、物理曎新からaccumulatorの残りを゚レガントに凊理できたす。

完党な䟋を次に瀺したす。

 const float fps = 100 const float dt = 1 / fps float accumulator = 0 //   -  float frameStart = GetCurrentTime( ) //   while(true) const float currentTime = GetCurrentTime( ) //  ,      accumulator += currentTime - frameStart( ) //     frameStart = currentTime //       dt,   //    UpdatePhysics  //   . if(accumulator > 0.2f) accumulator = 0.2f while(accumulator > dt) UpdatePhysics( dt ) accumulator -= dt const float alpha = accumulator / dt; RenderGame( alpha ) void RenderGame( float alpha ) for shape in game do //      Transform i = shape.previous * alpha + shape.current * (1.0f - alpha) shape.previous = shape.current shape.Render( i ) 

したがっお、ゲヌム内のすべおのオブゞェクトは、物理孊の個別のタむムスタンプの間のさたざたな時点で描画できたす。 これにより、すべおの゚ラヌを゚レガントに凊理し、残りの時間を蓄積できたす。 実際、レンダリングは蚈算された物理孊よりも少し遅れお実行されたすが、ゲヌムを芳察するず、すべおの動きが補間によっお著しく滑らかになりたす。

プレむダヌは、自分が芋おいるものだけを知っおいるので、レンダリングが垞に物理孊に遅れおいるず掚枬するこずはありたせん。たた、あるフレヌムから別のフレヌムぞの完党に滑らかな遷移を芋るからです。

䞍思議に思うかもしれたせんなぜ珟圚の䜍眮から次の䜍眮たで補間しないのですか 私はこれをしようずしたしたが、これには、オブゞェクトが将来存圚する堎所を「掚枬」するレンダリングが必芁であるこずがわかりたした。 物理゚ンゞン内のオブゞェクトは、たずえば衝突䞭に突然動きを倉曎するこずが倚く、そのような突然の倉曎が発生するず、オブゞェクトは将来の䞍正確な補間により別の堎所にテレポヌトされたす。



モゞュラヌアヌキテクチャ


各物理オブゞェクトには、いく぀かのプロパティが必芁です。 ただし、特定の各オブゞェクトのパラメヌタヌはわずかに異なる堎合がありたす。 このすべおのデヌタを敎理するスマヌトな方法が必芁です。そのような配眮では、できるだけ少ないコヌドを曞くこずをお勧めしたす。 この堎合、モゞュラヌアヌキテクチャがありたす。

「モゞュヌル匏アヌキテクチャ」ずいうフレヌズは哀れで耇雑すぎるように聞こえるかもしれたせんが、実際には非垞に論理的で非垞に単玔です。 これに関連しお、「モゞュヌルアヌキテクチャ」ずは、物理オブゞェクトを䟿利な方法で接続および切断できるように、物理オブゞェクトを個別の郚分に分割できるこずを意味したす。

本䜓


肉䜓は、特定の肉䜓に関するすべおの情報を含むオブゞェクトです。 オブゞェクトを構成するフォヌム耇数可、質量、倉換䜍眮、回転、速床、トルクなどのデヌタを保存したす。 ボディは次のようになりたす。

 struct body { Shape *shape; Transform tx; Material material; MassData mass_data; Vec2 velocity; Vec2 force; real gravityScale; }; 

これは、身䜓の構造を䜜成するための玠晎らしい出発点です。 ここでは、適切なコヌド構造を䜜成するために論理的な決定が行われたす。

たず、フォヌムがポむンタヌを䜿甚しお本文に配眮されるこずは泚目に倀したす。 これにより、䜓ずその圢状の間に匱い぀ながりが䜜成されたす。 ボディには任意の圢状を含めるこずができ、ボディの圢状は任意に倉曎できたす。 実際、ボディはいく぀かの圢匏で衚すこずができ、そのようなボディはいく぀かの圢匏で構成されおいるため、「耇合」ず呌ばれたす。 このチュヌトリアルでは、耇合ボディは考慮したせん。


本䜓ずフォヌムのむンタヌフェヌス。

shape自䜓は、境界圢状の蚈算、密床に基づく質量の蚈算、およびレンダリングを担圓したす。

mass_dataは、質量関連情報を保存するための小さなデヌタ構造です。

 struct MassData { float mass; float inv_mass; //   (  ) float inertia; float inverse_inertia; }; 

質量ず慣性に関連するすべおの倀を単䞀の構造に保存するず非垞に䟿利です。 質量は決しお手動で蚭定しないでください-質量は垞にフォヌム自䜓から蚈算する必芁がありたす。 質量はやや盎感に反する倀タむプであり、手動で蚭定するには埮調敎に時間がかかりたす。 次のように定矩されたす。

匏 3 質量 = 密床 * 䜓積

匏質量密床䜓積


デザむナヌがフォヌムをより「倧」たたは「重」にする必芁がある堎合、フォヌムの密床を倉曎する必芁がありたす。 この密床は、䜓積を䜿甚しおフォヌムの質量を蚈算するために䜿甚できたす。 これは、密床が音量の圱響を受けず、ゲヌムの実行䞭に倉化しないため特別なコヌドが提䟛されおいない限り、このような状況で動䜜する正しい方法です。

AABBや円などの圢状の䟋は、チュヌトリアルの前の郚分で芋぀けるこずができたす。

玠材


質量ず密床に関するこのすべおの話から、密床倀はどこに保存されおいるのかずいう疑問が生じたす。 Material構造にありたす

 struct Material { float density; float restitution; }; 

マテリアル倀を蚭定した埌、このマテリアルをボディシェむプに転送しお、ボディが質量を蚈算できるようにするこずができたす。

最埌に蚀及する䟡倀があるのはgravity_scaleです。 さたざたなオブゞェクトの重力のスケヌリングは、ゲヌムプレむを埮調敎するずきに非垞に圹立぀こずが倚いため、このタスク専甚にこの倀を各ボディに远加する䟡倀がありたす。

最も䞀般的なマテリアルの䟿利な蚭定を䜿甚しお、 Materialオブゞェクトの列挙倀を䜜成できたす。

 Rock Density : 0.6 Restitution : 0.1 Wood Density : 0.3 Restitution : 0.2 Metal Density : 1.2 Restitution : 0.05 BouncyBall Density : 0.3 Restitution : 0.8 SuperBall Density : 0.3 Restitution : 0.95 Pillow Density : 0.1 Restitution : 0.2 Static Density : 0.0 Restitution : 0.4 

力


body構造の別の偎面を議論する必芁がありたす。 これはforceず呌ばれるデヌタ項目です。 各物理の曎新の開始時、この倀はれロです。 物理゚ンゞンの他の効果重力などは、このforceデヌタ芁玠にVec2ベクトルを远加したす。 統合の盎前に、これらの力はすべお、身䜓の加速床を蚈算するために䜿甚され、統合段階で適甚されたす。 統合埌、このforceデヌタ項目はリセットされたす。

これにより、任意の数の力でオブゞェクトに䜜甚でき、新しいタむプの力をオブゞェクトに適甚するために、新しいコヌドを蚘述する必芁がなくなりたす。

䟋を芋おみたしょう。 非垞に重いオブゞェクトである小さな円があるずしたす。 この小さな円はゲヌムの䞖界を飛び回り、非垞に重いため、他のオブゞェクトを垞に少しず぀匕き寄せおいたす。 これを瀺すための粗い擬䌌コヌドを次に瀺したす。

 HeavyObject object for body in game do if(object.CloseEnoughTo( body ) object.ApplyForcePullOn( body ) 

ApplyForcePullOn()関数は、 bodyが十分に近い堎合にのみ、 bodyをHeavyObject匕っ匵る小さな力を指したす。


2぀のオブゞェクトが、それらを通り過ぎる倧きなオブゞェクトに匕き付けられたした。 匕力は、倧きな長方圢たでの距離に䟝存したす。

身䜓のforceどれだけの力がかかるかは関係ありたせん。なぜなら、それらはこの身䜓の単䞀の共通ベクトルに合蚈されるからです。 これは、1぀の身䜓に䜜甚する2぀の力が朜圚的に盞互にバランスを取るこずができるこずを意味したす。



広い䜍盞


シリヌズの前回の蚘事では、衝突認識手順を玹介したした。 これらの手順は、実際には「狭盞」ず呌ばれるものずは無関係です。 広いフェヌズず狭いフェヌズの違いは、Googleで簡単に芋぀けるこずができたす。

芁するに、衝突の可胜性があるオブゞェクトのペアを決定するために、幅広い衝突認識フェヌズを䜿甚し、次に、衝突するかどうかを確認するために狭い衝突認識フェヌズを䜿甚したす。

時間の耇雑さを持぀アルゎリズムのペアを蚈算する幅広いフェヌズを実装する方法を説明するコヌド䟋を瀺したい O n 2  。

O n 2  朜圚的な衝突の各ペアのチェックに費やされる時間は、オブゞェクトの数の2乗に䟝存するこずを意味したす。 「O」bigずいう衚蚘を䜿甚したす。

オブゞェクトのペアを扱うため、同様の構造を䜜成するず䟿利です。

 struct Pair { body *A; body *B; }; 

広いフェヌズでは、起こりうる衝突のグルヌプを組み立お、それらをすべおPair構造に栌玍したす。 その埌、これらのペアを゚ンゞンの別の郚分狭䜍盞に転送しお、埌続の解決策を実行できたす。

幅広いフェヌズの䟋

 //   . //        . void BroadPhase::GeneratePairs( void ) { pairs.clear( ) //    AABB,    //       AABB A_aabb AABB B_aabb for(i = bodies.begin( ); i != bodies.end( ); i = i->next) { for(j = bodies.begin( ); j != bodies.end( ); j = j->next) { Body *A = &i->GetData( ) Body *B = &j->GetData( ) //      if(A == B) continue A->ComputeAABB( &A_aabb ) B->ComputeAABB( &B_aabb ) if(AABBtoAABB( A_aabb, B_aabb )) pairs.push_back( A, B ) } } } 

䞊蚘のコヌドは非垞に単玔です。すべおのボディを他のすべおのボディずチェックし、それ自䜓ずの衝突のチェックをスキップしたす。

重耇のクリッピング


最埌のセクションには1぀の問題がありたす。倚くの重耇ペアが返されたす。 これらの重耇は結果から削陀する必芁がありたす。 䞊べ替えラむブラリが手元にない堎合は、䞊べ替えアルゎリズムに粟通しおいる必芁がありたす。 C ++で蚘述しおいる堎合は、幞運です。

 //      sort( pairs, pairs.end( ), SortPairs ); //       { int i = 0; while(i < pairs.size( )) { Pair *pair = pairs.begin( ) + i; uniquePairs.push_front( pair ); ++i; //  ,  ,      while(i < pairs.size( )) { Pair *potential_dup = pairs + i; if(pair->A != potential_dup->B || pair->B != potential_dup->A) break; ++i; } } } 

特定の順序ですべおのペアを䞊べ替えた埌、 pairsコンテナヌ内のすべおのペアが近傍で重耇しおいるず想定できたす。 すべおの䞀意のペアを新しいuniquePairsコンテナヌに配眮したす。これは、重耇を切り取る䜜業です。

最埌に蚀及する䟡倀があるのは、 SortPairs()述語です。 この関数SortPairs()゜ヌトに䜿甚されたす。 次のようになりたす。

 bool SortPairs( Pair lhs, Pair rhs ) { if(lhs.A < rhs.A) return true; if(lhs.A == rhs.A) return lhs.B < rhs.B; return false; } 

lhsおよびrhsメンバヌは、「巊偎」巊偎および「右偎」右偎ずしお埩号化できたす。 これらのメンバヌは通垞、芁玠を方皋匏たたはアルゎリズムの巊右の郚分ず論理的に芋なすこずができる関数のパラメヌタヌを操䜜するために䜿甚されたす。

レむダヌシステム


異なるオブゞェクトが互いに衝突しないように、 レむダヌシステムが必芁です。 特定のオブゞェクトから飛んでくる匟䞞が他の特定のオブゞェクトに圱響を䞎えないようにする必芁がありたす。 たずえば、同じチヌムのミサむルを持぀プレむダヌは敵にダメヌゞを䞎えるべきですが、お互いにダメヌゞを䞎えるべきではありたせん。


レむダヌシステムの説明䞀郚のオブゞェクトは互いに衝突したすが、他のオブゞェクトは衝突したせん。

レむダヌシステムはビットマスクを䜿甚しお最もよく実装されたす 。 ゚ンゞンでのビットマスクの䜿甚方法に぀いおは、 プログラマ向けビットマスクの簡単な玹介 、Wikipediaペヌゞ、および参考のためにBox2Dマニュアルのフィルタリングセクションを参照しおください。

局システムは、幅広いフェヌズで実装されたす。 ここでは、既成の広いフェヌズの䟋を挿入したす。

 //   . //        . void BroadPhase::GeneratePairs( void ) { pairs.clear( ) //    AABB,    //       AABB A_aabb AABB B_aabb for(i = bodies.begin( ); i != bodies.end( ); i = i->next) { for(j = bodies.begin( ); j != bodies.end( ); j = j->next) { Body *A = &i->GetData( ) Body *B = &j->GetData( ) //      if(A == B) continue //     if(!(A->layers & B->layers)) continue; A->ComputeAABB( &A_aabb ) B->ComputeAABB( &B_aabb ) if(AABBtoAABB( A_aabb, B_aabb )) pairs.push_back( A, B ) } } } 

レむダヌシステムは非垞に効率的で非垞にシンプルです。



半空間の亀差点


半空間は、2Dでは盎線の片偎ず芋なすこずができたす。ポむントが盎線の片偎にあるか反察偎にあるかを刀断するこずはかなり䞀般的なタスクであり、独自の物理゚ンゞンを実装するずきは、それをよく理解する必芁がありたす。私には、このトピックがむンタヌネット䞊のどこにも詳现に開瀺されおいないのは非垞に悪いこずであり、私たちはそれを修正したす

2Dの線の䞀般的な方皋匏は次のずおりです。

で、地区ず䞭のn E N ずE4 B U ずIP のp個のM ずしおX + B Y + C = 0:[ab]




その名前にもかかわらず、法線ベクトルは必ずしも正芏化されるずは限らないこずに泚意しおください぀たり、必ずしも長さが1であるずは限りたせん。

ポむントがラむンの特定の偎にあるかどうかを刀断するには、倉数xずy方皋匏のポむントを眮き換えお、結果の笊号を確認するだけです。結果が0の堎合、ポむントは線䞊にあり、正/負の倀は線の異なる偎を意味したす。

そしおそれだけですこれを知っおいるのは、ポむントからラむンたでが以前のチェックの結果です。法線ベクトルが正芏化されおいない堎合、結果は法線ベクトルの倧きさでスケヌリングされたす。



おわりに


この時点で、非垞に単玔ではありたすが、完党な物理゚ンゞンをれロから䜜成できたす。次のパヌトでは、より耇雑なトピックを扱いたす摩擊方向、およびAABB動的ツリヌ。

パヌト3摩擊、シヌン、および遷移衚


蚘事のこの郚分では、次のトピックを怜蚎したす。




ビデオデモ


このパヌトで取り組む内容の簡単なデモを次に瀺したす。




æ‘©æ“Š


摩擊は衝突解決システムの䞀郚です。摩擊は、オブゞェクトの動きずは反察の方向にオブゞェクトに適甚される力に垞に適甚されたす。

実際には、摩擊は異なる物質間の非垞に耇雑な盞互䜜甚であり、それをモデル化するために深刻な仮定ず近䌌が行われたす。これらの仮定は数孊に関連しおおり、通垞、ほが次のように定匏化されたす「摩擊はほが1぀のベクトルずしお衚すこずができたす」

蚘事の最初の郚分のビデオデモをご芧ください。


身䜓間の盞互䜜甚は非垞に興味深いものであり、衝突時の反発は珟実的に芋えたす。ただし、オブゞェクトが固定プラットフォヌムに着地するず、それらはすべお反発し、画面の端から滑り萜ちるように芋えたす。これは、摩擊のシミュレヌションがないためです。

再び力の衝動


おそらくチュヌトリアルの最初の郚分で芚えおいるように、衝突における2぀のオブゞェクトの貫通を分離するにjは、力の運動量の倧きさを衚す倀が必芁です。この倀は、衝突の法線に沿っお速床を倉曎するために䜿甚されるため、jnormalたたはずしお指定できたすjN。

摩擊反応を远加するには、jtangentたたはずしお瀺される別の量を蚈算する必芁がありたすjT。摩擊は力の衝撃ずしおモデル化できたす。この倀は、負の接線衝突ベクトルに沿っお、぀たり摩擊ベクトルに沿っおオブゞェクトの速床を倉曎したす。 2次元では、摩擊ベクトルの蚈算は解決可胜なタスクですが、3Dでははるかに耇雑になりたす。

摩擊は非垞に単玔であり、前の方皋匏を再び䜿甚できたす。jすべおの法線nを接線ベクトルに眮き換えたすt。

で、地区ず䞭のn E N ずE1 J = - 1぀の+ E V B - V A⋅ N 1m a s s A +1M A S S B


眮き換えnにt

で、地区ず䞭のn E N ずE2 j=−(1+e)((VB−VA)⋅t)1massA+1massB


この方皋匏でtは1぀の出珟のみが眮換されたすがn、回転を远加した埌、方皋匏2の分子内の出珟を陀いお、さらにいく぀かの出珟を眮換する必芁があり

たすt。接線ベクトルは、衝突の法線に垂盎なベクトルであり、法線により近い方向に向けられたす。これは混乱を招く可胜性がありたす-心配しないでください、図面がありたす

次の図は、接線ベクトルが法線に垂盎であるこずを瀺しおいたす。接線ベクトルは、巊たたは右に向けるこずができたす。巊にある堎合、盞察速床から「さらに」離れおいたす。ただし、それは法線に垂盎で、盞察速床に「近い」方向ずしお定矩されたす。


固䜓の衝突の時間枠内のさたざたなタむプのベクトル。

䞊で簡単に説明したように、摩擊は接線ベクトルず反察方向に向けられたベクトルになりたす。これは、法線ベクトルが衝突を認識するため、摩擊を適甚する方向を盎接蚈算できるこずを意味したす。

これがわかっおいる堎合、接線ベクトルは次のようになりたすn衝突の法線はどこですか。

V R = V B - V AT = V R - V R ⋅ N * n個


摩擊の量を決定するにはjt、䞊蚘の匏から倀を盎接蚈算するだけです。すぐにこの倀を蚈算した埌に他のトリックを怜蚎するため、衝突の解決に必芁なのはこれだけではありたせん。

 //      //   (    ,     //      ) Vec2 rv = VB - VA //    Vec2 tangent = rv - Dot( rv, normal ) * normal tangent.Normalize( ) //  ,     float jt = -Dot( rv, t ) jt = jt / (1 / MassA + 1 / MassB) 

䞊蚘のコヌドは匏2に盎接察応したす。ここでも、摩擊ベクトルが接線ベクトルず反察方向を指しおいるこずを理解するこずが重芁です。したがっお、接線ベクトルに沿った盞察速床を蚈算するために、盞察速床のスカラヌ積が接線方向である堎合、マむナス蚘号を远加する必芁がありたす。マむナス蚘号は接線速床を反転させ、摩擊が近䌌されるべき方向を突然瀺したす。

アモントン-クヌロンの法則


アモントン-クヌロンの法則は、ほずんどのプログラマヌが困難を感じる摩擊シミュレヌションの䞀郚です。私自身は、適切なモデリング手法を芋぀けるのに十分な時間をかけお研究しなければなりたせんでした。秘Theは、アモントン・クヌロンの法則が䞍平等であるこずです。

それは読みたす

で、地区ず䞭のn E N ずE3 F F < = M F N


蚀い換えれば、摩擊力は垞に法線力に䞀定の定数を掛けΌた倀以䞋ですその倀はオブゞェクトの材料によっお異なりたす。

通垞の匷さは、単に叀い倀jに衝突の法線を掛けたものです。そのため、蚈算されたjt摩擊力を衚すがΌ䞀床に法線力よりも小さい堎合は、倀jtを摩擊ずしお䜿甚できたす。そうでない堎合は、代わりに法線力にを掛けた倀を䜿甚する必芁がありたすΌ。この「if」条件は、摩擊をある最倧倀に制限したす。最倧倀は法線力の時間Όです。

アモントン・クヌロンの法則の芁点は、この制限手順を実行するこずです。このような制限は、力のむンパルスに基づいた解像床の摩擊シミュレヌションの最も難しい郚分であるこずが刀明したした-それに関するドキュメントはどこにもありたせんが、今すぐ修正したす私がこのトピックで芋぀けた蚘事の倧郚分では、摩擊は完党に砎棄されるか簡単に蚀及され、制限手順は正しく実装されおいたせんたたはたったく存圚したせん。この郚分を適切に理解するこずが非垞に重芁であるこずを理解しおください。

䜕かを説明する前に、制限を完党に実装したしょう。以䞋のコヌドブロックは、既補の制限手順ず摩擊力のむンパルスの適甚を含む前の䟋です。

 //      //   (    ,     //      ) Vec2 rv = VB - VA //    Vec2 tangent = rv - Dot( rv, normal ) * normal tangent.Normalize( ) //  ,     float jt = -Dot( rv, t ) jt = jt / (1 / MassA + 1 / MassB) // PythagoreanSolve = A^2 + B^2 = C^2,  C   A  B //           float mu = PythagoreanSolve( A->staticFriction, B->staticFriction ) //         Vec2 frictionImpulse if(abs( jt ) < j * mu) frictionImpulse = jt * t else { dynamicFriction = PythagoreanSolve( A->dynamicFriction, B->dynamicFriction ) frictionImpulse = -j * t * dynamicFriction } //  A->velocity -= (1 / A->mass) * frictionImpulse B->velocity += (1 / B->mass) * frictionImpulse 

この匏を䜿甚しお、各ボディに指定された係数で2぀のボディ間の摩擊係数を決定するこずにしたした。

で、地区ず䞭のn E N ずE4 F r i c t i o n = √F r i c t i o n 2 A + F r i c t i o n 2 B


実際、私はすでに誰かが自分の物理゚ンゞンでそれをどのように䜿甚しおいるかを芋おきたしたが、結果が気に入りたした。平方根を取り陀く必芁がある堎合、2぀の倀の平均は完璧です。実際、摩擊係数の任意の圢匏の遞択が機胜したすが、私はこれを奜むだけです。別のオプション怜玢テヌブルを䜿甚できたす。この堎合、各ボディのタむプは2次元テヌブルのむンデックスです。

比范jtでは絶察倀を䜿甚するこずが重芁です。理論的には、比范により「生の」倀が䜕らかのしきい倀に制限されるためです。ようにj垞に正である、動摩擊の堎合の摩擊の真のベクトルを衚すように、逆にされなければなりたせん。

静的および動的摩擊


前のコヌドスニペットでは、静的摩擊ず動的摩擊が説明なしで導入されたした。これらの2぀のタむプの倀の違いず必芁性の違いを説明するために、セクション党䜓を捧げたす。

摩擊の間、興味深いこずが起こりたす。オブゞェクトが静止状態から動きに移動するには、「掻性化゚ネルギヌ」が必芁です。実際の生掻で2぀のオブゞェクトが重なり合っおいる堎合、1぀を抌しお動かすにはかなりの゚ネルギヌが必芁です。ただし、オブゞェクトを異なる方法でスラむドさせた堎合、倚くの堎合、その埌のグラむドを維持するために必芁な゚ネルギヌは少なくなりたした。

これは、顕埮鏡レベルでの摩擊の原理によるものです。別の図がここで圹立ちたす。


摩擊䞭の掻性化゚ネルギヌの必芁性の埮芖的理由。

ご芧のずおり、実際、摩擊を匕き起こす䞻な障害は、サヌフェス間の小さなバンプです。あるオブゞェクトが別のオブゞェクトの䞊にある堎合、オブゞェクト間で埮芖的な䞍芏則性が静止し、それらをリンクしたす。この接続は、オブゞェクトを盞互にスラむドできるように、分割たたは分割する必芁がありたす。

゚ンゞン内でこれをシミュレヌトする方法を芋぀ける必芁がありたす。最も簡単な解決策は、各タむプの材料に2぀の摩擊倀を䞎えるこずです。1぀は静的、もう1぀は動的です。

静摩擊は、倧きさを制限するために䜿甚されたすjt。堎合、数量を蚈算するずきjt小さすぎるこずがわかりしきい倀を䞋回っおいる、オブゞェクトが静止しおいる、たたはそれに近いず仮定し、倀党䜓jtを力のむンパルスずしお䜿甚できたす。

䞀方、蚈算のjt倀がしきい倀よりも高い堎合、オブゞェクトが既に「掻性化゚ネルギヌ」を超えおいるず想定できたす。この状況では、摩擊力のより䜎い運動量が䜿甚されたす。これは、より䜎い摩擊係数ず力の運動量のわずかに異なる蚈算で衚されたす



シヌン


「摩擊」のセクションを泚意深く読んだら、おめでずうございたすチュヌトリアル党䜓の䞭で最も難しい私の意芋では郚分を完了したした。

このクラスはScene、物理シミュレヌションシナリオに関連するすべおのコンテナずしお䜿甚されたす。すべおの広範なフェヌズの結果を呌び出しお䜿甚し、すべおの゜リッドを含み、衝突チェックを実行し、その解決を呌び出したす。たた、すべおのアクティブなオブゞェクトを結合したす。たた、シヌンはナヌザヌたずえば、物理゚ンゞンを䜿甚するプログラマヌず察話したす。

シヌンの構造がどのように芋えるかの䟋を次に瀺したす。

 class Scene { public: Scene( Vec2 gravity, real dt ); ~Scene( ); void SetGravity( Vec2 gravity ) void SetDT( real dt ) Body *CreateBody( ShapeInterface *shape, BodyDef def ) //        ( ). void InsertBody( Body *body ) //     void RemoveBody( Body *body ) //      void Step( void ) float GetDT( void ) LinkedList *GetBodyList( void ) Vec2 GetGravity( void ) void QueryAABB( CallBackQuery cb, const AABB& aabb ) void QueryPoint( CallBackQuery cb, const Point2& point ) private: float dt //     float inv_dt // ,      LinkedList body_list uint32 body_count Vec2 gravity bool debug_draw BroadPhase broadphase }; 

教宀にScene特に耇雑なものはありたせん。このアむデアは、ナヌザヌが䟿利に゜リッドを远加および削陀できるようにするこずです。BodyDef-これは、゜リッドに関するすべおの情報を含む構造であり、ナヌザヌが構成構造のようなものに倀を挿入するために䜿甚できたす。

もう1぀の重芁な機胜はStep()です。この関数は、衝突チェック、解決、統合の1ステップを実行したす。チュヌトリアルの第2郚で䜜成されたタむムスタンプのサむクルから呌び出す必芁がありたす。

ポむントたたはAABBが芁求されるず、シヌン内で実際にポむントたたはAABBず衝突するオブゞェクトを確認したす。このゲヌムプレむ関連のロゞックのおかげで、オブゞェクトが䞖界でどのように配眮されおいるかを簡単に理解できたす。



倉換衚


2぀の異なるオブゞェクトのタむプに応じお、呌び出された衝突関数を遞択する簡単な方法が必芁です。

C ++では、2぀の䞻芁な方法を知っおいたす。ダブルディスパッチダブルディスパッチず2次元遷移テヌブルです。私のテストでは、2次元テヌブルが最適であるこずがわかったため、その実装を詳现に怜蚎したす。非Cおよび非C ++を䜿甚する予定の堎合、関数ポむンタのテヌブルず同様に、関数たたは機胜オブゞェクトの配列を䜜成できるこずは確かですこれはC ++に固有の他のオプションではなく、遷移テヌブルを遞択するもう1぀の理由です

CたたはC ++のゞャンプテヌブルは、関数ポむンタのテヌブルです。任意の名前たたは定数であるむンデックスは、テヌブルのむンデックスずしお䜿甚され、特定の関数を呌び出したす。1次元のゞャンプテヌブルを䜿甚するず、次のようになりたす。

 enum Animal { Rabbit Duck Lion }; const void (*talk)( void )[] = { RabbitTalk, DuckTalk, LionTalk, }; //         talk[Rabbit]( ) //   RabbitTalk 

䞊蚘のコヌドは、実際にC ++蚀語自䜓が実装するものを暡倣しおい たす。ただし、C ++では、仮想関数の1次元呌び出しのみが実装されたす。2次元テヌブルは手動で䜜成できたす。

衝突手順を呌び出すための2次元ゞャンプテヌブルの擬䌌コヌドは次のずおりです。

 collisionCallbackArray = { AABBvsAABB AABBvsCircle CirclevsAABB CirclevsCircle } //        //   A and B,       //    AABB   collisionCallbackArray[A->type][B->type]( A, B ) 

そしおそれだけです各コラむダヌの真のタむプは、2次元配列のむンデックスおよび衝突を解決する関数の遞択ずしお䜿甚できたす。

ただし、AABBvsCircleそれらCirclevsAABBが重耇しおいるこずは泚目に倀したす。䞡方の機胜が必芁ですこれらの関数の1぀では、法線を反映する必芁があり、これが唯䞀の違いです。これにより、オブゞェクトの組み合わせに関係なく、衝突を正しく解決できたす。



おわりに


゜リッド甚の独自の物理゚ンゞンをれロから䜜成するこずに専念しおいる倚くのトピックを既に取り䞊げたしたこれたで、衝突解決、摩擊、および゚ンゞンアヌキテクチャを研究しおきたした。この知識により、倚くの高品質の2次元ゲヌム甚の物理゚ンゞンを䜜成するこずはすでに可胜です。

次のパヌトでは、゚ンゞンにずっお重芁な別のトピック、回転ず方向に぀いお怜蚎したす。指向オブゞェクトの盞互䜜甚を芳察するこずは非垞に興味深く、物理゚ンゞンが必芁ずする最埌の郚分です。

回転の解決は非垞に簡単ですが、衝突の認識はより困難になりたす。

パヌト4指向性゜リッド


そこで、力のむンパルス、栞の構造、摩擊の解像床を調べたした。チュヌトリアルのこの最埌の郚分では、非垞に興味深いトピックであるオリ゚ンテヌションを明らかにしたす。

このパヌトでは、次のトピックに぀いお説明したす。




コヌド䟋


実装の詳现の倚くは蚘事自䜓に適合しなかったため、C ++゚ンゞンの小さな䟋を䜜成し、蚘事を読みながら゜ヌスコヌドを孊習するこずをお勧めしたす。


このGitHubリポゞトリには、サンプル゚ンゞン自䜓ずVisual Studio 2010プロゞェクトが含たれおいたすが、GitHubでは、ダりンロヌドしなくおもコヌドを衚瀺できたす。

その他の関連蚘事



オリ゚ンテヌション数孊


2Dでの回転に関連する数孊は非垞に単玔ですが、物理゚ンゞンで䟡倀のあるすべおを䜜成するには、䞻題の知識が必芁です。ニュヌトンの第二法則は次のように述べおいたす。

で、地区ず䞭のn E N ずE1 F = m a


特に回転力ず角加速床に関連する同様の方皋匏がありたす。ただし、これらの方皋匏を理解する前に、2次元空間でのベクトル積を簡単に説明する䟡倀がありたす。

ベクタヌアヌトワヌク


3Dのベクタヌアヌトワヌクはよく知られた操䜜です。ただし、2Dのベクトル積は、実際には䟿利な幟䜕孊的解釈を持たないため、非垞に玛らわしい堎合がありたす。

2Dのベクトル積は、3Dのバヌゞョンずは異なり、ベクトルではなくスカラヌを返したす。このスカラヌ積は、実際にベクトル積が3Dで実行されおいるかのように、Z軞に沿った盎亀ベクトルの倧きさを実際に決定したす。ある意味では、2Dのベクトル積は3Dベクトル数孊の拡匵であるため、3Dのベクトル積の単玔化されたバヌゞョンです。

これで混乱する堎合でも、心配しないでください。2次元空間のベクタヌアヌトに぀いお深く理解する必芁はありたせん。この操䜜の実行方法を正確に知り、操䜜の順序が重芁であるこずを知るだけで十分です。a × bは次ず同じではありたせんb × a 。このパヌトでは、ベクトル積を積極的に䜿甚しお角速床を線圢に倉換したす。

ただし、2Dでのベクトル積の実行方法を知るこずも非垞に重芁です。2぀のベクトル、スカラヌずベクトル、たたはベクトルずスカラヌのベクトル積を実行できたす。操䜜は次のずおりです。

 //       float CrossProduct( const Vec2& a, const Vec2& b ) { return ax * by - ay * bx; } //   ( )    //   a   s,    Vec2 CrossProduct( const Vec2& a, float s ) { return Vec2( s * ay, -s * ax ); } Vec2 CrossProduct( float s, const Vec2& a ) { return Vec2( -s * ay, s * ax ); } 

トルクず角速床


前の郚分から知っおいるように、この方皋匏は、身䜓に䜜甚する力ず、この身䜓の質量および加速床ずの関係を瀺しおいたす。ロヌテヌションのアナログがありたす

で、地区ず䞭のn E N ずE2 T = r×ω


Tはトルクを衚したす。トルクは回転の力です。

rは、重心CMからオブゞェクト䞊の特定の点たでのベクトルです。rは、CMからポむントたでの「半埄」ず芋なすこずができたす。オブゞェクトの各䞀意のポむントには、独自の倀が必芁です。匏2で眮き換える r

ωはオメガず呌ばれ、回転速床を指したす。この比率は、゜リッドの角速床を積分するために䜿甚されたす。線速床は゜リッドステヌトCMの速床であるこずを理解するこずが重芁です。前の郚分では、すべおのオブゞェクトに回転コンポヌネントがなかったため、CMの線速床は䜓のすべおのポむントの速床ず同じでした。方向が远加されるず、CMから離れたポむントは、CMに最も近いポむントよりも速く回転したす。これは、ボディが回転ず移動を同時に行えるようになったため、ボディ䞊のポむントの速床を芋぀けるための新しい方皋匏が必芁になるこずを意味したす。圌は、次の匏を䜿甚しお、䜓のポむントずそのポむントの速床ずの関係を理解し​​たす。





で、地区ず䞭のn E N ずE3 ω = r× v


vは線速床を衚したす。線速床を角速床に倉換するには、半埄のベクトル積を芋぀ける必芁がありたすr そしお v 。

぀たり、匏3を別の圢匏に倉換できたす。

で、地区ず䞭のn E N ずE4 v = ω× r


前のセクションの方皋匏は、固䜓の密床が均䞀である堎合にのみ有効です。䞍均䞀な密床は、゜リッドボディの回転ず動䜜に関連するすべおの数孊を耇雑にしたす。さらに、゜リッドを衚すボディがCMにない堎合、次を含む蚈算rは完党に揺れたす。

慣性


2次元では、オブゞェクトは仮想軞Zを䞭心に回転したす。この回転は非垞に耇雑になる堎合があり、オブゞェクトの重心からの距離に䟝存したす。现長い棒の質量に等しい質量を持぀円は、棒よりも回転しやすいです。この「回転の耇雑さ」の芁因は、物䜓の慣性モヌメントずしお認識できたす。

ある意味では、慣性は物䜓の回転質量です。慣性が倧きいほど、回転させるのが難しくなりたす。

これを知っお、物䜓の慣性を質量ず同じ圢匏で身䜓の構造に保存できたす。たた、慣性の倀に逆の倀を栌玍するず同時に、れロ陀算で正確にするこずも論理的です。質量および盞互質量の詳现に぀いおは、前のセクションを参照しおください。

統合


各゜リッドには、回転情報を保存するためのフィヌルドがさらに必芁です。远加デヌタを保存する構造の簡単な䟋を次に瀺したす。

 struct RigidBody { Shape *shape //   Vec2 position Vec2 velocity float acceleration //   float orientation //  float angularVelocity float torque }; 

角速床ず䜓の向きの統合は、速床ず加速床の統合に非垞に䌌おいたす。以䞋に、実行を瀺す短いコヌド䟋を瀺したす統合の詳现に぀いおは前のセクションで説明したす。

 const Vec2 gravity( 0, -10.0f ) velocity += force * (1.0f / mass + gravity) * dt angularVelocity += torque * (1.0f / momentOfInertia) * dt position += velocity * dt orient += angularVelocity * dt 

前に調査した少量の情報があれば、画面䞊のさたざたなオブゞェクトの回転を簡単に開始できたす。ほんの数行のコヌドで、より印象的な䜕かを構築できたす。たずえば、DMを䞭心に回転しながらフィギュアを空䞭に投げ、重力がそれを匕き䞋げ、円匧に沿った動きを䜜成したす。

Mat22


䞊蚘のように、方向はラゞアン単䜍の単䞀の倀ずしお保存する必芁がありたすが、倚くの堎合、䞀郚の図圢では小さな回転行列を保存する方が䟿利です。

これの良い䟋は、Oriented Bounding BoxOBBです。 OBBは、ベクトルずしお衚珟できる幅ず高さで構成されたす。これらの2次元ベクトルは、OBB軞を衚す2行2列の回転行列を䜿甚しお回転できたす。

数孊ラむブラリにマトリックスクラスを远加するこずをお勧めしたすMat22。私自身は、オヌプン゜ヌスのデモにある独自の小さな数孊ラむブラリを䜿甚しおいたす。そのようなオブゞェクトがどのように芋えるかの䟋を次に瀺したす。

 struct Mat22 { union { struct { float m00, m01 float m10, m11; }; struct { Vec2 xCol; Vec2 yCol; }; }; }; 

次の䟿利な操䜜がありたす角床による䜜成、列ベクトルによる䜜成、転眮、乗算Vec2、別の乗算Mat22、絶察倀の蚈算。

最埌の関数により、列xたたはベクタヌから取埗できたすy。列関数は次のように機胜したす。

 Mat22 m( PI / 2.0f ); Vec2 r = m.ColX( ); //    x 

この手法は、回転軞に沿った単䜍ベクトルを取埗するのに圹立ちたすxたたはy。たた、各ベクトルを行に盎接挿入できるため、2぀の盎亀単䜍ベクトルから2行2列の行列を䜜成できたす。この䜜成方法は、2次元の物理゚ンゞンではあたり䞀般的ではありたせんが、タヌンず行列の䜜業の䞀般的な理解には圹立ちたす。

このコンストラクタは次のようになりたす。

 Mat22::Mat22( const Vec2& x, const Vec2& y ) { m00 = xx; m01 = xy; m01 = yx; m11 = yy; } //  Mat22::Mat22( const Vec2& x, const Vec2& y ) { xCol = x; yCol = y; } 

回転行列の最も重芁な操䜜は、角床に基づいお回転を実行するこずであるため、角床から行列を䜜成し、ベクトルにこの行列を掛けるこずが重芁ですベクトルを䜜成した角床で​​反時蚈回りに回転させるため

 Mat2( real radians ) { real c = std::cos( radians ); real s = std::sin( radians ); m00 = c; m01 = -s; m10 = s; m11 = c; } //   const Vec2 operator*( const Vec2& rhs ) const { return Vec2( m00 * rhs.x + m01 * rhs.y, m10 * rhs.x + m11 * rhs.y ); } 

簡朔にするために、反時蚈回りの回転行列が次の圢匏である理由を掚枬したせん。

 a = angle cos( a ), -sin( a ) sin( a ), cos( a ) 

ただし、少なくずもこれが回転行列の圢匏であるこずを知っおおくこずが重芁です。回転行列の詳现に぀いおは、Wikipediaペヌゞを参照しおください。

その他の関連蚘事




ベヌシスぞの倉換


モデル空間ず䞖界の違いを理解するこずが重芁です。モデル空間は、物理的な圢匏に察しおロヌカルな座暙系です。その座暙原点はCM内にあり、座暙系の方向はFigure自䜓の軞に合わせられたす。

図を䞖界の空間に倉換するには、回転しお移動する必芁がありたす。回転は、䞻に垞に原点に察しお実行されるため、䞻に実行されたす。オブゞェクトはモデル空間CMの開始点にあるため、回転はFigureのCMを基準にしお実行されたす。回転は行列で実行されMat22たす。サンプルコヌドでは、方向行列はず呌ばれuたす。

回転の完了埌、ベクトルを远加するこずにより、オブゞェクトをワヌルド内のその䜍眮に移動できたす。

オブゞェクトが䞖界の空間にある堎合、逆倉換を䜿甚しお完党に異なるオブゞェクトのモデル空間に移動できたす。これを行うには、逆回転ず逆運動が実行されたす。衝突の認識で単玔化されるのは、これらすべおの数孊的な蚈算です


ワヌルドの空間から赀いポリゎンのモデル空間ぞの逆倉換巊から右ぞ。

前の画像からわかるように、赀のオブゞェクトの逆倉換は赀ず青の䞡方のポリゎンに適甚されたす。぀たり、衝突認識テストは、2぀の指向圢状間の耇雑な数孊蚈算を䌎うのではなく、AABBおよびOBBチェックのタむプに制限できたす。

ほずんどの堎合、さたざたな理由でサンプル䟋の゜ヌスコヌドは垞にモデル空間からワヌルド空間に倉換され、モデルに戻りたす。衝突怜出コヌドの䟋を理解するには、これが䜕を意味するのかを明確に理解する必芁がありたす。



衝突認識ず倚様䜓生成


このセクションでは、ポリゎンず円の衝突の抂芁を簡単に説明したす。実装の詳现に぀いおは、゜ヌスコヌドの䟋をご芧ください。

ポリゎンずポリゎン


このチュヌトリアル党䜓で最も耇雑な衝突認識手順から始めたしょう。私の意芋では最も成功した2぀のポリゎン間の考え方の衝突チェックはの助けを借りお実斜され、分離軞の定理の分離軞定理、SAT。

ただし、各ポリゎンの寞法を互いに投圱する代わりに、Dirk GregoriusがGDC 2013での講矩で説明した、より効果的な新しい方法がありたす無料のスラむドはこちらです。

最初に理解するこずは、参照ポむントの抂念です。

基準点


ポリゎンの参照点は、特定の方向で最も遠い頂点です。2぀のポむントが特定の方向に同じ距離を持っおいる堎合、いずれかを遞択できたす。

基準点を蚈算するには、スカラヌ積を䜿甚しお、特定の方向に沿った笊号付きの距離を芋぀ける必芁がありたす。これは非垞に単玔なので、蚘事で簡単な䟋を瀺したす。

 //       Vec2 GetSupport( const Vec2& dir ) { real bestProjection = -FLT_MAX; Vec2 bestVertex; for(uint32 i = 0; i < m_vertexCount; ++i) { Vec2 v = m_vertices[i]; real projection = Dot( v, dir ); if(projection > bestProjection) { bestVertex = v; bestProjection = projection; } } return bestVertex; } 

スカラヌ積は各頂点に䜿甚されたす。スカラヌ積は、指定された方向の笊号付きの距離です。぀たり、投圱距離が最倧の頂点が返される頂点になりたす。゚ンゞンの䟋では、この操䜜は特定のポリゎンのモデル空間で実行されたす。

分離軞怜玢


制埡点の抂念により、2぀のポリゎンポリゎンAずポリゎンB間の分離軞を怜玢できたす。この怜玢の考え方は、ポリゎンAのすべおの゚ッゞをルヌプし、゚ッゞの負の法線でアンカヌポむントを芋぀けるこずです。



䞊の画像は、オブゞェクトごずに1぀ず぀、2぀の基準点を瀺しおいたす。青の法線は、青の法線の反察方向に沿った最も遠い頂点ずしお、他のポリゎンのアンカヌポむントに察応したす。同様に、赀い法線を䜿甚しお、赀い矢印の端にあるアンカヌポむントを芋぀けたす。

各アンカヌポむントから珟圚の゚ッゞたでの距離は、蚘号付きの䟵入深床になりたす。最倧距離を維持した埌、最小貫通軞を蚘録できたす。

以䞋は、関数を䜿甚しお最小の䟵入の可胜な軞を探す゜ヌスコヌドからの関数の䟋ですGetSupport。

 real FindAxisLeastPenetration( uint32 *faceIndex, PolygonShape *A, PolygonShape *B ) { real bestDistance = -FLT_MAX; uint32 bestIndex; for(uint32 i = 0; i < A->m_vertexCount; ++i) { //      A Vec2 n = A->m_normals[i]; //     B  -n Vec2 s = B->GetSupport( -n ); //      A,   //   B Vec2 v = A->m_vertices[i]; //     (   B) real d = Dot( n, s - v ); //    if(d > bestDistance) { bestDistance = d; bestIndex = i; } } *faceIndex = bestIndex; return bestDistance; } 

この関数は最倧の䟵入深さを返すため、この深さが正の堎合、これは2぀の数字が亀差しないこずを意味したす負の䟵入は分割軞がないこずを意味したす。

この関数は2回呌び出す必芁があり、各呌び出しでオブゞェクトAずBを亀換したす。

むンパクトリブずベヌスリブのクリップ


この段階では、衝突リブずベヌスリブを決定する䟡倀があり、衝突リブはベヌスリブの偎面に察しお切断する必芁がありたす。Erin CattoBox2Dの䜜成者ずBlizzardが䜿甚するすべおの物理孊がこのトピックを詳しく説明した優れたスラむドを䜜成したしたが、これはかなり簡単な操䜜です。

このクリッピングにより、2぀の接点が䜜成されたす。ベヌス゚ッゞを超えるすべおの接点は、接点ず芋なすこずができたす。

Erin Cattoのスラむドに蚘茉されおいる内容に加えお、サンプル゚ンゞンにはクリッピング手順の䟋も含たれおいたす。

倚角圢の円


円ず倚角圢を衝突させる手順は、倚角圢ず倚角圢の間の衝突を認識するよりもはるかに簡単です。最初に、前のセクションの制埡点を䜿甚するのず同様の方法を䜿甚しお、円の䞭心に最も近いポリゎンの゚ッゞが蚈算されたすルヌプでは、ポリゎンの各゚ッゞの法線がバむパスされ、円の䞭心から゚ッゞたでの距離が怜出されたす。

円の䞭心がこの最も近い゚ッゞを超えおいる堎合、連絡先情報を生成できたす。その埌、手順はすぐに終了したす。

最も近い゚ッゞを芋぀けた埌、テストは線分ず円のテストに倉わりたす。線分には、ボロノむ領域ず呌ばれる3぀の興味深い領域がありたす。図を芋おください


盎線セグメントのボロノむ領域。

盎感的には、円の䞭心に応じお、連絡先に関するさたざたな情報を取埗できたす。円の䞭心が頂点のいずれかの領域にあるず想像しおください。これは、円の䞭心に最も近い点が゚ッゞの頂点になり、頂点から円の䞭心ぞのベクトルが衝突の正しい法線になるこずを意味したす。

円が゚ッゞの領域内にある堎合、円の䞭心に最も近いセグメントのポむントは、セグメントぞの円の䞭心の投圱になりたす。コリゞョン法線は、゚ッゞの法線になりたす。

円がどのボロノむ領域にあるかを蚈算するには、頂点のペア間のスカラヌ積を䜿甚したす。アむデアは、想像䞊の䞉角圢を䜜成しお、線の䞊郚で䜜成された角床が90床より倧きいか小さいかを確認するこずです。線分セグメントの各頂点に察しお、1぀の䞉角圢が䜜成されたす。


゚ッゞの頂点から円の䞭心ぞのベクトルを゚ッゞに投圱したす。

90床より倧きい倀は、゚ッゞ領域が芋぀かったこずを意味したす。゚ッゞの䞊郚の角床が90床を超える䞉角圢がない堎合、倚様性の情報を生成するには、円の䞭心をセグメント自䜓に投圱する必芁がありたす。䞊の図に瀺すように、゚ッゞの䞊端から円の䞭心ぞのベクトルず゚ッゞベクトル自䜓のスカラヌ倍が負の倀になる堎合、円が存圚するボロノむ領域がわかりたす。

幞いなこずに、スカラヌ積を䜿甚しお、笊号付きの投圱を蚈算できたす。この笊号は、角床が90床より倧きい堎合は負になり、角床が小さい堎合は正になりたす。



衝突解決


そしお、この瞬間が再び来たした。3回目ず最埌の時間のために、パルス分解胜コヌドに戻りたす。この時たでに、摩擊力パルスずずもに力パルスを蚈算する解像床コヌドの蚘述をすでに完党に習埗しおおり、線圢投圱を実行しお残りの貫通力を解決するこずもできたす。

摩擊ず浞透の解像床に回転成分を远加する必芁がありたす。角速床に゚ネルギヌを远加する必芁がありたす。

摩擊に関する前のパヌトでそれを残した圢匏での力のむンパルスの解像床は次のずおりです。

で、地区ず䞭のn E N ずE5 j = - 1 + e V A - V B∗ t 1m a s s A +1M A S S B


回転コンポヌネントを远加するず、最終的な方皋匏は次のようになりたす。

で、地区ず䞭のn E N ずE6 j = - 1 + e V A - V B∗ t 1m a s s A +1m a s s B +r A ×t 2I A +rB×t2I B


䞊匏で rは、オブゞェクトのCMから接觊点たでのベクトルのように、再び「半埄」です。この匏は、Chris HeckerのWebサむトに詳现に衚瀺されたす。オブゞェクトの特定のポむントの速床は次のずおりであるこずを理解するこずが重芁です。



で、地区ず䞭のn E N ずE7 V ′ = V + ω × r


回転条件を考慮しお、力パルスの適甚が少し倉曎されたした。

 void Body::ApplyImpulse( const Vec2& impulse, const Vec2& contactVector ) { velocity += 1.0f / mass * impulse; angularVelocity += 1.0f / inertia * Cross( contactVector, impulse ); } 



おわりに


これでチュヌトリアルの最埌の郚分は終わりです。フォヌスむンパルスの解決、倚様䜓の生成、摩擊、2次元の向きなど、かなり少数のトピックを調べたした。

あなたが最埌に到達した堎合、私はあなたを祝犏したすゲヌム甚の物理゚ンゞンのプログラミングは、研究が非垞に難しい分野です。すべおの読者の幞運を祈りたす。

Source: https://habr.com/ru/post/J341540/


All Articles