Text and Extrusions

Today we look at building more complex shapes. The primitives are very nice, and extremely efficient, but they often cannot exactly describe the shape we want.

For example, what if you wanted a pyramid, or a doughnut shape? What if you wanted to model the floor plan of a proposed building? What if you want to include text? Or stars? Or a wire-frame model of something? The primitive shapes are easy and powerful, but there are things they cannot model easily. They are also a little inflexible when being colored, as they have an "all-or-nothing" coloring scheme. For example, what if you wanted a cube with different colors on all six sides? It would be nice if we could work with the individual faces sometimes.

Today we will focus on some other types of geometry nodes, that will help us with these problems. A geometry node, as you remember, lives inside a shape node, and describes the physical appearance of the given object. So far, we have used only 'primitive' shapes. These are the sphere, box, cylinder, and cone. We will see some much more complex and powerful geometries in this session. Specifically, we will examine the text node and extrusions. In a later lesson, we will learn some other powerful geometry objects, including pointsets, linesets, and facesets.

Text nodes

We can place text in a shape. Examine the following world: text.wrl
#VRML V2.0 utf8
#text.wrl
#demonstrates using text in a geometry node

Shape {
  appearance Appearance {
    material Material {
      diffuseColor 1 1 0
    } # end material
  } # end appearance
  geometry Text {
    string "Hi there!!"
  } # end text
} # end shape
As you can see, this allows us to place a text value in the environment. Obviously, this is a nice capability, but it would be interesting to see what options we have in terms of typeface and positioning.

The next example illustrates some of these options:
fancyText.wrl


#VRML V2.0 utf8
#Fancytext.wrl
#demonstrates various features of text


#  This is the generic text node

Transform {
  children [
    Shape {
      appearance Appearance {
        material Material {
          diffuseColor 1 1 0
        } # end material
      } # end appearance
      geometry Text {
        string "default"
      } # end text
    } # end shape
  ] # end children
}


#  Here we've translated the shape node
#  and and changed the length of the text node

Transform {
  translation 0 1 0
  children [
    Shape {
      appearance Appearance {
        material Material {
          diffuseColor 1 1 0
        } # end material
      } # end appearance
      geometry Text {
        string "narrow"
        length 1
      } # end text
    } # end shape
  ] # end children
}


#  Here we made the text node length longer

Transform {
  translation 0 2 0
  children [
    Shape {
      appearance Appearance {
        material Material {
          diffuseColor 1 1 0
        } # end material
      } # end appearance
      geometry Text {
        string "wide"
        length 8
      } # end text
    } # end shape
  ] # end children
}


#  Now we add a fontStyle element, and make the 
#  style "ITALIC"

Transform {
  translation 0 -1 0
  children [
    Shape {
      appearance Appearance {
        material Material {
          diffuseColor 1 1 0
        } # end material
      } # end appearance
      geometry Text {
        string "italic"
        fontStyle FontStyle {
          style "ITALIC"
        } # end fontstyle
      } # end text
    } # end shape
  ] # end children
}# end transform


#  Here I changed the size inside the fontStyle node
#  This gives me better performance than changing 
#  the width of the Text node.

Transform {
  translation 0 -2.5 0
  children [
    Shape {
      appearance Appearance {
        material Material {
          diffuseColor 1 1 0
        } # end material
      } # end appearance
      geometry Text {
        string "Big"
        fontStyle FontStyle {
          size 2
        } # end fontstyle
      } # end text
    } # end shape
  ] # end children
}# end transform


#  size is a scaling node.  
#  The default size is being multiplied by 0.5, which 
#  also means divide by two.

Transform {
  translation 0 -3.5 0
  children [
    Shape {
      appearance Appearance {
        material Material {
          diffuseColor 1 1 0
        } # end material
      } # end appearance
      geometry Text {
        string "Small"
        fontStyle FontStyle {
          size .5
        } # end fontstyle
      } # end text
    } # end shape
  ] # end children
}# end transform


#  By setting horizontal FALSE, we made this a vertical
#  text field.  topToBottom determines the direction of 
#  the text.

Transform {
  translation -2 4 0
  children [
    Shape {
      appearance Appearance {
        material Material {
          diffuseColor 1 1 0
        } # end material
      } # end appearance
      geometry Text {
        string "going down"
        fontStyle FontStyle {
          size .5
          horizontal FALSE
          topToBottom TRUE
        } # end fontstyle
      } # end text
    } # end shape
  ] # end children
}# end transform


#  This is the same as the previous example, but we 
#  set topToBottom to FALSE.

Transform {
  translation -4 -4 0
  children [
    Shape {
      appearance Appearance {
        material Material {
          diffuseColor 1 1 0
        } # end material
      } # end appearance
      geometry Text {
        string "going up"
        fontStyle FontStyle {
          horizontal FALSE
          topToBottom FALSE
        } # end fontstyle
      } # end text
    } # end shape
  ] # end children
}# end transform


Text Experiment!!

Below I have started a text node. I have placed default values in all the fields we have discussed. Modify the code to contain your own values, and look at the resulting VRML world.

Extrusions

As usual, many concepts in VR are easier to illustrate than to describe. Let's begin our discussion of extrusions by looking at an example:
extrude1.wrl
#VRML V2.0 utf8

#extrude1
#a very simple example of extrusion

Shape {
  appearance Appearance {
    material Material {
      diffuseColor 0 0.5 1
    } # end material
  } # end appearance

  geometry Extrusion {
    crossSection [
       0  1,
      -1 -1,
       1 -1,
       0  1,
    ] # end cross section
    spine [
      0 0 0,
      0 .2 0,
    ] # end spine
  } # end extrusion
} # end shape

# force browser into 'examine mode'
NavigationInfo{
  type "EXAMINE"
}

As you can see, this object appears to be a triangle with 'thickness.' It is obviously not one of the primitive types, as those are quite well defined. It is a very simple example of an 'extrusion.' Bakers use the principle of extrusion when they decorate a cake. You've probably done this; you take frosting, and put it in a tube with a special tip. You can place different tips in the tube, and they will cause different streams of frosting to come out. If you use a small round tip, you will get a thin round stream of frosting. If you use a flat tip, you will get a ribbon. If you use a fancy serrated tip, you will get a different kind of ribbon.

You can apply this ribbon anywhere on the cake.

Basically, you generate an extrusion by the same process. You define a two-dimensional cross-section of your object, and then you tell the browser to apply that section across a three-dimensional spine. The cross section is the 'tip' in our frosting example. The spine would be like the path we are following on the cake.

Example

The Extrusion node contains two major nodes, crossSection and Spine. We will examine how those nodes are combined.

CrossSection is a template designed in two dimensions. For this project I wanted a triangular cross-section, so I sketched a triangle. My original sketch looked something like this:

Note how this relates to the node format

    crossSection [
       0  1,
      -1 -1,
       1 -1,
       0  1,
    ] # end cross section
I thought in X-Y coordinates for now. This defines the general section of the object. It does NOT necessarily reflect X and Y coordinates in the eventual model!! When we sketch a cross section, we are NOT working in the 3D coordinate system! Notice also that I 'closed off' the shape by returning to my first point. This is necessary, if I want all three sides to be drawn.

The other node, Spine looks like this in the code:

    spine [
      0 0 0,
      0 .2 0,
    ] # end spine
As you can see, the spine node appears to contain 3D coordinates. This is a very simple object. The spine is a virtual line running from (0, 0, 0) to (0, 0.2, 0). I am now defining a line in the coordinate system of the model (or an appropriate group or transform). My extrusion will essentially draw a series of representations of itself with that line as its origin.

Same section, different spine

Take a look at this code: extrude2.wrl
#VRML V2.0 utf8
 #extrude2
 #a more complex example of extrusion
 Shape {


   appearance Appearance {
     material Material {
       diffuseColor 1 1 1
     } # end material
   } # end appearance

   geometry Extrusion {
     crossSection [
	0  1,
       -1 -1,
	1 -1,
	0  1,
     ] # end cross section
     spine [
       -5   5  0,
       -5  -5  0,
	5  -5  0,
	5   5  0,
       -5   5  0,
     ] # end spine
   } # end extrusion
 } # end shape

 # force browser into 'examine mode'
 NavigationInfo{
   type "EXAMINE"
 }
 
You'll probably need to spin this thing around a little bit to get the full effect. Essentially, it's a kind of 'picture frame' effect. We have taken that simple triangular cross-section and twisted it into a 3-dimensional shape. The browser will do its best to conform to the cross section everywhere on the shape. Some browsers are better at this than others, and simpler cross sections definitely seem to give better results than more complex ones.

Come on Baby, let's do the twist!

Here is another example that illustrates the orientation node of the extrusion node:
twist.wrl
#VRML V2.0 utf8

#twist
#Using orientation node in an extrusion

Shape {
  appearance Appearance {
    material Material {
      diffuseColor 0 0.5 1
    } # end material
  } # end appearance

  geometry Extrusion {
    solid FALSE
    # same crossSection as before
    crossSection [
       0  1,
      -1 -1,
       1 -1,
       0  1
    ] # end cross section
    spine [
      0 0 0,
      0 1 0,
      0 2 0,
      0 3 0,
      0 4 0,
      0 5 0,
      0 6 0,
    ] # end spine

    orientation [
      # for each spine point, I will define a rotation angle.  
      # most of the time, you will translate around Y axis (0 1 0)
      # here I'm going in 10 degree increments, converted to radians
      0 1 0 0,
      0 1 0 .175,
      0 1 0 .349,
      0 1 0 .524,
      0 1 0 .700,
      0 1 0 .875,
      0 1 0 1.05,
    ] # end orientation
  } # end extrusion
} # end shape

# force browser into 'examine mode'
NavigationInfo{
  type "EXAMINE"
}
Again, you see that many things are the same. I have added the orientation node to the extrusion. This node has exactly the same number of values as the spine. Each element will relate directly to the corresponding spine coordinate. The orientation node describes any orientation changes (twists) that we want the model to follow at this point. The browser will try to make smooth transitions from one orientation to the next.

Remember that orientations are basically rotations. They consist of a vector and an angle in radians. We will almost always be rotating around the LOCAL Y axis. I specified local, because this is the direction the spine is currently going, NOT necessarily the Y axis of the model in general. You will almost always use 0 1 0 as the axis of rotation in an orientation node of an extrusion.

The angle will be expressed in radians. You can convert them from degrees, or remember these general guidelines (which are good enough for many applications)

Experiment with Extrusions

In the boxes below, define your own cross-section and spine values, and see what kind of effect you get.
Cross Section
Spine

More examples:

Laboratory Assignment

Use an extrusion geometry to create a roller coaster. Here is an example. The cross - section should be the cross section of the track, and the spine should define the course of the track. Here's some hints:
© Andy Harris
Indiana University / Purdue University, Indianapolis
email: aharris@klingon.cs.iupui.edu
homepage: www.cs.iupui.edu/~aharris