【问题标题】:Using matrices to transform the Three.js scene graph使用矩阵变换 Three.js 场景图
【发布时间】:2012-07-04 00:04:10
【问题描述】:

我正在尝试将文件中的场景加载到 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 加载程序(它与我尝试做的事情大致相同),似乎他们 decompose the matrix 转换/旋转/缩放并单独应用每个。我尝试用它代替上面显示的 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 执行相同的逻辑,但在场景图中的适当位置?

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

【问题讨论】:

    标签: webgl three.js scenegraph


    【解决方案1】:

    您可以使用 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

    【讨论】:

    • 相同的答案,相隔一分钟。 :) 无论如何,谢谢! updateMatrix 位非常有趣。
    【解决方案2】:

    叹息...

    在我发布此消息的几分钟内,在 Twitter 上更改了 Qualia pointed out the solution

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

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

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

    【讨论】:

      猜你喜欢
      • 2017-07-03
      • 2011-02-03
      • 1970-01-01
      • 1970-01-01
      • 2011-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多