Code snippets, ideas and events from IT related projects

by Robert Gawron

Fraktalny algorytm generowania terenu 3D w Javascript

21.05.2008 13:45, Posted in , 0 comments, 0 pingbacks

Wiele obiektów w przyrodzie ma kształt fraktalu, przykładowo liść paproci, chmury, czy też linia na granicy wody i piasku (nad rzeką/morzem). Nie są to dosłownie fraktale ale mają jedną z ich głównych cech - dowolnie duże powiększenie kształtem wciąż przypomina pierwotny (liść paprotki składa się z mniejszych listków a one z takich samych ale jeszcze mniejszych..).

Podobnie jest z terenem - mamy duże góry, na które nałożone są mniejsze itp.. Można by wykorzystać algorytm fraktalny do wygenerowania takiego kształtu. Służy do tego m.in. algorytm Diamond-square. Poniżej zrzut ze skryptu omówionego później wykorzystującego ten algorytm:

obrazek terenu - Robert Gawron

Działa to tak, iż bierzemy kwadrat, jego wierzchołki mogą mieć ustaloną bądź losową wysokość. Obliczamy wysokość środka kwadratu jako średnią wierzchołków plus małe zaburzenie. Wysokość środków boków kwadratu obliczamy jako średnią wysokości końców plus małe zaburzenie. Zaburzenie maleje wraz ze z ilością iteracji (im pod większym powiększeniem oglądamy teren, tym wypukłości są mniejsze - taki skrót myślowy).

Od razu powiem, że w mojej implementacji jest chyba błąd (a nie umiem go znaleźć), bo wynik wychodzi IMHO kiepski. Ogólnie to można to przejrzeć poklikać, zobaczyć OOP w JavaScript czy wykorzystać to do swoich celów ale kod w takiej postaci jak jest teraz jest do dupy :] Nie mówmy o wpadkach: fajnie wyszło to, że klase z algorytmem można podmienić i wygenerować teren wg. innego algorytmu (już mi się nie chciało pisać).

Kod napisany jest w obiektowo w JavaScript'cie, bo to się wydawało najprostsze do tego modelu, a do tego czytelnik może przetestować skrypt online. Do rysowania wykorzystany jest tag <canvas>, więc IE nie poradzi sobie z tym skryptem. Diagram UML klas wygląda tak:

obrazek terenu - Robert Gawron

Tym razem nie będzie listingów klas, natomiast będzie bliżej omówiony diagram klas. Teoretycznie to powinno wystarczyć do zrozumienia skryptu.

Klasa Screen odpowiedzialna jest za rysowanie, rzutowanie punktów, czyszczenie ekranu. Anyway ta klasa powinna być singletonem chyba.

  • canvasID - by rysować po tagu canvas musimy się do niego dostać, najprościej poprzez JavaScriptowe getElementById, to jest właśnie ID tagu, w którym chcemy rysować
  • width, height - opss, nie poprawiłem diagramu, to wymiary tagu na którym rysujemy, w kodzie teraz zamiast tego jest a, czyli dł boku (rysujemy na kwadracie, bo tak jest łatwiej).
  • azimuth, elevation, scaleFactor, near, nearToObj - z 3D musimy rzutować obiekty na 2D, by móc je wyświetlać na ekranie (canvas może obsługiwać 3d ale nie znalazłem bliższych szczegółów, więc jest to zakodowane żywcem). Algorytm rzutowania, te wszystkie sinusy etc. jest z gdzieś z neta wygrzebany.
  • step - o ile przesuwamy się klikając na góra/dół, prawo/lewo

Terrain to nasz algorytm, podmieniając obiekt tej klasy na obiekt innej można generować teren wg innego algorytmu. Zastanawiałem się, czy to algorytm ma ekran, czy ekran algorytm, tzn który obiekt powinien zawierać który.. Doszłem do wniosku, że to ekran ma algorytm.

  • len - ilość pkt wzdłuż i wszerz (czyli w sumie pkt. na mapie jest len*len).
  • str - jaki może być rozrzut skrajnych 4 pkt. Bez sensu ta zmienna jest :)
  • r, d0 - wygrzebane gdzieś z neta, do wzoru jak powinnien się zmieniać wsp. jaki może byc losowo dodany do punktu wraz z iteracją.

Point3D powinien dziedziczyć po Point2D, ale w JavaScript mi to nie wychodziło, więc są zakodowane żywcem. Pierwsza z tych klas służy do reprezentowania punktów na mapie, w rzeczywistej przestrzeni. Druga jest pomocnicza, by np. narysować linię na ekranie. Klasa Edge symbolizuje krawędź między dwoma punktami w przestrzeni 3D. Jakbyśmy nie rysowali krawędzi to by była tylko bezładna kupa kropek :)

To pierwszy raz, gdy stykam się z OOP w JavaScript i wrażenia są pozytywne. Jest inaczej niż np. w Javie czy w Perlu ale szybko można się połapać. Poniżej pokazany jest działający skrypt:

up
left start right
down

Poniżej znajduje się spis materiałów do pobrania. Kod testowałe pod Firefox/2.0.0.8. Tak offtopowo na koniec: no ostatni model czegoś na dłuższy czas tutaj, będzie bardziej konkretnie teraz (a niedługo o stream'ach, C i UDP ;))

  • Kod źródłowy - jako, że to JS, nie trzeba kompilatora, wystarczy przeglądarka :)
  • Diagram klas - plik źródłowy, do otwarcia np. w Umbrello

EDIT: kod przeszedł mały update by był bardziej zgodny z XHTML strict.. opss nie jest :/

Pingbacks

No pingbacks yet

Comments

No comments for this post

Leave your reply

Let me know what you think

Required. 30 chars of fewer.

Required.

captcha image