我正在尝试将文件中的场景加载到 Three.js(自定义格式,不是 Three.js 支持的格式)。这种特定格式描述了一个场景图,其中树中的每个节点都有一个指定为 4x4 矩阵的变换。将其推入 Three.js 的过程如下所示:
// Yeah, this is javascript-like psuedocode
function processNodes(srcNode, parentThreeObj) {
for(child in srcNode.children) {
var threeObj = new THREE.Object3D();
// This line is the problem
threeObj.applyMatrix(threeMatrixFromSrcMatrix(child.matrix));
for(mesh in child.meshes) {
var threeMesh = threeMeshFromSrcMesh(mesh);
threeObj.add(threeMesh);
}
parentThreeObj.add(threeObj);
processNodes(child, threeObj); // And recurse!
}
}
或者至少这就是我想要的。正如我所指出的,这applyMatrix
条线并不像我期望的那样工作。大部分场景看起来不错,但某些已旋转的元素没有正确对齐(而其他元素则很奇怪)。
通过 COLLADA 加载器(它与我正在尝试做的事情大致相同)看起来他们将矩阵分解为平移/旋转/缩放并单独应用每个。我尝试用它代替上面显示的 applyMatrix:
var props = threeMatrixFromSrcMatrix(child.matrix).decompose();
threeObj.useQuaternion = true;
threeObj.position = props[ 0 ];
threeObj.quaternion = props[ 1 ];
threeObj.scale = props[ 2 ];
这再一次产生了一个场景,其中大多数元素都在正确的位置,但以前未对齐的网格现在已经在某个地方变成了遗忘,根本不再出现。所以最后这并不比applyMatrix
上面的好。
查看有关该主题的几个在线讨论,似乎推荐的使用矩阵进行变换的方法是将它们直接应用于几何,而不是节点,所以我尝试通过手动构建变换矩阵,如下所示:
function processNodes(srcNode, parentThreeObj, parentMatrix) {
for(child in srcNode.children) {
var threeObj = new THREE.Object3D();
var childMatrix = threeMatrixFromSrcMatrix(child.matrix);
var objMatrix = THREE.Matrix4();
objMatrix.multiply(parentMatrix, childMatrix);
for(mesh in child.meshes) {
var threeMesh = threeMeshFromSrcMesh(mesh);
threeMesh.geometry.applyMatrix(objMatrix);
threeObj.add(threeMesh);
}
parentThreeObj.add(threeObj);
processNodes(child, threeObj, objMatrix); // And recurse!
}
}
这实际上产生了正确的结果!(减去法线的一些怪癖,但我可以弄清楚)这很好,但问题是我们现在已经有效地扁平化了场景层次结构:更改父级的变换将对子级产生意想不到的结果,因为完整的变换堆栈现在“烘焙”到网格中。在这种情况下,关于场景的信息丢失是不可接受的。
那么如何告诉 Three.js 执行相同的逻辑,但在场景图中的适当位置?
(抱歉,我非常想发布一些实时代码示例,但不幸的是,在这种情况下,这不是一个选项。)