create3000 / x_ite

X_ITE X3D Browser, view and manipulate X3D, VRML, glTF and other 3D sources in HTML.
https://create3000.github.io/x_ite/
Other
67 stars 15 forks source link

Strange behavior when using addChildren in VRML #177

Closed olafgithub closed 3 months ago

olafgithub commented 3 months ago

I like to use a script running on the HTML page to add (many) objects to a transform in VRML.

Minimal code example

VRML code:

DEF TR Transform {}

JavaScript code:

X3D (function ()
{
  Browser_1 = X3D.getBrowser ( "#x3d_1" )
})

Browser_1.currentScene.getNamedNode( 'TR' ).addChildren = Browser_1.createVrmlFromString( 'Shape { appearance Appearance { material Material { diffuseColor 1 1 0 } } geometry Box { size 0.5 2 4 } }' )
Browser_1.currentScene.getNamedNode( 'TR' ).addChildren = Browser_1.createVrmlFromString( 'Shape { appearance Appearance { material Material { diffuseColor 0 1 1 } } geometry Sphere {} }' )

I expect to see a Box shape intersected with a Sphere shape. All I see is the result of the latest call to addChildren: the Sphere...

When I look up the VRML standard on: https://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html

I read:

... All grouping nodes except Inline, LOD, and Switch also have addChildren and removeChildren eventIn definitions. The addChildren event appends nodes to the grouping node's children field. Any nodes passed to the addChildren event that are already in the group's children list are ignored. For example, if the children field contains the nodes Q, L and S (in order) and the group receives an addChildren eventIn containing (in order) nodes A, L, and Z, the result is a children field containing (in order) nodes Q, L, S, A, and Z. ...

It looks like the intention is to APPEND children. The way it works is more like REPLACE children.

Am I correct, or is there another way to append children?

Thanks,

Olaf

create3000 commented 3 months ago

Refers to previous issue: https://github.com/create3000/x_ite/issues/114

An event like transform.addChildren is not immediately executed, but at the beginning of the next frame. This means if you do an addChildren twice, it will only have the last value assigned. Instead of doing this, create a temporary variable first, assign all of your values, and then assign this value to addChildren.

const children = new X3D.MFNode ();

children .push (... Browser .createVRMLFromString ("declarations #1 come here"));
children .push (... Browser .createVRMLFromString ("declarations #2 come here"));

transform .addChildren = children;

// But you could also do:

transform .children .push (... Browser .createVRMLFromString ("declarations #1 come here"));
transform .children .push (... Browser .createVRMLFromString ("declarations #2 come here"));

Keep in mind that there is a newer function createX3DFromStringwhich is more powerful.

https://create3000.github.io/x_ite/reference/browser-services/#promisex3dscene-createx3dfromstring-string-x3dsyntax

olafgithub commented 3 months ago

Thanks...

I vaguely remembered having had more or less the same problem before. I could not find it easily. Also, I hoped/believed that the behavior would differ when running from a script on the HTML page. The previous time I ran into the problem was with a script inside the VRML code.

I will use your suggestion.

Thanks for the very, very fast reply.

Olaf

olafgithub commented 3 months ago

Works fine now! I tried something similar earlier but did not use the ... (spread operator) then. ... makes sense as the result of createVrmlFromString is an MFNode after all. Have a nice weekend!

Olaf