Kolize a následná reakce

Z CHWiki

Přejít na: navigace, hledání

Obsah

[editovat] Úvodník

Minulý článek vám doufám poskytl základní znalosti pro rozhýbání těles. Dnešní článek naváže popisem zjišťování kolizí v 3D prostoru a následné fyzikální reakce.

Seriál obsahuje velké množství výpočtů a algoritmů. Pustíte-li se do implementace herní fyziky pro 3D hru, musíte se přibližně takovým množstvím informací prokousat a nikdo to za vás neudělá. Cílem seriálu není naučit čtenáře naprogramovat fyziku, ani se nesnaží být jediným a dostačujícím informačním zdrojem. Rád bych předložil jakýsi výtah či přehled doplněný o vysvětlení principu, který by mohl posloužit jako reference při hledání různých jiných (většinou zahraničních) materiálů na internetu. Proto nečtěte text "jedním dechem", ale berte ho jako souhrn zkušeností, které lze použít časem. Jsou to zkušenosti, nabrané během asi půl roku, během nichž jsem implementoval fyziku pro naši hru Aquadelic.

[editovat] Zjištění kolize

Mnohý vývojář při svém prvním setkání s kolizemi zjistí, že vysněné testování mesh vs. mesh je tuze pomalé. Počítejte se mnou. Máme například dva objekty, každý s dvaceti trojúhelníky (jen krychle má 12!). Při kolizním testu se dostáváme v nejhorším případě na 20 * 20 testů trojúhelník versus trojúhelník (kvadratická složitost). Tedy 400 pomalých testů! A bohužel, tento případ nastává tehdy, kdy objekty spolu nekolidují, což je většinu času běhu simulace. Jsou na to různé náplasti, v podobě hierarchických před testů (např. OctTree), ale v praxi jsou i tyto náplasti pomalé. Musíme sáhnout k jinému řešení, aproximaci pomocí různých kolizních primitiv. Kolizními primitivy rozumíme jednoduché objekty, pro které je kolizní test rychlý a pomocí nichž můžeme objekt přibližně poskládat, tedy aproximovat. Nejpoužitelnější jsou v praxi koule a osově zarovnané či libovolně orientované kvádry. Dále můžeme použít pro kolize s terénem testování bod versus výšková mapa. Píšete-li malý kolizní systém pro svou hru, je žádoucí použít méně typů kolizních primitiv. V mém případě to jsou pouze natočené kvádry a koule. Důvod je ten, že musíte naprogramovat testy pro kolize každého primitiva s každým (KouleVsKvádr, KvádrVsKvádr, KouleVsKoule). Představte si třeba 4 typy primitiv. To máme 16 druhů testů, z toho některé jsou stejné (KvádrVsKoule, KouleVsKvádr), takže 10. A to je dost. Stejně nakonec použijete nejčastěji KvádrVsKvádr (viz. Obrázek 1). Image:Kolize CollAppr.jpg Obrázek 1. Přikládám barevný snímek, který jsem pořídil při své plavbě po Řecku. Modré kvádry mají statické kolizní objekty, červené pohyblivé a ta koule za lodí je kolizní objekt herní kamery. Vidíte, že aproximace mostu je v tomto případě velmi nepřesná, narozdíl od lodi. Záleží na typu aplikace, v případě této hry jsou jednoduché kolize dostačující, protože se počítá se srážkami ve velkých rychlostech, kdy nepřesnosti oku uniknou.

Třebaže systém kolizních primitiv používá většina fyzikálních enginů (např. ODE), existují i jiné přístupy. Zmíním hierarchické kulové stromy. Kolize dvou koulí je jednoduchá (rychlá) záležitost, čehož se dá využít. Objektům se vytvoří strom koulí, nejprve jedna velká, která obsahuje další menší (v místech kde objekt má nějaké trojúhelníky), v těch menších další menší a tak dále, až se velikostně dostaneme na akceptovatelný detail. Při testování se postupuje od kořene (největší koule vs. největší koule) a pokud kolidují, testují se koule jim hierarchicky podřazené.

[editovat] Co chceme vlastně zjišťovat?

Při kolizi dvou objektů potřebujeme znát především bod (P), kde ke kolizi došlo, abychom mohli v tomto místě zareagovat. Za druhé musíme znát normálu povrchu v bodě P (N), která určuje správný směr kolizní odezvy (fyzikální reakce). Poslední důležitá informace je hloubka kolize (D). Tedy jak moc jsou objekty zabořeny v sobě ve směru N. Hloubka D slouží k explicitnímu oddělení objektů od sebe. Představte si, že dva objekty se srazí rychlostí 50 m/s (180 km/h). To jsou třeba dvě auta při nehezké čelní srážce. Testujete kolize s nějakým konstantním FPS, třeba 80. Při střetu oněch dvou aut, mohou být v sobě kolizní primitiva zabořena (50 / 80) m, tedy 62,5 cm! Nevíte ale jak moc se od sebe odrazí, třeba vůbec, pohltí-li veškerou energii srážky plechy. Proto musíte znát D a před samotnou odezvou od sebe auta oddělit ve směru N.


[editovat] Kolize koule versus koule

Je-li součet poloměrů koulí větší než vzdálenost mezi středy (A, B), jsou v kolizi. Normála kolize (N) je v tomto případě normalizovaný vektor [A, B]. Hloubka D je rozdíl vzdálenosti a součtu poloměrů. Působiště P zvolte uprostřed průniku obou koulí (vynásobte N prvním z poloměrů zmenšeným o polovinu D, nakonec přičtěte první střed (A), abyste získali bod ve světových souřadnicích).

[editovat] Kolize kvádr versus koule

Kvádr může být libovolně natočený v prostoru. Pro zjednodušení výpočtů je vhodné odstranit tuto rotaci a kouli přenést do lokálních souřadnic kvádru. Přenesení koule do lokálních souřadnic se provede vynásobením jejího středu (C) invertovanou transformační maticí kvádru. Nyní můžeme na celou situaci pohlížet jako na test osově zarovnaného kvádru a koule se středem C'. Tento test je v principu jednoduchý, rozložíme trojrozměrný test na 3 dvojrozměrné boční testy obdélník versus kružnice (vždy jde o pohled z některé osy x, y, či z). Při bočním testu jde o kolizi středu kružnice se zvětšeným obdélníkem o poloměr kružnice (viz. obrázek 2). Jsou-li všechny 3 boční testy splněny, koule a libovolně natočený kvádr spolu kolidují. Image:Kolize BocniKol.gif Obrázek 2. Zelená označuje boční pohled na kvádr, okrová je zvětšení obdélníku o poloměr koule. (Pokud se bod C', tedy střed koule, ocitne v okrové nebo zelené oblasti, pak nastala kolize. )

A nyní pár implementačních detailů a hledání parametrů P, D a N. Střed souřadnic (pivot) umístíme do těžiště kvádru. Souřadné roviny rozdělily kvádr na 8 částí. My si budeme všímat pouze části, která má všechny souřadnice kladné (viz. obrázek 3). Vrchol tohoto malého kvádříku, který neleží na žádné ose (nazvěme ho B), určuje vrcholy všech ostatních částí (kvádr je osově souměrný podle všech tří os, takže když měníme znaménka u jednotlivých složek souřadnic B, získáme tím polohu ostatních vrcholů původního kvádru). Bod B má dále tu vlastnost, že jeho souřadnice (x,y,z) mají přesně velikost poloviny rozměrů původního kvádru (B = 1/2 * (délka původního kvádru, hloubka původního kvádru, výška původního kvádru)). Střed koule C upravíme na bod C' (násobením invertovanou transformační maticí kvádru) a dále nastavíme všechny jeho složky na absolutní hodnotu C' = (|C'[0]|, |C'[1]|, |C'[2]|), čímž jsme si vlastně přesunuli kouli do kladného oktantu (tedy tam kde je bod B). Odečtením absolutní hodnoty středu koule C' od B, získáme vektor S, obsahující vzdálenosti středu koule od stěn kvádru (S = B - |C'|). Jelikož počítáme v absolutních hodnotách, celý test se zjednodušil na test tří stěn, tří hran a jednoho vrcholu (viz. obrázek 3). Uvedu pouze příklady pro osu X:

  • Test stěny X je porovnání S[X] a poloměru koule R.
  • Test hrany rovnoběžné s osou X je porovnání délky vektoru [S[Y], S[Z]] a poloměru R.
  • Test vrcholu je porovnání délky vektoru S a R.

Image:Kolize AbsKvadr.gif Obrázek 3. Kladný prostor kvádru. Ostatní části kvádru mají stejné rozměry, ale jsou nějak zrcadlově převrácené. Bod B je vrchol kvádru s kladnými souřadnicemi, ale zároveň určuje i poloviční rozměry kvádru.

Při testování budeme postupně hledat i bod P' (P v lokálních souřadnicích kvádru). Při splněném testu stěny, posuneme souřadnici bodu P' na onu stěnu. Při nesplněném testu nastavíme souřadnici P' na příslušnou souřadnici středu koule v absolutní hodnotě |C'|. Příkladně pro stěnu X: Je-li S[X] <= R, nastavíme P'[X] = B[X], jinak P'[X] = |C'[X]|. Podobně postupujeme i pro testy hran. Kolize hrany rovnoběžné s osou X značí, že bod P' leží na stěnách Y a Z. Tedy je-li délka [S[Y], S[Z]] <= R bude P'[Y] = B[Y] a P'[Z] = B[Z]. A nakonec analogicky pro vrchol. Je-li koule v kolizi s vrcholem (délka S < R), bude bod kolize P' přímo B. Pokud jste nepochopili tento princip, přečtěte si tento odstavec ještě jednou a dívejte se přitom na obrázek 3.

Nyní víme, zda došlo ke kolizi a máme bod kolize v lokálních souřadnicích kvádru (P'), ale v absolutních hodnotách. Zbavit se absolutní hodnoty a získat opravdový P' je triviální záležitost. Nastavíme bodu P' znaménka bodu C'. K výpočtu hloubky kolize D a normály (v souřadnicích kvádru) N' použijeme vektor [C', P']. Tedy směr mezi bodem kolize a středem koule. Jeho směr je N', jeho délka mínus poloměr je D. Nakonec transformujeme bod a normálu kolize z lokálních do světových souřadnic vynásobením světovou transformační maticí kvádru.


[editovat] Kvádr versus kvádr a další objekty

Podobně jako u testu koule a kvádru se můžeme dívat z více projekcí i na situaci dvou kvádrů. V algoritmu, který popíšu se dokonce na kvádry díváme v jednom rozměru, promítáme je na jednotlivé osy. Na každé ose vznikne promítnutím kvádru interval. Dokud se tyto intervaly překrývají, pokračujeme, teprve když najdeme první intervaly kde se kvádry nepřekrývají, víme bezpečně, že ke kolizi nedošlo. Pro pochopení si nakreslete dva osově zarovnané obdélníky v rovině a promítněte je na osu x a y. Pokud se na x i y intervaly překrývají, máme kolizi. Tomuto principu se říká SAT (Separtion Axis Theorem) a je použitelný pouze pro konvexní objekty. Jak jsem již předeslal, tato teorie říká, že pokud konvexní objekty nekolidují, existuje alespoň jedna osa, na které se jejich projekce nepřekrývá. Jenže které osy si vybrat, je jich k testování nekonečně mnoho a X Y a Z nestačí. Vezměte si dvě krabičky zápalek a zkuste najít pozici, kdy budou v zákrytu ze všech tří na sebe kolmých pohledů, ale přesto se dotýkat nebudou. Najdete ji rychle. Které osy tedy použít k testům? Jsou to osy rovnoběžné s hranami jednotlivých objektů (což se dá snadno představit) a osy vzniklé vektorovým součinem (CrossProduct) hran jednoho objektu s hranami druhého objektu (v dvojrozměrném prostoru to není nutné, ovšem ve 3D ano). Takže budeme testovat osy obou kvádrů A a B, jelikož jsou rovnoběžné s hranami, dále jejich vzájemný CrossProduct. To jsou 3 osy pro kvádr A, 3 pro kvádr B a 3 krát 3 osy vzniklé vektorovým součinem mezi nimi. Celkem tedy 15 testů.

Výpočet intervalu pro kvádr A na ose Axis:

V každém testu promítáme kvádr na osu a zjišťujeme interval (min, max), který na této ose zabírá. Poté oba intervaly porovnáme a zjistíme, zda došlo k překryvu.

Nejprve promítnu na osu střed C kvádru. C = VectorDotProduct(A.Center, Axis) Podobně se promítnou i rozměry kvádru a vznikne jakýsi radius R

R =
    Abs(VectorDotProduct(A.DirectionX * A.HalfSize[0], Axis)) +
    Abs(VectorDotProduct(A.DirectionY * A.HalfSize[1], Axis)) +
    Abs(VectorDotProduct(A.DirectionZ * A.HalfSize[2], Axis))

HalfSize je poloviční velikost kvádru. DirectionXYZ je orientace kvádru v prostoru. Orientaci a pozici můžete získat ze světové transformační matice. První sloupec matice je DirectionX, druhý DirectionY, třetí DirectionZ a poslední je pozice.

Interval pro kvádr A [A_Min, A_Max] je pak roven [C - R, C + R]. Stejně postupujeme pro kvádr B. Pokud nedošlo k překryvu, tedy ((A_Min > B_Max) nebo (B_Min > A_Max)), končíme s testem, kvádry nekolidují. Naopak, pokud všechny osy vykazují překryv, jsou kvádry v kolizi.

Dále potřebujeme znát, kde došlo ke kolizi (P), jak hluboká je penetrace (D) a jaký směr má kolize (N). Začneme s D a N. Výsledky Min a Max si při výpočtu uložíme pro každou osu. Při kolizi je zde 15 výsledků Min a Max pro 15 os. Tam, kde je překryv intervalů min a max nejmenší, tam je objekt zabořen nejméně a tím směrem chceme reagovat na kolizi (tím směrem je chceme odsunout). Nakreslete si dva obdélníky v ploše, které se na jedné z os budou překrývat zanedbatelně a na druhé hodně. Hned poznáte, že tento přístup je správný. Najdeme tedy osu s nejmenším překryvem a vrátíme tento překryv coby hloubku D a samotnou osu jako normálu kolize N.

Výpočet bodu P (bohužel pro vás) trochu odbudu. Bod P se dá jistě vypočíst na základě dat z uvedeného SAT algoritmu, ale zatím se mi to nepodařilo. Doteď (a nejspíš navždy) používám průsečíky stran jednoho kvádru se stěnami druhého. Tyto průsečíky zprůměruji a výsledek je P. Jde vlastně o další typ testu kvádr vs kvádr. Opět používám trik, kdy jeden kvádr transformuji do prostoru druhého kvádru a tím se výpočty dají trochu "proškrtat". Možná se ptáte, proč nepoužít tento druh testu primárně pro kolizi? Odpovídám: není tak elegantní (jako SAT), je pomalejší a nehodí se pro nalezení hloubky a normály. Navíc tento druh testu musí být použit dvakrát, první kvádr s druhým a druhý s prvním, protože jeden roh kvádru může do druhého kvádru zasahovat třeba uprostřed stěny a tím pádem žádná hrana z druhého neprotíná první kvádr. Nicméně naprogramovat zjištění bodu P pomocí této druhé metody není těžké a funguje. Takže proč ne?

[editovat] Výšková mapa versus bod

Kolidovat s výškovou mapou a tedy například s terénem je velmi snadné. Stačí dvě funkce pro zjištění výšky na terénu v nějakém bodě a funkce pro zjištění normály povrchu terénu v nějakém bodě. Pak se již zeptáte, zda-li bod leží pod terénem či ne a v případě že ano, vrátíte rozdíl těchto výšek jako hloubku D, zjistíte si normálu povrchu z výškové mapy a máte N. Jako bod kolize P vrátíte právě zjišťovaný bod, ale upravíte jeho výšku tak, aby ležel na terénu.

[editovat] Reakce na kolizi

Při každém fyzikálním kroku může dojít ke kolizím a vznikne tak sběr kolizních kontaktů. Každý kontakt obsahuje tvrdě vydobyté informace N, D a P. Navíc samozřejmě ukazatele na kolidující objekty, přičemž platí, že první objekt je vždy pohyblivý (dynamický), druhý může být dynamický, nebo statický. Normála musí ukazovat ve směru prvního objektu (aby v tom nebyl zmatek a nestalo se, že reakce na kolizi naopak vtáhne objekty do sebe). Kolizní kontakty bude řešit fyzikální solver. Práce solveru bude vypadat takto:

  • Vyřešení průniků (pomocí normály kolize N a hloubky penetrace D)
  • Reakce na kolize
  • Výpočet sil působících na tělesa
  • Pohyb těles (numerická integrace)
  • Zjištění kolizí

Vzhledem k tomu, že smyčka simulace běží pořád dokola, mohou být jednotlivé fáze posunuty jinak. Jde hlavně o to, aby se nejprve vyřešily průniky, následně provedla reakce na kolize, poté integrace a teprve pak další zjištění kolizí.

[editovat] Vyřešení průniků

Důvod k explicitnímu řešení průniků jsem popsal výše v sekci "Co chceme vlastně zjišťovat?", proto se k tomu nebudu již vracet. Průnik vyřešíte prostým posunem objektů ve směrech N a -N od sebe na vzdálenost D * 0.5. Je-li jeden z objektů statický, třeba nějaká budova, tak se samozřejmě posouvat nebude. Máte-li ve scéně objekty velmi rozličných hmotností, výrazně doporučuji neodsunovat je v pevném poměru 1:1 (D * 0.5), ale podle hmotností. Vypadá to přirozeněji. Představte si, že by malý kanistr spadl na nákladní auto a odsunoval ho kamsi pryč. Častá otázka je: "Co se stane, když objekt vysunu a tím vysunutím jej zasunu do jiného objektu?". Praxe ukázala, že není třeba se tím trápit. V příštím časovém kroku se zase vysunou. Vzhledem k tomu, že objekty budou ještě mít nějakou fyzikální reakci, tak se od sebe nakonec za pár snímků dostanou, ne-li hned.

[editovat] Samotná reakce

Při srážce dvou objektů vzniká kolizní kontakt. V kolizním kontaktu (P) se při srážce vynuluje relativní rychlost objektů. Takové srážce říkáme dokonale nepružná srážka. Můžeme objekty odrazit plnou rychlostí jakou se srazili, tomu se říká dokonale pružná srážka. Reálný případ je ten, kdy se tělesa odrazí menší rychlostí než se srazily. U všech typů srážek potřebujeme znát relativní rychlost v bodě P a umět tuto relativní rychlost v P také nastavit. Nejdříve se nutně budeme věnovat relativní rychlosti těles při srážce.


[editovat] Získání rychlosti objektu v bodě P

Pokud vykonává objekt pouze translační pohyb (netočí se, jen posouvá), mají všechny jeho body rychlost těžiště (V). Ovšem při rotaci musíme připočítat dráhovou rychlost bodu P. Ve dvojrozměrném prostou je vztah mezi úhlovou a dráhovou rychlostí definován takto: Vel = AngVel * r Vel je dráhová rychlost bodů ve vzdálenosti r od osy otáčení, AngVel je úhlová rychlost.

Ve 3D stačí od bodu P, který je dosud ve světových souřadnicích, odečíst pozici těžiště a získáme vektor P', který obsahuje vzdálenost těžiště. Dráhová rychlost je pak: Vel = AngVel x P' (x je vektorový součin) K rychlosti těžiště V můžeme nyní přičíst rychlost Vel a dostáváme VP, tedy rychlost bodu P. Pro pořádek uvedu celý vzorec pro získání rychlosti bodu P na objektu ve 3D: VP = V + (AngVel x (P - C)) C je pozice těžiště Pozor na transformace z prostoru objektu do prostoru světa a opačně. Rychlost V a/nebo AngVel může být v lokálních souřadnicích, záleží na vaší implementaci. Cílem je, získat VP ve světových souřadnicích.


[editovat] Relativní rychlost objektů v bodě P

Odečtením obou vektorů rychlosti v bodě P, získáme relativní rychlost v kolizním kontaktu. Vrel = VP1 - VP2

Nyní ještě promítneme Vrel na normálu kolize N, abychom věděli, jaká je relativní rychlost ve směru kolize. rel = VectorDotProduct(Vrel, N)

Je-li rel > 0, nebudeme na kolizi reagovat, objekty jdou od sebe, blíži-li se rel 0, kontakt je v klidu (tyto kontakty se také počítají), ale nás bude zajímat nejvíc situace, kdy je rel < 0 a je potřeba rázně zareagovat.


[editovat] Hybnost tělesa a impuls síly

Přichází druhá část výpočtu odrazu těles, nastavení relativní rychlosti. Pro pochopení principu začneme s jedním objektem, jen s lineární složkou pohybu a pouhým vynulováním. Je to tedy perfektně nepružná srážka bodu s něčím nehybným. Představte si kuličku, kterou hodíte na podlahu a ona se po dopadu zastaví a stojí, to je náš jednoduchý případ. Můžeme samozřejmě po zjištění kolize nastavit rychlost = 0, ale my použijeme vzorec pro změnu hybnosti hmotného bodu p=m*v (m je hmotnost a v rychlost). Dosadíme-li rychlost kuličky V při dopadu (rychlost kolize), získáme impuls hybnosti p (1), kterým změníme rychlost kuličky V (2).

(1) p = m * V (2) V = V - (p / m) tedy V = V - ((m* V) / m) V = V - V V = 0 V tomto případě, kdy kulička spadne na nehybnou podlahu, bude po dosazení a vypočítání rychlost kuličky V = 0 a o to šlo. Můžeme nyní přistoupit ke srážce dvou těles. Již známe rychlost v kolizním kontaktu rel (viz pár odstavců výš) a tu můžeme rozložit zpět na dvě složky, pro každý objekt jednu rel = v1 + v2. Dosazením za v1 a v2 získáme rel = (p / m1) + (p / m2) a po úpravě vyjde

p = (rel * m1 * m2) / (m1 + m2) 

Nyní lze p opět aplikovat na každý objekt v opačném směru: v1 = v1 - (p / m1) v2 = v2 + (p / m2)

Dostaneme přesně vynulování kolize, kolizi bez odrazu. Násobením p číslem větším než 1, získáme odrazy. 2 odrazí objekty takovou rychlostí s jakou se srazily. Faktor odrazu si můžete uložit do tabulky pro různé typy objektů, nebo jednoduše zprůměrovat faktor odrazivosti povrchu obou objektů. p = odraz * (rel * m1 * m2) / (m1 + m2) v1 = v1 - (p / m1) v2 = v2 + (p / m2)

Při pohledu na vzorce vidíte, že lehčí objekt změní svou rychlost více, než těžší. To bylo cílem mise. Uvedené vzorce platí pro jednorozměrný případ. Ve 2D a 3D musíme samozřejmě nastavit směr p podle normály kolize N. Tyto vzorce se dají použít pro kolizi koulí s hladkým povrchem (bez tření, které by mohlo způsobit rotaci).


[editovat] Rotační složka

Při srážce těles libovolného tvaru většinou nastane situace, kdy směr kolizní odezvy neprochází těžišti objektů. Jelikož silový impuls nepůsobí proti těžišti, vzniká moment mající za následek změnu rotace tělesa (změnu úhlové rychlosti). Představte si, že vidíte ozubené kolečko, které se točí nějakou úhlovou rychlostí. Kolečko je pevně přišroubováno k něčemu pevnému, takže je situace dvojrozměrná, s pevnou osou rotace. Najednou mezi točicí se zuby skočí západka, která ihned zastaví pohyb kolečka. Došlo ke kolizi, při které byla vynulována úhlová rychlost kola. Minulý článek jsem mluvil o analogii mezi točivým momentem a silou, momentem setrvačnosti a hmotností, úhlovou rychlostí a rychlostí těžiště. Když se přidržím těchto analogií, můžu napsat podobný vzorec impulsu hybnosti, ale pro rotaci (nazvu jej pw). pw = J * AngVel Kde J je moment setrvačnosti a AngVel je úhlová rychlost tělesa. Stejně jako u lineární složky bylo cílem vynulovat relativní rychlost pomocí impulsu p, tak i u rotační je cílem vynulovat rychlost impulsem pw. Místo v = v - (p / m), chceme AngVel = AngVel - (pw / J). Dosazením za pw a úpravou získáme vynulování úhlové rychlosti.

pw = J * AngVel AngVel = AngVel - ((J * AngVel) / J) AngVel = AngVel - AngVel AngVel = 0

Západka zaklapla. Místo západky dáme další kolečko. Obě dvě mají nějakou libovolnou úhlovou rychlost. Když kolečka naráz přisuneme k sobě, dojde opět ke kolizi a vynulování relativní rychlosti v bodě kolize, nikoli však úhlové! V místě setkání se zoubky začnou pohybovat stejnou rychlostí a stejným směrem. Je-li AngVel1 úhlová rychlost prvního kolečka a AngVel2 druhého, můžeme s pomocí jejich poloměrů r1 a r2 vypočítat rychlost zoubku prvního i druhého kolečka (v1 = AngVel1 * r1 a v2 = AngVel2 * r2). Velikost relativní rychlosti, kterou chceme zrušit, je rel = v1 + v2.

Podívejte se nyní před tento odstavec a uvidíte vzorec pw = J * AngVel. Postupným dosazováním dostáváme: rel = v1 + v2 rel = (AngVel1 * r1) + (AngVel2 * r2)

rel = ((pw/J1) * r1) + ((pw/J2) * r2)

pw = (rel * J1 * J2) / (r1*J2 + r2*J1) Kde J1 a J2 jsou momenty setrvačnosti koleček, r1 a r2 jsou jejich poloměry a AngVel1 a AngVel2 úhlové rychlosti. Poslední tvar je přesně tvar, který nás zajímá. Přímo pomocí relativní rychlosti kolize rel, určuje impuls pw pro její vynulování. Na obě kolečka aplikujeme pw: AngVel1 = AngVel1 - (pw / J1) AngVel2 = AngVel2 + (pw / J2)

Vidíte opět, že čím má kolečko větší moment setrvačnosti J, tím méně ho impuls ovlivní. Stejně jako u lineární složky odrazu, můžete i do rotační přidat odraz. Rozepisovat nebudu, viz pár odstavců nahoře.

[editovat] Lineární a rotační složka dohromady

Finální část jsem se rozhodl dopsat maličko ležérně, oddechově. Je to z mé strany nutnost, protože veškeré snahy definovat nějaký úplný korektní vzorec pro 3D, skončily neúspěšně nebo neúplně. Tímto se váženému čtenářstvu omlouvám a předkládám pouze hotové věci. Pokud impulsy pro rotační i translační složku pohybu šikovně zkombinujete a zobecníte pro 3D, dostanete nejspíš takový vzorec:

          -odraz * (Dot(Vrel, N))
Impulse = ____________________________________________________________________________
           1/m0 + 1/m1 + (N Dot (II0 * (R0 x N)) x R0) + (N Dot (II1 * (R1 x N)) x R1)

Kde: m0 a m1 jsou hmotnosti kolidujících objektů N je normála kolize R0 a R1 jsou vektory z těžišť objektů do bodu kolize II0 a II1 jsou invertované tensory setrvačnosti objektů ve světových souřadnicích Opět x je vektorový součin. Je zde drobná odlišnost v aplikování výsledného impulsu na objekt:

V = Impulse / Mass 
AngVel = AngVel + (II * (R x Impulse))  

Význam II a R je stejný jako u předchozího vzorce. Vidíte, že tyto tvary jsou již poněkud složitější, než mnou prezentované situace. Princip je ale obdobný.


[editovat] Uzávěr

Nyní, shrnu co byste si měli odnést z dnešního článku. Nemyslím, že by můj popis kolizí byl dostačující pro zdárnou implementaci kolizního systému, ale doufám, že princip jsem ukázal. Snad vám text ukáže cestu při hledání vlastního fyzikálního řešení. Implementovat kolizní systém je pro začátečníka tvrdší oříšek, zvláště co se ladění týče. Přesto si dokážu představit, že i začátečník za krátký čas naprogramuje jednodušší 3D fyzikální solver, který jsem popsal v minulém díle a doplní ho kolizemi koule versus koule, ze kterých poskládá pohyblivé objekty (třeba auta ze šesti koulí). Statické objekty by mohly být třeba kvádry, či dokonce jen obdélníky (pro budovy dostačující). A máme tu hned celkem funkční fyzikální svět. Příští, poslední díl seriálu o fyzice, se bude týkat modelování různých fyzikálních objektů a situací. Kromě mého textu v článku najdete i část od ADragona, který popíše princip pružin a základní pravidla tvorby fyzikálního systému do hry z pohledu návrhu vlastností. Děkuji Tutchekovi za některé korekce a Jaresovi za vzorce v konci článku (které v praxi skutečně fungují). ]semo[

[editovat] Odkazník

něco o kolizní odezvě (a další věci): [[1]] detekování kolize různých kolizních primitiv: [[2]]