SceneGraph
The sceneGraph is a graph-like structure that contains all the data that could affect a 3D scene's visuals and behaviors. It consists of nodes (scene objects) connected by a parent-child or property relationship. A typical 3D scene could contain nodes of different types, like mesh, materials, lights, cameras, and so on. Inside the Threekit Player, these are converted into a graph structure of nodes, with each node containing its corresponding properties which directly affect how computers render the 3D objects.
Structure of a SceneGraph
A sceneGraph is constructed by a list of different types of nodes. There could be hierarchical structure between the nodes or a node could link to other nodes by property. For example, a mesh node could accept a material node for its material property.
Structure of a node
Every node in the scene graph has a name, type, and a set of plugs. Each plug consists of a stack of operators. Each operator contains a set of properties. The stack of operators will be evaluated, providing the result for each plug, and then used in the display of each node.
Here is an example of all properties of the first operator under the Transform plug of a PolyMesh type node. As the name of the plug indicates, it contains all the spatial information of the node in the 3D space.
More specifically, each node contains the data that defines how these nodes should be rendered, and the sceneGraph contains all the nodes that result in the final visualization in the Player.
Working with SceneGraph
The client-side API of the Player allows users to query and update nodes and properties of nodes, which provides the ability to fully control the visualization of your product through the API.
There are four major functions that allow you to interact with the nodes inside scenegraphs.
- Find: search and return the nodeId or operator property path
- Get: search and return the node data or operator property value
- Set: update the node or node operator property value
- Add/Delete: add new nodes or remove existing node from sceneGraph
Find and Filter
This section provides ways to search through the scene graph. It is usually used to check if a certain node exists, or to find the node property path for other API use.
The related API uses one argument, the QueryObject, that defines the node or property to search, and return the Path.
- find(queryObject) -> Path | null
- The find function returns the Path, depending on the query object, the Path could contain the nodeId or the full path up to the property level. If there are multiple results matching the query, only the first will be returned. If no match is found, it will return null
- filter(queryObject) -> [Path] | []
- The filter function works similarly to find, but returns an array of paths for all the matched results. An empty array will be returned if there is no matching value.
Param |
Type |
Description |
queryObject |
The query object to filter on. |
player.scene.find({name: ‘box’});
// find the first node with name box in the sceneGraph, return path only contains the nodeId, an example return could be something like ['abdfb59a-d2b4-4afc-8d4b-0e56802c2992']
player.scene.find({name: ‘box’, plug: ‘Transform’, property: ‘translation’});
// when looking for operator properties, the return path will also targeted to the operator properties level, an example return value could be ['abdfb59a-d2b4-4afc-8d4b-0e56802c2992', 'plugs', 'Transform', 0, 'translation']
FindNode and filterNodes
These APIs return the nodeId rather than the path. This is useful when user need to get the id of a node. For example, in a room builder configurator that allows users to select and move items, it is common for the app to have a selected state set to the selected nodeId.
- findNode(queryObject) -> uuid | null
- The findNode will return the nodeId directly if a matching node exists, otherwise it will return null.
- filterNodes(queryObject) -> [uuid] | []
- The filterNodes will return an array of all matching nodeId values.
Param |
Type |
Description |
queryObject |
The query object to filter on. |
Get
This section provides a way to retrieve data from the sceneGraph. Users will be able to get the entire node information, or specific data like name, type, or a certain value of an operator, based on the query object passed as the parameter.
- get(queryObject | Path) -> any
- The get function takes either a valid path or query object as parameter that defines the property to retrieve, and returns the value if a match exists, otherwise null. The return value type could be string/number/object, etc, depending on the property specified.
- getAll(queryObject) -> {nodeId: property}
- The getAll function works similarly to get, however, it only accepts queryObject as parameters. It returns an object, with nodeId as the key, and the property data as the value.
Param |
Type |
Description |
queryObject | Path |
QueryObject | Path |
The query object to filter on. |
Best practice: When trying to get the operator property value, due to the node’s structure, the user will need to provide the correct plug name, operator index and property name. To find the correct values, use the query parameter {id: ‘nodeId’} and review the node structure for appropriate keywords. |
Set
The set feature allows users to update the existing nodes directly. As a 3D configurator, a key feature is that the 3D visual needs to reflect the user's choice dynamically. This makes the set feature the most commonly used in the Scene API. The set function takes all of the get parameters as well as the new value you want to use to update the node. The set function is used for updating a specific property, so the property attribute should always be included in the Query Object.
- set(queryObject | Path, value) -> {path, value}
- The set function will update the first match node in the scene graph. Users are responsible to make sure the second parameter of the new value has the correct format. The return value will be an object that contains the path to the property and the new value.
- setAll(queryObject, value) -> Promise {nodeId: {path, value}}
- The setAll function is the bulk action version of the set function that updates the property of all the matched nodes. As with set, it only accepts queryObject as the first argument
Param |
Type |
Description |
queryObject | Path |
QueryObject | Path |
The query object to filter on. |
value |
any |
New value to be set. |
Add Node
The addNode API adds a new node to the sceneGraph
- addNode(nodeObj, parentNodeId) -> id of the added node
- The first argument should be an object that follows the node object structure. Only the name and type are mandatory, the plugs and operators are optional. Users may provide the value of certain properties when needed. Any properties that are not provided specific values will apply the default value.
Param |
Type |
Description |
nodeObj |
object |
The object follows the node structure |
parentNodeId |
string |
The parent node to add this node to |
// Add the node with initial translation of (0,1,0)
playerApi.scene.addNode({
type: 'Null',
name: 'test1',
plugs: {
Transform: [
{
type: 'Transform',
translation: {x:0, y:1, z:0}
}
]
}
}, '3e558651-628e-4fca-b44a-2eade866e233')
Delete Node
The deleteNode API removes a node and all its children from the sceneGraph
- deleteNode(nodeId)
Param |
Type |
Description |
nodeId |
string |
nodeId to be deleted |
Best practice: the addNode and deleteNode are often used in dynamically adding, moving and removing items to/from the modular configurator. Make sure the nodes have the correct hierarchy to ensure the child nodes respond correctly when performing moving and deleting. |
For a full example of add and delete node API, please check this page.
Reparent
The reparent api updates the hierarchy of the scene structure and a set of nodes to a new parent node.
- reparent(parent, children) -> object with parentId and childIds as properties
Param |
Type |
Description |
parent |
string | QueryObject |
nodeId or queryObject that specific a node as the parent |
children |
[string] | QueryObject |
An array of nodeId or a queryObject specify a list of child node to be reparent |
Add Operator
The addOperator API adds a specific operator to a given asset.
- addOperator(nodeId, plugType, OperatorType, operator?) -> Promise
Param |
Type |
Description |
nodeId |
String |
The node to add the operator to. |
plugType |
String |
The plug to add the operator to |
operatorType |
String |
Type of the operator to add |
operator |
object |
When missing, the default value will be applied to all the properties of the operator, users may overwrite some or all the properties by providing the value with this parameter. |
Best practice: The plugType and operatorType are keywords defined in the platform and require a valid value for this API. When looking for the specific keyword, a practical way is to create a test scene, add an operator of the same type, and get the node property in the console window to check the keywords used for the specific operator. |
Add Attribute
The addAttribute API adds an attribute to a given asset.
- addAttribute(nodeId, attribute) -> Promise
Param |
Type |
Description |
nodeId |
String |
The node to add the attribute to. |
attribute |
Any (link to attribute schema) |
The object that define the attribute to add |
Schema
Path
Every node is saved in the sceneGraph as an object, the path is an array that lists all the object keys and array indexes based on the node object structure, to target a certain property of a node.
- The first element of the Path is always the nodeId.
- The rest of the elements in the Path depend on where they are located in the node object.
For example, if we are using the node example above, name are saved directly under the node object, so the path to the name property would be [‘alphanumeric_nodeId_value_here’, ‘name’].
Another example, the translation property are saved in the first operator of the Transform plug under the plugs key of the node object, so the Path to it will be [‘alphanumeric_nodeId_value_here’, ‘plugs’, ‘Transform’, 0, ‘translation’]