Encapsulation and code re-use

Motivation

Real Audio

As you can see, our code is becoming increasingly complex and difficult to maintain. We are learning to build some intriguing models, but the shear length of code is causing problems. It would be nice to be able to have some shortcuts, to make our code shorter and easier to read.

def.wrl
#VRML V2.0 utf8
#def.wrl
#explains how the DEF and USE structures work

Transform {
  children [
    DEF theCone Shape {
      appearance Appearance {
        material Material {
          diffuseColor 0 0 1
        } # end material
      } # end appearance

      geometry Cone { }

    } # end shape

    Transform {
      translation 0 2 0
      children [
        USE theCone
      ] # end children
    } # end transform

  ] # end children

} # end big transform

The above program contains a large transform, which contains a shape and another transform. When you look at the world which is created, you will see two identical cones. You would expect a Shape node for each cone, with all the details of generating a cone. However, when we look at the code, we see that the code for the second cone is extremely simple. In fact, all the code really makes the transformation which moves the cone. There is no shape, appearance, or geometry explicitly defined for the second cone. Instead, where we expect to see a shape, we see USE theCone.

Of course, theCone is a previously defined shape. Take a careful look at the first line of code in the first cone. It is a little unusual:
    DEF theCone Shape {
Usually, we would only see the keyword Shape there. The DEF keyword (which must be all in uppercase) means 'Definition coming.' By declaring a DEF, we have assigned (in this situation) the keyword 'theCone' to the entire Shape structure which will follow. This is similar to creating variables in traditional languages, or naming components in the visual languages like VB or HTML.

Notice that we can DEF any node, but not specific values. So, we can also write a world that looks like this:
#VRML V2.0 utf8
#sharing colors

Transform {
  children [
    Shape {
      appearance DEF green Appearance {
        material Material{
          diffuseColor 0 0 1
        } # end material
      } # end appearance
      geometry box { }
    } # end shape

    #note how much easier the appearance is here...
    Transform {
      translate -2 0 0
      children [
        Shape {
          appearance USE green
          geometry Sphere { }
        } # end shape
      ] # end children
    } # end transform
  ] # end children
} # end transform

Notice that the green color was re-used.

Prototypes

Real Audio

Sometimes it would be nice to be able to hide the details of a model. Take a look at the following model:
proto.wrl
#VRML V2.0 utf8

PROTO ColorBall [
  field SFColor ballColor 1 0 0
]  # end proto interface

{
  Shape {
    appearance Appearance {
      material Material {
        diffuseColor IS ballColor
      } # end material
    } # end appearance

    geometry Sphere {
      radius .2
    } # end geometry
  } # end shape
} # end proto        

ColorBall {
  ballColor 0 1 0
} # end colorBall

Transform {
  translation .5 0 0
  children [
    ColorBall {
      ballColor 0 0 1
    } # end Colorball
  ] # end children
} # end transform

Transform {
  translation -.5 0 0
  children [
    ColorBall {

    } # end Colorball
  ] # end children
} # end transform

Transform {
  translation 0 .5 0
  children [
    ColorBall {
      ballColor 0 1 1
    } # end Colorball
  ] # end children
} # end transform

Transform {
  translation 0 -.5 0
  children [
    ColorBall {
      ballColor 1 1 0
    } # end Colorball
  ] # end children
} # end transform

Transform {
  translation 0 0 .5
  children [
    ColorBall {
      ballColor 1 0 1
    } # end Colorball
  ] # end children
} # end transform

Transform {
  translation 0 0 -.5
  children [
    ColorBall {
      ballColor 1 1 1
    } # end Colorball
  ] # end children
} # end transform
As you can see, there is repetition in this program, but it could be worse, as it describes five balls, all inside transforms. Fortunately, though, we can improve the readability by prototyping. To define a prototype, we use the PROTO keyword. Prototypes have two main areas: field definition and the proto shape definition. Fields are the part of the prototype we wish to expose, or allow to be changed through code. Prototypes do not always have fields, but they make the prototype much more flexible. The field definitions are encased in square brackets. They consist of the field keyword, followed by the type of variable contained, followed by its name, followed by a default value. Below is a list of the principle data types in VRML:

Real Audio

Field type Contents
SFBool Single field Boolean (TRUE or FALSE)
SFColor/ MFColor Three floating point values, all between zero and one
Used to to determine red, green, blue pigments
SFFloat/MFFloat floating-point real number(s)
SFInt32/MFInt32 a 32-bit integer
SFNode/MFNode A VRML node. Usually a specific type of node is indicated
SFRotation, MFRotation Three floats to determine an axis of rotation, and fourth is
amount of rotation in radians
SFString/MFString text string(s)
SFTime a floating-point value for time
SFVec2f/MFVec2f a vector of two floats. Mainly used for textures, cross-sections
SFVec3f/MFVec3f a vector of three floats. Mainly used for points in 3D space
SF stands for Singular field, and MF means multiple fields. Multi-field nodes requir the [ ] brackets.
After the fields are created, we use a set of { } brackets to define the shape or whatever other nodes we intend. The entire prototype will take the behavior of the first node defined, which should often be a Shape, Group, or Transform. Note that a PROTO, unlike a DEF, does not actually draw the shape as you are defining it. The PROTO definition stores the shape into memory for later use.

Inside the proto definition, use the IS keyword to 'map' a field to whatever value you wish that field to relate to.

To use the new node you have defined, just use it anywhere as if it were a pre-defined node, as long as you are in the same document that defined the node. (Later tonight we'll see a way to get past that.)

Here's the 'official' specs of the standard VR nodes. Now that you understand the field types, you can probably make sense of it.
Quick Node Reference

Improving encapsulation

Real Audio

The term encapsulation is used in computer science to denote hiding details of some process, to simplify things. Our first prototype helped, but there was still a lot of detail in the transformations. Take a look at the next example, and you will see a marked improvement in code readability:
proto2.wrl
#VRML V2.0 utf8
#the prototype  demo extended to include offset!!

PROTO ColorBall [
  field SFColor ballColor 1 1 1
  field SFVec3f offset 0 0 0
]  # end proto interface

{
  Transform {
    translation IS offset
    children [
      Shape {
        appearance Appearance {
          material Material {
            diffuseColor IS ballColor
          } # end material
        } # end appearance
    
        geometry Sphere {
          radius .2
        } # end geometry
      } # end shape
    ] # end children
  } # end transform
} # end proto        

ColorBall{}

ColorBall{
  ballColor 0 0 1
  offset -.5 0 0
}

ColorBall{
  ballColor 0 1 0
  offset .5 0 0
}

ColorBall{
  ballColor 0 1 1
  offset 0 -.5 0
}

ColorBall{
  ballColor 1 0 0
  offset 0 .5 0
}

ColorBall{
  ballColor 1 0 1
  offset 0 0 .5
}

ColorBall{
  ballColor 1 1 0
  offset 0 0 -.5
}

This one is MUCH better!!

We can use external prototyping to improve the situation even more. Now we move the definitions into an external library file:
protoLib.wrl
#VRML V2.0 utf8
#the prototype  library

PROTO ColorBall [
  field SFColor ballColor 1 1 1
  field SFVec3f offset 0 0 0
]  # end proto interface

{
  Transform {
    translation IS offset
    children [
      Shape {
        appearance Appearance {
          material Material {
            diffuseColor IS ballColor
          } # end material
        } # end appearance
    
        geometry Sphere {
          radius .2
        } # end geometry
      } # end shape
    ] # end children
  } # end transform
} # end proto        
... and here's a page that uses it:

proto3.wrl
#VRML V2.0 utf8
#the prototype  demo using EXTERNPROTO

#no default values in extern protos!!
EXTERNPROTO ColorBall [ 
  field SFColor ballColor 
  field SFVec3f offset 
] "protoLib.wrl#ColorBall"


ColorBall{}

ColorBall{
  ballColor 0 0 1
  offset -.5 0 0
}

ColorBall{
  ballColor 0 1 0
  offset .5 0 0
}

ColorBall{
  ballColor 0 1 1
  offset 0 -.5 0
}

ColorBall{
  ballColor 1 0 0
  offset 0 .5 0
}

ColorBall{
  ballColor 1 0 1
  offset 0 0 .5
}

ColorBall{
  ballColor 1 1 0
  offset 0 0 -.5
}
Note the use of EXTERNPROTO. It is much like the proto definition, but it does not need the default values, and there is only field definitions here.

Real Audio

Finally, here's a fun library of models to play with: legLib.wrl
#VRML V2.0 utf8
#legLib

#demonstrates proto node

PROTO Leg1 [
  exposedField SFColor color 1 0 0
  exposedField SFVec3f translation 0 0 0
]

{
  Transform {
    translation IS translation
    children [
      Shape {
        appearance DEF myColor Appearance {
          material Material {
            diffuseColor IS color
            shininess 1
          } # end material
        } # end appearance
        geometry Box {
          size .25 .25 .25
        } # end geometry
      } # end shape
  
      Transform {
        translation 0 .1 0
        children [
          Shape {
            appearance USE myColor
  
            geometry Cylinder {
              height .25
              radius .1
            } # end geometry
          } # end shape
        ] # end children
      } # end transform
    ] # end children
  } # end transform
} # end proto definition

PROTO Leg2 [
  exposedField SFColor color 1 0 0
  exposedField SFVec3f translation 0 0 0
]

{
  Transform {
    translation IS translation
    children [
      Transform {
        translation -.125 0 0
        children [
          Leg1 { color IS color }
        ] # end children
      } # end transform

      Transform {
        translation .125 0 0
        children [
          Leg1 { color IS color }
        ] # end children
      } # end transform
    ] # end children
  } # end transform
} # end Leg2 Definition

PROTO Leg4 [
  exposedField SFColor color 1 0 0
  exposedField SFVec3f translation 0 0 0
]

{
  Transform {
    translation IS translation
    children [
      Transform {
        translation 0 0  -.125
        children [
          Leg2 { color IS color }
        ] # end children
      } # end transform

      Transform {
        translation 0 0 .125
        children [
          Leg2 { color IS color }
        ] # end children
      } # end transform
    ] # end children
  } # end transform
} # end Leg4 Definition

PROTO Leg6 [
  exposedField SFColor color 1 0 0
  exposedField SFVec3f translation 0 0 0
]

{
  Transform {
    translation IS translation
    translation .125 0 0
    children [
      Transform {
        translation -.25 0 0
        children [
          Leg4 { color IS color }
        ] # end children
      } # end transform

      Transform {
        translation 0 0 0
        children [
          Leg4 { color IS color }
        ] # end children
      } # end transform
    ] # end children
  } # end transform
} # end Leg6 Definition



PROTO Leg8 [
  exposedField SFColor color 1 0 0
  exposedField SFVec3f translation 0 0 0
]

{
  Transform {
    translation IS translation
    children [
      Transform {
        translation -.25 0 0
        children [
          Leg4 { color IS color }
        ] # end children
      } # end transform

      Transform {
        translation .25 0 0
        children [
          Leg4 { color IS color }
        ] # end children
      } # end transform
    ] # end children
  } # end transform
} # end Leg8 Definition



#show model here  
Leg2 {
  color 0 0 1
  translation 0 1 0
}

Leg4 {
  color 0 1 1
  translation 0 0 0
}

Leg6 {
  color 1 0 1
  translation 0 -1 0
}

Leg8 {
  color 1 1 0
  translation 0 -2 0
}

... and a sample world using them...
name.wrl
© Andy Harris
Indiana University / Purdue University, Indianapolis
email: aharris@.cs.iupui.edu
homepage: www.cs.iupui.edu/~aharris