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

Silnik 3D dla początkujących I [podstawowy]

Jeśli ktokolwiek miał ochotę zbudować własny silnik 3D we Flash'u (ale nie tylko) nie wiedząc dokładnie czego się spodziewać, przy szukaniu informacji na pewno został przywitany mnóstwem matematyki i zaawansowanych metod programowania. Może to być trochę zniechęcające pod czas gdy prawda jest tak, że nie potrzebujesz tego wszystkiego by stworzyć coś podstawowego jak np. aplikacje wyświetlającą trójwymiarową kostkę.
Dlatego w tym poście napisze jak stworzyć silnik 3D dla całkowitych nowicjuszy w temacie (który wyświetli owa kostkę).

Całość będzie zawierać się tylko w jednej klasie - najlepiej niech będzie to klasa dokumentu. W razie czego "Klasę Dokumentu" można stworzyć na zakładce właściwości.

(Po wpisaniu nazwy klasy należy kliknąć ikonkę ołówka).
Po stworzeniu nowej klasy pierwszym krokiem będzie przygotowanie zmiennych których będziemy używać w silniku. Zacznijmy od pozycji kamery:

var cx:Number = 0;
var cy:Number = 0;
var cz:Number = 0;
Na razie nic szczególnego - od pozycji kamery zależy co będziemy widzieć na ekranie. Może w tym momencie wyjaśnię jak będzie wyglądał ruch na osiach (gdyż nie musimy się trzymać podstaw matematyki i to od nas zależy gdzie będzie góra a gdzie dół):
cx to ruch w lewo(-) albo prawo(+).
cy to ruch w górę(-) albo w dół(+).
cz to ruch do tyłu/"od ekranu"(-) albo do przodu/"do ekranu"(+).
Okej, teraz potrzebujemy punktu do którego będzie się zbiegać obraz:
var vx:Number = stage.stageWidth/2;
var vy:Number = stage.stageHeight/2;
Punkt zbiegu zwykle znajduje się na środku ekranu, tak więc najprościej po prostu podzielić szerokość i wysokość aplikacji na pół. Aczkolwiek nic nie stoi na przeszkodzie by wybrać własną pozycję (tylko, że będzie się to wiązać ze zmianą metody transformacji o której wspomnę później). Przy okazji, na ekranie punkt 0,0 znajduje się w lewym górnym rogu, a wszystko na prawo lub dół od niego to liczby dodatnie.
Ostatni zestaw zmiennych to sześcian który będziemy wyświetlać w 3D:
var bx:Array = [-50, 50, 50, -50, -50, 50, 50, -50];
var by:Array = [-50, -50, 50, 50, -50, -50, 50, 50];
var bz:Array = [200, 200, 200, 200, 300, 300, 300, 300];
Tutaj definiujemy 3 tablice z punktami opisującymi pozycje kątów naszego trójwymiarowego pudła. Na przykład biorąc wartości bx[0],by[0],by[0] otrzymamy pozycje lewego górnego kąta na boku znajdującym się najbliżej kamery.
Teraz gdy już mamy wszystkie potrzebne parametry możemy przystąpić do stworzenia funkcji generującej obraz 3D. Najlepiej jest ją podłączyć do zdarzenia ENTER_FRAME by animacja była płynna, dlatego w konstruktorze swojej klasy dopisz:
addEventListener(Event.ENTER_FRAME,render);
Nie zapomnij zaimportować flash.events.Event! Jak widzisz ja swoją funkcję nazwałem "render" i na początek wygląda ona tak:
private function render(e:Event):void {
 graphics.clear();
}
Standardowa definicja funkcji. Linijka graphics.clear(); będzie nam potrzebna gdyż proces renderowania zawsze polega na tym samym - przy wejściu do nowej klatki animacji usuwamy starą grafikę i wstawiamy nową (wstawianiem zajmiemy się za chwilę). W każdym razie, czas przejść do najważniejszej części aplikacji, czyli przetwarzania informacji 3D na 2D (ponieważ jak na razie ekrany monitorów potrafią wyświetlić jedynie dwuwymiarowy obraz):
var bx2:Array = new Array(bx.length);
var by2:Array = new Array(by.length);
var i:Number = 0;
while (i<bx.length) {
	bx2[i] = vx+(((cx-bx[i])/(cz-bz[i]))*vx);
	by2[i] = vy+(((cy-by[i])/(cz-bz[i]))*vy);
	++i;
}
Tak więc po kolei:
var bx2:Array = new Array(bx.length);
var by2:Array = new Array(by.length);
Te dwie tablice będą przechowywać wszystkie punkty po transformacji do 2D.
Dalej, w pętli, mamy:
bx2[i] = vx+(((cx-bx[i])/(cz-bz[i]))*vx);
by2[i] = vy+(((cy-by[i])/(cz-bz[i]))*vy);
Czyli kod odpowiedzialny za ową transformację. Powiedzmy sobie szczerze, nikt nie musi rozumieć tych równań by z nich korzystać dlatego nic nie stoi na przeszkodzie by pominąć poniższe wyjaśnienie i ewentualnie powrócić do niego w przyszłości:
cx-bx[i] - odejmujemy pozycję punktu od kamery by otrzymać wektor przesunięcia. Jest to standardowe działanie przy większości transformacji, ponieważ nie obchodzi nas gdzie znajduje się punkt, tylko w jakiej jest odległości od kamery - taką relatywną informacje jest łatwiej przenieść między przestrzeniami.
cz-bz[i] - tutaj wyliczamy odległość punktu od kamery. Potrzebujemy tej wartości by stworzyć iluzję perspektywy.
(cx-bx[i])/(cz-bz[i]) - tworzymy iluzję perspektywy o której wspomniałem, czyli zmniejszamy obiekty im dalej znajdują się od kamery.
*vx - gdy już sobie poradziliśmy z perspektywą czas doliczyć kąt widzenia. Tylko nie koniecznie w zakresie w jakim można byłoby się spodziewać bo większa liczba rozciąga obraz (zmniejsza kąt). Wyraźnie nie ma to związku z punktem zbiegu dla którego zdefiniowaliśmy vx ale tak się składa, że również i tutaj najlepsza wartość to połowa ekranu.
vx+ - i w końcu nasz punkt zbiegu.

Teraz gdy już mamy wszystkie punkt w 2D, pozostaje je tylko wyświetlić:

//rysowanie:
graphics.lineStyle(1, 0xffffff, 100);
//przednia sciana:
graphics.moveTo(bx2[0], by2[0]);
graphics.lineTo(bx2[1], by2[1]);
graphics.lineTo(bx2[2], by2[2]);
graphics.lineTo(bx2[3], by2[3]);
graphics.lineTo(bx2[0], by2[0]);
//tylna sciana:
graphics.moveTo(bx2[4], by2[4]);
graphics.lineTo(bx2[5], by2[5]);
graphics.lineTo(bx2[6], by2[6]);
graphics.lineTo(bx2[7], by2[7]);
graphics.lineTo(bx2[4], by2[4]);
//linie laczace:
graphics.moveTo(bx2[0], by2[0]);
graphics.lineTo(bx2[4], by2[4]);
graphics.moveTo(bx2[1], by2[1]);
graphics.lineTo(bx2[5], by2[5]);
graphics.moveTo(bx2[2], by2[2]);
graphics.lineTo(bx2[6], by2[6]);
graphics.moveTo(bx2[3], by2[3]);
graphics.lineTo(bx2[7], by2[7]);
Linijka graphics.lineStyle(1, 0xffffff, 100); ustala wygląd linii którą będziemy rysować. Pierwsza wartość to grubość (w pikselach), druga to kolor, a ostatnia to przeźroczystość.
Dalej już samo rysowanie, zaczynając od przedniej ściany:

Dodajemy tylną ścianę:

Na koniec łączymy je by stworzyć sześcian:

(Oczywiście w aplikacji to wszystko zostanie narysowane natychmiast).
Jeśli wszystko przebiegło pomyślnie na ekranie aplikacji powinien pojawić się sześcian (taki sam jak na ostatnim obrazku).
W kolejnym kroku powinniśmy dodać możliwość przesuwania kamery ale to zostawię na jeden z późniejszych postów.

Cały kod jest do pobrania tutaj: box3d.zip


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