create3000 / x_ite

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

Filling up an empty scene with Javascript #172

Closed Wagyx closed 4 months ago

Wagyx commented 5 months ago

Hello there,

I have discovered your framework yesterday (I have been using 3JS for two years now) and I am struggling to make a scene from scratch. My HTML just has <x3d-canvas onclick="init()"></x3d-canvas> in the body and my script containing the init() is added after the body. My javascript is

function init() {
    const xBrowser = X3D.getBrowser();
    const scene = xBrowser.currentScene;
    const background = scene.createNode("Background");
    background.skyColor = [0, 0.3, 0.2];
    background.groundColor = [0.5, 0.8, 0.2];
}

This does not work, I get a black canvas. But if I use an x3d source file in the x3d-canvas <x3d-canvas src="/simple.x3d" onload="init()"> and use const background = scene.getNamedNode("Background"); instead then I get the dark green/light green canvas.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.3//EN" "http://www.web3d.org/specifications/x3d-3.3.dtd">
<X3D profile='Immersive' version='3.3' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='http://www.web3d.org/specifications/x3d-3.3.xsd'>
  <Scene>
    <Background DEF='Background'
        skyColor='0 0.5 1'/>
  </Scene>
</X3D>

I would like to add many other elements to the scene specified by the user (at some point) but I cannot even add a simple background. So what am I missing ?

Two bonuses questions, how do I loop over every Node with a specific tag like ? Could I use DOM integration instead ?

create3000 commented 5 months ago

It is of course possible to get the Background node to be displayed. The Background node is, as well as Fog, NavigationInfo, and Viewpoint node an X3DBindableNode, which has a set_bind field. Assigning a true value to that field will bind this node and the isBound field will become true, and will send an event:

background.set_bind = true; // Will do the trick.
scene .rootNodes .push (background); // rootNodes is a MFNode field.

See also https://create3000.github.io/x_ite/components/environmentaleffects/background/.

Note that the skyColor and groundColor are MFColor fields, this means you should do to be compatible:

background.skyColor = new X3D .MFColor (new X3D .SFColor (0, 0.3, 0.2));
background.groundColor = new X3D .MFColor (new X3D .SFColor (0.5, 0.8, 0.2));

It is of course possible to assign pure Arrays, as you do, but this is not standard X3D, but will work.

To loop over the rootNodes you can do:

for (const node of scene .rootNodes)
{
   for (const type of node .getNodeType () .reversed ())
   {
      switch (type)
      {
          case X3D .X3DConstants .Background:
          {
              ....
              break;
          }
          default:
             continue;
      }

      break;
   }
}

See also https://create3000.github.io/x_ite/accessing-the-external-browser/#x3dconstants.

create3000 commented 5 months ago

MF fields are much like Arrays and have a corresponding SF fields. Which can be assigned:

background.skyColor[0] = new X3D .SFColor (0.1, 0.2, 0.3);

https://create3000.github.io/x_ite/reference/field-services-and-objects/

create3000 commented 5 months ago

I have updated the documentation to show a simple example, how to create nodes with JavaScript and add them to the scene-graph.

https://create3000.github.io/x_ite/accessing-the-external-browser/#usage

The first section shows the scene in declarative syntax, and below that there is the same scene created using pure JavaScript.

Wagyx commented 5 months ago

Thank you very much, a simple JavaScript example was exactly what I was missing. In the meantime, I managed to figure out how to add elements to the scene by looking into the various Parser codes and I made my own OFFParser, even adding it to the GoldenGate.Parser list to handle the src of the x3d-canvas seamlessly. I'll deal with InstancedShape today so I'll come back if I have any issue.

create3000 commented 5 months ago

You can continue to ask questions here if you like. I will be happy to help you.

Wagyx commented 5 months ago

Me again. What is the way in JavaScript to refer to another node with the "USE" keyword ? I see what it would look like from here https://create3000.github.io/x_ite/tutorials/naming-nodes/ but not what the proper JS syntax is.

create3000 commented 5 months ago

You do not have to do anything special, just add the node to another field, and that's it.

const shapeNode1 = scene .createNode ("Shape");
const shapeNode2 = scene .createNode ("Shape");
const boxNode = scene .createNode ("Box");

shapeNode1 .geometry = boxNode; // First use
shapeNode2 .geometry = boxNode; // Second use

When the scene is printed, proper DEF/USE statements are automatically generated.

Wagyx commented 5 months ago

So very simple ! It works :) Thank you. My project is 99% finished thanks to you.