Czujniki obrotu i przesunięcia

Do grupy czujników obrotu i przesunięcia należą węzły PlaneSensor, CylinderSensor i SphereSensor. Ich działanie polega na tym, że na po kliknięciu i przytrzymaniu klawisza myszki na aktywnym obiekcie, możemy go przesuwać lub obracać - w zależności od rodzaju użytego węzła czujnikowego.

Ponieważ wszystkie te węzły mają podobną budowę proponuję abyśmy zaczęli od wyjaśnienia elementów wspólnych dla tych trzech węzłów.

Po pierwsze każdy z nich posiada pole offset (typu SFVec3f) i autoOffset, które odpowiadają za zapamiętanie stanu ostatniego przesunięcia (lub obrotu) obiektu. Jeśli pole autoOffset ma ustawioną wartość TRUE (wartość domyślna) to miejsce, w którym obiekt został zostawiony podczas ostatniego korzystania z węzła czujnikowego zostaje zapamiętane, i przy ponownym użyciu tego węzła ruch rozpocznie się właśnie od tego miejsca.

Pola maxPosition i minPosition (oba typu SFVec2f) wyznaczają granice wychylenia obiektu. W momencie gdy pole autoOffset będzie miało wartość FALSE możemy zdefiniować własny punkt, z którego zacznie się przesuwanie obiektu przy uaktywnieniu tych węzłów czujnikowych. Punkt ten definiujemy w polu offset.

Po drugie wszystkie z tych węzłów zawierają zdarzenie trackPoint_changed (typu SFVec3F), które zostaje  wysłane w chwili uaktywnienia węzła. Zdarzenie to „śledzi" pozycję kursora, w związku z czym jeżeli połączymy zdarzenie trackPoint_changed ze zdarzeniem set_translation węzła Transform, w którym znajduje się definicja jakiegoś obiektu, to obiekt będzie się przesuwał w ślad za kursorem myszki. Spójrzmy na przykład.

#VRML V2.0 utf8

DEF Obiekt Transform {
              children [
                   Shape {
                     appearance Appearance {
                               material Material {
                                        diffuseColor 0 1 0 }
                                           }
                     geometry Cone {}
                         }
                       ]
}

DEF Czujnik SphereSensor {}

ROUTE Czujnik.rotation_changed TO Obiekt.set_rotation
ROUTE Czujnik.trackPoint_changed TO Obiekt.set_translation

Powyższy przykład pozwala przy wciśniętym klawiszu myszki jednocześnie przesuwać obiekt jak i nim obracać. Za przesunięcie odpowiada tutaj powiązanie zdarzeń trackPoint_changed węzła SphereSensor ze zdarzeniem set_translation węzła Transform - takie rozwiązanie prowadzi do tego, że węzeł SphereSensor działa jak węzeł PlaneSensor (patrz niżej). Obrót obiektu uzyskujemy poprzez powiązanie zdarzeń rotation_changed węzła SphereSensor ze zdarzeniem set_rotation węzła Transform.


PlaneSensor {
  exposedField SFBool  autoOffset          TRUE
  exposedField SFBool  enabled             TRUE
  exposedField SFVec2f maxPosition         -1 -1
  exposedField SFVec2f minPosition         0 0
  exposedField SFVec3f offset              0 0 0
  eventOut     SFBool  isActive
  eventOut     SFVec3f trackPoint_changed
  eventOut     SFVec3f translation_changed
}
 
Węzeł PlaneSenor umożliwia przesuwanie obiektów względem osi X i Y. Przesunięcia dokonuje użytkownik klikając i przytrzymując klawisz myszki na aktywnym obiekcie. Tam gdzie użykownik skieruje myszkę tam powinien przesunąć się obiekt. Oczywiście węzeł PlaneSensor daje możliwość ograniczenia przesunięcia obiektu. W polach maxPosition i minPosition określamy granice, w których można obiekt przemieszczać. Pierwsza wartość w tych polach dotyczy osi X a druga osi Y. Pozostawienie wartości domyślnych spowoduje, że użytkownik będzie mógł przemieszczać aktywny obiekt bez ograniczeń.

Poniższy przykład przedstawia czerwony sześcian, który możemy przemieszczać w obszarze ograniczonym w polach maxPosition i minPosition. Ponadto została zmieniona domyślna wartość pola offset - po wyłączeniu wartości domyślnej poprzez nadanie polu autoOffset wartości FALSE - w polu offset określone zostało miejsce, z którego zacznie się przesuwanie obiektu, gdy po raz drugi uaktywnimy węzeł PlaneSensor.

#VRML V2.0 utf8

DEF Obiekt Transform {
  children [
   Shape {
   appearance Appearance { material Material {
       diffuseColor 1 0 0 }
           }
   geometry Box {size 2 2 0.1} }
    ]
}

DEF Czujnik PlaneSensor {
   autoOffset FALSE
   offset 0 0 0
   minPosition -1 -1
   maxPosition 2 2 }

ROUTE Czujnik.translation_changed TO Obiekt.set_translation

Proszę zobaczyć jak powyższy przykład  wyświetli wasza przeglądarka.


CylinderSensor {
  exposedField SFBool     autoOffset TRUE
  exposedField SFFloat    diskAngle  0.262
  exposedField SFBool     enabled    TRUE
  exposedField SFFloat    maxAngle   -1
  exposedField SFFloat    minAngle   0
  exposedField SFFloat    offset     0
  eventOut     SFBool     isActive
  eventOut     SFRotation rotation_changed
  eventOut     SFVec3f    trackPoint_changed
}
 
Węzeł CylinderSensor działa podobnie jak węzeł PlaneSensor z tą tylko różnicą, że aktywny obiekt nie jest przesuwany a obracany i to obracany tylko względem osi Y.

#VRML V2.0 utf8

DEF Obiekt Transform {
  children [
      Shape {
        appearance Appearance {
                  material Material {
                     diffuseColor 1 0 0 }
                             }
        geometry Box {size 2 2 0.1}
            }
           ]
}

DEF Czujnik CylinderSensor {
   autoOffset TRUE
   minAngle -1
   maxAngle 1 }

ROUTE Czujnik.rotation_changed TO Obiekt.set_rotation

Powyższy przykład przedstawia nam ten sam sześcian tym razem poddany działalności węzła CylinderSensor. Pola minAngle i maxAngle typu SFFloat mają tę samą funkcję co pola minPosition i maxPosition w węźle PlaneSensor, z tą tylko różnicą, że dotyczą one obrotu obiektu, a wartości tych pól wyrażamy w radianach.


SphereSensor {
  exposedField SFBool     autoOffset        TRUE
  exposedField SFBool     enabled           TRUE
  exposedField SFRotation offset            0 1 0 0
  eventOut     SFBool     isActive
  eventOut     SFRotation rotation_changed
  eventOut     SFVec3f    trackPoint_changed
}
 
Węzeł SphereSensor działa prawie identycznie jak CylinderSensor. Różnica polega na tym, że dzięki węzłowi SphereSensor możemy dany obiekt obracać we wszystkich kierunkach.

Rozszyfrowanie pól w tym węźle, w świetle wcześniejszych wyjaśnień, nie powinny sprawić kłopotów. Przyjrzyjmy się więc przykładowi:

#VRML V2.0 utf8

DEF Obiekt Transform {
               children [
                    Shape {
                      appearance Appearance {
                                     material Material {
                                        diffuseColor 0 0 1 }
                                            }
                       geometry Cone { height 4
                                       bottomRadius 1 }
                          }
                        ]
                     }

DEF Czujnik SphereSensor {
                  enabled TRUE
                  autoOffset TRUE }

ROUTE Czujnik.rotation_changed TO Obiekt.set_rotation