使用矩阵转换 Three.js 场景图 [英] Using matrices to transform the Three.js scene graph

查看:37
本文介绍了使用矩阵转换 Three.js 场景图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将文件中的场景加载到 Three.js(自定义格式,而不是 Three.js 支持的格式)中.这种特殊格式描述了一个场景图,其中树中的每个节点都有一个指定为 4x4 矩阵的变换.将其推送到 Three.js 的过程如下所示:

I'm attempting to load a scene from a file into Three.js (custom format, not one that Three.js supports). This particular format describes a scene graph where each node in the tree has a transform specified as a 4x4 matrix. The process for pushing it into Three.js looks something like this:

// 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 行并不像我期望的那样工作.大部分场景看起来不错,但某些已旋转的元素未正确对齐(而其他元素则很奇怪).

Or at least that's what I'd like it to be. As I pointed out, the applyMatrix line doesn't work the way that I would expect. The majority of the scene looks okay, but certain elements that have been rotated aren't aligned properly (while other are, it's strange).

查看 COLLADA 加载程序(它执行的操作与我正在尝试做的事情大致相同)似乎它们 将矩阵分解为平移/旋转/缩放并分别应用.我尝试用它代替上面显示的 applyMatrix:

Looking through the COLLADA loader (which does approximately the same thing I'm trying to do) it appears that they decompose the matrix into a translate/rotate/scale and apply each individually. I tried that in place of the applyMatrix shown above:

var props = threeMatrixFromSrcMatrix(child.matrix).decompose();
threeObj.useQuaternion = true;
threeObj.position = props[ 0 ];
threeObj.quaternion = props[ 1 ];
threeObj.scale = props[ 2 ];

这再次产生了一个场景,其中大多数元素都在正确的位置,但以前未对齐的网格现在在某处被遗忘了,根本不再出现.所以最终这并不比上面的 applyMatrix 好.

This, once again, yields a scene where most elements are in the right place but meshes that previously were misaligned have now been transformed into oblivion somewhere and no longer appear at all. So in the end this is no better than the applyMatrix from above.

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

Looking through several online discussions about the topic it seems that the recommended way to use matrices for your transforms is to apply them directly to the geometry, not the nodes, so I tried that by manually building the transform matrix like so:

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

这实际上产生了正确的结果!(减去法线的一些怪癖,但我可以解决这个问题)很好,但问题是我们现在已经有效地扁平化了场景层次结构:更改父级的变换将对子级产生意想不到的结果,因为完整的变换堆栈现在烘焙"到网格中.在这种情况下,这是无法接受的场景信息丢失.

This actually yields the correct results! (minus some quirks with the normals, but I can figure that one out) That's great, but the problem is that we've now effectively flattened the scene hierarchy: Changing the transform on a parent will yield unexpected results on the children because the full transform stack is now "baked in" to the meshes. In this case that's an unacceptable loss of information about the scene.

那么如何告诉 Three.js 执行相同的逻辑,但在场景图中的适当位置?

So how might one go about telling Three.js to do the same logic, but at the appropriate point in the scene graph?

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

(Sorry, I would dearly love to post some live code examples but that's unfortunately not an option in this case.)

推荐答案

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

You can use matrixAutoUpdate = false to skip the Three.js scenegraph position/scale/rotation stuff. Then set object.matrix to the matrix you want and all should be dandy (well, it still gets multiplied by parent node matrices, so if you're using absolute modelview matrices you need to hack updateMatrixWorld method on Object3D.)

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

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

Now, if you'd like to have a custom transformation matrix applied on top of the Three.js position/scale/rotation stuff, you need to edit Object3D#updateMatrix to be something like.

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

这篇关于使用矩阵转换 Three.js 场景图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆