Jax v2.0.6 Released (and other good stuff)

With v2.0, Jax has finally progressed far enough that I can focus less on the framework itself and more on doing stuff with it.

First of all, I’d like to again tout its awesomeness. The framework was always designed with sheer productivity and application time-to-market at the forefront, but I never realized just how much time it saves. Now that it integrates seamlessly with Ruby on Rails, the things I’ve been able to knock out in the past few days alone have been staggering! The application that I’d previously hoped, optimistically, to enter beta in late January is now looking feasible by late December — and I only started coding it on the 11th!

Having said all that, Jax is admittedly not perfect. There is still room for improvement, and I’m constantly tackling bugs and considering feature improvements — now from the point of view of a person using the framework instead of someone developing it. This means I’m discovering all sorts of areas where Jax really could do better. Hence the rapidly-expanding list of objectives for v2.1.0!

Additionally, I’m shaking out the bugs by using Jax in ways I hadn’t originally planned around. I’ve tried to fix most of them as soon as they were discovered; check out the changelog for details!

As always, if you’ve found an issue you’d like to report or would just like to contribute some code, head on over to Github.

Upgrading

Thanks to Rails 3, upgrading Jax is a cinch (even if you’re using “vanilla” Jax, it uses Rails internally):

bundle update jax

All done!

Jax v2.0 Released!

It’s been two months to the day since my first experiment to see how Jax could be used with Ruby on Rails. Since then, the entire project has been revamped! It is now even more robust, making use of Rails directly and integrating with Rails apps seamlessly. Let’s take a breath, now, and check out an overview of the changes and new additions:

  • Lots of TLC for Rails applications. Rails v3.1 and above are officially supported.
  • No lack of love for those of you who prefer “vanilla” Jax. If you just need to build a static WebGL application, you can do so with no change in your existing workflow.
  • Jax now understands CoffeeScript! By default, if the CoffeeScript gem can be found in the bundle, Jax will generate CS code. If the gem can’t be found, Jax will fall back to standard JavaScript generation automagically.
  • A new development suite has replaced the old interface. It splits the runtime and test suites into two separate sections, since the previous approach of merging them both into the same page invariably ran into performance problems. It also adds a third section, in which developers can test drive their materials in isolation from the rest of the application.
  • The runtime section, where the WebGL application is run in its entirety, can be configured to point to any page within the Jax application. This allows you to test drive it such that it behaves exactly as it will in the field.
  • All of the guides have been updated to reflect the more minor changes in the framework, and the Getting Started guide has been updated to include how to get started in a Rails application.
  • All of the Jax generators now tie directly in with the Rails generator system. They can even be executed with the `rails` command, or executed with the `jax` command for both backward compatibility and as a short-cut so that you don’t need to add the Jax namespace to Rails commands.
  • Jax no longer precompiles “jax.js”. It is now integrated directly into your application’s JavaScript code. The major benefit to this is that there are fewer requests required to load your application, and thus a shorter load time.
  • The task of packaging your application just got better. Jax will now minify the JavaScript source files it produces when you are getting ready to run it in production. This is one of the many benefits that comes “for free” by letting Rails play a more influential role in how Jax works at the lowest levels.

As you can see, a lot of work has gone into this release. Expect more posts in the near future that will overview how to make the nuances of Jax work for you.

In the meantime, you should take a look at the Getting Started Guide if you haven’t done so already! It’s been updated to reflect Jax v2.0.

If you’d rather see Jax in action, check out the live demos page.

As always, if you have any questions or comments, feel free to leave them on the forum. Issues can be raised at the issue tracker on Github.

If you’d like to get involved with Jax development, head on over to the respository at Github!

 

Upgrading

For those of you using Jax v1.x, there are a few steps you’ll need to take in order to make the upgrade happen:

With Rails

Follow these instructions if you are developing Jax and are using Ruby on Rails:

  1. Add Jax to the Rails Gemfile:
    gem “jax”, “~> 2.0″
  2. Install the bundle:
    bundle install
  3. Run the Jax install generator:
    rails generate jax:install
  4. Scroll down.

Without Rails

Follow these instructions if you are developing Jax and not using Ruby on Rails:

  1. Install the new Jax gem:
    gem install jax -v 2.0
  2. Generate a brand-new Jax application:
    jax new application_name
  3. Scroll down.

Either Way

Regardless of whether you are or aren’t using Rails, follow these instructions after generating the new application:

  1. Copy all app/controllers/ files from the old application into app/assets/jax/controllers/ in the new one. Delete or overwrite the new application controller.
  2. Copy all app/helpers/ files from the old application into app/assets/jax/helpers/ in the new one. Delete or overwrite the new application helper.
  3. Copy all app/models/ files from the old application into app/assets/jax/models/ in the new one.
  4. Copy all app/resources/ files from the old application into app/assets/jax/resources/ in the new one.
  5. Copy all app/views/ files from the old application into app/assets/jax/views/ in the new one.
  6. Copy all app/shaders/ files from the old application into app/assets/jax/shaders/ in the new one.
  7. In the new application, rename all app/assets/jax/shaders/*.ejs files so that their extension is glsl instead of ejs. (Example: common.ejs => common.glsl)
  8. In the new application, rename all app/assets/jax/resources/*.yml files so that their extension is resource instead of yml. (Example: teapot.yml => teapot.resource)
  9. Copy all public/ files from the old application into public/ in the new one.
  10. Copy all spec/javascripts/ files from the old application into spec/javascripts/jax/ in the new one. Afterward, delete the spec/javascripts/jax/support folder.
  11. If you have any plug-ins installed in the old application, install them again in the new one.

Deprecations

If your old code has a lot of //= require‘s in them (controllers were generated with them by default), then the require path is now relative to app/assets/jax. For instance, to require the ApplicationController (which is no longer necessary, but as an example) the path would be “controllers/application_controller” instead of just “application_controller”.

If you have written your own shaders, the setUniforms and setAttributes functions within the material.js file were generated with calls to $super. Remove this call, and also remove $super from the functions’ argument lists.

Jax on Rails

Come closer, and I’ll let you in on a little secret. Going all the way back to the first drafts of the WebGL specification, one of my major long-term goals has been to bring WebGL to Ruby on Rails. Each iteration has brought me closer to realizing that dream.

Jax was not originally intended to be the incarnation of the Rails adapter I’ve been looking for. The way Jax is written today, it can’t interface directly with Rails applications, and trying to force it into doing so would, in all likelihood, end in catastrophe. Jax was more an attempt to bring Rails-like productivity into the JavaScript world, with particular emphasis on WebGL.

However, if you’ve ever taken a look at the Jax internals, you’ve undoubtedly seen numerous similarities to the Rails backend. Indeed, the Jax gem actually relies on railties, one of the main dependencies of Rails itself.

Fanboy though I may be, these similarities did not arise out of a blind adherence to any “Rails or bust” philosophy. Jax is written the way that it is because the railties system actually implements the vast majority of what Jax itself requires out of necessity. It sets up load paths; finds source files and provides hooks into managing them; interfaces with plugins; and is modular enough to coexist with other Rubygems that might be able to add more to the Jax experience. Why reinvent the wheel?

Still, though, in the back of my mind has always been that dream. WebGL in Rails today is not by any means an impossibility, but it’s not very Rails-like, either. A modular, extensible, MVC-based WebGL framework running in Rails does not exist today, and that is the void I’d like to eventually fill.

As it turns out, “eventually” isn’t all that far away. I’ve spent the whole of the last week experimenting with Rails 3.1, the new asset pipeline it introduces, and Jax. It’s taken a significant development effort (read: a complete rewrite!) of the Ruby side of Jax, but the result is nothing short, in my humble opinion, of impressive.

The best part is that even with the new structure, Jax still offers the ability to write static applications completely outside of Rails! This is a big deal to me, because I want people who don’t want to use Rails (for whatever reason) to keep being able to use Jax, as they are today.

At this point, it’s safe to say that Rails integration is inevitable, and it’s going to happen soon. The only thing I can’t decide on is whether it’s going to be in Jax v2.0 or Jax v1.2.

There’s lots more going on than “just” Rails integration, but that’s all I’ve got time to talk about right now. If you’d like to follow my progress, (or help me along), see the rails31 branch on Github!

Tutorial: BSP Trees in JavaScript and WebGL

The complete source code for this project is available on Github. The project uses Jax, which defines the Triangle, Plane and matrix functions. Note that this tutorial does not require you to use Jax yourself, provided you have implementations of those functions.

Today’s JavaScript engines are dramatically faster than they were even a few years ago, but they still have a long way to go. WebGL applications can’t afford to sacrifice even a few milliseconds; if you can gain them, you need to do so in any way possible.

One of the major techniques introduced in DOOM in 1993 was the application of binary space partitioning, or BSP, trees. These allowed the engine to predict with consistent accuracy which geometry was going to be rendered to the screen before the rendering actually took place. If the engine didn’t need to render a particular set of geometry, it could completely omit it from the rendering phase. This saved a huge amount of time.

The performance issues of JavaScript-based graphics engines today aren’t entirely different from the same issues of machines in the early 1990s. CPU speed is a major bottleneck; in fact, the JavaScript interpreter is generally far slower than the graphics processor, and the vast majority of your bottlenecks are going to be here — on the CPU.

BSP trees work by splitting the geometry to be rendered into two sections. Each section has a bounding box associated with it, which occupies half of the total area of the BSP. The geometry is then split again, with each half of the BSP containing two more halves, and so on. The last level of the BSP tree contains leaf nodes, which are the actual objects to be processed.

In this implementation, we’ll continue subdividing the tree until we have bounding boxes which only contain a single triangle each. It’s worth noting that this is usually not ideal for rendering in WebGL (in which case it’s usually best to stop on a per-object basis), but it’s very helpful for accurate collision detection, which usually involves figuring out exactly which triangles are intersecting.

In googling for other implementations, I found that most BSPs are constructed in a top-down manner. In other words, you start with the root node and work your way down to the individual leaf nodes. However, I decided to try something a bit different with my tree.

A particular sticking point in generating top-down BSP trees is how to efficiently divide the node to create two new sub-nodes. Intuition might suggest simply dividing the node down the center, but this is often insufficient. If most of your triangles are in one half and only a few are in the other half, then dividing them down the center will result in a huge waste of CPU power in each frame as you iterate through empty or nearly-empty BSP nodes.

Another approach is to iterate through each triangle in the scene, decide how many triangles lie in front of and behind its plane, and choose the one that balances the node most appropriately. I’m concerned with this approach, however, due to the inherent slowness of JavaScript interpreters today. At a minimum, this approach would require the BSP to iterate through the number of triangles in the scene squared, and do so again at each level of the BSP. I believe the majority of sizable 3D scenes would cause the browser to hang using this approach, making it unacceptable for any 3D scene that is large enough to actually make use of a BSP tree in the first place.

Instead, I opted for a completely different solution: a bottom-up algorithm that starts with the leaf nodes (the triangles) and moves upward toward a single root node. This allows us to completely skip choosing a dividing plane; all we have to do is choose two nodes from a pool of nodes and recurse upward from there. If we choose nodes that are very close to each other, our leaf nodes will be tightly packed together, resulting in a BSP tree that is very efficient all the way up to its root.

This approach may not be well suited to other languages like C, but as you’ll see, JavaScript certainly has no issue with building the tree in such a dynamic manner.

Assumptions

Before we jump into some code, I’m going to assume you have some basic supporting objects in place, namely Triangle, Plane, and Box. (If not, you can get implementations of each of these from the source code for this project, linked to at the top of this article.) Their signatures look like this:

new Plane([a, b, c]):

        If a, b, and c are given, they are passed to #set.

        Otherwise, a plane whose extents are undefined is created.

        set(a, b, c):

                resets this plane according to the vertices

        whereis(point):

                returns whether the given point is in FRONT, BACK or

                INTERSECT-ing the plane

new Triangle([a, b, c]):

        If a, b, and c are given, they are passed to #set.

        Otherwise, a triangle whose extents are undefined is created.

        set(a, b, c):

                sets up a triangle from the given 3 vertices

        center:

                a vec3 assigned by #set(a,b,c) representing the

                calculated center of this triangle

new Box(position, size):

        Creates an axis-aligned bounding box (AABB) with the given

        position (a vec3) and size (also a vec3).

        intersectOBB(other_box, transform):

                Tests the other box with this one as an oriented

                bounding box (OBB). Uses the given matrix to transform

                the other box into the coordinate space of this one.

In addition to these, I’m assuming you are making use of a matrix library like glMatrix. I’ve also added the following new functions to glMatrix, which you can feel free to copy-and-paste for convenience:

/**

 * vec3.min(a, b[, dest]) -> vec3

 * – a (vec3): first vector

 * – b (vec3): second vector

 * – dest (vec3): optional destination vector

 *

 * Stores the minimum value for each element of a and b

 * within dest. If dest is omitted, a new vec3 is created.

 **/

vec3.min = function(a, b, dest) {

        if (!dest) dest = vec3.create();

        dest[0] = Math.min(a[0], b[0]);

        dest[1] = Math.min(a[1], b[1]);

        dest[2] = Math.min(a[2], b[2]);

        return dest;

};

/**

 * vec3.max(a, b[, dest]) -> vec3

 * – a (vec3): first vector

 * – b (vec3): second vector

 * – dest (vec3): optional destination vector

 *

 * Stores the maximum value for each element of a and b

 * within dest. If dest is omitted, a new vec3 is created.

 **/

vec3.max = function(a, b, dest) {

        if (!dest) dest = vec3.create();

        dest[0] = Math.max(a[0], b[0]);

        dest[1] = Math.max(a[1], b[1]);

        dest[2] = Math.max(a[2], b[2]);

        return dest;

};

Now that we’ve gotten those formalities out of the way, let’s start building a BSP!

We’ll store the resultant function in a variable called, creatively, BSP:

var BSP = (function() {

        /* CODE GOES HERE */

})();

This code creates a temporary function, immediately calls it, and then assigns the return value of the function to the BSP variable. This gives us the flexibility of defining “private” helper functions that can only be used internally within the BSP object.

We will define two such helper functions: one to build the tree from the bottom up, and another for calculating a bounding box around a single triangle. First I’ll show the functions in their entirety, and then I’ll explain them line-by-line.

The buildLevel Function

// +level+ is an array, containing either Triangles or BSP nodes.

// This function replaces every 2 elements in the array with a single

// parent BSP node. The array is modified in-place and the size of the

// array will be cut in half, to a minimum of 1.

function buildLevel(level) {

  var nextLevel = [];

  var plane = new Jax.Geometry.Plane();

  while (level.length > 0) {

    var front = level.shift(), back = null;

    var dist = vec3.create();

    var closest = null, closest_index;

     

    var result = front;

    if (level.length > 0) {

      for (var j = 0; j  level.length; j++) {

        var len = vec3.length(

          vec3.subtract(front.center, level[j].center, dist));

        if (closest == null || closest > len) {

          closest = len;

          closest_index = j;

        }

      }

      back = level[closest_index];

      level.splice(closest_index, 1);

      // See if back and front are accurate. If not, swap them.

      // If triangle, use the plane created by the current triangle.

      // If node, use the first triangle in the box for a plane.

      if (front instanceof Jax.Geometry.Triangle)

        plane.set(front.a, front.b, front.c);

      else {

        var tri = front.front;

        while (tri instanceof BSP) tri = tri.front;

        plane.set(tri.a, tri.b, tri.c);

      }

       

      if (plane.whereis(back.center) == Jax.Geometry.Plane.FRONT)

        result = new BSP(back, front);

      else result = new BSP(front, back);

    }

     

    nextLevel.push(result);

  }

   

  for (var i = 0; i  nextLevel.length; i++)

    level.push(nextLevel[i]);

}

The buildLevel function is the meat of the BSP tree, and is responsible for building up the tree hierarchy, so it’s important that you understand what it’s doing. Let’s go through it a few lines at a time.

  var nextLevel = [];

  var plane = new Jax.Geometry.Plane();

We’re creating a few local variables to act as buffers. The nextLevel array contains the parent nodes we’re about to create; we don’t want to stick them right back into level just yet because level has to reach an empty state in order for our function to execute properly.

The plane variable will be used to check whether a given triangle or BSP node is in front of or behind another.

  while (level.length > 0) {

    var front = level.shift(), back = null;

Here we’re starting a loop that won’t end until we’ve exhausted the entire level array. Once within the loop, the first thing we do is shift the first element out of the array and store it in the front variable. We’re also creating a back variable; for now we’re just setting it to null.

    var dist = vec3.create();

    var closest = null, closest_index;

We’ll use the dist variable to check the distance from the front element to all other elements, and we’ll use the closest and closest_index variables to make a note of the closest elements.

    var result = front;

    if (level.length > 0) {

      for (var j = 0; j  level.length; j++) {

        var len = vec3.length(

          vec3.subtract(front.center, level[j].center, dist));

        if (closest == null || closest > len) {

          closest = len;

          closest_index = j;

        }

      }

Here’s where things start to get interesting, and maybe a bit confusing. We’re creating yet another variable called result. The result will ideally be a parent instance of BSP, but we don’t want to create parents that have only 1 child, because this would just make the BSP tree slower to traverse. If the parent is only going to contain a single child, then the parent’s dimensions are going to be equal to the dimensions of the child, and it’s faster to optimize the parent out of the equation. Therefore, we’re initially setting result to the child front element.

Next, we’re making sure the level array isn’t empty yet. This is necessary because the previous call to shift may have emptied the array; we have no guarantee that the number of triangles (or BSP nodes) is divisible by 2, so we need to be aware of that possibility.

Assuming the level array isn’t empty, we’ll iterate through all of its elements. Each time we find an element closer to front than the previous, we store its distance and the array index of the element itself.

      back = level[closest_index];

      level.splice(closest_index, 1);

At this point, we have a front element and we’ve noted the closest element to it in the array. We’re going to assign the closest element to the back variable, and then remove it from the array using splice.

It’s important to note that the names front and back are, at this point, misnomers. We have no guarantee that they are actually the front and back elements; the only thing we know is that they were two elements from the same soup, and that they are closer to each other than they are to any other element.

      if (front instanceof Jax.Geometry.Triangle)

        plane.set(front.a, front.b, front.c);

      else {

        var tri = front.front;

        while (tri instanceof BSP) tri = tri.front;

        plane.set(tri.a, tri.b, tri.c);

      }

       

In order for the BSP tree to be truly effective, we want to make front and back correspond to true “front” and “back” elements. That’s what the above code does.

First, we need to check whether we’re currently working with a Triangle or a BSP node. If the former, the plane is very simply constructed from the triangle’s 3 vertices.

If, however, we’re dealing with a BSP node, we need to find a plane within the BSP node to test against. I don’t think it matters which node we select at this point, so I just selected the front-most triangle using a while loop. The loop exits as soon as it encounters a node which is not a BSP; it is assumed to be a Triangle, and the plane is set from those vertices.

      if (plane.whereis(back.center) == Jax.Geometry.Plane.FRONT)

        result = new BSP(back, front);

      else result = new BSP(front, back);

The last step to constructing the parent node is to test whether the second element, stored in back, is in front the plane. Since the plane is itself assumed to correspond to the front element, we must ensure that the back element is indeed behind the plane.

This condition simply performs that test; if the back element tests to be in front of the front plane, then we’ve got the two reversed, and we just switch the order of the elements so that back is front and front is back.

If the condition fails, then our ordering is correct and we construct the parent as planned.

It’s important to make a distinction here. Traditional BSP trees also test for an intersect result from the plane. If the plane intersects a triangle, the BSP should probably consider splitting it into two triangles and adding the new triangles to the array before starting again. I don’t do this here for a number of reasons:

  1. JavaScript. Adding more triangles is going to add more BSP nodes and reduce overall efficiency, because it is inherently much slower than its C code counterpart.
  2. WebGL. If the BSP is to be used for rendering, your leaf nodes will likely be entire objects, not individual triangles, because the triangles will be grouped together into Vertex Buffer Objects (VBOs). It makes no sense to split triangles if they have to be rendered together anyway.
  3. For collision detection, it makes even less sense to split triangles because the front/back test can afford to be less accurate. During collision detection, we’re generally more interested in whether the bounding cubes intersect than we are the order of intersection. It’s a nice-to-have, but not necessarily a must-have.

  4. There are only 2 major reasons for splitting polygons in this manner:
  1. If you’re completely skipping use of the Z buffer, which was the story with DOOM. Back in the early ‘90s, depth buffer tests were expensive to perform, and DOOM had to avoid them wherever possible. Splitting polygons allowed polies to overlap each other at odd angles without causing depth-related rendering glitches.
  2. If you’re performing alpha blending, in which case you want to ensure that the back-most polygons are always drawn first or else the blending won’t come out right. However, going back to the WebGL argument above, you’re likely going to be rendering an entire object at one time (in which case you can’t dynamically control the order triangles appear in), so this argument breaks down.

With that, let’s move on to the remainder of the function:

    }

     

    nextLevel.push(result);

  }

   

  for (var i = 0; i  nextLevel.length; i++)

    level.push(nextLevel[i]);

}

This last chunk of code is pretty simple; we close out the condition we started earlier, push the result (which is now either a parent BSP or the last element in the level array) into the local nextLevel array, and close out the while loop.

The last thing this function does is iterate through nextLevel and push its contents into the now-empty level array so that the original array can be used in a loop.

The calcTriangleDimensions Function

  // Calculates the dimensions of a bounding box around

  // the given Triangle. If the triangle is axis-aligned,

  // one of the dimensions will be 0; in this case,

  // that dimension of the bounding box will be set to a

  // very small positive value, instead.

  function calcTriangleDimensions(tri) {

    var result = vec3.create();

    var min = vec3.create(), max = vec3.create();

    vec3.min(vec3.min(tri.a, tri.b, min), tri.c, min);

    vec3.max(vec3.max(tri.a, tri.b, max), tri.c, max);

    min_size = Math.EPSILON * 2;

    for (var i = 0; i  3; i++) {

      result[i] = max[i] - min[i];

      if (result[i]  min_size) result[i] = min_size;

    }

    return vec3.scale(result, 0.5);

  }

Leaf nodes in the BSP tree are triangles. However, its immediate parents will wrap around the triangle and need some information about the dimensions of the triangle in order to form an accurate bounding box around it. That’s what this function takes care of.

    var result = vec3.create();

    var min = vec3.create(), max = vec3.create();

    vec3.min(vec3.min(tri.a, tri.b, min), tri.c, min);

    vec3.max(vec3.max(tri.a, tri.b, max), tri.c, max);

First we create some local variables to work with, all of which are vec3s, and then we store within them the maximum and minimum extents of the triangle. Together, these extents describe a bounding box.

    min_size = Math.EPSILON * 2;

    for (var i = 0; i  3; i++) {

      result[i] = max[i] - min[i];

      if (result[i]  min_size) result[i] = min_size;

    }

To get the dimensions of the bounding box without its world-space position, we subtract the minimum extents from the maximum extents.

There’s an additional consideration, however: if the triangle is axis-aligned, it will have a height, width or depth equal to 0. The problem is, if we create a bounding box with a dimension of 0, it’ll be impossible for that box to intersect another! In order to work around this caveat, here we program a special case to handle a near-0-dimension triangle. If the size in any of the 3 dimensions is less than some very small value (called epsilon), we simply set it to that value. It’s multiplied by 2 to account for the final line in the function:

    return vec3.scale(result, 0.5);

Here we simply return half of the size of the triangle. Each node of the BSP tree is defined with a center point, and a half-dimension.

The BSP Object

Now we need to create a constructor which, when instantiated, will make use of these helper functions to build and traverse the BSP tree:

var bsp = function(front, back) {

  this.front = null;

  this.back = null;

  this.triangles = [];

  if (front || back) this.set(front, back);

};

/* MORE FUNCTIONS HERE */

return bsp;

Before we go further, note that we’re returning the bsp object. This wraps up our anonymous function and assigns the bsp object to the BSP variable that we defined at the beginning of this tutorial. This allows BSP to be instantiated directly, like so:

var myBSP = new BSP(front, back);

This very simple constructor merely creates a few variables and an array to hold triangles as they are added to the BSP tree. If the node was constructed with a front and/or back element, they are passed into the set() function, which we’ll go over next:

bsp.prototype.set = function(nodeFront, nodeBack) {

  this.front = nodeFront;

  this.back = nodeBack;

  this.center = vec3.create();

     

  var c = 0;

  if (nodeFront) {

    vec3.add(this.center, nodeFront.center,this.center);

    c++;

  }

  if (nodeBack) {

    vec3.add(this.center, nodeBack.center, this.center);

    c++;

  }

  if (c > 0) vec3.scale(this.center, 1.0 / c);

     

  var halfSize = this.calcHalfSize();

  var boxPosition = vec3.subtract(this.center, halfSize, vec3.create());

  var boxDimensions = vec3.scale(halfSize, 2, vec3.create());

  this.box = new Box(boxPosition, boxDimensions);

};

The set() function is responsible for storing the front and back nodes, and then recalculating its center property, which is done by taking the average of the centers of this node’s children. It also recalculates the half-size of this node by calling calcHalfSize() and then rebuilds the bounding box for this node.

bsp.prototype.getHalfSize = function() {

  return this.halfSize || this.calcHalfSize();

};

This very simple function simply returns the half-size of this node without recalculating it; an exception is if the half-size hasn’t been calculated yet, in which case it calls calcHalfSize().

bsp.prototype.calcHalfSize = function() {

  this.halfSize = this.halfSize || vec3.create();

  var min, max;

     

  function calcSide(side) {

    var size, cmin, cmax;

    if (side instanceof BSP) size = side.getHalfSize();

    else size = calcTriangleDimensions(side);

    cmin = vec3.subtract(side.center, size, vec3.create());

    cmax = vec3.add(side.center, size, vec3.create());

    if (min) {

      vec3.min(min, cmin, min);

      vec3.max(max, cmax, max);

    } else {

      min = vec3.create(cmin);

      max = vec3.create(cmax);

    }

  }

     

  if (this.front) calcSide(this.front);

  if (this.back)  calcSide(this.back);

     

  vec3.subtract(max, min, this.halfSize);

  vec3.scale(this.halfSize, 0.5);

  return this.halfSize;

};

The calcHalfSize() function looks more daunting at first glance than it really is; all it does is get the minimum and maximum extents of each sub-node, and then calculate the minimum and maximum extents of both nodes combined. By subtracting the minimum from the maximum, we’re left with the overall size of the node; scaling that down by half yields the half-size, and we’re done.

bsp.prototype.getTreeDepth = function() { return this.treeDepth; };

The getTreeDepth() function simply returns the maximum depth of the tree starting from the current node, which is calculated by the finalize() function.

bsp.prototype.addTriangle = function(triangle) {

  this.triangles.push(triangle);

};

The addTriangle() function simply adds the given triangle to the list of triangles. If you’re using something other than triangles (for instance, an entire vertex buffer object), youll want to add a function to correspond with whatever you plan to use. You’ll also want to tweak the other triangle-related functions to taste.

bsp.prototype.finalize = function() {

  var level = [];

  for (var i = 0; i  this.triangles.length; i++)

    level.push(this.triangles[i]);

  this.treeDepth = 1;

  while (level.length > 2) {

    buildLevel(level);

    this.treeDepth++;

  }

  this.set(level[0], level[1]);

  this.finalized = true;

};

This function, finalize(), is the last function which will be called when we are constructing a BSP tree. It builds a single, flat level of triangles, then starts a loop. Until the list of triangles has length 2 or less, the helper function buildLevel() is called repeatedly on the list. By the time the list is complete, it’s guaranteed to only have a maximum of 2 elements. We don’t really care whether those elemenst are Triangles or BSP nodes, as all of the special handling is taken care of elsewhere.

Finally, the finalize() function calls set() with the remaining elements in the array, thus making this instance of BSP the ultimate root node. A further optimization might be to check whether level has one or two elements; if it only has one, then we can remove it and assume its children, thus making the tree one node smaller and that much quicker to traverse.

Traversing the Tree

Now that we have a BSP tree, we need to think about how to traverse it. Each node has at most two sub-nodes, front and back, associated with it. That means that if we have a point in space, we can always tell which direction to traverse first: the one closest to the point. In this way, we can guarantee that all of our objects are rendered back-to-front by first traversing the tree down to its leaf nodes, and then rendering as the stack unravels. Here’s an example:

/**

 * BSP#traverse(point, renderCallback) -> undefined

 * – point (vec3): the position of the camera, used for polygon sorting

 * – renderCallback (Function): a callback function to call with each

 *                              leaf node as an argument

 *

 * Traverses the BSP tree using the given point as a reference; leaf

 * nodes will be sent to the +renderCallback+ function in back-to-front

 * order.

 **/

bsp.prototype.traverse = function(point, renderCallback) {

  // handle the (hopefully infrequent!) special

  // case of having only 1 child

  if (!this.front || !this.back) {

    var result = this.front || this.back;

    if (result instanceof BSP) result.traverse(point, callback);

    else renderCallback(result);

    return;

  }

     

  // find the distance from front to point, and from back to point

  var dist = vec3.create(), frontLen, backLen;

  vec3.subtract(this.front.center, point, dist);

  frontLen = vec3.dot(dist, dist);

 

  vec3.subtract(this.back.center, point, dist);

  backLen = vec3.dot(dist, dist);

     

  if (frontLen  backLen) {

    // closer to front, traverse back first

    if (this.back instanceof BSP) this.back.traverse(point, callback);

    else renderCallback(this.back);

       

    if (this.front instanceof BSP) this.front.traverse(point, callback);

    else renderCallback(this.front);

  } else {

    // closer to back, traverse front first

    if (this.front instanceof BSP) this.front.traverse(point, callback);

    else renderCallback(this.front);

    if (this.back instanceof BSP) this.back.traverse(point, callback);

    else renderCallback(this.back);

  }

};

This is the simplest example I could think of to demonstrate the approach; however, simplicity adds waste, and there are quite a few optimizations that could be made to it. Most notably, it’s a bad idea to recursively call functions during a render pass in JavaScript, because there’s a significant amount of overhead created by function calls. To keep the function calls to a minimum, this should be expanded into a flat loop using some sort of stack. That’s the approach I took in my collision detection algorithm, demonstrated below:

/**

 * BSP#collide(other, transform) -> Boolean | Object

 * – other (BSP): the potentially-colliding BSP model

 * – transform (mat4): a transformation matrix which is used to convert

 *                     +other+ into this BSP’s coordinate space.

 *

 * Applies the given transformation matrix to +other+; if any triangle

 * within +other+ is intersecting any triangle in this BSP tree, then

 * a generic object containing the properties +first+, +second+ and

 * +second_transformed+ is returned. They have the following meanings:

 *

 * * +first+ : the colliding triangle in this BSP tree

 * * +second+: the colliding triangle in the +other+ BSP tree

 * * +second_transformed+: a copy of the colliding triangle in the

 *                         +other+ BSP tree, transformed by the matrix

 *                         to be in this BSP tree’s coordinate space.

 *

 * If no collision has occurred, +false+ is returned.

 *

 **/

bsp.prototype.collide = function(other, transform) {

  if (!this.finalized) this.finalize();

  if (!other.finalized) other.finalize();

 

  // buffer checks for GC optimization

  var checks = this.checks = this.checks || [{}];

  var check_id = 1;

  checks[0][0] = this;

  checks[0][1] = other;

  var tri = new Jax.Geometry.Triangle(),

      a = vec3.create(), b = vec3.create(), c = vec3.create();

 

  while (check_id > 0) {

    var check = checks[--check_id];

    var first = check[0], second = check[1];

    if (first instanceof BSP && second instanceof BSP) {

      // both elements are nodes, if they intersect move to the next level;

      // if they don’t intersect, let them disappear.

      if (first.box.intersectOBB(second.box, transform)) {

        while (checks.length - check_id  4) checks.push([{}]);

        checks[check_id  ][0] = first.front;

        checks[check_id  ][1] = second.front;

        checks[check_id+1][0] = first.back;

        checks[check_id+1][1] = second.front;

        checks[check_id+2][0] = first.front;

        checks[check_id+2][1] = second.back;

        checks[check_id+3][0] = first.back;

        checks[check_id+3][1] = second.back;

        check_id += 4;

      }

    } else if (first instanceof Jax.Geometry.Triangle &&

               second instanceof BSP) {

      // first is a tri, keep it to retest against second’s children

      while (checks.length - check_id  2) checks.push([{}]);

      checks[check_id  ][0] = first;

      checks[check_id  ][1] = second.front;

      checks[check_id+1][0] = first;

      checks[check_id+1][1] = second.back;

      check_id += 2;

    } else if (first instanceof BSP &&

               second instanceof Jax.Geometry.Triangle) {

      // second is a tri, keep it to retest against first’s children

      while (checks.length - check_id  2) checks.push([{}]);

      checks[check_id  ][0] = first.front;

      checks[check_id  ][1] = second;

      checks[check_id+1][0] = first.back;

      checks[check_id+1][1] = second;

      check_id += 2;

    } else {

      // dealing with 2 triangles, perform intersection test

      // transform second into first’s coordinate space

      mat4.multiplyVec3(transform, second.a, a);

      mat4.multiplyVec3(transform, second.b, b);

      mat4.multiplyVec3(transform, second.c, c);

      tri.set(a, b, c);

     

      if (first.intersectTriangle(tri)) {

        return {

          first: first,

          second: second,

          second_transformed: new Jax.Geometry.Triangle(

                              tri.a, tri.b, tri.c)

        };

      }

    }

  }

  return false;

};

The collision detection is made a little more complicated by the addition of a second BSP, but hopefully it’s not too difficult to understand.

First, we create a stack, which is just an array with a single element. That first element is used to test the root node of this BSP with the root node of the potentially-colliding BSP. If the root nodes don’t intersect, we’re done.

Within the loop, we check whether the nodes to be tested are both BSPs. If they are, and if their bounding boxes are colliding, then each subnode of the first BSP must be compared with each subnode of the second, so 4 more checks are added onto the stack. If they are not colliding, then there’s nothing else to do except move on to the next check in the stack.

If one node is a BSP and the other is a triangle, then we only need to work our way down the BSP’s children and hold onto the triangle for testing against those children.

Finally, when both nodes are triangles, we can convert the second triangle into the first triangle’s coordinate space using the matrix that was passed into the function, and then do a simple triangle-triangle intersection test. If the triangles intersect, then obviously we have a collision.

There are a lot of ways you could code the collision response. I chose to create and return a generic object which contains information about the collision. Since the object evaluates to a non-false value, I can use this to simultaneously check for collisions and then respond to the collision without an extra function call. If you have the CPU performance to spare, you could just as easily fire a callback function or emit a ‘collided’ event instead.

Using the BSP Tree

We’re done coding the BSP tree, so let’s use it!

Let’s say, for sake of argument, that we have a mesh object with a getTriangles() function. Then, we could construct the BSP tree quite simply:

var bsp = new BSP();

var triangles = mesh.getTriangles();

for (var i = 0; i  triangles.length; i++)

  bsp.addTriangle(triangles[i]);

bsp.finalize();

This will create a new BSP, iterate through the mesh’s triangles, add them one-by-one to the tree, and then finalize it. Finalization causes the single root node to become, well, a tree.

Now that we’ve created the tree, let’s make use of it. Here’s an example of rendering it using our (unoptimized!) traverse() function:

bsp.traverse(camera.getPosition(), function(leaf) {

  // render the node

});

And of course, here’s a demonstration of checking for collisions using a mythical second BSP, presumably created in an identical manner to above:

var collision;

var xform = mat4.inverse(mesh.getTransform(), mat4.create());

mat4.multiply(otherMesh.getTransform(), xform, xform);

if (collision = bsp.collide(other_bsp, xform)) {

  // collision detected! it’s stored in +collision+

}

In case you’re not very familiar with matrix operations, the inverse of any given matrix is effectively its opposite; since an object’s transformation matrix is used to convert any given point from that object’s local space into world space, the inverse of an object’s transformation matrix will do the opposite, converting from world space into object space. So to test otherMesh against mesh, we combine the transform matrix of otherMesh, which converts otherMesh into world space, with the inverse transform matrix of mesh, which converts world space into mesh’s space. The combination of the two will go straight from otherMesh’s space into mesh’s space, and that’s exactly what we need to perform collision detection. If that was confusing, see this illustration:

Conclusion

Hopefully, this tutorial was informative for you. If you have any questions or comments, feel free to leave them here or on the Jax forums. There are other approaches to segregating scene data, such as using octrees or k-trees, though the others have more trouble replicating one of the major gains to using a BSP tree: the ability to render the scene back-to-front without having to sort the geometry first.

As a side note, octrees seem to have more-or-less replaced BSPs in C programs; I’m still unconvinced that they’re fast enough to replace BSPs just yet in JavaScript, however. In any case, BSPs are still used today for most collision detection, in which they supposedly outperform octrees in most cases. At least, that’s what Google says; I hope to do some benchmarking to come up with more definitive, JavaScript-specific results sometime in the near future.

Jax v1.1.0 Released!

Nearly two months after the initial release, Jax v1.1.0 is huge, representing a massive set of great improvements over the previous version, and I’m proud to announce it is officially ready for use!

As I was adding release notes to the Changelog, I realized that I’d doubled the size of the log with this release! So instead of overviewing them all here, I’ll highlight what I think are the greatest improvements and leave it to you to read through the individual updates, if you wish.

Without further ado, here are some of the highlights of this release:

  • The new plug-in system makes Jax trivial to extend on a per-application basis, allowing Jax itself to stay small without sacrificing your needs.
    • I’ve added a new Plugins Guide to help you get started. You’ll see that if you have ever worked with Jax at all, developing and releasing plugins is a breeze!
  • Massive reduction in memory footprint and performance gains across the board
    • Meshes now take full advantage of Typed Arrays, allowing them to remove redundancy in favor of sharing the same physical memory in numerous places.
    • This has allowed me to add some really helpful objects like Jax.Geometry.Triangle (see below), without duplicating vertex and normal data.
  • Full support for both Ruby 1.8.7 and Ruby 1.9.2!
  • Added Jax.Geometry.Triangle, which represents individual triangles in a mesh (via Jax.Mesh#getTriangles()), and comes with free triangle, sphere, ray and point intersection tests! This should make collision detection a relative breeze!
  • Built-in Perlin noise functions now only require a single function call to use. The old way still works, but the new way will drastically improve your application’s memory usage!
  • New error handling API allows the developer to directly intervene when an error is encountered
    • You can use this to report the error to your server, attempt to gracefully recover, or whatever else you want!
  • Loads of new documentation! I’ve almost finished documenting the entire JavaScript API!
    • The Ruby portion still leaves something to be desired, though. I’m working on it.

In addition to everything else, I’ve added a new quick-start page to help new developers get started. It’s a lot less daunting than the Getting Started Guide but you’ll still want to read the guide if you want to dig into anything more involved than a teapot.

Finally, I also updated the Getting Started Guide with some details. Out with the deprecated, in with the awesome. Besides minor changes, I added a section on redirection, which explains how the controllers can communicate with one another. It should have been there from the start, but it slipped my mind with everything else I’ve been working on!

Updating

A few of the improvements deal with how applications are generated, so those tweaks will naturally only be applied to new applications. Existing ones aren’t left in the dark, however. As always, the update process for an existing app is as follows:

  1. Update your Gemfile. Make sure the version of Jax is set to “1.1.0″.
  2. Update the bundle by running bundle update.
  3. Update the Jax JavaScript runtime by running rake jax:update.
  4. You’re Done!

Jax v1.0.1: Bugfixes and a Warning

I’ve just pushed Jax v1.0.1 up. As the version number implies, this is not a huge release — but a lot of effort has gone into it!

This is a bugfix release that addresses framerate and other issues with some driver sets. It also makes Jax shadowmapping smarter. When what would be considered a fatal error is encountered while generating a shadow map, shadowmaps will silently be disabled on a per-light basis so that rendering can continue, rather than letting the scene crash. Note that fatal errors encountered during the main rendering pass are still fatal.

Be Forewarned

This release should serve as a word of warning to everyone writing WebGL shaders, whether or not you use Jax. Video drivers are notorious for their bugs, which are incredibly difficult to track down and usually don’t seem to make any sense whatsoever when you finally discover what’s causing them.

In this case, the issues were all caused by the built-in Jax lighting shaders. When I wrote them, my original plan was to take every opportunity to return from a given function as early as possible, thus preventing unnecessary GPU usage. Unfortunately, it was the very act of returning that was causing the issue.

So for all you other shader writers out there, be aware of this very simple caveat: returning early from a void function can cause some serious issues for some users. The only solution I could find was to redesign the functions to use conditions instead of returning outright.

(I’ve read elsewhere that even if-conditions can have problems on some hardware; however, I’ve seen nothing [yet] to indicate that any WebGL-compatible hardware is effected by this, so I believe switching to conditions was still the right answer.)

Hopefully this issue will be resolved by the various video card manufacturers out there in the long term; for now, I’m afraid all we can do is gripe about it.

For the full discussion regarding this bug, see:

https://github.com/sinisterchipmunk/jax/issues/20

EDIT: P.S. – it seems really odd for something as fundamental as `return;` to crash an application. If you have more information regarding this, please let me know so I can make adequate corrections! Thanks!

Upgrading Your Application

Finally, the obligatory note on upgrading. As always, to upgrade, first update your Gemfile and run `bundle update jax`; then run `bundle exec rake jax:update` to bring your JavaScript files up to date.

‘Bout Time

This is it: I’m immensely proud to announce the first official release of Jax! It’s been over 8 months in the making, and the framework has spent the last several weeks undergoing strenuous tests in a variety of development and runtime environments. While I can’t possibly claim that it’s utterly bug-free, I’ve done everything in my power, including leveraging the strength of the WebGL community at large, to make Jax the best it can be out of the gate.

I’ve been testing and tweaking the framework for quite a while now, and the feedback I’ve gathered in the meantime is nothing short of awe-inspiring. Literally hundreds of people have been looking at Jax and the various demos I’ve concocted using it, and reports of failure have been generally few and far between. Those reports were analyzed and resolved, usually within a few hours or less.

I just finished running one more test to verify that everything goes well under Windows environments, and I had no trouble with it. I could sit here and make minor tweaks to the Jax internals until the world ends, but the simple fact is that Jax is as solid and robust as I can make it at this time. It’s handled every edge case I’ve thrown at it like a champ, and the only way it can get better at this point is through real-world experience with people doing things with it that I can’t possibly imagine.

Jax is a relatively young framework, but the project is not. I was researching how best to implement Jax way back when WebGL was still a draft specification, changing virtually every day. Back then, the only way to fly was with the latest nightly browser versions and magic command-line flags to enable WebGL support. The research I did in those early days is a large part of what has made Jax possible. In addition, I had started no less than 3 separate projects, all of which were designed to explore the fastest and most versatile ways to make productive WebGL development happen on the grand scale, far beyond simple demos. Jax is the result of that research, the culmination of those projects.

The Jax code base itself is already four months old. I feel I’ve shown a more-than-reasonable amount of restraint and caution in terms of versioning, which I hope speaks to my commitment to bringing a robust long-term 3D Web development environment to the table.

As I stamp the first major version number onto Jax, I can’t help but feel the excitement mounting. There are a lot of new features that I can’t wait to introduce, and now that Jax is officially shipped, I can get to work on the next batch of awesomeness.

Try out Jax; it’s been a lot of months, and now it’s finally ready for you. If you have problems with it, let me know so I can fix them! Send me all of your questions, comments, hate mail and love letters — I’ll read them all! Promise!

What’s New in Jax – v0.0.0.9

We’re coming down the stretch in preparation for Jax v1.0! I’ve had to draw a line in the sand and decided not to implement any new features following Picking (which was added in Jax v0.0.0.7). I can hardly wait to ship v1.0 so I can start adding in all the new features I’ve thought about since making that decision! But, patience is a virtue, as they say. I’ve decided to release v0.0.0.9 tonight instead of v1.0, and let it ride with the latest batch of changes for a day or two before making the leap to a major version number.

(Update: it’s now 0.0.0.10; I excluded some worthless files from the build, and the gem size dropped from almost 10MB to 100KB! Thought that was worth another release!)

So, what kinds of changes are we looking at here? Nothing too drastic, I assure you; but there are some things that might cause a headache or two if you go upgrading blindly.

As usual, here’s the changelog linkage!

First and foremost, the Custom Shaders Guide is up! Like the Getting Started Guide, it’s pretty comprehensive; that makes it big, but hopefully not too big. It answers every question I could think anyone might ask about Jax shaders. The guide is still in draft form and I’ll continue to polish it up over the next few days, but I wanted to get it out there as soon as possible since there’s been quite some interest about how to go about writing your own shaders lately.

Now I’ll talk about changes in the actual code base: I’ve altered how Jax specs are run, with particular emphasis on shader specs. Generating a new Jax application will now generate an additional helper file at spec/javascripts/support/helpers/jax_spec_environment_helper.js. I’ve moved all of the Jasmine set-up code into this file, and altered the generated spec/javascripts/support/spec_layout.html.erb file to call the helper.

In addition to cleaning up the layout file, this helper actually serves a useful purpose. It defines a global SPEC_CONTEXT which is now automatically managed by the test suite. No longer do you have to manage your own contexts from one spec to the next! It’s now completely transparent and totally automated — and not to mention safer. Since it runs on a completely different <canvas> element than the visual tests, you don’t have to worry about it causing problems. And since it’s automatically disposed and then reinitialized between tests, you don’t have to worry about individual specs tainting the context!

There’s a downside to this change, though. If you’re working on an existing Jax project, you’ll need to generate a new project and copy these files into your existing project; also, if you have custom shaders, you’ll want to remove the context initialization and disposal from the shader tests. (Other tests aren’t affected.) Sorry for that — though you were warned about it being pre-release software!

The rest of the changes were pretty minor, and only worthy of a footnote. Bugfixes here and there, and the error messages when a glDrawStuff function fails now include the exact enum name, so you don’t have to look it up the hard way. Stuff like that.

I’ve also got 2 more live demos on the way! I’m hoping to release them over the next day or so. Hold tight!

What’s New in Jax – v0.0.0.8

I just pushed Jax v0.0.0.8 to RubyGems, so now I’ll take a moment and elaborate on what’s inside.

In terms of app-breaking stuff, there was only one change that you need to be aware of, and only if you’re using the “classic” Perlin noise functions that ship with Jax. The function “noise()” has been renamed to “cnoise()”. Simplex noise was not affected.

Now on to the good stuff. After pushing the ‘meadow’ demo, which uses vertex texture lookups, I found that vertex texture lookups are not supported on Windows at this time. In the meantime, there’s a GitHub repository that implements all flavors of Perlin noise without relying on texture lookups! And it’s licensed under MIT, to boot. Woot!

I did some quick, unprofessional benchmarks (I watched the recently-implemented framerate on my MacBook Pro) to confirm that the library is, indeed, considerably slower than the texture-lookup version. My framerate dropped from about 100 down to 50-60. Ouch. Since it’s slower, and not just by a few frames, I didn’t want to lose the texture lookups for those who could use them. I did, however, want the demo (and the functions!) to run for those who couldn’t.

The answer was to improve the shader preprocessor a bit, and take advantage of those improvements for Perlin noise. The result is Jax v0.0.0.8, now available. Here it is, in bullet form:

  • Added Jax.Shaders.max_vertex_textures to make accessible the number of vertex textures supported by the client.
  • Exposed a new local variable to the Embedded JavaScript used in shaders (the .ejs files) called shader_type. This is a string equal to either ‘vertex’ or ‘fragment’, and is particularly useful when you’re defining reusable function libraries where you don’t necessarily know which type of shader you’re in.
  • Jax built-in Perlin noise functions now silently fall back to the non-textured version if they are used within a vertex shader and VTL is not supported by the hardware. In all other cases, the texture lookup version is used for the speed benefit.

That’s it. Not a huge release, but a release with huge implications. As far as I know, the noise functions now run properly on all machines that run WebGL itself properly.

The best part about it is that when VTL support makes it to Windows, programs using Jax noise should automatically get a performance increase — just “because”.

(Note: about 20% of clients will continue to not support VTL even after this change goes through; those machines won’t get an automatic performance increase, but they will run Jax noise-based applications without issue. So that’s a pretty cool fringe benefit.)

What’s New in Jax – v0.0.0.7

Since the first version, I’ve been iterating my way through Jax prereleases like there’s no tomorrow! I’ve been going so fast, in fact, that I’ve unfortunately not taken the time to post updates to say what’s actually in them.

So here they are: a list all of the noteworthy updates I’ve made in preparation for the first official release. I won’t bother mentioning all of the bugfixes and minor changes, because that would take up way too much space.

  • Custom shaders. Support for adding your own shaders to an application was added in v0.0.0.2, and they’ve been steadily improving since then. I’ve already covered how to use them in some detail and am currently working on comprehensive documentation.
  • Incremental failoff for shaders. As of v0.0.0.2, Jax is smart enough to detect when a given client is incapable of handling the graphics options you’ve requested, and to make an intelligent decision as to which effects to omit. First it tries to see if there’s anything blatantly impossible to run on the given hardware, and if not (or if it’s already omitted those effects), Jax will remove the last effect in a given effect list until the material itself works. Because the “basic” shader (that is, per-vertex color and nothing else) is guaranteed to run on WebGL-compatible hardware, your app is guaranteed to run on all hardware, even if they don’t have the processing power to run it full-blast.
  • The role of helpers has been solidly defined. Another thing that was added into v0.0.0.2, helpers can be used to make the application at large far DRYer.
  • New generators: the scaffold generator was added in v0.0.0.2, and the material generator was modified to accept the –append option to avoid overwriting existing materials. Both of these generators are extremely helpful.
  • Special handling was added for non-power-of-two (NPoT) textures. WebGL supports these types of textures under very specific circumstances. I wanted Jax to attempt to handle these textures automatically, and instead of simply scaling them up to power-of-two (which technically works, but is kind of flaky across browsers and takes additional processing overhead), I instead altered Jax to assume the specific circumstances that allow NPoT textures to be used natively. This includes switching to GL_LINEAR filters, GL_CLAMP_TO_EDGE wrapping techniques, etc. As long as all the right options are selected (which Jax now assumes automatically), the NPoT texture can be used without issue.
  • Added the Jax license, which is the MIT license. Basically, you can pretty much do anything you want to Jax — including redistribute it, modify it, or even sell it if you think you can find someone who’ll pay for free software.
  • All of the default shaders are now built directly within your application instead of being compiled into the main Jax JavaScript file. This makes the main Jax file smaller, and more importantly, it allows you to override any of them in your application by simply creating a shader with the same name. When you override the shader, it’s totally gone, so the source code for it isn’t cluttering up any of your sources.
  • Jax now checks automatically for version mismatches. One of the unfortunate facts of life is that because Jax spans both Ruby and JavaScript code, both code bases have to be kept in sync. Your Jax applications contain a copy of the Jax JavaScript code, so when you upgrade your Jax RubyGem, your application is in fact still using the old JavaScript base. Beginning in v0.0.0.5, Jax will now warn you whenever your application is loaded with a JavaScript version that doesn’t match the RubyGem version. The warning includes the command you need to run to get them back in sync — which is a pretty simple command:
    $ rake jax:update
  • Jax now sports built-in Perlin noise functions. None of the built-in shaders use it (yet), but you can easily include it into your own shaders:
    //= require "functions/noise"

    Detailed documentation for exactly how to use the noise is still in the works, but it’s not difficult. For now, see the example application for a demonstration.

  • In addition to tons of documentation and bugfixes, v0.0.0.6 included support for “picking”. Picking is a technique that involves you giving Jax an X/Y pixel coordinate. Jax will then render the scene to an off-screen buffer, read back the pixel in question (“pick” it), and then return the object that was rendered at that location (if any). This is exceedingly useful for linking mouse clicks with objects. It’s less accurate than unprojection (it only returns the entire object, not the exact 3D point), but because it’s hardware accelerated, picking is much faster than unprojection, which is done entirely in JavaScript on the CPU.
    • Jax also supports picking an entire region of pixels in the shape of a rectangle; all objects rendered in the region will be returned.
  • Also added in v0.0.0.6 were framerate and update-rate calculations. By default, Jax won’t waste the resources to figure these out, but if you request them, Jax will automatically start calculating them. You can programmatically disable calculating them when you’re finished.
    • The default spec layout was modified to include a hyperlink to activate FPS and UPS calculations. This will affect new applications, but not applications generated prior to v0.0.0.6.
  • Finally, v0.0.0.7 brings us current with a single fairly major bugfix. It turns out that when Jax was packaging files for use in production, it was packaging the helpers in the wrong order, breaking the entire application. I figured this was a major-enough fix to warrant its own, immediate, release. This was the only change between 0.0.0.6 and 0.0.0.7.

…and there you have it. In addition to the mountain of documentation and the plethora of bugfixes, I’ve been able to implement some quite noteworthy feature additions that I believe really bring Jax to the forefront of WebGL application development — again!

I’ll do my best to put out a blog post upon every release going forward so that you’re not left in the dark again. On the other hand, you could always check the changelog — but where’s the fun in that?