Three.js: chaotic mesh rotation after applyMatrix - matrix

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

Related

THREE.js raycaster intersectObject method returns no intersection when checking if point is inside mesh

I want to check whether a point is inside a mesh or not. To do so, I use a raycaster, set it to the point's origin and if the ray intersects the mesh only once, it must be inside. Unfortunately, the intersectObject always returns no intersection, even in cases I know that the point is located inside the mesh.
The point's origin is given in world coordinates and the mesh's matrixWorld is up to date too. Also, I set the mesh.material.side to THREE.DoubleSide, so that the intersection from inside should be detected. I tried setting the recursive attribute to true as well, but as expected, this didn't have any effect (since the mesh is a box geometry). The mesh is coming from the Autodesk Forge viewer interface.
Here is my code:
mesh.material.side = THREE.DoubleSide;
const raycaster = new THREE.Raycaster();
let vertex = new THREE.Vector3();
vertex.fromArray(positions, positionIndex);
vertex.applyMatrix4(matrixWorld);
const rayDirection = new THREE.Vector3(1, 1, 1).normalize();
raycaster.set(vertex, rayDirection);
const intersects = raycaster.intersectObject(mesh);
if (intersects.length % 2 === 1) {
isPointInside = true;
}
The vertex looks like this (and it obviosly lies inside of the bounding box):
The mesh is a box shaped room with the following bounding box:
The mesh looks like this:
The geometry of the mesh holds the vertices in the vb. After applying the world matrix, the mesh vertices are correct in world space. Here is a part of the vb list:
Why does the raycaster not return any intersection? Is the matrixWorld of the mesh taken into account when computing the intersections?
Thanks for any kind of help!
Note that Forge Viewer is based on three.js version R71, and it had to modify/reimplement some parts of the library to handle large and complex models (especially architecture and infrastructure designs), so THREE.Mesh objects might have a slightly different structure. In that case I'd suggest to raycast using Forge Viewer's own mechanisms, e.g., using viewer.impl.rayIntersect(ray, ignoreTransparent, dbIds, modelIds, intersections);.

THREEjs, updating an object's matrix doesnt change it's position and rotation params

I want to set a transformation matrix to an object upon creation and then control it by position, rotation and scale, but while changing the matrix does change the object in world space, it's position parameter still remains 0, 0, 0.
let mesh = new THREE.Mesh(
new THREE.BoxGeometry(),
new THREE.MeshPhongMaterial({color:0xf15728})
)
this.scene.add(mesh)
let pos = new THREE.Vector3().setFromMatrixPosition(m)
mesh.matrixAutoUpdate = false
mesh.matrix.copy(m)
// ***************//
mesh.updateMatrix()
// ***************//
console.log("mesh.position", mesh.position)
console.log("pos", pos)
Here's the output for the values of both pos and mesh.position
Updating an objects matrix does not update its position or rotation fields and by default three.js will update the matrix based on the position, rotation, and scale values before rendering (which you've disabled by setting matrixAutoUpdate to false).
If you would like to initialize an objects transformation from a matrix you can use the Matrix4.decompose function like so:
// m is the initial local matrix transform
m.decompose(
mesh.position,
mesh.quaternion,
mesh.scale,
);
Also if you keep mesh.matrixAutoUpdate = false you will have to call mesh.updateMatrix() before rendering whenever the position, rotation, or scale values are changed.
You can read more on how matrix transformations work here.

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.

Resources