使用矩阵转换Three.js场景图

时间:2012-07-04 00:04:10

标签: webgl three.js scenegraph

我试图将文件中的场景加载到Three.js(自定义格式,而不是Three.js支持的格式)。该特定格式描述了场景图,其中树中的每个节点具有指定为4×4矩阵的变换。将它推入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好。

通过几个关于该主题的在线讨论,看来为变换使用矩阵的推荐方法是将它们直接应用于几何体而不是节点,所以我尝试通过手动构建变换矩阵,如下所示: / p>

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!
    }
}

这实际上产生了正确的结果! (减去法线的一些怪癖,但我可以把它弄清楚)这很好,但问题是我们现在已经有效地压平了场景层次结构:更改父级的转换会产生意外的结果对孩子们来说,因为完整的变换堆栈现在已经在#34;到了网格。在这种情况下,关于场景的信息丢失是不可接受的。

那么怎么可能会告诉Three.js做同样的逻辑,但是在场景图中的适当点呢?

(对不起,我非常希望发布一些实时代码示例,但遗憾的是,在这种情况下,这不是一个选项。)

2 个答案:

答案 0 :(得分:5)

唉...

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

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

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

总是让你感到愚蠢的小事......

答案 1 :(得分: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