czwartek, 6 sierpnia 2009

Animacja szkieletowa

No temat masakra. Od poprzedniego postu cały czas walczę ze skiningiem. Na dobry początek zawiodły mnie szadery. Z jakiegoś, kompletnie nie zrozumiałego dla mnie, powodu pętla:
for (int i = 0; i < 4; i++)
wykonywała się tylko raz. Później, głównie dzięki przykładowi, zawartemu w Dx SDK, SkinMesh, udało mi się przekonać kompilator, że ta pętla to ma jednak 4 przebiegi. Co było przyczyną problemu wciąż nie wiem.
Następnie odkryłem, że kod (tym razem c++)
if (0 != flag & 1)
{
}

if
(0 != flag & 2)
{
}
...

if
(0 != flag & 32)
{
}
kompiluje się tylko do jednego, pierwszego, if'a. Cała reszta jest pomijana. Dzieje się tak przy -o0 -g3, a także dla domyślnych ustawień (czyt. bez flagi). Innych ustawień nie sprawdziłem. Nie mam pojęcia o co gcc chodziło. Czyżby bug ;)
Wyszło jeszcze kilka błędów. Wczoraj wieczorem udało mi się wyświetlić model w bind pose, ale ... . Ale wynik był zniekształcony. Geometria z całą pewnością jest poprawna, bo po ustawieniu macierzy jednostkowej wygląda jak należy. Czyli SUKCES, udało mi się w końcu zmusić wszystko do działania, a błędy muszą wynikać z nieprawidłowych macierzy.

Od początku idea aby wysyłać do karty "globalne" macierze dla każdej kości wydał mi się dziwny. Przecież to się musi rozjechać. Pomyślałem jednak, że może te wagi odpowiednio modyfikują transformację. Dzisiaj rano postanowiłem to przeanalizować matematycznie. No i oczywiście okazało się, że jest źle.

Weźmy taki przykład:
Punkt p [1, 1, 1], zaczepiony do dwóch kości, do obu po równo, czyli wagi 0,5
Kość A [0, 0, 0] zorientowana neutralnie (macierz jednostkowa)
Kość B [0, 0, 2] zorientowana neutralnie

p' = 0,5 * A * p + 0,5 * B * p
p' = [0,5 0,5 0,5] + [0,5 0,5 (0,5 * (1 + 2))] = [1, 1, 1,5]

A powinno wyjść [1, 1, 1]. Co z tym zrobić ? Bardzo UWAŻNIE przeczytać cokolwiek na ten temat. Na przykład ten temat na warsztacie. Odkryjemy w ten sposób, że macierze mają być "globalne", ale muszą uwzględniać pewien myk.

Na koniec screen, z bind pose:
Z Engine
Model pochodzi ze wspomnianej już strony: link

2 komentarze:

Gynvael Coldwind pisze...

Cześć ;>

Ciekawy post, blah, muszę się w końcu tą animacją szkieletową pobawić...

Rozwiążę twoją zagadkę dotyczącą if'ów ;> Nie jest to bug gcc btw ;>

if(a != x & y)
to jest (wg kolejności wykonywania operatorów):
if((a != x) & y)
a NIE:
if(a != (x & y))

Ponieważ z (a != x) może wyjść jedynie 0 lub 1, to dla y różnego od 1 (np w twoich przykładach było to 2 i 32), wyjdzie zawsze 0.
a if(0) { } się nigdy nie wykona, więc po co go wkompilowywać? ;>

Warto -Wall -Wextra w gcc dawać (ew /W4 w kompilatorze ms)

Gritz

Adam Śmigielski pisze...

Dzięki za odpowiedź.

Heh, no fakt. Binarne operatory mają niższy priorytet od porównania, jakoś mi się zapomniało ;)

Względem bug'a, to oczywiście spodziewałem się właśnie błędu w tym stylu. Taki żarcik :)

Ostrzeżenia mam włączone, tylko pewnie nie zwróciłem uwagi, że coś jest nie tak.

Jak skończę to robić to wrzucę dokładne wzory na przekształcenia.