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. 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 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 }
}
It is also possible to write programs to create of 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 Mobius Strip World 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;
}