2011-09-10

Spyruoklių ir virvių fizika(spring/rope-physics)


                Praeitą kartą panagrinėjome paprasčiausią kietų kūnų fizikos simuliacijos metodą, kai bandėme parašyti lengvasvorį fizikos varikliuką. Šįkart pritaikant tuos pačius principus ir nieko daug nekeičiant pridėsime dar papildomo interaktyvumo mūsų kurtai simuliacijai naudojant – spyruokles(spring physics). Šiame straipsnelyje pagvildensime kaip praktiškai pasinaudoti Huko dėsniu(Hooke‘s Law) kuriant akiai patrauklius efektus. Spyruoklės galima dažnai sutikti ten, kur net galbūt neįsivaizduojate joms esant, pavyzdžiui – virvių ir drabužių simuliacijai, minkštiems kūnams(soft-bodies) – žėlė ir pan. Taip pat naudojant tas pačias spyruokles galima spręsti tą pačią kolizijų atsako problemą(collision response). Ilgą laiką spyruoklės ir minkštų kūnų simuliacija buvo naudojama labai saikingai dėl per mažų skaičiavimo pajėgumų, o šiandien – vis dažniau pastebimos žaidimuose ir demonstracijose. Na, mažiau kalbų – daugiau darbų, bandom pasigilinti.


I. Tamprios spyruoklės - Huko dėsnis (Hooke‘s Law)

                    Iš fizikos kurso ne vienam teko susipažinti su Huko dėsniu tamprumo jėgoms, kurios atsiranda deformuojant kūną, aprašyti. Gerai matyta dėsnio išraiška yra tokia:
            Iš dėsnio žinoma, kad deformuojant kūną, atsiranda priešinga deformacijai jėga tiesiogiai proporcinga absoliučiam kūno pailgėjimui(sutrumpėjimui) x. Koeficientas k – tamprumo koeficientas, k > 0, kuo k didesnis, tuo jėga didesnė ir atvirkščiai. Minusas priekyje rodo, kad jėga yra priešingos krypties nei ta F‘, kuria veikiame(spaudžiame) kūną.

Tamprumo jėga atsirandanti spaudžiant kūną
                Šios savybės gali būti panaudojamos ten, kur reikalaujama šiek tiek tamprumo ir lankstumo – virvėse ir drabužių simuliacijai. Kadangi jau prakalbau apie virves, tai pabandysime išsiaiškinti visą tiesą apie jas!

II. Visa tiesa apie virtualias virves

                Iš praktikos žinome, kad virvių būną įvairių – vienos standesnės, plonesnės/storesnės, lengvai arba negreit nutrūksta ir pan. Virvės lankstumas, tamprumas ir kitos savybės realybėje atsiranda tarpatominiame lygmenyje. Turint ribotus resursus tokį tikslumą tiesiog neįmanoma pasiekti proto ir laiko ribose, todėl tenka sukčiauti. Virvę įsivaizduojame kaip segmentuotą atkarpą arba laužtę, kurios mazgai – kieti kūnai(rigid-bodies) tarp kurių veikia tamprumo ir kitos jėgos(virtualios spyruoklės).

Virvė kaip mazgų ir spyruoklių tarp jų sistema

                Tokią kietų kūnų sistemą realizuoti paprasčiau, be to galima pasirinkti norimą detalumą(segmentacijos laipsnį). Likę tarpai tarp mazgų užpildomi pagal pageidavimus – tiesėmis, 3D geometrija(jei virvė trimatėje aplinkoje), interpoliuojant Bezje(Bezier), cat-mull-rom splainais ir panašiai. Šiuo atveju pasirinksime paprasčiausią būdą – mazgus jungsime tiesėmis. Taigi virvę galima realizuoti kaip kietų kūnų eilę.
                Tam, kad būtų galima jau anksčiau realizuotą RigidBody klasę panaudoti virvės kūrimui, reikės ją papildyti Huko dėsniu bei keliai kitais pakeitimais:

  1. Virvės mazge turėti informaciją apie prie jo prijungtus kitus mazgus
  2. Jėgų nustatymo metode be gravitacijos paskaičiuoti ir veikiančią tamprumo jėgą bei ją pridėti prie kūną veikiančių jėgų atstojamosios
  3. Papildomai pridėti interaktyvumo pele, kad virvę būtų galima pajudinti
                Visa tai realizuoti lengviausia paveldint anksčiau sukurtą(praeitame straipsnyje) RigidBody klasę ir papildyti naujais metodais ir kintamaisiais. Realizaciją rasite pridėtame kode straipsnio gale, o toliau iš arčiau pažvelkime į galimus iškilti keblumus ir tam tikrus įgyvendinimo niuansus.

III. Huko dėsnis – praktiškai!

                Realizuoti sistemą šiek tiek pamąsčius atrodytų gal ir nesunku, jei ne tam tikros problemos. Viena iš jų – Huko dėsnis nieko nekalba apie slopinimą, o be jo – sistema išsiderintų, tamprumo jėgos paimtų viršų ar net virvės mazgai judėtų nesustodami(be pusiausvyros)! Todėl praktiškai yra naudojamas šiek tiek modifikuotas Huko dėsnis:


                Naujoje formulėje atsiranda spyruoklės ilgio apribojimas(maxLength – natūralus neištemptos spyruoklės ilgis) bei papildomas greičio narys ir koeficientas: b – slopinimo koeficientas(damping factor), b > 0. Slopinimo koeficientas(priklausomai nuo jo modulio) leidžia realizuoti įvairias terpes, kurioje veikia spyruoklės. Didesnis slopinimo koeficientas duoda didesnį stabilumą(mažesnį paslankumą) ir lėtesnį greičio kitimą spyruoklėms(pavyzdžiui klampioje terpėje). Naudojantis šia išraiška jau galima puikiai realizuoti spyruoklių sistemas.
                Bendru atveju ši formulė naudojama vektorinėje formoje ir 3D erdvėje nagrinėjant kiekvieną mazgą sistemoje - skaičiuojant prie jo prijungtų kitų mazgų poveikį esamam. Ilgio pokytis x skaičiuojamas kaip nagrinėjamo mazgo ir prie jo prijungto kito mazgo pozicijų erdvėje vektorius:
                 x = current_node.position – prev_node.position
Priklausomai nuo erdvės matmenų formulėje naudojama tiek jo kryptis tiek ir modulis. Na, o slopinimo dėmens greitis – tai reliatyvus mazgų greičių pokytis:
                v = current_node.velocity – prev_node.velocity
                Galų gale tamprumo jėgų skaičiavimus atliekame kiekvienam, prie nagrinėjamo mazgo prijungtam, mazgui. Kaip ir minėjau, vienas iš būdų tai padaryti  - papildant RigidBody klasės jėgos nustatymo metodą applyForces() štai taip:


gravity = vec(0, -9.81, 0)
object.forces = vec(0, 0, 0)
object.forces += gravity * object.mass

                                                // use Hooke's law & apply damping
                                                // F = -k*|x-length| - b*v
                                                dir = object.position - prevObject.position
                                                x = length(dir) - maxSpringLength
                                                hookesForce = - k * x * normalized(dir)
                                                relativeSpeed = object.velocity - prevObject.velocity
                                                hookesForce +=  - b * relativeSpeed // apply damping
                                                object.forces += hookesForce

                Na štai, pagrindinis ir svarbiausias metodas papildytas. Belieka tik keletas papildomų darbų – sukurti virvę sujungiant kelis kūnus viena su kitu bei pakoreguoti piešimą, kad būtų piešiama virvė sujungta tiesėmis. Bendru atveju virvės kūrimo metodas pseudokodu atrodytu taip:

    prevNode = null
                for number of rope nodes do
                                node =  createNode parent:prevNode
                                addPhysicalBody node
                                prevNode = node

                Papildomai reikia atkreipti dėmesį į tai, jog jei visi virvės kūnai judės(nebus fiksuoti vietoje) tai virvė nuo gravitacijos(ar kitų jėgų) tiesiog nukris, todėl vaizdumo dėlei pirmąjį virvės kūną galima fiksuoti vietoje. Tai galima atlikti jėgų nustatymo metode - tiesiog neveikti fiksuoto kūno jokia jėga. Tokiu atveju virvė gražiai kabos aplinkoje kaip pavyzdyje.

                Mano nurodytame jėgų nustatymo pavyzdyje mes tamprumo(Huko) jėgą skaičiavome ir pridėjome tik vienam kūnui, nors pagal teoriją – abu kūnai yra veikiami tokio pat modulio tik priešingų krypčių tamprumo jėgos. Galbūt sakysite, kad tai nėra visiškai teisingas būdas, tačiau tai priklauso nuo to, ko jums reikia. Jei tamprumo jėgą pridėsime kiekvienam kūnui(mazgui), gausime tikrai teisingą būdą, tačiau prikabinus daugiau nei vieną mazgą virvė labai ištįs dėl prikabintos mazgų masės. Jei mums reikia fiksuotų vienodų atkarpų tarp mazgų – lieka jėgą nustatyti tik vienam kūnui.  Kitas sprendimas būtų mažinti mases arba proporcingai didinti tamprumo jėgos modulį didinant tamprumo koeficientą k.

Virvė pagal tikrą fizikinį modelį, kai tamprumo jėga veikia abu, spyruokle sujungtus, kūnus
Virvė su vienodais segmentų ilgiais, kai tamprumo jėga veikia tik vieną kūną


IV. Tolesnės galimybės

                Spyruoklės leidžia realizuoti įvairius įdomesnius fizikinius mechanizmus. Dar nepakalbėjome apie 3D geometrijos(pvz. žėlė) bei drabužių simuliaciją, tačiau galbūt jau įsivaizduojate kaip tai galima būtų atlikti. Idėjos šiems objektams paprastos kaip ir virvei – tiesiog naudoti spyruokles, tik jų žymiai daugiau. Drabužiai sudaromi iš eilutėmis/stulpeliais sudėtų kūnų(rigid-body), prie kurių prijungta nemažai spyruoklių. Veikdamos kartu iš įvairių pusių jos puikiai imituoja drabužio medžiagą.


Kiti  spyruoklių taikymo būdai - drabužiai(audinys), minkšti kūnai - žėlė 

                Trimačiai minkšti besideformuojantys(soft bodies) modeliai sudaromi iš daugelio gardele spyruoklėmis sujungtų kūnų. Dažnai kūnai tiesiog talpinami geometrijos viršūnėse(vertex) ir sujungiami spyruoklėmis pagal trikampių kraštus. Kadangi reikalaujama, kad spyruoklės stengtųsi išlaikyti savo ilgį, tai kūnas gali išlaikyti ir savo formą lengvai svyruodamas ir deformuodamasis, jeigu jį veikia jėgos. Ech, pagaliau apžvelgėme spyruoklių fizikos pagrindus, dabar bus galima atsikvėpti ir paeksperimentuoti – tad iki sekančio susitikimo! 



Realizuotą projektą su Java Processing galite parsisiųsti iš čia.


Daugiau informacijos:
  1. Ian Millington, Game physics engine development
  2. Grant Palmer, Physics for game developers
  3. David Conger, Physics modelling for game developers

Komentarų nėra:

Rašyti komentarą