EN begrensning er en begrensning på et fysisk modellert objekt i en simulering. Generelt begynner et objekt med seks grader av frihet, som representerer evnen til å bevege seg rundt og rotere i den simulerte verden; ved å begrense disse frihetsgrader på ulike måter, kan vi oppnå mange interessante og tiltalende effekter.
Som CPU av moderne datamaskiner blir mer og mer kraftig, kan beregninger legges til modellering og løsning av mange interessante fysiske scenarier. Begrensninger er en generalisert og matematisk støttet måte å produsere slike scenarier på. Vi kan alle takke Erin Catto for sitt første papir om dette emnet: Iterativ Dynamikk med Temporal Sammenheng. Jeg vil bruke dette papiret som en referanse når du skriver dette innlegget, så jeg foreslår at du i hvert fall tar en titt før du leser på, selv om det bare er ute av respekt for Erins arbeid (og hans oppførte ressurs fungerer og spesiell takk av hver av sine bidragsytere ).
Det er noen forskjellige termer som ofte brukes når man snakker om fysikkmotorer. For klarhet, her er en kort ordliste som kan brukes som referanse når du leser dette innlegget:
Det kreves noen få forutsetninger for å dra full nytte av denne artikkelen. Imidlertid kan den generelle leseren fortsatt nyte mye av materialet, selv om det er best å ha en grunnleggende forståelse av:
Siden en begrensning begrenser grader av frihet, la oss sjekke ut hva en stiv kropp gjør når du bruker seks på en gang:
Ovennevnte stive kropp bruker tre grader av frihet til å oversette seg gjennom verden. De siste tre brukes til å forandre orientering av alle tre rotasjonsaksene.
La oss nå se på et par forskjellige eksempler på hvilke begrensninger faktisk er. Den mest kjente begrensningen vil være en som hindrer at to stive legemer trer inn. Denne typen begrensning er bare aktiv når to kropper penetrerer hverandre, og driver de to kroppene fra hverandre. Når denne interpenetreringsbegrensningen er aktiv, er det lett å se at graden av frihet for de stive kroppene blir begrenset og påvirket på en slik måte at det gir et interessant resultat (det interessante resultatet er at de to gjenstandene kan kollidere med hverandre ):
Hello World of Restraints ville være avstandsbegrensning, der to punkter på to stive legemer er begrenset til å være en nøyaktig avstand fra hverandre. Du kan forestille deg en masseløs stang som forbinder to punkter sammen, hvor denne stangen ikke kan strekkes eller komprimeres:
Mange typer begrensninger eksisterer for alle slags interessante atferd, inkludert: friksjon, prismatisk, revolusjon, sveising, vinkel og mer.
I generell form er en begrensning en skalarlikning lik noen verdi (vanligvis null).
\ Begynne ligning
C (l_1, a_1, l_2, a_2) = 0
\ Etikett EQ1
\ End ligning
\ (L \) og \ (a \) vilkårene i \ eqref eq1 er min egen notasjon: \ (l \) refererer til lineær mens \ (a \) refererer til vinkel. Abonnementene 1 og 2 refererer til de to objektene innenfor begrensningen. Som du kan se, finnes det lineære og vinkelinnganger i en begrensningsligning, og hver må være en skalarverdi.
La oss ta et skritt tilbake for å se på avstandsbegrensningen. Avstandsbegrensningen vil kjøre avstanden mellom to ankerpunkter på to kropper for å være lik noen skalarverdi:
\ Begynne ligning
C (l_1, a_1, l_2, a_2) = \ frac 1 2 [(P_2 - P_1) ^ 2 - L ^ 2] = 0
\ Etikett EQ2
\ End ligning
\ (L \) er stangens lengde som forbinder begge kroppene; \ (P_1 \) og \ (P_2 \) er de to kroppens stillinger.
I sin nåværende form er denne begrensningen en posisjonssammensetning. Denne typen stillingsligning er ikke-lineær, noe som gjør det vanskelig å løse det. En metode for å løse denne ligningen kan være å isteden utlede stillingsbegrensningen (med hensyn til tid) og bruke en hastighetsbegrensning. Resulterende hastighetsekvasjoner er lineære, noe som gjør dem løsbare. Løsninger kan da integreres ved hjelp av en slags integrator tilbake i posisjonsform.
I generell form er en hastighetsbegrensning av formen:
\ Begynne ligning
\ dot C (l_1, a_1, l_2, a_2) = 0
\ Etikett EQ3
\ End ligning
Under derivatet vises en ny term \ (J \) via kjederegel:
\ Begynne ligning
\ dot C (l_1, a_1, l_2, a_2) = JV = 0
\ Etikett Ligning 4
\ End ligning
Tidsderivatet av \ (C \) skaper en hastighetsvektor og en Jacobian. Jacobianen er en 1x6 matrise som inneholder skalarverdier som tilsvarer hver grad av frihet. I en parvis begrensning vil en Jacobian typisk inneholde 12 elementer (nok til å inneholde \ (l \) og \ (a \) termer for både kroppene \ (A \) og \ (B \).
Et system med begrensninger kan danne en ledd. Et felles kan inneholde mange begrensninger som begrenser frihetsgraden på ulike måter. I dette tilfellet vil Jacobian være en matrise hvor antall rader er lik antall begrensninger som er aktive i systemet.
Jacobian er avledet offline, for hånd. Når en Jacobian er kjøpt, kodes å beregne og bruke Jacobian kan opprettes. Som du kan se fra \ eqref eq4, forvandles hastigheten \ (V \) fra kartesisk plass til å begrense plass. Dette er viktig fordi opprinnelsen er kjent i begrensningsområdet. Faktisk kan et hvilket som helst mål bli kjent. Dette betyr at enhver begrensning kan utledes for å gi en Jacobian som kan forandre krefter fra kartesisk plass for å begrense plass.
I begrensningsrommet, gitt et målskalar, kan ligningen bevege seg enten mot eller vekk fra målet. Løsninger kan lett oppnås i begrensningsrom for å flytte nåværende tilstand til en stiv kropp mot en måltilstand. Disse løsningene kan da transformeres ut av begrensningsrom tilbake til kartesisk plass som sådan:
\ Begynne ligning
F = \ lambda J ^ T
\ Etikett EQ5
\ End ligning
\ (F \) er en kraft i kartesisk rom, hvor \ (J ^ T \) er den inverse (transponerte) Jacobian. \ (\ lambda \) (lambda) er en skalar multiplikator.
Tenk på Jacobian som en hastighetsvektor hvor hver rad er en vektor i seg selv (av to skalarverdier i 2D og tre skalarverdier i 3D):
\ Begynne ligning
J = \ start bmatrix
l_1 \\
a_1 \\
l_2 \\
a_2 \\
\ End bmatrix
\ Etikett EQ6
\ End ligning
For å multiplisere \ (V \) av \ (J \) matematisk ville det innebære matrixmultiplikasjon. Imidlertid er de fleste elementer null, og derfor behandler vi Jacobian som en vektor. Dette gjør at vi kan definere vår egen operasjon for databehandling \ (JV \), som i \ eqref eq4.
\ Begynne ligning
JV = \ start bmatrix
l_1 & a_1 & l_2 & a_2
\ End bmatrix
\ Begynne bmatrix
v_1 \\
ω_1 \\
v_2 \\
ω_2 \\
\ End bmatrix
\ Etikett EQ7
\ End ligning
Her representerer \ (v \) lineær hastighet, og \ (ω \) (omega) representerer vinkelhastighet. \ eqref eq7 kan skrives ned som noen prikkprodukter og multiplikasjoner for å gi en mer effektiv beregning i forhold til fullmatrisemultiplikasjon:
\ Begynne ligning
JV = l_1 \ cdot v_1 + a_1 \ cdot ω_1 + l_2 \ cdot v_2 + a_2 \ cdot ω_2
\ Etikett eq8
\ End ligning
Jacobianen kan betraktes som en retningsvektor i begrensningsområdet. Denne retningen peker alltid mot målet i den retningen som krever det minste arbeidet som skal gjøres. Siden denne "retningen" er avledet av Jacobian frakoblet, er alt som må løses for størrelsen på kraften som skal brukes for å opprettholde begrensningen. Denne størrelsen kalles \ (\ lambda \). \ (\ lambda \) kan kalles Lagrange Multiplikator. Jeg har selv ikke formelt studert lagrangemekanikk, men en studie av lagrangemekanikk er ikke nødvendig for å bare gjennomføre begrensninger. (Jeg er bevis på det!) \ (\ Lambda \) kan løses ved hjelp av a begrensningsløsning (mer om dette senere).
I Erin Cattos papir eksisterer det en enkel oversikt for hånd-opplæring av Jacobians. Trinnene er:
Den eneste harde delen er å beregne derivatet, og dette kan komme med praksis. Generelt er det vanskelig å håndlevere begrensninger, men blir lettere med tiden.
La oss få en gyldig Jacobian til bruk for å løse avstandsbegrensning. Vi kan starte i trinn 1 med \ eqref eq2. Her er noen detaljer for trinn 2:
\ Begynne ligning
\ dot C = (P_2 - P_1) (\ dot P _2 - \ dot P _1)
\ Etikett eq9
\ End ligning
\ Begynne ligning
\ dot C = (P_2 - P_1) ((v_2 + ω_2 \ ganger r_2) - (v_1 + ω_1 \ ganger r_1))
\ Etikett EQ10
\ End ligning
\ (r_1 \) og \ (r_2 \) er vektorer fra midten av massen til ankerpunktet, for henholdsvis kroppene 1 og 2.
Det neste trinnet er å isolere hastighetsbetingelsene. For å gjøre dette, vil vi gjøre bruk av den skalære trippelproduktidentiteten:
\ Begynne ligning
(P_2 - P_1) = d
\ Etikett eq11
\ End ligning
\ Begynne ligning
\ dot C = (d \ cdot v_2 + d \ cdot ω_2 \ ganger r_2) - (d \ cdot v_1 + d \ cdot ω_1 \ ganger r_1)
\ Etikett eq12
\ End ligning
\ Begynne ligning
\ dot C = (d \ cdot v_2 + ω_2 \ cdot r_2 \ ganger d) - (d \ cdot v_1 + ω_1 \ cdot r_1 \ ganger d)
\ Etikett eq13
\ End ligning
Det siste trinnet er å identifisere Jacobianen ved inspeksjon. For å gjøre dette vil alle koeffisientene for alle hastighetsbetingelser (\ (V \) og \ (ω \)) bli brukt som Jacobian-elementene. Derfor:
\ Begynne ligning
J = \ start bmatrix -d & -r_1 \ ganger d & d & r_2 \ times d \ end bmatrix
\ Etikett eq14
\ End ligning
Kontaktbegrensning (interpenetrasjonsbegrensning), hvor \ (n \) er kontakten normal:
\ Begynne ligning
J = \ start bmatrix -n & -r_1 \ ganger n & n & r_2 \ times n \ end bmatrix
\ Etikett eq15
\ End ligning
Friksjonsbegrensning (aktiv under penetrasjon), hvor \ (t \) er en friksjonsaksjon (2D har en akse, 3D har to):
\ Begynne ligning
J = \ start bmatrix -t & -r_1 \ ganger t & t & r_2 \ times t \ end bmatrix
\ Etikett eq16
\ End ligning
Nå som vi har forståelse for hva en begrensning er, kan vi snakke om hvordan de skal løses. Som nevnt tidligere, når en Jacobian er håndavledet, trenger vi bare å løse for \ (\ lambda \). Å løse en enkelt begrensning i isolasjon er enkelt, men å løse mange begrensninger samtidig er vanskelig og svært ineffektiv (beregningsmessig). Dette er et problem, ettersom spill og simuleringer vil trolig vil ha mange begrensninger aktive samtidig.
En alternativ metode for å løse alle begrensninger samtidig (globalt løse) ville være å løse begrensningene iterativt. Ved å løse for tilnærminger av løsningen og fôring i tidligere løsninger til ligningene, kan vi konvergere på løsningen.
En slik iterativ løsningsmiddel er kjent som sekvensielle impulser, som kalt av Erin Catto. Sekventielle impulser ligner veldig på Projected Gauss Seidel. Tanken er å løse alle begrensninger, en om gangen, flere ganger. Løsningene vil ugyldiggjøre hverandre, men over mange iterasjoner vil hver enkelt konvergens konvergere, og en global løsning kan oppnås. Dette er bra! Iterative solvers er raske.
Når en løsning er oppnådd, kan en impuls brukes på begge kroppene i begrensningen for å håndheve begrensningen.
For å løse en enkelt begrensning kan vi bruke følgende ligning:
\ Begynne ligning
\ lambda = \ frac - (JV + b) JM ^ - 1 J ^ T
\ Etikett eq17
\ End ligning
\ (M ^ - 1 \) er massen av begrensningen; \ (b \) er bias (mer om dette senere).
Dette er en matrise som inneholder den inverse massen og invers inerti av begge stive legemer i begrensningen. Følgende er massen av begrensningen; Legg merke til at \ (m ^ - 1 \) er den inverse massen til en kropp, mens \ (I ^ - 1 \) er en invers inerti til en kropp:
\ begin ligning M ^ - 1 =
\ Begynne bmatrix
m_1 ^ - 1 & 0 & 0 & 0 \\
0 & I_1 ^ - 1 & 0 & 0 \\
0 & 0 & m_2 ^ - 1 & 0 \\
0 & 0 & 0 & I_2 ^ - 1
\ End bmatrix
\ Etikett eq18
\ End ligning
Selv om \ (M ^ - 1 \) er teoretisk en matrise, må du ikke faktisk modellere den som sådan (det meste er nuller!). Vær i stedet klar over hva slags beregninger du gjør.
\ (JM ^ - 1 J ^ T \) er kjent som begrensningsmasse. Denne termen er beregnet en gang og brukes til å løse for \ (\ lambda \). Vi beregner det for et system som det:
\ Begynne ligning
JM ^ - 1 J ^ T = (l_1 \ cdot l_1) * m_1 ^ - 1 + (l_2 \ cdot l_2) * m_2 ^ - 1 + a_1 * (I_1 ^ - 1 a_1) + a_2 * (I_2 ^ - 1 a_2)
\ Etikett eq19
\ End ligning
Vær oppmerksom på at du må invertere \ eqref eq19 for å beregne \ eqref eq17.
Ovennevnte informasjon er alt som trengs for å løse en begrensning! En kraft i kartesisk rom kan løses for og brukes til å oppdatere hastigheten til en gjenstand for å håndheve en begrensning. Vennligst husk \ eqref eq5:
\ Begynne ligning
F = \ lambda J ^ T \\
V_ final = V_ initial + m ^ - 1 * F \\
∴ \\
\ Begynne bmatrix
v_1 \\
ω_1 \\
v_2 \\
ω_2 \\
\ end bmatrix + = \ start bmatrix
m_1 ^ - 1 & 0 & 0 & 0 \\
0 & I_1 ^ - 1 & 0 & 0 \\
0 & 0 & m_2 ^ - 1 & 0 \\
0 & 0 & 0 & I_2 ^ - 1
\ End bmatrix \ begynne bmatrix
\ lambda * l_1 \\
\ lambda * a_1 \\
\ lambda * l_2 \\
\ lambda * a_2 \\
\ End bmatrix
\ Etikett eq20
\ End ligning
På grunn av lineariseringen av de ikke-lineære posisjonekvasjonene, går noe informasjon tapt. Dette resulterer i løsninger som ikke tilfredsstiller den opprinnelige stillingsligningen, men tilfredsstiller hastighetsekvasjonene. Denne feilen er kjent som begrensningsdrift. Man kan tenke på denne feilen som et resultat av en tangentlinje tilnærming.
Det finnes noen forskjellige måter å løse slike feil på, som alle omtrentlige feilen og bruke noen form for korreksjon. Den enkleste er kjent som Baumgarte.
Baumgarte er et lite tillegg av energi i begrensningsområdet, og står for \ (b \) termen i de tidligere ligningene. For å regne med forspenning, her er en endret versjon av \ eqref eq4:
\ Begynne ligning
\ prikk C = JV + b = 0
\ Etikett eq21
\ End ligning
For å beregne en Baumgarte term og bruke den som en bias, må vi inspisere den opprinnelige begrensningsligningen og identifisere en egnet metode for å beregne feil. Baumgarte er i form:
\ Begynne ligning
JV = - \ beta C
\ Etikett eq22
\ End ligning
\ (\ beta \) (Baumgarte-termen) er en avstemt, enhetsløs, simuleringsavhengig faktor. Det er vanligvis mellom 0.1
og 0.3
.
For å beregne bias-begrepet, la oss se på ligningen for ikke-penetreringsbegrensningen \ eqref eq15 før det avledes med tiden, hvor \ (n \) er kontakten normal:
\ Begynne ligning
C = \ start bmatrix -x_1 & -r_1 & x_2 & r_2 \ end bmatrix \ cdot \ vec n
\ Etikett eq23
\ End ligning
Ovennevnte ligning sier at skalarfeilen til \ (C \) er inter-penetrasjonsdybden mellom to stive legemer.
Takket være Erin Catto og hans papir om begrensning, har vi en måte å løse posisjonsbegrensninger på når det gjelder hastighet. Mange interessante oppføringer kan oppstå fra begrensninger, og forhåpentligvis vil artikkelen være nyttig for mange mennesker. Som alltid, vær så snill å stille spørsmål eller gi kommentarer nedenfor.
Vennligst se Box2D Lite for en ressurs for å løse ulike typer 2D-begrensninger, samt innsikt i mange implementeringsdetaljer som ikke er dekket her.