Monday, August 2, 2010

Getting Started With Materials in WebGLU

For those who do not know, WebGLU is  a development framework for building applications with WebGL.

For the past several months I have been working on various internal improvements to WebGLU. One of the most significant improvements I've made is the introduction of a materials system. This system allows shaders and textures to be associated with one another and for them to all be loaded and initialized with a single line of code.

A material can be created in a declarative manner using a JSON formatted file, or procedurally at runtime. In either case the Material constructor is given an object literal containing either the path to the file or the complete material definition.

Here's an example material file we'll call example.json:
 name: 'myMaterial',
 program: {
   name: 'textured',
     {name:'texVS', path:$W.paths.shaders + 'tex.vert'},
     {name:'texFS', path:$W.paths.shaders + 'tex.frag'}
 textures: [
   {name:'check', type:'Image', 
    path:'$W.paths.textures + 'check.png'}

As can be seen here, there is support for multiple shaders and multiple textures. WebGLU automatically generates the appropriate callbacks to setup the textures each frame, though this can be modified should you wish to change it at runtime.

It's worth noting that material definitions will have access to the $W object when the material is created so the constant paths can be used as shown above. This is not necessary, but allows shaders to not only be shared between programs, but to do so without relocating textures or shaders in the process. If the material files are also stored on the $W.paths.materials path then all programs will simply have access to them. That means no more mucking about with shaders at all unless you want to!

To use this material in a WebGLU program it's as simple as creating it and assigning it to an object:

new $W.Material({path:$W.paths.materials+'example.json'});

In a future post I will go into more detail about the improvements to the Object type, but I just want to show here that creating the object, setting its geometry, and setting its material can all be done with a single call. Although whether the createObject() call will remain independent or be folded into the $W.Object constructor is a decision I still have to make that will also affect how other classes are instantiated in the future. It's not a decision I'm taking lightly and any opinions or advice would be greatly appreciated because I want WebGLU to have a consistent API, so any decision I make for Object will be propagated to the other types and their constructors.

sphere = $W.createObject({
  model:$W.util.genSphere(20, 20, 8),

If people are interested I could do an entire post on exactly the changes to the API I am considering.