Just when you thought you knew them all, along comes the official VRML standard !!!. This one is called VRML 2.0 or Moving Worlds and it's simply amazing. VRML 1.0, for all its ingenuity was at its heart a static language. The dynamic Moving Worlds, on the other hand is VRML 1.0 on steroids !!! This Virtual Reality Modeling Language standard has no scripting language ( programming language ) of its own, instead it relies entirely on Java, Sun's platform independent, Internet oriented programming language. This means that before you can attempt to master VRML 2.0, you must learn Java first. ( Check out our tutorial on the subject !!) To learn Java, you have to know C++ and to understand C++, you first have to learn C. In other words, although VRML is the hottest thing to happen to the WWW since the introduction of HTML, it isn't as easy as the latter. Even after learning these languages, you'll still have a tough time with VRML 2.0 unless you're comfortable with VRML 1.0 (yes, we have a tutorial on this language... ) or Active VRML ( ....and on this one too !!..). We reccomend you first learn ( and forget some off ) VRML 1.0, then SONY'S extensions to VRML 1.0 and then try to learn either Moving Worlds or Active VRML.
This tutorial focuses on Moving Worlds (VRML 2.0) using SONY's browser, CyberPassage. It's very surprising that a company previously known only for it's home appliances has come out with the worlds first VRML 2.0 browser, beating more experienced companies to the draw. This move by SONY strengthens our convictions that VRML will make a greater impact on the World Wide Web than HTML made when it was first released.
Silicon Graphics have said that they too will soon be releasing their own VRML2.0 browser. Have no fear, we'll cover it as soon as we get our paws on it. And how could we forget Microsoft ? It's come out with a whole suite of Active products, one of which is its own implementation of the VRML standard, Active VRML.
Isn't all of this a little confusing ? I mean, these two different versions, one from Silicon Graphics and the other from Microsoft, are totally incompatible with each other. It would have been much better if the guys who brew up these standards had worked a little harder at making our lives easier. Maybe if they were forced to use their own products, it would help change their demeanor.
It's up to you to choose which one you will adopt as your language of choice. We're just here to help you decide, not make the decisions for you, after all, we can't be seen taking sides, can we ? Ofcourse, if one of the parties decided to ( ahem !! ) hand over some of the green stuff, our tutorials might suddenly change their tone ....
To use VRML productively, you will require a pretty fast machine. We're using a Pentium 66, with 16 MB RAM, a large hard disk, a display adapter set to 256 colors and Windows95. These are the minimum requirements for running VRML programs at anything approaching normal speed ( Most programs run okay, but we could use a little more juice....).
To get SONY's CyberPassage browser ( Alpha ), go to their site and simply download it from there. Copy it into a separate subdirectory and run the file cp2a1xs.exe. The program automatically installs itself onto your machine.
Lets start our journey from the world of the static to the dynamic moving universe that VRML makes possible with this simple program.STATUTORY WARNING: Reading this could be injurious to your health.
At times, while explaining the workings of a program to you, we will be technically wrong. This has been done on purpose, so don't keep writing to us and pointing out our mistakes!!! (Typo's are an exception !!) We're doing this for your own good. So that you can grasp a difficult concept better and become a more accomplished programmer.
And don't worry !! before the tutorial is over, we'll correct all our errors and put you back on track. Scouts honor !!!
b1.wrl
#VRML V2.0 utf8
WorldInfo
{
  title "BackgroundTexture"
  info  "evening.jpg"
}
In a new subdirectory, create a file called b1.wrl. After having created the file, load on CyberPassage (SONY's new VRML browser), go to File Open and load the file b1.wrl ( Program number 1).
What you will see is the image, evening.jpg. A  file which is present on your hard disk in the 'birds' subdirectory and which will not be supplied by us.  Lets take a closer look at this program, which starts off with a line beginning with a hash (#). This line is a comment and it declares to all that this is a VRML 2.0 program. People in different parts of the world speak different languages and utf8  changes according to the language the program is written in. The word WorldInfo is not gleaned from a indigestion induced nightmare, it's one of the many reserved words that VRML 2.0 understands. WorldInfo {} can be thought of as a structure having, as of now,  two members ( fields ) , title   and info . In this program, title is equal to BackgroundTexture, and info is equal to the name of the file to be displayed, i.e. evening.jpg. By now, you'll have realized that the WorldInfo Node or Object, which ever you want to call it, furnishes general information to the browser. In WorldInfo, title is a  reserved word, but whatever appears in double inverted commas can vary.  Here the words "Background Texture", informs the browser that the image evening.jpg is meant to be the background and must be handled as such.
Use the arrows to move around and you'll realize that, miracle of miracles !!, the background is indeed evening.jpg. The SONY browser can not only read a .jpg files, but also .gif files. The next program proves this assertion. 
 
b2.wrl
#VRML V2.0 utf8
WorldInfo
{
        title "BackgroundTexture"
        info  "a1.gif"
}
b3.wrl
#VRML V2.0 utf8
WorldInfo
{
        title "Title"
        info  "Bird"
}
In this  program, you change the title to "Title " (with a capital T),and info to "Bird ". The title of the window, which was previously CyberPassage, changes to Bird. You can also change the title to "YAWN ". 
The program will not error, it'll just work a little slower !!!
b4.wrl
#VRML V2.0 utf8
WorldInfo
{
        title "ViewerSpeed"
        info  "0.1"
}
WorldInfo
{
        title "BackgroundTexture"
        info  "evening.jpg"
}
b5.wrl
#VRML V2.0 utf8
WorldInfo
{
        title "ViewerSpeed"
        info  "0.1"
}
Background
{
        skyColor 0.3 0.7 0.9
        negZ "a1.gif"
}
In program no 5, instead of having the default background, we are going to add our own, colored backdrop, with a .gif image in the foreground. By changing the values in skyColor, you can alter the background color.
It's time to step into the twilight zone because now we'll dabble in some Java programming.
b55.wrl
#VRML V2.0 utf8
Script
{
            url "b55.class"
            scriptType "javabc"
}
b55.java
import vrml.*;
import java.io.*;
public class b55 extends Script
{       DataOutputStream d;
        public b55()
        {       try
                {      FileOutputStream f = new FileOutputStream("b55.txt");
                        BufferedOutputStream b = new BufferedOutputStream(f,128);
                        d = new DataOutputStream(b);
                }
                catch ( Exception e ) {}
                abc("In Constructor\r\n");
                String a1 = Browser.getName();
                String a2 = Browser.getVersion();
                String a3 = Browser.getWorldURL();
                float f1 = Browser.getCurrentSpeed();
                float f2 = Browser.getCurrentFrameRate();
                String t[];t=new String[1];
		    t[0]="b1.wrl";
		    Browser.loadWorld(t);
                abc(a1);abc("\r\n");
                abc(a2);abc("\r\n");
                abc(a3);abc("\r\n");
        }
        public void abc( String a)
        {
                try
                {       d.writeChars(a);
                        d.flush();
                } catch ( Exception e ) {}
        }
}
What we have done here is create a .wrl file with the word Script instead of WorldInfo. Like WorldInfo, Script is also an object or a node, whatever you want to call it ( The official name is Node ), understood by VRML 2.0. This object has two fields, url and scriptType. The url in this program is 'b55.class', which is a Java compiled program, and the script type is 'javabc' which notifies the browser that the related script is in Java. This scripting language is specified by the programmer and can be changed by you. Although it's possible to use C/C++ as a scripting language, to try and do so would quite irrevocably prove your insanity .
At this point in time, we'll assume that everyone is as lost as we were when we were trying to decipher this program and so we'll go through this section real slooww.
All that the Java program ( b55.class ) contains is a function called abc that writes a specified string to a specific file onto a specified disk ( Notice how Specific you have to get !!). Now because the file itself is named b55.java, we'll name the text file it will create, b55.txt. ( Creativity is NOT our middle name !! ). Even if you are not too confident and clear about try and catch and FileOutputStream, Reellaxx !!, we'll get back to it later. Remember that each time you want to write to the disk, you'll need to call the function abc. If you run this program, you'll see b1.wrl appear on the screen and the file b55.txt, containing the words, 'in constructor', will be created. This means that using VRML 2.0 in conjunction with Java, we can call or create an object (class b55). After public class b55, we type in extends Script. This means that b55.class now contains all the code which is held in the class Script.
In this program we've also typed in import vrml.*; . We've done this because you're supposed to have a path set to the Java classes on VRML 2.0, the main thing that helps VRML interact with Java. If, horror of horrors !!!, you haven't done so, your programs will not work. To make your programs work, follow the steps detailed below.
OR
Set the CLASSPATH variable along with the defaults ,to this zip file (name). If you are doing it in this way, the import statement will also change.
The .zip file contains the Java classes on VRML 2. Script.class is one of them. Script has a large number of important functions which we can now use. But more importantly, we have a class called Browser which has a large number of static functions like getName, getVersion, getWorldUrl. If you've read our Java tutorial , you'll know that you can use static functions without creating any objects. The functions do many useful things, e.g. getName will give you the name of the browser currently being used (CyberPassage), getWorldURL will give you the name of the current wrl file, and so on.
The class Browser , contains a function called LoadWorld. In this program we are giving it an array of strings. The first element of this array is initialized to b1.wrl. When you load on CyberPassage, the output of b1.wrl will be displayed on your monitor. This means that Browser.LoadWorld actually worked !! Now the question that you are probably going to ask us ( If your brain weighs more than Captain Picards hair )is, why are we giving LoadWorld() an array of strings and not just one string ? We have done this because if you make a mistake in typing in the program name (e.g. b.wrl instead of b1.wrl ) and there isn't any file present with that name, then the browser will automatically go to the next string in the array and follow it to its end. This is not as useless a feature as it first seems, in fact it can be used to make your programs more user friendly. Picture this scenario. Your web page has a link to another site somewhere in Dullsville. Now because of an acute shortage of creativity, the owner of that site decides to shift to India, the home of artistic expression (Okay, I'm biased, so SUE me !!). His problem is that everyones links to his site will expire. So, what he can do is change the strings in the array so that, if the first link fails, the browser, without the users knowledge, automatically goes to his new address.
Here's a recap of all that we've done so far.
In our b55.java file we have said public class b55 extends Script, which means that an object (e.g. b55 ) that looks like Script (because it is extended or derived from Script) will be created. When an object is created, the constructor automatically gets called. So the b55() constructor in the Java file will be called and it will execute the statements present in that function.
We are not commenting on the decisions made by the committee that set the standards, but the facts are that VRML 2.0 decided against having a specialized scripting language and instead decided to use Java for all its programming needs. Now the problem is, that when Java was written , it was not meant to interact with VRML 2.0, which hadn't even been created by then. Since they could not revise Java, they decided to do the next best thing, create a set of classes tailored for VRML 2.0, so that it could successfully interact with Java. Java VRML programming is a lot like Java Odbc programming. You receive a set of classes which are used in programs by you. In the same way new classes have been released by SONY, that help Java interact with VRML 2.0. Java itself has not been modified.
b6.wrl
#VRML V2.0 utf8
WorldInfo
{       title "BackgroundTexture"
        info  "evening.jpg"
}
DEF t1 TimeSensor
{       discrete    TRUE
        loop        TRUE
        enabled     TRUE
        cycleInterval  0.08
}    
DEF s1 Script
{
        url "b6.class"
        scriptType "javabc"
        eventIn  SFTime  fly
}
ROUTE  t1.time TO s1.fly
b6.java
import vrml.*;
import java.io.*;
public class b6 extends Script
{       DataOutputStream d;
        public b6()
        {       try
                {       FileOutputStream f = new FileOutputStream("b6.txt");
                        BufferedOutputStream b = new BufferedOutputStream(f,128);
                        d = new DataOutputStream(b);
                }
                catch ( Exception e ) {}
                abc("In Constructor\r\n");
        }
        public void fly(SFTime t, SFTime now)
        {       abc("In Fly\r\n");
        }
        public void abc( String a)
        {       try
                {       d.writeChars(a);
                        d.flush();
                } catch ( Exception e ) {}
        }
}
Program 6, is a bit on the lengthy side, but don't be discouraged by that, soon you too will be fabricating programs even larger and more cryptic than this one !!! This program doesn't do anything remarkable, but it does help us explain the concepts to you. In WorldInfo we have a background picture named evening.jpg. We also have a variable s1, which stands for the Script. DEF means that s1 looks like and represents a certain script (This is similar to the original use of DEF in version 1.0 ). So whenever you see s1, you know that we are taking about a particular script.
The third line of the program contains the word eventIn, which implies that b6, or an object that looks like Script, will receive an event named fly. This means that there should be a function in your Java program or in class b6.class called fly. Remember that events in VRML 2.0 always have data types associated with them ( This is important so keep it in mind ), which is not the case in Java. SFTime is .class file present in the VRML subdirectory and TimeSensor is a node that VRML understands.
One of the most useful things about VRML 2.0 is the number of sensors it has. A sensor is a piece of code that perceives a certain event, e.g. a time sensor senses time etc. We have named the time sensor t1 in our program and stated that it has four members. i.e. Time Sensor has 4 properties called, to use the official terminology, fields. Right now, we think it's best that you remain ignorant of the true meaning of discrete.We are also assuming that the loop marked as true is of a Boolean data type (which means that it keeps on going continuously). When enabled is true, it means that when the .wrl file is loaded, the time sensor should start generating events. The next word, cycleInterval, asks at what intervals should these events be generated.
If you had stopped here, the time sensor will keep churning out time events. These events should be received by somebody. So you need a construct ( called ROUTE ) to take the Time Event generated by t1 and call a certain Java function. ROUTE first asks for the identity of the event generator, i.e. t1.time. t1 is a time sensor and it constantly throws up time events. What we've typed in is....
ROUTE t1.time to s1.fly
This means that the time events generated by t1.time will be 'routed' to s1.fly. s1 stands for Script and because we have said url "b6.class" in the Script, s1 stands for b6.class. When we say s1.fly, it refers to the function fly in b6.class .
By now you should have realized that fly takes two parameters, both of which happen to be time and that abc will keep displaying 'In fly' on the screen every time it's called. If you run the program for a minute or two and then display the contents of b6.txt, your screen will fill up with reams of 'in fly' . I bet you're wondering what use you'll ever have for a function that keeps screaming for a bug ? You go figure that one out yourself .
You've probably noticed that things are getting a little confusing now and that's because, as we've mentioned earlier, Java does not understand VRML 2.0.
b7.wrl
#VRML V2.0 utf8
WorldInfo
{       title "BackgroundTexture"
        info  "evening.jpg"
}
DEF t1 TimeSensor
{       discrete    TRUE
        loop        TRUE
        enabled     FALSE
        cycleInterval       0.08
}    
DEF s1 Script
{       url "b7.class"
        scriptType "javabc"
        eventIn  SFTime  fly
        eventOut SFBool  e1
}
ROUTE  t1.time TO s1.fly
ROUTE  s1.e1 TO t1.set_enabled
b7.java
import vrml.*;
import java.io.*;
public class b7 extends Script
{       SFBool e = (SFBool) getEventOut("e1");
        DataOutputStream d;
        public b7()
        {       try
                {       FileOutputStream f = new FileOutputStream("b7.txt");
                        BufferedOutputStream b = new BufferedOutputStream(f,128);
                        d = new DataOutputStream(b);
                }
                catch ( Exception e ) {}
                e.setValue(true);
                abc("In Constructor\r\n");
        }
        public void fly(SFTime t, SFTime now)
        {       abc("In Fly\r\n");
        }
        public void abc( String a)
        {       try
                {       d.writeChars(a);
                        d.flush();
                } catch ( Exception e ) {}
        }
}
Now lets do another example where instead of just receiving events, a Java program will generate and receive events. In this program, the time sensor is not enabled ( enabled FALSE ) and so it is impossible for it to generate events. Now in the Script, we use e1 in the same way as we used fly in the previous program. The data type of e1 is SFBool (Boolean) and it represents eventOut ( fly was the opposite, it was eventIn ). eventOut means that the Java program will figure out how to generate the event e1.
The second ROUTE statement has s1.e1, the event generator and this event is to be directed to t1 which is the time sensor. What this means is that when the script s1 generates the event e1, it gets ROUTEd to the time sensor. In the time sensor we enable the timer by typing in t1.set_enabled.
Now let go through the parts of the program written in Java one step at a time. We created a public variable in our Java program called e which looks like SFBool, a data type which is similar to SFTime . e will contain the value returned by getEventOut. We have typed getEventOut with "e1" as the event name ( because in the wrl file , the Script has the event (e1)). So what we are trying to say is that e will stand for the event e1, in our Java program.
In the constructor we simply type in e.setValue with the value true. In other words, when we say e.setValue, we are actually triggering an event called e1 with the value true. Also you will realize that e1 is an SFBool ( i.e. its value should either be true or false ). So setValue activates the event e1 with the value true which is then routed to t1 , a time sensor with a field called enabled .
So set_enabled will simply take the field called enabled and set it to a value given by the event. That value, given by setValue , is true. By doing this, enabled becomes true and because it becomes true, the timer now starts.
So to reiterate, eventIn or eventOut specify whether an event will be generated by the Java program or received by a Java program. The event always has a data type which could either be a bool or time or another valid datatype.
The following explanation should clear your doubts.....
A TimeSensor has a large no. of fields, one of which is enabled ( data type = Boolean). The Java program would like to change the field value of this node. So in the Java program you need a handle to eventOut (e.g. e1 ). Once we have the handle, we can use a function called setValue which will generate an event with a certain value. Then we can route it to the node and on to the field. If we want to change the value we should use set_, or we could do the reverse. If we did it the other way round we have to use getValue in our program and get the current value of the field. So now we can rewrite the above mentioned program so that it runs for 10 seconds and then stops. To do this we will have to set setValue to FALSE. When setValue is set to FALSE, the timer will stop automatically.
In VRML 2.0 programming you need to have an Object or a Node named Script which is your interface between VRML and Java. If you want to access any node of VRML2.0, you have to make it a part of your Script. The construct ROUTE decides where the generated events should go. Both Java and VRML 2.0 can generate events and it is ROUTE which decides whose events should go where and when they should cross the border between Java and VRML. So at its heart, ROUTE is simply a courier.
In the same way, our Java programs also have to interact with VRML. They must be informed when certain events occur across the line of control in VRML land. ROUTE carries this information across and gives it to Java and depending on this intelligence the Java programs alter their behaviour.
This is the tutorial that we have compiled and will keep on updating as and when we keep cracking the code. Have any suggestions, comments, ideas, cracked code, feed back ? Feel free to Get in touch with us.