
VRML is an abbreviation for Virtual Reality Modeling Language. In the words of Mark Pesce, one of its creators, VRML is "a language for describing multi-participant interactive simulations--virtual worlds networked via the global Internet and hyperlinked with the World Wide Web." More simply, VRML is a language that enables you to construct 3-D worlds that you can move through and with which you can interact.
VRML is a subset of the Open Inventor File Format, which was developed by Silicon Graphics. Like HTML, VRML is an ASCII text language that uses markup codes to provide information to a browser. Unlike HTML, the VRML codes are the content rather than tags that affect the content. VRML files describe worlds that can contain objects and links to other URLs, including other VRML worlds. Using your browser, you can navigate through these worlds, click links, and view the information presented in 3-D.
In this section, you learn how to use VRML files and how to create your own virtual worlds.
The first step is to learn how to use existing VRML files; how to navigate them using a browser; and how to host them on a server.
Next you see the VRML language itself. Because VRML is a unique language like HTML, you need to learn some basics before you integrate VRML with Cold Fusion. The VRML language is simple. It only has a few object definitions that can be used to create anything you want. The price for this simplicity is the amount of objects you will need to create (and time you'll spend) to build your virtual worlds. For example, you can't build a VRML model of a house using one complex cube object. Instead, the house would be made up of many cubes--one for the floor, at least one for each wall, and so on.
Before you can build, view, or host VRML files, your software must be properly configured. Fortunately, this is easy to do, and it might have been done for you because VRML is now a relatively common file format.
Configuring Your Web Server to Serve VRML files. Your Web server has to recognize
the VRML file format if you want it to host VRML files. You do this with MIME standards,
as described in Chapter 25, "MIME Types." Simply add the MIME type x-world/
x-vrml, matched to the file extension .wrl, to your server's MIME type configuration
section. Figure 26.1 shows how you would do this using WebSite.
Figure 26.1 The Content Type configuration tab in WebSite, showing the MIME type for VRML files.
Using a VRML Browser. If you want to view VRML files (and you do!), you'll
need a browser application that can display VRML output. Until recently, this meant
you needed a helper application that, when your Web browser received VRML output,
would launch and display that output. Depending on your computer and operating system,
this could still be true for you. For the most part, with newer systems you can view
VRML output from directly within your Web browser using a VRML plug-in or ActiveX
control. If you are using Netscape Navigator 2.0 or later, you can use Live3D from
Netscape, a plug-in that displays VRML inline just like GIF or JPG files. Sometimes
Navigator comes bundled with this plug-in, but if you don't have it, you can download
it from the Netscape Web site (http://home.netscape.com/).
Likewise, if you are using Internet Explorer 3.0 or later, you can download an ActiveX
control that will perform the same functions for you.
If you are using another browser, such as the Spyglass Mosaic browser shown in Figure 26.2, you will probably need to use a helper application. Helper applications exist for several operating environments, and many are freely available on the Internet. A good place to find one is the VRML Repository (http://www.sdsc.edu/vrml/), which is a Web site dedicated to VRML information and applications. If you are using a separate helper application, set it up and configure your Web browser to recognize VRML files and to launch the helper application.
Figure 26.2 Spyglass Mosaic showing the Helpers configuration screen, selected from the Edit menu. WebSpace, the helper application, is a product of Silicon Graphics.
Once you have set up your VRML browser, you're ready to jump into 3-D! You can start with one of the files on the CD-ROM for this chapter, or you can view them in many places on the Web. Once again, you might want to visit the VRML Repository.
Your next task is to learn how to move through 3-D space using your VRML browser. The interface will vary from one VRML browser to the next, so you need to learn different commands for navigation depending on your browser. But all of the browsers perform the same sorts of actions. The following example uses the Netscape Live3D Plug-in.
The first step is to actually load a VRML file. Like HTML documents, you can load VRML files from your local machine or from the Web. Unlike HTML files, you can't load a file until all of the node descriptions have been read. If you view a large HTML document on the Web, you can start to read it before your browser has finished receiving the entire document. But you can't read VRML files until your browser reads all of the text within the file.
Some VRML files are very large and complex, so you may have to wait awhile to view them. Once you download them however, they are not delayed by having to retrieve information from the Internet, for the most part. VRML files can contain textures, which are GIF, JPG, or other graphics file formats. They also can contain inline VRML files, which are separate stand-alone VRML files that are referenced as part of the larger scene. These inline VRML files might be preloaded by the browser you are using.
Not only does size matter when you download VRML files, it also matters when you view them. Large, complex scenes display more slowly, movement through them may become bogged down and jerky, and screen redraws will take longer. Also, VRML display performance is dependent on the computer that you use. What displays well on a 200 MHz Pentium Pro could be very unusable on a 486.
NOTE: Different browsers render scenes differently. Lighting and other effects will vary greatly among browsers, and the differences in effects will multiply as your virtual worlds become more complex. So you may want to choose one browser as the approved browser for viewing your VRML files.
For this example, the file Temple.wrl, shown in Figure 26.3 is used. You can find it on the CD-ROM. When you have loaded your VRML file, you can start moving through its virtual world. There are different methods of movement, just like in the real 3-D world. In fact, in VRML there is more freedom of movement because you're not hindered by gravity or physics. You can walk, fly, and slide through the virtual world. Within the Live3D interface, you move either by using the arrow keys or by clicking the mouse on a point and dragging the point one way or another. The question mark at the end of the line on the browser's interface turns on a heads-up display command list within the browser window.
Figure 26.3 The TEMPLE.WRL VRML file, as it is first displayed in the Netscape Live3D VRML browser.
The default method of movement is walking, which means moving within the hori- zontal plane of your current viewpoint. If your viewpoint is not along the plane of the ground, you might walk through space! Keep in mind that there may not even be a plane within the virtual world which corresponds to the ground in reality. In this example however, shown in Figure 26.4, walking will move you along the green surface until you move your viewpoint from your horizontal plane.
How do you move from this plane? Selecting the spin, look, or slide controls will do it in different ways. Spin enables you to rotate the world around its center point, just like spinning a globe. You might see something like Figure 26.5, if you try the spin control. Look moves the center point of the world around you, along a circle in which the radius is the distance between you and the center. Slide moves the world along the axis perpendicular to the direction you're facing.
Figure 26.4 Using the walk method you can navigate within your horizontal plane, in this case, parallel to the ground. Note that the line of text and the mouse cursor indicate a clickable area. The clickable area is a WWWAnchor node, which is a link to another URL.
Figure 26.5 Using the spin control, you can escape the horizontal ground plane so that you can see the "top" of the world.
What tools do you need to create VRML files? Because they are ASCII text, you can use a simple text editor such as Notepad. On the other hand, you've probably seen VRML authoring tools in your local software store. Many designers of 3-D rendering and CAD-style applications have added VRML authoring capability to their programs, and there are some tools designed just for VRML authoring. So what should you use?
What you should use depends on what you want to do. If you want to create very complex scenes, such as a model of your entire office building, it would take you forever to build this in a text editor. If you use an authoring tool, however, it would be much easier. There are several packages on the market that enable you to draw and manipulate shapes and to view your output at the same time. A good example is Virtus Walkthrough Pro 2.5.2, available for Windows 3.1 and Macintosh. Using a program like this, you don't have to know anything about VRML, you just need to know how to draw. So why should you learn VRML coding by hand? There are several reasons.
The most important reason is that the results will not be as good. Authoring tools can create VRML output, but they can't yet optimize it. A simple cube of five meters on each side, created by hand and by Virtus Walkthrough Pro, varies greatly in size and complexity. The handmade cube, Listing 26.1, is three lines of text and 86 bytes. It contains two nodes. The Cube node describes the spatial information about the cube, and the Material node makes it red. The cube created in Virtus Walkthrough Pro, Listing 26.2, consists of 95 lines of text and weighs in at 2.91K.
#VRML V1.0 ascii
Material { ambientColor 1 0 0 }
Cube { height 5 width 5 depth 5 }
Why such a difference? For one thing, Virtus adds all sorts of special settings, such as background color and lighting sources, that you won't add unless you explicitly want them. Also, Virtus doesn't use primitives, which are the object nodes that are used to describe simple 3-D shapes: cubes, spheres, cones, and cylinders. Every object authored in Virtus Walkthrough Pro is defined as a set of points upon which faces are placed. In the handmade cube, the cube itself is defined using the Cube primitive, which can be done on one line and quickly interpreted by the browser.
We'll be using the Virtus cube example shown in Listing 26.2 later in the chapter, so here's a little explanation of what's in it. The first section, the coordinate3 node, defines the set of points. The material node sets the color for the cube. The final section, the indexedfaceset node, draws polygon faces using the point set defined at the top. Don't worry too much about how this works yet; it will be made clearer in the following sections.
Separator { #Polyhedron
DEF COORD786432 Coordinate3 {
point [
0.0000 5.0000 -10.0000,
0.0000 5.0000 -5.0000,
-5.0000 5.0000 -5.0000,
-5.0000 5.0000 -10.0000,
0.0000 0.0000 -10.0000,
0.0000 0.0000 -5.0000,
-5.0000 0.0000 -5.0000,
-5.0000 0.0000 -10.0000
]
} #Coordinate3
Material {
ambientColor 0.2500 0.0000 0.0000 #ambientColor
diffuseColor 1.0000 0.0000 0.0000 #diffuseColor
transparency -0.0039 #transparency
} #Material
IndexedFaceSet {
coordIndex [
0, 1, 2, 3,-1,
3, 2, 1, 0,-1,
0, 3, 7, 4,-1,
4, 7, 3, 0,-1,
1, 0, 4, 5,-1,
5, 4, 0, 1,-1,
2, 1, 5, 6,-1,
6, 5, 1, 2,-1,
3, 2, 6, 7,-1,
7, 6, 2, 3,-1,
7, 6, 5, 4,-1,
4, 5, 6, 7,-1,
]
} #IndexedFaceSet
} #Polyhedron
}
You can see from this example that hand-coding gives you a smaller and easier-to- manage VRML file. In addition, it is also easier to read and modify. Later, when you are using Cold Fusion to generate VRML, you'll find it much easier to edit your templates and to dynamically generate VRML if you use primitives instead of complex polygon modeling.
You can use authoring tools when you want to create a complex, static VRML file, and if you want to build a complex interface, for example. You can do it much faster, and the differences in file size might not matter to you.
If you want to dynamically generate VRML using Cold Fusion, you'll have to learn VRML first! What follows is a brief introduction to the VRML language. It's pretty long and dry, so you might want to skim through it, then refer back to details about specific nodes as you run into them, or you might want to skip directly to the VRML primer section. In any case, you'll probably want a glass of your favorite caffeinated beverage before you start reading it.
When the designers of VRML decided to develop a virtual reality language, they wanted a platform-independent, extensible format that would enable hypermedia linking like HTML. They selected a subset of the Open Inventor File Format, which Silicon Graphics made an open format, and they designed a language that is simple, easily parsed, and tightly structured.
The language's structure is hierarchical--all objects, called nodes, are placed in a container called a scene graph. These containers hold nodes for primitive objects, as well as nodes that describe the other nodes. The ordering of nodes within a scene graph determines how nodes will affect other nodes. Scene graphs can be combined within a file using nodes that separate them. In the same way that adjectives within a sentence are used to describe nouns, nodes within a scene graph describe later nodes.
Before you list the nodes you can use in VRML 1.0, here are a few notes about VRML syntax.
Every VRML 1.0 file begins with this line:
#VRML V1.0 ascii
This signals the VRML browser that the file is a valid VRML file. The # character is used to begin a comment. Except for the first line, every character on the same line after # is ignored.
White space within a document, like spaces and tabs, does not provide any information to the VRML browser.
Nodes, being containers, have a type designation followed by curly braces, which may contain fields, children, or both. They may also have a name that you can create and reference. Using the Cube node as an example:
DEF MyCube Cube { height 1 width 1 depth 1 }
This creates a cube with height, width, and depth fields, and defines it as the object MyCube.
The VRML Coordinate System. Because VRML describes 3-D space, it requires
a 3-D coordinate system.This coordinate system, shown in Figure 26.6, has x-, y-,
and z-axes. If you think of the origin, with x, y, and z values equal to zero, as
situated in the center of your computer monitor, the positive x-axis increases in
value from zero as it goes to the right, the positive y-axis increases as it goes
up, and the positive z-axis increases as it moves toward you. Likewise, the negative
portions of these axes point in the opposite directions.
Distance is measured in meters, and angles between vectors are measured in radians. If you are more accustomed to measuring angles in degrees, you will need to convert degrees to radians. 180 degrees is equal to, or approximately, 3.14159265359 radians. Fortunately, you can round this to 3.14 with no noticeable effect on your models.
There are several types of nodes in the VRML 1.0 specification. They are divided into three categories: shape nodes like the Cube node shown in Listing 26.1, property nodes like Material, and group nodes that contain and separate other nodes. There is one node that doesn't belong in any of these categories, WWWInline. This node is described at the end of the Group nodes list.
Figure 26.6 The VRML coordinate system, showing the positive x-, y-, and z-axes pointing in the directions in which they increase.
Most nodes have default values that will be described later. You can often omit fields when you don't change their values. For example,
Cube { height 2 width 2 depth 2 }
which lists the default values, is equivalent to
Cube { }
The following sections list each node divided into the three categories described earlier: shape, property, and group. All nodes that are defined in the VRML 1.0 Specification are listed here. However, some nodes are not fully described because they are beyond the scope of this book. For more information about these nodes, as well as VRML 1.0 in general, consult the VRML 1.0 Specification, as well as Special Edition Using VRML from Que Publishing.
Shape Nodes. You can model 3-D scenes of unbelievable complexity using VRML,
by simply putting together different simple 3-D shapes. These shapes--cube, sphere,
cylinder, and cone--are created using shape nodes. All of the 3-D objects in VRML
are created using shape nodes.
AsciiText. This node displays simple ASCII text strings as objects. The first string will display with its bottom edge at y = 0, and centered on the y-axis. Any subsequent strings will be displayed below the first. The justification, LEFT, CENTER, or RIGHT, aligns to the origin.
AsciiText {
string ""
spacing 1
justification LEFT
width 0
}
Cone. This cone has a circular bottom and it points upward. By default, the cone is placed so that its bisecting point is at the origin. The parts field lets you display the SIDES, BOTTOM, or ALL of the cone.
Cone {
parts ALL
bottomRadius 1
height 2
}
Cube. This node is not really a cube, but rather a cuboid solid. By default, it is placed so that the origin is at its center.
Cube {
width 2
height 2
depth 2
}
Cylinder. This node draws a cylinder centered around the y-axis and bisected by the x-axis. The parts field can be used to display the SIDES, TOP, BOTTOM, or ALL of the cylinder.
Cylinder {
parts ALL
radius 1
height 2
}
IndexedFaceSet. This node uses the point values defined in a Coordinate3 node, and places polygons between the vertices using the coordIndex field. A value of -1 is used to terminate the current polygon. We'll refer back to Listing 26.2 to illustrate this node. In the listing, there is a Coordinate3 node with eight points from 0 to 7, shown below.
DEF COORD786432 Coordinate3 {
point [
0.0000 5.0000 -10.0000,
0.0000 5.0000 -5.0000,
-5.0000 5.0000 -5.0000,
-5.0000 5.0000 -10.0000,
0.0000 0.0000 -10.0000,
0.0000 0.0000 -5.0000,
-5.0000 0.0000 -5.0000,
-5.0000 0.0000 -10.0000
]
} #Coordinate3
Shortly after, there is an IndexedFaceSet node. On each line of the coordIndex value, a polygon is defined using the points 0 to 7 as defined in the Coordinate3 node, then it is terminated with -1. For example, the first line of the coordIndex value has five values. The first four specify points in 3D space, and the fifth, -1, is used to inform the VRML browser that there are no more points belonging to this polygon.
IndexedFaceSet {
coordIndex [
0, 1, 2, 3,-1,
3, 2, 1, 0,-1,
0, 3, 7, 4,-1,
4, 7, 3, 0,-1,
1, 0, 4, 5,-1,
5, 4, 0, 1,-1,
2, 1, 5, 6,-1,
6, 5, 1, 2,-1,
3, 2, 6, 7,-1,
7, 6, 2, 3,-1,
7, 6, 5, 4,-1,
4, 5, 6, 7,-1,
]
} #IndexedFaceSet
The browser uses this information to draw a two-dimensional rectangular polygon with its corners at points 0, 1, 2 and 3.
The materialIndex and normalIndex refer to Material and Normal nodes respectively, in the same way as the coordIndex, as the textureCoordIndex field refers to a previous TextureCoordinate2 node.
IndexedFaceSet {
coordIndex 0
materialIndex -1
normalIndex -1
textureCoordIndex -1
}
IndexedLineSet. Similar to the IndexedFaceSet node, it uses the values in a Coordinate3 node to draw lines between vertices and to create a wire-frame effect. The parameters are the same as for the IndexedFaceSet.
IndexedLineSet {
coordIndex 0
materialIndex -1
normalIndex -1
textureCoordIndex -1
}
PointSet. This node uses the values in a Coordinate3 node to place points in 3-D space. The startIndex field is used to select the first point that will be displayed. The numPoints field sets the number of points that will be displayed. Each value from startIndex to numPoints within the Coordinate3 node will be displayed as a point. If numPoints is -1, all values after the startIndex will be displayed. This differs from the IndexedLineSet and IndexedFaceSet nodes because it doesn't draw any connections between the points--they will be displayed as a cloud of individual points in 3-D space.
PointSet {
startIndex 0
numPoints -1
}
Sphere. The Sphere node creates a sphere that is centered on the origin.
Sphere {
radius 1
}
Property Nodes. Property nodes, as you can probably guess from the name, don't create shapes. Instead, they provide properties that can specify characteristics of shape nodes.
Coordinate3. This node is used to define a set of one or more points in 3-D space, which can later be referenced by an IndexedFaceSet, IndexedLineSet, or PointSet node. By itself, this node does not produce any visible result in your model. Each point is a set of three numbers, corresponding to coordinates along the x, y and z axes.
Coordinate3 {
point 0 0 0
}
If you define more than one point, you must use brackets to contain the points, and commas to separate the number triplets. You first saw this format in Listing 26.2. Here is the Coordinate3 node from that listing.
DEF COORD786432 Coordinate3 {
point [
0.0000 5.0000 -10.0000,
0.0000 5.0000 -5.0000,
-5.0000 5.0000 -5.0000,
-5.0000 5.0000 -10.0000,
0.0000 0.0000 -10.0000,
0.0000 0.0000 -5.0000,
-5.0000 0.0000 -5.0000,
-5.0000 0.0000 -10.0000
]
} #Coordinate3
DirectionalLight. This node creates a light source within your model that provides illumination along the path of the vector specified in the direction field. The color field is a RGB value, with parameters of floating point values between zero and one.
DirectionalLight {
on TRUE
intensity 1
color 1 1 1
direction 0 0 -1
}
FontStyle. This node is used to set properties for AsciiText nodes following it within the scene group. The family field can be set to SERIF, SANS, or TYPEWRITER. The style field can be set to NONE, BOLD, or ITALIC.
FontStyle {
size 10
family SERIF
style NONE
}
Info. This node can be used to provide information. Comments using the # character are occasionally stripped by VRML browsers.
Info {
string ""
}
LOD. The Level of Detail node enables you to create renderings that will appear to the viewer at different distances. These renderings, children of the LOD node, contain all of the objects and property nodes that you want to display at that range. The range field is used to specify the boundaries between levels of detail. The number of children should be one more than the number of ranges. For example, if you use 30, 60, and 90 as ranges, you should define four children--the first would appear if the viewer's perspective within the world is between 0 and 30 meters away, the second between 31 and 60, the third between 61 and 90, and the fourth 91 or more. Ranges are placed between brackets.
LOD {
range [ ]
center 0 0 0
}
Material. This node enables you to specify surface properties for shape nodes. There are several properties that you can set, and all of these fields can accept multiple properties to be used as an index. The ambientColor field enables you to set the secondary color for an object. The diffuseColor sets the primary color for an object, and it is a required field in the Material node. The specularColor field sets the color of light reflected from the object. The emissiveColor is the color of the object in shadow. Shininess and transparency are self-explanatory, and they accept floating-point values between 0 and 1. Here's a simple example:
Material {
ambientColor 0.2 0.2 0.2
diffuseColor 0.8 0.8 0.8
specularColor 0 0 0
emissiveColor 0 0 0
shininess 0.2
transparency 0
}
Alternatively, you can use the Material node to specify more than one set of properties. Here's an example in which the Material node lists six values for ambientColor and diffuseColor.
Material {
ambientColor [ 0.250000 0.000000 0.000000,
0.250000 0.000000 0.000000,
0.250000 0.000000 0.000000,
0.250000 0.000000 0.000000,
0.250000 0.000000 0.000000,
0.250000 0.000000 0.000000,
] #ambientColor
diffuseColor [ 1.000000 0.000000 0.000000,
1.000000 0.000000 0.000000,
1.000000 0.000000 0.000000,
1.000000 0.000000 0.000000,
1.000000 0.000000 0.000000,
1.000000 0.000000 0.000000,
] #diffuseColor
} #Material
Using multiple values in a Material node allows you to bind multiple properties to a single node, which is usually a complex node drawn from a Coordinate3 node.
MaterialBinding. This node is used to specify how materials--colors, opacity and reflectiveness--are bound to objects, usually those created using the Coordinate3 node. A complete explanation of how to use this node is beyond the scope of this book; usually you wouldn't create one of these by hand unless you're a real masochist. Here's a brief explanation of how this works. If you've created a Material node with multiple values for properties, as illustrated above, you can distribute the properties over a single shape node. For those nodes which accept a materialIndex value, such as the IndexedFaceSet node, you can use the PER PART INDEXED, PER FACE INDEXED and PER VERTEX INDEXED values to specify one of the listed Material values for each segment, in the same manner as you reference a Coordinate3 node to specify points. Table 26.1 shows the different bindings and how they affect the shape node.
MaterialBinding {
value DEFAULT
}
| Name | Effect |
| DEFAULT | Use default binding |
| OVERALL | The same material is used on the entire object |
| PER_PART | A different material is placed on each part of the object |
| PER_PART_INDEXED | As PER_PART, for shapes that enable indexing |
| PER_FACE | A different material for each face of the object |
| PER_FACE_INDEXED | As PER_FACE, for shapes that enable indexing |
| PER_VERTEX | A different material for each vertex of the object |
| PER_VERTEX_INDEXED | As PER_VERTEX, for shapes that enable indexing |
MatrixTransform. This node enables you to perform multiple transforms using a four-by-four matrix. The first column controls scaling and translation in the x direction, the second column controls scaling and translation in the y direction, and the third column controls scaling and translation in the z direction. The fourth column doesn't do anything except for the final value, which scales the entire object. The rows specify which parts of the objects will be scaled or translated. The first row refers to x faces of an object, the second refers to y faces, and the third refers to z faces.
MatrixTransform {
matrix 1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
}
Normal. This node creates 3-D normal vectors for use with the IndexedFaceSet, IndexedLineSet, and PointSet nodes.
Normal {
vector 0 0 1
}
NormalBinding. This node performs the same function for normals that MaterialBinding does for materials, and it accepts the same values.
NormalBinding {
value DEFAULT
}
OrthographicCamera. This node creates a viewpoint within your world that does not provide objects with perspective, instead it shows them at the same size regardless of distance.
OrthographicCamera {
position 0 0 1
orientation 0 0 1 0
focalDistance 5
height 2
}
PerspectiveCamera. Like an OrthographicCamera, this places a viewpoint, but it uses perspective to display objects.
PerspectiveCamera {
position 0 0 1
orientation 0 0 1 0
focalDistance 5
heightAngle 0.785398
}
PointLight. This node creates an omnidirectional light source at the given location.
PointLight {
on TRUE
intensity 1
color 1 1 1
location 0 0 1
}
Rotation. This node rotates its children around an axis that is defined by the line that runs through the origin and the point defined by the first three numbers of the rotation value. The fourth number represents how much to the right, in radians, the objects will be rotated about the axis.
Rotation {
rotation 0 0 1 0
}
Scale. This node scales objects by x, y, and z amounts from the origin.
Scale {
scaleFactor 1 1 1
}
ShapeHints. This node controls whether IndexedFaceSets display as solid, with ordered vertices, or convex faces. The vertexOrdering field controls whether vertices are ordered CLOCKWISE from the outside, COUNTERCLOCKWISE, or UNKNOWN_ORDERING. The shapeType field defines whether the shape is SOLID, enclosing a volume, or UNKNOWN_SHAPE_TYPE. The faceType field describes whether faces are CONVEX or UNKNOWN_FACE_TYPE. The creaseAngle field causes the edge between two polygonal faces to be smoothly shaded if the angle formed by the faces is less than the creaseAngle. If the creaseAngle is equal to or greater than the angle, the edge is faceted.
ShapeHints {
vertexOrdering UNKNOWN_ORDERING
shapeType UNKNOWN_SHAPE_TYPE
faceType CONVEX
creaseAngle 0.5
}
SpotLight. This node creates a light source which illuminates a cone along the specified direction. The dropOffRate affects the amount that light fades near the edge of the cone, and the cutOffAngle controls the angle of the cone.
SpotLight {
on TRUE
intensity 1
color 1 1 1
location 0 0 1
direction 0 0 -1
dropOffRate 0
cutOffAngle 0.785398
}
Texture2. This node specifies a texture map, a JPG file, that can be applied to the surface of objects. This is specified using the file name parameter. The image parameter enables you to embed a bitmap directly within your file, instead of referring to an external JPG file. The wrap parameters control the texture display using REPEAT or CLAMP values.
Texture2 {
filename ""
image 0 0 0
wrapS REPEAT
wrapT REPEAT
}
Texture2Transform. This node changes the size and position of textures as they are displayed on shapes.
Texture2Transform {
translation 0 0
rotation 0
scaleFactor 1 1
center 0 0
}
Transform. This node changes the size and position of shape nodes with one instruction.
Transform {
translation 0 0 0
rotation 0 0 1 0
scaleFactor 1 1 1
scaleOrientation 0 0 1 0
center 0 0 0
}
Translation. This node moves its children x, y, and z units from the origin.
Translation {
translation 0 0 0
}
Group Nodes. Group nodes, unsurprisingly, are used to combine logical sets of shape and property nodes together. The only ones you'll find yourself using are Separator, WWWAnchor and WWWInline.
Group. This node simply groups other nodes together. It does not limit the effects of property nodes like the Separator node does.
Group {
}
Separator. This node groups other nodes together, and it limits the effects of property nodes to shape nodes within the same separator. The renderCulling field enables you to control whether children of the separator will be traversed.
Separator {
renderCulling AUTO
}
Switch. This node can switch the effects of properties on or off. The whichChild field selects the index of the child you want to traverse. A value of -1 causes it not to traverse any children; -3 traverses all of them, making the switch act like a group node.
Switch {
whichChild -1
}
TransformSeparator. This node saves only the transform information before traversing its children.
TransformSeparator {
}
WWWAnchor. This node, like an HREF tag in HTML, is an anchor to some other URL. The name field specifies the URL. The description enables you to attach a description string to the anchor, which is usually displayed by the browser when the mouse pointer is over the anchor. The map field enables you to send the 3-D coordinates of the point clicked to the URL in the format "?x,y,z" to be evaluated by the URL, if you place POINT in the map value.
WWWAnchor {
name ""
description ""
map NONE
}
WWWInline. This node enables you to contain other VRML files inline within the active file. This is somewhat analogous to the way the IMG tag enables you to display images inline within HTML. You can display these files as part of the larger file by specifying a bounding box with a non-zero volume using the bboxSize field. The name filed refers to the URL of the desired VRML file.
WWWInline {
name ""
bboxSize 0 0 0
bboxCenter 0 0 0
}
Live3D VRML Enhancements. Netscape, with its Live3D VRML syntax enhancement, has divided VRML as it did with HTML--created instructions that are not part of the regular VRML instruction set, but which add functionality. Like HTML, you must decide whether you want to take advantage of these instructions because many viewers will be unable to fully use your virtual worlds if you do.
The extensions, which are not described in detail here, enable you to add simple animation and action to your worlds, to create animated textures, and to communicate with Java and JavaScript. In addition, you can embed a VRML file inline by using the EMBED SRC plug-in syntax.
If you want to learn more about Live3D extensions and view some examples, visit the Netscape Web site.
VRML 2.0 and Moving Worlds. The VRML 1.0 specification allows the creation
of sta-tic worlds. VRML 2.0 presents the opportunity to create dynamic, scripted,
interactive worlds. The VRML 2.0 specification, originally named Moving Worlds, was
released in August 1996; there are few VRML 2.0 browsers available at the time of
this writing. Because this is such a new specification, no nodes or examples from
VRML 2.0 will be used here.
Before you start to use Cold Fusion to generate VRML, you should build a few small virtual worlds to get a grasp of using VRML nodes. This example shows you how to construct a small virtual world that you will later modify for use as a Cold Fusion template.
To create a small virtual world, you should open your favorite text editor and your VRML browser. You don't have to host VRML files on a Web server to develop and test them, until you add Cold Fusion markup tags to them.
#VRML 1.0 ascii
Cube { }
Cube { height .05 width 20 depth 10 }
Sphere { }
#VRML 1.0 ascii
#
# A VRML Primer
Cube { height .05 width 20 depth 10 }
Transform {
translation 0 1.05 0
}
Sphere { }
Transform {translation 0 5.05 -5}
Cube { height 10 width 20 depth .05 }
#VRML 1.0 ascii
#
# A VRML Primer
Separator {
Cube { height .05 width 20 depth 10 }
Separator {
Transform {
translation 0 5.05 -5
}
Cube { height 10 width 20 depth .05 }
}
}
Separator {
Transform {
translation -9.9985 5.05 0
}
Cube { height 10 width .05 depth 10 }
}
Material {
diffuseColor 0 0 1
}
Separator {
Transform {
translation -9.9985 5.05 0
}
Cube { height 10 width .05 depth 10 }
}
}
Separator {
Material {
diffuseColor 1 1 0
}
Transform {
translation 0 8 -4.85
scaleFactor .15 .15 .15
}
AsciiText {
string "A2Z Books Virtual Graph"
justification CENTER
}
}
#VRML 1.0 ascii
#
# A VRML Primer
Separator {
Separator {
Material {
diffuseColor 0 0 1
}
Cube { height .05 width 20 depth 10 }
Separator {
Transform {
translation 0 5.05 -5
}
Cube { height 10 width 20 depth .05 }
}
Separator {
Transform {
translation -9.9985 5.05 0
}
Cube { height 10 width .05 depth 10 }
}
}
Separator {
Material {
diffuseColor 1 1 0
}
Transform {
translation 0 8 -4.85
scaleFactor .15 .15 .15
}
AsciiText {
string "A2Z Books Virtual Graph"
justification CENTER
}
}
Separator {
Transform {
translation 0 12 -4.85
}
Separator {
Material {
diffuseColor 1 0 0
}
Transform {
translation -8 0 0
}
WWWAnchor {
name "http://www.a2z.com/aboutgraph.cfm"
description "About this graph"
Sphere { }
}
}
Separator {
Material {
diffuseColor 1 1 0
}
Transform {
translation 1 -.25 0
scaleFactor .1 .1 .1
}
AsciiText {
string "Click the red sphere for information"
justification CENTER
}
}
}
}
This is the end of your first VRML model. There are a lot of nodes that you haven't used yet. Some of them are used and explained later, and you may experiment with the others on your own. Later you'll use your model as the basis for a Cold Fusion example.
Now you should be ready to integrate Cold Fusion with VRML output. The methods aren't very different than any other text-based output, except that instead of using HTML tags within your templates, you use VRML nodes.
As you probably recall from Chapter 27, "MIME Types," when you output other MIME Content Types you use the CFCONTENT tag. So, all of your VRML output will begin with this line:
<CFCONTENT TYPE="x-world/x-vrml">#VRML V1.0 ascii
You should place the VRML identification directly after the CFCONTENT tag, so that browsers will not have any problem with blank space at the top of the file.
Then you can place your VRML nodes and CFML tags to produce the desired results.
Your first example will generate a graph from the A2Z data source, and display it in your VRML container which you just created. Copy the VRML file into your Cold Fusion A2Z template folder, and rename it graph.cfm. Open it in your text editor and add the CFCONTENT tag at the top. Test your browser's capability to recognize the CFCONTENT tag by opening the URL:
http://www.a2z.com/cgi/dbml.exe?template=/graph.cfm
If your VRML browser or plug-in doesn't load, your browser could be overriding the MIME header sent by Cold Fusion, which would be ".wrl" with the ".cfm" extension of the actual template file. This problem usually doesn't occur with other helper applications, but occasionally it does with VRML browsers.
A Simple Looping Graph Display Engine. Once you've confirmed that your browser
is fully functional, you're ready to build dynamic VRML. For the first graph, use
a query of books in stock. The desired result is a graph of vertical bars, each of
which represents one book in the database, along the x-axis. The height of the bar
along the z-axis displays the number of copies, and the z-axis will represent the
different store locations. In addition, when a store location doesn't have any copies
of a particular book in stock, a large red exclamation point should appear. When
you move the mouse over it, it tells you which store is out of what book and enables
you to click it for more information. Figure 26.7 shows what you hope to end up with.
Figure 26.7 A view of the 3-D chart through the Netscape browser. It is displayed within a frame because Netscape can embed content inline when it is supported by a plug-in. You may be unable to do this with your browser.
At the top of graph.cfm, between the header and the first separator, type the query information you're going to use. This file is displayed below in Listing 26.7 and on the CD as GRAPH1.CFM.
<CFCONTENT TYPE="x-world/x-vrml">#VRML V1.0 ascii
<CFQUERY NAME="StockGraph" DATASOURCE="A2Z">
SELECT DISTINCTROW Books.BookID, Books.Title, Stock.*, Locations.LocationID
FROM Locations
INNER JOIN (Books INNER JOIN Stock ON Books.BookID = Stock.BookID)
ON Locations.LocationID = Stock.LocationID
ORDER BY Books.BookID, Locations.LocationID
</CFQUERY>
Separator { ...
The next step is to build an engine to display the bars. Place your cursor directly before the last closing curly bracket of the highest-level Separator node. All of your additional entries will be made here.
The sequence of the bars in the display is left to right, and front to back. You can use nested CFOUTPUT loops. The inner loop will display all of the bars from front to back, and when one iteration is completed, the outer loop moves the insertion point one column to the right.
Before you start the loops, use CFSET variables to move the starting x and y values where you want them, to the left front of the box you created earlier.
<CFSET #CurrentX# = -8> <CFSET #CurrentZ# = 4>
Now you can start the loops themselves. Using the GROUP parameter of CFOUTPUT, you can display each book as a column of bars. Listing 26.8 shows the structure of the loops.
<CFOUTPUT QUERY="StockGraph" GROUP="BookID">
<CFOUTPUT>
<CFSET #Height# = #NumInStock# / 15>
<CFSET #OffsetY# = #Height# / 2>
Separator {
Transform {
translation #CurrentX# #OffsetY# #CurrentZ#
}
Cube { height #Height# width .5 depth .5 }
}
<CFSET #CurrentZ# = #CurrentZ# - 1.5>
</CFOUTPUT>
<CFSET #CurrentZ# = 4>
<CFSET #CurrentX# = # CurrentX# + 1>
</CFOUTPUT>
The first thing the inner loop does is to set the height and offset along the y-axis for the current bar. The ratio chosen to display the height is arbitrary, but the offset is not--it divides the current height value in half and is used to place the object on the floor plane.
Next the bar is drawn using a cube node. its height is drawn from the query value, and its positioning is calculated from the starting position. Once the bar is drawn, the next location along the z-axis is assigned to the CurrentZ variable. This loop repeats once for every store location in the database.
Then, within the outer loop, the z location returns to its starting point, and the x location moves one meter to the right.
Now you can test your template. It should display the columns correctly, but without color. Also the empty spaces where there are no books in stock are not yet marked, and there are no active anchors attached to any of the bars. That's the next step.
Adding Functionality to Your Graph. First, add color to your graph. Each store
location should be given a color because you can see the book columns easier than
the location rows. This is easy!
Add a Material node within the Separator that draws the cube, before the Cube node itself:
Material {
diffuseColor #BarColor#
}
As the parameter for diffuseColor, you've typed a Cold Fusion variable. Now all you need to do is set it. Listing 26.9 shows the CFIF block which assigns one color to each store location. It should be placed directly after the inner CFOUTPUT tag.
<CFIF #LocationID# is 1>
<CFSET #BarColor# = "0 .7 .4">
<CFELSEIF #LocationID# is 2>
<CFSET #BarColor# = ".2 .6 .1">
<CFELSEIF #LocationID# is 3>
<CFSET #BarColor# = ".4 .7 0">
<CFELSEIF #LocationID# is 4>
<CFSET #BarColor# = ".2 .1 .3">
<CFELSEIF #LocationID# is 5>
<CFSET #BarColor# = "0 .6 0">
<CFELSEIF #LocationID# is 6>
<CFSET #BarColor# = ".1 .2 0">
<CFELSE>
<CFSET #BarColor# = ".8 .8 .8">
</CFIF>
This step is a little more complicated. You're going to create a set of shape nodes to display empty results, and you'll make these shapes anchors to other pages. To do this, you can add a CFIF structure to choose a path depending on whether the #NumInStock# value is zero or nonzero. If it is nonzero, you want to display nodes just as you are now; otherwise, you want to display your special nodes. Listing 26.10 shows the result.
<CFIF #NumInStock# is not 0 >
<CFIF #LocationID# is 1>
<CFSET #BarColor# = "0 .7 .4">
<CFELSEIF #LocationID# is 2>
<CFSET #BarColor# = ".2 .6 .1">
<CFELSEIF #LocationID# is 3>
<CFSET #BarColor# = ".4 .7 0">
<CFELSEIF #LocationID# is 4>
<CFSET #BarColor# = ".2 .1 .3">
<CFELSEIF #LocationID# is 5>
<CFSET #BarColor# = "0 .6 0">
<CFELSEIF #LocationID# is 6>
<CFSET #BarColor# = ".1 .2 0">
<CFELSE>
<CFSET #BarColor# = ".8 .8 .8">
</CFIF>
<CFSET #Height# = #NumInStock# / 15>
<CFSET #OffsetY# = #Height# / 2 + 0.05>
Separator {
Material {
diffuseColor #BarColor#
}
Transform {
translation #CurrentX# #OffsetY# #CurrentZ#
}
Cube { height #Height# width .5 depth .5 }
}
<CFELSE>
<CFSET #OffsetY# = 0.405>
Separator {
Material {
diffuseColor 1 0 0
}
Transform {
translation #CurrentX# #OffsetY# #CurrentZ#
}
WWWAnchor {
name "/cgi-shl/cfml.exe?template=/outofstock.cfm&ID=#BookID#"
description "#City# is out of #Title#!"
Sphere { radius .4 }
Transform {
translation 0 3.5 0
rotation 1 0 0 3.14
}
Cone { bottomRadius .4 height 7 }
}
}
</CFIF>
Your graph can now be used to quickly view and react to information. In addition, the size of this generated file (located on the CD-ROM as size.wrl) is 20.7K (kilobytes).
An optional step remains. If you want to use the graph within a frames-based interface as shown in Figure 26.7, you must modify it slightly so that it can send URL requests to another frame rather than loading them on top of it. This enhancement requires two things: a frames-syntax compliant VRML plug-in such as Live3D, and that you use the server API modules and document type mapping, explained in detail in Chapter 29, "Server Modules."
Why is this? Because you need to specify a target frame and to send parameters as URL parameters. If you want to try it, change the WWWAnchor name from:
name "/cgi-shl/cfml.exe?template=/outofstock.cfm&ID=#BookID#"
to
name "/outofstock.cfm?ID=#BookID# TARGET=details"
If you simply append the TARGET string on the end, your browser will fail to interpret it correctly, because of the ampersand between parameters. Perhaps, by the time you read this book, the problem will have been solved in the next revision of browsers.
If you have met both of these conditions, go ahead and create the following files, or copy them from the CD, to play with a frames-based interface. Listings 26.11 through 26.14 show how you can do this.
The first listing, 26.11, contains the framesets which contain all of the other templates. This would be the template you'd want to reference as the URL for this application. When you do, the header.html file will display in the frame running across the top of the browser, the graph you just created will appear in the left frame, and a placeholder HTML file will show on the right.
<HTML>
<HEAD>
<TITLE>A2Z Index</TITLE>
</HEAD>
<FRAMESET ROWS="50,*">
<FRAME NAME="header" SRC="/header.html" NORESIZE SCROLLING="OFF">
<FRAMESET COLS="70%,30%">
<FRAME NAME="graph" SRC="/graph.cfm" NORESIZE>
<FRAME NAME="details" SRC="/details.html">
</FRAMESET>
</FRAMESET>
</HTML>
Then, if you click on an anchor in the VRML graph for an out of stock item, the template shown in Listing 26.12 will execute, replacing the placeholder in the right frame.
<CFQUERY NAME="TitleInfo" DATASOURCE="A2Z">
SELECT * FROM Books
WHERE BookID = #URL.ID#
</CFQUERY>
<HTML>
<HEAD>
<TITLE>Stock Short Report</TITLE>
</HEAD>
<BODY>
<CFOUTPUT QUERY="TitleInfo">
<H2>#Title#</H2>
Other details about this book would go here!
</CFOUTPUT>
</BODY>
</HTML>
The header file in Listing 26.13 is just a convenience--you'd probably want to place a menu structure here, for example.
<HTML> <HEAD> <TITLE>A2Z Header</TITLE> </HEAD> <BODY> <H2>A2Z Books Virtual Graph Page</H2> </BODY> </HTML>
Finally, you'll need an HTML version of a "blank page," as in Listing 26.14, until a VRML anchor is clicked on.
<HTML> <HEAD> <TITLE>A2Z Details</TITLE> </HEAD> <BODY> <H2>This is the details page</H2> </BODY> </HTML>
There are plenty of improvements you can make to this simple graph. You can add AsciiText nodes to describe the axes, or a color-coded legend panel. The best modification you can make is to generalize it. It isn't too difficult to make it fully generic so that you can generate graphs of anything within your databases by using the same template and plugging in different queries using CFINCLUDE. Happy graphing!
This section is even more fun than the last! You've seen how you can generate dynamic virtual reality scenes. Now you can take that to a more realistic and interesting level. You can create a navigable, virtual interface for your Web site, and by using Cold Fusion you can make this interface dynamic and feature-driven. Then you can build a virtual bookstore that will tell the user whether it's day or night at your bookstore, allow authorized users into the back room, and display the best-selling book title.
The model provided for you to use is very simple, and somewhat clunky looking so there is plenty of room for you to add additional features. The model introduces more VRML nodes, including cameras, backgrounds, and texture mapping.
Let's start at the beginning. This model displays a landscape, in the middle of which your bookstore is located. There is a road from your bookstore to the edge of the world, which could be an anchor to a virtual town (or anything else). The model is designed for walking rather than flying. Just because you normally think of models in terms of landscapes, however, you shouldn't feel limited by this format. You can design models floating in space so that browsers fly from one point to another. For starters, though, landscapes work just fine, and everyone is familiar with them. Figure 26.8 shows your future bookstore from an aerial view.
Figure 26.8 An aerial view of the Virtual A2Z Bookstore.
The first step, after creating your file header, is to define a ground plane. Use a large one, so that you don't run out of "real estate" in the future. This example uses a cube of height .5, width 1000, and depth 1000. Next add bounding edges to all edges of this plane to provide the illusion of a skyline and landscape. Use cubes of height 20 and depth 1000. Your example should look like Listing 26.15. (Note the use of naming and reusing nodes with the DEF and USE commands.)
<CFCONTENT TYPE="x-world/x-vrml">#VRML V1.0 ascii
Separator {
################
# Ground Nodes #
################
Separator {
Material {
diffuseColor 1 1 0
}
Cube { height .5 width 1000 depth 1000 }
Separator {
Separator {
Transform {
translation -500 10 0
}
DEF SideCube Cube { height 20 width .5 depth 1000 }
}
Separator {
Transform {
translation 500 10 0
}
USE SideCube
}
Separator {
Transform {
translation 0 10 -500
}
DEF EndCube Cube { height 20 width 1000 depth .5 }
}
Separator {
Transform {
translation 0 10 500
}
USE EndCube
}
}
}
}
In Listing 26.15, some of the nodes are preceded by DEF and a name, and they are later referenced by the same name and the USE command. You can define nodes and reference them later. This reduces the overall number of polygons handled by the VRML engine, and it could be easier to write when you have similar shape nodes.
Now for a neat trick. When you look at your world in your browser, it doesn't look much like a landscape even though it's greenish-brown. You can fix this by mapping a JPG file to a surface. Map the dayedge.jpg file, which can be found on the CD, which looks vaguely like a forest skyline, to your bounding cubes using the Texture2 node:
Texture2 {
filename "dayedge.jpg"
}
This node should be inserted between your first cube, which is the ground plane, and the Separator, which follows it and brackets the other four cubes. It applies the texture to all four edges. Now when you view your world, you can see the skyline. But what about the blackness above it?
Place the following line between the very first Separator and the comment tag for Ground Nodes. This turns the sky blue and obscures the top edge of your texture.
DEF BackgroundColor Info { string " 0.3 0.8 1.0 " }
Your world looks fine so far, right? But it's pretty static. Use Cold Fusion to bring day and night to your world. This requires three steps. First, you need a mechanism to tell the world what time it is. Type the following line directly under your CFCONTENT tag.
<CFSET #CurrentHour# = #Hour(Now())#>
This uses Cold Fusion's native time functions to return the current hour as a number between zero and twenty-three, which is exactly what you need. Next you need a CFIF decision tree to act on the #CurrentHour# variable, as shown in Listing 26.16:
<CFIF #CurrentHour# GTE 7 AND #CurrentHour# LTE 19>
DEF BackgroundColor Info { string " 0.3 0.8 1.0 " }
<CFSET #Edge# = "dayedge.jpg">
<CFELSE>
DEF BackgroundImage Info { string "nightsky.gif" }
<CFSET #Edge# = "nightedge.jpg">
</CFIF>
################
# Ground Nodes #
################
Separator {
Material {
diffuseColor 1 1 0
}
Cube { height .5 width 1000 depth 1000 }
Separator {
Texture2 {
filename <CFOUTPUT>#Edge#</CFOUTPUT>
The CFIF statement sets the background color to blue in the daytime, sets a background image of stars at night, and selects the appropriate image for texture mapping. Next, you need to change the filename field of the Texture2 node to a Cold Fusion variable.
CAUTION: Be careful not to use the VRML comment tag (#) within any section of your file that is contained within CFOUTPUT tags, since # is used by Cold Fusion as a variable delimiter.
Next add the nodes listed under the Paths and Ground Features section of Listing 26.17. None of these are new to you, so you shouldn't have any problems with them. Then you're ready to work on the bookstore itself.
The bookstore also doesn't have any new nodes within it, so you can read it directly from Listing 26.17. The one item of note is the CFIF statement which enables you to limit access to a WWWAnchor node, depending upon whether the template was called with the #ClearedForEntry# parameter set to the proper value. The syntax itself is very simple, and the supporting templates are not included. In addition, you can place additional WWWAnchor nodes and dynamic display nodes. For example, you might want to display a variable text string on the inside wall. The front of the building was omitted for your viewing convenience.
Finally, as you can see at the top of Listing 26.17, there are several new nodes. They are very helpful and you'll probably use them a lot.
The first is the CollideStyle node, which is currently a proprietary Live3D extension. Collision detection, which can be set within the Live3D browser, will prevent you from walking through walls, floors, and other solid objects. This world, being the flat plane that it is, is best viewed with collision detection on.
The second and more important, is the PerspectiveCamera node. When named using the DEF convention, it places a viewpoint within your model which can be selected from a menu. If you have a complex model, you can simplify navigation by placing a PerspectiveCamera or OrthographicCamera node at every significant location. Within this world four viewpoints are defined. Using the Live3D browser, right-click the viewable area, then select the desired viewpoint from the list and you will slide directly to it.
<CFCONTENT TYPE="x-world/x-vrml">#VRML V1.0 ascii
<CFSET #CurrentHour# = #Hour(Now())#>
Separator {
###################
# Global Settings #
###################
CollideStyle {
collision TRUE
}
DEF "Start" PerspectiveCamera {
position 0 1.1 20
}
DEF "Back To Town" PerspectiveCamera {
position 0 1.1 450
orientation 0 1 0 3.14
}
DEF "A2Z_Entrance" PerspectiveCamera {
position 20 1.1 -10
orientation 0 1 0 .25
}
DEF "Office" PerspectiveCamera {
position 2 1.1 -45
orientation 0 1 0 2
}
<CFIF #CurrentHour# GTE 7 AND #CurrentHour# LTE 19>
DEF BackgroundColor Info { string " 0.3 0.8 1.0 " }
<CFSET #Edge# = "dayedge.jpg">
<CFELSE>
DEF BackgroundImage Info { string "nightsky.gif" }
<CFSET #Edge# = "nightedge.jpg">
</CFIF>
################
# Ground Nodes #
################
Separator {
Material {
diffuseColor 1 1 0
}
Cube { height .5 width 1000 depth 1000 }
Separator {
Texture2 {
filename <CFOUTPUT>#Edge#</CFOUTPUT>
}
Separator {
Transform {
translation -500 10 0
}
DEF SideCube Cube { height 20 width .5 depth 1000 }
}
Separator {
Transform {
translation 500 10 0
}
USE SideCube
}
Separator {
Transform {
translation 0 10 -500
}
DEF EndCube Cube { height 20 width 1000 depth .5 }
}
Separator {
Transform {
translation 0 10 500
}
USE EndCube
}
}
}
#############################
# Paths and Ground Features #
#############################
Separator {
Separator {
Material {
diffuseColor .8 .8 .8
}
Separator {
Transform {
translation 0 .51 249
}
Cube { height .0001 width 10 depth 520 } # Path
}
Transform {
translation 0 .51 -30
}
Cube { height .0001 width 50 depth 50 }
}
Separator {
Material {
diffuseColor .7 .5 0
}
Transform {
translation -6 .5 480
}
DEF SignPost Cube { height 1 width .1 depth .1 } # Signpost
}
WWWAnchor {
name "http://vag.vrml.org/"
description "Exit Book World and return to town"
Separator {
Material {
diffuseColor .6 .6 .6
}
Transform {
translation -6 2 480
}
DEF Sign Cube { height 2 width .1 depth 5 } # Sign
}
Separator {
Material {
diffuseColor .5 .5 1
}
Transform {
translation -5.9 2 480
rotation 0 1 0 1.57
scaleFactor .08 .08 .08
}
AsciiText {
string "Exit To Town"
justification CENTER
}
}
} # WWWAnchor
}
#################
# The Bookstore #
#################
Separator {
Separator {
Material {
diffuseColor .6 .3 0
}
Transform {
translation 0 .2 -35
}
DEF AreaCube Cube { height .7 width 30 depth 30 }
Transform {
translation 0 6 0
}
USE AreaCube
}
Separator {
Material {
diffuseColor .8 .8 .8
}
Transform {
translation 0 3 -20
}
DEF BuildingWall Cube { height 7 width 30 depth .5 }
}
Separator {
Material {
diffuseColor .8 .8 .8
}
Transform {
translation 0 3 -50
}
USE BuildingWall
}
Separator {
Material {
diffuseColor .8 .8 .8
}
Transform {
translation -14.75 3 -35
}
DEF SideBuildingWall Cube { height 7 width .5 depth 30 }
}
Separator {
Material {
diffuseColor .9 .9 .9
}
Transform {
translation 0 3 -30
scaleFactor 1 1 -.66
}
USE SideBuildingWall
}
Separator {
<CFIF #ClearedForEntry# is 1>
WWWAnchor {
name "/private.cfm Target=details"
description "Management Only! Keep Out!"
</CFIF>
Material {
diffuseColor .9 .99 .99
}
Transform {
translation -7.1 3 -39.5
scaleFactor -.48 1 1
}
USE BuildingWall
}
<CFIF #ClearedForEntry# is 1>
}
</CFIF>
Separator {
Material {
diffuseColor 0 0 1
}
Transform {
translation 0 4 -19
scaleFactor .3 .3 .3
}
AsciiText {
string "A2Z BOOKS"
justification CENTER
}
}
}
###############
# End of File #
###############
}
This simple interface is just a start; you'll need to add lots of features to make it useful for you. Remember that almost any idea which can be visualized can be expressed in VRML, and in ways that reflect the way people actually work. For example, the 3-D graph that you built earlier in this chapter can be converted into a virtual warehouse within your bookstore. Also, you might want to receive input variables, such as ClearedForEntry, through form submission rather than appending them to the URL--this example doesn't show that for the sake of simplicity.
This introduction to VRML is also just a start; there are many nodes, such as light nodes, which have not been described here. You should play with VRML the same way you probably did with HTML, but be sure to save your working files before you make any changes!
Finally, keep in mind that VRML 1.0 is just a stepping stone. The VRML specification is rapidly evolving and will soon permit many sorts of interactivity. As a Cold Fusion user, you can easily take advantage of these advances.
If you have followed the sequence of this book, you have now completed the sections that tell you how to write templates and Web applications. If you can do all of the things discussed in this and earlier chapters, you can do just about everything that can be done with HTML and its extensions. The next chapters discuss more challenging topics. Some of the topics, which you may need as you bump into the inherent limitations of HTML, cover lower-level programming rather than HTML and CFML authoring. Other topics are more similar to housekeeping topics, like using the server API modules and integration with Microsoft BackOffice.
© Copyright, Macmillan Computer Publishing. All rights reserved.