| Najnowsza grafika |
 |
|
|
| 2008-07-15 |
| Najnowsza tapeta |
 |
|
|
| 2009-01-14 |
|
Tutorial - Budujemy szkielet - podstawy IK
Jak przy każdym tutorialu, który piszę tak i przy tym nie wiem jak zacząć, bo w zasadzie po co piszę taki tutorial? Mógłbym zrobić coś innego, pograć, napisać dokumentacje dla klienta, czy też może posprzątać w mieszkaniu. A jednak poświęcam wieczór na napisanie tej małej pomocy. Myślę, że pisaniu czegoś takiego należy sobie odpowiedzieć na pytanie co chcemy osiągnąć pisząc coś takiego. Odpowiedź na to pytanie postaram się podać pod koniec tego artykułu czy jak to tam nazwać.
Dobrze zacznijmy od stworzenia prostej sceny, małego świata w którym będziemy umieszczać nasze dzieło. A naszym dziełem będzie szkielet, podstawa do animacji i może w przyszłości do kinematyki odwrotnej.
#version 3.5;
global_settings { assumed_gamma 1.0 }
#include "colors.inc"
camera { angle 15
location <0.0 , 20.0 ,-40.0>
right x*image_width/image_height
look_at <0.0 , 1.0 , 0.0>}



 // SŁOŃCE
 light_source {<1500,2500,-2500> color White}

 sky_sphere { pigment { gradient <0,1,0>
 color_map { [0 color rgb<1,1,1> ]
 [0.4 color rgb<0.14,0.14,0.56>]
 [0.6 color rgb<0.14,0.14,0.56>]
 [1.0 color rgb<1,1,1> ]
 }
 scale 2 }
 }

 plane { <0,1,0>, 0 texture { pigment {color White} } }
 //--------------------------------------------------------------------------
 //---------------------------- OBIEKTY W SCENIE ----------------------------
 //--------------------------------------------------------------------------

Skoro mamy scenę to teraz słów klika o obiekcie, który będziemy tworzyć. Szkielet w ogólnym zarysie będzie wyglądał tak.

Zdaję sobie sprawę, że nie jest to arcydzieło rysunku i szkicu, ale do naszych potrzeb wystarczy. od samego początku będziemy ludka tworzyć jako obekt powstały w wyniku działania macra. Podstawy tworzenia macra można znaleźć dla przypomnienia. Macro jest to swego rodzaju funkcja, procedura która odpowiednio wywołana wykonuje jakąś czynność, od obliczania, poprzez tworzenie jakiś zaawansowanych obiektów.
Do dzieła, definiujemy macro.
#macro mc_szkielet(_tObr)
// terść macra
#end
W pierwszej linijce deklarujemy macro (słowo kluczowe macro poprzedzone hashem #). W nawiasach okrągłych określamy ile parametrów będziemy przekazywać do naszego macra. Zaś w trzeciej określamy koniec macra (słowo kluczowe end poprzedzne #).
_tObr - jest to parametr, który będziemy przekazywać do naszego macra, tak naprawdę będzie to tablica wetorów. Wektory te będą nam sterować obrotem poszczególnych części ciała, ale wszystko po kolei.
Każdy obiekt prosty czy też masakrycznie złożony ma swój środek ciężkości tzn punkt obrotu, domyślnie wszystkie tworzone obiekty w povray;u mają ten punkt w <0,0,0>. Masz ludek swój punkt obrotu będzie miał w miednicy. Na początek stwórzmy miednicę.
#macro mc_szkielet(_tObr)
1. #local __miednica=box { <-4,-1.5,-1>,<4,1.5,1> }
2. object { __miednica}
#end
Miednica jest to zwyczajny sześcian o wymiarach 8x3x2 (SxWxG). Ważny jest w nim punkt obrotu, w tym wypadku jest to środek tego sześcianu. Teraz jeszcze tylko uruchomienie naszego macra...
#macro mc_szkielet(_tObr)
#local __miednica=box { <-4,-1.5,-1>,<4,1.5,1> }
object { __miednica}
#end
1. #declare tabObr=array[17];
2. object { mc_szkielet(tabObr) pigment { color Red }}
Doszły nowe dwie linijki, w pierwszej linicje deklarujemy tablice, która będzie zawierała 17 wektorów. w drugiej linicje wywołujemy to macro i przypisujemy mu kolor Czerwony.
No i nasz pierwszy render.

Teraz może wykorzystamy naszą tablicę i przekarzemy w niej wektor obrotu dla naszej miednicy. W tym celu musimy dokonać dwóch zmian.
a) Zdeklarować jako pierwszy element tablicy wektor #declare tabObr[0]=<0,0,0>;
b) W deklaracji naszej miednicy obrócić ją o ten właśnie wektor. #local __miednica=box { <-4,-1.5,-1>,<4,1.5,1> rotate _tObr[0] }
Całość wygląda tak.
#macro mc_szkielet(_tObr)
#local __miednica=box { <-4,-1.5,-1>,<4,1.5,1> rotate _tObr[0] }
object { __miednica}
#end
#declare tabObr=array[1];
#declare tabObr[0]=<0,0,0>;
 object { mc_szkielet(tabObr) pigment { color Red }}

Okej teraz jeżeli ten wektor zdeklarujemy tak: #declare tabObr[0]=<0,45,0>; i wyrenderujemy to nasza miednica wygląda tak. Ja wiem, że to co zrobiliśmy wydawało by się, że można to zrobić łatwiej ale myślę, że później się wyjaśni dlaczego tak to zrobiłem.
Rendering:

(Zielony cylinder dodałem aby zobrazować w którym miejscu, się obraca nasza miednica).
Dobrze teraz zdeklarujmy nogę a dokładnie udo prawe.
#local __udo_praw=union {
sphere { <0,0,0>,1 }
cylinder { <0,0,0>,<0,-12,0>, .7 }
rotate _tObr[1]
}
Udo prawe jest to obiekt złożony z dwóch prymitywów: kuli i walca. Proszę zwrócić uwagę na punkt obrotu, który został ustawiony w środku kuli, natomiast walec początek ma w tym samym punkcie co kula ma swój środek.
Teraz nasze udo umieszczamy w odpowiednim miejsc miednicy w tym celu trochę zmieniamy deklarację miednicy
#local __miednica=union {
box { <-4,-1.5,-.5>,<4,1.5,.5> }
object { __udo_praw translate <-3,-1.5,0> }
rotate _tObr[0]
}
Teraz nasza miednica jest to obiekt typu UNION składający się z box'a czyli tej miednicy, co do tej pory i naszego uda prawego. Proszę zauważyć, że nasze udo zostało przesunięte na pozycję. 3, 15, 0 Ze względu na to aby czytelniej się to nam renderowało zmieniłem trochę ustawienia sceny. (oddaliłem kamerę i cały obiekt szkielet przesunąłem do góry)
A tak wygląda nasz render

Dobrze, reasumując mamy dwa obiekty miednice (którą obracamy wektorem (zerowy element tablicy)) i udo prawe które obracamy wektorem (pierwszym elementem tablicy). Teraz np. obracając udo w x o -45 mamy takie coś:

Ale jeżeli obrócimy dodatkowo miednice w x o -45 to będziemy mieli coś takiego:

Proszę zwrócić uwagę, że mimo, że miednica została przekręcona o 45 stopni, to udo pozostało tak samo obrócone..
Dobrze ale zdeklarujmy łydkę, to się jeszcze wyjaśni.
#local __lydka_praw=union {
sphere { <0,0,0>,1 }
cylinder { <0,0,0>,<0,-11,0>, .6 }
rotate _tObr[2]
}
Dobrze skoro mamy łydkę to teraz ją powinniśmy jakoś dodać. I teraz niespodzianka łydkę dodajemy do uda :-) kod wygląda tak
#macro mc_szkielet(_tObr)
#local __lydka_praw=union {
sphere { <0,0,0>,1 }
cylinder { <0,0,0>,<0,-11,0>, .6 }
rotate _tObr[2]
}
#local __udo_praw=union {
sphere { <0,0,0>,1 }
cylinder { <0,0,0>,<0,-12,0>, .7 }
 object { __lydka_praw translate <0,-12,0> }
 rotate _tObr[1]
 }

 #local __miednica=union {
 box { <-4,-1.5,-.5>,<4,1.5,.5> }
 object { __udo_praw translate <-3,-1.5,0> }
 rotate _tObr[0]
 }

 object { __miednica}
 #end


 #declare tabObr=array[17];
 #declare tabObr[0]=<0,0,0>;
 #declare tabObr[1]=<0,0,0>;
 #declare tabObr[2]=<0,0,0>;

Niemal, że dodaliśmy łydkę do uda to jeszcze ją przesuneliśmy w Y o -12, ale proszę zwrócić uwagę, że mimo tego jak będziemy łydką obracać to nadal ona się zgina w kolanie...

Dobrze teraz skoro mamy już trzy punkty obrotu to zademonstrujemy jakie ma to zalety.
Jest to animacja, gdzie obracamy tylko lydkę. Kod tego wygląda tak,
#declare tabObr=array[17];
#declare tabObr[0]=<0,0,0>;
#declare tabObr[1]=<0,0,0>;
#declare tabObr[2]=<-75*clock,0,0>;
Zauważyć można, że obracamy tylko wektor znajdujący się w drugim elemencie tablicy.

A teraz jak dodamy obrót w udzie wyjdze coś takiego.

#declare tabObr=array[17];
#declare tabObr[0]=<0,0,0>;
#declare tabObr[1]=<-(75 - 150*clock),0,0>;
#if(clock<.5)
#declare tabObr[2]=<-150*clock,0,0>;
#else
#declare tabObr[2]=<-(150-150*clock),0,0>;
#end
W linijce 3 deklarujemy wektor obrotu dla uda, uzależniamy kąt obrotu X od zmiennej clock, która to zmienia się z zakresu 0 - 1 czyli kąt zmienia się z zakresu -75 do 75. Od linijki 4 do 8 jest zdeklarowany warunek, króty określa że jeżeli zmienna clock jest mniejsza od 0.5 to wykonywana jest linijka 5 czyli obracamy łydkę w osi X od 0 -75 następnie jeżeli zmienna clock jest większa od .5 wykonujemy linijkę 7 czyli obracamy łydkę w osi X od -75 - 0.
Co nam to daje takie ustawienie wektorów obrotów i przekazywanie do macra? pozwala nam obracać poszczególne elementy w ich własnym lokalnym punkcie <0,0,0> dopiero po obrocie przenosimy je do wybranego punktu i obracamy, ale wektorem obrotu rodzica.
Dobrze pokazałem jak wygląda i co nam daje takie ustawienie i taki model przekazywania kątów obrotu, teraz szybko stwórzmy prawą stopę i całą lewą nowy zrobimy na zasadzie kopiuj wklej :-)
Tak wygląda deklaracja stopy
#local __stopa_prawa=union {
sphere { <0,0,0>,1 }
box { <-1,0,-1>,<1,-2,1> }
box { <-1,-1,-4>,<1,-2,1> }
rotate _tObr[3]
}
Dobrze po zdeklarowaniu lewej nogi i przypisaniu jej odpowiednich wektorów obrotów otrzymujemy coś takiego..

Teraz szybko stworzę tłów ręce szyję i głowę, technika i metoda jest taka sama jak przy tworzeniu nóg. Pominę szczegółowe opisywanie poszczególnych etapów tworzenia tych obiektów, nie jest to istotne na treść tego tutoriala, po stworzeniu tych elementów przejdziemy do tworzenia macr które ułatwią zarządzanie ludkiem. Opiszę tylko hierarichę.
Tak wygląda nasz model, dodałem wszystkie elementy teraz przejdziemy do tworzenia macr pomocniczych

object { mc_szkielet(tabObr) pigment { color Red } translate <0,26.5,0> }
Proszę zwrócić uwagę na to, aby nasz obiekt stał na ziemi musimy przesunąć go o 26.5 do góry. Taką wysokość mają nogi ludka. Dlatego wstawimy to translate do naszego macra.
Teraz podciągniemy kolana do góry
#declare tabObr[1]=<45,0,0>; // Udo prawe
#declare tabObr[2]=<-90,0,0>; // Łydka prawa
#declare tabObr[3]=<45,0,0>; // stopa prawa
#declare tabObr[4]=<45,0,0>; // udo lewe
#declare tabObr[5]=<-90,0,0>; // Łydka lewa
#declare tabObr[6]=<45,0,0>; // Stopa lewa
a rendering wygląda tak

Proszę zwrócić uwagę, że podciąganięcie kolan do góry osiągneliśmy zmienijąc kąty ud, łydkek i stóp, jednocześnie stopy uniosły się od poziomu ) o jakąś tam odległość, teraz aby nasz ludek stał na ziemi musimy znowu go przesunąć o jakąś tam odległość. Oczywiście są tacy co trafiają i próbują aż w końcu udam się przestawić ludka na odpowiednią wysokość :-) oczywiście szanujemy ich. My stworzymy macro i użyjemy do tego transform i vtransform... Ogólnie rzecz ujmując musimy znaleźć punkt na którmy znajduje się dół stopy i przesunąć cały obiekt o tą wartość.
Transform - jest to swego rodzaju grupowanie poszczególnych operacji przekształcania, rotate, translate scale, który można później użyć do każdego rodzaju obiektu, np
#local _trMoj=transform
{
translate <12,0,0>
rotate x*12
translate <0,-1,0>
scale <1,.4,1>
}
sphere { <0,0,0>, 2 transform _trMoj }
Tworzymy obiekt przekształcenia, a następnie przekształcamy sferę.
Natomiast
vtransform(p, tra) - jest to macro które punkt (p) poddaje transformacji (tra) i zwraca położenie tego punktu.
No to mamy wszystkie już potrzebne narzędzie, tak więc tworzymy macro które obliczy nam punkt gdzie znajduje się stopa
#macro obliczY(tO)
#local _trStopaPrawa=transform
{
translate <0,-2,0> // punkt od dołu stopy do poczatku stopy tam gdzie jest to sphere
rotate tO[3] // kąt obrotu stopy
translate <0,-11,0> // przesunięcie lydki
rotate tO[2] // kąt obroty łydki
 translate <0,-12,0> // przesuniecie uda
 rotate tO[1] // obrot uda

 translate <0,-1.5,0> // przesuniecie biodra
 rotate tO[0] // obrot całego biodra

 translate <0,26.5,0>
 }
 -vtransform(<0,0,0>, _trStopaPrawa).y
 #end

W pierwszej linijce tworzymy macro do którego przekazujemy tablice wektorów,
w drugijej linijce zaś tworzym transform takie jakie jest uzywane w ludku. W 18 linijce obliczamy punkt i zwracamy tylko wartość y z tego punktu.
Macra używamy tak,
object { mc_szkielet(tabObr) pigment { color Red } translate y*obliczY(tabObr) }
A oto Efekt..

Takie rozwiązanie ma swoje wady ponieważ bierzemy pod uwagę tylko jedną nogę, jeżeli np noga lewa jest bardziej wyprostowana to nie do końca działa... oto przykład

Jednak jak przerobimy nasze macro o tak
#macro obliczY(tO)
#local _trStopaPrawa=transform
{
translate <0,-2,0> // punkt od dołu stopy do poczatku stopy tam gdzie jest to sphere
rotate tO[3] // kąt obrotu stopy
translate <0,-11,0> // przesunięcie lydki
rotate tO[2] // kąt obroty łydki

 translate <0,-12,0> // przesuniecie uda
 rotate tO[1] // obrot uda

 translate <-3,-1.5,0> // przesuniecie biodra
 rotate tO[0] // obrot całego biodra

 translate <0,26.5,0>
 }
 #local _trStopaLewa=transform
 {
 translate <0,-2,0> // punkt od dołu stopy do poczatku stopy tam gdzie jest to sphere
 rotate tO[6] // kąt obrotu stopy

 translate <0,-11,0> // przesunięcie lydki
 rotate tO[5] // kąt obroty łydki

 translate <0,-12,0> // przesuniecie uda
 rotate tO[4] // obrot uda

 translate <3,-1.5,0> // przesuniecie biodra
 rotate tO[0] // obrot całego biodra

 translate <0,26.5,0>
 }
 max(-vtransform(<0,0,0>, _trStopaPrawa).y,-vtransform(<0,0,0>, _trStopaPrawa).y)
 #end

Wtedy już będziemy potrafili określić ile trzeba przesunąć do poziomu;
A oto gotowy render...

I sam koniec przykład zastosowania, obrazujący jak to co stworzylismy działa:

Można dopisać jeszcze macro które będzie ustawiało stopy równolegle do podłoża... ale to już w innym tutorialu,
|