Documentation of the GFX.js library

The most recent GFX.js is here: https://rawgit.com/wolftype/200c/gh-pages/js/gfx_v02.js

        <script src = "https://rawgit.com/wolftype/200c/gh-pages/js/gfx_v02.js"></script>

The previous GFX.js is here: https://rawgit.com/wolftype/200c/gh-pages/js/gfx_v01.js

Recent Changes to the API

In gfx_v02.js I have renamed member variables of GFX.Frame in order to distinguish between:

  • Properties of a frame (.position, .orientation, and .size)
  • Transformations of those properties (.translate(), .rotate(), and .scale())

.scale(sx,sy,sz) is a function that changes the .size property.
.rotate(t,x,y,z) is a function that changes the .orientation property.
.translate(x,y,z) is a function that changes the .position property.

So if you were changing frame properties directly using:

  frame.rotation = ...
  frame.scale =  ...

instead use

  frame.orientation = ...
  frame.size = ...

Contents

Introduction

GFX.js is an ASAP (as-simple-as-possible) framework for experimenting with WebGL graphics.

Its goals are to be easy to use, minimally designed, and (hopefully) maintain backward compatibility when (only necessary) features are added. It is built to assist in introducing students to the modern, programmable OpenGL pipeline.

Keeping the code to under 2000 lines means it can be read (by you!) in full. Some assumptions were made in order to keep the code simple.

A current limitation is that the scene.draw(mesh) method assumes you are only using one shader. This will likely change, likely by adding a feature which allows meshes to have their own shaders attached to them.

Pipeline Overview

A GFX.Mesh has buffers of data (vectors, indices, colors, uv texture coordinates), settings for how to draw these by a GFX.Scene, and a GFX.Frame for specifying an object’s position, orientation, and size.

A GFX.Scene has a GFX.Shader for processing mesh data, a GFX.Camera used to create view matrix based on the camera’s GFX.Frame and a projection matrix based on its field-of-view and the width and height of the screen. A scene also has its own frame, and its own transformation GFX.MatrixStack.

A GFX.Frame is composed of a GFX.Vector position, a GFX.Quaternion orientation, and another vector representing size.

The HTML file

Below is a shell of a script for creating a WebGL application using GFX.

We will have to add code to the onInit and onRender methods of the GFX.App, as well as a vertex shader and fragment shader.

      <html>
      <script src = "https://rawgit.com/wolftype/200c/gh-pages/js/gfx_v02.js"></script>
      
      var app = new GFX.App();

      app.onInit() = function(){
      //initialize GL objects and buffers
      }

      app.onRender() = function(){
      //drawing routines
      }

      <script id = "gfxvert" type="text/glsl">
      //vertex shader code
      </script>

      <script id = "gfxfrag" type="text/glsl">
      //fragment shader code
      </script>
      
      <body onload = "app.start()">
      <canvas id = "gfxcanvas" width = "640" height = "480"></canvas>
      </body>
      </html>
      

GFX.App

GFX.App handles initialization of the webGL context, loads the scene’s shader from the scripts

Methods

  • .onInit(): Setup GL objects and buffers.
  • .onRender(): Called repeatedly by the animation loop.
  • .start(): Begins the program.

Members

  • .scene: A GFX.Scene
  • .canvas: The html canvas element to which we are rendering.

GFX.Scene

A GFX.Scene manages all the matrix information we need to transform our mesh data as it is sent over to the graphics card (GPU). It has its own frame of reference for rotating the scene, a camera for a stack of matrices to push, transform, and pop, and a shader to which all these matrices are sent, and which then processes mesh information.

  • The scene.camera enables you to move your view in 3D space.
  • The scene.matrix stack enables you to push and pop your transformation matrices, which can be rotated, translated, and scaled.
  • The scene.frame enables you to translate, rotate, and scale the whole scene.

It also controls the background color

Inside app.onRender() we will typically add the following code:

      app.onRender() = function(){
            var scene = this.scene;
            scene.begin();
                scene.draw(/*...myMesh...*/);
            scene.end();
      }
      

Methods

Members

  • .width: The width of the scene in pixels.
  • .height: The height of the scene in pixels.
  • .color: The background color (used in GL.clearColor).
  • .time: An incrementing counter.
  • .camera: A GFX.Camera for use in calculating the View matrix.
  • .shader: A GFX.Shader defined by you in your .html document.
  • .frame: A GFX.Frame which encodes a global translation-rotation-scale matrix.
  • .matrix: A GFX.MatrixStack for rotating, translating, and scaling in arbitrary order.

GFX.MatrixStack

GFX.Scene has a .matrix member which is a stack (i.e. a list) of matrices that enable us to compound transformations in interesting ways.

During scene.draw(), the last entry of this matrix is used as one of three matrices to calculate the model which is sent to the vertex shader.

The following code draws a circle of objects by manipulating the scene.matrix stack.

      app.onRender(){
            var scene = this.scene;
            scene.begin();
                
                  for (var i =0;i<=100; ++i){
                        var t = i/100;
                        scene.matrix.push();

                              scene.matrix.rotate(2*Math.PI*t,0,0,1);
                              scene.matrix.translate(2,0,0);

                              scene.draw(objA);

                        scene.matrix.pop();
                  }
            scene.end();
      }
      

For 100 iterations, we push the matrix stack, making a copy of the last matrix, rotate by an every increasing angle around the z axis, and translate by a fixed amount along the x axis, then we pop (discard) the matrix.

Compare that to the following code, where the push and pop happen outside the loop:

            app.onRender = function() {
                var scene = this.scene;
                scene.begin();
                    
                      scene.matrix.push();
                      for (var i =0;i<=100; ++i){
                            var t = i/100;
                            scene.matrix.rotate(8*Math.PI/100,0,0,1);
                            scene.matrix.translate(t,0,0);
                            scene.draw(mesh);            
                      }
                      scene.matrix.pop();

                scene.end();
            }
      

For 100 iterations, we rotate by a fixed angle around the z axis, and then translate by an ever increasing amount in that new coordinate system. Then we repeat. What shape does this make?

Methods

  • .push(): Copies the last entry in the stack and adds it to the stack
  • .set(m): Sets the last entry in the stack to be matrix m.
  • .translate(x,y,z): Multiplies the last entry in the stack by a transformation matrix.
  • .rotate(t,x,y,z): Multiplies the last entry in the stack by a rotation matrix.
  • .scale(sx,sy,sz): Multiplies the last entry in the stack by a scale matrix.
  • .pop(): Removes the last entry in the stack.

Members

  • .stack: A list of matrices

Calculating The Model

When drawing a Mesh in scene.draw(), the model transformation sent to the shader is computed as:

1 - $A_{meshFrame}$: The Mesh Frame’s position, orientation, and size, converted into a translation-rotation-scale (TRS) matrix (in that order).

2 - $A_{stack}$: The current (i.e. last) entry in the Scene’s matrix stack.

3 - $A_{sceneFrame}$: The Scene’s own frame, converted into a TRS matrix.

GFX.Mesh

A collection of buffers of 3D data and specifications for how to render it. The following code creates a mesh, loads vertex and index information into buffers, and draws the mesh to the screen:

      var mesh;

      app.onInit(){
           mesh = new GFX.Mesh();
           var vertices = [/*...coordinates...*/]; 
           var indices = [/*...index into coordinates...*/];
           mesh.load(vertices,indices);
      }

      app.onRender(){
            
            var scene = this.scene;

            scene.begin();
            scene.draw(mesh);
            scene.end();
      }
      

For now, one built-in Mesh is already included, GFX.Mesh.Frame, which can be used:

  var mesh; 
  app.onInit(){
        mesh = GFX.Mesh.MakeFrame();
  }

This creates the Mesh if it does not exist already, and returns a fresh copy if it does.

Methods:

  • .load(vertices,indices): Buffers Vertex and Index Data to the GPU
    - vertices is a list of 3D Vertex Coordinates.
    - indices is a list of integer indices into the vertex list.
    - If a list of indices is passed in then useElements is set to true.
  • .loadVertices(vertices, hint): Buffers Vertex Data only, with optional hint
    - hint is an optional value (GL.STATIC_DRAW, GL.STREAM_DRAW, or GL.DYNAMIC_DRAW)
  • .loadIndices(vertices, hint): Buffers Index Data only, with optional hint
    - hint is an optional value (GL.STATIC_DRAW, GL.STREAM_DRAW, or GL.DYNAMIC_DRAW)
  • .loadUV(texCoords,hint): Buffers Texture Coordinate Data to the GPU
    - texCoords is a list of 2D Texture Coordinates
    - hint is an optional value (GL.STATIC_DRAW, GL.STREAM_DRAW, or GL.DYNAMIC_DRAW) - Sets .useUV to true.
  • .loadColor(colors,hint): Buffers Color Data to the GPU
    - colors is a list of 3D Color values
    - hint is an optional value (GL.STATIC_DRAW, GL.STREAM_DRAW, or GL.DYNAMIC_DRAW) - Sets .useColor to true;

Members

  • .useElements: A boolean value specifying whether to call GL.DrawElements or GL.DrawArrays. If set to true, then when the mesh is drawn by scene.draw(mesh), the .indexBuffer is bound with GL.bindBuffer and then used to specify the order in which the vertices are drawn with GL.drawElements.
  • .useUV: A boolean value specifying whether to enable uv mapping. - If set to true, the “uv” attribute on the shader is enabled during rendering with GL.enableVertexAttribArray, the mesh’s.texBuffer is bound with GL.bindBuffer, and the attribute and buffer are bound with GL.vertexAttributePointer.
  • .useColor: A boolean value specifying whether to enable the “color” attribute on the shader. - If set to true, the “color” attribute on the shader is enabled during rendering with GL.enableVertexAttribArray, the mesh’s.colorBuffer is bound with GL.bindBuffer, and the attribute and buffer are bound with GL.vertexAttributePointer.
  • .vertexBuffer: A buffer of 3D Vector data.
  • .indexBuffer: A buffer of index data.
  • .texBuffer: A buffer of UV data.
  • .colorBuffer: A buffer of Color data.

GFX.Camera

Contains a frame of reference for calculating a view matrix, and some parameters for calculating a projection matrix.

GFX.Scene has a Camera.

The following code causes the scene’s camera to orbit around the origin, while always facing it.

      app.onRender(){
            
            var scene = this.scene;
            var t = scene.time;
            scene.camera.frame.position.set( 5 * Math.sin(t), 0, 5* Math.cos(t));
            scene.camera.setTarget( new GFX.Vector(0,0,0));
            scene.begin();
                  scene.draw(mesh);
            scene.end();
      }
      

Methods

Members

  • .frame: A GFX.Frame for position and orientation data. Used when calculating the view matrix in scene.begin(). Note that the camera looks along its negative z axis.
  • .fovy: The Field-of-View in degrees, used for calculating the Projection matrix.
  • .focalLength: Parallax merge point (used in 3D Stereoscopic rendering).
  • .eyeSep: Eye Separation (used in 3D Stereoscopic rendering).

GFX.Frame

A frame of reference with .position, .orientation, and .size member variables and .translate(), .rotate(), and .scale() methods to transform those variables.

GFX.Mesh has a frame.
GFX.Camera has a frame.
GFX.Scene has a frame.

The following code would animate your mesh by moving it, rotating it, and scaling it repeatedly.

            app.onRender(){
                  var scene = this.scene;
                  scene.begin();
                        mesh.frame.translate(/*...dx,dy,dz...*/);
                        mesh.frame.rotate(/*...dt,x,y,z...*/)
                        mesh.frame.scale(/*...dsx,dsy,dsz...*/)
                        scene.draw(mesh);
                  scene.end();
            }    
            

For frames, it is not important in which order these transformations are written in your code: the frame’s transformation is always converted into a matrix in TRS order:

For manipulating imagery with order-dependent coordinate system transformations, see the GFX.MatrixStack of GFX.Scene.

Features

The .orientation of Frames can be specified by setting it directly using the methods from GFX.Quaternion, or by using helper functions like setTargetZ which can lock a frame’s axis onto a target.

Frames can be interpolated between by using the static method GFX.Frame.FromTo which takes two Frames as parameters, and a scalar amount by which to interpolate between them.

Frames can be composed together with .mult(f), to create new Frames that are a composition of the two.

Methods

  • .matrix(): Calculates a Translation-Rotation-Scale matrix.
  • .translate(x,y,z): Moves the .position vector.
  • .rotate(t,x,y,z): Spins the .orientation quaternion by t radians around the global x,y,z axis.
  • .scale(x,y,z): Dilates the .size vector by x,y,z.
  • .x(): Get the local x axis GFX.Vector.
  • .y(): Get the local y axis GFX.Vector.
  • .z(): Returns the local z axis GFX.Vector.
  • .rotateX(t): Rotate t radians about the local x axis.
  • .rotateY(t): Rotate t radians about the local y axis.
  • .rotateZ(t): Rotate t radians about the local z axis.
  • .setTargetX(v): Set orientation so that local x axis points towards GFX.Vector v.
  • .setTargetY(v): Set orientation so that local y axis points towards GFX.Vector v.
  • .setTargetZ(v): Set orientation so that local z axis points towards GFX.Vector v.
  • .setTarget(v): Set orientation so that local z axis points towards GFX.Vector v while keeping local y axis as close to vertical as possible.
  • .mult(relFrame): Returns a new Frame by composing this one with a transformation relative to it.

Static Methods

  • GFX.Frame.FromTo(fa,fb, t): Returns a Frame whose position, orientation, and size is an interpolated value between fa and fb by amount t.

Members

GFX.Vector

A 3D Vector.

OpenGL is right-handed, so this means:

The positive z axis points towards you.
The positive y axis points up.
The positive x axis points right.

Vectors can be rotated using the .apply(v) method of GFX.Quaternion

      var v = GFX.Vector(1.2,4.7,3.2);
      var q = GFX.Quaternion.Rotation(Math.PI/2,0,1,0);
      var vp = q.apply(v);
      

Methods

  • .set(x,y,z): set values
  • .add(v): Return a new Vector by summing of coordinate values with Vector v
  • .sub(v): Return a new Vector by subtracting Vector v.
  • .mult(s): Return a new Vector by multiplying each coordinate value by s.
  • .divide(s): Return a new Vector by dividing each coordinate value by s.
  • .dot(v): Return the dot product with v.
  • .cross(v): Return the cross product with v.
  • .norm(): Return the length.
  • .unit(): Return the a new normalized vector.
  • .neg(): Return negative vector.

Members

  • .x: Coordinate along x axis;
  • .y: Coordinate along y axis;
  • .z: Coordinate along z axis;

GFX.Matrix

A 4x4 Matrix. Matrices in GFX are Row-Major, and so are transposed when sending values to the shader with shader.setUniformMatrix.

Methods

  • .mult(m): Returns new Matrix by multiplication with matrix m.
  • .multVec(v): Returns a new 4D Vector by multiplying with v.
  • .transpose(): Returns a new Matrix that by transposition.
  • .inverse(): Inverse of Matrix
  • .det(): Determinant of Matrix

Static Methods

  • GFX.Matrix.identity(): Identity
  • GFX.Matrix.translation(x,y,z): Translation by x,y,z
  • GFX.Matrix.rotation(angle,x,y,z): Rotation by angle radians about axis x,y,z.
  • GFX.Matrix.scale(x,y,z): Scale by x,y,z.
  • GFX.Matrix.perspective(fovy, ratio, near, far): Generate Projection from Symmetrical Frustum.
  • GFX.Matrix.frustum(l,r,t,b,near,far): Generate Projection from General Frustum.
  • GFX.Matrix.lookAt(eye,target,up): Generate View Matrix.

Members

  • .val: An array of 16 floating point numbers.

GFX.Matrix3

A 3x3 Matrix. Matrices in GFX are Row-Major, and so are transposed when sending values to the shader with shader.setUniformMatrix3. 3x3 matrices are only used for Normal matrices, and so multiplication methods are not provided (use GFX.Matrix instead).

Methods

  • .inverse(): Inverse of Matrix
  • .det(): Determinant of Matrix

Members

  • .val: An array of 16 floating point numbers.

GFX.Quaternion

A Quaternion represents a rotation in 3D. It can be used to transform a GFX.Vector and can be multiplied with other quaternions to compose rotations. The following code creates a quaternion that rotates a vector 90 degrees around the y axis:

      var v = GFX.Vector(1,0,0);
      var q = GFX.Quaternion.Rotation(Math.PI/2,0,1,0);
      var tv = q.apply(v);
      

Quaternions can be created by specifying:

  • An angle and an axis (GFX.Quaternion.AxisAngle, GFX.Quaternion.setAxisAngle, GFX.Quaternion.Rotation, GFX.Quaternion.setRotation)
  • Euler angles (GFX.Quaternion.Euler, GFX.Quaternion.setEuler)
  • a relative transformation from one vector to another (GFX.Quaternion.Relative, GFX.Quaternion.setRelative`)
  • a relative transformation from one quaternion to another (GFX.Quaternion.Slerp, GFX.Quaternion.setSlerp)
  • a z direction at and an [optional] y target direction vector (GFX.Quaternion.setForwardUp, GFX.Quaternion.setForwardUp)

A Quaternion is used to represent the .orientation of a GFX.Frame. It’s w,x,y,z elements should not be set directly, but rather with methods like .setAxisAngle and .setEuler.

      // set from euler angles
      frame.orientation.setEuler(yaw,pitch,roll);
      // set from angle and axis
      frame.orientation.setRotation(t,x,y,z);
      // set from relative transformation
      frame.orientation.setRelative(va,vb,t);
      

The following code interpolates an orientation in 3D:

      for (var i=0; i < 10; ++i){
            var t = i/10;
            var q = GFX.Quaternion.Slerp(qa,qb,t);
            frame.orientation = q;
      }
      

Methods

  • .setAxisAngle(v,t): Returns a rotation t radians around axis GFX.Vector v
  • .setRotation(t,x,y,z): Returns a rotation in t radians around axis x,y,z:
  • .setEuler(yaw,pitch,roll): Returns a rotation in Euler angles.
  • .setRelative(va,vb,t): Returns a rotation that takes vector va to vb, with t an amount from (0-1).
  • .apply(v): Returns a transformed position of GFX.Vector v.
  • .mult(q): Returns a new Quaternion encoding a transformation by q, followed by a transformation by this.
  • .matrix(): Returns a 4x4 GFX.Matrix encoding of the Quaternion. Used internally to calculate model matrices.
  • .scalarMult(s): Returns a new Quaternion multiplied by a scalar value s. Used internally to normalize quaternions.
  • .add(q): Returns a new Quaternion by summing the values of this and q. Used internallly in shorthand versions of .Slerp();

Static Methods

  • GFX.Quaternion.Slerp(qa,qb,t): A rotation of qa to qb, with t an amount from (0-1).
  • GFX.Quaternion.AxisAngle(v,t): A rotation of t radians around axis GFX.Vector v.
  • GFX.Quaternion.Rotation(t,x,y,z): A rotation t radians around axis x,y,z.
  • GFX.Quaternion.Euler(yaw,pitch,roll): A rotation in Euler angles.

Note on Euler angles: Here, we consider “y” to be up/down and “z” to be forward/back (in some physics references this is the opposite). -yaw: y axis rotation (“heading”) -pitch: x axis rotation (“attitude”) -roll: z axis rotation (“bank”)

GFX.Shader

Creates, Loads, compiles, attaches, links and binds vertex and fragment shader programs.

  var shader = new GFX.Shader();
  shader.program(vertCode,fragCode);

Methods

  • .program(vert,frag): Create a program from shader source code.
  • .create(): Creates a new program and new vertex and fragment shaders.
  • .load(vert,frag): Loads source text into vertex and fragment shaders.
  • .compile(): Compiles vertex and fragment shaders with and checks for errors.
  • .checkCompilation(): Checks for error when compiling.
  • .link(): Attach vertex and fragment shaders to program, links program, and check for linking errors.
  • .checkLinking(): Checks for error when linking.
  • .setUniformMatrix(uname, m): Set uniform 4x4 matrix uname to float array m.
  • .setUniformFloat(uname, f): Set uniform float uname to scalar value f.
  • .getAttribute(aname): Get location id of attribute named aname.
  • .enableAttribute(aname): Enable attribute named aname.
  • .pointAttribute(aname, n): Point n-dimensional attribute aname to currently bound buffer.
  • .printActiveAttributes(): Print out all active attributes to the javascript console.

GFX.Buffer

Creates, allocates, and loads mesh data (vertex coordinates, indices, uv coordinates, colors) onto the GPU.

Typically accessed via GFX.Mesh which has a bunch of Buffers.

Constructor

Creates and binds a new buffer

  var buffer = new GFX.Buffer(type)

with type either GL.ARRAY_BUFFER (default) or GL.ELEMENT_ARRAY_BUFFER or unspecified (in which case default is used).

Methods

  • .create(): Create a new buffer.
  • .bind(): Bind the buffer.
  • .alloc(size,hint): Allocate memory with size in bytes and hint.
    - hint is either GL.STATIC_DRAW, GL.STREAM_DRAW or GL.DYNAMIC_DRAW.
  • .data(d,offset): Sends data d to buffer’s offset position (default is 0).
  • .load(data, hint): binds, allocates, and sends data over to buffer.
  • .drawElements(mode,num): Draws coordinate data in currently bound array buffer by using indices in currently bound element array buffer. mode is either GL.LINES, GL.TRIANGLES, etc. num is an optional parameter specifying the number of elements in the index buffer (if unspecified, uses num set during data loading)
  • .drawArrays(mode,num): Draws coordinate data in currently bound array buffer. mode is either GL.LINES, GL.TRIANGLES, etc. num is an optional parameter specifying the number of elements in the array buffer (if unspecified, uses the number set during data loading)

Members

  • .num: Length of buffer (set during data() load)
  • .type: GL.ARRAY_BUFFER or GL.ELEMENT_ARRAY_BUFFER