Modul 3.3: Transformasjoner og matrisestack

Sammensatte figurer

Anta at vi skal modellere en enkel «papirmann» oppbygd av 2D-rektangler/flater med ulike størrelser og farger, som vist i figuren under.


Figuren består av flere deler som «henger» sammen. Vi ønsker å oppnå to ting:
  1. Det skal være mulig å bevege på ulike kroppsdeler uavhengig av andre deler.
  2. Når man endrer størrelse, roterer eller flytter kroppen (torsoen) skal ben og armer henge med
Det første punktet innebærer at det skal være mulig å bevege armer og ben uavhengig av kroppen (torsoen), underarm uavhengig av overarm, fingrer uavhengig av underarm osv. Dersom dette skal være mulig må de ulike delene tegnes med sin egen modelltransformasjon
De ulike kroppsdelene tegnes vha. et og samme rektangel. Det betyr at samme rektangel tegnes flere ganger. For hver gang settes en ny transformasjon (Alternativet er å definere alle verteksene i forhold til torsoen – dette gjør det imidlertid veldig vanskelig å bevege enkeltdeler som f.eks. armer og ben)
Eksempel: Modellmatrisa til høyre overarm består av torsoens modellmatrise kombinert med en rotasjon om z-aksen og en translasjon. Modellmatrisa til høyre underarm består av overarmens modellmatrise kombinert med en rotasjon om z-aksen og en translasjon.
Modellmatrisa til fingrene består av underarmens modellmatrise kombinert med en rotasjon og en translasjon osv.   
Det andre punktet betyr at dersom man flytter, roterer eller skalerer torsoen, skal også alle andre deler gjøre tilsvarende. Dersom størrelsen på torsoen endres skal størrelsen på kroppsdeler, som ben og armer, endres tilsvarende. Dersom man roterer overarmen skal tilknyttet underarm og fingrer følge med.

Akkumulert modellmatrise

Dette kan vi løse ved å akkumulere modellmatrisa for de ulike objektene. Vi bruker torsoens modellmatrise som en del av overarmenes modellmatrise. På samme måte brukes overarmens modellmatrise som en del av underarmens modellmatrise, underarmens matrise blir en del av fingrenes matrise osv.
Modellmatrisa til hver kroppsdel beregnes med utgangspunkt i «foreldrerektanglets» modellmatrise.

Bruk av matrisestack

En teknikk for å få til dette er å bruke en matrisestack slik at man enkelt kan ta vare på og akkumulere transformasjonsmarisene. Koden til push, pop og peek-metodene er vist under:
. . .

let matrixStack = [];
. . .

//Legger matrix til stack.
function pushMatrix(matrix) {
    let copyToPush = new Matrix4(matrix);
    matrixStack.push(copyToPush);
}

//Fjerner øverste element fra stack:
function popMatrix() {
    if (matrixStack.length == 0)
        throw "Feil i popMatrix - matrisestacken er tom!";
    matrixStack.pop();
}

//Leser og returnerer toppmatrisa. NB! Fjerner ikke:
function peekMatrix() {
    if (matrixStack.length == 0)
        throw "Feil i peekMatrix - matrisestacken er tom!";
    let matrix = new Matrix4(matrixStack[matrixStack.length - 1]);
    return matrix;
}

. . .

Legg merke til matrxStack er deklarert som et array. Javascript-array har allerede metoder for push() og pop(). Disse brukes i funksjonene pushMatrix(), popMatrix() og peekMatrix().
Legg også merke til at peekMatrix() kun leser og returnerer det øverste elementet i stakken (uten å fjerne det) mens popMatrix() fjerner det øverste elementet (uten å returnere det) i stakken.
Hver kroppsdel får sin egen modelltransformasjon, som er basert på foreldredelens transformasjon. Før torsoen tegnes opprettes en modellmatrise for denne. Matrisen legges på toppen av stacken. Deretter tegnes torsoen.
Deretter beregnes modellmatrisa til høyre overarm. Dennes settes i utgangspunktet til matrisa til torsoen (vha. peekMatrix()). Denne kombineres med en rotasjon og en translasjon for å få armen på riktig plass i forhold til torsoen.
Tilsvarende skjer med underarmen. Denne tar utgangspunkt i overarmens modellmatrise osv.
Legg merke til at popMatrix() fjerner matrisa som ligger på toppen av stacken, mens peekMatrix() kun leser toppen, uten å fjerne.
Se paperman0 for komplett kodeeksempel.

Ingen kommentarer:

Legg inn en kommentar