Tworzenie złożonych obiektów
(węzły IndexedFaceSet, IndexedLineSet, PointSet i Extrusion) 
Tworzenie obiektów za pomocą węzłów IndexedfaceSet, IndexedLineSet i PointSet opiera się na prostej metodzie wyznacznia punktów w przestrzeni trójwymiarowej a następnie łączenia tych punktów. Każdy z tych trzech węzłów w inny sposób traktuje określone przez nas punkty. Węzeł IndexedfaceSet używa ich do utworzenia dwuwymiarowych wielokątów - trzy połączone ze sobą punkty tworzą wielokąt. Z pojedynczych wielokątów dwuwymiarowych tworzone są potem obiekty trójwymiarowe. Węzeł IndexedLineSet tworzy linie między minimum dwoma punktami a węzeł PointSet tworzy pojedyncze, świecące w przestrzeni punkty.

Węzeł Extrusion, który omówimy na końcu tworzy obiekty trójwymiarowe z dwuwymiarowego planu obiektu.



IndexedFaceSet {
  eventIn       MFInt32 set_colorIndex
  eventIn       MFInt32 set_coordIndex
  eventIn       MFInt32 set_normalIndex
  eventIn       MFInt32 set_texCoordIndex
  exposedField  SFNode  color             NULL
  exposedField  SFNode  coord             NULL
  exposedField  SFNode  normal            NULL
  exposedField  SFNode  texCoord          NULL
  field         SFBool  ccw               TRUE
  field         MFInt32 colorIndex        []
  field         SFBool  colorPerVertex    TRUE
  field         SFBool  convex            TRUE
  field         MFInt32 coordIndex        []
  field         SFFloat creaseAngle       0
  field         MFInt32 normalIndex       [] 
  field         SFBool  normalPerVertex   TRUE
  field         SFBool  solid             TRUE
  field         MFInt32 texCoordIndex     []        
}

W węźle IndexedfaceSet można utworzyć trójwymiarowy obiekt poprzez osobne zdefiniowanie każdej jego ściany. Ściany te sładają się z wielokątów, których wierzchołki wyznaczamy w polu coord typu SFNode (węzeł Coordinate). Zdefiniowane punkty łączymy według ustalonych zasad w polu coordIndex węzła IndexedfaceSet. Wartość -1 w polu coordIndex wskazuje na to, że kończy się definicja pierwszego wielokąta i zaczyna następnego. Jeśli liczba zdefiniowanych punktów w węźle Coordinate wynosi N, to liczba wartości w indeksie (pole coordIndex) powinna być N-1. Dzieje się tak dlatego, że indeksowanie przebiega od 0 do N. Każda zdefiniowana ściana obiektu powinna zawierać przynajmniej trzy nie pokrywające się wierzchołki, które definiują płaski wielokąt.

Spójrzmy na przykład definiujący jeden wielokąt - kwadrat, bok sześcianu:

#VRML V2.0 utf8

Transform {
    translation 0 0 0
    rotation 0 1 0 -3.14
    children [
         Shape { appearance NULL
                 geometry IndexedFaceSet {
                 coord Coordinate { point  [ -1 -1 0,   #punkt [0]
                                             -1  1 0,   #punkt [1]
                                              1  1 0,   #punkt [2]
                                              1 -1 0 ]  #punkt [3]
                                         }
                                    coordIndex [0, 1, 2, 3, -1]
 
                                 }
             }
           ]
}

Na początku występuje standardowy opis węzła grupującego i węzła Shape odpowiadającego za tworzenie i wyświetlanie obiektów. Następnie w polu coord węzła IndexedfaceSet widzimy zdefiniowane w przestrzeni trójwymiarowej cztery punkty. W polu coordIndex następuje ich połączenie w odpowiedniej kolejności i zamknięcie wielokątu cyfrą -1.

Przyjrzyjmy się teraz innym polom węzła IndexedfaceSet. W polu ccw typu SFBool 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, 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 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 wyświetlany niezależnie od tego, czy użytkownik ma ku niemu zwrócony wzrok, czy nie. Wartość TRUE powoduje, że niewidoczne wielokąty nie są wyświetlane, dzięki czemu wyświetlanie świata jest płynniejsze. Pole convex wskazuje na to, czy wszystkie ściany kształtu są wypukłe.

W polach color, normal, texCoord możemy zdefiniować odpowiednio węzły Color, Normal i TextureCoordinate. Użycie tych węzłów wiąże się również z zastosowaniem pozostałych pól węzła IndexedFaceSet: colorIndex (typu MFInt32), colorPerVertex, normalIndex, normalPerVertex, texCoordIndex. Zależności między tymi wszystkimi elementami opisują dosyć złożone zasady.

Zdarzenia, które węzeł IndexedfaceSet może przyjąć, można wykorzystać do przekształceń (animowania) każdego z pól, którego zdarzenia te dotyczą.

Za pomocą węzła IndexedfaceSet można tworzyć obiekty o dowolnych kształtach. Jednak węzeł ten żadko jest używany przez programistów piszących kody źródłowe światów z klawiatury. Węzeł ten jest natomiast nagminnie wykorzystywany przes edytory VRML (VRCreator, Home Space Designer) bo czyjest coś prostszego dla programu komputerowego niż zapisanie obiektów trójwymiarowych za pomocą liczb?

Stosowanie węzła IndexedfaceSet ma jednak pewien poważny minus. Tworzenie obiektów za pomocą tego węzła bardzo zwiększa wielkość pliku VRML, co tym samym wydłuża czas potrzebny na ściągnięcie pliku. Dlatego bardzo uważajcie ze stosowaniem tego węzła. Powyżej widzieliście zdefiniowany jeden bok sześcianu. Wyobraźcie sobie teraz, że chcecie utworzyć cały sześcian, czyli do powyższego przykładu należy dodać jeszcze definicję siedmiu ścian. Porównajcie to teraz z definicją węzła Box:

Box { size 2 2 2 }

Rezultat wizualny ten sam a o ile bardziej ekonomiczny.


IndexedLineSet {
  eventIn       MFInt32 set_colorIndex
  eventIn       MFInt32 set_coordIndex
  exposedField  SFNode  color             NULL
  exposedField  SFNode  coord             NULL
  field         MFInt32 colorIndex        []  
  field         SFBool  colorPerVertex    TRUE
  field         MFInt32 coordIndex        []  
}

Węzeł IndexedLineSet tworzy linie w przestrzeni trójwymiarowej przebiegające między zdefiniowanymi wierzchołkami. Wierzchołki te definiujemy w polu coord, w którym umieszczamy definicję węzła Coordinate. Kolejność łączenia wierzchołków ustanawiamy tworząc indeks w polu coordIndex, gdzie definiowanie jednej linii kończymy wartością -1.
Linie zdefiniowane w tym polu nie uczestniczą w  kolizji, nie można na nie również nałożyć tekstury ani ich oświetlić. Ich szerokość zależy od tego, jak przeglądarka interpretuje węzeł IndexedLineSet. Można natomiast nadać im dowolny kolor.

#VRML V2.0 utf8

Transform {
 translation 0 0 0
 rotation 0 1 0 -3.14
 children [
  Shape { appearance NULL
     geometry DEF Trojkat IndexedLineSet {
        coord Coordinate { point  [ 1 0 0,
                                   -1 0 0,
                                    0 1 0 ]
                                         }
                           coordIndex [0, 1, 2, 0, -1]
                         }
        }
  Transform {
   rotation 0 1 0 -1.57
   children [
    Shape { geometry USE Trojkat }
    ]
   }
  Transform {
   rotation 0 1 0 -0.8
   children [
    Shape { geometry USE Trojkat }
    ]
   }
  Transform {
   rotation 0 1 0 0.8
   children [
    Shape { geometry USE Trojkat }
    ]
   }
  ]
 }

Powyższy przykład pokazuje jak można uzyskać w miarę ciekawy efekt stosując węzeł IndexedLineSet i mechanizm DEF/USE.

Zasady użycia pól color, colorIndex i colorPerVertex opisane są tutaj.


PointSet {
  exposedField  SFNode  color      NULL
  exposedField  SFNode  coord      NULL
}

Węzeł PointSet definiuje punkty w przestrzeni trójwymiarowej. Każdemu z punktów możemy nadać inny kolor. W polu coord możemy zdefiniować węzeł Coordinate, w którym wprowadzamy współrzędne punktów. W polu color natomiast umieszczamy węzeł Color, w którym każdemu z punktów określonych w polu coord przypisujemy określony kolor.

Jeżeli pole color będzie miało wartość NULL, a w węźle Shape, w którym definiujemy węzeł PointSet, znajdzie się definicja węzła Material to dla wszystkich zdefiniowanych punktów powinien zostać przyjęty kolor określony w polu emissiveColor.

Na punkty zdefiniowane w węźle PointSet nie mają wpływu światła zdefiniowane na scenie.

Wspaniałym przykładem wykorzystania węzła PointSet jest świat znajdujący się w naszej galerii Czarnej Dziury, pt: Virtual Head II.


Extrusion {
  eventIn MFVec2f    set_crossSection
  eventIn MFRotation set_orientation
  eventIn MFVec2f    set_scale
  eventIn MFVec3f    set_spine
  field   SFBool     beginCap         TRUE
  field   SFBool     ccw              TRUE
  field   SFBool     convex           TRUE
  field   SFFloat    creaseAngle      0
  field   MFVec2f    crossSection     [ 1 1, 1 -1, -1 -1,
                                       -1 1, 1  1 ]
  field   SFBool     endCap           TRUE
  field   MFRotation orientation      0 0 1 0
  field   MFVec2f    scale            1 1
  field   SFBool     solid            TRUE
  field   MFVec3f    spine            [ 0 0 0, 0 1 0 ]
}

Dzięki węzłowi Extrusion możemy tworzyć trójwymiarowe obiekty o dowolnym wyglądzie. Najpierw w polu crossSection typu MFVec2f tworzymy dwuwymiarowy przekrój naszej bryły. Następnie w polu spine definiując trójwymiarowe wektory nadajemy przekrojowi trzeci wymiar.

Każdemu punktowi opisanemu w polu spine typu MFVec3f możemy przypisać operację skalowania (pole scale) lub obrotu (pole orientation). Jeżeli zdecydujemy się na zastosowanie tych pól, to liczba wartości w tych polach musi być identyczna z liczbą wartości w polu spine. Aby w polu scale uzyskać efekt zmiejszenia, wartości muszą zawierać się między 0 a 1. Wartości powyżej 1 będą powodowały zwiększanie obiektu.

Obiekt utworzony przez węzeł Extrusion składa się zasadniczo z trzech części: płaszczyzn stanowiących boki obiektu oraz przestrzeni wyznaczonej przez pierwszą i ostatnią wartość w polu spine. Za zamknięcie tej pierwszej przestrzeni odpowiada pole beginCap, a za zamknięcie przestrzeni końcowej pole endCap. Pola te nie mają wpływu na wygląd obiektu, jeżeli punkty określone w polu crossSection będą tworzyły zamkniętą bryłę.

Sposób działania pól ccw, solid i convex opisany został przy okazji omawiania węzła IndexedFaceSet.

Zobaczmy na przykład zastosowania węzła Extrusion:

#VRML V2.0 utf8

Shape {
    appearance Appearance { material Material {
                           diffuseColor 0 0 1 }
                       }
    geometry Extrusion {
              creaseAngle 0
              crossSection [0.92 -0.38,0.38 -0.92,-0.38
                           -0.92,-0.92 -0.38, -0.92 0.38,
                           -0.38 0.92,0.38 0.92,0.92 0.38,
                            0.92 -0.38 ]

       spine [ 0 -2 0, 0 -1.5 0, 0 -1 0, 0 -0.5 0, 0 0 0,
               0 0.5 0, 0 1 0, 0 1.5 0, 0 2 0 ]
       scale [ 2 2, 1.7 1.7, 1 1, 0.7 0.7, 1.5 1.5,
               0.7 0.7, 1 1, 1.7 1.7, 2 2 ]
 
       }
}

Bardzo namawiam do ekperymentów z tym węzłem gdyż można w nim uzyskać bardzo ciekawe efekty tworząc w sumie niewielki kod źródłowy. Plik, w którym ten sam obiekt utworzony by został węzłem IndexedFaceSet byłby o wiele większy.