Lightballs

tested with ++


This tutorial deals about a PROTO with a Script node which switches some of its properties. A PlaneSensor will enable us to move the lightballs around. We will trigger a spotlight once the balls are at certain positions.
The PROTO starts with a declaration of all its events and fields:

PROTO LightBall

[

exposedField SFColor LBColor 0.6 0.6 0

exposedField SFVec3f LBPosition 1 0 0

exposedField SFVec3f LBSize 0.5 0.5 0.5

field SFVec3f activePosition 1 0 0

]

We will have no eventIns or eventOuts since the PROTO LightBall contains already all of its functionality. We would like to vary the LightBall's size, color, position, and activePosition. The last item determines where in the X-Y plane the LightBall will be active.
Next we build the geometry:

Transform {

  translation IS LBPosition

  children [

The translation is ISed and moves the LightBall instance to its end position. The children of this node are listed:

    DEF PS PlaneSensor { }

    DEF ball Transform {

      scale IS LBSize

      children [	

        Shape { 

          appearance Appearance { 

            material Material { 

              diffuseColor IS LBColor

            }

          }

          geometry Sphere { } 

        }

First we define a PlaneSensor PS. This sensor maps mouse movement into translation in the X-Y plane. After you clicked on a PlaneSensor the x-y coordinates of your mouse pointer can be used to move objects, typically contained in the PlaneSensor's parent node. A ball is build with its properties scale and diffuseColor ISed. Each instance of this PROTO will have its own SpotLight:

        DEF LBLight SpotLight {

          color IS LBColor

          location 0 0 1

          on FALSE

        }

      ]

    }

  ]

}
It's color is also ISed. Initially the SpotLight is turned off. To implement the PlaneSensor we need only one ROUTE:

ROUTE PS.translation_changed TO ball.set_translation

When the PlaneSensor is active it will send out an event translation_changed which can be ROUTEd to the ball's translation field.
Now that we have the geometry set up we can turn to the Script node:

DEF LBscript Script {

  eventIn SFVec3f LBpositionCheck

  eventOut SFBool LB_on

  field SFVec3f activePosition IS activePosition

The eventIn 'ballPosition' represents the current position of the LightBall and is compared with 'activePosition'. Once the LightBall is in the target range an eventOut 'LB_on' is triggered which in turn is used to turn on/off the SpotLight.

  url "javascript:

    function LBpositionCheck(pos) {

      posX = pos[0];

      activeX = activePosition[0];

      if(posX > activeX) LB_on = TRUE;

      if(posX < activeX) LB_on = FALSE;

    }

  "

}

ROUTE PS.translation_changed TO LBscript.LBpositionCheck	

ROUTE LBscript.LB_on TO LBLight.on

The PlaneSensor's translation field is continuously ROUTEd and passed as 'pos' to the function 'LBpositionCheck'. The function then compares the x-value of the current position to the x-value of the 'activePosition' field. In case we dragged the LightBall into the active region the Script will trigger a TRUE for the SpotLight's enabled field and turn the light on. The complete LightBall Proto sums up our work so far.
As a test for today's PROTO I thought that I can use the LightBalls to demonstrate another issue in VRML: the lighting model, in particular the fact that usually the light shed on an object is calculated at the vertices. A plane build with one Box node has four vertices (corners) and thus will have only very limited light/shading capabilities.
The scene starts with three basic nodes:

NavigationInfo {

  headlight  FALSE

}

DirectionalLight {

  direction 0 -1 -1

  intensity 0.5

}

Viewpoint {

  position 0 0 10

  description "first"

}

NavigationInfo tells the browser not to use the headlight since we provide our own lights: DirectionalLight. The intensity is set to a value of 0.5 which is about half way to full intensity. A DirectionalLight node gives you parallel light rays along the direction vector which we define to be in a 45 degree angle downwards in the Y-Z plane.
Our LightBalls will illuminate two planes: one build from one single Box node and the other one from four Box nodes:

DEF plate Transform {

  translation 4 2 -2

  children [

    Shape { 

      appearance Appearance { 

        material Material { 

          diffuseColor 0.3 0.4 0.5 

        }

      }

      geometry Box { size 8 4 0.1 }

    }

  ]

}

Transform {

  translation 0 -3 -2

  scale 0.55 0.5 0.5

  children USE plate

}

Transform {

  translation 4.25 -3 -2

  scale 0.55 0.5 0.5

  children USE plate

}

Transform {

  translation 0 -5 -2

  scale 0.55 0.5 0.5

  children USE plate

}

Transform {

  translation 4.25 -5 -2

  scale 0.55 0.5 0.5

  children USE plate

}

You can see that I define the first Box as plate and then use it four more times to build the second plane. By scaling and translating the plates I end up with a tiled second plane. Look at the LightBall source or the VRML scence LightBall.wrl.
Finally we use our PROTO LightBall and make two instances of it:

DEF LB1 LightBall {

  LBColor 1 0 0

  LBPosition -2 0 0

  LBSize 0.45 0.45 0.45

  activePosition 5 0 0

}



DEF LB2 LightBall {

  LBColor 0 1 0

  LBPosition -2 2 0

  LBSize 0.3 0.3 0.3

  activePosition 1 0 0

}

This demo/tutorial was tested in Cosmo Player 1.0beta3 and after you loaded the final scene LightBall.wrl you can drag the lightballs around and test the lights on the planes. You will notice that the upper plane will show light exposure only when you drag the balls to the corners. The red ball works only in the very right half of your screen. Both balls will turn themselves off when you drag them to the left. As always here is the entire LightBall source




Copyright © 1996-98 Markus Roskothen. All rights reserved.