Skip to content

A Node-RED widget node to show an interactive BabylonJs 3D scene in the Node-RED dashboard

License

Notifications You must be signed in to change notification settings

bartbutenaers/node-red-contrib-ui-babylonjs-3d

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

node-red-contrib-ui-babylonjs-3d

A Node-RED widget node to show an interactive BabylonJs 3D scene in the Node-RED dashboard

⚠️ THIS IS AN EXPERIMENTAL NODE:
  • The API can still change, which means existing flows need to be changed manually.
  • This node is far from finished, and will certainly contain bugs. So keep that in mind while testing!
  • THIS NODE IS NOT AVAILABLE ON NPM OR IN THE NODE-RED PALETTE (SEE INSTALLATION COMMAND BELOW)!!!
  • Only a small part of the BabylonJs API has been implemented in this node at the moment. Since I don't have time to implement the entire API, I will add new features when people explicit request them.

Install

Run the following npm command in your Node-RED user directory (typically ~/.node-red):

npm install bartbutenaers/node-red-contrib-ui-babylonjs-3d

Support my Node-RED developments

Please buy my wife a coffee to keep her happy, while I am busy developing Node-RED stuff for you ...

Buy my wife a coffee

Getting started

Some basic steps to setup a 3D scene with this node:

  1. Check (e.g. here) whether you browser supports WebGL. I had to enable the WebGL 2.0 experimental features in Chrome:

    web gl

    Remark: WebGL is a JavaScript API for rendering interactive 2D and 3D graphics within any compatible web browser without the use of plug-ins.

  2. Create a 3D scene in a third party 3D editor that can export gltf/glb/obj files. Of course this step is not needed when you want to create a 3D scene from scratch via messages from Node-RED...

  3. When you have a 3D file exported (gltf, glb or obj), install it on your server and specify the path to it in the node's config screen. For obj files, all related files (e.g. material .mtl file) should be stored in the same directory as the obj file! Note that currently there is a bug for obj files!

  4. Add the required startup commands in the "Startup" field on the config screen (which will be executed as soon as the dashboard tabsheet is loaded, e.g. to setup a camera, lights, meshes, ...

Meshes

Meshes are renderable models in the 3D scene, e.g. boxes, spheres ...

Working with meshes

This node offers some basic functionality for working with meshes:

image

[{"id":"361e82c.ab5407e","type":"inject","z":"2b6f5d19.202242","name":"Add \"pick\" action to mesh","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"add_mesh_action\",\"name\":\"my_box\",\"actionTrigger\":\"pick\",\"payloadToSend\":\"my_payload\",\"topicToSend\":\"my_topic\"}","payloadType":"json","x":1390,"y":340,"wires":[["4876dd4.6fe9224"]]},{"id":"b2e122e.7541de","type":"inject","z":"2b6f5d19.202242","name":"Create box mesh","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"box\",\"name\":\"my_box\",\"meshOptions\":{\"width\":1,\"height\":2,\"depth\":2},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1360,"y":220,"wires":[["4876dd4.6fe9224"]]},{"id":"698ab7e2.6fa6a8","type":"inject","z":"2b6f5d19.202242","name":"Remove box mesh","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"remove_mesh\",\"name\":\"my_box\"}","payloadType":"json","x":1370,"y":260,"wires":[["4876dd4.6fe9224"]]},{"id":"3b6e1e34.0a59c2","type":"inject","z":"2b6f5d19.202242","name":"Get mesh properties","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"get_mesh_properties\",\"name\":\"^.*\"}","payloadType":"json","x":1370,"y":300,"wires":[["4876dd4.6fe9224"]]},{"id":"4876dd4.6fe9224","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs3 (Material)","group":"284af3b3.34ccbc","order":0,"width":"6","height":"6","folder":"","filename":"","outputField":"payload","actions":[{"selectorType":"meshName","selector":"my_box","trigger":"nothing","payload":"my_payload","topic":"my_topic"}],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":3,\"y\":3,\"z\":3},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true}]","x":1680,"y":220,"wires":[["db6bbf92.6ef2d"]]},{"id":"db6bbf92.6ef2d","type":"debug","z":"2b6f5d19.202242","name":"3D output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1880,"y":220,"wires":[]},{"id":"284af3b3.34ccbc","type":"ui_group","z":"","name":"Default","tab":"7a5078d4.54b268","order":1,"disp":true,"width":"6","collapse":false},{"id":"7a5078d4.54b268","type":"ui_tab","z":"","name":"BabylonJs3 (Material)","icon":"dashboard","disabled":false,"hidden":false}]

Some remarks about this flow:

  • Create a mesh, with some id and/or name. Afterwards this mesh can be removed, based on the name or id. Note that arrays and regular expressions are also supported to remove multiple meshes at once.
  • Get the properties of a mesh.
  • Add a pick-action to a mesh (see the "Helper tools" section).

Update mesh

The "update_mesh" command can be used to update all kind of settings of a mesh.

Mesh colors

Beside to apply a coloured material to a mesh, it is also possible to apply:

  • overlay color: the color that will be overlayed on the mesh planes.

  • outline color: the color that will be applied to the mesh outline (i.e. the visual borders of the mesh, not all the edges!). Note that the outline width needs to be kept small, otherwise strange artifacts will occur at the corners (as described here). For example a box with large outline width:

    Outline color

  • Edges color: the color that will be applied to the edges. Note that (beside to an RGB value) it is also required to specify an alpha value (between 0 and 2555)

    Edges color

Example flow:

Mesh colors

[{"id":"1c8bcdc84f84427f","type":"ui_babylon_js","z":"7f9646080c92c297","name":"BabylonJs3 (Mesh transformations)","group":"284af3b3.34ccbc","order":0,"width":"6","height":"6","folder":"","filename":"","outputField":"payload","actions":[{"selectorType":"meshName","selector":"my_box","trigger":"nothing","payload":"my_payload","topic":"my_topic"}],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":20,\"y\":20,\"z\":20},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true},{\"command\":\"create_mesh\",\"type\":\"box\",\"name\":\"my_box\",\"meshOptions\":{\"width\":10,\"height\":10,\"depth\":10},\"position\":{\"x\":0,\"y\":0,\"z\":0}}]","x":740,"y":80,"wires":[["69885e9cfa03c065"]]},{"id":"69885e9cfa03c065","type":"debug","z":"7f9646080c92c297","name":"3D output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":980,"y":80,"wires":[]},{"id":"b4079dac5a7e7afe","type":"inject","z":"7f9646080c92c297","name":"Red outline color","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh\",\"id\":\"my_box\",\"outlineWidth\":1,\"outlineColor\":{\"r\":255,\"g\":0,\"b\":0},\"renderOutline\":true}","payloadType":"json","x":440,"y":80,"wires":[["1c8bcdc84f84427f"]]},{"id":"96b5b1708ad3463a","type":"inject","z":"7f9646080c92c297","name":"Blue overlay color","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh\",\"id\":\"my_box\",\"overlayColor\":{\"r\":0,\"g\":0,\"b\":255},\"renderOverlay\":true,\"overlayAlpha\":1}","payloadType":"json","x":430,"y":120,"wires":[["1c8bcdc84f84427f"]]},{"id":"da44e2c4ebf28cdb","type":"inject","z":"7f9646080c92c297","name":"Green edges color","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh\",\"id\":\"my_box\",\"edgesWidth\":20,\"edgesColor\":{\"r\":0,\"g\":100,\"b\":0,\"a\":255},\"renderEdges\":true}","payloadType":"json","x":430,"y":160,"wires":[["1c8bcdc84f84427f"]]},{"id":"284af3b3.34ccbc","type":"ui_group","name":"Default","tab":"7a5078d4.54b268","order":1,"disp":true,"width":"6","collapse":false},{"id":"7a5078d4.54b268","type":"ui_tab","name":"BabylonJs3 (Material)","icon":"dashboard","order":24,"disabled":false,"hidden":false}]

Note that this feature is not implemented entirely correctly yet! But not sure where the problem is at the moment ...

Bounding box

It is possible to display the bounding box of a mesh. A bounding box is an imaginary box, that completely includes the mesh and is used as a collision box for that object (for fast calculations of mesh collisions).

Bounding box

[{"id":"d5b874685d2e22e9","type":"inject","z":"7f9646080c92c297","name":"Show bounding box","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh\",\"id\":\"my_sphere\",\"showBoundingBox\":true}","payloadType":"json","x":210,"y":780,"wires":[["55f16d2bf2fcc2b3"]]},{"id":"46dfef637b9453ee","type":"inject","z":"7f9646080c92c297","name":"Hide bounding box","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh\",\"id\":\"my_sphere\",\"showBoundingBox\":false}","payloadType":"json","x":210,"y":820,"wires":[["55f16d2bf2fcc2b3"]]},{"id":"55f16d2bf2fcc2b3","type":"ui_babylon_js","z":"7f9646080c92c297","name":"BabylonJs3 mesh bounding box","group":"284af3b3.34ccbc","order":0,"width":"6","height":"6","folder":"","filename":"","outputField":"payload","actions":[{"selectorType":"meshName","selector":"my_box","trigger":"nothing","payload":"my_payload","topic":"my_topic"}],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":20,\"y\":20,\"z\":20},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true},{\"command\":\"create_mesh\",\"type\":\"sphere\",\"name\":\"my_sphere\",\"meshOptions\":{\"diameterX\":10,\"diameterY\":10,\"diameterZ\":10},\"position\":{\"x\":0,\"y\":0,\"z\":0}}]","x":510,"y":780,"wires":[["589429510883a04b"]]},{"id":"589429510883a04b","type":"debug","z":"7f9646080c92c297","name":"3D output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":760,"y":780,"wires":[]},{"id":"284af3b3.34ccbc","type":"ui_group","name":"Default","tab":"7a5078d4.54b268","order":1,"disp":true,"width":"6","collapse":false},{"id":"7a5078d4.54b268","type":"ui_tab","name":"BabylonJs3 (Material)","icon":"dashboard","order":24,"disabled":false,"hidden":false}]

For example for a sphere, the bounding box will look like this:

boundingbox sphere

Transformations

Via transformations it is possible to position a mesh (or multiple meshes) at a specified location, or to rotate it:

Mesh transformations

[{"id":"222d2073.79327","type":"inject","z":"2b6f5d19.202242","name":"Position mesh","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh\",\"id\":\"my_box\",\"position\":{\"x\":0,\"y\":0,\"z\":1}}","payloadType":"json","x":450,"y":140,"wires":[["52b6c290.e8f12c"]]},{"id":"433aa8f2.e4ed78","type":"inject","z":"2b6f5d19.202242","name":"Rotate mesh","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh\",\"id\":\"my_box\",\"rotation\":{\"x\":0,\"y\":0,\"z\":45}}","payloadType":"json","x":450,"y":180,"wires":[["52b6c290.e8f12c"]]},{"id":"52b6c290.e8f12c","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs3 (Mesh transformations)","group":"284af3b3.34ccbc","order":0,"width":"6","height":"6","folder":"","filename":"","outputField":"payload","actions":[{"selectorType":"meshName","selector":"my_box","trigger":"nothing","payload":"my_payload","topic":"my_topic"}],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":3,\"y\":3,\"z\":3},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true},{\"command\":\"create_mesh\",\"type\":\"box\",\"name\":\"my_box\",\"meshOptions\":{\"width\":1,\"height\":1,\"depth\":1},\"position\":{\"x\":0,\"y\":0,\"z\":0}}]","x":740,"y":140,"wires":[["6914f76a.da0758"]]},{"id":"6914f76a.da0758","type":"debug","z":"2b6f5d19.202242","name":"3D output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":980,"y":140,"wires":[]},{"id":"284af3b3.34ccbc","type":"ui_group","z":"","name":"Default","tab":"7a5078d4.54b268","order":1,"disp":true,"width":"6","collapse":false},{"id":"7a5078d4.54b268","type":"ui_tab","z":"","name":"BabylonJs3 (Material)","icon":"dashboard","disabled":false,"hidden":false}]

Wireframes

A mesh material can be updated to show it in wireframe mode:

Wireframe

[{"id":"739cddf3.86dac4","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs3 (Mesh wireframes)","group":"284af3b3.34ccbc","order":0,"width":"6","height":"6","folder":"","filename":"","outputField":"payload","actions":[{"selectorType":"meshName","selector":"my_box","trigger":"nothing","payload":"my_payload","topic":"my_topic"}],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":3,\"y\":3,\"z\":3},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true},{\"command\":\"create_mesh\",\"type\":\"box\",\"name\":\"my_box\",\"meshOptions\":{\"width\":1,\"height\":1,\"depth\":1},\"position\":{\"x\":0,\"y\":0,\"z\":0}},{\"command\":\"create_material\",\"name\":\"box_material\",\"targetName\":\"my_box\",\"diffuseColor\":{\"r\":255,\"g\":0,\"b\":0}}]","x":970,"y":260,"wires":[[]]},{"id":"83209769.6a1f98","type":"inject","z":"2b6f5d19.202242","name":"Show wireframe","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh_material\",\"name\":\"^.*\",\"wireframe\":true}","payloadType":"json","x":680,"y":260,"wires":[["739cddf3.86dac4"]]},{"id":"66ea45f1.2c2c7c","type":"inject","z":"2b6f5d19.202242","name":"Hide wireframe","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh_material\",\"name\":\"^.*\",\"wireframe\":false}","payloadType":"json","x":680,"y":300,"wires":[["739cddf3.86dac4"]]},{"id":"284af3b3.34ccbc","type":"ui_group","z":"","name":"Default","tab":"7a5078d4.54b268","order":1,"disp":true,"width":"6","collapse":false},{"id":"7a5078d4.54b268","type":"ui_tab","z":"","name":"BabylonJs3 (Material)","icon":"dashboard","disabled":false,"hidden":false}]

Which can be used to look through meshes:

wireframe

Mesh types

BabylonJs offers a number of mesh types, each with their own properties:

Create meshes flow

[{"id":"35f9eaf0.706f66","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs4","group":"5a86123b.48efdc","order":0,"width":"12","height":"10","folder":"","filename":"","outputField":"payload","actions":[],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":12,\"y\":12,\"z\":12},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true}]","x":1870,"y":480,"wires":[["73ed404.64c3cc"]]},{"id":"b59e983c.eec108","type":"inject","z":"2b6f5d19.202242","name":"Box","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"box\",\"name\":\"my_mesh\",\"meshOptions\":{\"width\":4,\"height\":2,\"depth\":6},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1450,"y":60,"wires":[["a15b23ef.4599"]]},{"id":"85c3d78a.4cc268","type":"inject","z":"2b6f5d19.202242","name":"Tiled Box","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"command\": \"create_mesh\",     \"type\": \"tiledBox\",     \"name\": \"my_mesh\",     \"meshOptions\": {         \"width\": 4,         \"height\": 2,         \"depth\": 6     },     \"position\": {         \"x\": 0,         \"y\": 0,         \"z\": 0     } }","payloadType":"json","x":1440,"y":100,"wires":[["a15b23ef.4599"]]},{"id":"cd933b05.488838","type":"inject","z":"2b6f5d19.202242","name":"Sphere","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"command\": \"create_mesh\",     \"type\": \"sphere\",     \"name\": \"my_mesh\",     \"meshOptions\": {         \"diameterX\": 4,         \"diameterY\": 2,         \"diameterZ\": 6     },     \"position\": {         \"x\": 0,         \"y\": 0,         \"z\": 0     } }","payloadType":"json","x":1450,"y":140,"wires":[["a15b23ef.4599"]]},{"id":"eeabdbf1.908768","type":"inject","z":"2b6f5d19.202242","name":"Cylinder","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"cylinder\",\"name\":\"my_mesh\",\"meshOptions\":{\"height\":8,\"diameterTop\":3,\"diameterBottom\":5},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1440,"y":180,"wires":[["a15b23ef.4599"]]},{"id":"87e91468.d50f38","type":"inject","z":"2b6f5d19.202242","name":"Capsule","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"capsule\",\"name\":\"my_mesh\",\"meshOptions\":{\"height\":8,\"radius\":2},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1440,"y":220,"wires":[["a15b23ef.4599"]]},{"id":"70d89a20.db1254","type":"inject","z":"2b6f5d19.202242","name":"Plane","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"command\": \"create_mesh\",     \"type\": \"plane\",     \"name\": \"my_mesh\",     \"meshOptions\": {         \"width\": 10,         \"height\": 6     },     \"position\": {         \"x\": 0,         \"y\": 0,         \"z\": 0     } }","payloadType":"json","x":1450,"y":260,"wires":[["a15b23ef.4599"]]},{"id":"8146214d.82b61","type":"inject","z":"2b6f5d19.202242","name":"Tiled plane","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"command\": \"create_mesh\",     \"type\": \"tiledPlane\",     \"name\": \"my_mesh\",     \"meshOptions\": {         \"width\": 10,         \"height\": 6,         \"tileSize\": 2     },     \"position\": {         \"x\": 0,         \"y\": 0,         \"z\": 0     } }","payloadType":"json","x":1440,"y":300,"wires":[["a15b23ef.4599"]]},{"id":"cdbe391c.6afd58","type":"inject","z":"2b6f5d19.202242","name":"Disc","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"command\": \"create_mesh\",     \"type\": \"disc\",     \"name\": \"my_mesh\",     \"meshOptions\": {         \"radius\": 5     },     \"position\": {         \"x\": 0,         \"y\": 0,         \"z\": 0     } }","payloadType":"json","x":1450,"y":340,"wires":[["a15b23ef.4599"]]},{"id":"8cc905e1.861ef8","type":"inject","z":"2b6f5d19.202242","name":"Torus","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"command\": \"create_mesh\",     \"type\": \"torus\",     \"name\": \"my_mesh\",     \"meshOptions\": {         \"diameter\": 8,         \"thickness\": 3,         \"tessellation\": 32     },     \"position\": {         \"x\": 0,         \"y\": 0,         \"z\": 0     } }","payloadType":"json","x":1450,"y":380,"wires":[["a15b23ef.4599"]]},{"id":"ab6f0f7f.0ad4e","type":"inject","z":"2b6f5d19.202242","name":"Torus knot","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"torusKnot\",\"name\":\"my_mesh\",\"meshOptions\":{\"radius\":4,\"tube\":1,\"n\":5},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1440,"y":420,"wires":[["a15b23ef.4599"]]},{"id":"278d2280.2aa76e","type":"inject","z":"2b6f5d19.202242","name":"Ground","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"ground\",\"name\":\"my_mesh\",\"meshOptions\":{\"width\":12,\"height\":5},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1450,"y":460,"wires":[["a15b23ef.4599"]]},{"id":"72061b64.3e44c4","type":"inject","z":"2b6f5d19.202242","name":"Tiled ground","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"tiledGround\",\"name\":\"my_mesh\",\"meshOptions\":{\"width\":30,\"height\":20},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1430,"y":500,"wires":[["a15b23ef.4599"]]},{"id":"b9eb2c9f.63711","type":"inject","z":"2b6f5d19.202242","name":"Lines","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"lines\",\"name\":\"my_mesh\",\"meshOptions\":{\"points\":[{\"x\":-6,\"y\":-4,\"z\":0},{\"x\":0,\"y\":6,\"z\":0},{\"x\":6,\"y\":-4,\"z\":0}]},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1450,"y":540,"wires":[["a15b23ef.4599"]]},{"id":"3e7ebc41.dc8624","type":"inject","z":"2b6f5d19.202242","name":"Dashed lines","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"dashedLines\",\"name\":\"my_mesh\",\"meshOptions\":{\"points\":[{\"x\":-6,\"y\":-4,\"z\":0},{\"x\":0,\"y\":6,\"z\":0},{\"x\":6,\"y\":-4,\"z\":0}],\"dashSize\":2,\"gapSize\":4},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1430,"y":580,"wires":[["a15b23ef.4599"]]},{"id":"b53c23c3.91127","type":"inject","z":"2b6f5d19.202242","name":"Line system","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"lineSystem\",\"name\":\"my_mesh\",\"meshOptions\":{\"lines\":[[{\"x\":0,\"y\":0,\"z\":5},{\"x\":5,\"y\":0,\"z\":5}],[{\"x\":5,\"y\":0,\"z\":0},{\"x\":5,\"y\":5,\"z\":0},{\"x\":1,\"y\":5,\"z\":0}]]},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1430,"y":620,"wires":[["a15b23ef.4599"]]},{"id":"aa8a7079.9d522","type":"inject","z":"2b6f5d19.202242","name":"Ribbon","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"ribbon\",\"name\":\"my_mesh\",\"meshOptions\":{\"pathArray\":[[{\"x\":5,\"y\":0,\"z\":0},{\"x\":4.5,\"y\":1,\"z\":0},{\"x\":4,\"y\":2,\"z\":0},{\"x\":3.5,\"y\":3,\"z\":0},{\"x\":3,\"y\":4,\"z\":0}],[{\"x\":0,\"y\":0,\"z\":-5},{\"x\":0,\"y\":0.5,\"z\":-7},{\"x\":0,\"y\":1,\"z\":-9},{\"x\":0,\"y\":1.5,\"z\":-11},{\"x\":0,\"y\":2,\"z\":-13}],[{\"x\":-5,\"y\":0,\"z\":0},{\"x\":-4.5,\"y\":1,\"z\":0},{\"x\":-4,\"y\":2,\"z\":0},{\"x\":-3.5,\"y\":3,\"z\":0},{\"x\":-3,\"y\":4,\"z\":0}]]},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1450,"y":660,"wires":[["a15b23ef.4599"]]},{"id":"3512c1a9.018a4e","type":"inject","z":"2b6f5d19.202242","name":"Tube","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"tube\",\"name\":\"my_mesh\",\"meshOptions\":{\"path\":[{\"x\":5,\"y\":0,\"z\":0},{\"x\":0,\"y\":1,\"z\":0.1},{\"x\":-4,\"y\":5,\"z\":0.2}],\"radius\":1},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1450,"y":700,"wires":[["a15b23ef.4599"]]},{"id":"a0f494ad.983378","type":"inject","z":"2b6f5d19.202242","name":"Extrusion","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"extrusion\",\"name\":\"my_mesh\",\"meshOptions\":{\"shape\":[{\"x\":0,\"y\":5,\"z\":0},{\"x\":1,\"y\":1,\"z\":0},{\"x\":5,\"y\":0,\"z\":0},{\"x\":1,\"y\":-1,\"z\":0},{\"x\":0,\"y\":-5,\"z\":0},{\"x\":-1,\"y\":-1,\"z\":0},{\"x\":-5,\"y\":0,\"z\":0},{\"x\":-1,\"y\":1,\"z\":0}],\"path\":[{\"x\":0,\"y\":1,\"z\":0},{\"x\":0,\"y\":1.5,\"z\":2},{\"x\":0,\"y\":2.25,\"z\":4},{\"x\":0,\"y\":3.37,\"z\":6},{\"x\":0,\"y\":5.06,\"z\":8},{\"x\":0,\"y\":8.32,\"z\":10}]},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1440,"y":740,"wires":[["a15b23ef.4599"]]},{"id":"6d93de54.aa879","type":"inject","z":"2b6f5d19.202242","name":"Custom extrusion","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"customExtrusion\",\"name\":\"my_mesh\",\"meshOptions\":{\"shape\":[{\"x\":0,\"y\":5,\"z\":0},{\"x\":1,\"y\":1,\"z\":0},{\"x\":5,\"y\":0,\"z\":0},{\"x\":1,\"y\":-1,\"z\":0},{\"x\":0,\"y\":-5,\"z\":0},{\"x\":-1,\"y\":-1,\"z\":0},{\"x\":-5,\"y\":0,\"z\":0},{\"x\":-1,\"y\":1,\"z\":0}],\"path\":[{\"x\":0,\"y\":0,\"z\":0},{\"x\":0,\"y\":0,\"z\":1},{\"x\":0,\"y\":0,\"z\":2},{\"x\":0,\"y\":0,\"z\":3},{\"x\":0,\"y\":0,\"z\":4},{\"x\":0,\"y\":0,\"z\":5}]},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","x":1420,"y":780,"wires":[["a15b23ef.4599"]]},{"id":"2950aafc.367ed6","type":"inject","z":"2b6f5d19.202242","name":"Lathe","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"command\": \"create_mesh\",     \"type\": \"lathe\",     \"name\": \"my_mesh\",     \"meshOptions\": {         \"shape\": [{                 \"x\": 0,                 \"y\": 0,                 \"z\": 0             },             {                 \"x\": 10,                 \"y\": 5,                 \"z\": 0             },             {                 \"x\": 5,                 \"y\": 10,                 \"z\": 0             },             {                 \"x\": 12,                 \"y\": 15,                 \"z\": 0             },             {                 \"x\": 3,                 \"y\": 20,                 \"z\": 0             }         ],         \"radius\": 2     },     \"position\": {         \"x\": 0,         \"y\": 0,         \"z\": 0     } } ","payloadType":"json","x":1450,"y":820,"wires":[["a15b23ef.4599"]]},{"id":"f9569364.3da8d","type":"inject","z":"2b6f5d19.202242","name":"Polygon","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"command\": \"create_mesh\",     \"type\": \"polygon\",     \"name\": \"my_mesh\",     \"meshOptions\": {         \"shape\": [{                 \"x\": 4,                 \"y\": 0,                 \"z\": -4             },             {                 \"x\": 2,                 \"y\": 0,                 \"z\": 0             },             {                 \"x\": 5,                 \"y\": 0,                 \"z\": 2             },             {                 \"x\": 1,                 \"y\": 0,                 \"z\": 2             },             {                 \"x\": 5,                 \"y\": 0,                 \"z\": 5             },             {                 \"x\": 4,                 \"y\": 0,                 \"z\": -4             },             {                 \"x\": -3,                 \"y\": 0,                 \"z\": 1             },             {                 \"x\": -4,                 \"y\": 0,                 \"z\": -4             },             {                 \"x\": -2,                 \"y\": 0,                 \"z\": -3             },             {                 \"x\": 2,                 \"y\": 0,                 \"z\": -3             }         ]     },     \"position\": {         \"x\": 0,         \"y\": 0,         \"z\": 0     } }     ","payloadType":"json","x":1440,"y":860,"wires":[["a15b23ef.4599"]]},{"id":"1059e96f.845db7","type":"inject","z":"2b6f5d19.202242","name":"Polygon extrusion","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"command\": \"create_mesh\",     \"type\": \"polygonExtrusion\",     \"name\": \"my_mesh\",     \"meshOptions\": {         \"shape\": [{                 \"x\": 4,                 \"y\": 0,                 \"z\": -4             },             {                 \"x\": 2,                 \"y\": 0,                 \"z\": 0             },             {                 \"x\": 5,                 \"y\": 0,                 \"z\": 2             },             {                 \"x\": 1,                 \"y\": 0,                 \"z\": 2             },             {                 \"x\": -5,                 \"y\": 0,                 \"z\": 5             },             {                 \"x\": -3,                 \"y\": 0,                 \"z\": 1             },             {                 \"x\": -3,                 \"y\": 0,                 \"z\": 1             },             {                 \"x\": -4,                 \"y\": 0,                 \"z\": -4             },             {                 \"x\": -2,                 \"y\": 0,                 \"z\": -3             },             {                 \"x\": 2,                 \"y\": 0,                 \"z\": -3             }         ],         \"depth\": 7     },     \"position\": {         \"x\": 0,         \"y\": 0,         \"z\": 0     } } ","payloadType":"json","x":1410,"y":900,"wires":[["a15b23ef.4599"]]},{"id":"25e45fce.a09b5","type":"inject","z":"2b6f5d19.202242","name":"Icosphere","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"command\": \"create_mesh\",     \"type\": \"icoSphere\",     \"name\": \"my_mesh\",     \"meshOptions\": {         \"radiusX\": 4,         \"radiusY\": 2,         \"radiusZ\": 6     },     \"position\": {         \"x\": 0,         \"y\": 0,         \"z\": 0     } }  ","payloadType":"json","x":1440,"y":940,"wires":[["a15b23ef.4599"]]},{"id":"a15b23ef.4599","type":"function","z":"2b6f5d19.202242","name":"","func":"var commands = [{\n    \"command\": \"remove_mesh\",\n    \"name\": \"my_mesh\"\n}]\ncommands.push(msg.payload);\nmsg.payload = commands;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1680,"y":480,"wires":[["35f9eaf0.706f66"]]},{"id":"73ed404.64c3cc","type":"debug","z":"2b6f5d19.202242","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":2050,"y":480,"wires":[]},{"id":"5a86123b.48efdc","type":"ui_group","name":"Meshes","tab":"f03e0277.d4a25","order":1,"disp":true,"width":"12","collapse":false},{"id":"f03e0277.d4a25","type":"ui_tab","name":"BabylonJs4","icon":"dashboard","disabled":false,"hidden":false}]

Transform nodes

Transform nodes are invisible objects that are not rendered but can be used as a center of transformation. This can decrease memory usage and increase rendering speed compared to using an empty mesh as a parent and is less complicated than using a pivot matrix. Moreover the transformation will be applied to all the child meshes of the specified transform node parent.

When creating meshes, the mesh will be added as a child of a transform node if a msg.payload.parent has been specified. The following example flows shows how to create a transform node and use it afterwards as a parent for a mesh, and finally rotate the mesh by rotating the parent transform node:

image

[{"id":"b2e122e.7541de","type":"inject","z":"5623aa0bb38bbf0e","name":"Create box mesh","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_mesh\",\"type\":\"box\",\"name\":\"my_box\",\"parent\":{\"name\":\"my_transform_node\"},\"meshOptions\":{\"width\":1,\"height\":2,\"depth\":2},\"position\":{\"x\":0,\"y\":0,\"z\":0}}","payloadType":"json","_mcu":{"mcu":false},"x":300,"y":1060,"wires":[["4876dd4.6fe9224"]]},{"id":"698ab7e2.6fa6a8","type":"inject","z":"5623aa0bb38bbf0e","name":"Remove transform node","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"remove_transform_node\",\"name\":\"my_transform_node\"}","payloadType":"json","_mcu":{"mcu":false},"x":320,"y":1140,"wires":[["4876dd4.6fe9224"]]},{"id":"4876dd4.6fe9224","type":"ui_babylon_js","z":"5623aa0bb38bbf0e","name":"BabylonJs3 (Material)","group":"284af3b3.34ccbc","order":0,"width":"6","height":"6","folder":"","filename":"","outputField":"payload","actions":[{"selectorType":"meshName","selector":"my_box","trigger":"nothing","payload":"my_payload","topic":"my_topic"}],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":3,\"y\":3,\"z\":3},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true}]","_mcu":{"mcu":false},"x":620,"y":1020,"wires":[[]]},{"id":"21dee65753f87488","type":"inject","z":"5623aa0bb38bbf0e","name":"Create transform node","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_transform_node\",\"name\":\"my_transform_node\",\"parent\":{\"name\":\"my_transform_node\"},\"position\":{\"x\":0,\"y\":0,\"z\":0},\"rotation\":{\"x\":0,\"y\":0,\"z\":0},\"scaling\":{\"x\":1,\"y\":1,\"z\":1}}","payloadType":"json","_mcu":{"mcu":false},"x":320,"y":1020,"wires":[["4876dd4.6fe9224"]]},{"id":"8a85926fc79519dd","type":"inject","z":"5623aa0bb38bbf0e","name":"Update transform node","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_transform_node\",\"name\":\"my_transform_node\",\"rotation\":{\"x\":0,\"y\":90,\"z\":0}}","payloadType":"json","_mcu":{"mcu":false},"x":320,"y":1100,"wires":[["4876dd4.6fe9224"]]},{"id":"284af3b3.34ccbc","type":"ui_group","name":"Default","tab":"7a5078d4.54b268","order":1,"disp":true,"width":"6","collapse":false},{"id":"7a5078d4.54b268","type":"ui_tab","name":"BabylonJs3 (Material)","icon":"dashboard","disabled":false,"hidden":false}]

Lights

Lights are used to specify how meshes are seen, both for illumination and colour. All meshes allow light to pass through them unless shadow generation is activated. Note that this node currently only supports 4 lights maximum!

BabylonJs supports multiple light types, each with their own properties:

  • Point light: a light defined by an unique point in world space, from which light is emitted in every direction. This can be used to simulate a standard light bulb.

  • Directional light: a light that is emitted from everywhere in the specified direction (with an infinite range). Similar to how a planet is lit by the sun.

  • Spot light: a cone of light starting from the position, emitting toward the direction.

  • Hemispheric light: a light that is defined by a direction, usually 'up' towards the sky, to simulate an ambient environment light.

The following flow demonstrates how lights can be controlled:

image

[{"id":"b2ba445c.92b848","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs (Lights)","group":"acd0f09f.5354d","order":2,"width":"12","height":"8","folder":"C:\\Users\\Gebruiker\\Downloads","filename":"scene (6).glb","outputField":"","actions":[],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":-6,\"y\":2,\"z\":12},\"targetPosition\":{\"x\":-6,\"y\":2,\"z\":0},\"active\":true}]","x":530,"y":420,"wires":[["d3affde8.40ef9"]]},{"id":"d3affde8.40ef9","type":"debug","z":"2b6f5d19.202242","name":"3D output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":740,"y":420,"wires":[]},{"id":"18a919b8.9ade46","type":"inject","z":"2b6f5d19.202242","name":"Create 3 point lights","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[{\"command\":\"create_light\",\"type\":\"pointLight\",\"name\":\"light_1\",\"position\":{\"x\":-1.6,\"y\":6.3,\"z\":0.7}},{\"command\":\"create_light\",\"type\":\"pointLight\",\"name\":\"light_2\",\"position\":{\"x\":-6,\"y\":6.3,\"z\":0.7}},{\"command\":\"create_light\",\"type\":\"pointLight\",\"name\":\"light_3\",\"position\":{\"x\":-1.6,\"y\":6.3,\"z\":-6.5}}]","payloadType":"json","x":230,"y":400,"wires":[["b2ba445c.92b848"]]},{"id":"a696184a.63f5b8","type":"comment","z":"2b6f5d19.202242","name":"Maximum 4 lights","info":"By default a material can only have 4 light sources.\nSee https://doc.babylonjs.com/divingDeeper/lights/lights_introduction","x":210,"y":360,"wires":[]},{"id":"d9b97684.5c9108","type":"inject","z":"2b6f5d19.202242","name":"Light on","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[{\"command\":\"update_light\",\"name\":\"light_2\",\"enabled\":true}]","payloadType":"json","x":270,"y":440,"wires":[["b2ba445c.92b848"]]},{"id":"a5495d40.08275","type":"inject","z":"2b6f5d19.202242","name":"Light off","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[{\"command\":\"update_light\",\"name\":\"light_2\",\"enabled\":false}]","payloadType":"json","x":270,"y":480,"wires":[["b2ba445c.92b848"]]},{"id":"a56a24d3.40efc8","type":"inject","z":"2b6f5d19.202242","name":"Diffuse color red","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[{\"command\":\"update_light\",\"name\":\"light_2\",\"diffuseColor\":{\"r\":255,\"g\":0,\"b\":0}}]","payloadType":"json","x":240,"y":520,"wires":[["b2ba445c.92b848"]]},{"id":"3bf8ac7.c47b454","type":"inject","z":"2b6f5d19.202242","name":"Diffuse color white","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[{\"command\":\"update_light\",\"name\":\"light_2\",\"diffuseColor\":{\"r\":255,\"g\":255,\"b\":255}}]","payloadType":"json","x":230,"y":560,"wires":[["b2ba445c.92b848"]]},{"id":"ea32effe.f1688","type":"inject","z":"2b6f5d19.202242","name":"Intensity up","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"up","payloadType":"str","x":250,"y":680,"wires":[["53a60ca9.ed4334"]]},{"id":"fe4cb828.ffc358","type":"inject","z":"2b6f5d19.202242","name":"Intensity down","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"down","payloadType":"str","x":250,"y":720,"wires":[["53a60ca9.ed4334"]]},{"id":"53a60ca9.ed4334","type":"function","z":"2b6f5d19.202242","name":"Calculate intensity","func":"// Default intensity in BabylonJs is 1\nvar intensity = flow.get(\"light_intensity\") || 1;\n\nswitch (msg.payload) {\n    case \"up\":\n        intensity += 0.5;\n        break;\n    case \"down\":\n        intensity -= 0.5;\n        break;\n}\n\nflow.set(\"light_intensity\", intensity);\n\nmsg.payload = {\n    \"command\": \"update_light\",\n    \"name\": \"light_2\",\n    \"intensity\": intensity\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":450,"y":680,"wires":[["b2ba445c.92b848"]]},{"id":"c62511b7.c9063","type":"inject","z":"2b6f5d19.202242","name":"Get light properties","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"get_light_properties\",\"name\":\"^.*\"}","payloadType":"json","x":230,"y":600,"wires":[["b2ba445c.92b848"]]},{"id":"448d44c6.08de5c","type":"inject","z":"2b6f5d19.202242","name":"Remove 3 point lights","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"remove_light\",\"name\":\"^light_.*\"}","payloadType":"json","x":220,"y":640,"wires":[["b2ba445c.92b848"]]},{"id":"acd0f09f.5354d","type":"ui_group","z":"","name":"Lights","tab":"5c22a35.629215c","order":1,"disp":true,"width":"12","collapse":false},{"id":"5c22a35.629215c","type":"ui_tab","name":"BabylonJs","icon":"dashboard","disabled":false,"hidden":false}]

For this demo it is required to download the free kitchen model to the server, and specify the path in the node's config screen.

Note that two properties of a light affect the color:

  • Diffuse: gives the basic color to an object.
  • Specular: produces a highlight color on an object.

The above flow will result in the following demo:

lights demo

Cameras

A camera allows us to view our 3D scene from a certain perspective. Multiple camera's can be created in a BabylonJs scene, but only one camera can be active at a time.

BabylonJs offers different kind of camera's:

  • Universal camera: this camera can be controlled by the keyboard, mouse, touch:

    • Keyboard: The left and right arrow keys move the camera left and right, and the up and down arrow keys move it forwards and backward.
    • Mouse: Rotates the camera about the axes with the camera as origin.
    • Touch': Swipe left and right to move the camera left and right, and swipe up and down to move it forward and backward.
  • Arc Rotate camera: this camera always points towards a given target position and can be rotated around that target with the target as the center of rotation. It can be controlled with cursors and mouse, or with touch events. This camera orbits its target position, like a satellite orbits the earth. Its position relative to the target can be set using a vector and a radius (= the distance from the target). When using the keyboard/mouse/touch swipes, the left/right directions change alpha and the up/down directions change beta

    Arc rotation

  • Follow camera: this camera follows a target mesh, an it will move to a goal position from which to view the target. When the target mesh moves, the camera will follow the target.

    • radius: the distance from the target.
    • heightOffset: the height above the target.
    • rotationOffset: the goal angle in degrees around the target in the x y plane.
    • 'cameraAcceleration':the speed with which the camera moves to a goal position.
    • 'maxCameraSpeed': the maximum speed to which the camera can accelerate.
  • Anaglyph universal camera: this camera extends the use of a universal camera for use with red and cyan 3D glasses. The eyeSpace parameter sets the amount of shift between the left-eye view and the right-eye view.

  • Anaglyph arc rotate camera: this camera extends the use of an arc rotate camera for use with red and cyan 3D glasses. The eyeSpace parameter sets the amount of shift between the left-eye view and the right-eye view.

The following example flow defines how to create these different camera types:

Cameras

[{"id":"59628457.4b462c","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs (Cameras)","group":"3c00e495.ad69ec","order":0,"width":"12","height":"9","folder":"C:\\Users\\Gebruiker\\Downloads","filename":"appartment.gltf","outputField":"payload","actions":[],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":1360,\"y\":28,\"z\":480},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true}]","x":860,"y":360,"wires":[["8eeddfcb.ca14f"]]},{"id":"8eeddfcb.ca14f","type":"debug","z":"2b6f5d19.202242","name":"camera properties","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1090,"y":360,"wires":[]},{"id":"3ee40b49.2d50f4","type":"inject","z":"2b6f5d19.202242","name":"Get camera(s) properties","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"get_camera_properties\",\"name\":\"^.*\"}","payloadType":"json","x":530,"y":220,"wires":[["59628457.4b462c"]]},{"id":"474a583c.13fff8","type":"inject","z":"2b6f5d19.202242","name":"Create universal camera","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_camera\",\"type\":\"universal\",\"name\":\"my_universal_cam\",\"position\":{\"x\":-211,\"y\":35,\"z\":-195},\"targetPosition\":{\"x\":-80,\"y\":30,\"z\":-105}}","payloadType":"json","x":530,"y":280,"wires":[["59628457.4b462c"]]},{"id":"a6c3f235.3158c","type":"inject","z":"2b6f5d19.202242","name":"Create and activate arcRotate camera","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":-211,\"y\":35,\"z\":-195},\"targetPosition\":{\"x\":-80,\"y\":30,\"z\":-105},\"active\":true}","payloadType":"json","x":490,"y":380,"wires":[["59628457.4b462c"]]},{"id":"8c0d15d9.030878","type":"inject","z":"2b6f5d19.202242","name":"Create and activate follow camera","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_camera\",\"type\":\"follow\",\"name\":\"my_follow_cam\",\"targetName\":\"Material2\",\"position\":{\"x\":-211,\"y\":35,\"z\":-195},\"radius\":100,\"heightOffset\":10,\"rotationOffset\":0,\"cameraAcceleration\":0.005,\"maxCameraSpeed\":1,\"active\":true}","payloadType":"json","x":500,"y":460,"wires":[["59628457.4b462c"]]},{"id":"1166257b.5931fb","type":"inject","z":"2b6f5d19.202242","name":"Create and activate anaglyphUniversal camera","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_camera\",\"type\":\"anaglyphUniversal\",\"name\":\"my_anaglyphUniversal_cam\",\"position\":{\"x\":-211,\"y\":35,\"z\":-195},\"targetPosition\":{\"x\":-80,\"y\":30,\"z\":-105},\"eyeSpace\":0.033,\"active\":true}","payloadType":"json","x":460,"y":500,"wires":[["59628457.4b462c"]]},{"id":"fd106477.563568","type":"inject","z":"2b6f5d19.202242","name":"Create and activate anaglypArcRotate camera","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_camera\",\"type\":\"anaglypArcRotate\",\"name\":\"my_anaglypArcRotate_cam\",\"position\":{\"x\":-211,\"y\":35,\"z\":-195},\"targetPosition\":{\"x\":-80,\"y\":30,\"z\":-105},\"eyeSpace\":0.033,\"active\":true}","payloadType":"json","x":470,"y":540,"wires":[["59628457.4b462c"]]},{"id":"ea20b98d.ac5248","type":"inject","z":"2b6f5d19.202242","name":"Create and activate deviceOrientation camera","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_camera\",\"type\":\"deviceOrientation\",\"name\":\"my_deviceOrientation_cam\",\"position\":{\"x\":-211,\"y\":35,\"z\":-195},\"targetPosition\":{\"x\":-80,\"y\":30,\"z\":-105},\"angularSensibility\":10,\"moveSensibility\":10,\"active\":true}","payloadType":"json","x":470,"y":580,"wires":[["59628457.4b462c"]]},{"id":"148091ff.fbab8e","type":"inject","z":"2b6f5d19.202242","name":"Activate universal camera","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_camera\",\"name\":\"my_universal_cam\",\"active\":true}","payloadType":"json","x":530,"y":320,"wires":[["59628457.4b462c"]]},{"id":"f7e5bc8a.2ba99","type":"comment","z":"2b6f5d19.202242","name":"Demo follow camera not ok yet","info":"","x":510,"y":420,"wires":[]},{"id":"3c00e495.ad69ec","type":"ui_group","z":"","name":"Cameras","tab":"ed46361d.448ae8","order":4,"disp":true,"width":"12","collapse":false},{"id":"ed46361d.448ae8","type":"ui_tab","z":"","name":"BabylonJs7","icon":"dashboard","disabled":false,"hidden":false}]

Some remarks about this flow:

  • The command get_camera_properties gets the properties of a camera with the specified name. Or get the properties of multiple camera's by using a regular expression in the camera name. In this flow the regular expression "name": "^.*" means we want to have the properties of all camera's. As a result a separate output message will be send for every camera in the scene. This is very useful if you have manually positioned a camera, and you want to know its current position (in order to be able to use it the next time)!

  • The command create_camera creates a camera in the scene, without the camera becoming the active camera. By adding the json parameter "active": true, the camera will become immediately active (which means you can create a single command to create and activate a camera).

  • The command update_camera allows the properties of an existing camera (by name) to be updated. This can be used e.g. to make another camera the active one...

  • For this demo you need to download the free building model on your server, and specify the file path in the node's config screen. Note that this is a low resolution box with a detailed texture applied to it...

If multiple preset positions are required (i.e. view a scene from multiple angles), this can be achieved in multiple ways:

  • Update the position of a single camera.
  • Create multiple cameras and switch between those cameras, by specifying which camera needs to be active.

camera demo

Gizmos

Gizmo's are objects that can be attached to a existing node (e.g. meshm), to provide user interaction with that node. For example to scale, move, rotate... that node manually.

BabylonJs offers different kinds of gizmos:

Gizmos

The following example flow demonstrates how different kind of gizmos can be created:

Create gizmo flow

[{"id":"fdfcf844.039a28","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs5 (Gizmo demo)","group":"6d46881d.dc2b88","order":0,"width":"12","height":"11","folder":"","filename":"","outputField":"payload","actions":[],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":3,\"y\":3,\"z\":3},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true},{\"command\":\"create_mesh\",\"type\":\"box\",\"name\":\"my_box\",\"meshOptions\":{\"width\":1,\"height\":1,\"depth\":1},\"position\":{\"x\":0,\"y\":0,\"z\":0}}]","x":1280,"y":1660,"wires":[[]]},{"id":"6c6fba54.d02f94","type":"inject","z":"2b6f5d19.202242","name":"Create axisDrag gizmo","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"add_gizmo\",\"name\":\"my_box\",\"type\":\"axisDrag\",\"direction\":{\"x\":1,\"y\":0,\"z\":0},\"outlineColor\":{\"r\":255,\"g\":0,\"b\":0}}","payloadType":"json","x":980,"y":1540,"wires":[["fdfcf844.039a28"]]},{"id":"528b7b19.c0de44","type":"inject","z":"2b6f5d19.202242","name":"Create axisScale gizmo","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"add_gizmo\",\"name\":\"my_box\",\"type\":\"axisScale\",\"direction\":{\"x\":1,\"y\":0,\"z\":0},\"outlineColor\":{\"r\":255,\"g\":0,\"b\":0}}","payloadType":"json","x":980,"y":1580,"wires":[["fdfcf844.039a28"]]},{"id":"d61972da.92563","type":"inject","z":"2b6f5d19.202242","name":"Create planeRotation gizmo","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"add_gizmo\",\"name\":\"my_box\",\"type\":\"planeRotation\",\"direction\":{\"x\":1,\"y\":0,\"z\":0},\"outlineColor\":{\"r\":255,\"g\":0,\"b\":0}}","payloadType":"json","x":960,"y":1620,"wires":[["fdfcf844.039a28"]]},{"id":"f22b0ad8.fb1928","type":"inject","z":"2b6f5d19.202242","name":"Create position gizmo","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"add_gizmo\",\"name\":\"my_box\",\"type\":\"position\"}","payloadType":"json","x":980,"y":1660,"wires":[["fdfcf844.039a28"]]},{"id":"332f1821.99a208","type":"inject","z":"2b6f5d19.202242","name":"Create scale gizmo","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"add_gizmo\",\"name\":\"my_box\",\"type\":\"scale\"}","payloadType":"json","x":990,"y":1700,"wires":[["fdfcf844.039a28"]]},{"id":"bf382804.dd4328","type":"inject","z":"2b6f5d19.202242","name":"Create rotation gizmo","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"add_gizmo\",\"name\":\"my_box\",\"type\":\"rotation\"}","payloadType":"json","x":980,"y":1740,"wires":[["fdfcf844.039a28"]]},{"id":"97af2b5f.2fefb8","type":"inject","z":"2b6f5d19.202242","name":"Create boundingBox gizmo","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"add_gizmo\",\"name\":\"my_box\",\"type\":\"boundingBox\"}","payloadType":"json","x":970,"y":1780,"wires":[["fdfcf844.039a28"]]},{"id":"241a172c.eb3908","type":"inject","z":"2b6f5d19.202242","name":"Remove gizmo","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"remove_gizmo\"}","payloadType":"json","x":1000,"y":1840,"wires":[["fdfcf844.039a28"]]},{"id":"6d46881d.dc2b88","type":"ui_group","name":"Gizmo demo","tab":"555447ec.4acbe8","order":1,"disp":true,"width":"12","collapse":false},{"id":"555447ec.4acbe8","type":"ui_tab","name":"BabylonJs5","icon":"dashboard","disabled":false,"hidden":false}]

I found gizmos very useful to setup e.g. an initial scene:

  1. Add a command to the "Startup" command on my node config screen, to create a mesh (e.g. a box) with some position and size.

  2. As soon as the mesh is visualised, inject a message to add a gizmo to it.

  3. By using the gizmo's it becomes possible to transform the mesh to whatever I want, until the mesh position/size/... fits your needs:

    gizmo-demo

  4. Inject a message containing a get_mesh_properties command to get the properties of the mesh, which are the properties after the gizmo transforms had been applied.

  5. Copy the transformed properties from the debug panel, and copy those to the mesh in the "Startup" command on the node config screen.

  6. After refreshing the screen, the mesh will be displayed automatically with the wanted position/size/...

GUI controls

A GUI control is a (2D) widget that can be displayed on top of the scene, to interact directly with the scene.

BabylonJs offers different types of GUI controls, but currently only the colorpicker is supported in this node:

image

[{"id":"a12627a6.c0b228","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs widgets","group":"ac886c83.c74f1","order":2,"width":"12","height":"9","folder":"C:\\Users\\Gebruiker\\Downloads","filename":"solar_panel.glb","outputField":"payload","actions":[],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":1360,\"y\":28,\"z\":480},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true}]","x":510,"y":1760,"wires":[[]]},{"id":"f878b6fb.09a598","type":"inject","z":"2b6f5d19.202242","name":"Create colorpicker","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_gui_control\",\"type\":\"colorPicker\",\"name\":\"my_colorpicker\",\"targetName\":\"default light\",\"targetProperty\":\"diffuse\",\"horizontalAlignment\":\"right\"}","payloadType":"json","x":250,"y":1760,"wires":[["a12627a6.c0b228"]]},{"id":"21a66d86.b199d2","type":"comment","z":"2b6f5d19.202242","name":"Note that light has 'diffuse' property instead of 'diffuseColor' (like material)","info":"","x":400,"y":1700,"wires":[]},{"id":"ac886c83.c74f1","type":"ui_group","name":"Gui control demo","tab":"956f2124.271f6","order":2,"disp":true,"width":"12","collapse":false},{"id":"956f2124.271f6","type":"ui_tab","name":"BabylonJs Widgets","icon":"dashboard","disabled":false,"hidden":false}]

By binding the colorpicker directly to the color of the light, it becomes possible to control the light via the colorpicker:

colorpicker_demo

Remark: download the free solar panel file, install it on your server, and add the path to the node's config screen to get this demo working.

Animations

Animations can be used to change a property value at some rate (i.e. fps), with some possible intermediate values (= "key values").

The following flow demonstrates the basic animation commands which are supported by this node:

Animations

[{"id":"9e061f1c.49b79","type":"inject","z":"2b6f5d19.202242","name":"Create animation","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_animation\",\"name\":\"my_animation\",\"targetName\":\"my_box\",\"targetProperty\":\"material.diffuseColor\",\"frameRate\":10,\"propertyType\":\"color3\",\"loopMode\":\"cycle\",\"keyFrames\":[{\"time\":0,\"value\":{\"r\":0,\"g\":255,\"b\":0}},{\"time\":2,\"value\":{\"r\":255,\"g\":0,\"b\":0}}]}","payloadType":"json","x":1040,"y":520,"wires":[["6970c5ba.b1ab2c"]]},{"id":"bb6335e3.ab10f8","type":"inject","z":"2b6f5d19.202242","name":"Pause animation","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"pause_animation\",\"name\":\"my_animation\",\"targetName\":\"my_box\"}","payloadType":"json","x":1040,"y":640,"wires":[["6970c5ba.b1ab2c"]]},{"id":"baace73d.fc96d8","type":"inject","z":"2b6f5d19.202242","name":"Restart animation","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"restart_animation\",\"name\":\"my_animation\",\"targetName\":\"my_box\"}","payloadType":"json","x":1040,"y":680,"wires":[["6970c5ba.b1ab2c"]]},{"id":"91e6365f.60a548","type":"inject","z":"2b6f5d19.202242","name":"Stop animation","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"stop_animation\",\"name\":\"my_animation\",\"targetName\":\"my_box\"}","payloadType":"json","x":1040,"y":720,"wires":[["6970c5ba.b1ab2c"]]},{"id":"32cd56f0.fb04ea","type":"inject","z":"2b6f5d19.202242","name":"Reset animation","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"reset_animation\",\"name\":\"my_animation\",\"targetName\":\"my_box\"}","payloadType":"json","x":1040,"y":760,"wires":[["6970c5ba.b1ab2c"]]},{"id":"a6925e3e.585f9","type":"inject","z":"2b6f5d19.202242","name":"Create and start animation","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_animation\",\"name\":\"my_animation\",\"targetName\":\"my_box\",\"targetProperty\":\"material.diffuseColor\",\"frameRate\":10,\"propertyType\":\"color3\",\"loopMode\":\"cycle\",\"keyFrames\":[{\"time\":0,\"value\":{\"r\":0,\"g\":255,\"b\":0}},{\"time\":2,\"value\":{\"r\":255,\"g\":0,\"b\":0}}],\"loop\":true,\"startFrame\":0,\"endFrame\":20,\"autoStart\":true}","payloadType":"json","x":1010,"y":600,"wires":[["6970c5ba.b1ab2c"]]},{"id":"4765ad2f.658cc4","type":"inject","z":"2b6f5d19.202242","name":"Start animation","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"start_animation\",\"name\":\"my_animation\",\"targetName\":\"my_box\",\"loop\":true,\"startFrame\":0,\"endFrame\":20}","payloadType":"json","x":1040,"y":560,"wires":[["6970c5ba.b1ab2c"]]},{"id":"6970c5ba.b1ab2c","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs6 (Animation)","group":"5969529b.1176bc","order":0,"width":"6","height":"6","folder":"","filename":"","outputField":"payload","actions":[{"selectorType":"meshName","selector":"my_box","trigger":"nothing","payload":"my_payload","topic":"my_topic"}],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":3,\"y\":3,\"z\":3},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true},{\"command\":\"create_mesh\",\"type\":\"box\",\"name\":\"my_box\",\"meshOptions\":{\"width\":1,\"height\":1,\"depth\":1},\"position\":{\"x\":0,\"y\":0,\"z\":0}},{\"command\":\"create_material\",\"name\":\"box_material\",\"targetName\":\"my_box\",\"diffuseColor\":{\"r\":255,\"g\":0,\"b\":0}}]","x":1330,"y":640,"wires":[[]]},{"id":"5969529b.1176bc","type":"ui_group","z":"","name":"Default","tab":"5c85638b.e9a33c","order":1,"disp":true,"width":"6","collapse":false},{"id":"5c85638b.e9a33c","type":"ui_tab","z":"","name":"BabylonJs6 (Animation)","icon":"dashboard","disabled":false,"hidden":false}]

babylonJs_animation_demo

Some remarks about this flow: +. It is possible to create an animation, and start it afterwards. Instead it is also possible to create an animation and start it immediately, by adding the autoStart=true property to the command.

  • It is possible to pause an animation and resume it afterwards. Which means that the animation is started again at the same value where it had been paused.

  • A running animation can be stopped, or resetted which means revert the property to its original value.

Materials

Materials are used to cover meshes in color and texture. How a material is displayed depends on the light(s) used in the scene, and how the material is configured to react to those lights. A material can react in 4 possible ways that to light:

  • Diffuse: the basic color or texture of the material as viewed under a light.
  • Specular: the highlight given to the material by a light.
  • Emissive: the color or texture of the material as if self lit.
  • Ambient: the color or texture of the material lit by the environmental background lighting.

The following flow demonstrates how to use materials:

Materials

[{"id":"9decf1f0.6daa3","type":"inject","z":"2b6f5d19.202242","name":"Create and apply material","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_material\",\"name\":\"box_material\",\"targetName\":\"my_box\",\"diffuseColor\":{\"r\":255,\"g\":0,\"b\":0}}","payloadType":"json","x":1330,"y":600,"wires":[["f816d7c.5ffcd28"]]},{"id":"78997b59.4c5094","type":"inject","z":"2b6f5d19.202242","name":"Create material","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"create_material\",\"name\":\"box_material_2\",\"diffuseColor\":{\"r\":0,\"g\":255,\"b\":0}}","payloadType":"json","x":1300,"y":480,"wires":[["f816d7c.5ffcd28"]]},{"id":"b08249d2.a90858","type":"inject","z":"2b6f5d19.202242","name":"Apply material","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"apply_mesh_material\",\"name\":\"box_material_2\",\"targetName\":\"my_box\"}","payloadType":"json","x":1290,"y":520,"wires":[["f816d7c.5ffcd28"]]},{"id":"f816d7c.5ffcd28","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs3 (Material)","group":"284af3b3.34ccbc","order":0,"width":"6","height":"6","folder":"","filename":"","outputField":"payload","actions":[{"selectorType":"meshName","selector":"my_box","trigger":"nothing","payload":"my_payload","topic":"my_topic"}],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":3,\"y\":3,\"z\":3},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true},{\"command\":\"create_mesh\",\"type\":\"box\",\"name\":\"my_box\",\"meshOptions\":{\"width\":1,\"height\":1,\"depth\":1},\"position\":{\"x\":0,\"y\":0,\"z\":0}}]","x":1580,"y":480,"wires":[["a500491a.627b38"]]},{"id":"a500491a.627b38","type":"debug","z":"2b6f5d19.202242","name":"3D output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1780,"y":480,"wires":[]},{"id":"207be304.084a4c","type":"inject","z":"2b6f5d19.202242","name":"Update material","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh_material\",\"name\":\"my_box\",\"diffuseColor\":{\"r\":0,\"g\":0,\"b\":255}}","payloadType":"json","x":1300,"y":560,"wires":[["f816d7c.5ffcd28"]]},{"id":"284af3b3.34ccbc","type":"ui_group","z":"","name":"Default","tab":"7a5078d4.54b268","order":1,"disp":true,"width":"6","collapse":false},{"id":"7a5078d4.54b268","type":"ui_tab","z":"","name":"BabylonJs3 (Material)","icon":"dashboard","disabled":false,"hidden":false}]

So it is possible to create a material, and apply that afterwards to one or more meshes. However when creating a material, it can be applied immediately to one or more meshes (by appending the targetName property to the command).

Helper tools

Pick action

As explained above, it is possible to apply a pick-action to a mesh.

Axes viewer

In case you have no idea where the origin (0, 0, 0) of the coordinate system is located, it is possible to show the 3 axes:

Axes viewer

[{"id":"19d2dc03.344814","type":"inject","z":"2b6f5d19.202242","name":"Show short axes","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_axes\",\"showAxes\":true,\"scaleLines\":1}","payloadType":"json","x":220,"y":280,"wires":[["c1f721a9.284de"]]},{"id":"b0585dec.4fc3d","type":"inject","z":"2b6f5d19.202242","name":"Hide axes","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_axes\",\"showAxes\":false}","payloadType":"json","x":240,"y":360,"wires":[["c1f721a9.284de"]]},{"id":"21351d09.f8bf82","type":"inject","z":"2b6f5d19.202242","name":"Show long axes","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_axes\",\"showAxes\":true,\"scaleLines\":1.5}","payloadType":"json","x":220,"y":320,"wires":[["c1f721a9.284de"]]},{"id":"c1f721a9.284de","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs (Axes)","group":"26b94af2.881a86","order":2,"width":"6","height":"6","folder":"","filename":"","outputField":"","actions":[],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":3,\"y\":3,\"z\":3},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true},{\"command\":\"create_mesh\",\"type\":\"box\",\"name\":\"my_box\",\"meshOptions\":{\"width\":1,\"height\":1,\"depth\":1},\"position\":{\"x\":0,\"y\":0,\"z\":0}}]","x":490,"y":280,"wires":[[]]},{"id":"26b94af2.881a86","type":"ui_group","z":"","name":"Axes","tab":"d8520920.0128d8","order":3,"disp":true,"width":"6","collapse":false},{"id":"d8520920.0128d8","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

The size of the axes can be defined via the scaleLines property.

Selection mode

From time to time it is useful to get some information about one or more meshes in the scene. But if you don't know theire name (e.g. for an imported 3D file), it is not possible to use a get_mesh_properties command. In those cases you can activate the selection mode:

image

[{"id":"4a0d2504.c6c09c","type":"inject","z":"2b6f5d19.202242","name":"Start selection mode","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"start_selection_mode\",\"outlineWidth\":0.05,\"outlineColor\":{\"r\":255,\"g\":0,\"b\":0}}","payloadType":"json","x":230,"y":100,"wires":[["8ab59cae.e48d"]]},{"id":"f79a6c3.2b4dc9","type":"inject","z":"2b6f5d19.202242","name":"Stop selection mode","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"stop_selection_mode\"}","payloadType":"json","x":230,"y":140,"wires":[["8ab59cae.e48d"]]},{"id":"5f77a80e.d25d28","type":"debug","z":"2b6f5d19.202242","name":"3D output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":760,"y":100,"wires":[]},{"id":"8ab59cae.e48d","type":"ui_babylon_js","z":"2b6f5d19.202242","name":"BabylonJs (Selection mode)","group":"d4a8599c.28f058","order":2,"width":"6","height":"6","folder":"","filename":"","outputField":"","actions":[],"showBrowserErrors":true,"startupCommands":"[{\"command\":\"create_camera\",\"type\":\"arcRotate\",\"name\":\"my_arcRotate_cam\",\"position\":{\"x\":3,\"y\":3,\"z\":3},\"targetPosition\":{\"x\":0,\"y\":0,\"z\":0},\"active\":true},{\"command\":\"create_mesh\",\"type\":\"box\",\"name\":\"my_box\",\"meshOptions\":{\"width\":1,\"height\":1,\"depth\":1},\"position\":{\"x\":0,\"y\":0,\"z\":0}}]","x":520,"y":100,"wires":[["5f77a80e.d25d28"]]},{"id":"d4a8599c.28f058","type":"ui_group","z":"","name":"Selection mode","tab":"d8520920.0128d8","order":2,"disp":true,"width":"6","collapse":false},{"id":"d8520920.0128d8","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

When being in selection mode, it is possible to click on meshes in the 3D scene. The selected mesh will get a RED outline, and an output message will be send containing the mesh information.

Demos

Mission impossible style

The following demo combines a number of techniques: when a problem has been detected in a room, the building is displayed in wireframe and the room or roof will be highlighted in red.

mission impossible

[{"id":"2ad576ac8b3bbc4b","type":"ui_babylon_js","z":"7f9646080c92c297","name":"BabylongJs2 (Mission impossible style)","group":"33049469.4e754c","order":0,"width":"12","height":"14","folder":"C:\\Users\\Gebruiker\\Downloads\\sanzio","filename":"scene.gltf","outputField":"payload","actions":[],"showBrowserErrors":false,"startupCommands":"[]","x":760,"y":360,"wires":[[]]},{"id":"c19de8e5542ae7d8","type":"inject","z":"7f9646080c92c297","name":"Show wireframe","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh_material\",\"name\":\"^.*\",\"wireframe\":true}","payloadType":"json","x":400,"y":360,"wires":[["2ad576ac8b3bbc4b"]]},{"id":"6c5416afc3720f7d","type":"inject","z":"7f9646080c92c297","name":"Hide wireframe","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh_material\",\"name\":\"^.*\",\"wireframe\":false}","payloadType":"json","x":400,"y":400,"wires":[["2ad576ac8b3bbc4b"]]},{"id":"97e3dc8338989d99","type":"inject","z":"7f9646080c92c297","name":"Show appartement in red outline color","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh\",\"name\":\"Shape018_paredes_0\",\"outlineWidth\":120,\"outlineColor\":{\"r\":255,\"g\":0,\"b\":0},\"renderOutline\":true}","payloadType":"json","x":330,"y":440,"wires":[["2ad576ac8b3bbc4b"]]},{"id":"5637244c42d4a91d","type":"inject","z":"7f9646080c92c297","name":"Show roof in red overlay color","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"update_mesh\",\"name\":\"Box018_paredes_0\",\"overlayColor\":{\"r\":255,\"g\":0,\"b\":0},\"renderOverlay\":true,\"overlayAlpha\":1}","payloadType":"json","x":360,"y":480,"wires":[["2ad576ac8b3bbc4b"]]},{"id":"33049469.4e754c","type":"ui_group","name":"Mission impossible style","tab":"c2805f33.505de","order":1,"disp":true,"width":"12","collapse":false},{"id":"c2805f33.505de","type":"ui_tab","name":"BabylonJs2","icon":"dashboard","order":23,"disabled":false,"hidden":false}]

Which will result into this:

mission_impossible_demo

For this demo, you need to download the free building model to your server, and specify the file path in the node's config screen.

About

A Node-RED widget node to show an interactive BabylonJs 3D scene in the Node-RED dashboard

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages