Modeling Orbiting and Rotating Bodies Using VRML

H. Albert Lilly, PhD
Alabama School of Mathematics and Science
1255 Dauphin St.
Mobile, AL 36604
lilly@asms.net
www.asms.net/~lilly

Abstract:
Virtual Reality Modeling Language (VRML) can be used to model bodies in motion. The model might be used, for example, to illustrate a solar system. A body may be rotating on its axis, the axis may be tilting with the seasons, and the body may have a satellite to form a system. A system, e.g., a body and its satellite, may then be rotating around a sun according to an elliptical orbit. The elliptical orbits for satellites and systems alike can be calculated easily using a spreadsheet.

This paper will take the reader through the steps to show orbiting, rotating, and tilting bodies including how to create the objects, visually show the paths of the orbits, and set the time length for rotations, tilting of axes, and orbits for bodies. In addition, an explanation is given on how to create satellites of orbiting bodies and run the whole system continuously. The procedure for examining the model from various distances and angles during the animation is dependent on the VRML plug-in being used. Methods for creating the x, y and z coordinates of orbits using trigonometric functions and the timing for placement of objects are also explained.

Keywords:
apogee, elliptical, orbit, perigee, rotate, satellite, virtual reality

Introduction

A series of four steps is taken to develop a system. Each step has an example which includes a Virtual Reality Modeling Language (VRML) animation, the code for the animation, and an explanation. First, a sphere is rotated on its axis. Then, the axis of the sphere is tilted as it continues to rotate. The third example shows a satellite orbiting the sphere as it continues to tilt on its axis and rotate. Finally, the rotating and tilting sphere with its satellite is placed in orbit around a sun and a second body that orbits the sun is added also.

A Rotating Sphere

A sphere rotated on its axis is shown below. If it is not visible, the browser being used to view this file needs a VRML plug-in added. Following the animation is the entire code used to create the animation. After that is an explanation of the VRML world file.

#VRML V2.0 utf8

#VRML world file for a rotating body

Viewpoint {
       position  0 0 10
}

          DEF RotateSphere Transform {
            translation 0 0 0
            children [ 
              Shape {
                appearance Appearance {
                             texture ImageTexture { url "sky.jpg" }
                           }
                geometry Sphere {
                             radius 1.2
                           }
                    }
        
        # Run once for .5 sec.
        DEF RotateSource TimeSensor { cycleInterval .50 loop TRUE} 

        DEF Rotate OrientationInterpolator {
            key      [ 
				0, .25, .5, .75, 1.0
				]
            keyValue [ 
				0	1	0	0		, 
				0	1	0	-1.570796	,	
				0	1	0	-3.141593	,	
				0	1	0	-4.712389	,	
				0	1	0	-6.283185		
				]
        }
    ]
}

ROUTE RotateSource.fraction_changed TO Rotate.set_fraction
ROUTE Rotate.value_changed TO RotateSphere.rotation

Explanation of the VRML World File

The first line in a VRML world file should always contain the standard being used. The world file extension is wrl. The first line in the VRML files used in this paper is

#VRML V2.0 utf8

The version is 2.0. UTF8 is an 8-bit universal transformation format which is a superset ASCII [1] . After the first line, text following # on the same line is a comment and is ignored by the browser.

The viewpoint sets the camera position. The camera is looking at the origin of an invisible X and Y Cartesian plane from a distance of 10 meters on the positive Z axis. The meter is the standard unit of distance measurement in VRML. The X axis splits the screen horizontally. The Y axis splits the screen vertically. The Z axis is coming straight at the user from the center of the screen.

The key word "Transform" is used to create an object or collection of objects. The name of the object being created is "RotateSphere." The key word "translation" places the center of the object at the x, y, and z coordinates given, which in the above case is at 0 0 0 or the origin. The key word "children" is used to group objects. The shape being created is a sphere with radius 1.2 meters. The image file "sky.jpg" is used to add color and texture to the sphere.

The "TimeSensor" sets the time of the motion to be once every one half of a second. The value of TRUE following "loop" means to repeat the motion continuously. The name given to the time sensor is RotateSource. The "OrientationInterpolator" designates the type of movement to be a rotation. Interpolators move objects with a key and a keyValue. The values in the key are fractions from zero to one. Each number in the key corresponds to a set of numbers in the keyValue. In the "OrientationInterpolator", a set consists of four numbers. The first three numbers are a vector in space and the last number determines the number of radians to rotate around the vector. The numbers in the key specify the timing of each movement. For example, the second key value is .25 and the total length of the motion is one half of a second. Therefore, the second key sets the movement at time .125 (.25 X one half of a second). The movement at time .125 is determined by the second set of numbers in the keyValue. The second set of numbers means rotate 1.570796 radians in a clockwise direction around the Y axis which is the vector specified by 0 1 0. In the keyValue, if the negative numbers were positive, the sphere would rotate in the opposite direction. The name of the "OrientationInterpolator" is Rotate.

The "Route" key word is used to activate the motion. The names given to the "TimeSensor", the "OrientationInterpolator", and the "Transform" are used in the "Route" commands. These names are, respectively, RotateSource, Rotate, and RotateSphere. The "TimeSensor" is routed to the "OrientationInterpolator" and the "OrientationInterpolator" is routed to the "Transform."

A useful exercise is to run the VRML file on the hard drive. (Note that the sky.jpg file must be in the same folder as the wrl file to achieve the same results as online.) Select a number in the file, change the number, save the file, and try to predict the change in behavior due to the changed number. Test your prediction by visual inspection to see if it is correct. If it is not correct, try to determine why. Repeat this process for each number or type of number in the VRML world file.

Tilting the Sphere

In the animation below, the sphere is tilted as it continues to rotate. If it is not visible, the browser being used to view this file needs a VRML plug-in added. Following the animation is the entire code used to create the animation. After that is an explanation of the VRML world file.

#VRML V2.0 utf8

#VRML world file for a rotating and tilting body

Viewpoint {
       position  0 0 10
}

DEF TiltSphere Transform {
	translation 0 0 0
	children [
          DEF RotateSphere Transform {
            translation 0 0 0
            children [ 
              Shape {
                appearance Appearance {
                             texture ImageTexture { url "sky.jpg" }
                           }
                geometry Sphere {
                             radius 1.2
                           }
                    }
        
        # Run once for .5 sec.
        DEF RotateSource TimeSensor { cycleInterval .50 loop TRUE} 

        DEF Rotate OrientationInterpolator {
            key      [ 
				0, .25, .5, .75, 1.0
				]
            keyValue [ 
				0	1	0	0		, 
				0	1	0	-1.570796	,	
				0	1	0	-3.141593	,	
				0	1	0	-4.712389	,	
				0	1	0	-6.283185		
				]
        }
    ]
}

        # Run once for 20.3 sec.
        DEF TiltSource TimeSensor { cycleInterval 20.3 loop TRUE} 

        DEF Tilt OrientationInterpolator {
            key      [ 
				0, .25, .5, .75, 1.0
				]
            keyValue [ 
				0	16.544		0	3.14159, 
				0	16.544		3	3.14159,	
				0	16.544		0	3.14159,
				0	16.544		-3	3.14159,	
				0	16.544		0	3.14159		
				]
     }
  ]
}

ROUTE RotateSource.fraction_changed TO Rotate.set_fraction
ROUTE Rotate.value_changed TO RotateSphere.rotation

ROUTE TiltSource.fraction_changed TO Tilt.set_fraction
ROUTE Tilt.value_changed TO TiltSphere.rotation

Explanation of the VRML World File

The rotating sphere is surrounded with additional code. It is important for the reader to thoroughly understand the VRML file in the previous example and to compare the two files and identify the additional lines which begin with

DEF TiltSphere Transform {
	translation 0 0 0
	children [

and end with an additional "TimeSensor, "OrientationInterpolator," and pair of "Route" instructions. The purpose of the surrounding code is to apply a tilt to the rotating sphere. The timing of the tilt is 20.3 seconds, but any time limit could be used. The axis of the sphere at the start coincides with the Y axis. The axis moves to coincide with the vector 0 8 3, then back to the Y axis, then to the vector 0 8 -3, and back to the Y axis. The process is repeated every 20.3 seconds. The movement is in a semicircle (Pi radians or 3.14159 radians rounded). The calculation of the vector about which the movement occurs is as follows. Determine the magnitude of the vector representing the desired axis position, e.g., 0 8 3. Since the magnitude of the vector is the distance from the origin, the calculation can be done using the distance formula as follows: (0^2 + 8^2 + 3^2)^.5 = 8.544. Then, using the magnitude calculated, create a vector along the Y axis with equal magnitude. The vector of equal magnitude to 0 8 3 along the Y axis is 0 8.544 0. Add the two vectors together to form a parallelogram in space. In this case, 0 + 0 = 0 for the X coordinate, 8 + 8.544 = 16.544 for the Y coordinate, and 3 + 0 = 3 for the Z coordinate. The resulting vector splits the parallelogram and can be used as a pivot. Since the default starting position for the axis of a sphere coincides with the Y axis, the axis of a sphere can be changed from its default position to the desired axis position by moving around the pivot in a semicircle. For example, if the starting axis position coincides with a vector position of 0 8.544 0 (which, of course, coincides with the Y axis) and the pivot vector is 0 16.544 3, then a semicircle rotation around the pivot will move the axis to a position coinciding with the vector position of 0 8 3. This method of creating a parallelogram, splitting it to create a pivot vector, and rotating half way around the pivot vector can be used to move the axis of a sphere to coincide with any arbitrary vector.

A useful exercise is to run the VRML file on the hard drive. (Note that the sky.jpg file must be in the same folder as the wrl file to achieve the same results as online.) Select a number in the file, change the number, save the file, and try to predict the change in behavior due to the changed number. Test your prediction by visual inspection to see if it is correct. If it is not correct, try to determine why. Repeat this process for each number or type of number in the VRML world file.

Adding a Satellite

In the example below, a satellite is shown orbiting the sphere as it continues to tilt its axis and rotate. If it is not visible, the browser being used to view this file needs a VRML plug-in added. Following the animation is the entire code used to create the animation. After that is an explanation of the VRML world file.

#VRML V2.0 utf8

#VRML world file for a body with a satellite

Viewpoint {
       position  0 0 10
}

        DEF SatelliteOfRotatingAndTiltingObject Transform {
          translation 0 0 0
          children [ 
                Shape {
                  appearance Appearance {               
	     	     	   texture ImageTexture { url "rock.gif" }
                          }
                  geometry Sphere {
                     radius 0.5 # radius is the sole field
                          }
                       }

        # Run once for 2.3 sec.
        DEF TimeSourceForSatelliteOfRotatingAndTiltingObject TimeSensor {
              cycleInterval 2.3
              loop TRUE
            }

        DEF AnimationForSatelliteOfRotatingAndTiltingObject
              PositionInterpolator {
              key      [
                        0,      0.03125,        0.0625,         0.09375,  
                        0.125,  0.15625,        0.1875,         0.21875,  
                        0.25,   0.28125,        0.3125,         0.34375,  
                        0.375,  0.40625,        0.4375,         0.46875,
                        0.5,    0.53125,        0.5625,         0.59375,
                        0.625,  0.65625,        0.6875,         0.71875,
                        0.75,   0.78125,        0.8125,         0.84375,
                        0.875,  0.90625,        0.9375,         0.96875,
                        1 ]
              keyValue [
                        -3      -1      0,
                        -2.942355841    -0.98078528     0.780361288,
                        -2.771638598    -0.923879533    1.530733729,
                        -2.494408837    -0.831469612    2.222280932,
                        -2.121320344    -0.707106781    2.828427125,
                        -1.666710699    -0.555570233    3.325878449,
                        -1.148050297    -0.382683432    3.69551813,
                        -0.585270966    -0.195090322    3.923141122,
                        0       0       4,
                        0.585270966     0.195090322     3.923141122,
                        1.148050297     0.382683432     3.69551813,
                        1.666710699     0.555570233     3.325878449,
                        2.121320344     0.707106781     2.828427125,
                        2.494408837     0.831469612     2.222280932,
                        2.771638598     0.923879533     1.530733729,
                        2.942355841     0.98078528      0.780361288,
                        3       1       0,
                        2.942355841     0.98078528      -0.780361288,
                        2.771638598     0.923879533     -1.530733729,
                        2.494408837     0.831469612     -2.222280932,
                        2.121320344     0.707106781     -2.828427125,
                        1.666710699     0.555570233     -3.325878449,
                        1.148050297     0.382683432     -3.69551813,
                        0.585270966     0.195090322     -3.923141122,
                        0       0       -4,
                        -0.585270966    -0.195090322    -3.923141122,
                        -1.148050297    -0.382683432    -3.69551813,
                        -1.666710699    -0.555570233    -3.325878449,
                        -2.121320344    -0.707106781    -2.828427125,
                        -2.494408837    -0.831469612    -2.222280932,
                        -2.771638598    -0.923879533    -1.530733729,
                        -2.942355841    -0.98078528     -0.780361288,
                        -3      -1      0
               ]
            }
    ]
}

DEF OrbitOfSatelliteOfRotatingAndTiltingObject Transform {
         translation 0 0 0
         children [
           Shape { 
             appearance Appearance {
               material Material {
                 diffuseColor   .8 .5 .2
                 emissiveColor  .8 .5 .2
                 shininess      1.0
                 transparency   0.0
              }
            }
    geometry IndexedLineSet {
    # Draw a line from point 0 to point 1, point 1 to point 2, etc.
    # The -1 means to stop drawing points
        coordIndex [ 0, 1, 2, 3, 4, 5, 6, 7, 8,
                     9, 10, 11, 12, 13, 14, 15, 16,
                     17, 18, 19, 20, 21, 22, 23, 24,
                     25, 26, 27, 28, 29, 30, 31, 32, -1]
        coord Coordinate { 
              point [
                        -3      -1      0,
                        -2.942355841    -0.98078528     0.780361288,
                        -2.771638598    -0.923879533    1.530733729,
                        -2.494408837    -0.831469612    2.222280932,
                        -2.121320344    -0.707106781    2.828427125,
                        -1.666710699    -0.555570233    3.325878449,
                        -1.148050297    -0.382683432    3.69551813,
                        -0.585270966    -0.195090322    3.923141122,
                        0       0       4,
                        0.585270966     0.195090322     3.923141122,
                        1.148050297     0.382683432     3.69551813,
                        1.666710699     0.555570233     3.325878449,
                        2.121320344     0.707106781     2.828427125,
                        2.494408837     0.831469612     2.222280932,
                        2.771638598     0.923879533     1.530733729,
                        2.942355841     0.98078528      0.780361288,
                        3       1       0,
                        2.942355841     0.98078528      -0.780361288,
                        2.771638598     0.923879533     -1.530733729,
                        2.494408837     0.831469612     -2.222280932,
                        2.121320344     0.707106781     -2.828427125,
                        1.666710699     0.555570233     -3.325878449,
                        1.148050297     0.382683432     -3.69551813,
                        0.585270966     0.195090322     -3.923141122,
                        0       0       -4,
                        -0.585270966    -0.195090322    -3.923141122,
                        -1.148050297    -0.382683432    -3.69551813,
                        -1.666710699    -0.555570233    -3.325878449,
                        -2.121320344    -0.707106781    -2.828427125,
                        -2.494408837    -0.831469612    -2.222280932,
                        -2.771638598    -0.923879533    -1.530733729,
                        -2.942355841    -0.98078528     -0.780361288,
                        -3      -1      0
               ]
            }
         }
      }
   ]
}

DEF TiltSphere Transform {
	translation 0 0 0
	children [
          DEF RotateSphere Transform {
            translation 0 0 0
            children [ 
              Shape {
                appearance Appearance {
                             texture ImageTexture { url "sky.jpg" }
                           }
                geometry Sphere {
                             radius 1.2
                           }
                    }
        
        # Run once for .5 sec.
        DEF RotateSource TimeSensor { cycleInterval .50 loop TRUE} 

        DEF Rotate OrientationInterpolator {
            key      [ 
				0, .25, .5, .75, 1.0
				]
            keyValue [ 
				0	1	0	0		, 
				0	1	0	-1.570796	,	
				0	1	0	-3.141593	,	
				0	1	0	-4.712389	,	
				0	1	0	-6.283185		
				]
        }
    ]
}

        # Run once for 20.3 sec.
        DEF TiltSource TimeSensor { cycleInterval 20.3 loop TRUE} 

        DEF Tilt OrientationInterpolator {
            key      [ 
				0, .25, .5, .75, 1.0
				]
            keyValue [ 
				0	16.544		0	3.14159, 
				0	16.544		3	3.14159,	
				0	16.544		0	3.14159,
				0	16.544		-3	3.14159,	
				0	16.544		0	3.14159		
				]
        }
        ]
       }

ROUTE RotateSource.fraction_changed TO Rotate.set_fraction
ROUTE Rotate.value_changed TO RotateSphere.rotation

ROUTE TiltSource.fraction_changed TO Tilt.set_fraction
ROUTE Tilt.value_changed TO TiltSphere.rotation

ROUTE TimeSourceForSatelliteOfRotatingAndTiltingObject.fraction_changed
        TO AnimationForSatelliteOfRotatingAndTiltingObject.set_fraction
ROUTE AnimationForSatelliteOfRotatingAndTiltingObject.value_changed
        TO SatelliteOfRotatingAndTiltingObject.translation

Explanation of the VRML World File

Two independent blocks of code and a pair of "ROUTE" instructions are added to the rotating and tilting sphere. It is important for the reader to thoroughly understand the VRML file in the previous example and to compare the two files and identify the additional lines. The first new block of code appearing in the file begins with

        DEF SatelliteOfRotatingAndTiltingObject Transform {
          translation 0 0 0 
          children [ 

This block defines the satellite and its orbit. The interpolator used to move the satellite in its orbit was a "PositionInterpolator" rather than an "OrientationInterpolator." A "PositionInterpolator" does a "translation" rather than a "rotation." A "translation" moves the center of an object to a specified position in 3D space. Compare the new pair of "ROUTE" instructions to the previous two pairs. The last word in the second of the pair is "translation" rather than "orientation."

The color and texture of the satellite are supplied by the file "rock.gif." The radius of the satellite is 0.5 meters. The length of the orbit is 2.3 seconds. The "PostionInterpolator" moves objects by translation. As with all interpolators, the "PositionInterpolator" has a key and a keyValue. The values in the key are fractions from zero to one. Each number in the key corresponds to a set of numbers in the keyValue. In the "PositionInterpolator", a set consists of three numbers which are the X, Y, and Z coordinates. The center of the object moves to the X, Y, and Z coordinates at the prescribed time. The numbers in the key specify the timing of each movement. For example, the second key value is 0.03125 and the total length of the motion is 2.3 seconds. Therefore, the second key sets the movement at time 0.071875 (0.03125 X 2.3). At time 0.071875 the center of the satellite moves to the position X = -2.942355841, Y = -0.98078528, and Z = 0.780361288.

The coordinates in the keyValue are a elliptical orbit. The values can be calculated in a spreadsheet. The instructions using Microsoft Excel are as follows. Place a 0 in cell A1. Put the formula =A1+PI()/16 in cell A2. Fill down from cell A2 to cell A33. This yields 33 equally spaced number from 0 to 2Pi which is one revolution around a circle. Place the formula =IF(ABS(COS(A1))<0.00001,0,COS(A1)) in cell B1. Fill down from cell B1 to cell B33. The reason for the IF function is so that if the result is very close to 0, the number returned will be exactly 0. This column gives the horizontal values for a unit circle. Place the formula =IF(ABS(SIN(A1))<0.00001,0,SIN(A1)) in cell C1. Fill down from cell C1 to cell C33. Again, the reason for the IF function is so that if the result is very close to 0, the number returned will be exactly 0. This column gives the vertical values for a unit circle. One of the three coordinates (X, Y, or Z) must be based on the horizontal values of the unit circle, another on the vertical values of a unit circle and the third can be a constant or any pattern that begins and ends with the same number including the horizontal or vertical values of a unit circle. A constant can be multiplied times the horizontal or vertical values of the unit circle and a constant can be added or subtracted. Multiplication can be used to transform the values of the unit circle into an ellipse. Adding or subtracting a constant from each element can create a perigee and apogee in the orbit. The perigee is the point in the orbit when a satellite is closest to the body it orbits and the apogee is most distant point. [2] .

In the satellite orbit, the X and Y coordinates are based on the horizontal values of a unit circle (column B in the spreadsheet) and the Z coordinates on the vertical values (column C in the spreadsheet). The instructions are as follows using the spreadsheet started above. Place the formula =-3*B1 in cell D1 and fill down to cell D33. These are the X coordinates. Place the formula =-1*B1 in cell E1 and fill down to cell E33. These are the Y coordinates. Place the formula =4*C1 in cell F1 and fill down to cell F33. These are the Z coordinates. Since no constants were added or subtracted in any of the three formulas above, a perigee and apogee do not exist. The timing values in the key can be calculated by placing a 0 in H1, the formula =H1+1/32 in H2, and filling down from H2 to H33.

The second new block of code appearing in the file begins with

DEF OrbitOfSatelliteOfRotatingAndTiltingObject Transform {
    translation 0 0 0
    children [   

This block of code draws a set of lines along the orbit of the satellite. The appearance of the lines is controlled by the key words "diffuseColor" which is color from reflected light, "emissiveColor" which is color from light emanating from an object, "shininess" or luster, and "transparency" or lack of visibility. The numbers following "diffuseColor" and "emissiveColor" are red, green, and blue color values which can range from 0 to 1. The "shininess" and "transparency" values can also range from 0 to 1. Zero is the least amount of a color or attribute and 1 is the greatest amount with values in between being partial amounts which vary according to the relative size of the number. The lines are joined using the key word "IndexedLineSet" which has two components which are "coordIndex" and "coord Coordinate." The values in the "coordIndex" number the points in the "coord Coordinate" with the first one being point #0. A line is draw from point #0 to point #1, form point #1 to point #2, and so forth until -1 is reached which means STOP DRAWING POINTS. For example, creating a line from point #0 to point #1 draws a line from the point X = -3, Y = -1, and Z = 0 to the point X = -2.942355841, Y = -0.98078528, and Z = 0.780361288. The points are the same as those calculated above in the spreadsheet to get the keyValue for the "PositionInterpolator."

A useful exercise is to run the VRML file on the hard drive. (Note that the sky.jpg and rock.gif files must be in the same folder as the wrl file to achieve the same results as online.) Select a number in the file, change the number, save the file, and try to predict the change in behavior due to the changed number. Test your prediction by visual inspection to see if it is correct. If it is not correct, try to determine why. Repeat this process for each number or type of number in the VRML world file.

Creation of a System

In the animation below, the rotating and tilting sphere with its satellite is placed in orbit around a sun and a second body that orbits the sun is added. If it is not visible, the browser being used to view this file needs a VRML plug-in added. Following the animation is the entire code used to create the animation. After that is an explanation of the VRML world file.

#VRML V2.0 utf8

#VRML world file for a system of orbiting bodies

Viewpoint {
       position  0 0 36
}

DEF CenterObject Transform {
    translation 0 0 0
    children [ 
        Shape {
           appearance Appearance {
               material Material {
                 diffuseColor   0.8 0.5 0.2
                 emissiveColor  0.8 0.5 0.2
                 shininess      1.0
                 transparency   0.0
               }
            }
            geometry Sphere {
                    radius 3 # radius is the sole field
           }
         }
    ]
}
 
DEF RotatingAndTiltingObject Transform {
    translation 0 0 0
    children [ 

        DEF SatelliteOfRotatingAndTiltingObject Transform {
          translation 0 0 0
          children [ 
                Shape {
                  appearance Appearance {               
	     	     	   texture ImageTexture { url "rock.gif" }
                          }
                  geometry Sphere {
                     radius 0.5 # radius is the sole field
                          }
                       }

        # Run once for 2.3 sec.
        DEF TimeSourceForSatelliteOfRotatingAndTiltingObject TimeSensor {
              cycleInterval 2.3
              loop TRUE
            }

        DEF AnimationForSatelliteOfRotatingAndTiltingObject
              PositionInterpolator {
              key      [
                        0,      0.03125,        0.0625,         0.09375,  
                        0.125,  0.15625,        0.1875,         0.21875,  
                        0.25,   0.28125,        0.3125,         0.34375,  
                        0.375,  0.40625,        0.4375,         0.46875,
                        0.5,    0.53125,        0.5625,         0.59375,
                        0.625,  0.65625,        0.6875,         0.71875,
                        0.75,   0.78125,        0.8125,         0.84375,
                        0.875,  0.90625,        0.9375,         0.96875,
                        1 ]
              keyValue [
                        -3      -1      0,
                        -2.942355841    -0.98078528     0.780361288,
                        -2.771638598    -0.923879533    1.530733729,
                        -2.494408837    -0.831469612    2.222280932,
                        -2.121320344    -0.707106781    2.828427125,
                        -1.666710699    -0.555570233    3.325878449,
                        -1.148050297    -0.382683432    3.69551813,
                        -0.585270966    -0.195090322    3.923141122,
                        0       0       4,
                        0.585270966     0.195090322     3.923141122,
                        1.148050297     0.382683432     3.69551813,
                        1.666710699     0.555570233     3.325878449,
                        2.121320344     0.707106781     2.828427125,
                        2.494408837     0.831469612     2.222280932,
                        2.771638598     0.923879533     1.530733729,
                        2.942355841     0.98078528      0.780361288,
                        3       1       0,
                        2.942355841     0.98078528      -0.780361288,
                        2.771638598     0.923879533     -1.530733729,
                        2.494408837     0.831469612     -2.222280932,
                        2.121320344     0.707106781     -2.828427125,
                        1.666710699     0.555570233     -3.325878449,
                        1.148050297     0.382683432     -3.69551813,
                        0.585270966     0.195090322     -3.923141122,
                        0       0       -4,
                        -0.585270966    -0.195090322    -3.923141122,
                        -1.148050297    -0.382683432    -3.69551813,
                        -1.666710699    -0.555570233    -3.325878449,
                        -2.121320344    -0.707106781    -2.828427125,
                        -2.494408837    -0.831469612    -2.222280932,
                        -2.771638598    -0.923879533    -1.530733729,
                        -2.942355841    -0.98078528     -0.780361288,
                        -3      -1      0
               ]
            }
    ]
}

DEF OrbitOfSatelliteOfRotatingAndTiltingObject Transform {
         translation 0 0 0
         children [
           Shape { 
             appearance Appearance {
               material Material {
                 diffuseColor   .8 .5 .2
                 emissiveColor  .8 .5 .2
                 shininess      1.0
                 transparency   0.0
              }
            }
    geometry IndexedLineSet {
    # Draw a line from point 0 to point 1, point 1 to point 2, etc.
    # The -1 means to stop drawing points
        coordIndex [ 0, 1, 2, 3, 4, 5, 6, 7, 8,
                     9, 10, 11, 12, 13, 14, 15, 16,
                     17, 18, 19, 20, 21, 22, 23, 24,
                     25, 26, 27, 28, 29, 30, 31, 32, -1]
        coord Coordinate { 
              point [
                        -3      -1      0,
                        -2.942355841    -0.98078528     0.780361288,
                        -2.771638598    -0.923879533    1.530733729,
                        -2.494408837    -0.831469612    2.222280932,
                        -2.121320344    -0.707106781    2.828427125,
                        -1.666710699    -0.555570233    3.325878449,
                        -1.148050297    -0.382683432    3.69551813,
                        -0.585270966    -0.195090322    3.923141122,
                        0       0       4,
                        0.585270966     0.195090322     3.923141122,
                        1.148050297     0.382683432     3.69551813,
                        1.666710699     0.555570233     3.325878449,
                        2.121320344     0.707106781     2.828427125,
                        2.494408837     0.831469612     2.222280932,
                        2.771638598     0.923879533     1.530733729,
                        2.942355841     0.98078528      0.780361288,
                        3       1       0,
                        2.942355841     0.98078528      -0.780361288,
                        2.771638598     0.923879533     -1.530733729,
                        2.494408837     0.831469612     -2.222280932,
                        2.121320344     0.707106781     -2.828427125,
                        1.666710699     0.555570233     -3.325878449,
                        1.148050297     0.382683432     -3.69551813,
                        0.585270966     0.195090322     -3.923141122,
                        0       0       -4,
                        -0.585270966    -0.195090322    -3.923141122,
                        -1.148050297    -0.382683432    -3.69551813,
                        -1.666710699    -0.555570233    -3.325878449,
                        -2.121320344    -0.707106781    -2.828427125,
                        -2.494408837    -0.831469612    -2.222280932,
                        -2.771638598    -0.923879533    -1.530733729,
                        -2.942355841    -0.98078528     -0.780361288,
                        -3      -1      0
               ]
            }
         }
      }
   ]
}

DEF TiltSphere Transform {
	translation 0 0 0
	children [
          DEF RotateSphere Transform {
            translation 0 0 0
            children [ 
              Shape {
                appearance Appearance {
                             texture ImageTexture { url "sky.jpg" }
                           }
                geometry Sphere {
                             radius 1.2
                           }
                    }
        
        # Run once for .5 sec.
        DEF RotateSource TimeSensor { cycleInterval .50 loop TRUE} 

        DEF Rotate OrientationInterpolator {
            key      [ 
				0, .25, .5, .75, 1.0
				]
            keyValue [ 
				0	1	0	0		, 
				0	1	0	-1.570796	,	
				0	1	0	-3.141593	,	
				0	1	0	-4.712389	,	
				0	1	0	-6.283185		
				]
        }
    ]
}

        # Run once for 20.3 sec.
        DEF TiltSource TimeSensor { cycleInterval 20.3 loop TRUE} 

        DEF Tilt OrientationInterpolator {
            key      [ 
				0, .25, .5, .75, 1.0
				]
            keyValue [ 
				0	16.544		0	3.14159, 
				0	16.544		3	3.14159,	
				0	16.544		0	3.14159,
				0	16.544		-3	3.14159,	
				0	16.544		0	3.14159		
				]
        }
        ]
       }

        # Run once for 20.3 sec.
        DEF TimeSourceForRotatingAndTiltingObject TimeSensor {
              cycleInterval 20.3
              loop TRUE
            }

        DEF AnimationForRotatingAndTiltingObject PositionInterpolator {
              key      [
                        0,      0.03125,        0.0625,         0.09375,  
                        0.125,  0.15625,        0.1875,         0.21875,  
                        0.25,   0.28125,        0.3125,         0.34375,  
                        0.375,  0.40625,        0.4375,         0.46875,
                        0.5,    0.53125,        0.5625,         0.59375,
                        0.625,  0.65625,        0.6875,         0.71875,
                        0.75,   0.78125,        0.8125,         0.84375,
                        0.875,  0.90625,        0.9375,         0.96875,
                        1 ]
            keyValue [
                        -11     2       0,
                        -10.77903072    1.951963201     1.560722576,
                        -10.12461462    1.809698831     3.061467459,
                        -9.061900541    1.578674031     4.444561864,
                        -7.631727984    1.267766953     5.656854249,
                        -5.88905768     0.888925583     6.651756898,
                        -3.900859472    0.456708581     7.39103626,
                        -1.743538703    -0.012274195    7.846282243,
                        0.5     -0.5    8,
                        2.743538703     -0.987725805    7.846282243,
                        4.900859472     -1.456708581    7.39103626,
                        6.88905768      -1.888925583    6.651756898,
                        8.631727984     -2.267766953    5.656854249,
                        10.06190054     -2.578674031    4.444561864,
                        11.12461462     -2.809698831    3.061467459,
                        11.77903072     -2.951963201    1.560722576,
                        12      -3      0,
                        11.77903072     -2.951963201    -1.560722576,
                        11.12461462     -2.809698831    -3.061467459,
                        10.06190054     -2.578674031    -4.444561864,
                        8.631727984     -2.267766953    -5.656854249,
                        6.88905768      -1.888925583    -6.651756898,
                        4.900859472     -1.456708581    -7.39103626,
                        2.743538703     -0.987725805    -7.846282243,
                        0.5     -0.5    -8,
                        -1.743538703    -0.012274195    -7.846282243,
                        -3.900859472    0.456708581     -7.39103626,
                        -5.88905768     0.888925583     -6.651756898,
                        -7.631727984    1.267766953     -5.656854249,
                        -9.061900541    1.578674031     -4.444561864,
                        -10.12461462    1.809698831     -3.061467459,
                        -10.77903072    1.951963201     -1.560722576,
                        -11     2       0
                     ]
        }
    ]
}

ROUTE RotateSource.fraction_changed TO Rotate.set_fraction
ROUTE Rotate.value_changed TO RotateSphere.rotation

ROUTE TiltSource.fraction_changed TO Tilt.set_fraction
ROUTE Tilt.value_changed TO TiltSphere.rotation

ROUTE TimeSourceForRotatingAndTiltingObject.fraction_changed
        TO AnimationForRotatingAndTiltingObject.set_fraction
ROUTE AnimationForRotatingAndTiltingObject.value_changed
        TO RotatingAndTiltingObject.translation

ROUTE TimeSourceForSatelliteOfRotatingAndTiltingObject.fraction_changed
        TO AnimationForSatelliteOfRotatingAndTiltingObject.set_fraction
ROUTE AnimationForSatelliteOfRotatingAndTiltingObject.value_changed
        TO SatelliteOfRotatingAndTiltingObject.translation

DEF OrbitOfRotatingAndTiltingObject Transform {
         translation 0 0 0
         children [
           Shape { 
             appearance Appearance {
               material Material {
                 diffuseColor   .8 .5 .2
                 emissiveColor  .8 .5 .2
                 shininess      1.0
                 transparency   0.0
              }
            }
    geometry IndexedLineSet {
    # Draw a line from point 0 to point 1, point 1 to point 2, etc.
    # The -1 means to stop drawing points
        coordIndex [ 0, 1, 2, 3, 4, 5, 6, 7, 8,
                     9, 10, 11, 12, 13, 14, 15, 16,
                     17, 18, 19, 20, 21, 22, 23, 24,
                     25, 26, 27, 28, 29, 30, 31, 32, -1]
        coord Coordinate { 
             point   [
                        -11     2       0,
                        -10.77903072    1.951963201     1.560722576,
                        -10.12461462    1.809698831     3.061467459,
                        -9.061900541    1.578674031     4.444561864,
                        -7.631727984    1.267766953     5.656854249,
                        -5.88905768     0.888925583     6.651756898,
                        -3.900859472    0.456708581     7.39103626,
                        -1.743538703    -0.012274195    7.846282243,
                        0.5     -0.5    8,
                        2.743538703     -0.987725805    7.846282243,
                        4.900859472     -1.456708581    7.39103626,
                        6.88905768      -1.888925583    6.651756898,
                        8.631727984     -2.267766953    5.656854249,
                        10.06190054     -2.578674031    4.444561864,
                        11.12461462     -2.809698831    3.061467459,
                        11.77903072     -2.951963201    1.560722576,
                        12      -3      0,
                        11.77903072     -2.951963201    -1.560722576,
                        11.12461462     -2.809698831    -3.061467459,
                        10.06190054     -2.578674031    -4.444561864,
                        8.631727984     -2.267766953    -5.656854249,
                        6.88905768      -1.888925583    -6.651756898,
                        4.900859472     -1.456708581    -7.39103626,
                        2.743538703     -0.987725805    -7.846282243,
                        0.5     -0.5    -8,
                        -1.743538703    -0.012274195    -7.846282243,
                        -3.900859472    0.456708581     -7.39103626,
                        -5.88905768     0.888925583     -6.651756898,
                        -7.631727984    1.267766953     -5.656854249,
                        -9.061900541    1.578674031     -4.444561864,
                        -10.12461462    1.809698831     -3.061467459,
                        -10.77903072    1.951963201     -1.560722576,
                        -11     2       0
                     ]
               }
           }
       }
    ]
}

DEF SecondOrbitingObject Transform {
      translation 0 0 0
      children [
        Shape {
           appearance Appearance {
               material Material {
		     diffuseColor  0.0 0.0 0.0
                 emissiveColor 1.0 0.0 1.0
                     transparency 0.0
              }
            }
            geometry Sphere {
                    radius .8 # radius is the sole field
           }
         }
     
        # Run once for 5 sec.
        DEF TimeSourceForSecondOrbitingObject TimeSensor {
              cycleInterval 5.0
              loop TRUE
        }

        DEF AnimationForSecondOrbitingObject PositionInterpolator {
              key      [
                        0,      0.03125,        0.0625,         0.09375,  
                        0.125,  0.15625,        0.1875,         0.21875,  
                        0.25,   0.28125,        0.3125,         0.34375,  
                        0.375,  0.40625,        0.4375,         0.46875,
                        0.5,    0.53125,        0.5625,         0.59375,
                        0.625,  0.65625,        0.6875,         0.71875,
                        0.75,   0.78125,        0.8125,         0.84375,
                        0.875,  0.90625,        0.9375,         0.96875,
                        1 ]
            keyValue [
                        0       -7      0,
                        0.390180644     -6.865496963    2.92635483,
                        0.765366865     -6.467156728    5.740251485,
                        1.111140466     -5.820287286    8.333553495,
                        1.414213562     -4.949747468    10.60660172,
                        1.662939225     -3.888991631    12.47204418,
                        1.847759065     -2.678784027    13.85819299,
                        1.961570561     -1.365632254    14.71177921,
                        2       0       15,
                        1.961570561     1.365632254     14.71177921,
                        1.847759065     2.678784027     13.85819299,
                        1.662939225     3.888991631     12.47204418,
                        1.414213562     4.949747468     10.60660172,
                        1.111140466     5.820287286     8.333553495,
                        0.765366865     6.467156728     5.740251485,
                        0.390180644     6.865496963     2.92635483,
                        0       7       0,
                        -0.390180644    6.865496963     -2.92635483,
                        -0.765366865    6.467156728     -5.740251485,
                        -1.111140466    5.820287286     -8.333553495,
                        -1.414213562    4.949747468     -10.60660172,
                        -1.662939225    3.888991631     -12.47204418,
                        -1.847759065    2.678784027     -13.85819299,
                        -1.961570561    1.365632254     -14.71177921,
                        -2      0       -15,
                        -1.961570561    -1.365632254    -14.71177921,
                        -1.847759065    -2.678784027    -13.85819299,
                        -1.662939225    -3.888991631    -12.47204418,
                        -1.414213562    -4.949747468    -10.60660172,
                        -1.111140466    -5.820287286    -8.333553495,
                        -0.765366865    -6.467156728    -5.740251485,
                        -0.390180644    -6.865496963    -2.92635483,
                        0       -7      0
                     ]
        }
    ]
}

ROUTE TimeSourceForSecondOrbitingObject.fraction_changed
        TO AnimationForSecondOrbitingObject.set_fraction
ROUTE AnimationForSecondOrbitingObject.value_changed
        TO SecondOrbitingObject.translation

DEF OrbitOfSecondOrbitingObject Transform {
         translation 0 0 0
         children [
           Shape { 
             appearance Appearance {
               material Material {
                 diffuseColor   .8 .5 .2
                 emissiveColor  .8 .5 .2
                 shininess      1.0
                 transparency   0.0
              }
            }
    geometry IndexedLineSet {
    # Draw a line from point 0 to point 1, point 1 to point 2, etc.
    # The -1 means to stop drawing points
        coordIndex [ 0, 1, 2, 3, 4, 5, 6, 7, 8,
                     9, 10, 11, 12, 13, 14, 15, 16,
                     17, 18, 19, 20, 21, 22, 23, 24,
                     25, 26, 27, 28, 29, 30, 31, 32, -1]
        coord Coordinate { 
            point    [
                        0       -7      0,
                        0.390180644     -6.865496963    2.92635483,
                        0.765366865     -6.467156728    5.740251485,
                        1.111140466     -5.820287286    8.333553495,
                        1.414213562     -4.949747468    10.60660172,
                        1.662939225     -3.888991631    12.47204418,
                        1.847759065     -2.678784027    13.85819299,
                        1.961570561     -1.365632254    14.71177921,
                        2       0       15,
                        1.961570561     1.365632254     14.71177921,
                        1.847759065     2.678784027     13.85819299,
                        1.662939225     3.888991631     12.47204418,
                        1.414213562     4.949747468     10.60660172,
                        1.111140466     5.820287286     8.333553495,
                        0.765366865     6.467156728     5.740251485,
                        0.390180644     6.865496963     2.92635483,
                        0       7       0,
                        -0.390180644    6.865496963     -2.92635483,
                        -0.765366865    6.467156728     -5.740251485,
                        -1.111140466    5.820287286     -8.333553495,
                        -1.414213562    4.949747468     -10.60660172,
                        -1.662939225    3.888991631     -12.47204418,
                        -1.847759065    2.678784027     -13.85819299,
                        -1.961570561    1.365632254     -14.71177921,
                        -2      0       -15,
                        -1.961570561    -1.365632254    -14.71177921,
                        -1.847759065    -2.678784027    -13.85819299,
                        -1.662939225    -3.888991631    -12.47204418,
                        -1.414213562    -4.949747468    -10.60660172,
                        -1.111140466    -5.820287286    -8.333553495,
                        -0.765366865    -6.467156728    -5.740251485,
                        -0.390180644    -6.865496963    -2.92635483,
                        0       -7      0
                     ]
             }
         }
      }
   ]
}

Explanation of the VRML World File

Three major changes are made to the example in the previous section. A sun is added with a block of code. The rotating and tilted sphere and its satellite are surrounded with additional code in order to place the system in orbit around the sun. Also, an additional rotating body is added. It is important for the reader to thoroughly understand the VRML file in the previous example and to compare the two files and identify the additional lines. The code for the sun begins with

DEF CenterObject Transform {
    translation 0 0 0
    children [ 

and is straightforward in the sense that nothing new is used. The code surrounding the rotating and tilted sphere and its satellite begins with

DEF RotatingAndTiltingObject Transform {
    translation 0 0 0
    children [ 

and ends with a "PositionInterpolator" and a pair of ROUTE instructions so that the system orbits around the sun. The coordinates for the orbit were calculated using a spreadsheet. The first three columns (A, B, and C) and column H are the same as in the example described in the previous section. The instructions for columns D, E, and F are as follows. Place the formula =-11.5*B1+0.5 in cell D1 and fill down to cell D33. These are the X coordinates. Place the formula -1*(-2.5*B1+0.5) in cell E1 and fill down to cell E33. These are the Y coordinates. Place the formula =8*C1 in cell F1 and fill down to cell F33. These are the Z coordinates. Note that the time the orbit takes is set to coincide with the time the tilt takes which is arbitrarily set to 20.3 seconds. This is patterned after earth in which the four seasons are due to the tilting of the earth's axis. The seasons are repeated each year which is one revolution around the sun. The code for an additional rotating body begins with

DEF SecondOrbitingObject Transform {
      translation 0 0 0
      children [

and ends with a "PositionInterpolator" and a pair of ROUTE instructions so that the body orbits around the sun. The coordinates for the orbit were calculated using a spreadsheet. The first three columns (A, B, and C) and column H are the same as in the example described in the previous section. The instructions for columns D, E, and F are as follows. Place the formula =2*C1 in cell D1 and fill down to cell D33. These are the X coordinates. Place the formula =-7*B1 in cell E1 and fill down to cell E33. These are the Y coordinates. Place the formula =15*C1 in cell F1 and fill down to cell F33. These are the Z coordinates. The time of the orbit is set arbitrarily to 5 seconds.

A useful exercise is to run the VRML file on the hard drive. (Note that the sky.jpg and rock.gif files must be in the same folder as the wrl file to achieve the same results as online.) Select a number in the file, change the number, save the file, and try to predict the change in behavior due to the changed number. Test your prediction by visual inspection to see if it is correct. If it is not correct, try to determine why. Repeat this process for each number or type of number in the VRML world file.

Conclusions

VRML can be used to show how to build an animated system of orbiting bodies. A body can be rotated on its axis and tilted back and forth in synchronization with the timing of its orbit. Of course, on earth, the synchronization of the tilting with the timing of the orbit produces the four seasons of winter, spring, summer, and fall every year. The rotating and tilting body can have a satellite or moon and the system can be placed in an orbit around a sun. Other bodies or planets can be added using calculations for elliptical orbits which can be done in a spreadsheet.

References

1. Jed Hartman, Josie Wernecke. The VRML 2.0 Handbook: Building Moving Worlds on the Web. Reading, MA: Addison-Wesley. 1996.

2. Dinah L. Moche. Astronomy: A Self-Teaching Guide. Fourth Edition. New York: John Wiley. 1996.