As you worked on your last project, you undoubtedly noticed some limitations in the things we can do now. All of the objects are created right on top of each other! There must be some way to move things around. Also, we learned how to change the basic shapes of objects, but not their orientation. For example, all of our cones are pointing up! What if we wanted a cone to be pointing down, or at some other angle? Also, it would be nice to have other ways to change the shapes. For example, what if we wanted some sort of elliptical shape rather than a perfect sphere?
All of these things can of course be done. The key to all of them is a node called the Transform node. Transform is a generic term meaning change the shape. There are three types of transformations available in VRML, and they are our topic of concern for today.
It might be easier to look at this world, which illustrates the
coordinate system used in VRML. NOTE: You are always welcome to look
at the source code, but this particular example uses some concepts we
have not yet covered, so don't worry if you don't understand it.
axis.wrl
Transform {
children [ ]
translation 0, 0, 0
rotation 0, 0, 1, 0
scale 1, 1, 1
} # end transform
#ball
Transform {
children [
Shape {
appearance Appearance {
material Material {
diffuseColor 0, 0, 1
} # end material
} # end appearance
geometry Sphere {
radius .5
} # end geometry
} # end Shape
] # end children
} # end transform
Notice that I simply placed a shape definition inside the children
node, and indented appropriately. While indentation is technically
optional, you can see why it is such a good idea. Even our relatively
simple worlds consist of many layers of nodes within nodes, and it's
nice to see how things fit together. For the same reason, notice the
comments that ended a particular structure. These are also a really
good idea, as it is relatively easy to get totally confused about what
structure you're currently in. Note also that the children node has
[square brackets] instead of the more typical {curly ones.} This
indicates that you could have more than one child of the node. The
current code won't really do anything new, because we have defined
that a transformation might happen, but we haven't specified exactly
what kind of transformation we want to do.
Another thing you might have noticed in this code was the use of the inline node. This little beauty allows me to bring in the value of any VRML file I can find on the Internet, and incorporate it into my own world. As you can guess, this is an incredibly powerful feature. In this case, it simply allows us to ignore the details of creating the axis, since it has already been created for us.
#VRML V2.0 utf8
#Jet plane
#demonstrates scale and translation
#body
Shape {
appearance Appearance {
material Material {
diffuseColor .7 .7 .7
} # end material
} # end appearance
geometry Cone {
height 3
bottomRadius .5
} # end geometry
} # end shape
#wing
#notice this is EXACTLY like the body, except the scale!!
Transform {
scale 5, .5 , .1
children [
Shape {
appearance Appearance {
material Material {
diffuseColor .7 .7 .7
} # end material
} # end appearance
geometry Cone {
height 3
bottomRadius .5
} # end geometry
} # end shape
] # end children
} # end transform
#cockpit
Transform{
translation 0, 0, .2
scale .8, 1.2, 1
children [
Shape {
appearance Appearance {
material Material {
diffuseColor .5 .5 1
} # end material
} # end appearance
geometry Sphere {
radius .25
} # end geometry
} # end shape
] # children
} # end transform
Try to guess what this will look like BEFORE loading it up in a
browser. Now you can look at the model and wiggle it around a bit,
then come back here, and let's discuss how it was designed. Things
are starting to look complicated here, but there is nothing new here
at all. I started by designing the body. I figured I'd keep this really simple, so I went for a simple cone. I played around with the size and color until I was happy with it. Notice this shape is NOT inside a transformation. It's just a plain vanilla cone. (Sorry, I couldn't resist!) Notice also that I don't yet know how to turn things, so the cone is pointing up. For now, the jet is standing on its rear end. (stay tuned, we'll learn how to rotate later).
Now I decided to make the wing a sort of a delta shape, but when I thought about it, I realized I could just take a cone shape, and 'squish and stretch' it via the scale transformation to make it look like a wing. Here's the amazing thing. The fuselage and the wing are EXACTLY THE SAME CONE!!! The only difference is that I performed a scale transform on the wing. This illustrates how useful scaling can be. It allows you to take these primitive shapes, and make them into all kinds of other shapes. There is no 'flat triangle' primitive in VRML, but such a shape is easy to make when transforming a primitive shape. How did I know what values to put in the scale fields? I didn't. I guessed, but it was an educated guess. I already knew what the original cone looked like, because I had one on the screen. It was just a matter of thinking about how I wanted it changed. My thought process was something like this:
X is side-to-side. I want my wing wider than the body, so I'll multiply X by something greater than 1, maybe 5. Y is up and down. I want the wing to be not as tall as the plane (when it's standing on its tail as it is now), so I'll go with half-height, or multiply y by .5. Z is front to back. I want the wing to be thin looking, so I'll try .1 for the z factor.Amazingly enough, all my guesses were just right. I decided not to modify them at all. This is very unusual. Most of the time you have to fiddle a bit to get things working.
Make sure your comfortable with the relationship between the wing and the body. Now we're gonna look at the cockpit.
To make the cockpit, I envisioned a 'bubble canopy' like on modern fighter planes. The shape is very much like an elongated sphere. Again, it's easy to make a sphere, and I could use the scale transformation to make it the shape I wanted, but it kept disappearing inside the fuselage. Also, I only want it to show up on one side of the plane. The answer is to have both a translation and a scale field in the Transform node of the cockpit. Take another look at the source code and see what I mean. This time, my numbers didn't come out perfect the first time, so I had to play with them a bit. I ended up moving the shape around a bit, and playing with the scale some until it looked like what I wanted. This seems complicated, but the code that you have to change is simply values inside the scale and translate fields.
How did pi get in here? Well, the amount that you rotate a figure is a measure of angles. We often measure angles in terms of degrees, but mathematicians prefer in another unit, radians. It seems scary, but once you get used to it, radians can actually be easier to understand than degrees. Examine the following table for some equivalences:
| Fraction of a circle | degrees | Radians (pi) | decimal Radians |
|---|---|---|---|
| 1/24th | 15 | pi/12 | .262 |
| 1/12th | 30 | pi/6 | .524 |
| 1/8th | 45 | pi/4 | .785 |
| 1/6th | 60 | pi/3 | 1.05 |
| 1/4th | 90 | pi/2 | 1.57 |
| 1/2 | 180 | pi | 3.14 |
See if you can find values that would a negative and a positive value that would point between 7 and 8 on a clock face.
This requires some practice to get used to, especially if you have never worked with radians before, but it can be very useful. Later on, you can come back to this program to experiment with some angles when you need to see them interactively.
The reason the model is rotating around the Z axis has to do with the first three fields of the rotation node. As you may have guessed, they represent X, Y, and Z. Usually, though, you will only have ones or zeroes in these fields, because you will often be rotating around the X, Y, and Z axes. Play around with 1, 0, 0 and 0, 1, 0 for X, Y, and Z in the rotation example above, until you understand how they work. By the way, because the XYZ fields only define an axis, 1, 0, 0 is identical to 300, 0, 0 and .0001, 0, 0 when you are defining a rotation axis. 1 is easier to work with, so that's what we usually use.
Play with other rotation vectors as well, such as 1, 1, 0, or 1, 0, -1, and see what happens. You really need to experiment a lot with the rotation transform to get it working for you, but it is worth the effort.