正确的场景图转换顺序

时间:2015-07-25 08:48:29

标签: matrix webgl scenegraph

我正在开发一个带有场景图的快速WebGL引擎,以便在reddit(https://www.reddit.com/r/gameideas/comments/3dsy8m/revolt/)上快速构建我的游戏创意原型。现在,在我完成一些基本渲染后,我无法找出正确的顺序,以及对大多数人来说正确的顺序,我应该使用它来转换场景图中的节点。

很难解释发生了什么,但我希望你能够理解它并没有像大多数人预期的那样在任何其他引擎中旋转。

这是我目前正在做的简化版本。

  • Mat4 = glMatrix 0.9.5
  • Utils = Custom Utilitys

节点(渲染):

@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);
}

实体(渲染):

@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();

2 个答案:

答案 0 :(得分:0)

通常的顺序是SRT,或缩放,旋转然后翻译。

此外,我不确定你是否可以做到

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]);

使用欧拉角并获得正确的结果方向。我没有使用欧拉角,所以我没有完全掌握细节。如果我错了,请有人纠正我。有关欧拉角和旋转矩阵之间的转换,请参阅此页:http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/

答案 1 :(得分:0)

我没有找到我希望的原始方式,因为我以前是缓存矩阵,并且希望继续这样做,但现在我从头开始重新创建旧引擎后找到了一种更简单的方法。

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);
  }
}

我基本上做的是,如果矩阵有一个父(它不是根节点),那么我将矩阵作为其父节点的克隆启动,否则我将矩阵设置为它的单位矩阵。然后对它应用常规变换。如果我找到一种方法来继续缓存矩阵,我会尽快上传它。