Getting Global Rotation position of object in ThreeJS - three.js

Just like we have getWorldPosition(), is there a way we can get the absolute Rotation angle of an object. This will be relevant when the object is under another object; both of which could be rotated.
Thanks

You can use the matrixWorld property on objects and use the setFromRotationMatrix function on Euler to get the angles:
// make sure the matrix world is up to date
obj.updateMatrixWorld();
// extract the rotation matrix
const rotMat = new THREE.Matrix4();
obj.matrixWorld.extractRotation(rotMat);
// extract the rotation
const euler = new THREE.Euler();
euler.setFromRotationMatrix(rotMat);
There are equivalent function for quaternions
Hope that helps!

Related

Threejs mesh matrix getInverse Uncaught TypeError: Cannot read property 'elements' of undefined

I have baisc problem that I am strugling to solve using the ThreeJs apis, due to an exception of
Uncaught TypeError: Cannot read property 'elements' of undefined
Essentially this is very basic problem that most likely boils to some improper use of the threejs apis (perhaps i have the wrong assumption / understanding of what a mesh.matrix represents).
The problem I am trying to solve is utterly basic.
I have some offset coordinates (x,y,z) where the (x,y,z) is a vluae
in the world coordinate system.
Let us call this x,y,z offset coordinates the concept of "Approach".
And this approach represents some offset distance away from an abitrary object that we can call "SomeObject".
The ultimate goal is that it would be nice to represent this distance away as sphere in the air that would be added to the scene as child object of SomeObject.
Obvisouly, I cannot simply take these (x,y,z) representing an offset in real world coordinates and simply add my sphere as:
Approach.x = x;
Approach.y = y;
Approach.z = z;
SomeObject.add(appraoch)
This pseudo code above is completely wrong.
This code above makes no sense, it would only work when the SomeObject orientation to the world is 0 degrees. On all other situations the X,Y,Z axis of SomeObject will not coincice with the positions of the world coordinate system and the Sphere would appear on the wrong side of my object.
In short, this Offset must be translated from world coordinates into SomeObject coordinates.
Mathematically, what I am saying is trivial.
The problem to be solved is nothing more that the following Homogeneous Transformation Matrix multiplication.
meshApproachTo2SomecObject = wolrd2SomeObjectMatrix X meshApproach2World.matrix;
That is all and game over.
The code I tried to run looks as follows:
var whitekMaterial = new THREE.MeshBasicMaterial( {color: 0xFFFFF} );
var dummyGeometry = new THREE.SphereGeometry( 50);
var meshApproach2World = new THREE.Mesh( dummyGeometry, whitekMaterial );
meshApproach2World.position.x = 560;
meshApproach2World.position.y = -760;
meshApproach2World.position.z = 381;
meshApproach2World.updateMatrix();
// meshApproach2World.matrix.getPosition()
var someOject2World = new THREE.Mesh( dummyGeometry, whitekMaterial );
someOject2World.position.x = 0;
someOject2World.position.y = 0;
someOject2World.position.z = 0;
someOject2World.rotation.z = Math.PI/2;
someOject2World.updateMatrix();
// compute the COORDINATES of the APPRORACH OBJECT Relative to the "SOmeObject
// Mathmathicall APPROACH2SomeObject= World2SomeObject X Apporache2World
// Therefore
var wolrd2SomeObjectMatrix = someOject2World.matrix.getInverse();
// Do later
// ApproachOffset2SomecObjectMatrix = wolrd2SomeObjectMatrix X ApproachOffset2WorldMatrix;
Obviously if in the exercise above my SomeObject is 90 degrees rotated relative to the world coordinate system, the transformation of (x,y,z) = (560, -760, 381)
is supposed to return:
coordinates=CalcCoordinates [x=-760.0, y=-560.0, z=381.0] ,
orientation=CalcOrientation [aYawDegrees=270.0, bPitchDegrees=-0.0,
cRollDegrees=0.0]
x2=Y1
Y2=-X1
Z2=Z1
However, I get stuck when I try to get the coordinates of the world relative to my some object.
When I try to get the inverse matrix:
var wolrd2SomeObjectMatrix = someOject2World.matrix.getInverse();
Threejs blows up.
I thought that when you have a mesh in threejs, the MATRIX represents HTM from that object relative to the world.
you should threfore be able to get the mesh 4x4 matrix and ask for its inverse.
Instead it blows up... with this not so understandable exception.
Thanks for your help.

Rotate around World Axis

I tried to rotate an object arount the Worlds-Y-Axis, with
myObject.rotateOnWorldAxis(new THREE.Vector3(0,1,0),THREE.Math.degToRad(1));
but the result was, that the object is only rotated in object space.
To be sure that I used the correct method I looked into the documentation and found that there are three methods to rotate an object:
.RotateY(rad) // rotate in Local Space
.rotateOnAxis(axis,rad) // rotation in Object Space
.rotateOnWorldAxis(axis,rad) // rotation in World Space
It seems that I used the correct method.
Is this a bug or an understanding problem on my side?
Here is a JSFiddle which illustrates my problem (the blue cube should rotate around the world axis).
Here is a second Fiddle where thy cyan cube is a child of another object.
It looks to me like your real question isn't regarding world space or object space rotations, cause those are working as expected in your examples.
You probably meant, how to change the point of rotation of an object. If that is the case, you have two options, you can either translate all your geometry vertices in respect to a pivot point of rotation. That way, your pivot will be centered at (0,0,0) and your vertices will rotate in respect to that.
mesh.geometry.translate( x, y, z );
Or you can make your object a child of a different Object3D (pivot), position your original mesh similarly to what was described above and rotate your pivot mesh.
var cube = new THREE.Mesh( geometry, material );
var pivot = new THREE.Object3D();
cube.position.set( 0, 12, 30 ); // offset from center
pivot.add( cube );
scene.add( pivot );
//...
pivot.rotation.y += Math.PI/2;
JSFiddle

three.js bind Plane to proxy Object transformations

I'm trying to transform a Plane according to a Object3D (position and rotation). That Plane is used as a clippingPlane.
If I call Plane.applyMatrix4( Object.matrixWorld ) it just applies the matrix once, and doesn't bind the Plane to that matrix for future transformations.
However if I call the same function in a loop the transformations applied to the Plane are continuous.
EG if I call Object.rotate.z = 1 once, and then Plane.applyMatrix4( Object.matrixWorld ) in a loop, the Plane rotates 1 unit along the Z axis at every loop.
Any ideas?
Being this Plane used as a clipping plane, I also tried to transform it in the shader material of the mesh being clipped, and it maybe would be the best performance-wise, but I'm not so skilled to accomplish that.
I would just to this:
object.add( plane );
In this way, plane is a child of object. All transformations applied to object are also applied to plane. Besides, it's now very easy to transform plane relative to object.
The quickest solution I found is to reset and apply Object's .matrixWorld to the Plane. As I said before, it would be great to add useful transformation and "binding" methods to the THREE.Plane object, since it's used as clipping plane too.
Right now I did this way:
// will store the object's inverse transformations matrix in world coords
var inversePrevMatrix = new THREE.Matrix4();
function loop(){
// reset plane previous transformations
plane.applyMatrix4( inversePrevMatrix );
// apply actual object matrix in world coordinates
plane.applyMatrix4( object.matrixWorld );
// set prevMatrix
inversePrevMatrix.getInverse( object.matrixWorld );
}

Three.js - change camera POV on click

Some project background:
I have a Sprite particle field that is randomly generated. The camera is located at position 0, 0, 0. The particle field is all around the camera. I'm using Raycaster to be able to select the particle that is clicked on and change it's color. Once clicked I would like the camera to focus on this particle. I'm also attempting to use Tween to glide the particle into view.
I've attempted several different methods and none of them work. They are described here:
A traditional lookAt method that used Raycaster to pick up the intersect point from clicking.
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, this.camera);
var intersects = raycaster.intersectObjects( this.starfield.children );
this.camera.lookAt(intersects[0].object.position)
A distanceTo method where the distance between the camera and the intersect coordinates is used to move the camera. This only moves the camera along the z plane. It wont actually change its POV.
var cameraPosition = new THREE.Vector3(this.camera.position.x, this.camera.position.y, this.camera.position.z);
var intersectPosition = new THREE.Vector3(intersects[0].object.position.x, intersects[0].object.position.y , intersects[0].object.position.z );
var zoomPos = intersectPosition.distanceTo( cameraPosition );
const newCameraPosition = cameraPosition.addVectors(this.camera.position, vector.setLength(zoomPos));
I calculated the angle of rotation for each X, Y, and Z axis via tan and cos equations. I then attempted to rotate the camera by those degrees. I even tried converting them to radians to see if that would make a difference with the rotation method. It didnt :(
I don't know what else to do. At this stage I'm completely open to a different approach as long as I get this camera working. I'm very stuck,
any help would be greatly appreciated!
Instead of using
intersects[0].object.position
try using
intersects[0].point
.point is the world space position of the hit.
.objectis the object the triangle belongs to. .object.position is just the origin of that object, in this case the particle system. The particle positions themselves are relative to this origin.

Three.js: chaotic mesh rotation after applyMatrix

After applying a matrix to mesh I print its rotation parameters.
After resetting mesh rotation, scale and position and re-applying the same matrix - rotation parameters aren't equal to previous ones.
var ctm1 = new THREE.Matrix4();
var ctm2 = new THREE.Matrix4();
ctm1.set(...............);
ctm2.set(...............);
function reset(mesh)
{
mesh.position.set(0,0,0);
mesh.scale.set(5,5,5);
mesh.rotation.set(0,0,0);
}
reset(myMesh);
myMesh.applyMatrix(ctm1);
console.log(myMesh.rotation.x);
reset(myMesh);
myMesh.applyMatrix(ctm2);
reset(myMesh);
myMesh.applyMatrix(ctm1);
console.log(myMesh.rotation.x); //Isn't equal to previous output !!!
Three.js r.58
The three.js renderer handles updating the object matrix, so that the matrix is consistent with the object's position, rotation, and scale.
Since you do not make a render() call, you need to add mesh.updateMatrix() as the last line of your reset() function.
three.js r.58

Resources