[Home]OpenGL/WebGL

ec2-3-142-197-212.us-east-2.compute.amazonaws.com | ToothyWiki | OpenGL | RecentChanges | Login | Webcomic

Canvas element


WebGL? is accessed as a named Context property of the Canvas element.

    var canvas = document.getElementById?( "webgl-canvas" );
    glContext = canvas.getContext( "experimental-webgl" );

The webgl context contains a wrapper around most of the C OpenGL API.  It works in roughly the same way.

Matrices


Matrices are handled as simple 1D arrays of type Float32Array(...).  It is relatively easy to handle values as Javascript arrays, converting to the native format when interacting with OpenGL objects.

  /* Return an identity matrix */
  function identityMatrix() {
    return [ 1.0, 0.0, 0.0, 0.0,
            0.0, 1.0, 0.0, 0.0,
            0.0, 0.0, 1.0, 0.0,
            0.0, 0.0, 0.0, 1.0 ];
  }

  /* Return a rotation matrix */
  function rotateMatrix(a) {
    return [  Math.cos(a), Math.sin(a), 0.0, 0.0,
            -Math.sin(a), Math.cos(a), 0.0, 0.0,
                0.0,    0.0, 1.0, 0.0,
                0.0,    0.0, 0.0, 1.0 ];
  }

  /* This is the Orthographic Projection matrix */
  function projectMatrix( w, h, far, near ) {
    return [  2.0/w, 0.0,  0.0,            0.0,
              0.0,  2.0/h, 0.0,            0.0,
              0.0,  0.0,  2.0/(far-near), -1.0 * (far+near)/(far)-near,
              0.0,  0.0,  0.0,            1.0 ];
  }

Buffers


Lists of object vertices can be loaded into OpenGL buffers, ready for multiple reuse.  In the example, we abstract a list of vertices into a VertexBuffer? class:

  /**
  * The Vertex Buffer class encapsulates an array of vertices within WebGL?
  */
  function VertexBuffer?( glContext, vertices ) {

    /* Initialiser - Build a buffer and store the vertices */
    this.initialiser =
      function initialiser( vertices ) {
        this.vertexBuffer = this.glContext.createBuffer();
        this.glContext.bindBuffer( this.glContext.ARRAY_BUFFER, this.vertexBuffer );
        this.glContext.bufferData( this.glContext.ARRAY_BUFFER, new Float32Array( vertices ), this.glContext.STATIC_DRAW );
        this.vertexCount = vertices.length / this.getVertexSize?();
      };

    /* Retrieve the number of vertices */
    this.getVertexCount? =
      function getVertexCount?() {
        return this.vertexCount;
      };

    /* Return size of vertex */
    this.getVertexSize? =
      function getVertexSize?() {
        return 3;
      };

    /* Retrieve the OpenGl? buffer */
    this.getGlBuffer? =
      function getGlBuffer?() {
        return this.vertexBuffer;
      };

    /* Call the initialiser */
    this.glContext = glContext;
    this.initialiser( vertices );
  }

Shaders


As in C based OpenGL, shader programs consist of a Vertex Shader and Fragment Shader that are compiled from GLSL source.  By convention, shaders are encoded for delivery as <script> sections within the HTML DOM, but in reality these are just loaded straight into Javascript strings and passed to the compiler.

As with C based OpenGL, variables and vector lists are passed to the shader program by resolving variable names at run time.

In the example, a class is used to abstract the Shader APIs:

  /**
  * The Shader class encapsulates a shader program
  */
  function Shader( glContext, vertexShaderProgram?, fragmentShaderProgram? ) {

    /* Initialiser - Compiles and links shader [private] */
    this.initialiser =
      function initialiser( fragmentShaderProgram?, vertexShaderProgram? ) {
        this.fragmentShader = this.compileShader( fragmentShaderProgram?, glContext.FRAGMENT_SHADER );
        this.vertexShader  = this.compileShader( vertexShaderProgram?,  glContext.VERTEX_SHADER );

        this.shaderProgram  = glContext.createProgram();
        glContext.attachShader( this.shaderProgram, this.vertexShader);
        glContext.attachShader( this.shaderProgram, this.fragmentShader);
        glContext.linkProgram(  this.shaderProgram );

        if ( !glContext.getProgramParameter?( this.shaderProgram, glContext.LINK_STATUS ) ) {
          throw "Failed to link shader.";
        }
    };

    /* Create a Shader instance, and compile the supplied program [private method] */
    this.compileShader =
      function compileShader( program, programType ) {
        var shader = this.glContext.createShader( programType );
        this.glContext.shaderSource( shader, program );
        this.glContext.compileShader( shader );

        if ( !this.glContext.getShaderParameter?( shader, this.glContext.COMPILE_STATUS ) ) {
          throw "Failed to compile shader: " + this.glContext.getShaderInfoLog?( shader );
        }
        return shader;
      };

    /* Set a Uniform Matrix within the Shader by name */
    this.setMatrix =
      function setMatrix( name, matrix ) {
        this.glContext.uniformMatrix4fv( this.glContext.getUniformLocation?( this.shaderProgram, name ),
                                        false,
                                        new Float32Array( matrix ));
      };

    /* Retrieve an Attribute location from the Shader by name */
    this.getAttribute =
      function getAttribute( name ) {
        this.glContext.getAttribLocation?( this.shaderProgram, name );
      };

    /* Bind a Vertex buffer to the Shader by name */
    this.setVertexBuffer? =
      function setVertexBuffer?( name, vertexBuffer ) {
        this.glContext.enableVertexAttribArray?( this.getAttribute( name ) );
        this.glContext.bindBuffer( this.glContext.ARRAY_BUFFER, vertexBuffer.getGlBuffer?() );
        this.glContext.vertexAttribPointer?( this.getAttribute( name ), vertexBuffer.getVertexSize?(), this.glContext.FLOAT, false, 0, 0);
      };

    /* Select this Shader program */
    this.use =
      function use() {
        this.glContext.useProgram( this.shaderProgram );
      };

    /* Call the initialiser */
    this.glContext      = glContext;
    this.initialiser( fragmentShaderProgram?, vertexShaderProgram? );
  }

Putting it together


To display a triangle using the shader and vertexBuffer classes above, we define a shader program taking a set of vertices, and two matrices.

  var vertexShaderProg? =
          "  attribute vec3 vertexPosition;  \n"
        + "                                  \n"
        + "  uniform  mat4 rotationMatrix;  \n"
        + "  uniform  mat4 projectionMatrix; \n"
        + "                                  \n"
        + "  void main(void) {                \n"
        + "    gl_Position = projectionMatrix * rotationMatrix * vec4( vertexPosition, 1.0 );\n"
        + "  }                                \n"

  var fragmentShaderProg? =
          "  #ifdef GL_ES                    \n"
        + "  precision highp float;          \n"
        + "  #endif                          \n"
        + "                                  \n"
        + "  void main(void) {                \n"
        + "    gl_FragColor? = vec4(1.0, 0.0, 0.0, 1.0);\n"
        + "  }                                \n";

... some vertex data ...

  var triangle = [
        0.0,  1.0,  0.0,
        -1.0, -1.0,  -2.0,
        1.0, -1.0,  -7.0
  ];

... finally we create the main() function  to initialise and draw everything...


  /* Run the GL canvas */
  function main() {
    var canvas = document.getElementById?( "webgl-canvas" );
    var glContext = canvas.getContext( "experimental-webgl" );
    glContext.viewport( 0, 0, canvas.width, canvas.height );

    glContext.clearColor( 0.0, 0.0, 0.0, 1.0 );
    glContext.clearDepth( 1.0 );
    glContext.enable( glContext.DEPTH_TEST );
    glContext.depthFunc( glContext.LEQUAL );

    var vertexBuffer = new VertexBuffer?( glContext, triangle );

    var shader = new Shader( glContext, vertexShaderProg?, fragmentShaderProg? );
    shader.use();

    glContext.clear( glContext.COLOR_BUFFER_BIT | glContext.DEPTH_BUFFER_BIT );
    shader.setMatrix( "rotationMatrix",  rotateMatrix( 0.1 ) );
    shader.setMatrix( "projectionMatrix", projectMatrix( 2.0, 2.0, 10.0, 0.5 ) );
    shader.setVertexBuffer?( "vertexPosition", vertexBuffer );

    /* Draw triangle */
    glContext.drawArrays( glContext.TRIANGLES, 0, vertexBuffer.getVertexCount?() );
  }


Further resources


See http://learningwebgl.com/blog/?p=28 and http://www.khronos.org/webgl/

ec2-3-142-197-212.us-east-2.compute.amazonaws.com | ToothyWiki | OpenGL | RecentChanges | Login | Webcomic
This page is read-only | View other revisions | Recently used referrers
Last edited February 23, 2011 6:54 pm (viewing revision 4, which is the newest) (diff)
Search: