Now lets look at prog. 14

b14.wrl

#VRML V2.0 utf8
DEF TT Transform
{       children
        [       Transform
                {       children
                        [       DEF SS  Shape
                                {       appearance Appearance
                                        {       material Material { }
                                        }
                                        geometry Cube {}
                                },
                        ]
                }
        ]
}
DEF s1 Script
{       	eventIn SFTime  fly
       	url  "b14.class"
        	scriptType	"javabc"
        	field SFNode ch1Shape USE SS 
}

DEF t1 TimeSensor
{       	discrete	TRUE
	loop	TRUE
        	enabled TRUE
	cycleInterval	0.2
}

ROUTE t1.time TO s1.fly
b14.java
import vrml.*;
import java.io.*;
public class b14 extends Script
{       Shape c;
        int i;
        SFNode cn = (SFNode)getField("ch1Shape");
        DataOutputStream d;
        public b14()
        {       try
                {       FileOutputStream f = new FileOutputStream("b14.txt");
                        BufferedOutputStream b = new BufferedOutputStream(f,128);
                        d = new DataOutputStream(b);
                }
                catch ( Exception e ) {}
                abc("In Constructor\r\n");
                c = (Shape)cn.getValue();
        }
        public void fly(SFTime t, SFTime now)
        {       i++;
                float f[] = new float[3];
                f[0]=i/10f;
                f[1]=i/10f;
                f[2]=i/100f;
                c.setColor(c.diffuse,f);
                if ( i == 100)
                        i = 0;
                abc("aaa\r\n");
        }
        public void abc( String a)
        {       try
                {       d.writeChars(a);
                        d.flush();
                } catch ( Exception e ) {}
        }
}

Now in this program, we have multiple DEF's and using these DEF statements we've given Transform a new name. We've also re-christened the Shape present within Transform. We've taken this action because we want to refer to it in the Script.

To refer to the Shape in the Script, we've created a field called ch1Shape ( the data type is SFNode ), which stands for the Shape ( USE SS ). This Shape has two fields, the geometry ( Cube ) and the appearance (which has material) . So in this case, ch1Shape stands for a Cube, constructed of certain specified materials.

What we are trying to say here is that we will be using DEF, whenever we want a field in the script. This means that now, theoretically, we can refer to the specified field in our Java program.

To refer to the field ch1Shape in the Java program, we use the function getField. Now because getField requires a field name, we supply it with the field ch1Shape, garnished with double inverted commas. The field chlShape will now return an SFNode to the variable cn. SFNode is a data type that represents a Node. The Node can stand for a Transform, a Shape, or even Material. So in the constructor, we use the getValue function of SFNode ( we say cn.getValues) to return a specific Node. In this case the getValue will return a Shape, because we have said that chlShape, in the Script sl, is a Shape. If we had not specified this, it would have not returned a Shape ( obviously !! ).

If you just accepted the above statement, you need a refresher course in C/C++. What we are really doing here is Casting. If you don't cast this variable the compiler starts to throw rude error messages at you. This is because a getValue can return a lot of stuff besides a Shape.

So now, with c ,which is a Shape, we are affecting the Cube in the original program. What we'll now do is create an array of 3 floats. In this array, we place some numbers having variable values and then use the setColor function of Shape to diffuse the color of the Cube. Any object, at any one time, has different colors visible on it, depending on the amount of light it receives. What you'll see when you run the program is a Cube whose color keeps getting darker ( as the value of i increases ). When the value of i is equal to 100 ( i.e. when the Cube is at its darkest ) we set it back to 0, so the Cube becomes bright and shiny once again. As the value of i is once again relentlessly increased by the loop, the Cube darkens again and the process continues ad infinitum.

A point that we would like to mention here is, that Shape is not part of the original Java VRML 2.0 specification, rather, it's another one of SONY's add-ons. I sincerely hope that everyone sticks to it as it makes life so much easier.

b15.wrl

#VRML V2.0 utf8
DEF TT Transform
{       children
        [       Transform
                {       children
                        [       DEF SS Shape
                                {       appearance Appearance
                                        {       material Material {}
                                        }
                                        geometry Cone {}
                                },
                        ]
                }
        ]
}

DEF s1 Script
{       	eventIn SFTime  fly
	url     "b15.class"
	scriptType	"javabc"
	field SFNode ch1 USE TT 
}

DEF t1 TimeSensor
{       	discrete  TRUE
	loop	TRUE
        	enabled 	TRUE
	cycleInterval	0.2
}

ROUTE t1.time TO s1.fly
b15.java
import vrml.*;
import java.io.*;
public class b15 extends Script
{       SFNode u = (SFNode)getField("ch1");
        Transform ut = (Transform) u.getValue();
        DataOutputStream d;
        Shape c;int i;
        SFNode b = (SFNode)getField("ch1");
        Transform bt = (Transform)b.getValue();
        public b15()
        {       try
                {      FileOutputStream f = new FileOutputStream("b15.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)
        {      i++;
                float f[] = new float[4];
                f[0]=f[2]=0;f[1]=1;
                f[3]=i;
                if ( i == 360)
                        i = 0;
                bt.rotateDegree(f, bt.modeAbsolute);
                abc("In Fly\r\n");
        }
        public void abc( String a)
        {      try
                {     	d.writeChars(a);
                        	d.flush();
                } catch ( Exception e ) {}
        }
}

In program b15, we are doing exactly the same thing as before, only now we're running another function called rotateDegree. As you've probably guessed, this makes the entire structure rotate about on the screen.

Hours of viewing pleasure !!!

b16.wrl

#VRML V2.0 utf8
Transform
{       children
        [       Viewpoint
                {},
        ]
}
Sound
{       source DEF GUSYA AudioClip
        {       url "bird01.wav"
                loop TRUE
        }
}

In program no. 16, we finally introduce you to the wondrous world of sound ! Now Sound as a Node has a field called source which has to look like an object ( in our case AudioClip ). This field has to be present, otherwise no sound will be generated. You can give the source a name e.g. GUSYA ( Don't ask !! I don't know why the guys at SONY used this name either !! ). The source requires a url pointing to the .wav file to be played ( in our example, bird01.wav ) Now because we have said loop is equal to TRUE, the sound will play continuously. Going through the code, you'll have noticed that we have a Transform with children which contains the word Viewpoint. Try the program with and without Viewpoint. The sound will keep playing but if you don't have a Viewpoint then you will have to get closer to the Cube to hear it. In this next example we will demonstrate how to associate a sound with a shape, using no Viewpoints. Only when the user moves closer to the cube, will the sound start playing.

b17.wrl

#VRML V2.0 utf8
DEF BIRD Transform
{       children
        [       Shape
                {       appearance Appearance
                        {       material Material {}
                        }
                        geometry Cube { }
                },
                Sound
                {       source DEF BGM AudioClip
                        {       url "bgm.wav"
                                loop TRUE
                        }
                }
        ]
}

On to the next example

b18.wrl

#VRML V2.0 utf8
Transform
{       children
        [       Shape
                {       appearance Appearance
                        {       material Material {}
                        }
                        geometry Cube { }
                },
                DEF CLICK TouchSensor {},
                Sound
                {       source DEF BGM AudioClip
                        {       url "bgm.wav"
                                stopTime 1
                                loop TRUE
                        }
                }
        ]
}

DEF s1 Script
{       url "b18.class"
        scriptType "javabc"
        eventIn  SFBool  clicked
        eventOut SFTime bgmStart
        eventOut SFTime bgmStop
}

ROUTE CLICK.isActive TO s1.clicked
ROUTE s1.bgmStart TO BGM.set_startTime
ROUTE s1.bgmStop TO BGM.set_stopTime
b18.java
import vrml.*;
import java.io.*;
public class b18 extends Script
{       DataOutputStream d;
        SFTime stop  = (SFTime) getEventOut("bgmStop");
        SFTime start  = (SFTime) getEventOut("bgmStart");
        boolean r = false;
        public void clicked (SFBool press, SFTime t)
        {       abc("clicked\r\n");
                if(press.getValue())
                        return ;
                if(r)
                {       r=false;
                        stop.setValue(t.getValue());
                }
                else
                {       r=true;
                        start.setValue(t.getValue());
                }
        }
        public b18()
        {       try
                {       FileOutputStream f = new FileOutputStream("b18.txt");
                        BufferedOutputStream b = new BufferedOutputStream(f,128);
                        d = new DataOutputStream(b);
                }
                catch ( Exception e ) {}
                abc("In Constructor\r\n");
        }
        public void abc( String a)
        {       try
                {       d.writeChars(a);
                        d.flush();
                } catch ( Exception e ) {}
        }
}

The next example b18, has two eventOuts present in it's code. One is named bgmstart and the other one is named bgmstop. This means these two events will be generated by the Java Program. EventIn says clicked which means that in the Java Program, the clicked function will be called whenever we click on the cube.

Now the sound, which we have named BGM ( using the DEF statement ), has 2 variables. One called startTime, and the other called stopTime, both of whom are pre-defined variables. Whenever the Java Program generates the bgmstart event , we route it to startTime and bgmstop is routed to stopTime. Note that we don't have a variable startTime in Audioclip. This makes it evident that we'll be using the default value. The clicked function will be called twice with every mouse click, the first time, when you press the left mouse button and the second time when you release it. Nothing happens when you press the left mouse button, but things start to move when the button is released. So when you release the mouse button for the first time, r will be made true or false and depending on the values of r , the if or the else statements will be executed. t represents the time and with t.getValue() we will get the current time. When we say setValue , we trigger an event which will return this value to the variable in the .wrl file. In our program the value will be given to startTime or stopTime.

What happens is that when you click, you set the timer on and at the same time, you set the Audioclip on. Unless you move closer to the cube, the sound won't start playing. So when finally you decide to move closer to it, the sound starts and when you move away, the sound file stops playing . Now when you click again, you are stopping the Audioclip because you are setting the value of t to startTime ( This makes startTime greater than stopTime ). All this means that each time you click, you are setting the values of stop and start. Stop is represented by bgmstop, start is represented by bgmstart. When you say start.setvalue, you are actually setting the values of the variable named startTime. In the second case you are setting the value of stopTime. Depending on these values the Audioclip will be turned on or off.

When the value of the variable startTime is larger than stopTime, the sound file will not play. If the value of stopTime is greater than startTime only then will the file play. Keep repeating this sentence till it is firmly planted in the loose and porous soil of your mind.

In a nutshell....

Every Audio player has the variables startTime and stopTime. startTime tells the player when to start playing and stopTime tells it when to stop. Now obviously startTime should be less than stopTime. If the startTime is higher than stopTime , the audio file will stop playing. So the difference in the values between startTime, stopTime decides how long a sound file should play.

b19.wrl

#VRML V2.0 utf8
DEF BIRD Transform
{       children
        [       DEF PAPER Switch
                {       whichChild 0
                        choices
                        [       Inline{ url "k1.wrl" },
                                Inline{ url "k2.wrl" },
                                Inline{ url "k3.wrl" },
                        ]
                },  
                DEF CLICK TouchSensor {},
        ]
}
DEF s1 Script
{       url "b19.class"
        scriptType "javabc"
        eventIn  SFBool  clicked
        eventOut SFInt32    pChild
}

ROUTE CLICK.isActive TO s1.clicked
ROUTE s1.pChild TO PAPER.set_whichChild
b19.java
import vrml.*;
import java.io.*;
public class b19 extends Script
{       SFInt32  paperChild= (SFInt32) getEventOut("pChild");
        DataOutputStream d;int i=0;
        public b19()
        {       try
                {       FileOutputStream f = new FileOutputStream("b19.txt");
                        BufferedOutputStream b = new BufferedOutputStream(f,128);
                        d = new DataOutputStream(b);
                }
                catch ( Exception e ) {}
                abc("In Constructor\r\n");
        }
        public void clicked (SFBool press, SFTime t)
        {       if(press.getValue())
                        return ;
                abc("In clicked\r\n");
                paperChild.setValue(i);
                i++;
                if ( i == 3)
                        i = 0;
        }
        public void abc( String a)
        {       try
                {       d.writeChars(a);
                        d.flush();
                } catch ( Exception e ) {}
        }
}
k1.wrl
#VRML V2.0 utf8
DEF UFO Transform
{       translation 0.406737 0.913545 0
        children
        [       Shape
                {       appearance Appearance
                        {       material Material
                                {       diffuseColor     1 0.956773 0.5
                                }
                        }
                        geometry Cube { }
                },
        ]
}
k2.wrl
#VRML V2.0 utf8
DEF UFO Transform
{       translation 0.406737 0.913545 0
        children
        [       Shape
                {       appearance Appearance
                        {       material Material
                                {       diffuseColor     1 0.956773 0.5
                                 }
                        }
                        geometry Sphere { }
                },
        ]
}
k3.wrl
#VRML V2.0 utf8
DEF UFO Transform
{       translation 0.406737 0.913545 0
        children
        [       Shape
                {       appearance Appearance
                        {       material Material
                                {       diffuseColor     1 0.956773 0.5
                                }
                        }
                        geometry Cylinder { }
                },
        ]
}

Now program b19 talks about how we can have a very simple case statement or a series of if statements. This case statement is also known as a Switch. In this program the Switch has been named PAPER. Now every Switch has to have a certain syntax. Each Switch has a variable called whichChild. If whichChild is given the value of 0 it will bring in the first file (Named k1.wrl ). inline simply means that the file brought in shouldn't overwrite the existing file.

Now try this yourself. Make whichChild equal to 2, and you will see the third inline getting called. In other words, choice is simply a collection of if statements.

Now in the children we have a Touch Sensor, named CLICKED. This means that we have now attached a touchsensor to the choices. Now because of the ROUTE, whenever we click with the mouse , the clicked function will get called. In the Script ,we have said that pChild is an eventOut , implying that the event will be produced by the Java program. Each time the event is generated, it will change the values of whichChild in the Switch. So based on these values, the respective files will be loaded.

What you have to get here is that the data type of eventOut is SFInt32, because paperChild is a number. The result of pChild too will be a number. If we were to say getEvenOut, we would get a string, which is why we have casted it to SFInt32.

So paperChild in my Java program now stands for the pChild in the script, and each time we say setValue, we are generating an event through which we are changing the value of whichChild. Keep in mind that setValue takes an int, so the value of i keeps changing. Since the value of i changes, the value of pChild oscillates between 0,1 and 2. Each time i changes, a different geometry is displayed.

Click to learn more on children


This tutorial is a joint effort of

Mr. Vijay Mukhi
Ms. Sonal Kotecha
Mr. Arsalan Zaidi

Visit the Vijay Mukhi's Technology Cornucopia to know about our other tutorials or just move back to the VRML Page. Comments , suggestions and criticisms are always appreciated, but we love praise !!


Vijay Mukhi's Computer Institute
B-13, Everest Building, Tardeo, Bombay 400 034, India.
http://www.vijaymukhi.com
e-mail : vmukhi@giasbm01.vsnl.net.in

Tel : 91-22-496 4335 /6/7/9
Fax : 91-22-307 28 59