Home| Products| Projects| Articles| Contact
Articles Menu
› Index › Microsoft MapPoint › Natural Language Processing › Google AdSense › Authenticode › Geoweb Guru › XSLT and the HSX › VRML

Virtual Reality Modelling Language (VRML)

VRML is something I dabbled with a few years ago - when VRML 1.0 was all the rage, and the VRML 2.0 specification was still being written. Alas, VRML never became the big thing which many expected. This was partly because VRML is very verbose. Although this is no longer a problem, it also failed to match the rapid development of graphics display cards during the late 1990s. It has also been replaced by X3D, which extends VRML and is XML-compliant. Over ten years later, there is also the argument that the Internet still is not ready to be 3D and fully immersive. 2D vector graphics for the web is beginning to become popular with workable standards such as Scalable Vector Graphics (SVG), so X3D or an X3D-like format may become popular in the near future.

A Sample VRML 1.0 World

A VRML file or scene is called a World, and has the extension of wrl. The following VRML code is a simple example of four glasses of dark beer on a box table:

#VRML V1.0 ascii
# Pints of Beer (Old Peculier) on a Box
# (C) Copyright Winwaed Software Technology LLC 1996-2006.

DEF table_scene Separator {

# Box Table
Separator {
	Transform { translation 0 -2.15 0 }
	Material { diffuseColor 0.6 0.6 0.6 emissiveColor 0.2 0 0}
	Cube { width 5
               height 4.3
               depth 5 }
        }

# Define a beer glass + dark beer 
DEF BEER_GLASS Separator  {

Separator {
	# Liquid part of beer
	Material { diffuseColor 0.3 0.15 0 }
	Transform {
	        rotation 1 0 0 3.14159265
        	translation 0 -1.3 0}
	Cone {
	 parts ALL
	 bottomRadius 0.2
	 height 4}
}

Separator {
        # Head of beer  
	Transform {
	translation  0 0.7 0 }
        Material { diffuseColor 1 1 0.7 }
	Cylinder {
	 parts ALL
	 radius 0.2
	 height 0.015 }
       }
}
#End of Beer Glass Definition

# Add some more Beer Glasses
Separator { Translation { translation 1.5 0 1 }
            USE BEER_GLASS }
Separator { Translation { translation -1.15 0 1.35 }
            USE BEER_GLASS }
Separator { Translation { translation 0.7 0 -1.5 }
            USE BEER_GLASS }
Separator { Translation { translation -1.65 0 -0.95 }
            USE BEER_GLASS }
}

Writing Programs to Create VRML Worlds

It is also possible to write programs to create or modify VRML worlds. In 1995, I wrote a simple C program that created a VRML Mobius Strip. This is thought to be the world's first cyberspace Mobius Strip, and was published in the book "Programmierung animierter Welten: Java, JavaScript, und VRML" by Eckhard Ammann. URLs for the actual Mobius Strip have also appeared in the appendices of at least a couple of introductory VRML books.

The resulting VRML Mobius Strip is available for download (13.1KB). The C program that created is here:

/*
MOBIUS.C
Creates a VRML 1.0 (.wrl) file of a Mobius Strip. Polygons are double sided,
and the whole strip is rainbow coloured.

(C) Copyright Richard Marsden 1995-2006  (http://www.winwaed.com)
Users are free to distribute this code as is, and add/change any code
as long as this comment is not removed or edited.
If you make any interesting changes (or improve the VRML output), please
contact me!
*/

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define PI  3.14159

FILE            *fOut;                       // Output file
char            filename[50];                // Output filename
int             no_segs,no_points,c_seg;     // Segment/point dimensions
int             i;                           // Counter
float           red,green,blue;              // Used in colour calculations
double          width, inc, radius, col;     // Dimensions + increment & colours
double          x, y, z, x2, y2;             // Point coord & temp. coord
double          nx,ny,nz;                    // Normal vector

void	main ();

void	main ()
{
// Get info from user
      printf("MOBIUS v1.1 - Create Mobius Strip VRML File.\n");
      printf("(C) Copyright Richard Marsden 1995-2006\n\n");
      printf("Output filename: ");
      scanf("%s",filename);
      if ((fOut=fopen(filename,"wt"))==NULL)
      {
	   printf("Cannot open file: %s\n",filename);
         return;
	}
      printf("No. of segments in the strip? ");
      scanf("%d",&no_segs);
      if (no_segs % 3 != 0)
      {
	   no_segs += (3- no_segs%3);
         printf("Rounding up to %d segments!\n",no_segs);
      }
      inc = 2.0 * PI / (float) no_segs;
      no_points = no_segs * 2;
      printf("Radius of circle? ");
      scanf("%lf",&radius);
      printf("Width of strip? ");
      scanf("%lf",&width);

// Output header
      fprintf(fOut,"#VRML V1.0 ascii\n");
      fprintf(fOut,"# Mobius Strip VRML File\n");
      fprintf(fOut,"# Output from MOBIUS v1.1 - Written by Richard Marsden\n");
      fprintf(fOut,"# Contact: Richard Marsden, http://www.winwaed.com\n");

// Begin Mobius Definition
      fprintf(fOut,"PointLight { intensity 0.7}\n");
      fprintf(fOut,"DEF Mobius_Strip Separator {\n");
      fprintf(fOut,"Coordinate3 { point [\n");

// Calculate+Dump Coordinates
      for (i=0; i<no_segs; i++)
      {
          if (i>0)    fprintf(fOut,",\n");

// Rotate about centre line
          x = width * sin (inc*0.5*(float)i) * 0.5;
          z = width * cos (inc*0.5*(float)i) * 0.5;

// Move along strip
          x2 = (radius + x) * cos (inc*(float)i);
          y2 = (radius + x) * sin (inc*(float)i);
          y = (radius -x) * sin (inc*(float)i);
          x = (radius - x) * cos (inc*(float)i);
          fprintf(fOut,"%.3lf %.3lf %.3lf, ",x,y,z);
          fprintf(fOut,"%.3lf %.3lf %.3lf",x2,y2,-z);
      }
	
// Define normals
      fprintf(fOut,"]}\nNormal {vector[");
      for (i=0; i<no_segs; i++)
      {
          if (i>0) fprintf(fOut,",\n");

// Rotate about centre line
          nx = cos(inc*0.5*(float)i);
          nz = sin(inc*0.5*(float)i);

// Rotate around strip
          x2 = x * cos (inc*(float)i);
          y2 = x * sin (inc*(float)i);
          ny = -x*sin(inc*(float)i);
          nx = -x*cos(inc*(float)i);
          fprintf(fOut,"%.3lf %.3lf %.3lf, ",nx,ny,nz);
          fprintf(fOut,"%.3lf %.3lf %.3lf",-nx,-ny,-nz);
      }
	
// Define colours
      c_seg = no_points/3;
      fprintf(fOut,"]}\n NormalBinding {value DEFAULT}\nMaterial { emissiveColor [1 0 0");
      for (i=1; i<c_seg; i++)
      {
	    green = (float)i/c_seg;
          fprintf(fout,",%.2f %.2f 0",1.0-green,green);
      }
      for (i=0; i<c_seg; i++)
      {
	    blue = (float)i/c_seg;
          fprintf(fout,",0 %.2f %.2f",1.0-blue,blue);
      }
      for (i=0; i<c_seg-1; i++)
      {
	    red = (float)i/c_seg;
          fprintf(fout,",%.2f 0 %.2f",red,1.0-red);
      }
      fprintf(fout,"]} MaterialBinding {value PER_FACE_INDEXED}\n");
	
// connect points up (and colour faces)...
      for (i=0; i<no_points-2; i+=2)
      {
	   fprintf(fout,"IndexedFaceSet { coordIndex [ ");
         fprintf(fout,"%d,%d,%d,-1,",i,i+2, i+1);
         fprintf(fout,"%d,%d,%d,-1,",i,i+2, i+1);
         fprintf(fout,"%d,%d,%d,-1,",i+1,i+2,i+3);
         fprintf(fout,"%d,%d,%d,-1 ]",i+1,i+2,i+3);
         fprintf(fout," materialIndex [%d,%d,%d,%d]}\n",i,i,i+1,i+1);
      }
      fprintf(fout,"IndexedFaceSet {coordIndex [ ");
      fprintf(fout,"%d,%d,%d,-1,",no_points-2,0,no_points-1);
      fprintf(fout,"%d,%d,%d,-1,",no_points-2,0,no_points-1);
      fprintf(fout,"%d,%d,%d,-1,",no_points-2,0,1);
      fprintf(fout,"%d,%d,%d,-1]\n",no_points-2,0,1);
      fprintf(fout," materialIndex [%d,%d,%d,%d]}\n",no_points-1,no_points-1,no_points,no_points);

// finish
      fprintf(fout,"}\n");
      fclose(fout);
      printf("\nDone!\n");
      return;
}