mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
102.15k stars 35.34k forks source link

THREE Group and Object3D add child BUG. #6426

Closed RemusMar closed 9 years ago

RemusMar commented 9 years ago

Ricardo, why did you delete the reported issue? I'm a 3DS Max user since the DOS era, so I know very well what I'm saying. Again:

Result: everything is messed up ! That previous child object will get position and rotation (0,0,0) and scale(1,1,1). And that's wrong! Perform the same operations with 3DS Max. The new group (parent) will not mess up the new children parameters.

cheers

mrdoob commented 9 years ago

Uh! I didn't delete it. In fact. Github doesn't allow deleting issues...?

mrdoob commented 9 years ago

Ah no... It's still there: #6424 Please, don't create duplicated issues, you can continue the discussion in the original one even if it has been closed.

mrdoob commented 9 years ago

Can you rotate a group in 3DS Max?

RemusMar commented 9 years ago

Ricardo, If the previous post is difficult to understand: I'm not talking about the LOCAL coords of the child. Obviously, they will depend on the new parent: in this case position(0,0,0), rotation(0,0,0) and scale(1,1,1)

I am talking about the PREVIOUS WORLD coords of the child. The child size and rotation on the screen must be the same no matter what parent do you set for it. Please perform the same test with THREE and with 3DS Max and see the result.

cheers

RemusMar commented 9 years ago

Can you rotate a group in 3DS Max?

Yes, you can rotate a group (and it will rotate all the childs). If I detach a child after the group rotation, the child will keep the same rotation. If I attach that child to a new (empty) group, the child will get rotation(0,0,0), but on the screen will KEEP the previous rotation. This is not happen in THREE !

mrdoob commented 9 years ago

Could you do a screen capture of how 3DS Max behaves? I don't have a Windows machine.

RemusMar commented 9 years ago

Ricardo, pay attention to this screenshot. I've imported a mesh with many childrens. I've set the scale to (0.1, 0.1, 0.1) and the rotation to (0, 0, 45). I've detached the girl boots. I've created a new group ( rotation(0,0,0) and scale(1,1,1). I've attached the boots to that group. The boots LOOK THE SAME! The new group didn't mess up the child. If you perform the same operations in THREE, you will get wrong results.

cheers group_child

RemusMar commented 9 years ago

And Ricardo, this is not a Suggestion. It's a BUG! At this moment (THREE r71), if you change the parent of a child object you mess up the child on the screen (scene). Unless all the parents have the same scale, rotation and position ...

cheers

gero3 commented 9 years ago

That is how all 3D engines work @RemusMar. 3ds max calculates in the background what the new coordinates are for the deattached objects. The reason why it is important to act like that is for instancing.

You are technically comparing a 3D engine against a 3D modeller which have differnt ideas behind them.

dubejf commented 9 years ago

Are you looking for THREE.SceneUtils.detach and THREE.SceneUtils.attach ?

http://threejs.org/docs/#Reference/Extras/SceneUtils

RemusMar commented 9 years ago

That is how all 3D engines work

Wrong dear. I work with Shockwave 3D since its first release (2001). The groups are treated the same as in 3DS Max. As general rule: !!! a group does not mess up a new added child !!!

Are you looking for THREE.SceneUtils.detach and THREE.SceneUtils.attach ?

I used them from the very beginning. The same wrong result as group.add(child); (read carefully my first post).

The main problem with you folks is that you got used to work with something not quite "normal". I can understand that. But there is always room for better!

cheers

RemusMar commented 9 years ago

The bottom line:

You have a group of big apples and a group of small apples. If you detach a small apple and you attach it to the first group, do you make it bigger??? Obviously not!

So Ricardo please fix it, or at least to keep the (wrong) backward compatibility, add an extra parameter. Something like: group.add( child, preserve); Where "preserve" is true or false (false by default).

cheers

mrdoob commented 9 years ago

Oh, sorry. When I said "screen capture" I meant video screen capture.

Anyway, I have the feeling 3D Studio group is not really part of the scene graph. Can you add a group as a child of another object? What happens if you do that?

RemusMar commented 9 years ago

Ricardo,

Group, Object3D, Mesh, ... they all act the same: A NEW PARENT DOES NOT MESS UP A NEW ADDED CHILD !!! Here is another example for you (I hope this is the last one on this subject: mesh_add_child

As you can see, the result is perfect! The child got the new parent parameters, but on the screen it looks the same! The same size, world position and world rotation.

This must be fixed in THREE.

cheers

mrdoob commented 9 years ago

Is there a way you can show the hierarchy of the last example?

Something like this...

screen shot 2015-04-20 at 5 05 19 pm

WestLangley commented 9 years ago

@RemusMar

I've detached the boots of the first model. I've attached the child to the second model.

In three.js, you can assign an object a new parent, but three.js does not have an operation called 'detach'. It does have the utility method THREE.SceneUtils.detach() however. You have to make it clear what you are referring to.

Please see "How to report a bug" in the guidelines.

The guidelines request a test case. A simple, 50-line program demonstrating what you claim is not working as you think it should, would be helpful in resolving this.

RemusMar commented 9 years ago

to Ricardo:

1) before detaching the boots: Scene with 2 meshes:

2) after attaching the child to the new parent (Girl2): Scene with 2 meshes:

I think the screenshot makes all of these obvious.

mrdoob commented 9 years ago

Sorry, but I need to see a hierarchy screenshot.

I think the screenshot makes all of these obvious.

I understand that this issue is clear for you but it is not clear for me. I'm trying to understand it and I'm asking you what I need for understanding it. Saying that it's obvious for you doesn't make it any clearer for me (unless your intention is to make me feel dumb 😉)

RemusMar commented 9 years ago

to WestLangley:

No matter what method you try in THREE ( object.add(child) or THREE.SceneUtils.detach( child, parent, scene ) ) You get the WRONG result: The child size, world position and world rotation are messed up. Unless the previous parent has position(0,0,0), rotation(0,0,0) and scale(1,1,1)

In a complex project you need to change the parents for certain objects at runtime. In the current status of THREE that's a nightmare. And that's because the previous world coords of the child are messed up.

WestLangley commented 9 years ago

@RemusMar

three.js works exactly as it was designed to. If you will provide a simple three.js example, as requested in the guidelines, perhaps a new feature can be added.

If you choose not to provide the example, then this issue will be closed.

benaadams commented 9 years ago

@RemusMar a child's position, scale, rotation etc are adjustments on its parent's position, scale, rotation etc in a transformation hierarchy so if you change its parent the child will change based on the hierarchy it is now joined to; much like the position of the points that make up the triangles of the objects are offset positions of the object's position. So for a sphere of radius 50 all the vertex positions are 50 units around 0,0,0 whether or not the sphere is at 0,0,0 or 1000,0,0.

If you had two scenes at -1000 and another at 1000 and added the same object to each scene the object would appear at the center of each scene (-1000 and 1000 respectively) although their positions are 0,0,0

Coincidently John Carmack has just tweeted on the same subject: capture https://twitter.com/ID_AA_Carmack/status/590161929957683200

gero3 commented 9 years ago

This shows of the problem you have https://jsfiddle.net/46n9rjw6/1/

Simply by adding a updateMatrixWorld() before THREE.SceneUtils.detach, it works. https://jsfiddle.net/46n9rjw6/2/

This is something we should add to the documentation.

This could be all avoided if you just added a example, so we could understand what was wrong with it.

benaadams commented 9 years ago

@RemusMar Also depending on what and when you are doing things try calling child.updateMatrixWorld() before you remove it with THREE.SceneUtils.detach(), then before you add it with THREE.SceneUtils.attach() to its new parent call newParent.updateMatrixWorld()

RemusMar commented 9 years ago

"Sorry, but I need to see a hierarchy screenshot".

The submeshes have the same hierarchy level (there is no "parent" mesh). But here is the GROUP case (girl2 + girl1.boots): group

mrdoob commented 9 years ago

Maybe we could move .attach() and .detach() to Object3D?

RemusMar commented 9 years ago

"gero3 : Simply by adding a updateMatrixWorld() before THREE.SceneUtils.detach, it works."

Indeed. updateMatrixWorld() at runtime makes sense. But to use it during setup when the models are loaded and there is nothing on the screen, honestly ... does not make any sense.

Anyway, thanks for hint. cheers

benaadams commented 9 years ago

But to use it during setup when the models are loaded and there is nothing on the screen

At runtime the matrixes are kept updated, so you probably wouldn't have to to this then

RemusMar commented 9 years ago

As I said before folks, you got used to work with not quite "normal" things. So I have to update things during setup ... I will keep that in mind (LOL). Meanwhile have fun with this "hardcore" benchmark: http://necromanthus.com/Test/html5/test9_disco.html You'll find most of the THREE goodies inside of it.

Thank you all for feedback. cheers

RemusMar commented 9 years ago

to WestLangley (he was happy to close the "issue"):

If "detach" is so buggy, why don't you include "parent.updateMatrixWorld()" into "THREE.SceneUtils.detach" and into "parent.add(child)" ?

cheers

gero3 commented 9 years ago

We are working on it right now #6433 and #6434 are direct results of this issue.

RemusMar commented 9 years ago

glad to hear.

all the best

dlannan commented 5 years ago

I know this is old, but Im surprised to find the same problems still. A child "add" to an Object3d should never change the child's world position, only its local matrix. But even in the editor if you have a parent object at 1,0,0 and a child at 3, 0, 0 then add the child to the parent - it moves its world position to 4,0,0 - this makes no sense? Is this intended behaviour? It appears the world position is being kept as a the local position?? and the rotation is being reset? It causes all sorts of problems when moving child objects around hierarchies. Putting various workarounds in is a little odd since this should be part of the parent/child relationship. Would highly recommend examining a scenegraph from a modern engine (or old.. ).

Mugen87 commented 5 years ago

this makes no sense? Is this intended behaviour?

Absolutely. This is how hierarchical transformation works. The child respects the translation of its parent. Hence the world position is (4,0,0).

yomboprime commented 5 years ago

I know this is old, but Im surprised to find the same problems still. A child "add" to an Object3d should never change the child's world position, only its local matrix. But even in the editor if you have a parent object at 1,0,0 and a child at 3, 0, 0 then add the child to the parent - it moves its world position to 4,0,0 - this makes no sense? Is this intended behaviour? It appears the world position is being kept as a the local position?? and the rotation is being reset? It causes all sorts of problems when moving child objects around hierarchies. Putting various workarounds in is a little odd since this should be part of the parent/child relationship. Would highly recommend examining a scenegraph from a modern engine (or old.. ).

What you want can be done with THREE.SceneUtils.attach() and .detach()

RemusMar commented 5 years ago

A child "add" to an Object3d should never change the child's world position, only its local matrix.

That's true. But let's forget about that ... :innocent:

dlannan commented 5 years ago

I understand the problems underlying this (the push/pop matrix collation and resolution). And why it is probably impossible (or extremely difficult) to implement a better scenegraph. Its why Ive resorted to my own LQDB.. but I think its important that you consider the 'large scale' entity problems this will cause. It will make developing a good editor much more difficult too if you dont make this more intuitive/correct. If you want a good resource for scenegraphs, try to get a hold of the old SGI Performer scenegraph system, it really was quite beautiful, and ThreeJS has quite a similar style of structure (quite loose) that could be a good match. Note: I sort of understand too, that ThreeJS is more of an engine... rather than a scenegraph (much like many 3D engines).. but for a great engine to work well, the scenegraph system is critical (esp in perf for large projects).

On attach/detach, not really. @RemusMar I think understands the issue. For example, I have some high speed sensors being simulated in a 3D env. Those sensors can be moved from parent to parent depending on what they are doing (for example, a car carrier sensor moving from conveyor system to conveyor system). The issue is, that I need to ensure when the sensor is drawn and when I do the sensor modelling (mathematical), the world matrix is actually correct when it has been re-parented. I shouldnt need to do this at all (only the local matrix should change, when re-parenting). Consider 50 conveyors.. 12 drop towers (conveyor transfer systems) and hundreds of carriers with 2-3 sensors per carrier. The problem becomes large enough to be a serious issue. I have examples with robotic forklifts, autonomous vehicles and vessels as well. I personally very much love working with ThreeJS. But this problem has been a bit of a challenge, hence why I ported OpenSteer and ended up using their LQDB to work with my own child/parent hierarchy. I should note: This isnt a 'single' edge case issue. I personally class this as a 'broken scenegraph', if you have used scenegraphs for as long as I have :) .. but in terms of a vision engine, it technically is not a bug.

WestLangley commented 5 years ago

Try this.

There are a lot of edge cases, so it may require additional testing.

THREE.Object3D.prototype.attachTo = function() {

    // adds this as a child of object, without changing the child's world transform

    var m = new THREE.Matrix4();

    return function attachTo( object ) {

        object.updateWorldMatrix( true, false ); // bubble up

        m.getInverse( object.matrixWorld )

        if ( this.parent !== null ) {

            this.parent.updateWorldMatrix( true, false ); // bubble up

            m.multiply( this.parent.matrixWorld )

        }

        if ( this.matrixAutoUpdate ) this.updateMatrix();

        this.applyMatrix( m );

        this.updateWorldMatrix( false, false );

        object.add( this );

    }

}();
WestLangley commented 5 years ago

This issue has been resolved with #16528.

ljason1993 commented 4 years ago

OMG Thanks so much i use attach() today, so great~~~