Object - Oriented Approach

 

4.1 Introduction

VRML design can be a very difficult task. When building complex world very deep hierarchies are required. VRML files can be very articulated and full of parameters. And VRML designer must understand these structures and these scene graphs. The task is very hard when working with big VRML files. Moreover VRML language doesn't give the programmer good programming constructs.

When the complexity is high the best solution (or the common solution) is to use an object-oriented approach. And VRML seems to be very suitable to such methodologies. It works with concrete objects as an house, a cube, a human figure and so on. Applying OO technique should improve VRML design, readability and extendibility. And above all it should allow developing of reusable components.

The prototype node in VRML 2.0 goes in this direction. But it's not enough. It allows to encapsulate complex hierarchy and to create an interface for it, made up with EventIns, EventOuts and fields. So, It allows abstraction (dividing the scene graphs into reusable nodes) and encapsulation (hiding the prototype implementation). But it lacks other OO functionality.

The main problem is how to put OO paradigms in VRML. Active groups are working about it. And several proposal are developing. Different directions have been taken: extending VRML language, using JavaScript , ...

This paper explore the use of Java to add OO techniques to VRML. The main idea is to move all VRML capabilities inside Java. Then all OO constructs of Java are available for OO design of VRML world. And so all the benefits of Java programming are acquired by VRML. A library of VRML objects is needed (here JVerge is used) and the External Authoring Interface is used.

4.2 Java and VRML: an example

This simple example creates two cubes in a VRML world. The two cubes move up and down and when the mouse is over them they change color. One of them change color when it is moving. The example is here. There is no VRML code, only Java code and inheritance is used.

Here is the class diagram of the example:

 

The base class is Cube. It is the abstraction of a cube. It represents a cube which changes color when the mouse is over it. The calss is based on Group (grouping node) and EventOutObserver (interface for receiving events from VRML nodes). On Java side it is a class with color and position properties (accessible via methods) and with a callback function for catching VRML events. On VRML side it's a cube object with this description:

Transform {

  scale 0 0 0

  translation 0 1 0

  children [

    Shape {

      geometry Box { size 1 1 1}

      appearance Appearance {

        material material { diffuseColor 1 0 0 }

      }

    }

    TouchSensor { }

  ]

}

 

This description is built by the constructor of Cube at run time. The JVerge objects are used to construct it. The events of TouchSensor are routed to the callback method by the EventOutObserver interface.

For using it an object of type Cube must be created and it must be added to a VrmlRoot object:

VrmlRoot root = VrmlRoot(browser, "root");

Cube cube = new Cube();



root.addChild(cube);

and then to change, for example, the position:

float[] new_pos = {1, 0, 1};

cube.SetPosition(new_pos);

The Java code of Cube class is:

import java.io.*;

import java.util.*;

import vrml.external.*;

import vrml.external.field.*;

import vrml.external.exception.*;

import vlc.vrml.external.geometry.*;

         

public  class Cube extends Group implements EventOutObserver

{ 

    

    private Transform transform = new Transform() ;

    private Material material = new Material() ;

    private Box box = new Box(1, 1, 1);

    private Appearance appearance = new Appearance() ;

    private float[] pos = {0, 0, 0};

    private Shape shape = new Shape();

    private TouchSensor sensor = new TouchSensor();

    EventOutSFBool isOver = null;

    int counter = 0;

   

    public Cube () 

    {

        //Call parent constructor

        super();

        

        //Define the Geometry of Cube

        

        //Color and Material

        material.set_diffuseColor(1,0,0);

        appearance.set_material(material);



        shape.set_geometry(box); //Geometry



        shape.set_appearance(appearance);



        //Set the transform Node and add the cube to it

        ChildrenNode[] children = new ChildrenNode[1];

        children[0] = (ChildrenNode)shape;

        transform.addChildren(children);



        //Set the new position

        transform.set_translation(pos);

        

        //Get the EventOut isOver

        isOver = (EventOutSFBool) sensor.node.getEventOut("isOver");

        isOver.advise(this, new String("isOver"));



        //Add the cube and the sensor to the Group Node (parent)

        ChildrenNode[] children1 = new ChildrenNode[2];

        

        children1[0] = (ChildrenNode)transform;

        children1[1] = (ChildrenNode)sensor;

      

        addChildren(children1);

    }

    

    public void SetPosition(float[]pos) { transform.set_translation(pos); }

    public float[] GetPosition() { return transform.get_translation(); }

    public void SetColor(float[]color) 

        { material.set_diffuseColor(color[0], color[1], color[2]); }

    public float[] GetColor() { return material.get_diffuseColor(); }



    public void callback(EventOut who, double when, Object which)

    {

        String type = (String) which;

        

        if (type.equals("isOver")) 

        {

            boolean val = isOver.getValue();

         

            if (val)

            {

                counter = (counter + 1) % 3; 



                if (counter ==0) material.set_diffuseColor(1,0,0);

                else if (counter == 1) material.set_diffuseColor(0,1,0);

                else material.set_diffuseColor(0,0,1);

            }

        }

    }

}

 Two classes are based on Cube. They add properties to the simple cube. MovingCube is a cube which moves up and down. ColorMovingCube extends MovingCube and adds the changing color property. They just add a TimeSensor and implement the callback method for catching their own events. Here is the code:

MovingCube.java

import java.io.*;

import java.util.*;

import vrml.external.*;

import vrml.external.field.*;

import vrml.external.exception.*;

import vlc.vrml.external.geometry.*;



public class MovingCube extends Cube

{

    private TimeSensor timeSensor = new TimeSensor();

    private EventOutSFTime time = null;

    private float[] oldPos = {0, 0, 0};

    

    public MovingCube()

    {

        //Call parent constructor

        super();

           

        timeSensor.set_stopTime(-1);

        timeSensor.set_loop(true);

        

        time = (EventOutSFTime) timeSensor.node.getEventOut("time");

        time.advise(this, new String("time"));

        

        ChildrenNode[] children = new ChildrenNode[1];

        children[0] = (ChildrenNode)timeSensor;

      

        addChildren(children);

    }

  

    public void callback(EventOut who, double when, Object which)

    {

        //Call parent callback method

        super.callback(who, when, which);

        

        String type = (String) which;

        

        if (type.equals("time"))

        {

            float val = timeSensor.get_fraction_changed();

            float[] newPos = {1,1,1};

                

            newPos = GetPosition();

            newPos[1] += val - .5;

            SetPosition(newPos);

        }

    }

}

ColorMovingCube.java

import java.io.*;

import java.util.*;

import vrml.external.*;

import vrml.external.field.*;

import vrml.external.exception.*;

import vlc.vrml.external.geometry.*;



public class ColorMovingCube extends MovingCube

{

    private TimeSensor timeSensor = new TimeSensor();

    private EventOutSFTime time = null;

    private float[] oldColor = {0, 0, 0};

    

    public ColorMovingCube()

    {

        //Call parent constructor

        super();

           

        timeSensor.set_stopTime(-1);

        timeSensor.set_loop(true);

        

        time = (EventOutSFTime) timeSensor.node.getEventOut("time");

        time.advise(this, new String("CMC_time"));

        

        //Add the TimeSensor to this Node

        ChildrenNode[] children = new ChildrenNode[1];

        children[0] = (ChildrenNode)timeSensor;

      

        addChildren(children);

        

    }

  

    public void callback(EventOut who, double when, Object which)

    {

        //Call parent callback method

        super.callback(who, when, which);

        

        String type = (String) which;

        

        //Check if it is my event

        if (type.equals("CMC_time"))

        {

            float val = timeSensor.get_fraction_changed();

            float[] newCol;



            //Change the color

            newCol = GetColor();

            newCol[0] = val;

            newCol[1] = 1-val;

            SetColor(newCol);

        }

    }

}

The applet class is very simples. It create a VrmlWorld object, a MovingCube object and a ColorMovingCube and then it adds the cubes to the code:

import java.applet.Applet;

import java.applet.*;

import java.awt.*;

import vrml.external.Browser;



public class MovingCubeTest extends Applet

{

    MovingCube movingCube = null;

    ColorMovingCube colorCube = null;

	private Browser	browser = null;

	VrmlRoot root = null;



	public void start()

	{

		browser = Browser.getBrowser(this);



		if(browser == null) System.out.println("Browser not available");

		else System.out.println("Browser handle is available");



		root = new VrmlRoot(browser, "root");



        //Create the cubes

        movingCube = new MovingCube();

        colorCube = new ColorMovingCube();

        

        //Set the position of colorCube

        float[] pos = {2,1,1};

        colorCube.SetPosition(pos);



        // Add the cubes to the Root Node

		root.addChild(movingCube);

		root.addChild(colorCube);



        //Write the scenegraph to the System.out

		root.writeToStream(System.out);

	}

}

HTML and VRML files are very short:

Index.html

<HTML>

<HEAD>

<TITLE>MovingCubeTest</TITLE>

</HEAD>



<BODY>



<EMBED SRC="basic.wrl" WIDTH="100%" HEIGHT="500">



<APPLET CODE="MovingCubeTest.class" HEIGHT="40" WIDTH="100%" MAYSCRIPT>

</APPLET>



</BODY>

</HTML>

Basic.wrl

#VRML V2.0 utf8

#

# The basic world



DEF root Group {}

 

4.2 Comments

The above example show that it's possible to use Java for building VRML code in a OO way. All the OO techniques are easy accessible using Java. Or, on the other hand, it's possible to give 3D behavior to Java classes. Each class can have a direct counterpart in a VRML object.

In this way it's very easy to build a reusable library of VRML objects. The library is a package of Java classes with 3D behavior.

 

4.5 References

VRML Object-Oriented Extensions Working Group

http://www.cs.uni-sb.de/RW/users/diehl/ooevrml/