Adding and Removing Nodes on the Scene Graph via code
On the Threekit platform, it is not always possible to place everything into the scene graph on your 3D asset. An example of this could be a room configurator where users can dynamically add several chairs, tables, couches… as much as they like!
Given that every user’s experience will be unique, it is difficult to create a scene graph to hold the data. Naming nodes for furniture that does not yet exist would be impossible. Instead it is best to create and remove models/nodes from your scene dynamically through code.
For this use case, we focus on a pair of functions, scene.addNode() and scene.deleteNode(), in the example below.
Note you can click the check boxes to add and remove cubes and spheres on the plane in the asset. When you check an “add” checkbox, a new node cube/sphere is added at the origin. You can click on the object to select it. Then, once selected, click-and-drag to move it around.
Checking the “remove” checkboxes removes the most recent cube/sphere that was added to the scenegraph.
The code utilized on the Add Box button is the following (code for sphere buttons are nearly identical with swapping in “Sphere” for “Box” in most places):
Example: scene.addNode code
// This script will add a box at the origin
const boxNodes = [];
const allNodes = api.scene.getAll();
for(const node in allNodes){
if(allNodes[node].name.includes('DynamicBox')){
boxNodes.push(node);
}
}
// Create new box with addNode()
api.scene.addNode({
type: 'Model',
name: 'DynamicBox_' + (boxNodes.length + 1),
plugs: {
Null: [
{
type: 'Model',
asset: {
query: {metadata: {addNodeExample: 'YellowBox'}}
}
}
],
Properties: [
{
type: 'ModelProperties',
visible: true,
}
]
},
},
api.scene.find({from: api.instanceId, name: 'Layout Container'})
);
The first argument of addNode contains information about the asset that is being added to the scene. Give it a custom name and utilize the query object to find the asset you are trying to add to the scene. It is recommended to utilize the first parameter to identify the asset to insert and name the node. If you wish to add transformations and other details, utilize scene.set() on the newly created node’s property of your choice.
The second argument of addNode() is required and is the id of the desired parent node within the scene graph. In this example, the Layout Container is the parent node so that drag-and-drop will work automatically when the node is added to the scene. If you wish to create a top level node, then you need to use the .instanceId property of the Player API.
Example: scene.deleteNode code
// This script removes the most recently added box as determined by the name of the box node
const boxNodes = [];
const allNodes = api.scene.getAll();
let largestNum = 0;
let latestBoxId;
for(const node in allNodes){
nodeName = allNodes[node].name;
if(nodeName.includes('DynamicBox')){
if(nodeName.split('_')[1] > largestNum){
largetNum = nodeName.split('_')[1];
latestBoxId = node;
}
}
}
api.scene.deleteNode(latestBoxId);
The code loops through all nodes to find the most recently-created box node. The only parameter passed to deleteNode() is the instanceId of the node to be deleted from the scenegraph.
Note that getAll() returns an object with properties ordered alphabetically by id of the instances of the scene nodes. Therefore, the order of the nodes in that object cannot be used on its own to determine the most recently added node.