This question already has an answer here:
Three.js add an object to a group but keep global position/rotation/scale as it was
(1 answer)
Closed 6 years ago.
When I add an Object3D to another Object3D ("add" method) the child changes its transform depending on parent's one.
Is there a way to keep position/rotation/scale of the child after adding it to a parent?
Fiddle: https://jsfiddle.net/pqfzd8a2/1/
mesh = new THREE.Mesh(geometry, material);
mesh.position.y = 25;
var mesh2 = mesh.clone();
mesh2.position.y = 80;
var mesh3 = mesh2.clone();
mesh.rotation.z = Math.PI*0.25;
scene.add(mesh);
mesh.add(mesh2);
scene.add(mesh3);
What was done?
mesh is rotated.
mesh2 and mesh3 are clones of each other with same position.
mesh2 is added to mesh, while mesh3 was added to scene.
The difference between mesh2 and mesh3 is that they were added (parented) to different parents (to mesh and directly to the scene, correspondingly). Before being added (parented) to something, they were in same position. The point is to keep the object where it was before being added (parented).
Expected result: mesh2 and mesh3 should be in the same positions.
Actual result: mesh2 changes position/rotation/scale after being added.
How to make objects keep their global transform after being parented?
Well that is the defined behaviour and at least the reason why those hierarchical structures exist. If you do not want to apply the parent's transform on the child, there is no reason to parent those items.
With this approach it is much easier to handle complex Objects, which are composed of smaller objects, like a car with wheels. Instead of moving the car and then each wheel, one makes the wheels childs of the car and they will move/rotate/scale with it all the time. That is how the transformation of the parent is »inherited« by all its children. So their transform is relative their respective parent. Like the moon rotates around the earth, which rotated around the sun, which rotates around whetever…
If you really need to cancel out the parents transform within a child, then you need to apply the inverse of parents transform to the child's transform, but as I said, that does not make much sense, because you just do not need to parent them and your done.
No they shouldn't be in the same position, because you are changing position and rotation of both mesh and mesh2. If you are adding a mesh to another you are adding it to the parent context.
mesh.add(mesh2); // <-- mesh is translated and rotated, mesh2 will inherit the same context
In this fiddle you see that the rotation on mesh also applies to mesh2: https://jsfiddle.net/r57opdgn/
Related
In my current project, I need a way to outline a mesh.This color outline will represent the object's current state, relevant for me.
The problem is that it is a custom mesh, loaded using JSONLoader.
I've tried different approaches, following (mainly) these 2 examples: https://stemkoski.github.io/Three.js/Outline.html and
THREEx.geometricglow. In both cases, I scale the mesh outline to a bit bigger than the original. My main problem is that scaling equally in all axis will not cover my object the way I intended to.
Here is the code I'm using:
var outlineMaterial2 = new THREE.MeshBasicMaterial( { color: 0x00ff00, side: THREE.BackSide, transparent: true, opacity:0.5 } );
var outlineMesh2 = new THREE.Mesh( object.geometry, outlineMaterial2 );
outlineMesh2.position.copy(object.position);
outlineMesh2.scale.copy(object.scale);
outlineMesh2.scale.multiplyScalar(1.1)
scene.add( outlineMesh2 );
`
With a simple cube mesh, the outline will be good.
But with my custom mesh, the scale will not fit the shape correctly.
Here is a image demonstrating: http://s13.postimg.org/syujtd75z/print1.png
Also, using Stemkoski approach, the outlining mesh will also show in front of the object, not just outline (as seen in the above picture).
My question is: How should I resize the mesh? For what I know, it might have something to do with face normals.
Thanks for your time.
In Object3D contains a mesh
Object3D has an arbitrary scaling
Mesh has an arbitrary rotation. So my mesh is scaled relative to world coordinates.
But when I detach my mesh in the scene (for example, with the aid of THREE.SceneUtils.detach (mesh, obj3d, scene) I get an incorrect result, the mesh is scaled only locally.
I tried to change the geometry of the mesh, but still get an incorrect result:
http://jsfiddle.net/Ni55aN/VsWb9/3426/
var euler = new THREE.Euler(-mesh.rotation.x,-mesh.rotation.y,-mesh.rotation.z);
mesh.geometry.applyMatrix(new THREE.Matrix4().makeRotationFromEuler(mesh.rotation));
mesh.geometry.applyMatrix(new THREE.Matrix4().makeScale(
obj.scale.x,
obj.scale.y,
obj.scale.z
));
mesh.geometry.applyMatrix(new THREE.Matrix4().makeRotationFromEuler(euler));
mesh.geometry.verticesNeedUpdate=true;
I realized what was my mistake.
It was necessary to apply getInverse of my first matrix instead .makeRotationFromEuler with negative values
var firstMatrix=new THREE.Matrix4().makeRotationFromEuler(mesh.rotation);
var inverseMatrix=new THREE.Matrix4().getInverse(firstMatrix);
mesh.geometry.applyMatrix(firstMatrix);
mesh.geometry.applyMatrix(new THREE.Matrix4().makeScale(
obj.scale.x,
obj.scale.y,
obj.scale.z
));
mesh.geometry.applyMatrix(inverseMatrix);
mesh.geometry.verticesNeedUpdate=true;
Within my THREE scene i have an Object that rotates. The child object is positioned at (92,92,92) within the rotating Object, so it orbits the centre position (0,0,0) is a spherical path with my mouse movement. How can i find the global position of the child object in respect to the scene as it rotates. I'm fairly new to THREE.js and thankful for any support in advance.
My code:
ObjectParent = new THREE.Object3D();
scene.add( ObjectParent );
ObjectChild = new THREE.Object3D();
ObjectParent.add( ObjectChild );
ObjectChild.position.set(92,92,92);
Render:
ObjectParent.rotation.y -= (target.y + ObjectParent.rotation.y) * 0.08;
ObjectParent.rotation.x += (target.x - ObjectParent.rotation.x) * 0.07;
ObjectParent.updateMatrixWorld();
scene.updateMatrixWorld();
First of all, you usually do not need to call
ObjectParent.updateMatrixWorld();
scene.updateMatrixWorld();
inside your render loop. The renderer will do that for you.
To find the world position of a child object, you can use this pattern:
var vector = new THREE.Vector3();
...
vector.setFromMatrixPosition( child.matrixWorld );
The renderer should have previously updated the scene matrices for you. If you have changed a parent's position since the last rendering, you will have to first call
parent.updateMatrixWorld();
to update the relevant matrices.
It is a good idea to look at the three.js source code so you understand what these functions do.
three.js r.67
I have a Three.js Scene with several meshes moving around. I want to take a snap shot and copy all of the mesh locations by placing a new instance of a mesh (with the same geometry) in the scene in the same location & with the same rotation. I can't simply copy the mesh's .position & .rotation because the mesh is a child to other meshes. I tried to .clone() the mesh's matrixWorld but that didn't work. How do you inherit the world location of a mesh?
This is what I am trying to do:
// mesh is an existing mesh loaded into a scene
// geom is an existing geometry definition
var material = new THREE.MeshFaceMaterial();
var newMesh = new THREE.Mesh( geom, material);
newMesh.matrixWorld = mesh.matrixWorld.clone();
scene.add(newMesh);
Any help would be much appreciated.
It's as simple as this:
newMesh.position.copy( mesh.matrixWorld.getPosition() );
EDIT: See this updated answer, instead.
I have some custom geometries obtained from a STEP file conversion and I use the mouse to rotate them. They rotate around the origin of the scene, but since they are far from it, they seem rotating on a virtual sphere. How can I move them to the origin so that they don't seem "floating" around (I mean that I'd like to reduce to zero the radius of the virtual sphere). This is the example I'd like to move. I've tried setting their position to (0, 0, 0) doing:
object.position.x = 0;
object.position.y = 0;
object.position.z = 0;
but it didin't work.
The typical solution to this problem is to translate the geometry right after it is created. You do that by applying a translation matrix to the geometry like so:
geometry.applyMatrix( new THREE.Matrix4().makeTranslation( distX, distY, distZ ) );
EDIT: You can simply do this, instead:
geometry.translate( distX, distY, distZ ); // three.js r.72
The function geometry.computeBoundingBox() may be of help to you in determining an amount to translate.
However, I see in your case, you have multiple geometries, so it it a bit more complicated, but doable. You will need to translate each geometry by the same amount.
EDIT
Tip: Instead of adding each object to the scene, create a parent object, add it to the scene, and then add the objects to the parent.
var parent;
parent = new THREE.Object3D();
scene.add( parent );
parent.add( object1 );
parent.add( object2 );
// and so on...
Then in your render function, just rotate the parent, not the individual objects.