Making a Color Changing Object

One of the things you can't do in Spazz is an animate changes in color. That's another good reason to try your hand at hand coding.

Here's a simple cube that will change colors when you click it.

Here's the full VRML description of a color-changing cube. I'll follow it with a description of how it works.


#VRML V2.0 utf8
Shape {
  appearance Appearance {
    material DEF changeableColor Material { diffuseColor 1 1 1 }
  }
  geometry Box {
  }
}

DEF onSwitch TouchSensor {
}

DEF timer TimeSensor {
  cycleInterval 10
  startTime -1
  loop TRUE
}

DEF colorChanger ColorInterpolator {
  key [0, .25, .5, .75, 1]
  keyValue [1 1 1, 1 0 0, 0 1 0, 0 0 1, 1 1 1]
}

ROUTE onSwitch.touchTime TO timer.set_startTime
ROUTE timer.fraction_changed TO colorChanger.set_fraction
ROUTE colorChanger.value_changed TO changeableColor.set_diffuseColor

#VRML V2.0 utf8

Okay. Let's see what all that means. First, you need the VRML header. This tells the browser the version of VRML and character set you're using.

Shape {

  appearance Appearance {
    material DEF changeableColor Material { diffuseColor 1 1 1 }
  }

  geometry Box {
  }

}

We'll just make a simple box as the color changing object. A box is a shape, so we stick it into a Shape node.

The Appearance node encapsulates (surrounds) all of the information about how the shape should look. We'll make a nice white color for the object's diffuseColor (diffuse color is color created by reflecting light). To create white, you set the value of Red, Green and Blue to "1 1 1" (meaning 100% of each color).

Note that I use the DEF (define) keyword to name the Material changeableColor. This is important, because later in the program we need to be able to identify which Material should change color.

The geometry node for the shape is defined as a Box. I'll just take the default, which is to make a cube 1x by 1y by 1z.


DEF onSwitch TouchSensor {
}

This is a TouchSensor node that I've named onSwitch. Keep in mind, I could name this item, or any other item any name I want (oatmeal, stinky, Murgatroid, etc.). It's just easier to remember what something is if you give it a descriptive name, like onSwitch, which is used to turn on the animation.

A TouchSensor is activated when you click any item in the same group. If you put it at the root level of the VRML file, then it will be activated when you click anything in the VRML scene.

DEF timer TimeSensor {
  cycleInterval 10
  startTime 0
  loop TRUE
}

This is a TimeSensor node that I've named timer.

The cycleInterval is the number of seconds the animation will run; in this case, 10 seconds is one complete cycle of animation.

The startTime indicates when the animation should start. Setting it to -1 sets the TimeSensor to "stopped."

By setting loop to TRUE, we tell the animation to repeat forever, until it receives a command to stop or the file is closed. In this example, we don't have a stop button, so it will just keep going.

DEF colorChanger ColorInterpolator {
  key [0, .25, .5, .75, 1]
  keyValue [1 1 1, 1 0 0, 0 1 0, 0 0 1, 1 1 1]
}

Interpolation is a fancy word for being in between two things (inter - between, polar - opposite sides). There are Interpolators for everything that you animate in VRML (position, orientation, etc.). Here, we're using a ColorInterpolator to change colors.

The first part of the Interpolator is the key. The key is a list of fractional values of the total animation time. Here, I've divided the animation into 4 pieces of equal length (.25). There are 5 values, because you don't count the starting point(0) as a piece.

The second part is the keyValue. The keyValue is a set of numbers, in this case color values, that will be set when the timer reaches each key. When the animation starts, the cube is white (1 1 1). When the timer reaches .25 seconds, the keyValue is Red (1 0 0). The cycle continues, changing from Red to Green (0 1 0), Green to Blue (0 0 1), Blue to White (1 1 1). Then, the timer loops, and the process starts all over again.

ROUTE onSwitch.touchTime TO timer.set_startTime

Finally, we get to the ROUTE statements. ROUTE statements connect events TO objects and changes a setting on one of the object's properties, such as its size, position or color.

The logic is this: when a value changes, ROUTE the value TO the Interpolator key. When the Interpolator key changes, ROUTE the Interpolator value TO an object and set one of its properties based on that value.

So, in this case, when the onSwitch is touched (clicked), send the touchTime to timer, and make that the startTime (which means, start it now).


ROUTE timer.fraction_changed TO colorChanger.set_fraction

Each time the timer changes a fraction, send that fraction of time to the colorChanger, and set its current key to that fraction.


ROUTE colorChanger.value_changed TO changeableColor.set_diffuseColor

Based on the fractional value in the key, choose the corresponding value in the keyValue. Route that changed value to the changeableColor node, and set the diffuseColor to the new value.

So, I click the object, which starts the timer. The value is then between 0 and .25 (say it's at .125 to make the math easy). The keyValue is set to halfway between 1 1 1 and 1 0 0, which is 1 .5 .5. That value is sent to the changeableColor node, and is used to set the value of diffuseColor (creating a pink color). As the clock moves each fraction, the pink will get darker until the timer is at .25, when it will be completely red. The object continues to gradually move from color to color as it cycles through green, blue, and back to white, then starts all over again.

And that is how you animate color in VRML. Pretty simple, huh?


Back to Creating Objects for Cybertown

Send your comments on this page to Epistomolus.

Updated February 23, 2007