The next step in my journey this summer will be to do some research into WebGL and figure out how I will structure my workflow and pipeline for the creation of this app. There are a few main questions that need answering:
1. How do I compile shaders in WebGL?
This is actually quite simple. As it turns out there are just a few simple steps to take: first you create the shader, then you define it’s source with a string, and finally compile.
[code lang=”javascript”]
var newShader = gl.createShader(type);
gl.shaderSource(newShader, source);
gl.compileShader(newShader);
[/code]
The type is either VERTEX_SHADER or FRAGMENT_SHADER, and then there is another couple of useful lines that allow you to display any errors while compiling:
[code lang=”javascript”]
status = this.gl.getShaderParameter(newShader, gl.COMPILE_STATUS);
if(!status)
{
console.log(this.gl.getShaderInfoLog(shader));
}
[/code]
I also learned about the WebGL program object, which contains various compiled shaders and can be activated at anytime to change the rendering pipeline. In WebGL, creating and linking a program looks something like this:
[code lang=”javascript”]
var newProgram = this.gl.createProgram();
this.gl.attachShader(nerwProgram, vert);
this.gl.attachShader(newProgram, frag);
this.gl.linkProgram(newProgram);
[/code]
and in the same way you can easily check if it succeeded:
[code lang=”javascript”]
status = this.gl.getProgramParameter(newProgram, this.gl.LINK_STATUS);
if(!status)
{
console.log(this.gl.getProgramInfoLog(newProgram));
}
[/code]
2. How will my algorithms create geometry / what does a buffer look like in WebGL?
WebGL seems to create and display geometry using buffers, similar to OpenGL
A buffer must be created, then bound before it can be edited. You can then pass arrays to the graphics card to be used in the buffer. A seperate buffer can be used for each item or an interleaved buffer can be used to store all data in the same buffer (positions, color, etc). I will setup my code to use all separate buffers, to simplify my process and ensure that data can be separated into STATIC_DRAW and DYNAMIC_DRAW so that any animations I have can run as fast as possible. The basic buffer creation looks something like this:
[code lang=”javascript”]
//get attribute location
var attribLoc = this.gl.getAttribLocation(program, attribute);
//create and bind buffer
var buffer = this.gl.createBuffer();
if(!buffer)
{
console.log("buffer creation failed");
return null;
}
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
//pass data to buffer
this.gl.bufferData(this.gl.ARRAY_BUFFER, data, drawType)
this.gl.enableVertexAttribArray(attribLoc);
this.gl.vertexAttribPointer(attribLoc, perVert, this.gl.FLOAT, false, 0, 0);
return buffer;
[/code]
3. How do I pass textures tot he graphics card in Javascript?
This process is fairly straightforward, it simply involves creating an image, binding it and then passing in the image data. The general process is as follows:
[code lang=”javascript”]
//create a new texture
var tex = this.gl.createTexture();
//bind texture and push in image
this.gl.bindTexture(gl.TEXTURE_2D, tex);
this.gl.texImage2D(this.gl.TEXTURE_2D, lod, colorType, this.gl.RGBA, gl.UNSIGNED_BYTE, img);
return tex;
[/code]
The internet is filled with tutorials and expamples of WebGL sites that use pre-existing WebGL libraries but no raw WebGL code. I found a wonderful resource with some simple code examples of raw WebGL by Nick Desauliners here.
Anther useful resource was some articles on WebGL fundamentals by ‘graggman’, they can be found here.
Having answered these questions, I feel that I am in a good position to start rendering simple geometry in WebGL. I think that sticking to a 2D simulation will help keep the project in scope and not over-complicate the process.