javascript - Setting matrixWorld property of a three.js object - Stack Overflow

I have an array containing a 4x4 transformation matrix encoding rotation and position data (I've a

I have an array containing a 4x4 transformation matrix encoding rotation and position data (I've already confirmed that this matrix represents a valid transformation in Octave). I'd like to set the matrixWorld property of a three.js object (an Object3D) using the contents of this array, i.e., set the position and rotation of the object based on the transformation matrix.

According to this page from the three.js documentation and various questions asked here (e.g., this one and this one), it seems the key is to set nameOfObject.matrixAutoUpdate to false. However, with this accounted for, I've tried a variety of approaches to set nameOfObject.matrixWorld and none of them change the location where the object is rendered: it remains at the origin with no rotation, as is the case when matrixWorld is the 4x4 identity matrix.

Here's what I've tried (this code is inside an update method before render() is called):

// 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);

A few notes:

  • I'd expect that it's not actually necessary to set matrixAutoUpdate to false inside every iteration, but for now I've done so just to play it safe.
  • If nameOfObject.position is modified based on the values in the fourth column of the transformation matrix instead of changing matrixWorld, the object's position changes as expected, so this doesn't appear to be a rendering issue.
  • I've read in multiple locations that updateMatrix() shouldn't be called when manually setting the matrix as it overwrites it based on the position and rotation properties. I'd assume updateMatrixWorld() is subject to similar considerations, but I haven't found as much discussion of what it does.

Any suggestions would be appreciated! Worst case I'll look through the source, but three.js has been quite easy to use thus far and I suspect I'm simply missing something.

I have an array containing a 4x4 transformation matrix encoding rotation and position data (I've already confirmed that this matrix represents a valid transformation in Octave). I'd like to set the matrixWorld property of a three.js object (an Object3D) using the contents of this array, i.e., set the position and rotation of the object based on the transformation matrix.

According to this page from the three.js documentation and various questions asked here (e.g., this one and this one), it seems the key is to set nameOfObject.matrixAutoUpdate to false. However, with this accounted for, I've tried a variety of approaches to set nameOfObject.matrixWorld and none of them change the location where the object is rendered: it remains at the origin with no rotation, as is the case when matrixWorld is the 4x4 identity matrix.

Here's what I've tried (this code is inside an update method before render() is called):

// 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);

A few notes:

  • I'd expect that it's not actually necessary to set matrixAutoUpdate to false inside every iteration, but for now I've done so just to play it safe.
  • If nameOfObject.position is modified based on the values in the fourth column of the transformation matrix instead of changing matrixWorld, the object's position changes as expected, so this doesn't appear to be a rendering issue.
  • I've read in multiple locations that updateMatrix() shouldn't be called when manually setting the matrix as it overwrites it based on the position and rotation properties. I'd assume updateMatrixWorld() is subject to similar considerations, but I haven't found as much discussion of what it does.

Any suggestions would be appreciated! Worst case I'll look through the source, but three.js has been quite easy to use thus far and I suspect I'm simply missing something.

Share Improve this question edited May 23, 2017 at 12:15 CommunityBot 11 silver badge asked May 25, 2016 at 19:46 Reign of ErrorReign of Error 6256 silver badges19 bronze badges 7
  • You can only set the object's matrix. You can't set the object's world matrix. Is this your question? "How can I set object.matrix so that it results in a particular object.matrixWorld -- taking into account the transforms of the object's parents?" – WestLangley Commented May 26, 2016 at 21:24
  • If the object's world matrix is read-only, that answers my question. I assumed it could be set because the matrixWorld property isn't labelled "readonly" in the Object3D docs (the descriptions for other read-only properties, e.g., id, start with "readonly"). – Reign of Error Commented May 27, 2016 at 14:17
  • 1 It is not read-only. The renderer is resetting it. – WestLangley Commented May 27, 2016 at 16:39
  • Is it possible to prevent the renderer from doing so? (I realize this isn't essential given the attach and detach methods in SceneUtils.) The description of matrixAutoUpdate seems to imply that setting it to false should prevent both matrix and matrixWorld from updating, but this appears to only prevent matrix from being updated. – Reign of Error Commented May 27, 2016 at 18:36
  • I am trying to understand what you are trying to achieve. If you answer the question in my first ment, that would be helpful. – WestLangley Commented May 27, 2016 at 19:34
 |  Show 2 more ments

3 Answers 3

Reset to default 2

For now, I was able to achieve the desired result by setting the object's matrix property (the local transform relative to the object's parent). Since the object's parent is scene, code like this works:

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

It seems setting matrixWorld just doesn't work. I suppose this is fine when the object in question is a child of scene, but I can imagine this causing problems if the object is a child of a child of scene and it's necessary to set its world position independent of its parent (edit: it appears that the attach and detach methods of SceneUtils would permit this, albeit indirectly).

I won't be marking this as the answer since it's really just a workaround that applies only when the object's parent is scene.

An aside: I find it a little odd that Matrix4.set() uses row-major order but Matrix4.fromArray() and Matrix4.elements use column-major order.

Looking through the source.

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

We see that an Object3D's matrix is built from it position, quaternion and scale parameters.

So rather than setting the matrix its might be easier to set the individual parts making up the matrix.

For example this code translates the scene so its centered on the middle of the range and scales it to fit.

    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();

Generally speaking, we will use the following methods to update matrixWorld of an object.

    const mesh = new THREE.Mesh();
    const matrixWorld = new THREE.Matrix4();
    // this will update mesh position, quaternion and scale with new matrix.
    matrixWorld.depose(mesh.position, mesh.quaternion, mesh.scale);

This is official remendations in three doc.

https://threejs/docs/#manual/en/introduction/Matrix-transformations

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744347880a4569797.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信