Welcome to GLOW

We’re really proud to introduce GLOW – a WebGL wrapper. GLOW is for you who have some WebGL experience and would like to get to the core – shaders. Please try out GLOW for experimenting with shaders, to create your custom render pipe or make a WebGL demo. Please fork here.

GLOW was initiated right after we finished ROME – Three Dreams of Black. My main insight from ROME was the power of shaders and I wanted a way to work with this, not having to care about low-level WebGL and high-level abstractions.

Soon Olov Lassus joined and we’ve pushed GLOW to be clean and simple, yet powerful. Check out JSShaper and Restrict Mode that Olov is juggling as well.

2012+03+13

A few updates

Today we uploaded a few handy changes to the repo. Among these, we’d say these are the most interesting:

  • GLOW.Float and GLOW.Int now support arrays as constructor parameter. This is very good to have when you have uniform arrays in your shaders.
  • GLOW.Matrix3.extractFromMatrix4() was added so you easily can get the rotation part of the GLOW.Matrix4 into your GLOW.Matrix3.
  • The GLOW.Compiler doesn’t call the GLOW.Texture.init() if there’s no texture there to initialize. This allows you to init your shader without a texture set.
  • We added GLOW.Geometry.Cylinder so you can create cylinders easily.
  • We added interleaved attributes to the cache (I have no idea why we hadn’t this before, but now it’s there :)

Enjoy!

2011+12+27

Refactored .elements

To make it easier and more logical to activate GL.drawArrays (see previous post) we’ve thrown away the good old elements property and changed it into…

var shaderConfig = {
  indices: myArrayOfIndices,
  primitives: GL.TRIANGLES,
  data: {
    // attributes and uniforms
  },
  usage: {
    primitives: GL.DYNAMIC_DRAW
  }
}

(First a side note: elements is now primitives in the usage object). As you can see we’ve split elements into indices and primitives, where…

  • indices is the array of indices
  • primitives is the type of primitive you’d like to use

If you leave out the primitives property, it defaults to GL.TRIANGLE. Also, the good old…

  • triangles
  • triangleStrip
  • triangleFan
  • points
  • lines
  • lineLoop
  • lineStrip

… properties still work and automatically sets the primitive property.

Now, to use GL.drawArrays instead of GL.drawElements you simply leave out the indices property…

var shaderConfig = {
  primitives: GL.POINTS,
  data: {
    // attributes and uniforms
  }
}

As you see, you no longer have to set the amount of primitives to draw (this is calculated from the attribute length).

Thanks Neil Mendoza for the excellent suggestion.
Hope you like it!

2011+12+25

Added support for drawArrays

As Neil Mendoza rightfully pointed out, GLOW only supported drawElements. We’ve now added support for drawArrays. It’s quite simple to do, you just…

var shaderConfig = {
  triangles: 10 * 3
  primitives: GL.POINTS,
  data: {
    // attributes and uniforms
  }
}

var shader = new GLOW.Shader( shaderConfig );
shader.draw();

As you can see the only difference is that you, instead of creating an array of indices, tell the shader the length of the arrays to draw which type of primitive you’d like to draw. As drawArrays doesn’t use indicies like drawElements you’re not limited by the 65535-limit imposed by the Uint16Array used by drawElements.

Another nerdy addition is the GLOW.Elements.offset property that’s been added. This can be used to create animation-like behaviors, moving over the attributes. Please note that you have to keep the GLOW.Elements.length in check, so you don’t run outside the attribute buffers.

We’ve updated the particle thingy we launched some week ago as well as killing some bugs related to cloning textures.

Please pull!

2011+12+12

FBO Simulations

It’s been a while but we’ve just added a new tutorial on how to use FBO and GL.FLOAT for complex shader simulations. Click here to get into the game. And here to see an example.

2011+07+21

GLOW.Texture Changes

We just refactored and simplified the GLOW.Texture. Read all about the new texture capabilities here.

2011+07+15

Interleaved Attributes

GLOW had one feature, the cache, but we just added its second – automatically interleaved attribute data.

Interleaved attributes is a performance improvement, which in some cases can make a big difference but really is a very nerdy feature. It’s not widely supported by existing WebGL frameworks so I’ll try to explain what it is and why you like to have it.

Instead of having one VBO for vertices, another for normals and a third for UV coordinates, you simply interleave them into one VBO. So instead of…

VBO A: Vertex Vertex Vertex...
VBO B: Normal Normal Normal...
VBO C: UV UV UV...

…you get…

VBO: Vertex Normal UV Vertex Normal UV...

The good thing with this is that you only have to bind one buffer instead of one per attribute, when setting up the attributes prior to the draw call.

To get the right data to the right attribute, WebGL uses something called Stride and Offset (or Pointer). You can read all about it here. This is all handled internally by GLOW, and you’ll not even notice unless you use WebGL Inspector and look at the trace.

Most of the time you like this to be enabled and just work but in some cases you might want to control how the attributes are interleaved or not interleaved at all. This is possible through the shader definition object that you pass into the GLOW.Shader constructor…

var shaderInfo = {
  vertexShader: "...vertex shader code...",
  fragmentShader: "...fragment shader code...",
  data: { ...all uniform, attribute and texture data... },
  elements: [ ...UInt16Array containing element info... ],
  interleave: {
    vertices: false,
  }
}

In this example the attribute called ”vertices” won’t be interleaved (and work just as an ordinary GLOW.Attribute) and all other attributes will be automatically interleaved.

var shaderInfo = {
  vertexShader: "...vertex shader code...",
  fragmentShader: "...fragment shader code...",
  data: { ...all uniform, attribute and texture data... },
  elements: [ ...UInt16Array containing element info... ],
  interleave: {
    vertices: false,
    normals: 5,
    uvs: 5,
    speed: 1,
    acceleration: 1
  }
}

In this example the ”vertices” attribute won’t be interleaved, ”normals” and ”uvs” will be interleaved together and ”speed” and ”acceleration” will be interleaved together. The number can be any number you like – think of it as the id of the interleaved VBO you’re creating. If you happen to have even more attributes than the ones controlled in the interleave object, they will be automatically interleaved.

You can even control the usage for interleaved attributes by…

var shaderInfo = {
  vertexShader: "...vertex shader code...",
  fragmentShader: "...fragment shader code...",
  data: { ...all uniform, attribute and texture data... },
  elements: [ ...UInt16Array containing element info... ],
  interleave: {
    vertices: false,
    normals: 5,
    uvs: 5,
    speed: 1,
    acceleration: 1
  },
  usage: {
    normals: GL.DYNAMIC_DRAW,
    uvs: GL.DYNAMIC_DRAW
  }
}

…which will make the ”normals” and ”uvs” buffer use DYNAMIC_DRAW. If you only define usage for one of the attributes in an interleaved buffer, GLOW will throw a warning and default back to STATIC_DRAW.

Last, some details, a new object called GLOW.InterleavedAttributes has been introduced. You cannot use the clone except-property on an interleaved attribute (as it’s now part of a set of interleaved attributes). The interleaved attribute name is generated by the attributes in the set – like ”vertices_uvs_normals” for example, and is accesible directly on the GLOW.Shader like other attributes (and uniforms).

2011+07+03

Usage

Usage in WebGL is used for hinting the GPU how to store data. This parameter is now supported by GLOW.

The GLOW shader data object has a new property, simply called usage…

var shaderData = {
  vertexShader: "...the vertex shader code...",
  fragmentShader: "...the fragment shader code...",
  data: {
    viewMatrix: new GLOW.Matrix4(),
    vertices: myFloat32ArrayWithVertices,
    uvs: myFloat32ArrayWithUVs,
    ...and all other uniforms and attributes...
  }
  usage: {
    vertices: GL.DYNAMIC_DRAW,
    uvs: GL.STREAM_DRAW,
    triangles: GL.DYNAMIC_DRAW
  }
  triangles: myUint16ArrayWithTriangles
}

As you see, I use the global GL object for parameters – make sure that a GLOW.Context has been created before you create the shader data object.

  • GL.DYNAMIC_DRAW is for buffers that are used often and updated often
  • GL.STREAM_DRAW is for buffers that are initialized once and seldom drawn.
  • GL.STATIC_DRAW (default) is for buffers that are initialized once and drawn often.

Note that the elements (in this case triangles) also can be subject to usage. You don’t have to define the usage property and if you do, you only have to set it for data that use GL.STREAM_DRAW or GL.DYNAMIC_DRAW.

2011+07+03

Point, Lines, Triangles

Sometimes you don’t want to draw triangles, but lines and points. Now GLOW has support for this as well as some other types.

As you know, this is the GLOW shader data object…

var shaderData = {
  vertexShader: "...the vertex shader code...",
  fragmentShader: "...the fragment shader code...",
  data: {
    viewMatrix: new GLOW.Matrix4(),
    vertices: myFloat32ArrayWithVertices,
    ...and all other uniforms and attributes...
  }
  elements: myUint16ArrayWithElements
}

As of today the elements property can be switched to any of the following…

  • points
  • lines
  • lineLoop
  • lineStrip
  • triangles
  • triangleStrip
  • triangleFan

…which are the different element types that WebGL supports. Elements is the same as triangles, but we decided to keep it for now. If you’re into details, you can see that the GLOW.Elements have some new parameters – data, type and usage (more about usage in the next post).

2011+06+22

Benefits with GLOW

Several people have asked me why they should use GLOW when there’re a lot more competent libraries out there. It’s a good question, which I’ll try to answer here.

GLOW is a WebGL wrapper, so you’re flying very LOW over the GL – that’s where the name comes from. This also means that GLOW is not for beginners but for you with some experience of WebGL or OpenGL. It also means that it’s not a WebGL 3D framework (like Three.js). It’s just a wrapper.

Given that you have experience, you’re probably familiar with code looking like…

GL.useProgram( program );
GL.uniformMatrix4fv( viewMatrixLoc, false, viewMatrix );
GL.uniformMatrix4fv( projMatrixLoc, false, projMatrix );
GL.uniform1i( sampleLoc, 0 );
GL.activeTexture( GL.TEXTURE0 );
GL.bindTexture( GL.TEXTURE_2D, texture );
GL.enableVertexAttribArray(0);
GL.enableVertexAttribArray(1);
GL.enableVertexAttribArray(2);
GL.bindBuffer( GL.ARRAY_BUFFER, vertices );
GL.vertexAttribPointer( 0, 3, GL.FLOAT, false, 0, 0 );
GL.bindBuffer( GL.ARRAY_BUFFER, uvs );
GL.vertexAttribPointer( 1, 2, GL.FLOAT, false, 0, 0 );
GL.bindBuffer( GL.ARRAY_BUFFER, normals );
GL.vertexAttribPointer( 2, 3, GL.FLOAT, false, 0, 0 );
GL.bindBuffer( GL.ELEMENT_ARRAY_BUFFER, faces );
GL.drawElements( GL.TRIANGLES, 36, GL.UNSIGNED_SHORT, 0 );

This is pretty much the only way to draw something with WebGL – it’s designed this way. GLOW wraps this with a tiny overhead (most of which is the cache) and all you do is…

myShader.draw();

It’s in your shader code the magic happens and we think this is where you should spend your time. The shader data format is similar to the Three.js custom shader format – only slightly simpler, all to get you started within minutes…

var shaderData = {
  vertexShader: "...the vertex shader code...",
  fragmentShader: "...the fragment shader code...",
  data: {
    viewMatrix: new GLOW.Matrix4(),
    vertices: myFloat32ArrayWithVertices,
    ...and all other uniforms and attributes...
  }
  elements: myUint16ArrayWithElements
}

var shader = new GLOW.Shader( shaderData );
shader.draw();

GLOW comes with an extras library including matrices, vectors, hierarchies, geometry parsers and other helpful objects, all (most probably) working out of the box. As GLOW is just a wrapper, it’s compatible with all other WebGL libraries and can be used to extend these in all possible ways.

So, the benefits are:

  • You get close to WebGL without having to deal with the WebGL API
  • It’s very easy to create shaders
  • There are a lot of extras that helps you get going
  • It’s compatible with all other WebGL frameworks

Enjoy!

2011+06+14

Three.js and GLOW

One of the coolest features of GLOW is that you can use it in conjunction with all existing WebGL 3D frameworks out there. As I’ve worked a lot with Three.js and it’s one of the best, the examples here uses Three.js but could easily be transfered to other frameworks.

This time I wanted to explore how to use GLOW to make post-effects on a scene rendered by Three.js. It turned out to be quite easy, with one little exception.

You simply create an ordinary Three camera and scene with meshes and lights. Then you create your GLOW.Context like this…

var cntx = new GLOW.Context( { context: renderer.getContext() } );

The GLOW.Context can actually just take another, already created context and use that instead of creating a new one. This is key to making it work with other frameworks. Then you just create a new GLOW.FBO and a post-shader, as in the Hello FBO tutorial.

Now comes the tricky part: Three’s WebGLRenderer have an internal cache for shader programs, which you can’t invalidate. The problem is that we need to switch program to draw the post shader, and this program will be used in the next WebGLRender call, causing it to crash.

But there’s a trick, you can use the global GL-object and do the following…

var currentProgram = GL.getParameter( GL.CURRENT_PROGRAM );

…which will give you a render loop that looks something like…

myFBO.bind();
myGlowContext.cache.clear();
myGlowContext.clear();
myThreeRenderer.render( scene, camera );
var currentProgram = GL.getParameter( GL.CURRENT_PROGRAM );
myFBO.unbind();
myPostEffect.draw();
GL.useProgram( currentProgram );

You simply read back what program is currently loaded and put it back in when you’re done with your GLOW calls. A bit hackish, but it works.