5

我正在尝试将文件中的场景加载到 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 执行相同的逻辑,但在场景图中的适当位置?

(抱歉,我非常想发布一些实时代码示例,但不幸的是,在这种情况下,这不是一个选项。)

4

2 回答 2

5

叹...

Altered Qualia在我发布此消息后的几分钟内就在 Twitter 上指出了解决方案。

这是一个简单的单行修复:只需matrixAutoUpdate在 Object3D 实例上设置为 false,第一个代码示例就会按预期工作。

threeObj.matrixAutoUpdate = false; // This fixes it
threeObj.applyMatrix(threeMatrixFromSrcMatrix(child.matrix));

总是那些愚蠢的小事让你...

于 2012-07-04T00:32:43.237 回答
5

您可以使用 matrixAutoUpdate = false 跳过 Three.js 场景图位置/缩放/旋转的内容。然后将 object.matrix 设置为您想要的矩阵,所有这些都应该是花花公子(好吧,它仍然会乘以父节点矩阵,所以如果您使用绝对模型视图矩阵,您需要破解 Object3D 上的 updateMatrixWorld 方法。)

object.matrixAutoUpdate = false;
object.matrix = myMatrix;

现在,如果您想在 Three.js 位置/缩放/旋转的东西上应用自定义转换矩阵,您需要将 Object3D#updateMatrix 编辑为类似的东西。

THREE.Object3D.prototype._updateMatrix = THREE.Object3D.prototype.updateMatrix;
THREE.Object3D.prototype.updateMatrix = function() {
  this._updateMatrix();
  if (this.customMatrix != null)
    this.matrix.multiply(this.customMatrix);
};

https://github.com/mrdoob/three.js/blob/master/src/core/Object3D.js#L209

于 2012-07-04T00:33:54.210 回答