Tworzenie rzeźby terenu (węzeł ElevationGrid)

Dzięki węzłowi ElevationGrid możemy utworzyć nawet bardzo urozmaiconą (dołki, górki, górki, dołki) rzeźbę terenu. W skład tego węzła w wchodzą następujące pola:

ElevationGrid {
  eventIn      MFFloat  set_height
  exposedField SFNode   color             NULL
  exposedField SFNode   normal            NULL
  exposedField SFNode   texCoord          NULL
  field        MFFloat  height            []
  field        SFBool   ccw               TRUE
  field        SFBool   colorPerVertex    TRUE
  field        SFFloat  creaseAngle       0    
  field        SFBool   normalPerVertex   TRUE
  field        SFBool   solid             TRUE
  field        SFInt32  xDimension        0
  field        SFFloat  xSpacing          1.0
  field        SFInt32  zDimension        0
  field        SFFloat  zSpacing          1.0
}

Zasada działania tego węzła jest bardzo prosta. Najpierw należy utworzyć dwuwymiarową siatkę rozciągnięta między osią X a Z, następnie ustalamy wysokości punktów, w których siatka się przecina. Siatkę tworzymy za pomocą pól xDimension i zDimension (oba typu SFInt32) definiując w nich ilość linii, które będą się przecinać. W polach xSpacing i zSpacing (oba typu SFFloat) ustalamy odległości między tymi liniami - rozrzedzając lub zagęszczając siatkę.

Teraz wystarczy jedynie zdefiniować pole height (typu MFFloat), gdzie każdemu punktowi przecięcia linii siatki podporządkowujemy wysokość wierzchołków. Pierwsza wartość w tym polu odnosi się do punktu (0, 0) w układzie (X, Z), następne wartości odnoszą się do kolejnych punktów znajdujących się na osi X (będzie tych wartości tyle ile określone zostało w polu xDimension). Kiedy opiszemy wszystkie wartości na osi X dla Z=0 wtedy następnym punktem, który należy opisać w polu height będzie pierwszy punkt znajdujący się na dodatniej stronie osi Z dla X=0. Kolejno opisujemy pozostałe punkty od X=0 do X=n, aż do chwili opisania wszystkich punktów przecięcia siatki. Ilość wartości w polu height musi być równa działaniu xDimension * zDimension.

Poniższe demo węzła ElevationGrid napewno ułatwi wam zrozumienie tego węzła.

W polu ccw określamy porządek współrzędnych wierzchołków użytych w celu utworzenia bryły. Jeżeli w polu tym znajdzie się wartość TRUE to oznacza to, że wierzchołki tworzące jedną ścianę bryły, definiowane są w kierunku przeciwnym do ruchu wskazówek zegara. Jeżeli pole to przyjmie wartość FALSE będzie to oznaczać, że wierzchołki te będą definiowane zgodnie z ruchem wskazówek zegara. W polu solid wartość FALSE oznacza, że każdy z wielokątów wchodzących w skład definiowanej bryły będzie renderowany niezależnie od tego, czy użytkownik ma ku niemu zwrócony wzrok, czy nie.

Pole color pozwala przypisać inny kolor każdemu wierzchołkowi bądź każdemu wielokątowi, zdefiniowanemu w węźle ElevationGrid. W polu color możemy zdefiniować węzeł Color, jednak wartości, które mogą się w nim znaleźć zależne są od pola colorPerVertex. Pole colorPerVertex określa czy kolory zdefiniowane w polu color będą przypisane do każdego wierzchołka (TRUE) czy do każdego czworoboku (FALSE).

Pole normal przypisuje każdemu wierzchołkowi bądź czworobokowi wektory normalne. W polu normal możemy zdefiniować węzeł Normal, jeżeli tego nie zrobimy przeglądarka automatycznie wygeneruje wektory normalne (prostopadłe do powierzchni) korzystając z wartości pola creaseAngle. Jeśli kąt między dwoma płaszczyznami będzie mniejszy od kąta zawartego w polu creaseAngle to krawędzie tych dwóch płaszczyzn powinny być delikatnie wycieniowane. Podobnie jak to było w przypadku kolorów, cieniowanie możemy przypisać albo do wierzołków albo do wielokątów (pole normalPerVertex).

W polu texCoord możemy zdefiniować węzeł TextureCoordinate odpowiadający za nałożenie tekstury na obiekty o budowie wierzchołkowej.
 
Przykład:

Powiedzmy, że teren, który chcemy zdefiniować będzie oparty na siatce X=5 i Z=5 (aby nie definiować za dużo wartości w polu height). Węzeł ElevationGrid traktujemy jak każdy inny obiekt w związku z czym definicję tego węzła umieszczamy w polu geometry węzła Shape:

#VRML V2.0 utf8

Shape {
   appearance Appearance { material Material {
                                    diffuseColor 0 1 1}
                         }
   geometry ElevationGrid {
               xDimension 5
               zDimension 5 ...

Następnie ustalamy odległości między liniami siatki (między liniami wychodzącymi s osi X - 2, a dla osi Z - 4):

            ...xSpacing 2
               zSpacing 4 ...

Teraz, w polu height, definiujemy wysokości dla punktów, w których siatka się przecina. Jak było wcześniej powiedziane, liczba tych wartości musi być równa działaniu xDimension * zDimension - czyli w naszym przypadku 5*5=25.
Zaczynamy od definiowania wysokości w punkcie X=0, Z=0; następnie definiujemy wysokości dla wszystkich punktów na osi X dla Z=0. W polu height pierwsza wartość ma indeks [0], w naszym przykładzie ostatnia wartość na osi X dla Z=0 będzie miała indeks [4] (jak na rysunku powyżej). Zdefiniujmy teraz wysokości dla punktów znajdujących się na osi X przy Z=0:

               height [ 0, 0.5, 0, 1, 0, ...

Następnie definiujemy wysokości dla Z=1:

                     ...0, 0.3, 0.1, 0.2, 0, ...

dla Z=2:

                     ...0, 0.2, 0.2, 0, 0, ...

dla Z=3:

                     ...0.2, 0.1, 0.3, 0.2, 0, ...

dla Z=4:

                     ...0.1, 0, 0.5, 0.1, 0.1 ]
                    }
        }

Po dodaniu definicji światła oraz miejsca patrzenia - nasz przykład będzie wyglądał następująco:

#VRML V2.0 utf8

Viewpoint { position 3 2 20 }

NavigationInfo { headlight FALSE
                 type "FLY"}

DirectionalLight {direction 0 -0.5 0.5}

Shape { appearance Appearance { material Material {
                                         diffuseColor 0 1 1}
                              }
   geometry ElevationGrid {
               xDimension 5
               zDimension 5
               xSpacing 2
               zSpacing 4
               height [ 0, 0.5, 0, 1, 0,
                        0, 0.3, 0.1, 0.2, 0,
                        0, 0.2, 0.2, 0, 0,
                        0.2, 0.1, 0.3, 0.2, 0,
                        0.1, 0, 0.5, 0.1, 0.1 ]
                    }
        }

Zobaczmy teraz jak będzie ten świat wyglądał w naszej przeglądarce.