E nter.net  


VRML (2)
Tworzenie ANIMACJI
Kamil D▒bkowski


W poprzednim odcinku naszego kursu zobaczyli╢my, jak z najprostszych bry│ (kula, sto┐ek, walec) mo┐na tworzyµ obiekty z│o┐one. Oczywi╢cie, w VRML mo┐emy definiowaµ obiekty o dowolnych kszta│tach.

W tym celu musimy zdefiniowaµ punkty w przestrzeni tr≤jwymiarowej oraz metodΩ, jak▒ te punkty bΩdziemy │▒czyµ. MetodΩ ustanawiamy poprzez zastosowanie odpowiedniego wΩz│a. I tak, wΩze│ IndexedFaceSet │▒czy te punkty tworz▒c bry│y, wΩze│ IndexedLineSet │▒czy zdefiniowane punkty liniami, a wΩze│ PointSet powoduje, ┐e zdefiniowane punkty wy╢wietlane s▒ jako pojedyncze punkciki. Przyk│ad zwyk│ego prostopad│o╢cianu - tym razem wykorzystuj▒cego wΩze│ IndexedFaceSet, a nie wΩze│ Box (kt≤rego zastosowanie by│oby oczywi╢cie o wiele prostsze), przedstawia Listing 1 znajduj▒cy siΩ na kr▒┐ku ENTER CD 1/98 w katalogu LISTINGI.
Jak widaµ tworzenie obiekt≤w, przy kt≤rych korzysta siΩ z tych wΩz│≤w jest ma│o przyjemnym zajΩciem, gdy┐ trzeba sobie wyobraziµ przestrze± tr≤jwymiarow▒, obiekt, kt≤ry chce siΩ stworzyµ i wybraµ punkty wierzcho│k≤w tego obiektu, a wszystko to zapisaµ w postaci liczbowej. Dlatego te┐ autorzy modeluj▒cy samodzielnie ╢wiaty VRML rzadko korzystaj▒ z tych wΩz│≤w. Nadaj▒ siΩ one natomiast wspaniale dla wszelkiego typu edytor≤w VRML, w kt≤rych mo┐na tworzyµ dowolne kszta│ty za pomoc▒ przyjaznych narzΩdzi, a dla takiego programu nic bardziej wygodnego, jak zapisaµ to w postaci liczbowej. Minusem jest jednak to, ┐e niekt≤re edytory zapisuj▒ nawet najprostsze obiekty korzystaj▒c z wΩz│a IndexedFaceSet, co zwiΩksza niepomiernie wielko╢µ pliku, a to wyd│u┐a czas ╢ci▒gania ╢wiata VRML z sieci.

Wprowadzamy ruch


Skupmy siΩ na temacie wprowadzania w ruch zdefiniowanych obiekt≤w. Aby dokonaµ animacji musimy, po pierwsze, ustaliµ warunki trwania animacji w czasie (czas pocz▒tku, ko±ca, szybko╢µ itd.) u┐ywaj▒c w tym celu wΩz│a TimeSensor oraz okre╢liµ trasΩ animacji, czyli drogΩ po jakiej bΩdzie porusza│ siΩ obiekt - a tego dokonujemy z kolei definiuj▒c wΩz│y interpolacji. Interpolacja polega na tym, ┐e po okre╢leniu kilku punkt≤w, do kt≤rych obiekt ma zmierzaµ, przegl▒darka sama oblicza trasΩ miΩdzy tymi punktami. W zale┐no╢ci od zastosowanego typu wΩz│a interpolacji trasa ta mo┐e prowadziµ zar≤wno po prostej, jak i po krzywej.
Po zdefiniowaniu wΩz│a TimeSensor i wybranego wΩz│a interpolacji oraz obiektu, kt≤ry chcemy animowaµ, musimy powi▒zaµ zdarzenia wysy│ane przez te trzy elementy sceny. Zdarzenia wi▒┐emy ze sob▒ za pomoc▒ komendy ROUTE.
O zdarzeniach pisa│em ju┐ nieco miesi▒c temu, jednak przypomnijmy i uzupe│nijmy sobie najwa┐niejsze informacje na ich temat:

1. Zdarzenia, kt≤re wysy│aj▒ zdarzenie posiadaj▒ etykietΩ event_ out, natomiast zdarzenia, kt≤re przyjmuj▒ zdarzenie maj▒ etykietΩ event_in. Zdarzenia (lub pola), kt≤re mog▒ jednocze╢nie wysy│aµ i przyjmowaµ zdarzenia maj▒ etykietΩ exposedField.
2. U┐ywaj▒c komendy ROUTE zdarzeniu event_out przyporz▒dkowujemy zdarzenie event_in - nigdy na odwr≤t.
3. Zdarzenia mog▒ byµ │▒czone tylko wtedy, gdy maj▒ takie same typy warto╢ci, np. aby ze zdarzeniem event_out o typie warto╢ci SFBool mo┐na by│o powi▒zaµ jakie╢ zdarzenie event_in, to musi ono zawieraµ typ warto╢ci SFBool.

Przejd╝my do praktyki


Fragment programu, kt≤rego listing zamieszczono na kr▒┐ku ENTER CD 1/98 (Listing 2), pokazuje przyk│ad najprostszej animacji. Na pocz▒tku mamy zdefiniowane dwa wΩz│y, kt≤re jeszcze s▒ nam nie znane. Pierwszy z nich to NavigationInfo, kt≤ry m≤wi przegl▒darce o warunkach, w jakich u┐ytkownik bΩdzie eksplorowa│ ╢wiat wirtualny. Mo┐na tu okre╢liµ takie opcje jak: wymiary avatara (uczestnika ╢wiata), w│./wy│. ╢wiat│o headlight, prΩdko╢µ poruszania siΩ po ╢wiecie, rodzaj eksploracji (chodzenie, badanie, latanie), ograniczenie widoczno╢ci. W naszym przyk│adzie mamy wy│▒czone ╢wiat│o headlight i mamy jedynie mo┐liwo╢µ badania (EXAMINE) obiekt≤w na scenie. Drugim nie stosowanym przez nas jeszcze wΩz│em jest wΩze│ Viewpoint. Mo┐emy w nim zdefiniowaµ (bardzo wiele) punkt≤w patrzenia na ╢wiat VRML. WΩze│ ten jest szalenie pomocny przy eksploracji ╢wiata, zw│aszcza dla os≤b, kt≤re jeszcze nie najlepiej s▒ zapoznane z przegl▒dark▒ VRML. W naszym przyk│adzie pierwszy viewpoint nazywa siΩ START i umieszczony jest na dodatniej osi Z, a "kamera" skierowana jest domy╢lnie w prz≤d. NastΩpnie widzimy dobrze znany nam wΩze│ DirectionalLight, kt≤ry odpowiada za o╢wietlenie obiekt≤w zgromadzonych w wΩ╝le grupuj▒cym - w tym przypadku o╢wietli on nasz▒ kulΩ w kierunku ujemnej strony osi X, czyli z prawej strony na lew▒.

Definiowanie element≤w animacji


Najpierw okre╢lamy warunki "czasowe" dla ruchu naszego obiektu wprowadzaj▒c wΩze│ TimeSensor. Jak widzimy przed definicj▒ wΩz│a umieszczona jest (ju┐ nam znajoma) komenda DEF i nazwa wΩz│a "CzasRuchu". DEFiniowanie, czyli "wrzucanie do pamiΩci" nazw, kt≤re bΩd▒ reprezentowaµ dane wΩz│y jest niezbΩdne potem przy u┐yciu komendy ROUTE. W wΩ╝le TimeSensor najistotniejszymi obecnie dla nas s▒: loop i cycleInterval. Pole loop odpowiada za to, czy animacja ma siΩ ci▒gle powtarzaµ (pole to mo┐e przybieraµ warto╢ci typu SFBool, czyli TRUE lub FALSE). Pole cycleInterval odpowiada za prΩdko╢µ animacji - im wiΩksza warto╢µ w tym polu, tym animacja bΩdzie wolniejsza.
Do animacji zosta│ wybrany wΩze│ OrientationInterpolator ("Interpolacja"), kt≤ry oblicza funkcjΩ interpolacyjn▒ obrotu obiektu. Obr≤t obiektu definiujemy w polu key okre╢laj▒c liczbΩ "moment≤w kluczowych animacji", czyli takich punkt≤w, w kt≤rych dany obiekt ma byµ obr≤cony o warto╢µ okre╢lon▒ w polu keyValue. WΩze│ korzystaj▒c z p≤l key i keyValue oblicza funkcjΩ interpolacyjn▒ obrotu obiektu. Liczba warto╢ci w polu key i keyValue musi byµ identyczna. Dlaczego wiΩc nasz obiekt nie obraca siΩ wok≤│ w│asnej osi tylko kr▒┐y wok≤│ jakiego╢ punktu? Dlatego, ┐e w polu translation wΩz│a Transform zosta│o dodatkowo okre╢lone przesuniΩcie (5 0 0) - po zmianie warto╢ci 5 na 0 obiekt bΩdzie siΩ krΩci│ tylko wed│ug w│asnej osi.
Poeksperymentujmy z warto╢ciami p≤l rotation i translation, a usyskamy bardzo ciekawe efekty. Na ko±cu widzimy wspomniane wy┐ej zastosowanie wΩz│a ROUTE. U┐ycie tej komendy mo┐na zapisaµ jako:

ROUTE [nazwa zDEFiniowanego wΩz│a].[zdarzenie_changed] TO [nazwa zDEFiniowanego wΩz│a].[set_zdarzenie]

W pierwszej linii widzimy powi▒zanie zdarzenia wΩz│a TimeSensor fraction_changed ze zdarzeniem wΩz│a OrientationInterpolator set_fraction (warto╢ci typu SFFloat). Stworzyli╢my wiΩc podstawΩ animacji: czas powi▒zali╢my z tras▒. W drugiej linii komend▒ ROUTE do trasy animacji przyporz▒dkowujemy ju┐ konkretny obiekt │▒cz▒c zdarzenie value_changed wΩz│a OrientationInterpolator z polem exposedField rotation (zapisuj[KD1]▒c jako set_rotation) wΩz│a Transform (warto╢ci typu SFRotation). Aby dok│adnie przeanalizowaµ po│▒czenie tych zdarze±, proponujΩ siΩgn▒µ do szczeg≤│owego opisu wΩz│≤w TimeSensor, OrientationInterpolator i Transform, kt≤ry mo┐na znale╝µ w specyfikacji VRML 97 (www.vrml.org/Specifications/VRML97/DIS/index.html).

Tworzymy karuzelΩ


Skoro ju┐ wiemy, jak wprowadziµ dany obiekt w ruch, spr≤bujmy trochΩ rozbudowaµ nasz przyk│ad i stworzyµ cyberkaruzelΩ. Wyobra╝my sobie, ┐e siedzeniami bΩd▒ cztery kule, punkt obrotu karuzeli bΩdzie stanowi│ walec, a siedzenia do punktu centralnego po│▒czymy prΩtami (bardzo w▒skimi walcami). Zacznijmy od pomno┐enia liczby siedze± (kul). Zastosujemy tutaj dobrze nam znany (i lubiany) mechanizm DEF/USE. WΩze│, kt≤ry bΩdziemy chcieli ponownie przywo│aµ jest ju┐ zDEFiniowany i nazywa siΩ "ObrotKuli" - pozostaje nam wiΩc tylko przywo│aµ ten wΩze│ jeszcze trzykrotnie w innych miejscach. Poni┐sze linie dopiszmy przed (lub po) definicji tras: LISTING 3 - znajduje siΩ na kr▒┐ku ENTER CD 1/98 w katalogu LISTINGI.
Zbudujmy teraz walec, kt≤ry bΩdzie stanowi│ centraln▒ czΩ╢µ naszej cyberkaruzeli. Tu┐ pod wcze╢niejszymi liniami dopiszmy:
LISTING 4 - znajduje siΩ na kr▒┐ku ENTER CD 1/98 w katalogu LISTINGI.
NastΩpnie zdefiniujmy "rurki", kt≤re bΩd▒ │▒czyµ siedzenia z centralnym walcem. Poniewa┐ "rurki" r≤wnie┐ bΩd▒ w ruchu, informacjΩ o ich w│a╢ciwo╢ciach musimy zawrzeµ w wΩ╝le "ObrotKuli", gdy┐ tylko dla tego wΩz│a zdefiniowana jest trasa animacji. Dlatego pod definicj▒ kuli-siedzenia (czyli po { radius 1 } }) dopiszmy kolejne linie programu: LISTING 5 - znajduje siΩ na kr▒┐ku ENTER CD 1/98 w katalogu LISTINGI.
Tego elementu karuzeli nie musimy ju┐ powielaµ, gdy┐ zdefiniowali╢my go w wΩ╝le, w kt≤rym wystΩpuj▒ (wcze╢niej przez nas powielone) siedzenia, dlatego "rurki" automatycznie bΩd▒ cztery. W tym momencie mamy ju┐ zdefiniowan▒ ca│▒ karuzelΩ. Chcecie siΩ trochΩ pokrΩciµ? Nic prostszego - w wΩ╝le ObrotKuli po definicji drugiego dziecka (czyli children [), a przed definicj▒ wΩz│a siedzenia dodajmy nastΩpuj▒ce linie:

DEF Karuzela Viewpoint { orientation 0 1 0 1.57 position 0 2 0 description "Siedzenie" }

A do definicji tras animacji dodajmy liniΩ:

ROUTE CzasRuchu.isActive TO Karuzela.set_bind

Sto┐ek i kula
W ten spos≤b stworzyli╢my ruchomy Viewpoint. Gdy teraz za│adujemy nasz ╢wiat do przegl▒darki VRML, pod prawym klawiszem myszki uka┐e nam siΩ menu, z kt≤rego wybierzcie opcjΩ Viewpoint. Uka┐▒ wam siΩ wszystkie zdefiniowane "punkty patrzenia na ╢wiat" i spr≤bujcie, na kt≤rym siedzeniu bΩdzie wam najwygodniej. Aby siΩ upewniµ, ┐e na pewno siΩ krΩcimy, dodajmy do naszej sceny jaki╢ nieruchomy obiekt, kt≤ry bΩdzie dla nas punktem odniesienia, np. drzewo (w ko±cu to karuzela wiΩc jaki╢ park by siΩ przyda│). Na ko±cu naszego kodu ╝r≤d│owego dopiszmy nastΩpuj▒ce linie.

Transform { translation 20 -1 0 children Inline { url "drzewko.wrl" } }

Tak powinna ostatecznie wygl▒daµ nasza karuzela
Tak powinna ostatecznie wygl▒daµ nasza karuzela
TrochΩ dziwne, prawda? Zastosowa│em tutaj wΩze│ Inline, kt≤ry daje mo┐liwo╢µ do│▒czenia do naszego ╢wiata inne ╢wiaty VRML.
Zadanie dla Czytelnik≤w: stw≤rzcie drzewko (np. ze sto┐ka i kuli), sw≤j plik nazwijcie drzewko.wrl i uruchomcie w waszej przegl▒darce powy┐ej zdefiniowany ╢wiat. Powinno dzia│aµ.
PS. Zastosujcie mechanizm DEF/USE do zwiΩkszenia liczby drzew. Wszelkie pytania do mnie mo┐na kierowaµ pod adres bombadil@novell.ibin.uw.edu.pl.

(c) Copyright LUPUS