Models and objects
Load model files, place copies of them, and link the objects in them to parameters: every option of files, objects and links.
8 minute read
The Grid 3D widget shows a 3D model, a digital twin, of your robot or machine, and moves its parts with live parameters from your application: a joint turns when the real joint turns. You build the model in Blender or a CAD tool, export it as a glTF file, and write a small JSON file that links each moving part to a parameter.
The video shows the whole workflow, from creating a model to linking it to an application:
The widget moves an object by setting its position, rotation or scale relative to its parent. So how you build the model decides how it moves:
.glb, the binary format. Tick Apply Modifiers under Geometry if you use modifiers. Animations you made in Blender are exported with the model and can be played in the dashboard.Keep the file small, so the dashboard loads quickly on a tablet: the stock robot models are 4 to 8 MB. There is no hard limit. Draco and Meshopt compression make files smaller and are supported. A .gltf text file also works, as long as its buffers and textures are embedded in it.
The importer changes some characters in object names. Use the changed name in the JSON file:
| In Blender | In the widget | Example |
|---|---|---|
| A space | Becomes _ |
Upper Arm becomes Upper_Arm |
. : / [ ] |
Removed | Cube.001 becomes Cube001 |
| The same name twice in one file | _1, _2 and so on are added |
The second Link becomes Link_1 |
To see the final names, type grid3d.tree() in the browser console. See Inspect the scene in the browser console.
The JSON file tells the widget which model files to load and which parameter moves which object. The paths of model files are relative to the JSON file. Name the file <name>.3d.json, for example robot.3d.json: the file editor in the portal then checks it against the schema and suggests the keys as you type.
This minimal file loads one model and turns the object Link1 with the first joint position:
{
"files": [
{ "file": "robot.glb" }
],
"objects": [
{
"name": "Link1",
"links": [
{ "link": "root/ManipulatorControl/jointPositionsActual", "channel": 0, "axis": "rz" }
]
}
]
}
Each entry in links takes one value from a parameter and applies it to the object. These are the fields you need most:
| Field | What it does | Default |
|---|---|---|
link |
The parameter path | |
channel |
The element of an array parameter. Ignored for a single value | 0 |
axis |
What the value sets, see the next table | |
gain, offset |
The widget uses value × gain + offset |
1, 0 |
value |
A fixed value, used while the parameter has no data, or always when there is no link |
axis |
Sets | Values read |
|---|---|---|
x, y, z |
Position along one local axis, in m | 1 |
rx, ry, rz |
Rotation about one local axis, in rad | 1 |
position |
Position x, y, z | 3, from channel on |
rotationZYX |
Rotation z, y, x | 3, from channel on |
pose |
Position x, y, z, then rotation z, y, x: a pose such as a tool pose | 6, from channel on |
s, sx, sy, sz |
Scale: all axes, or one | 1 |
visible |
Shows the object when the value is 0.5 or more |
1 |
opacity |
Transparency, from 0 to 1 |
1 |
The widget does not convert units: positions are in metres and rotations in radians, relative to the object’s parent. For a parameter in degrees, use gain 0.0174533; for millimetres, 0.001. Colours, glow, any other property of an object, vector lengths and numbered objects are on Models and objects.
Every joint is linked the same way, to its element of the joint positions. The tool frame follows the tool pose:
"objects": [
{
"name": "Link1",
"castShadow": true,
"links": [{ "axis": "rz", "link": "root/ManipulatorControl/jointPositionsActual", "channel": 0 }]
},
{
"name": "Link2",
"castShadow": true,
"links": [{ "axis": "ry", "link": "root/ManipulatorControl/jointPositionsActual", "channel": 1 }]
},
{
"name": "ToolPose",
"links": [{ "axis": "pose", "link": "root/ManipulatorControl/manipulatorToolPoseActual" }]
}
]
Older files put link, channel and axis directly on the object, for a single link. The widget still reads that form, but new files use links.
To find an object inside another one, separate the names with *: "Robot2*Link1" finds Link1 under Robot2. Use this when you load two models with the same object names. Give each one its own name in files, because duplicates across files are not renamed.
The same file can do much more than move parts. Each topic has its own page:
| Key | What it does | Details |
|---|---|---|
files |
The model files to load, how often and where: one copy, several named copies, or thousands of copies drawn with GPU instancing | Models and objects |
objects |
Settings and links per object: shadows, and parameters that move, show, colour or change it | Models and objects |
animations |
Plays the animations in a model: by itself, on a trigger, at a linked speed, or at a linked position | Animations |
traceLine |
Draws the path of a point, such as the tool centre, coloured or thickened by a value such as the speed | Trace lines |
camera, cameraPosition, cameraLookAt |
Where you look from and at | Camera, lights and rendering |
hemisphereLight, spotLight |
The lights, and the shadows of the spot light | Camera, lights and rendering |
renderSettings |
Frame rate, lighting model, environment, background, ambient occlusion, bloom | Camera, lights and rendering |
Two rules apply to the whole file:
_ is ignored. JSON has no comments, so use this to keep an alternative setting: "spotLight_": { ... } switches the spot light off and keeps its settings, and a files entry with "file_" instead of "file" is not loaded.The schema describes every key, its type and its default:
v-3d schema. The portal’s file editor uses it for files named *.3d.json. Other editors, such as Visual Studio Code, can use it through their JSON schema settings.
The widget has two more settings: frequency divider, how often the parameters update (default 100), and disable view navigation, which locks the camera.
While the widget loads the file, it checks it: files that are missing or are not a glTF model, objects that are not found, keys with a value it does not know. Errors and warnings show in a pop-up on the dashboard, and all of them, with the details, in the browser console (press F12). Each message names the place in the file, such as objects[3] or animations[0], and most say how to fix it. For an object that is not found, the message lists the names that come close.
Open the browser console (F12) on the dashboard and type one of these:
| Command | Shows |
|---|---|
grid3d.tree() |
The object hierarchy, names only, including empties: the names to use in objects and parent. grid3d.tree('Robot') shows only the branch under Robot |
grid3d.find('Link1') |
The object with that name, to look at its position, rotation and materials |
grid3d.animations() |
The animations each model can play, their length, and which entry plays them now. grid3d.animations('Conveyor') shows one model |
grid3d.scene |
The whole scene of the 3D widget on screen |
grid3d.views |
All 3D widgets on screen, by JSON file, each with its scene, camera and renderer |
The console also shows the Grid version the dashboard runs, in the line that starts with grid version:.
opacity changes the object’s material, and every other object in the same file that uses that material changes with it. Give an object its own material before you make it transparent. Copies of a model from a name list or an instances list each get their own materials.castShadow or receiveShadow on them. Keep these to a few objects on slower devices.Load model files, place copies of them, and link the objects in them to parameters: every option of files, objects and links.
Play the animations of a glTF model in a dashboard: by themselves, on a trigger from your application, at a linked speed, or at a linked position.
Draw the path of a moving point, such as a robot’s tool centre, and colour or thicken the line with a value such as the speed.
Set where the 3D view looks from, how the scene is lit, and how it is rendered: environment, background, ambient occlusion, bloom and frame rate.
A room, hall, sky or colour gradient made by the widget itself.
An environment from one equirectangular image, such as an HDR from an HDRI site or a Blender world texture.
An environment from six square images, one per axis direction.