Search code examples
matrixwebglscenegraph

Correct transformation order for scene graph


I am working on a quick WebGL Engine with a scene graph to quickly prototype my game idea on reddit (https://www.reddit.com/r/gameideas/comments/3dsy8m/revolt/). Now, after I have got some basic rendering done, I can't figure out the correct order, well the one that looks right to most people, that I am supposed to use in order to transform the nodes in the scene graph.

It's hard to explain what is happening but I hope you get a understanding that it just isn't rotating the way that most would expect it to happen in any other engine.

Here is a simplified version of what I am currently doing.

  • Mat4 = glMatrix 0.9.5
  • Utils = Custom Utilitys

Node(Render):

@param {parentMatrix}

// Create Local Matrix
self.lMatrix = mat4.create();
mat4.identity(self.lMatrix);
mat4.translate(self.lMatrix, self.position);
mat4.rotate(self.lMatrix, self.rotation[0], [1, 0, 0]);
mat4.rotate(self.lMatrix, self.rotation[1], [0, 1, 0]);
mat4.rotate(self.lMatrix, self.rotation[2], [0, 0, 1]);

var wMatrix = mat4.create();
mat4.identity(wMatrix);
if(parentMatrix){
    mat4.multiply(self.lMatrix, parentMatrix, wMatrix);
}
else{
    mat4.set(self.lMatrix, wMatrix);
}
// Render
var children = this.children,
numChildren = children.length,
child;

for(var i = 0; i < numChildren; i++){
    child = children[i];
    child.render(wMatrix);
}

Entity(Render):

@param {parentMatrix}

// Set Transformation matrix
var tMatrix = mat4.create();
mat4.identity(tMatrix);
mat4.translate(tMatrix, self.position);
mat4.rotate(tMatrix, self.rotation[0], [1, 0, 0]);
mat4.rotate(tMatrix, self.rotation[1], [0, 1, 0]);
mat4.rotate(tMatrix, self.rotation[2], [0, 0, 1]);
mat4.scale(tMatrix, self.scale || [1, 1, 1]);

var wMatrix = mat4.create();
mat4.identity(wMatrix);
mat4.multiply(tMatrix, parentMatrix, wMatrix);

Utils.loadTMatrix(wMatrix);
this.texture.bind();
this.mesh.render();

Solution

  • I didn't find the original way that I was hoping for because I was previously caching matrices, and was hoping to continue doing it, but now I have found a much easier way after recreating my old engine from scratch.

    Engine.prototype.NODE.prototype.render = function(parentMatrix){
      var children = this.children,
          numChildren = children.length,
          child, pos, rot, scale;
      // If has set matrix to a copy of it
      if(parentMatrix){
        this.matrix = mat4.clone(parentMatrix);
      }
      else{
        // Else set it to a identity matrix
        mat4.identity(this.matrix);
      }
      // If matrix needs updating reconstruct it
      pos = [this.position.x,
             this.position.y,
             this.position.z];
      rot = [this.rotation.x,
             this.rotation.y,
             this.rotation.z];
      scale = [this.scale.x,
               this.scale.y,
               this.scale.z];
      // Recreate Transformation matrix
      mat4.translate(this.matrix, this.matrix, pos);
      mat4.rotate(this.matrix, this.matrix, rot[0], [1, 0, 0]);
      mat4.rotate(this.matrix, this.matrix, rot[1], [0, 1, 0]);
      mat4.rotate(this.matrix, this.matrix, rot[2], [0, 0, 1]);
      mat4.scale(this.matrix, this.matrix, scale);
      // Render Children with this matrix
      for(var i = 0; i < numChildren; i++){
        child = children[i];
        child.render(this.matrix);
      }
    }
    

    what I am basically doing is that, if the matrix has a parent (it isn't the root node) then I am starting the matrix off as a clone of its parent, else I am setting the matrix to it's identity matrix. Then applying the regular transformations to it. If I find a way in order to continue caching matrices I will uploaded it as soon as possible.