<<   Interaktion zwischen Knoten, Sensoren >>

Mehrere Knotentypen können Ereignisse empfangen und/oder senden. Ereignisse enthalten einen Wert und eine Zeitmarke, sie sind ihrerseits als Felder von Knoten definiert. 
  • Sendeereignisse können die Änderung von Werten von Feldern anordnen
  • Empfangsereignisse können Werte von Feldern ändern
  • Ereignis, das die Änderung eines Feldes mitteilt: Schlüsselwort eventOut
    Ereignisname meist = Feldname und Suffix  "_changed" (Ausnahmen: Ereignisse mit den Typen  Boolean und Time.) 
  • Ereignis, das ein Feld ändern kann: Schlüsselwort eventIn
    Ereignisname meist = Feldname und Präfix "set_"

Schnittstellen-Schema eines Knotens:

  • Ereignistyp: Typ des geänderten bzw. des zu ändernden Feldes. 
    Ereignisse werden durch Routen zwischen zwei Knoten übertragen.
  • Dabei können nur Knoten verwendet werden, die mit dem Schlüsselwort DEF einen Namen zugeordnet bekommen haben (siehe Kursteil 3a).
  • Voraussetzung: Die Ereignistypen des Output- und des Input-Ereignisfeldes müssen übereinstimmen. 
  • Syntax der Routen-Vereinbarung: 
    ROUTE  KnotenNameA.feld1_changed  TO KnotenNameB.set_feld2 
  • Ausnahmen von der Namenskonvention "_changed" für Output- und "set_" für Inputereignisse: 
    Ereignisse mit booleschen Werten: is... (z.B. isActive)
  • Ereignisse mit Zeitwerten: ...Time (z.B. touchTime)
     
  • In den folgenden Beispielen werden verschiedene Sensoren vorgestellt:
  • ein TouchSensor (empfindlich auf Berührung),
  • ein PlaneSensor (zum waagrechten Verschieben eines Objektes), ein
  • ein  CylinderSensor zur Drehung um eine Achse und
  • ein SphereSensor für sphärische Drehungen
     
  • Im folgenden Beispiel ist das auslösende Ereignis das Anklicken des violetten Kegels, das ausgelöste Ereignis ein Sound.
    Anmerkung: der Sound ist in einem Elliptischen Bereich hörbar mit Brennpunkt im Zentrum und Koordinaten der Hauptscheitel maxFront und minFront
  • Im nächsten Beispiel kann ein Objekt durch Mausgriff waagrecht verschoben werden
  • Anschließend kann ein Quader um die y-Achse gedreht werden
  • und schließlich erfolgt die Drehung eines Kegels um einen Punkt (Kugeldrehung)
#VRML V2.0 utf8

NavigationInfo {type "EXAMINE" headlight TRUE}

Transform
{ children
  [ DEF Grapscher TouchSensor { }
    Shape
    { appearance Appearance {material Material { diffuseColor  1 0 1 } }
      geometry  Cone { bottomRadius  1  height  2 }
    }
  ]
}

Sound	{ source DEF Schrei AudioClip { url ["hahn.wav"] }	maxFront 100 minFront 5    }

ROUTE Grapscher.touchTime TO Schrei.startTime
#VRML V2.0 utf8

NavigationInfo {type "EXAMINE"  headlight TRUE}

Group {   children
          [  DEF Schieber PlaneSensor {  }
             DEF Quader Transform
                 { children  [ Shape  { appearance Appearance {material Material { diffuseColor 1 0 1}}
                                        geometry Box { size 2 0.5 2}
                                      }
                             ]
                 }
          ]
      }

Shape { appearance Appearance { material Material { diffuseColor 1 1 1 transparency 0.4 }}
        geometry  Box { size 6 6 0.01 }
      }

ROUTE Schieber.translation_changed TO Quader.set_translation
Durch eine etwas subtile Programmierung kann man auch die Drehachse verlagern, siehe das Beispiel.
#VRML V2.0 utf8

Transform
{ translation 2 0 0
  children  [ DEF Dreher CylinderSensor {minAngle -1.5 maxAngle 1.5 }
              DEF Objekt Transform
              { children Transform
                         { translation -1 0 0
                           children  [ Shape {appearance Appearance {material Material {diffuseColor 1 0 1}}
                                              geometry   Box { size 2 3 0.1}
                                             }
                                     ]
                         }
              }
            ]
}
ROUTE Dreher.rotation_changed TO Objekt.set_rotation
#VRML V2.0 utf8

Group {
    children
    [  DEF DrehQua CylinderSensor {
       }
       DEF Quader Transform
       {  children
          [  Shape
             {  appearance Appearance { material Material { diffuseColor  1 0 1  }}
                geometry    Box { size 1 3 1 }
             }
           ]
       }
    ]
}

Shape
{ appearance Appearance { material Material { diffuseColor 1 1 1  transparency 0.4 }}
  geometry   Box { size 6 0.01 6}
}

ROUTE DrehQua.rotation_changed TO Quader.set_rotation
#VRML V2.0 utf8

NavigationInfo {type "EXAMINE"  headlight TRUE}

Group {   children
          [  DEF DrehKug SphereSensor {    }
             DEF Kegel Transform
             {  children [  Shape {   appearance Appearance { material Material { diffuseColor  1 0 1  } }
                                      geometry   Cone {  bottomRadius   1   height  2  }
                                  }
                         ]
             }
          ]
      }

Shape {  appearance Appearance {  material Material {  diffuseColor    1 1 1  transparency    0.4  }  }
                                  geometry   Box    {  size 6 6 .001   }
      }

ROUTE DrehKug.rotation_changed TO Kegel.set_rotation
Hier wird mit einem beleuchteten Schalter das Licht auf einen Würfel aufgedreht:
#VRML V2.0 utf8

NavigationInfo { headlight  FALSE  }

Shape { appearance Appearance { material Material {diffuseColor 0 0 1} }  geometry Box {}  }

Transform
{  children
   [  Shape { appearance Appearance { material Material { emissiveColor 1 0 0 } }
              geometry Cylinder {radius 0.5 height 0.2}
            }
      DEF Schalter TouchSensor {}
   ]
   translation 4 0 0
   rotation 1 0 0  1.57
}
DEF Licht PointLight { location -6 4 3  on FALSE  color 0 0 1}

ROUTE Schalter.isActive TO Licht.on 
 

Interpolatoren

  • sind diskrete Funktionen mit Definitionsmenge   D = { eine Anzahl von Werten zwischen 0 und 1 },  angenommen  D = { 0  0.33  0.67  1 }
    und Wertemenge aus einem beliebigen Bereich u. zw. entweder wieder einzelne Zahlen oder Vektoren.
  • ScalarInterpolator: die Werte sind Zahlen, angenommen W = { 1  2  3  2 }. Dann ist f(0) = 1, f(0.33) = 2, f(0.67) = 3 und  f(1) = 2
    Man könnte damit z.B. den Transparenzgrad beschreiben
  • PositionInterpolator: die Werte sind Vektoren, könnten also z.B. eine Translation beschreiben.
  • ColorInterpolator: die Werte sind Vektoren und geben den RGB- Wert an.
  • OrientationInterpolator hat als Werte vierdimensionale Vektoren, kann also eine Drehung beschreiben.

Mit ihrer Hilfe lassen sich Animationen programmieren.

Animationen

Eine Animation besteht meist aus folgenden Komponenten:
  • einem geometrischen Objekt samt zugehörigem Transform-Knoten
  • einer Uhr (TimeSensor) mit ablaufender Uhrzeit vorgegebener Länge und mit oder ohne Wiederholung
  • einem Interpolator, der zu vorgegebenen Zeitpunkten Zwischenwerte zu Position, Rotation, Scale, Farbe usw.berechnet
  • und dem Routen zwischen den Objekten
  • key [] Liste mit Stützwerten (z.B. Zeitwerten) auf der Eingabeseite. Die Liste muss aufsteigend sortiert sein
  • keyValue [] Liste mit Stützwerten auf der Ausgabeseite. Die Art der Werte hängt vom Interpolator ab: eine Zahl beim SkalarInterpolator, drei beim Positionsinterpolator und vier beim Orientierungsinterpolator. Die Anzahl der Werte muss mit der im key-Feld übereinstimmen
  • set_fraction Eingabefeld
  • value_changed Ausgabefeld
  • Routen kann man nur zwischen benannten Objekten definieren, insofern ist es wichtig, dass alle Objekte mittels „DEF" benannt werden.
  • Geänderte Uhrzeit geänderter keygeänderter keyValueRotation in XForm

Hier dreht sich ein Würfel. Das Zeitintervall beträgt 6s, nach 0s, 2s, 4s, 6s hat er sich um  0°, 120°, 240°, 360° gedreht
Und hier schwebt er auf und ab. In beiden Fällen beginnt die Uhr sofort zu laufen.

#VRML V2.0 utf8
Viewpoint { position 0 0 10 }

DEF Wuerf Transform
{  children  [  Shape  { appearance Appearance { material Material { diffuseColor 1 0 0 } }
                         geometry Box {}
                       }
             ]
}
DEF Uhr TimeSensor { cycleInterval 6.0 startTime 0 loop TRUE }
DEF Animation OrientationInterpolator
{  key      [ 0,         0.33,        0.66,        1        ]
   keyValue [ 0 1 0  0,  0 1 0  2.1,  0 1 0  4.2,  0 1 0  6.3 ]
}
ROUTE Uhr.fraction_changed TO Animation.set_fraction
ROUTE Animation.value_changed TO Wuerf.rotation
soll erst nach Anklicken gestartet werden, ersetzt man die Steuerungsgruppe unten durch (der Schalter ist hier zugleich der Würfel):
DEF Uhr TimeSensor { enabled FALSE cycleInterval 5 loop TRUE }
DEF Schalter TouchSensor {}

ROUTE Schalter.isActive TO Uhr.set_enabled
ROUTE Uhr.fraction_changed TO Interpolator.set_fraction
ROUTE Interpolator.value_changed TO Wuerfel.set_translation

#VRML V2.0 utf8

DEF Wuerfel Transform { children Shape { appearance Appearance { material Material {} }
                                         geometry Box {}  }
                      }

DEF Interpolator PositionInterpolator  { key      [ 0      0.5    1 ]
                                         keyValue [ 0 0 0, 0 2 0, 0 0 0 ]
                                       }

DEF Uhr TimeSensor { cycleInterval 5 loop TRUE }

ROUTE Uhr.fraction_changed TO Interpolator.set_fraction
ROUTE Interpolator.value_changed TO Wuerfel.set_translation

  • EINE Uhr kann auch mehrere Animationen steuern:
  • eine Verformung mit scale und eine Translation, siehe hier
#VRML V2.0 utf8
DEF Kugel Transform  { children [ Shape { appearance Appearance { material Material { diffuseColor 1 0 0 } }
                                          geometry Sphere {}
                                        }
                                ]
                     }

DEF Uhr TimeSensor  { cycleInterval 6.0 startTime 0 loop TRUE }
DEF dickundduenn    PositionInterpolator  { key      [ 0,      0.5,      1 ]
                                            keyValue [ 1 2 1,  2 0.5 2,  1 2 1 ]
                                          }
DEF aufundab PositionInterpolator         { key      [ 0,       0.5,     1 ]
                                            keyValue [ 0 -2 0,  0 2 0,   0 -2 0 ]
}
ROUTE Uhr.fraction_changed TO dickundduenn.set_fraction
ROUTE dickundduenn.value_changed TO Kugel.scale
ROUTE Uhr.fraction_changed TO aufundab.set_fraction
ROUTE aufundab.value_changed TO Kugel.translationn
 
  • Eine Türe dreht sich in der Angel
  • Die Drehachse geht durch den Ursprung, ist also z.B. hier die y-Achse
  • Die Türe wurde aber verschoben, so dass die Drehung so erscheint wie beim Öffnen einer Türe
  • das erste Transform bezieht sich auf die Drehung, das zweite auf die Verschiebung der Türe
#VRML V2.0 utf8

Switch 
{ choice DEF Tuere Shape  { appearance Appearance { material Material { diffuseColor 1 0 0 } }
                            geometry Box {size 2 4 0.25 } }
}

DEF rundherum Transform { children [ Transform { children [ USE Tuere ] translation 1 0 0} ] }

DEF Uhr TimeSensor { cycleInterval 2 startTime 0 loop TRUE }
DEF Dreher OrientationInterpolator  { key      [ 0,        0.33,       0.66,       1 ]
                                      keyValue [ 0 1 0 0,  0 1 0 2.1,  0 1 0 4.2,  0 1 0 6.3 ]
                                    }

ROUTE Uhr.fraction_changed TO Dreher.set_fraction
ROUTE Dreher.value_changed TO rundherum.rotation
Ein wichtiger Unterschied: die Türe soll sich jetzt nicht um die y-Achse drehen sondern um eine parallele Gerade dazu. Temporär wird dabei der Koordinatenursprung mit center verschoben (ACHTUNG: an der RICHTIGEN Stelle im Skript)
#VRML V2.0 utf8

Switch
{ choice DEF Tuere Shape  { appearance Appearance { material Material { diffuseColor 1 0 0 } }
                            geometry Box {size 3 4 0.25 } }
}

DEF rundherum Transform { children [ Transform { children [ USE Tuere ] } ]  center 1.5 0 0 }

DEF Uhr TimeSensor { cycleInterval 2 startTime 0 loop TRUE }
DEF Dreher OrientationInterpolator  { key      [ 0,        0.33,       0.66,       1 ]
                                      keyValue [ 0 1 0 0,  0 1 0 2.1,  0 1 0 4.2,  0 1 0 6.3 ]
                                    }

ROUTE Uhr.fraction_changed TO Dreher.set_fraction
ROUTE Dreher.value_changed TO rundherum.rotation
  • Farbänderung
  • Jeder Farbauswahl rgb ist die Zahl r*2563 + g*2562 + b*256 zugeordnet, daher kann interpoliert werden
#VRML V2.0 utf8
Transform
{ children
  [ Shape
    { appearance Appearance { material DEF Farbe Material { diffuseColor 0 1 0 } }
     geometry Sphere {}
    }
  ]
}

DEF Uhr TimeSensor { cycleInterval 5 startTime 0 loop TRUE }
DEF FarbInt ColorInterpolator
{  key      [ 0,      0.5,    1     ]
   keyValue [ 0 1 0,  0 0 1,  1 0 0 ]
}

ROUTE Uhr.fraction_changed TO FarbInt.set_fraction
ROUTE FarbInt.value_changed TO Farbe.set_diffuseColor
Hier wieder zwei gleichzeitige Farbwechsel:
#VRML V2.0 utf8

DEF Wechsler1 ColorInterpolator
{   key        [ 0            0.5    1           ]
    keyValue   [ 0.5 0.5 0.5  1 0 0  0.5 0.5 0.5 ]
}

DEF Wechsler2 ColorInterpolator
{   key        [ 0           0.5           1     ]
    keyValue   [ 0.2 0.2 1   0.5 0.5 0.5   0.2 0.2 1 ]
}

DEF Uhr TimeSensor { cycleInterval 10.0  loop TRUE }

Shape
{   appearance Appearance { material DEF Farbe1 Material { } }
    geometry Sphere       { radius 1 }
}

Shape
{   appearance Appearance { material DEF Farbe2 Material { } }
    geometry Cylinder     { radius 0.5 height 4 }
}

ROUTE Uhr.fraction_changed TO Wechsler1.set_fraction
ROUTE Wechsler1.value_changed TO Farbe1.set_diffuseColor
ROUTE Uhr.fraction_changed TO Wechsler2.set_fraction
ROUTE Wechsler2.value_changed TO Farbe2.set_diffuseColor
Hier wird eine Türe in einer Wand geöffnet.
#VRML V2.0 utf8

Switch 
{  choice
   [ DEF Tuere Shape  { appearance Appearance { material Material { diffuseColor 1 0 1 } }
                        geometry Box { size 2 3 0.2}
                      }
     DEF Wand Shape   { appearance Appearance { material Material { diffuseColor 0 1 1 } }
                        geometry Box { size 4 4 0.2}
                      }
   ]
}

Transform { children USE Wand translation 3 0 0 }
Transform { children USE Wand translation -3 0 0 }

Group {children  [ DEF Dreher CylinderSensor {minAngle -1.5 maxAngle 1.5 }
                   DEF Objekt Transform {children USE Tuere center 1 0 0 }
                 ]
      }
ROUTE Dreher.rotation_changed TO Objekt.set_rotation

Änderung : Schiebetüre
Group {children [ DEF Schieber PlaneSensor {minPosition 0 -0.5 maxPosition 0 2 }
                  DEF Objekt Transform {children USE Tuere }
                ]
      }
ROUTE Schieber.translation_changed TO Objekt.set_translation
Hier ist als Auslöser ein kleiner Schalter vorhanden
#VRML V2.0 utf8
DEF Wuerfel Transform  { children   Shape { appearance Appearance { material Material {} }
                                            geometry Box {}
                                          }
                       }

Transform {  children [  Shape { appearance Appearance { material Material {diffuseColor 1 0 0} }
              geometry Box {size 0.5 0.5 0.2}
            }
DEF Schalter TouchSensor {}
   ]
   translation 4 0 0
}

DEF Interpolator PositionInterpolator {  key      [ 0      0.5     1     ]
keyValue [ 0 0 0  0 2 0   0 0 0 ]
}

DEF Uhr TimeSensor { enabled FALSE cycleInterval 5.0 loop TRUE }
ROUTE Schalter.isActive TO Uhr.set_enabled
ROUTE Uhr.fraction_changed TO Interpolator.set_fraction
ROUTE Interpolator.value_changed TO Wuerfel.set_translation

<<   >>