Filling up an empty scene with Javascript
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 <Shape> ? Could I use DOM integration instead ?
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.
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/
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.
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.
You can continue to ask questions here if you like. I will be happy to help you.
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.
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.
So very simple ! It works :) Thank you. My project is 99% finished thanks to you.