设置three.js对象的matrixWorld属性

时间:2016-05-25 19:46:17

标签: javascript matrix 3d three.js transform

我有一个包含编码旋转和位置数据的4x4变换矩阵的数组(我已经确认此矩阵表示Octave中的有效变换)。我想使用此数组的内容设置three.js对象(Object3D)的matrixWorld属性,即根据转换矩阵设置对象的位置和旋转。

根据来自three.js文档的this page和此处提出的各种问题(例如,this onethis one),似乎关键是要将nameOfObject.matrixAutoUpdate设置为假。但是,考虑到这一点,我尝试了各种方法来设置nameOfObject.matrixWorld,并且它们都没有改变渲染对象的位置:它保留在原点而没有旋转,就像这样当matrixWorld是4x4单位矩阵时。

以下是我尝试过的内容(此代码在调用render()之前的更新方法中):

// Setting up a three.js matrix
var tempMatrix = new THREE.Matrix4();
tempMatrix.fromArray(arrayContainingTransformationMatrix);

// Values are set as expected
console.log(tempMatrix.elements);

// Note that the approaches below were tried one at a time

// First approach (doesn't work)
nameOfObject.matrixAutoUpdate = false;
nameOfObject.matrixWorld.copy(tempMatrix);

// Second approach (also doesn't work)
// Based on the second SO question linked above
nameOfObject.matrixAutoUpdate = false;
nameOfObject.matrix.copy(tempMatrix);
nameOfObject.updateMatrixWorld(true);

// Third approach (this doesn't work either, unfortunately)
nameOfObject.matrixAutoUpdate = false;
nameOfObject.matrixWorld.fromArray(arrayContainingTransformationMatrix);

// Appears to be set correctly regardless of which approach is used
console.log(sphere1.matrixWorld.elements);

一些注意事项:

  • 我希望在每次迭代中都不需要将matrixAutoUpdate设置为false,但是现在我只是为了安全起见。
  • 如果根据转换矩阵的第四列中的值修改nameOfObject.position而不是更改matrixWorld,则对象的位置会按预期更改,因此这并非如此似乎是一个渲染问题。
  • 我已在多个位置读取,在手动设置矩阵时不应调用updateMatrix(),因为它会根据positionrotation属性覆盖矩阵。我假设updateMatrixWorld()受到类似的考虑,但我还没有找到关于它做什么的讨论。

任何建议将不胜感激!最糟糕的情况我会查看来源,但到目前为止,三个.js一直很容易使用,我怀疑我只是遗漏了一些东西。

2 个答案:

答案 0 :(得分:2)

现在,我可以通过设置对象的matrix属性(相对于对象父级的局部变换)来实现所需的结果。由于对象的父级是scene,因此这样的代码可以工作:

scene.add(nameOfObject);

// Using this transformation matrix (translation of two units along the x axis):
// 1 0 0 2
// 0 1 0 0
// 0 0 1 0
// 0 0 0 1

// Column-major version of the transformation
var tempArrayCM = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1];
// Per the docs, Matrix4.fromArray() uses column-major format

// Row-major version of the transformation
var matrixT = new THREE.Matrix4();
matrixT.set(1, 0, 0, 2, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
// Per the docs, Matrix4.set() uses row-major format

nameOfObject.matrixAutoUpdate = false;

nameOfObject.matrix.fromArray(tempArrayCM); // This works

//nameOfObject.matrix.copy(matrixT); // This also works

//nameOfObject.matrixWorld.fromArray(tempArrayCM); // No effect

//nameOfObject.matrixWorld.copy(matrixT); // No effect

似乎设置matrixWorld不起作用。我认为当有问题的对象是scene的孩子时这很好,但我可以想象如果对象是scene的孩子的孩子并且有必要设置其世界位置,这会导致问题独立于其父级(编辑>,SceneUtilsattachdetach方法似乎允许这样做,尽管是间接的)。

我不会将此标记为答案,因为它实际上只是在对象的父级为scene时才适用的解决方法。

暂且不说:我发现Matrix4.set()使用行主要订单但Matrix4.fromArray()Matrix4.elements使用列主要订单时有点奇怪。

答案 1 :(得分:0)

浏览源代码。

updateMatrix: function () {
        this.matrix.compose( this.position, this.quaternion, this.scale );
        this.matrixWorldNeedsUpdate = true;
    },

我们看到Object3D的矩阵是根据其位置,四元数和比例参数构建的。

因此,与其设置矩阵,不如设置构成矩阵的各个部分可能更容易。

例如,此代码转换场景,使其居中于范围中间,并缩放以适合场景。

    let xrange = xmax-xmin, yrange = ymax-ymin, zrange = zmax-zmin;
    let range = (xrange+yrange+zrange)/3;
    scene.scale.set(2/range,2/range,2/range);
    scene.position.set( -(xmax+xmin)/2, -(ymax+ymin)/2, -(zmax+zmin)/2); 
    seene.updateMatrix();