
comp.lang.vrml
FAQ Answers
5. Techniques
There are two ways to have both 2D text and graphics and a 3D VRML world on the same web page: putting the world in a frame and embedding it in a webpage.
In the first case, you use the <FRAME> tag inside the <FRAMESET> container
tag. You can find documentation at the HTML Compendium (among other
places) for the grammar and options of the <FRAME>
tag and the <FRAMESET> tag.
Example: <FRAME SRC="my.wrl" NAME="vrmlframe">
In the second case you use the <EMBED>
tag.
Example: <EMBED SRC="my.wrl" WIDTH="500" HEIGHT="280">
The <OBJECT> tag is preferred in HTML 4.0. Here's an example from Braden McDaniel which works
in MSIE 4.0 but not Netscape Navigator or Communicator:
<OBJECT DATA="foo.wrl" TYPE="model/vrml" WIDTH="320" HEIGHT="240" STYLE="width: 100%; height: 100%"> <PARAM NAME="SRC" VALUE="foo.wrl"> Alternate content goes here. </OBJECT>
Braden reports that you can use percent values for width and height, which is not valid HTML, but which both Netscape Communicator and Microsoft Internet Explorer 4.0 will accept.
A JavaScript script will do this:
<SCRIPT LANGUAGE="JavaScript">
<!-- You know why
function newWindow(width, height, world) {
window.open(world,'vrmlWindow','width='+width+',height='+height);
}
// -->
</SCRIPT>
And later on in the page:
Click <A TARGET="_self" HREF="javascript:newWindow(300,200,'foo.wrl')">here</A>
Note that the "TARGET=" field isn't necessary unless you've got another TARGET
in your HEAD container.
David Frerichs of Cosmo Software says that you should always control the size of the display window, either this way or by embedding it in a frame with a fixed height and width, so that you have better control over the speed and detail of your world. I've followed his advice in this FAQ.
In the specification for the VRML 2.0 Anchor node, there's a "parameter"
field. You use it like this:
Anchor {
url "http://vrmlworks.crispen.org/faq/"
description "Click here for the VRML FAQ"
parameter "target=newpage"
children [
Wally
The_Beaver
]
}
If you have a frame named "newpage", then the Anchor's reference (in the example, this FAQ) will come up in that frame. If you don't, then Netscape and Internet Explorer will launch a new browser window and name it "newpage". That means that if you have several Anchors all pointing to "newpage", you'll only bring up one extra window on the visitor's screen instead of littering her screen with extra windows.
There is nothing special about the name "newpage". It's not a reserved target name in HTML. It was chosen because it's not likely to be the name of a frame. If you use the name of an existing frame on your page, VRML browsers that support this feature will cause the text to load in the frame you name. This is very useful for web pages that consist of both text and VRML and allows you to change the text by clicking on an object in the VRML world.
Note that VRML browsers aren't required by the spec to support "target=" in the parameter
field, but since it's listed as an example in the spec, and since it's so useful, all VRML browsers I know of do
support it.
There is one way that's absolutely independent of the VRML browser that visits your world:
NavigationInfo {
type [ "NONE" ]
...
}
In this case you will need to provide some VRML objects (see the answer to another question) that your visitor can use to navigate through the world.
Cosmo Software and Intervista support the following extra parameters in the EMBED tag:
WorldView:
<EMBED SRC="my.wrl" WIDTH="500" HEIGHT="280" VRML_DASHBOARD="FALSE">
Cosmo Player:
<EMBED SRC="my.wrl" WIDTH="500" HEIGHT="280" VRML-DASHBOARD="FALSE">
Murat Aktihanoglu reports that if you use the <OBJECT> tag, as in the answer to a
previous FAQ, adding
<PARAM NAME="VRML-DASHBOARD" VALUE="FALSE">
will work. Note that using any browser-specific parameter is generally a bad idea unless you can guararantee that only the users of a particular browser will ever visit your VRML world. You gain the ability to let the visitor navigate without seeing the dashboard, and without your doing the work of providing alternate navigation controls, but you lose universality and can alienate the visitors to your world who have the "wrong" browser.
This is sometimes called a heads-up display or HUD and can contain controls, displays or both.
Here are two examples you can download: a simple HUD by Chris Fouts [download] and a slightly more elaborate HUD by Flounder [download]. Chris's is elaborately commented and I've modified Flounder's example, which originally displayed the numbers rounded off, because different VRML browsers generate string values in JavaScript differently, making the results of rounding difficult to guarantee across platforms. The answer to another FAQ shows some controls in a HUD.
If you're using Java, the best tutorial is Justin
Couch's tutorial here at the VRMLworks. If you're using ECMAScript, look at this
example [download] which uses createVrmlFromString() -- click on the cube
to add the children or this example [download],
which uses createVrmlFromURL() -- approach the yellow cube and it turns into a red sphere.
Although it's possible to ROUTE a sensor's isActive eventOut to a Viewpoint's set_bind
as we do in this example [download VRML
and texture] (approach the disc and be taken on a tour around the sacred head of "Bob"),
pull back away from the disc as it's moving to see why this is a bad idea. The jump from the disk (if the browser
lets you do it) is disorienting. In other applications, if the visitor wanders too far away from the sensor that's
causing the viewpoint to be bound, he could jump back to the original viewpoint. It's far better to ROUTE
the sensor's isActive eventOut through a diode Script. There's an example of a diode Script in the answer to another FAQ.
It's called a diode because it only passes TRUE values. By putting the diode between the sensor
and the viewpoint, you keep the viewpoint bound even when the visitor moves out of the sensor's range, and the
user doesn't pop to a different place in the scene unexpectedly.
The answer to the previous FAQ has an example of taking the visitor for a ride. The duck
[download (tar.gz)] at the VRML 98 website has
an even more elaborate ride (wait till everything loads, then click on the duck to take the ride). Basically, you
bind the viewpoint to a viewpoint that's the child of an object that you animate. Notice that after the duck gets
to the castle, a ProximitySensor by the castle binds the viewpoint (through a diode) so that the duck
can fly away and leave the visitor behind without snapping the visitor back to the mountain top.
There's a page at the VRMLworks that
discusses this question in detail and points to some excellent tutorials and articles. How fast is fast enough?
Here's what Rikk Carey said on www-vrml not long ago:
| Frames per second | Effect |
|---|---|
|
20-60 |
Perfect illusion, fully 3D experience, dream-like clarity |
|
12-20 |
Reasonable illusion of 3D, good enough |
|
8-12 |
Operable 3D interface, subconscious frustration, boat-like navigation, ok for design/expert tool |
|
1-8 |
Unusable 3D interface, poor navigation, conscious frustration, in need of different UI techniques (e.g. Myst) |
Ligos has a free VRML Detector that will detect VRML browsers
in Netscape Navigator/Communicator and Microsoft Internet Explorer and will show them the appropriate content.
John Fairley of Platinum Technology has written another
VRML Detector with the help of some members of www-vrml.
Tom Kaye of SGI's Huntsville office has developed a camera tracking PROTO.
David McLure has written an article on this that includes some sample implementations. The DIS-Java-VRML Working Group has developed some applications in Java that communicate via sockets and solve some of the Java security problems.
Yes, through a CoordinateInterpolator. Here's an example of a dolphin
[download] in which each of the points morphs. I turned the famous dolphins
[download] from the Avalon Repository into one morphing dolphin.
Here are two answers. The first is for people who want to understand the "magic numbers". The first
three numbers in the orientation field are a vector that describes which way up is. But wait a minute;
three numbers describe a point; how can they describe a vector? Easy. The other point in the vector is the origin
(0,0,0). The vector is nominally a unit vector, but I don't know of any VRML browser that complains if the length
of the vector isn't 1. The fourth number is the rotation about that vector, using the right-hand rule (point your
right thumb along the line from the origin to the point you described with the first three numbers, and the direction
your fingers curl is a positive angle).
The second answer is for people who don't remember their high school math. Instead of figuring out what the numbers mean, use Stephen Chenney's orient (C source code and Win95 executable).
Some object modelers and scene modelers will let you fly your camera to a point in the scene, orient your view, and then set that as a Viewpoint node.
Here are two examples: one that uses addChildren
[download] and one that uses removeChildren
[download]. In both examples, click on the yellow cube.
This is easier to demonstrate than to explain. Here's an example [download].
The quickest and probably the best way is to use a Switch node and a Script. In this
example [download], click
on the yellow cube and it disappears. You can also:
but all those methods put an unnecessary load on the browser, since the browser will still have to do the computations
to render the object (or at least determine if it's visible). You can also use removeChildren, but
that would be overkill, especially if you ever want to make the object reappear. Finally, an LOD is also a kind
of sensor, and you could make the object disappear when you approach it by having an empty Group node
in the range field.
Slightly different code in the script in our example could make an object appear or make one object disappear and another appear.
The second example in a previous answer shows the user's position. Note that the user's orientation
is also available from the ProximitySensor and can be displayed the same way.
Yup. That one confused me too at first. The solid field tells the browser that your object is solid
and that it only needs to render one face. That's the default. Unless you have objects without thickness and need
to show both sides, leave it alone.
Open Worlds has a C++ toolkit that allows you to develop a stand-alone application that can view and manipulate VRML worlds. [I'd be glad to note the names of other companies who are working on similar toolkits.] A number of VRML browsers, among them Cosmo Player 2.1, WorldView 2.1, and Blaxxun CCPro 3.x, can use Microsoft's COM to interface between the VRML browsers and applications.
Justin Couch has a set of classes called JVerge that replicate the VRML 97 nodes as individual Java classes.
Intervista has a package WorldView for Developers that lets you develop applications in C++, Visual Basic, Java, and Macromedia Director Xtras and use WorldView as an embedded VRML application.
Open Inventor from Silicon Graphics can use their own nodes, VRML 1 nodes, and (this is relatively new) VRML 97 nodes.
First of all, think about security. You're asking the visitors to your world to run an application on their machines when they don't know you from Adam. You need to give the visitor some assurance that your Script won't format their disks or swipe their collection of dirty pictures. The surest way to do that in Netscape Navigator is to use Java, which runs in Netscape's security "sandbox". But you needn't code in Java. There's a list at developer.com of [x]-to-Java cross compilers and, yes, Ada, Visual Basic and even COBOL are on that list.
By attaching sensors to objects. There are four kinds of sensors you can use for manipulating objects: TouchSensor,
PlaneSensor, CylinderSensor, and SphereSensor. We've used a TouchSensor
in the example for an answer to a previous question. This
example [download VRML and texture] uses a PlaneSensor
to control speed forwards and backwards, a CylinderSensor for a steering wheel, and a SphereSensor
to manipulate one of the objects. It's based on Chris Fouts's HUD from the answer to a previous question.
Vladimir Bulatov supplied the solution to a serious problem in the original version and suggested a way to make
it look more object oriented.
Note that this example also shows a way to integrate variables over time. In this case, we integrate the velocity to produce a position.
The best way is to use createVrmlFromURL in a Script and trigger the Script when
you want the object to load. This also works to prevent downloads of invisible levels of detail, since nothing
in the spec requires the browser to load an invisible LOD or avoid loading an invisible LOD. This example shows
a LOD that doesn't load until the user gets close enough.
[download].
Use the Collision node, put it around everything you don't want your avatar to collide with, and
set the collide field FALSE. There are some objects in your scene that it's impossible
for the avatar to collide with, like ornaments on the tops of buildings, and it might be worthwhile experimenting
in a few browsers to see if wrapping those objects in a Collision node would speed up your frame rate.
Short answer: you can't. Longer answer: you need to write either a Script or an EAI applet that computes collisions for the objects you want to have collide with one another. You can often work around this limitation of VRML by pre-programming the movement of objects or by filtering object movements through a Script that applies limits to simulate collisions. A paper at the 1997 VRML Symposium: "V-COLLIDE: Accelerated Collision Detection for VRML" by Thomas C. Hudson et al (pdf) talked about a program for detecting collisions between objects.
No VRML browser I know of will let you print the screen from your web browser's Print button. But there's a workaround. Many platforms give you the capability of doing a screen capture (on PCs Alt-Print Screen will capture the current window). You can then open up a 2D bitmap graphics program such as Photoshop (Mac and PC), Paint Shop Pro (PC), or xv (Unix) and either paste the image onto another blank image or paste it as a new image. Unix systems may automatically save the screen capture in a file. The better 2D bitmap graphics programs will then let you edit and print the image or convert it to a format like EPS which can be printed.
Tom Kaye of SGI's Huntsville office has developed a PROTO for generating motion trails [download].
Some browsers offer this as a viewing option, but you can do it in any browser. DEF your Coordinate
node from your IndexedFaceSet and then USE it in an IndexedLineSet node.
You will need to generate the coordIndex field for the IndexedLineSet, but this can be
easily done by copying the field from the IndexedFaceSet and trimming out duplicate lines. Put the
two nodes in branches of a Switch node and toggle the switch from a script.
Dennis McKenzie said not long ago that he tries to keep his VRML files down to 2K polygons or less. David Frerichs uses a stricter heuristic that needs to be more widely known:
| Download Speed | Type | Maximum Size |
|---|---|---|
|
28.8Kb/Sec |
NanoVRML |
12KB |
|
56Kb/Sec, ISDN |
Vignette |
200KB |
|
CD-ROM, T1 |
Immersive |
1MB+ |
The critical parameter is how fast the average visitor's modem is. Right now that average is around 28.8K.
First, let's do some figuring. If the average visitor to your world has an 800 x 600 screen, then the difference between a point with coordinates 1000 0 0 and 1001 0 0 is a little less than one pixel. That would seem to mean that 3 digits of precision is enough for any virtual world, but that doesn't take the user's viewpoint into account.
Suppose you have a slide on a virtual microscope. A difference between 4.0000001 and 4 might be enormous. On the other hand, if you have a temple roof with a carving that will never get larger than 2 degrees in the visitor's field of view, you can probably cut both precision and polygons without harm.
The true answer is to figure out for each object, and perhaps even each part of each object (say, an automatic teller machine on a long wall that the visitor might approach and use), how big that object will ever be in the visitor's field of view, and then figure out how many polygons and how much precision you need.
One more point: in the real world we're used to objects revealing themselves in more and more detail as we approach them. That's an important part of how we perceive distance. By using LODs selectively, we can mimic that experience in our virtual worlds and make them more realistic.
Many people have noticed that the example of a guided tour in Hartman & Wernecke's book doesn't work the way it should. Jed has a thoroughly commented replacement for the example in the book.
This example [download] shows a stick of dynamite with a sizzling fuse using PixelTextures and a Script. There's a utility at the VRMLworks that can turn an ordinary GIF or JPEG image into a PixelTexture.
This is a known deficiency in the spec. The following example from Greg Seidman shows a way to get around that limitation:
PROTO Foo [ exposedField SFBool enabled TRUE ] {
DEF CONTROL Script {
field SFNode enabled ENABLED PointLight { on IS enabled }
eventIn SFBool set_enabled
url [ "vrmlscript:
function set_enabled(val, time) {
//do something based on the new value
}
"]
}
ROUTE ENABLED.on_changed TO CONTROL.set_enabled
}
Greg notes that it's sometimes necessary to set directOutput TRUE. In my own work, I've often discovered
that an eventIn or an eventOut is all that's necessary, and have avoided exposedFields in PROTOs.
You could sit down with your text editor and type in points, but that's absurd. Most VRML modelers have a tool that does that. But if you don't have a VRML modeler or if you find that modeler's ElevationGrid tool hard to use, there are other ways to make an ElevationGrid.
One way is to use a regular 2D bitmap graphics program like Photoshop or Paint Shop Pro and create a greyscale
terrain map. The lighter the color, the higher the elevation. Then save it as a PGM or greyscale PNM file. Most
2D bitmap graphics programs will let you save in one of those formats, and if yours doesn't, you can almost certainly
save as a greyscale (256-grey values) GIF file and use "giftopnm", included in the free
pnmtopix utility from the VRMLworks, to turn it into
a greyscale PNM. Then take your PGM or PNM file and use a free utility from the VRMLworks called pbm2wrl
to convert it to an ElevationGrid.
Another way to make an ElevationGrid is by taking real elevation data from the U.S. Geological Survey or other sources and using a free utility from the VRMLworks called dem2wrl to convert it to an ElevationGrid. DEMs can be huge, so unless the level of detail in the DEM is vital to your application, make sure you cull that data; 10-to-1 reduction is average for what I've done.
Still another way is to take advantage of the work people in the raytracing community have done on terrain generation tools. Jörn Seger has created a list of raytracing utilities, many of them free. I've used both Silver Software's Terrain Forge and Tapio Vocadlo's Leveler. In both cases you export a 2D greyscale map (in Terrain Forge, a Windows bitmap and in Leveler a targa file -- though Tapio and I are working on a plugin so that Leveler will directly export VRML ElevationGrids). Then you use pbm2wrl to convert it to an ElevationGrid.
![]()
Did I leave something out on one of these questions that you need to know? Let me know.
-- Bob Crispen
-- Thursday, June 11, 1998