Hands-on WebGL: Basic GLGE Tutorial

In a previous tutorial I explained how to draw a triangle on the screen with pure low-level WebGL. A lot had to be done before anything could be drawn to the screen: define shaders, set up matrices, create shader programs, depth testing, vertex attributes, etc. Pretty interesting stuff if you’re into the technical details of WebGL but a true pain if you just want to create a nice 3D scene.

Fortunately there has been quite a lot of activity around WebGL already. The specification hasn’t been finished yet but there are already numerous libraries utilising WebGL:

GLGE

For this tutorial I’m going to use GLGE. It is very easy to set up and already has loads of features (from the GLGE website):

  • Keyframe animation
  • Perpixel lighting directional lights, spot lights and point lights
  • Normal mapping
  • Animated materials
  • Skeletal animation(WIP)
  • Collada format support
  • Parallax Mapping
  • Text rendering(probably bitmap)
  • Fog
  • Depth Shadows
  • Shader based picking

This tutorial will show you how to set up a simple scene, add a box, material and a texture.
If you don’t have a WebGL-enabled browser installed, here’s how to get one.

Setting up the scene

GLGE materials, meshes, cameras, animations, etc and the scene graph can all be specified through JavaScript or XML. The most convenient way is to do it in XML. This is an example of a very basic scene:


<?xml version="1.0" ?>
<glge>
	<mesh id="box">
		<positions>1.000000,0.999999,1.000000,1.000000,1.000000,-1.000000,-1.000000,1.000000,-1.000000,1.000000,0.999999,1.000000,-1.000000,1.000000,-1.000000,-1.000000,1.000000,1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,1.000000,-1.000000,1.000000,1.000000,-1.000000,-1.000000,-1.000000,-1.000000,1.000000,1.000000,-1.000000,1.000000,-1.000000,1.000000,-1.000000,-1.000000,0.999999,-1.000001,1.000000,-1.000000,-1.000000,-1.000000,0.999999,-1.000001,1.000000,-1.000000,-1.000000,1.000000,-1.000000,-1.000000,-1.000000,1.000000,1.000000,-1.000000,1.000000,0.999999,1.000000,1.000000,-1.000000,-1.000000,1.000000,0.999999,1.000000,0.999999,-1.000001,1.000000,1.000000,-1.000000,-1.000000,1.000000,0.999999,1.000000,-1.000000,1.000000,1.000000,0.999999,-1.000001,1.000000,-1.000000,1.000000,1.000000,-1.000000,-1.000000,1.000000,0.999999,-1.000001,1.000000,1.000000,1.000000,-1.000000,1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,1.000000,1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,1.000000,-1.000000</positions>
		<normals>0.000000,1.000000,0.000000,0.000000,1.000000,0.000000,0.000000,1.000000,0.000000,0.000000,1.000000,0.000000,0.000000,1.000000,0.000000,0.000000,1.000000,0.000000,-1.000000,0.000000,-0.000000,-1.000000,0.000000,-0.000000,-1.000000,0.000000,-0.000000,-1.000000,0.000000,-0.000000,-1.000000,0.000000,-0.000000,-1.000000,0.000000,-0.000000,-0.000000,-1.000000,-0.000000,-0.000000,-1.000000,-0.000000,-0.000000,-1.000000,-0.000000,-0.000000,-1.000000,0.000000,-0.000000,-1.000000,0.000000,-0.000000,-1.000000,0.000000,1.000000,0.000000,-0.000000,1.000000,0.000000,-0.000000,1.000000,0.000000,-0.000000,1.000000,-0.000001,0.000000,1.000000,-0.000001,0.000000,1.000000,-0.000001,0.000000,-0.000000,-0.000000,1.000000,-0.000000,-0.000000,1.000000,-0.000000,-0.000000,1.000000,0.000000,-0.000000,1.000000,0.000000,-0.000000,1.000000,0.000000,-0.000000,1.000000,0.000000,0.000000,-1.000000,0.000000,0.000000,-1.000000,0.000000,0.000000,-1.000000,0.000000,-0.000000,-1.000000,0.000000,-0.000000,-1.000000,0.000000,-0.000000,-1.000000</normals>
		<uv1>0.333333,0.498471,0.001020,0.500000,0.000000,0.001529,0.333333,0.498471,0.000000,0.001529,0.332314,0.000000,0.000000,0.998471,0.001020,0.500000,0.333333,0.501529,0.000000,0.998471,0.333333,0.501529,0.332314,1.000000,0.665647,0.500000,0.666667,0.998471,0.333333,0.501529,0.666667,0.998471,0.334353,1.000000,0.333333,0.501529,0.998981,0.000000,1.000000,0.498471,0.666667,0.001529,1.000000,0.498471,0.667686,0.500000,0.666667,0.001529,1.000000,0.501529,0.998981,1.000000,0.667686,0.500000,0.998981,1.000000,0.666667,0.998471,0.667686,0.500000,0.334353,0.500000,0.333333,0.001529,0.665647,0.000000,0.334353,0.500000,0.665647,0.000000,0.666667,0.498471</uv1>
		<faces>0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35</faces>
	</mesh>

	<camera id="maincamera" loc_z="20" />

	<material id="boxmaterial" color="#900" />

	<scene id="mainscene" camera="#maincamera" ambient_color="#fff">
		<light id="mainlight" loc_y="5" type="L_POINT" />
		<object id="box" mesh="#box" rot_x="-.8" rot_y=".5" material="#boxmaterial" />
	</scene>
</glge>

First the mesh data is defined. In this case, the mesh data is exported from Blender using the included exporter script or the Blender to WebGL script. I don’t think there is a built in way to add primitives to the scene as of now (please tell me if I’m mistaken).

Then a camera is defined. Only one property is defined, loc_z or the z position.

A simple color material is defined (#990000, crimson red). Later on we will use a texture.

Then the scene graph is defined. It consists of a simple point light and a box primitive. Note how the mesh and materials nodes are referenced by their ids (mesh=”#box” and material=”#boxmaterial”).

HTML & JavaScript

Once this is all defined we can start coding the HTML and JavaScript. First download the GLGE library files and put them in a folder called “glge”. Then include the following script in the HTML page:


<script type="text/javascript" src="glge/glge_math.js"></script>
<script type="text/javascript" src="glge/glge.js"></script>

Then add a canvas element:


<canvas id="canvas" width="400" height="400"></canvas>

Now comes the scripting part. Insert this after the canvas element (explanation in the code):


<script type="text/javascript">
// -- create a document
var doc = new GLGE.Document();

// -- callback function that is called when the xml document
//    has finished loading
doc.onLoad = function() {
	// -- create a renderer and pass in the canvas object
	var renderer = new GLGE.Renderer(document.getElementById("canvas"));
	// -- create a new scene. the name defined in the parameter corresponds
	//    to the id attribute of the scene element in the xml file.
	var scene = doc.getElement("mainscene");
	// -- pass the scene to the renderer
	renderer.setScene(scene);

	// -- the rendering loop
	function render() {
		renderer.render();
	}

	// -- render each millisecond
	setInterval(render, 1);
}

// -- load the xml containing the scene data
doc.load("scene1.xml");
</script>

See a working version here.

Using textures

The color material is nice, but looks a bit boring. We can make it more interesting by adding a texture to it. In the XML document change the material to this:


<material id="boxmaterial">
	<texture id="boxtexture" src="eddie.jpg" />
	<material_layer texture="#boxtexture" mapinput="UV1" mapto="M_COLOR" />
</material>

Here we’ve added a new <texture> node that point to a jpeg file. Then a material layer is defined (a material can have multiple layers). The texture attribute contains a reference to the <texture> node. The mapinput attribute references the <uv1> node that was defined in the <mesh> node.

Now we need to update the <object> sub node in the scene declaration:


<object id="box" mesh="#box" rot_x="-.8" rot_y=".5" scale_x="3" scale_y="3" scale_z="3" material="#boxmaterial" />

Here we’ve added an extra material attribute that references the id attribute (#boxmaterial) of the <material> node. Note the addition of the rotation and scale attributes as well.

See a working version here.

Animation

Adding animation is really simple as well. This can all be done in the XML document.
To illustrate this we’ll add a simple spinning animation to the cube. Add this xml node under the <glge> node:


<animation_vector id="spin" frames="300">
	<animation_curve channel="RotX">
		<linear_point x="1" y="0" />
		<linear_point x="300" y="-6.283" />
	</animation_curve>
</animation_vector>

Not much to it, right? You can specify the duration by passing a number to the frames attribute. Then you add an <animation_curve> node for every property you want to animate. In this case we’re rotating the y rotation (RotY). The values in the <linear_point> nodes specify the frame number and the value (in radians, -6.283 = 2 * PI = 360 degrees).

See the result here:

That’s it for this very basic tutorial. If this has whetted your appetite and you want to see more tutorials then do let me know :-)

For a complete set of GLGE documentation follow this link.

  • Delicious
  • Facebook
  • Digg
  • Reddit
  • StumbleUpon
  • Twitter

5 thoughts on “Hands-on WebGL: Basic GLGE Tutorial

  1. John says:

    Great tutorial,

    There’s a few things you missed out towards the end of the tutorial.

    There’s no link to the image, (256×256) I assume it has to be a power of 2 ratio?

    Also you’ve said the animation node needs to be added after the node – but I think it needs to be inside this node. Your working examples has it inside this node (after the node.

    You also need to update the box object in the scene with a animation=”#spin” attribute.

    A tutorial handling key and mouse inputs would be great.

    Thanks for getting me started, much appreciated.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>