Issues with updating transformation matrices

Hi,

I’m working on a project using three.js and I want to get a better grip on the transformation matrices and how they work. What I want to be able to do is to store - outside of three.js - geometry/meshes once (e.g. a box) that can be located at multiple locations (each location has a transformation matrix). When I was playing with transformation matrices, I’ve had some strange results while sending intermediate results to the console:

// cube is a mesh (box geometry) that is not transformed yet
var m1 = cube.matrix;
console.log(m1); //already updated before doing the transformation => NOT EXPECTED
//[2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 4, 0, 0, 1]

// do transformations on a standard cube (not transformed) using a matrix
cube.scale.set(2,2,2);
cube.translateX(4);

// checking transformation matrix again
var m2 = cube.matrix;
console.log(m2); //is updated according to transformations as expected
//[2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 4, 0, 0, 1]
console.log(m2.elements); // array (= the actual matrix) is not changed => NOT EXPECTED
//[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
console.log(m2.elements[12]); // an individual element of the matrix is not changed => NOT EXPECTED
//0

// other methods to extract translation/rotation/scaling: matrix components are not updated => NOT EXPECTED
var v = new THREE.Vector3();
var r = new THREE.Quaternion();
var s = new THREE.Vector3();
m2.decompose(v,r,s);
console.log(v);
//{x: 0, y: 0, z: 0}
console.log(r);
//{_x: 0, _y: 0, _z: 0, _w: 1}
console.log(s);
//{x: 1, y: 1, z: 1}

// other methods to extract translation/rotation/scaling: matrix components are not updated => NOT EXPECTED
var vec = new THREE.Vector3();
var rot = new THREE.Quaternion();
var sca = new THREE.Vector3();
vec.setFromMatrixPosition( cube.matrix );
rot.setFromRotationMatrix( cube.matrix );
sca.setFromMatrixScale( cube.matrix );
console.log(vec);
//{x: 0, y: 0, z: 0}
console.log(rot);
//{_x: 0, _y: 0, _z: 0, _w: 1}
console.log(sca);
//{x: 1, y: 1, z: 1}

So my question: is this normal behavior or is it some kind of bug? How should transformation matrices be accessed?

If you use Object3D.scale() or Object3D.translateX(), you only change the scale and position property of your cube. You have to call Object3D.updateMatrix() in order to compose the transformation matrix (representing the local space of the object) from position, rotation/quaternion and scale. The following fiddle should illustrate this:

https://jsfiddle.net/f2Lommf5/15034/

BTW: Since the fiddle logs the same array object three times, you have to run the fiddle with open dev console. If you open the dev tools after you run the script, you will just see some minimized logs of the array object. When you click on one of these minimized entries, you will always see the latest state of the object and thus wrong values.

Hi thanks,

Okay, so three.js keeps track of the individual translation, rotation and scaling and you have to manually ask it to compose/update the transformation matrix. Only then, you can use the transformation matrix to perform an operation on other objects?

Well, the renderer does update the matrix as long as Object3D.matrixAutoUpdate is set to true (default). But if you change let’s say the position property of a mesh, you have to call Object3D.updateMatrix() if you immediately want to use Object3D.matrix. Read the following guide for more information:

https://threejs.org/docs/index.html#manual/en/introduction/Matrix-transformations

I think I have an additional issue with transformations of meshes. I created rows of cubes by creating one and translating it to its position. I also add it to scene and see the rows of cubes. In the same function, I also export each cube to an OBJ after having translated the cube. The problem is that all my cubes in OBJ are the same (the not translated cube). I thought it had to do something with the matrix of each cube that had to updated, but that didn’t helped… Here is the code:

createOBJBoxes(3);
function createOBJBoxes (amount){
	var k = 0;
	for ( var i = 1 ; i < amount+1 ; i++ ){
		var testBox = createBox();
		testBox.translateX(k);
		testBox.updateMatrix();
		k += 2;
		var exp = new THREE.OBJExporter();
		var res = exp.parse(testBox);
		var content = "data:application/plain;charset=utf-8," + escape( res );
            window.open( content, '_blank' );
	}
}

// function to create one box
function createBox (){
	var boxSampleGeometry = new THREE.BoxGeometry( 1 , 1 , 1 );
	var boxSampleMaterial = new THREE.MeshLambertMaterial();
	var boxSampleMesh = new THREE.Mesh( boxSampleGeometry , boxSampleMaterial );
	scene.add(boxSampleMesh);
	return boxSampleMesh;
}