场景图的正确转换顺序
Correct transformation order for scene graph
我正在开发一个带有场景图的快速 WebGL 引擎,以便在 reddit (https://www.reddit.com/r/gameideas/comments/3dsy8m/revolt/) 上快速制作我的游戏创意原型。现在,在我完成一些基本渲染后,我想不出正确的顺序,对大多数人来说看起来正确的顺序,我应该使用它来转换场景图中的节点。
很难解释发生了什么,但我希望您能理解它并没有像大多数人期望的那样在任何其他引擎中发生。
这是我目前正在做的事情的简化版本。
- Mat4 = glMatrix 0.9.5
- Utils = 自定义实用程序
节点(渲染):
@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();
通常的顺序是 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/.
我没有找到我希望的原始方法,因为我之前一直在缓存矩阵,并希望继续这样做,但现在我从头开始重新创建我的旧引擎后找到了一种更简单的方法。
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);
}
}
我基本上做的是,如果矩阵有一个父节点(它不是根节点),那么我将矩阵作为其父节点的克隆开始,否则我将矩阵设置为单位矩阵。然后对其应用常规转换。如果我找到继续缓存矩阵的方法,我会尽快上传。
我正在开发一个带有场景图的快速 WebGL 引擎,以便在 reddit (https://www.reddit.com/r/gameideas/comments/3dsy8m/revolt/) 上快速制作我的游戏创意原型。现在,在我完成一些基本渲染后,我想不出正确的顺序,对大多数人来说看起来正确的顺序,我应该使用它来转换场景图中的节点。
很难解释发生了什么,但我希望您能理解它并没有像大多数人期望的那样在任何其他引擎中发生。
这是我目前正在做的事情的简化版本。
- Mat4 = glMatrix 0.9.5
- Utils = 自定义实用程序
节点(渲染):
@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();
通常的顺序是 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/.
我没有找到我希望的原始方法,因为我之前一直在缓存矩阵,并希望继续这样做,但现在我从头开始重新创建我的旧引擎后找到了一种更简单的方法。
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);
}
}
我基本上做的是,如果矩阵有一个父节点(它不是根节点),那么我将矩阵作为其父节点的克隆开始,否则我将矩阵设置为单位矩阵。然后对其应用常规转换。如果我找到继续缓存矩阵的方法,我会尽快上传。