|
Tutorial: User Interface
Caution: the Layer and Layout nodes are new to the X3D version 3.2
specification and are not supported by some viewers.
The Layering Example

In the previous tutorial we inserted out the basic geometry of the file.
Now we will attach the functionality to the buttons. In the scene illustrated,
the cube can be rotated and the buttons at the bottom can be used to change
the color of the cube. For red, the color will change immediately. For blue,
the color will change gradually.
Moving Over the Buttons

The images of the buttons are contained in a texture file. The upper images of
the buttons are the default images. The images at the bottom are used to
indicate that the mouse is over the button.
The first step to to set up routing so that when the mouse is over the blue button
the image with the red border is chosen but when the mouse is not over the blue button
then the upper image with the gray border is chosen.
The two versions of the blue button are placed within a Switch node (Blue_sw).
The TextureCoordinate nodes are set so that either the upper left part of the texture
is used or the lower left portion is used. The routing will be set to change between
these two Shapes depending on the location of the mouse. A simplified version of the
code for this is as follows.
<Scene>
<LayerSet order="1 2">
....
<LayoutLayer>
...
<LayoutGroup>
...
<Transform>
<Transform translation="-54 -24 2">
<Switch DEF="Blue_sw" whichChoice="0">
<Shape>
<Appearance>
<ImageTexture url="buttons.png"/>
</Appearance>
<IndexedFaceSet coordIndex="0 1 3 2"
normalIndex="0 0 0 0"
texCoordIndex="0 1 3 2">
<Coordinate point="0 0 0, 48 0 0,
0 48 0, 48 48 0"/>
<Normal vector="0 0 1"/>
<TextureCoordinate
point="0.0 0.5, 0.5 0.5,
0.0 1.0, 0.5 1.0"/>
</IndexedFaceSet>
</Shape>
<Shape>
<Appearance>
<ImageTexture url="buttons.png"/>
</Appearance>
<IndexedFaceSet coordIndex="0 1 3 2"
normalIndex="0 0 0 0"
texCoordIndex="0 1 3 2">
<Coordinate point="0 0 0, 48 0 0,
0 48 0, 48 48 0"/>
<Normal vector="0 0 1"/>
<TextureCoordinate
point="0.0 0.0, 0.5 0.0,
0.0 0.5, 0.5 0.5"/>
</IndexedFaceSet>
</Shape>
</Switch>
<TouchSensor DEF="Blue_ts"/>
<BooleanFilter DEF="Blue_bf"/>
<IntegerTrigger DEF="Blue_it0"/>
<IntegerTrigger DEF="Blue_it1" integerKey="1"/>
</Transform>
</Transform>
...
</LayoutGroup>
</LayoutLayer>
</LayerSet>
<ROUTE fromNode="Blue_ts" fromField="isOver"
toNode="Blue_bf" toField="set_boolean"/>
<ROUTE fromNode="Blue_bf" fromField="inputTrue"
toNode="Blue_it1" toField="set_boolean"/>
<ROUTE fromNode="Blue_bf" fromField="inputFalse"
toNode="Blue_it0" toField="set_boolean"/>
<ROUTE fromNode="Blue_it1" fromField="triggerValue"
toNode="Blue_sw" toField="whichChoice"/>
<ROUTE fromNode="Blue_it0" fromField="triggerValue"
toNode="Blue_sw" toField="whichChoice"/>
</Scene>
It is the job of the TouchSensor "Blue_ts" to monitor the position of the mouse and to send out
events accordingly. The TouchSensor monitors the actions over the button because it and the Switch
node that contains the button geometry are both children of the same node, in case a Transform node.
In other words, the TouchSensor and Switch node are siblings. When the mouse is over the blue button,
a value of TRUE is sent to the BooleanFilter "Blue_bf". This causes it to send a TRUE value to the
IntegerTrigger "Blue_it1". Since the integerKey of the IntegerTrigger is 1, it sends a 1 to the
Switch node, selecting the second image.
When the mouse is not over, the blue button the message is similar, however because the
BooleanFilter "Blue_bf" receives a FALSE, it will instead send a TRUE value to the IntegerTrigger "Blue_it0",
whose integerKey is 0. Thus the first button in the Switch node will be selected.
When the mouse is over the blue button
TouchSensor "Blue_ts" --True-->
BooleanTrigger "Blue_bf" --True-->
IntegerTrigger "Blue_it1" --1-->
SwitchNode "Blue_sw"
When the mouse is not over the blue button
TouchSensor "Blue_ts" --False-->
BooleanTrigger "Blue_bf" --True-->
IntegerTrigger "Blue_it0" --0-->
SwitchNode "Blue_sw"
Changing the Color
The TouchSensor "Blue_ts" also monitors mouse clicks on the blue button. When the mouse is
left-clicked over the button, the TouchSensor sends out a touchTime event. ROUTEs are inserted
into the scene so that the touchTime event causes a startTime event to be sent to the TimeSensor "Blue_timer".
The timer then starts to send fraction events to the ColorInterpolator "Blue_ci",
which calculates the color and sets the diffuse color of the Material "BoxMaterial", which is
associated with the cube in the main scene. The ColorInterpoator contains two colors, red and blue.
So the color changes gradually from red to blue.
For the red button, both colors in the ColorInterpolator are red. This means that
the color will change immediately to red, and will stay red. Routing messages can be sent between
nodes located anywhere in the scene, even if they are in different layers.
<Scene>
<LayerSet order="1 2">
<Layer>
<Background skyAngle="0.785398 1.5"
skyColor="0.2 0.2 1, 0.5 0.5 1,
0.9 0.9 1"/>
<NavigationInfo type="EXAMINE"/>
<Viewpoint position="0 0 3"/>
<Shape>
<Appearance>
<Material DEF="BoxMaterial"
ambientIntensity="0.167"
diffuseColor="1 0 0"
emissiveColor="0 0 0"
shininess="0.098"/>
</Appearance>
<Box size="0.5 0.5 0.5"/>
</Shape>
</Layer>
<LayoutLayer>
....
<LayoutGroup>
....
<Transform>
<Transform translation="-54 -24 2">
<Switch DEF="Blue_sw" whichChoice="0">
....
</Switch>
<TouchSensor DEF="Blue_ts"/>
<TimeSensor DEF="Blue_timer"/>
<ColorInterpolator DEF="Blue_ci" key="0 1"
keyValue="1 0 0, 0 0 1"/>
</Transform>
<Transform translation="6 -24 2">
<Switch DEF="Red_sw" whichChoice="0">
....
</Switch>
<TouchSensor DEF="Red_ts"/>
<TimeSensor DEF="Red_timer"/>
<ColorInterpolator DEF="Red_ci" key="0 1"
keyValue="1 0 0, 1 0 0"/>
</Transform>
</Transform>
</LayoutGroup>
</LayoutLayer>
</LayerSet>
<ROUTE fromNode="Blue_ts" fromField="touchTime"
toNode="Blue_timer" toField="startTime"/>
<ROUTE fromNode="Blue_timer" fromField="fraction_changed"
toNode="Blue_ci" toField="set_fraction"/>
<ROUTE fromNode="Blue_ci" fromField="value_changed"
toNode="BoxMaterial" toField="diffuseColor"/>
</Scene>
Download tutorial files (same as previous tutorial)
|