1

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?

  1. mesh is rotated.
  2. mesh2 and mesh3 are clones of each other with same position.
  3. 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?

Dmitry
  • 543
  • 2
  • 5
  • 20
  • What is exact the use case for that? Why do you really need a child object, that should be at its parent level in hierachy? Why can't you just move the child to another level in hierachy? – philipp Nov 21 '16 at 20:07
  • Moving child objects around is important in physics and sensor systems where these objects may change where they are placed (even at runtime). A position of an object (world) should _always_ be constant. The local matrix should reflect the parent relationship (thats why its a local space). Changing the hierarchy is not at question, its the fact the world matrix is being modified and thus each time its moved you need to have a before and after behaviour to maintain it. This is a classic scenegraph mistake and makes managing objects extremely difficult. – David Lannan Apr 07 '19 at 02:44
  • In response to q: I would recommend implementing your own Push/Pop stack and make your own child/parent hierarchy. It will be very difficult to manage large scene structures of dynamic entities otherwise. You could use a lightweight location database if you want a more 'loose' hierarchy. Ive implemented OpenSteers LQ DB for that exact purpose. – David Lannan Apr 07 '19 at 02:46

2 Answers2

0

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.

philipp
  • 15,947
  • 15
  • 61
  • 106
  • 1
    This is an incorrect statement. You are saying that its "ok" to change the world matrix of an object when you change the childs parents. The world matrix should remain the same, the local matrix (for the child) should change based on the parenting. This is a _normal_ hierarchy scenegraph (even back to SGI Performer, this is how it should work). If you change the world position of the child _everytime_ a child is added/removed from a parent, you then need to have pre and post behaviours when objects are re-parented. This is clearly incorrect. – David Lannan Apr 07 '19 at 02:36
0

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/

Marcs
  • 3,768
  • 5
  • 33
  • 42
  • Yes, I'm adding it into parent context. But how to make child keep its position? – Dmitry Nov 21 '16 at 14:31
  • When you are adding `mesh2` to `mesh` you are also changing context (`mesh` is the origin), in your scene if you want to keep `mesh2` at the same translation in space of `mesh`, reset `position.y` to zero: `mesh2.position.y = 0`. If you want to use global axes you shouldn't set `mesh2` as a child of `mesh`. – Marcs Nov 21 '16 at 15:08
  • The world matrix should _never_ be changed when you change a parenting of an object. ThreeJS is odd in this manner - you wont find other engines that _move_ the world position of the object when it becomes a child. The problem with this is that underneath the world position is being copied into the local position - this is incorrect mathematical behaviour. The childs world matrix should remain _the_same_ and its local matrix change, based on its parent relationship. – David Lannan Apr 07 '19 at 02:31