mjbWorld - VRML File Format

VRML is now superceded by X3D. I have put some ideas for extending these standards to support simulation and games here.

VRML 2 example

#VRML V2.0 utf8
DEF trBALL Transform {
  children [
    DEF tsBALL TouchSensor {}
    DEF shBALL Shape {
      appearance Appearance {
        material Material {
          diffuseColor 1 0 0
          specularColor 0.9 0.9 0.9
      geometry Sphere {
        radius 5
DirectionalLight {
  color 1 1 1
  direction -1 -1 -5
  intensity 0.3
DEF scrBALL Script {
  url ""
  field SFNode shBALL USE shBALL
  eventIn SFBool clicked
ROUTE tsBALL.isActive TO scrBALL.clicked


The program can also save in X3D format, which is similar to VRML but wrapped in XML.

Comparison of mjbWorld with Web3D Consortium browser

The Web3D Consortium has a working group which has written a VRML browser (com.sun.j3d.loaders.vrml97), this section tries to contrast and compare it with mjbWorld.

  Web3D Consortium mjbWorld
Purpose VRML browser, no saving or editing capabilities. VRML editor and with capabilities to read, write, edit graphically and extend (for example as a platform to experiment with 3D simulations)
Loading Consortium - uses a parser, javacc (like yacc). Initializing a vrml world is carried out mostly by an instance of vrmlimpl.Parser. The parser is given a url that represents the location of a wrl, making it transparently useful as either part of a web browser or standalone client. As the parser carries out the vrml grammar, a set of vrml nodes containing j3d objects are generated. A scenegraph is constructed of the j3d objects Each node class type (such as Sphere, Box, TransformGroup, Fog, etc.) contains its own method to read and write itself, and its children, to and from VRML, this is similar to the serialisation mechanism and conforms with Bean standards.
Internal data structure (Compiled Mode) The general memory strategy is to create a Java 3D scene graph with retained data, and garbage collect ancillary VRML fields and other node objects, including the VRML node, unless there is a reference maintained to VRML node by instance of the ROUTE object, hence no GC for that object. Both the Java3D scene graph and the associated mjbWorld beans are retained in memory, these are cross-linked so parameters can be stored in the scene graph if possible, but for parameters that do not correspond to Java3D scene graph information, then they can be retained in the Bean.
Expansion I'm not sure how it is intended to be customised? Since it is built using Bean standards, it can be expanded by creating beans for new node types, or extending existing Bean types. The program can also be extended with a scripting language or editing the source code.
Runtime uses com\sun\j3d\utils\geometry to generate box, sphere etc. These classes are released once the scene graph is initiated. Has its own box, sphere, etc. classes (which are beans) these are live all the time the program is running, so no parameters are lost (even if they cannot be stored in the scene graph, such as 'radius' or 'crease angle').


Reading and parsing exponential numbers

  1. Use the java.text package - not an option does not support exponential and also inefficient
  2. Use StreamTokenizer - does not support exponential.
  3. Use ReaderTokenizer - which is written by Steve Pietrowicz and works like StreamTokenizer but with exponentials supported (costs money for commercial use).
  4. Use StringTokenizer (which does support exponentials) then use Double.parseDouble(s)
  5. Use a parse program.

Currently the program uses option 4, would another option be better? I want something that's fast for large meshes. I prefer the functionality of StringTokenizer over StreamTokenizer because it allows multiple separators and it supports exponentials. However I guess StreamTokenizer should be more efficient because you don't have to create a string for each number to pass to parseDouble(), however the workarounds for the lack of exponential support seem to cause there own inefficiencies - which is worse?

further info on reading exponential floating point numbers

A limitation might be lack of support for double floating point variables.

The behaviors build into VRML and Java3d are limited (OK for simple repetative behaviors but now very extendable for simulating physics). There is some work being started under MPEG4-VRML


Export to Java source issue

VRML and Java3D use a similar scene graph (which is a tree structure) so its quite easy to convert between them. However there is an area where they differ, that is the mechanism for reusing nodes in several parts of the tree. In VRML we can name a node with the DEF keyword and then use it at other places in the scenegraph with the USE keyword. In Java3d nodes can be used at several points in the scene by using the Link and SharedGroup nodes however the rules for using these nodes are mode restrictive than the VRML DEF/USE keywords. Where the Link and SharedGroup nodes cannot be used then the nodes have to be cloned, which uses more memory. The easiest way to do this would be to implement this would be to always clone nodes when a USE is found. But this would be wasteful in memory so I am trying to build in the intelligence to use Link and SharedGroup nodes where appropriate, but this will take time to do properly.

Calculation of normals

If the VRML does not contain normals then these are generated in the program. The normal to any face can be easily generated by taking the cross-product of the vectors representing any 2 non-parallel sides of the face. The program does this without any problem. However the Indexed array geometry that I am using in java3d requires a normal per vertex and not a normal per face. So I do this by averaging out all the normals of the faces that meet at the vertex. This works well for curved surfaces such as a sphere. If the shapes require hard edges then the VRML signals this by having a 'crease angle' parameter to specify the angle between the normals for different faces at the same vertex. This is the bit that is complex to implement, it will also going to drastically increase the number of normals and hence the size of arrays to hold them. However there may be an interim solution which would be to say: if crease angle is less than say 0.3 then calculate normals as the program does at present, if crease angle is greater than 0.3 then use the normals generated from the faces without averaging. There are still some complications here because there may be more faces than vertexes so I may have to increase the size of the arrays, but it would be much quicker than fully implementing crease angle.

see normals

metadata block
see also:


Correspondence about this page

This site may have errors. Don't use for critical systems.

Copyright (c) 1998-2023 Martin John Baker - All rights reserved - privacy policy.