Strona wykorzystuje ciasteczka by usprawnić komfort z jej korzystania. Korzystając ze strony akceptujesz naszą Politykę Ciasteczek. X

Podstawy Stage3D część II: poruszanie kamerą i funkcja poinatAt [ekspert]

W poprzedniej części artykułu pisałem jak rozbudować przykład z dokumentacji ActionScript3 na temat grafiki 3D by obsługiwał wyświetlanie wielu obiektów przy jednoczesnym zachowaniu możliwości transformacji każdego obiektu z osobna. Pojawiła się tam również wzmianka o matrycy odpowiedzialnej za kamerę ("view"), która tak naprawdę nie do końca działała jak należy ponieważ brakowało w niej kilku podstawowych ustawień. Tu właśnie zaczyna się schody dla osób które nigdy nie miały styczności z grafiką 3D, ponieważ informacje dostępne w Internecie na temat owych ustawień i jak powinny wyglądać są dość mieszane, szczególnie że prawidłowe poruszanie kamerą będzie zależało od ustawień i implementacji samego środowiska 3D. Dlatego tą cześć artykułu o podstawach Stage3D poświecę prawidłowemu stosowaniu wirtualnej kamery, a w szczególności konstrukcji, pozycjonowaniu i korzystaniu z funkcji pointAt.

Zaczynając gdzie skończyliśmy ostatnim razem (kod źródłowy z poprzedniej części artykułu: Tutorial3D.zip) mamy już całkiem niezły start do zaimplementowanie wirtualnej kamery. Co prawda można dla niej przygotować jakąś osobną klasę, ale matryca na razie w zupełności wystarcza. W każdym razie, matryca kamery jest gotowa i można z niej skorzystać jednak rezultaty transformacji będą co najmniej... nieprzewidywalne, albo przynajmniej innej niż się można było by spodziewać (np. x+=-5 okaże się przesunięciem w prawo zamiast lewo). Wiąże się to z pominięciem pewnego szczegółu w funkcji renderującej w przykładzie dostarczonym przez Adobe, a który może nam przysporzyć kilku nieprzespanych nocy. O co dokładnie chodzi? Zerknijmy jak tworzona jest matryca finalTransform w funkcji render:

finalTransform.identity();   
finalTransform.append(box.getMatrix3D());   
finalTransform.append(world);   
finalTransform.append(view);   
finalTransform.append(projection);
Niby wszystko wydaje się w porządku, ale wystarczy się zatrzymać na chwilę i przyjrzeć dokładnie - powiedzmy, że chcemy aby cały świat był przesunięty w lewo, a kamera w prawo, dlatego ustawiamy world na x = -10, a view na x = 5. W idealnym świecie oznaczało by to, że teraz jest między nimi 15 jednostek różnicy, ale oczywiście w naszej aplikacji tak nie będzie, a wszystko przez to jak powstaje finalTransform. Spójrzmy jeszcze raz, world to przesuniecie o -10 a view o +5:
finalTransform.append(-10);   
finalTransform.append(5);
Wiec jaki będzie wynik? Oczywiście każdy obiekt w programie zostanie najpierw przesunięty w lewo (-10) a potem w prawo (+5), ostatecznie lądując na pozycji x = -5. Niby oczywista oczywistość, ale bardzo ważne jest zrozumienie, że tak naprawdę nie przesuwamy kamery, ale cały świat wokół niej. I to jest ten ważny szczegół: nie przesuwamy kamery w lewo, tylko cały świat w prawo! I prawda jest taka, że można było by to załatwić prostym "po prostu transformuj kamerę w przeciwnym kierunku i będzie ok", ale … to tragiczny pomysł - jeszcze rotacje i pozycje da się tak zmieniać, ale o funkcji poinatAt możesz zapomnieć. Na szczęście właściwie rozwiązanie jest bardzo proste, wystarczy obrócić matrycę widoku:
var camera:Matrix3D = view.clone();  
camera.invert();
Zgadza się, tyle wystarczy. Cała funkcja render będzie teraz wyglądać tak:
private function render(event:Event):void {  
renderContext.clear(.3, .3, .3);  
var camera:Matrix3D = view.clone();  
camera.invert();  
for each(var box:Box3D in vBox) {  
finalTransform.identity();  
finalTransform.append(box.getMatrix3D());  
finalTransform.append(world);  
finalTransform.append(camera);  
finalTransform.append(projection);  
renderContext.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, finalTransform, true);  
box.render(renderContext);  
}  
renderContext.present();  
}
Te dwie linijki kodu wystarczą by nasza kamera zaczęła działać dokładnie tak jak się tego spodziewamy, przesunięcie view w lewo autentycznie będzie wyglądać jakbyśmy przesunęli kamerę w lewo, a co najważniejsze będziemy mogli skorzystać z funkcji pointAt, o czym napiszę za chwilę. W tym momencie najlepiej byłoby przetestować poruszanie widokiem w rezultacie dostając coś takiego:
(Poruszanie na klawiszach strzałek)
W razie czego możesz skorzystać z kodu na końcu poradnika.
Teraz gdy już wszystko jest poprawnie ustawione, czas wziąć się za funkcję pointAt. Bez wiedzy o tym, że matryce view należy obrócić (funkcją invert) przed użyciem w finalTransform, pointAt nigdy nie działało by jak należy! Jednak to nie koniec problemów, zostaje jeszcze kwestia parametrów które są potrzebne dla pointAt, bo oczywiście domyślne nie będą działać. Te parametry to:
1. Pozycja celu - matryca zostanie zwrócona w kierunku tego punktu.
2. Kierunek zwrotu - innymi słowy kierunek "do przód" bez żadnych transformacji; dla kamery zawsze będzie to Vector3D(0, 0, -1).
3. Kierunek wznoszenia - w którą stronę jest "do góry"; domyślnie Vector3D(0, -1, 0).
To powinno wystarczyć. Poprawnie działający pointAt będzie wyglądać tak:
Niestety, zmiana pozycji nie uwzględnia kierunku w jakim spogląda kamera - zostawmy to na kiedy indziej.
Kod źródłowy: Tutorial3D-2.zip

Imię:
Komentarz:
Potwierdz kod z obrazka:confirm image

 
Aly Chiman pisze:
20.09.2018 05:03
Hello there, My name is Aly and I would like to know if you would have any interest to have your website here at 4as.pl promoted as a resource on our blog alychidesigns.com ? We are in the midst of updating our broken link resources to include current and up to date resources for our readers. Our resource links are manually approved allowing us to mark a link as a do-follow link as well . If you may be interested please in being included as a resource on our blog, please let me know. Thanks, Aly