2. Editor interface¶
All AGX Dynamics for Unity scripts are using a custom editor that renders the Inspector GUI. The custom editor supports “editing/serialization” of objects exposed as C# properties. This feature is important to properly synchronize data or states changed during runtime, when the AGX Dynamics native instances has been created, since it’s not reasonable to synchronize all data all the time.
2.2. Components¶
2.2.1. Shapes¶
Shapes defines the geometry of an object and can be of primitive types, such as sphere, capsule, box etc., or arbitrarily shaped, such as triangle mesh or height field.
Shape is base component for collision objects and all primitive and mesh shape types inherits its properties.

Shape properties and tools inherited by all shape types.¶
Property |
Description |
Default |
---|---|---|
Collisions Enabled |
True if this shape can collide with other objects, false to disable all interactions with this shape. |
true |
Is Sensor |
True if this shape is a sensor, meaning this shape will be included in the collision detection but the resulting contacts are not passed to the solver. |
false |
Material |
Shape Material associated to this shape. |
null |
Render Material |
Render material (UnityEngine.Material) used when a visual representation has been associated with the shape, e.g., by using Create visual tool. |
null/not visible |
Tool |
Description |
Notes |
---|---|---|
Resize shape in Scene View holding Ctrl for asymmetric or Ctrl+Shift for symmetric resize of the shape. See Shape resize tool for details. |
||
[Experimental] Create additional shapes as children to this object given visual representations. Select child visual in Scene View and follow instructions in the Inspector. |
||
Disable collisions between this object and objects selected in Scene View. See Disable collisions tool for details. |
||
Create visual representation of current context shapes. See Create visual tool for details. |
Note
Primitive shapes doesn’t support scaling of the transforms when each primitive shape has a well defined size. The more general shape Mesh supports scaling.
2.2.1.1. Box¶
Box collision shape which size is defined given half-extents, i.e., half-width, half-height and half-depth.

Box Inspector properties with default half-extents 0.5 x 0.5 x 0.5.¶
Property |
Description |
Default |
---|---|---|
Half Extents |
Box half-extents. |
(0.5, 0.5, 0.5) |
See also
Inherited properties and tools.
2.2.1.2. Sphere¶
Sphere collision shape which size is defined given radius.

Sphere Inspector properties with default radius 0.5.¶
Property |
Description |
Default |
---|---|---|
Radius |
Sphere radius. |
0.5 |
See also
Inherited properties and tools.
2.2.1.3. Capsule¶
Capsule collision shape which size is defined given height and radius.

Capsule Inspector properties with default height 1.0 and default radius 0.5.¶
Property |
Description |
Default |
---|---|---|
Height |
Capsule height. |
1.0 |
Radius |
Capsule radius. |
0.5 |
Note
The Inspector is showing Common Render Material instead of Render Material because the visual representation of the capsule is an assembly of three objects; top half-sphere, cylinder cap and bottom half-sphere. The three objects share the same material and changing Common Render Material will assign the new material to all three objects. If the objects don’t have common material Render Material will be a list of each individual material.
See also
Inherited properties and tools.
2.2.1.4. Cylinder¶
Cylinder collision shape which size is defined given height and radius.

Cylinder Inspector properties with default height 1.0 and default radius 0.5.¶
Property |
Description |
Default |
---|---|---|
Height |
Cylinder height. |
1.0 |
Radius |
Cylinder radius. |
0.5 |
See also
Inherited properties and tools.
2.2.1.5. Mesh¶
Generic mesh collision shape which surface and size is defined given a source UnityEngine.Mesh
asset
and scale of the transform. Note that this AGXUnity.Collide.Mesh
supports any number of source meshes,
which will be merged into a single collision mesh when initialized. Support for multiple source meshes hasn’t been
exposed in the Inspector but is accessible from scripts.

Mesh Inspector properties.¶
Property |
Description |
Default |
---|---|---|
Source |
Source mesh asset. |
null |
Options |
Trimesh, vertex reduction disabled. |
See also
Inherited properties and tools.
Mesh and scale of its transform and parent transform.
2.2.1.5.1. Source read/write access is required¶
The Source mesh asset has to have mesh data read/write access enabled. When Unity imports models, such as
.fbx
or .dae
, the mesh data is protected on the GPU. This means that it’s not possible to read
the mesh data, required for the collision mesh, on the CPU.
To enable read/write, select the asset in Project View and make sure the Read/Write Enabled
checkbox is
enabled in the Inspector.

Model import settings Inspector, the Read/Write Enabled
has to be checked for the collisions mesh to
be able to access the mesh data.¶
2.2.1.5.2. Collision Mesh Options¶
Applied Collision Mesh Options will separate the mesh data from the given source UnityEngine.Mesh
to enable
additional non-runtime mesh operations, such as Vertex Reduction, Convex Shape and Convex Decomposition.
Applying the default options will create an exact copy of the mesh data in the source UnityEngine.Mesh
.
Vertices and Triangles/Indices of a collision mesh are stored in AGXUnity.Collide.CollisionMeshData
and
Mesh contains a list of these collision meshes. If the list is empty (default), the source
UnityEngine.Mesh
is used, as in 2.4.3 (2021-06-17) and earlier versions.
Property |
Description |
Default |
---|---|---|
Mode |
Collision shape(s) type: Trimesh, Convex or Convex Decomposition |
Trimesh |
Vertex Reduction Enabled |
True to enable vertex reduction. |
false |
Reduction Ratio |
Reduction ratio ranging [0.02, 0.98] where lower values results in more reduced vertices. |
0.5 |
Reduction Aggressiveness |
Lower is faster and higher value results in better decimation. |
7.0 |
Element Resolution Per Axis |
Convex Decomposition - lower values results in less accurate decomposition but is faster. Higher values results in a more accurate convex representation but takes more time. Recommended range [20, 400]. |
50.0 |

Expanded Collision Mesh Options Inspector of a Mesh with Vertex Reduction enabled at 0.3 Reduction Ratio. The “Summary” shows a reduction of triangles from 4368 to 1326.¶
Note
Apply will generate the collision mesh(es) given the current options. Reset will delete the current collision mesh(es) and reset the options to default.
Demonstration of mesh gears, interacting with each other by the contacts created between them.
Default, using the source UnityEngine.Mesh
- vertex reduction enabled - as convexes
(bad idea for gears) and convex decompositions with Element Resolution Per Axis at 90 to catch
(almost) all cogs. Note that most of the time it took performing the convex decomposition has
been edited out. It took about 10 seconds per gear.
Note
Avoid generation of collision meshes on prefab instances. To a the prefab, open the prefab in the Prefab Stage and generate the collision meshes from there instead. The reason for this is that Unity may hang for a long time due to the amount of Prefab Overrides the collision meshes results in on prefab instances.
2.2.1.6. Height Field¶
Height field is a static height map that reads the height data from an UnityEngine.Terrain instance.

Height field Inspector properties.¶
See also
Inherited properties and tools.
2.2.1.7. Plane¶
Plane collision shape where the plane normal is the y-axis of its transform.

Plane Inspector properties are the default of every other shape. The plane is defined by its transform where the y-axis defines the normal in the plane.¶
See also
Inherited properties and tools.
2.2.1.8. Additional shapes¶
Note
Hollow Cylinder, Cone and Hollow Cone supports proper contact generation between each other. When colliding with other shape types a fallback is used, treating either Hollow Cylinder, Cone or Hollow Cone as a convex, generating maximum one contact point. Hollow Cylinder and Hollow Cone doesn’t have a hole either colliding with other shapes since Hollow Cylinder and Hollow Cone are converted to convex shapes.
Hollow Cylinder

Hollow Cylinder Inspector properties with default thickness 0.1, default radius 0.5 and default height 1.0.¶
Cone

Cone Inspector properties with default top radius 0.1, default bottom radius 0.5 and default height 1.0.¶
Hollow Cone

Hollow Cone Inspector properties with default thickness 0.1, default top radius 0.3, default bottom radius 0.5 and default height 1.0.¶
2.2.2. Rigid Body¶
A rigid body is an entity in 3D space with physical properties such as mass, inertia and dynamic properties such as position, rotation and velocity.

Rigid body box (1 x 1 x 1 meters) Inspector with default mass and inertia given default density 1000 \(kg/m^3\).¶
Property |
Description |
Default |
---|---|---|
Mass |
Mass of the rigid body. |
1 |
Inertia Diagonal |
Inertia diagonal of the rigid body. |
(1, 1, 1) |
Motion Control |
Motion control of the rigid body. |
DYNAMICS |
Handle As Particle |
Toggle whether rotational properties of the rigid body should be disabled. |
false |
Linear Velocity |
Initial/current linear velocity of the rigid body - in world frame. |
(0, 0, 0) |
Angular Velocity |
Initial/current angular velocity of the rigid body - in world frame. |
(0, 0, 0) |
Linear Velocity Damping |
Linear velocity damping of the rigid body - in local frame. |
(0, 0, 0) |
Angular Velocity Damping |
Angular velocity damping of the rigid body - in local frame. |
(0, 0, 0) |
Tool |
Description |
Notes |
---|---|---|
Configure and create constraints. |
||
Disable collisions between this object and objects selected in Scene View. See Disable collisions tool for details. |
||
[Experimental] Create additional shapes as children to this object given visual representations. Select child visual in Scene View and follow instructions in the Inspector. |
||
Create visual representation of current context shapes. See Create visual tool for details. |
Affects all shapes associated to the rigid body. |
2.2.2.1. Mass properties¶
Mass and inertia can either be calculated given current shape configuration (size, shape materials and relative transform) of the rigid body, or explicitly assigned in the Inspector.

Mass properties Inspector with automatic calculation toggle, mass/inertia fields and explicit update button.¶
2.2.2.2. Collision shapes¶
Shapes can either be added to the game object the Rigid Body component is at, without relative offset, and/or as child game objects with arbitrary relative transform.
Rigid body and box components on the same game object meaning the rigid body shares the transform with the box - suitable when the shape doesn’t have a relative transform to the rigid body.
Rigid body game object with several shapes, of arbitrary relative transforms, as children.
2.2.2.3. Motion control¶

A dynamic rigid body has mass and inertia, and interacts with other objects through its Shapes and/or Constraints. Dynamics rigid bodies may have an initial linear- and/or angular velocity. The continuous velocities and transform integrations are made by the AGX Dynamics solvers.
A kinematic rigid body has infinite mass and inertia when it interacts with other objects and kinematic bodies has explicit (user defined) linear- and angular velocity.
A static rigid body has infinite mass and inertia but no linear- or angular velocity. The transform should also remain constant through a simulation.
2.2.3. Constraint¶
Constraint (or Joint) in AGX Dynamics for Unity defines a geometrical relation between one or two objects. Each object in the constraint has its own frame, where that frames z-axis is, by definition, the constraint axis. Several constraint types has a well defined rotation and/or translation axis and that axis is about/along the constraint axis.
Constraints could have controllers. Controllers are drivers or further limitations about/along the constraint axis.
Type |
Axis |
Controllers |
---|---|---|
Hinge |
Rotation |
Range, Target Speed, Lock, Electric Motor, Friction |
Prismatic |
Translation |
Range, Target Speed, Lock, Electric Motor, Friction |
Lock Joint |
None |
None |
Cylindrical Joint |
Rotation and Translation |
Range, Target Speed, Lock, Electric Motor, Friction, Screw |
Ball Joint |
None |
None |
Distance Joint |
Translation |
Range, Target Speed, Lock, Electric Motor, Friction |
Angular Lock Joint |
None |
None |
Plane Joint |
None |
None |
2.2.3.1. Frames¶

Constraint frames Inspector.¶
All constraints contains two frames - Reference frame and Connected frame. The reference frame is the main reference frame and by default the connected frame is synchronized to be initialized given the transform of the reference frame.
Property |
Description |
Default |
---|---|---|
Parent |
Parent object that the frame follows when moved. |
null |
Local Position |
Local position with respect to Parent. |
(0, 0, 0) |
Local Rotation |
Local rotation with respect to Parent. |
(0, 0, 0) |
Tool |
Description |
---|---|
Select parent in Scene View. |
|
Find transform given a point on a mesh surface. |
|
Find transform given a triangle edge and surface. |
|
Toggle to enable/disable the transform handle in Scene View. |
2.2.3.2. Properties¶

Constraint Inspector.¶
Property |
Description |
Default |
---|---|---|
Reference frame |
Constraint reference frame with Parent and local transform with respect to the parent. |
|
Connected frame |
Constraint connected frame with Parent and local transform with respect to the parent. |
|
Disable Collisions |
Disable collisions between the pair of rigid bodies in the constraint or disable collisions between reference frame parent against connected frame parent - or don’t disable. |
Don’t disable collisions |
Solve Type |
Constraint solve type Direct, Direct And Iterative or Iterative. |
Direct |
Connected Frame Animated |
When true, the transform of the native connected frame is written back to the connected frame. |
false |
Translational properties |
Compliance, damping and force range of each constrained, translational degree of freedom. |
|
Rotational properties |
Compliance, damping and force range of each constrained, rotational degree of freedom. |
|
Controllers |
List of controllers if the constraint type supports controllers. |
Translational properties
Compliance, damping and force range of each constrained translational degree of freedom. If the degree of freedom isn’t constrained, the GUI is disabled and has value 0.

A Hinge Translation properties with default values.¶
Rotational properties
Compliance, damping and force range of each constraint rotational degree of freedom. If the degree of freedom isn’t constrained, the GUI is disabled and has value 0.

A Hinge Rotational properties with default values. Note that the hinge rotates about the constraint axis N (or Z), meaning that degree of freedom isn’t constrained, so these parameters are disabled.¶
2.2.3.3. Controllers¶
A constraint controller is constraining a free degree of freedom of a constraint, e.g., the rotation axis of a hinge. Each controller type inherits the following base properties:
Property |
Description |
Default |
---|---|---|
Enable |
Toggle to enable/disable the controller. |
false |
Compliance |
Compliance of the controller. |
1.0E-8 |
Damping |
Damping of the controller. |
0.0333 |
Force Range |
The controller may only apply forces within this range. |
(-inf, inf) |

Controllers of a Hinge. This list is similar for all constraint types that has controllers except for Cylindrical Joint which has both rotational and translational controllers and an additional Screw Controller.¶
Range controller
Controller that, when enabled, defines a range which the constraint angle should fulfill.
Property |
Description |
Default |
---|---|---|
Range |
Range the constraint angle should fulfill. Unit distance for translational and radians for rotational controllers. |
(-inf, inf) |
Target speed controller
Controller that, when enabled, drives the constraint angle with given speed.
Property |
Description |
Default |
---|---|---|
Speed |
Target speed of the constraint angle. |
0 |
Lock At Zero Speed |
Transforms to a holonomic lock when target speed is exactly zero, preventing the angle to drift over time. |
false |
Lock controller
Controller that, when enabled, defines a position/angle which the constraint angle should fulfill.
Property |
Description |
Default |
---|---|---|
Position |
Target position of the constraint angle. |
0 |
Electric motor controller
Controller that, when enabled, drives the constraint angle given an electric motor model.
Property |
Description |
Default |
---|---|---|
Voltage |
Available voltage or voltage drop across the terminals of this motor. |
24 V |
Armature Resistance |
Resistance in the armature circuit. |
1 Ohm |
Torque Constant |
Couples electrical current in to force/torque out. |
1 |
Friction controller
Controller that, when enabled, adds internal friction forces about/along the constraint axis.
Property |
Description |
Default |
---|---|---|
Friction Coefficient |
Friction coefficient. Note: If this controller is rotational (Hinge, Cylindrical Joint) the radius of the axle should be included in this value. |
0.4167 |
Non Linear Direct Solve Enabled |
Toggle to enable non-linear direct solves for a more accurate normal force magnitude given current friction force. |
false |
2.2.3.4. Configuration¶
When constraints normally relates to a pair of objects, the constraint component lives on its own game object where the game object transform is ignored.
Under normal conditions, configuration of a constraint can be divided into three tasks:
Find constraint (reference) frame parent and transform.
Select connected frame parent.
Assign initial values and/or enable and configure controllers.
Tools, such as Find point tool , Find edge tool
and Select parent tool
, can be used to complete (1) and (2).
Using Find edge tool and Select parent tool to configure frames for a Prismatic and a Hinge. The Target Speed controller is enabled with 1 m/s target speed for the prismatic.
2.2.4. Wire¶
Wire is an adaptive resolution lumped element model for simulating wires, ropes and chains. The resolution of the wire adopts to current tension, filtering out the high frequencies when the wire is under heavy load by removing mass nodes and distributing the mass to other places along the wire. The removed nodes comes back again when/if the tension is low enough. This makes the wire model stable and accurate for a wide range of scenarios, such as heavy loads and/or extremely long (10 km or longer) where for example our fixed resolution model, Cable, will fail to perform.
See AGX Dynamics Wire documentation for further information about the wire model.
Note
Torsion is not included in the wire model.
To create a wire, add the Wire
component to a game object or click
AGXUnity -> Model -> Wire
from the main menu for a new game object
with the Wire
component added.

Wire Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Route |
List of nodes that defines the initial route of the wire. |
|
Radius |
Radius of the wire (coupled with Diameter). |
0.015 |
Diameter |
Diameter of the wire (coupled with Radius). |
0.03 |
Resolution Per Unit Length |
Target maximum resolution of mass nodes per length unit. |
1.5 |
Linear Velocity Damping |
Velocity damping value of the wire. |
0 |
Scale Constant |
Value that indicates how likely it is that mass nodes appears along the wire. Higher value means more likely. |
0.35 |
Material |
Shape Material of the wire. |
null |
Tip
Demo Scene and Deck Crane examples.
2.2.4.1. Routing a wire¶
The wire route is a list of nodes where the order of the nodes is important. Read more about the different node types in the AGX Dynamics Node documentation.
The route is empty by default, the first node is added by pressing (1) in the figure below.

Wire route list Inspector. (1) Append new node to the list. (2) Insert node before, insert node after and erase node.¶
Each node in the route has a type and a frame. The frame has Select parent tool,
Find point tool, Find edge tool and toggle transform handle to manage
the transform and visualization of the node. The rotation of the node is only important for
Winch Node
where the direction of the winch is along the z-axis of the node frame.
Errors in the route are marked in red and the tooltip displays the error.


Route error displaying tooltip: Body Fixed Node can only be at the begin or at the end of wire.¶
Routing a wire around three cylinders and attaching a dynamic box using eye nodes (slides along the wire). The additional free node before the dynamic box is to add additional length to the route when the wire will wrap around the cylinders when the simulation starts.
2.2.4.2. Rendering the wire¶
The provided AGXUnity.Rendering.WireRenderer is currently an example implementation of how a wire can be rendered.
Example how collect the world positions of the route nodes:
var wire = GetComponent<Wire>();
var positions = new List<Vector3>();
foreach ( var routeNode in wire.Route )
positions.Add( routeNode.Position );
Vector3[] alsoPositions = ( from node in wire.Route
select node.Position ).ToArray();
When the wire has been initialized, the route shouldn’t be accessed since there’s more data in the simulation. Collecting the world positions of all points of an initialized wire:
// Extension methods ToHandedVector3() etc.
using AGXUnity.Utils;
...
var nativeWire = GetComponent<Wire>().Native;
var positions = new List<Vector3>();
var currIterator = nativeWire.getRenderBeginIterator();
var endIterator = nativeWire.getRenderEndIterator();
while ( !currIterator.EqualWith( endIterator ) ) {
positions.Add( currIterator.getWorldPosition().ToHandedVector3() );
// Incrementing the iterator on the native side to avoid
// creating garbage.
currIterator.inc();
}
// Pooling iterators to avoid garbage.
currIterator.ReturnToPool();
endIterator.ReturnToPool();
2.2.5. Cable¶
The cable module is used to simulate cables, hoses, ropes, short wires and dress packs. These are long structures with a circular cross section that can be bent, stretched and twisted.
See AGX Dynamics Cable documentation for more information about the cable module.
To create a cable, add the Cable
component to a game object or click
AGXUnity -> Model -> Cable
from the main menu for a new game object with the
Cable
component added.

Cable Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Route |
List of nodes that defines the initial route of the cable. |
|
Radius |
Radius of the cable (coupled with Diameter). |
0.05 |
Diameter |
Diameter of the cable (coupled with Radius). |
0.1 |
Resolution Per Unit Length |
Target maximum resolution per length unit. |
5.0 |
Linear Velocity Damping |
Linear velocity damping value of each cable element. |
0 |
Angular Velocity Damping |
Angular velocity damping value of each cable element. |
0 |
Material |
Shape Material of the wire. |
null |
Properties |
Cable Properties of the cable. |
null |
Tip
Demo Scene example.
2.2.5.1. Routing the cable¶
Routing a cable is very similar to routing a wire but since the cable model includes torsion, the complete transform of the node is important and the direction of the cable is by definition along the z-axis of the frame.
Another discrepancy from the Wire is there may be any number of fixed nodes along a cable.
Note
The frame tools around routing of cables aren’t currently optimal. The workflow of routing cables will be improved in the future.
2.2.6. Deformable Terrain¶
Deformable Terrain, AGXUnity.Model.DeformableTerrain
, module is a deformable
surface enabling objects to perform different operations - such as compressing,
digging, pushing/pulling and grading.
See AGX Dynamics Terrain documentation for detailed information about the terrain module.
Note
Currently, the Deformable Terrain
component depends on
UnityEngine.Terrain
which is required to be static, while
the AGX Dynamics Terrain module supports dynamic/moving terrains.
To create a Deformable Terrain, add the Deformable Terrain
component to
a UnityEngine.Terrain
game object or click AGXUnity -> Model -> Deformable Terrain
from the main menu for a new UnityEngine.Terrain
game object with the
Deformable Terrain
component added. The latter will create a 60 square
meter UnityEngine.Terrain
with a 257 x 257 height map resolution.
The Terrain width and length with the height map resolution defines the size of the particles while digging. 60 square meters with a 257 x 257 resolution results in a nominal radius of 0.127 meters of the particles.

Deformable Terrain Inspector with default values (Element Size is dependent on terrain width, length and resolution and cannot be changed).¶
Property |
Description |
Default |
---|---|---|
Material |
Shape Material of the terrain. |
null |
Terrain Material |
Deformable Terrain Material of the terrain. |
null |
Properties |
Deformable Terrain Properties of the terrain. |
null |
Maximum Depth |
Maximum depth possible to dig/deform, see Initialization for further information. |
20.0 |
Shovels |
Shovels associated to the terrain. |
Tip
Wheel Loader on Terrain example.
2.2.6.1. Initialization¶
When compacting, digging, pushing/pulling and grading the deformable terrain, the
heights in the UnityEngine.TerrainData
object are updated, and these changes
are normally persistent. To prevent the height data from being persistent, Deformable
Terrain is storing the initial heights during initialize and writing them back to the
UnityEngine.TerrainData object during uninitialize. As a result of this, the data could be
lost/left modified if the application exists without proper uninitialization, e.g., due to a crash.
The Unity terrain doesn’t support negative height values and normally one don’t
want to raise the whole terrain (using the Unity terrain tools) to be able to
dig in the Deformable Terrain. Deformable Terrain solves this by, during initialization,
adding Maximum Depth
to all height values and compensating the height
difference by changing the position of the terrain game object Maximum Depth
down. The change of the transform is restored to the original during uninitialization.
The change of the transform is made during runtime so the transform will always be restored,
even after a crash, but the transform could seem wrong due to the initially changed
height values in case of a crash.
Note
Make sure the Terrain Height
property under
Terrain Settings -> Mesh Resolution
is large enough to handle
the addition of height made during initialization. E.g., if the hills in
the terrain is expected to be at maximum 15 meters high and Maximum Depth
is 20 meters, Terrain Height
should be at least 15 + 20 = 35 meters.
Initialization summary
Store
UnityEngine.TerrainData
initial height data into array.Add
Maximum Depth
to all heights in theUnityEngine.TerrainData
object.Move the terrain game object
Maximum Depth
down.
Uninitialization summary
Set
UnityEngine.TerrainData
heights to the ones stored during initialization.Restore position of the terrain game object to the original.
2.2.6.2. Shovel¶
A “Shovel” is any object that can represent a tool used in earthmoving operations - from an excavator or wheel loader bucket to a bulldozer blade.
See AGX Dynamics Terrain Shovel documentation for detailed information about the shovel.
The Deformable Terrain Shovel
component requires a game object with the Rigid Body
component.
Debug.Assert( bucketGameObject.GetComponent<AGXUnity.RigidBody>() != null );
var shovel = bucketGameObject.AddComponent<AGXUnity.Model.DeformableTerrainShovel>();

Adding the Deformable Terrain Shovel
component to a game object with a Rigid Body component.¶

Deformable Terrain Shovel Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Top Edge |
Top edge of the shovel. |
unconfigured |
Cutting Edge |
Cutting edge of the shovel. |
unconfigured |
Cutting Direction |
Cutting direction of the shovel. |
unconfigured |
Settings |
Deformable Terrain Shovel Settings of the shovel. |
null |
For a shovel to be able to dig in the Deformable Terrain, the shovel instance must be added to the Deformable Terrain.
Configuring the edges
See AGX Dynamics Terrain Shovel Setup documentation for detailed information about the edges and cutting direction.
Configuring the edges and cutting direction for a bulldozer blade and a wheel loader bucket.
The directions of the edges and cutting direction are all dependent and must be correct for the shovel to function while interacting with Deformable Terrain. The Inspector tools coupled to the shovel instance are doing their best to find the correct directions. The following capture shows how information is displayed for misconfigured edges.
2.2.6.3. Rendering the particles¶
The simulated spheres generated from the Deformable Terrain aren’t particles, they’re 6 DOF, so
rotation may be taken into account. The included Deformable Terrain Particle Renderer
is
rendering the particles, including rotation, given a unit size object to instantiate.

Deformable Terrain Particle Renderer Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Render Mode |
Draw Mesh Instanced or Game Object where Draw Mesh Instanced is using
|
Draw Mesh Instanced |
Granule Instance |
Game Object of unit size containing the visual data. For Draw Mesh Instanced it’s
required that Game Object contains one |
null |
Example how to update the transforms of the instances:
var soilSimulation = DeformableTerrain.Native.getSoilSimulationInterface();
var granulars = soilSimulation.getSoilParticles();
var numGranulars = (int)granulars.size();
// More granular instances comparing to last time, create
// more instances to match numGranulars.
if ( numGranulars > transform.childCount )
Create( numGranulars - transform.childCount );
// Less granular instances comparing to last time, destroy.
else if ( transform.childCount > numGranulars )
Destroy( transform.childCount - numGranulars );
Debug.Assert( transform.childCount == numGranulars );
for ( int i = 0; i < numGranulars; ++i ) {
var granule = granulars.at( (uint)i );
var instance = transform.GetChild( i );
instance.position = granule.position().ToHandedVector3();
instance.rotation = granule.rotation().ToHandedQuaternion();
// Assuming unit size of the instance, scale to diameter
// of the granule.
instance.localScale = Vector3.one * 2.0f * (float)granule.getRadius();
// Return the proxy class to the pool to avoid garbage.
granule.ReturnToPool();
}
2.2.7. Track¶
Continuous track is part of the AGX Dynamics agxVehicle
module.
See AGX Dynamics Track documentation for detailed information about track wheel, track and properties.
To create a Track, add the Track
component to a game object or
click AGXUnity -> Model -> Track
for a new game object with the
Track
component added.

Track Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Number Of Nodes |
The number of nodes/shoes of the track. |
64 |
Thickness |
Thickness of the track. |
0.05 |
Width |
Width the track. |
0.35 |
Initial Tension Distance |
Initial node separation of the track nodes. |
1.0E-3 |
Properties |
Track Properties of the track. |
null |
Internal Merge Properties |
Track Internal Merge Properties of the track. |
null |
Material |
Shape Material of the track. |
null |
Wheels |
Wheels associated to the track. |
Creating and configuring a track using available tool to select track wheels and adding the track wheel to the Track instance, using Scene View. If the selected object doesn’t have a Track Wheel component, the component is added to the Rigid Body game object.
Creating and configuring a track using individual components.
Tip
Demo Scene example.
2.2.7.1. Track Wheel¶
The Track Wheel component is used by Track instances as an implicit definition of the geometry of the wheel. It contains a frame where the direction of the axes are important. For more information, read the AGX Dynamics Track Wheel documentation.

Track Wheel Inspector with initial estimated values.¶
In Reset
of the Track Wheel component, the radius, model and the rotation axes
are estimated.
Radius estimation
If the associated Rigid Body has one or more shapes with a property named
Radius
- the maximum value of Radius
is used.
If the associated Rigid Body doesn’t have shapes with a defined radius any
UnityEngine.MeshFilter
under the rigid body is tested, where if two extents
of the local bounding box are similar and the last is smaller, the extents of the
larger two is assumed to be the radius. The maximum radius of all collected mesh filters
under the rigid body is used.
Model estimation
If the name of the game object contains the sub-string of the different model names,
the model is assumed to be that model. The model names are Sprocket
, Idler
and Roller
. The sub-strings are matched with lower cases.
For example, MySprocket72 -> AGXUnity.Model.TrackWheelModel.Sprocket
and
an_idler_4 -> AGXUnity.Model.TrackWheelModel.Idler
. If no match is found, the
default model (AGXUnity.Model.TrackWheelModel.Roller
) is used.
Relative frame estimation
The rotation axis (y-axis) is found by either using the default rotation axis (y-axis) of any Cylinder or Capsule, or similar to Radius estimation, using the shortest extent of the local bounds of a mesh filter under the rigid body.
The wheel up axis (z-axis) is found by rotating about the rotation axis towards the y-axis of the rigid body game object.
2.2.8. Tire¶
AGX Dynamics for Unity supports both One- and Two Body Tire models where One Body Tire is performing contact reduction and orienting the friction plane given the rotation axis. Two Body Tire is a model with two constrained rigid bodies, the tire and the rim, to model the deformation of the tire.
See AGX Dynamics Tire Model documentation for more information about Two Body Tire.
2.2.9. Hydro- and Aerodynamics¶
When an object is moving through air, water or another fluid it is affected by hydrodynamic effects such as lift, drag and added mass. This functionality is enabled by adding a Wind And Water Manager to the scene.
All objects interacting with the Water associated to the Wind And Water Manager will be subject to hydrodynamics forces. Aerodynamics is disabled by default and enabled using the Aerodynamics Parameters component.
See AGX Dynamics Hydro- and Aerodynamics documentation for more information.
Tip
Demo Scene example.
2.2.9.1. Hydrodynamics Parameters¶
It’s possible for objects to have different hydrodynamics specific parameters, such as drag, lift
and mesh resolution. Add the Hydrodynamics Parameters
to the object, or group of objects,
the parameters should affect.

Hydrodynamics Parameters Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Shape Tessellation |
Primitive shape types mesh tessellation quality: Low, Medium, High or Ultra High |
Medium |
Pressure Drag |
Pressure drag coefficient - affects force magnitudes along the surface normals. |
0.6 |
Viscous Drag |
Viscous drag coefficient - affects force magnitudes along the surface tangents. |
0.1 |
Lift |
Lift coefficient - affects force magnitudes along the surface normals depending on the tangential relative velocity. |
0.01 |
Propagate To Children |
Propagate Parameters to this object and all its children. |
false |
The parameter that controls the buoyancy force is Density
in the Shape Material of the objects.
2.2.9.2. Aerodynamics Parameters¶
The Aerodynamics Parameters are identical to the Hydrodynamics Parameters. The only difference is that the aerodynamics calculations is disabled by default - resulting in an extra enabled flag in the Aerodynamics Parameters.

Aerodynamics Parameters Inspector with default values.¶
Note
Aerodynamics Enabled is by default true in this component, but any object not affected by Aerodynamics Parameters, Aerodynamics Enabled is implicitly false.
Capture showing that aerodynamics is disabled by default and how to enable it for a Rigid Body/Shapes, Wire and Cable.
2.2.10. Adaptive Model Order Reduction - AMOR¶
Adaptive Model Order Reduction, short AMOR, is a novel technique that reduces the computational complexity of a simulation by merging objects with each other, reducing the overall number of degrees of freedom in the simulation. Unlike sleep/wake, which many physics engines support, AMOR preserves the dynamics of merged sub-systems, enabling further interactions with other objects. This means that, e.g., parts of a coupled system (a complex crane for example) may be merged while the reactive forces on an active actuator is still accurate. Or having 1 500 rocks as payload on an operating Articulated Dump Truck, with complex wheel suspensions and hydraulic flatbed, the rocks may merge with the flatbed during operation, reducing the simulated system size with orders of magnitude.
See AGX Dynamics Merge Split Handler - AMOR documentation for detailed information about this functionality.
This feature is enabled by toggling Simulation (Manager) property Enable Merge Split Handler
to true/enabled and by enabling merge and/or split for objects using the Merge Split Properties
component.
Enabling the Merge Split Handler using the Simulation (Manager) instance in the scene.
Tip
Demo Scene example.
2.2.10.1. Merge Split Properties¶
The Merge Split Properties component controls enabling/disabling of merging and splitting
of objects, given Enable Merge Split Handler
is enabled in the Simulation (Manager).
See AGX Dynamics AMOR Merge Split Properties documentation for further information about these properties.

Merge Split Properties Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Enable Merge |
Toggle if the object(s) may or may not merge with other objects. |
false |
Enable Split |
Toggle if the object(s) may or may not split from other objects. |
false |
Geometry Contact Thresholds |
Contact thresholds related to merging and splitting of objects in contact. |
Default |
Constraint Thresholds |
Constraint thresholds related to merging and splitting of constrained objects. |
Default |
2.2.11. Disable collisions¶
AGX Dynamics for Unity is using named collision groups to filter interactions between objects. Default interaction behavior is enabled, meaning collision groups defines groups that shouldn’t interact.
Objects supporting collision groups are:
2.2.11.1. Collision groups¶
List of collision groups that will be added to all supported components on subject game object. There’s a per group name option to propagate the group to children of this game object.
The collision groups aren’t affecting interactions until group pairs are disabled in the Collision Groups Manager.

Collision groups Inspector with two groups added. My object group name
will be added
to all supported objects on this game object. My collection group name
will be added
to all supported objects on this game object and all its children.¶
Property |
Description |
Default |
---|---|---|
Propagate To Children |
Toggle to share this group name with all children. |
false |
Tag |
Group tag/name. |
Note
Since AGX Dynamics supports groups for rigid bodies it’s not necessary to check
Propagate To Children
for the rigid body groups to affect its shapes.
2.2.12. Articulated Root¶
The Articulated Root component manages transform updates of Rigid Body instances when rigid bodies has other rigid bodies as parents. Any child Rigid Body of this component (in Hierarchy) will have its automatic transform updates disabled.
This component is suitable when, e.g., modeling of a robot, where the base may be considered root and fingers/tool the leafs. The rigid bodies affected by this component are collected using GetComponentsInChildren<AGXUnity.RigidBody>().

Hierarchy of robot where all objects within the green rectangle are Rigid Body instances constrained to each other with hinge or prismatic joints.¶

Articulated Root Inspector where AR_Robot
contains the Articulated Root
component.¶
Tip
Articulated Robot example.
2.2.13. Rigid Body Emitter¶
The Rigid Body Emitter component is an emitter that emits Rigid Body instances given a set of prefab templates. A template is spawned inside a given shape sensor with a configurable distribution.

Rigid Body Emitter Inspector when the component has been added to a game object with a shape Cylinder.¶
If the Rigid Body Emitter component is added to a game object containing a shape, the
Emitter Shape
property is initialized with that shape. The Emitter Shape
property is required to be assigned but the Rigid Body Emitter doesn’t require a shape
component on its game object when the Emitter Shape
may be assigned manually.
Property |
Description |
Default |
---|---|---|
Emitting Quantity |
Unit quantity of given Emit Rate. The quantity can be: Count (default) - the number of instances created per second. Volume - the maximum volume emitted per second. Mass - the maximum mass emitted per second. |
Count |
Maximum Quantity |
The maximum quantity to emit. |
Infinity |
Emit Rate |
Quantity number (Emitting Quantity) per second. |
100 |
Initial Velocity |
Reference initial velocity of an emitted body, given in the frame of the Emitter Shape. This velocity is slightly randomized when a body is emitted. |
(0, 0, 0) |
Random Seed |
Random seed used when emitting bodies which are randomly positioned within the emitter shape and receives some randomized velocity with respect to the given initial velocity. The seed is randomized during component Reset (i.e., when the component is added to a game object or when Reset is pressed from the component context menu). |
Random during Reset |
Emitter Shape |
Sensor shape the bodies should be emitted from within. |
null |
Probability Quantity |
The probability quantity of the templates probability weights. |
Count |
Templates |
List of added template prefabs. The Probability Weight of a template is revealed when the list is expanded. See figure below. |
Empty |

A template prefab expanded in the Inspector has an extra property - Probability Weight. The Probability Weight is controlling how likely it is that this specific template is spawned.¶
2.2.13.1. Emitter Templates¶
An emitter template is a rigid body prefab of any shape and/or visual structure as children. The name of the template has to be unique to the Rigid Body Emitter because AGX Dynamics is emitting bodies with a callback and the name of the emitted body is mapped to the prefab resource in Unity.
To add the template to the emitter, drag and drop the prefab from the project view to the Add item
area or click the context icon on the right for a list of valid prefabs that
can be added.

Note
The context icon marked in the image above is only searching for supported prefabs in folders with
a Resources
folder as a parent. E.g., Assets/Resources/MyTemplates/thisTemplate.asset
will show up there. Still, it’s not required for a template to be located in a resources folder.
2.2.13.2. Sink¶
A rigid body emitter sink is a shape where given, or all, emitted instances from one or many Rigid Body Emitter disappears when in contact with the shape. As soon as the contact between a sink shape and an emitted rigid body is registered, the rigid body is removed from the simulation and its visual representation is destroyed.

Default Rigid Body Emitter Sink Inspector when added to a game object with a shape (Plane). Any shape type is supported to be a sink.¶
Property |
Description |
Default |
---|---|---|
Shape |
The sink shape instance. |
null |
Sink All |
Sink all emitted rigid bodies, independent of template or Rigid Body Emitter instance. |
true |
Sink Templates |
Visible in the Inspector when Sink All is false. List of Emitter Templates this sink should destroy. The template rigid body may be part of any Rigid Body Emitter. |
empty |
Example showing Sink All and the granularity of using Sink Templates in different sinks.
2.3. Managers¶
2.3.1. Simulation (Manager)¶
The Simulation is the fundamental single instance scene object of AGX Dynamics for Unity. Simulation owns almost all AGX Dynamics for Unity instances in a scene.
Empty scene vs. scene with an AGX Dynamics for Unity instance vs. explicitly added Simulation (disabling gravity).
To add Simulation to a scene, click AGXUnity -> Simulation
from the
main menu.

Simulation Inspector with default values and various features to dump the simulation to AGX Dynamics native formats.¶
Property |
Description |
Default |
---|---|---|
Auto Stepping Mode |
Simulation Stepping Mode: Fixed Update, Update or Disabled |
Fixed Update |
Time Step |
Simulation time step size. |
0.02 (Unity) |
Fixed Update Real Time Factor |
When Auto Stepping Mode is Fixed Update and Maximum Allowed Timestep > Fixed Timestep in the project settings, this factor can be used to skip simulation updates when Unity is catching up on lost time. If 0.0 (disabled), the simulation time will match Unity fixedTime. If 0.333, three times (1.0/0.333) Fixed Timestep may be spent in stepping the simulation before additional simulation steps are skipped. See recommended settings in Stepping Mode. |
0.0 (disabled) |
Gravity |
Gravity acceleration in the simulation. |
(0, -9.82, 0) |
Solver Settings |
Solver Settings of the simulation. |
null |
Enable Merge Split Handler |
false |
|
Display Statistics |
Toggle simulation statistics, rendered in Game View. |
false |
Save current step as (.agx) |
Save current simulation state to a file. |
|
Dump initial (.agx) |
Save initial state of the simulation to a file. |
2.3.1.1. Stepping Mode¶
By default, the simulation is stepped in the Unity FixedUpdate
callback with
the Fixed Timestep
time step size given in the Unity Time Manager
in Project Settings.
For computationally intensive simulations, or when many objects suddenly interact,
the simulation time could exceed the Fixed Timestep
time and since wall time is lost,
Unity fires FixedUpdate
again until the wall time is recovered or maximum for 0.333
seconds.
The recommended settings are:
Property |
Value |
---|---|
Auto Stepping Mode (AGXUnity.Simulation) |
Fixed Update (default) |
Fixed Timestep (Project Settings) |
Anything <= 0.02 seconds |
Maximum Allowed Timestep (Project Settings) |
Same as Fixed Timestep |
Manual stepping
It’s possible to drive the simulation from a separate script by disabling auto-stepping and
call AGXUnity.Simulation.Instance.DoStep()
. The following example is performing
(by default) 10 sub-steps of the simulation each FixedUpdate
.
using UnityEngine;
public class ManualStepping : MonoBehaviour
{
public int NumSubSteps = 10;
private void Start()
{
AGXUnity.Simulation.Instance.AutoSteppingMode = AGXUnity.Simulation.AutoSteppingModes.Disabled;
}
private void FixedUpdate()
{
AGXUnity.Simulation.Instance.TimeStep = Time.fixedDeltaTime / System.Math.Max( NumSubSteps, 1 );
for ( int i = 0; i < System.Math.Max( NumSubSteps, 0 ); ++i )
AGXUnity.Simulation.Instance.DoStep();
}
}
2.3.2. Contact Material Manager¶
The Contact Material Manager is an optional singleton instance in a scene. When this manager is active, the list of Contact Materials are active and enabled.
Add Contact Material Manager to current scene by clicking
AGXUnity -> Managers -> Contact Material Manager
from the main menu.
Defining Shape Material for Sphere and Ground. Contact Material and Friction Model for Sphere vs. Ground are created. The changes doesn’t have any effect until the Contact Material is added to the Contact Material Manager.
2.3.3. Collision Groups Manager¶
The Collision Groups Manager is an optional singleton instance in a scene. When the manager is active, the list of collision group pairs will be disabled for collisions.

Add Collision Groups Manager to current scene by clicking AGXUnity -> Managers -> Collision Groups Manager
from the main menu.¶
To disable a pair use the Add pair panel where the groups may either be input as free text
or use the context menu for a list of all current Collision groups
in the current scene.

Add new disabled pair by typing the group name or click for a
list of all current Collision groups in the scene.¶
2.3.4. Wind And Water Manager¶
The Wind And Water Manager is a single instance object that has to be added to the scene
to enable hydro- and/or aerodynamics. To add the Wind And Water Manager to a scene click
AGXUnity -> Managers -> Wind and Water Manager
from the main menu.

Wind And Water Manager Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Water |
Water game object with one or several sensor shapes as children. |
null |
Water Velocity |
Velocity/Current in the water. |
(0, 0, 0) |
Wind Velocity |
Velocity/Wind for objects with aerodynamics enabled. |
(0, 0, 0) |
Note
Make sure each shape representing water has the Is Sensor
toggle set (to true/enabled).
Note
Disable hydrodynamics for certain shapes by disabling collisions between the objects and the water shape(s).
WaterShape
is a regular box and transforms into a water volume by enabling Is Sensor
and registering the instance to the Wind And Water Manager.
2.3.5. License Manager¶
The License Manager manages any AGX Dynamics for Unity license in Unity projects and builds.
The License Manager Window is opened from the main menu AGXUnity -> License -> License Manager
.

Default License Manager Window without any supported AGX Dynamics for Unity license files in the project. It’s possible to Activate a license, Refresh a license, Deactivate a license, inspect license data and copy an already existing license file to the current project.¶
While in the Unity editor, the Licence Manager searches for *.lfx
files from the project root
directory. For example, if the project directory name is MyProject
and AGX Dynamics for Unity is located at
MyProject/Assets/AGXUnity
, it’s valid to place the license file anywhere where MyProject
is root, e.g., MyProject/AGX License/agx.lfx
or MyProject/Assets/EditorStuff/agx.lfx
.
In a build, the search is similar to while in the editor, but the root directory is the build directory,
where the main executable is located. If no valid *.lfx
file is found, a similar search is made
for a Encrypted runtime license activation *.rtlfx
file.
Note
Legacy license files, normally named agx.lic
, are searched for similar to *.lfx
as a fallback when no *.lfx
file is found. Previously to 3.0.0 (2021-07-01), the filename
was constrained to be agx.lic
and located in pre-defined directories, but may from
3.0.0 (2021-07-01) be named *.lic
and located in any directory under the Unity project
or build directory root.
2.3.5.1. Activate a license¶
A license is activated using a License Id and Activation Code and results in a
file (e.g., agx.lfx
) that unlocks AGX Dynamics for the computer/hardware where
the activation took place. The license file may be copied and used in unlimited projects
and builds on the computer it was activated on, but the number of activations is limited
to something small, e.g., two where a developer has a stationary workstation and a laptop.
To activate a license using the License Manager Window, write your License Id and Activation Code into their respective text fields, select a target License File Directory where the generated license should be created, and click Activate. If the activation is successful, a license info section should appear with the generated license information, otherwise check the Unity Console for any warnings or errors.
To activate a license in a script:
// Check for already created, valid, .lfx and .lic files.
if ( !AGXUnity.LicenseManager.LoadFile() ) {
// License hasn't been activated, activate the license and place
// the generated agx.lfx in the 'dataPath' directory.
var success = AGXUnity.LicenseManager.Activate( 123456,
"FOOBAR123",
Application.dataPath );
// Unsuccessful, print status to the Console.
if ( !success )
Debug.Log( "Activation failed with status: " +
AGXUnity.LicenseManager.LicenseInfo.Status );
}
The Licence Id and Activation Code is a document of value - avoid using the License Id and Activation Code in scripts. See Encrypted runtime license activation for more information how to activate runtime licenses.
2.3.5.2. Refresh a license¶
The license will occasionally automatically refresh itself with any updated information from the server. It’s possible to explicitly refresh a license by clicking 1) (figure below) of the license in the License Manager Window. Refreshed license information could be new expired date, enabled modules, etc.

License Manager Window with one loaded, valid license. 1) Update license information/Refresh license from the license server. 2) Deactivate the license and delete the file, for the license activation to become available to activate on another device. 1) and 2) requires internet connection.¶
2.3.5.3. Deactivate a license¶
A deactivated license may be activated again, e.g., on another computer. The license file of a deactivated license is not possible to use, so it’s safe to delete the file after it has been deactivated.
To deactivate and delete a license from the License Manager Windows, click 2) of the license to deactivate and delete.
Deactivate a license and delete the file in a script:
using AGXUnity;
...
var file = LicenseManager.FindLicenseFiles( LicenseInfo.LicenseType.Service ).FirstOrDefault();
if ( !LicenseManager.DeactivateAndDelete( file ) )
Debug.LogError( "Deactivate and delete failed: " + LicenseManager.LicenseInfo.Status );
2.3.5.4. Encrypted runtime license activation¶
The License Id and Activation Code of the runtime license can be encrypted with the final build.
The agx.rtlfx
file containing the required data can be generated by opening the Runtime
Activation Generator window from the main menu: AGXUnity -> License -> Runtime Activation Generator
.
This window is also opened automatically after a successful build with some of the required fields
filled out.
Note
The license information (id and activation code) isn’t tested to be valid against the server.

Runtime Activation Generator window with required fields.¶
The Reference File is a static file that is unique to your application and is used to encrypt and later decrypt the activation information. If the contents of the Reference File has been changed, the encrypted runtime license has to be re-generated.
The generated agx.rtlfx
is placed in <build_directory>/<name>_Data/Plugins/x86_64/agx.rtlfx
and will be replaced by a hardware locked agx.lfx
file in the same directory after a successful
license activation, the first time the application is started. This means that the default behavior is
to activate the license for the machine the application is started on, so if the application is tested
before being packaged, it’s important that the activated agx.lfx
file is replaced by a backed up
version of the agx.rtlfx
.
It’s also possible to take the contents from the .rtlfx
file and manually activating it in a script.
using System.Linq;
using UnityEngine;
using AGXUnity;
namespace Scripts
{
public static class RuntimeLicenseHandler
{
[RuntimeInitializeOnLoadMethod]
public static bool ActivateUnlock()
{
#if AGXUNITY_UPDATING
// Avoiding calls to AGX Dynamics during updates.
return false;
#else
// Check if there's already an activated and valid license.
var hasLoadedValidLicense = LicenseManager.LicenseInfo.IsParsed &&
LicenseManager.LicenseInfo.IsValid;
if ( hasLoadedValidLicense )
return true;
// Check if there's an existing license and try to load it if it exist.
// If a license file exist we're not performing activation since the
// current license could have expired or something else is wrong with it.
// Another choice could be to delete the invalid license and try to
// activate it again.
var existingLicenseFile = LicenseManager.FindLicenseFiles().FirstOrDefault();
if ( !string.IsNullOrEmpty( existingLicenseFile ) ) {
// The license manager will log any status or errors.
return LicenseManager.LoadFile( existingLicenseFile );
}
Debug.Log( "Activating AGX Dynamics for Unity license: " + s_activationContent );
var licenseExt = LicenseManager.GetLicenseExtension( LicenseInfo.LicenseType.Service );
var activatedLicenseDirectory = Application.dataPath;
var activatedLicenseFilename = activatedLicenseDirectory + "/agx" + licenseExt;
try {
// Note that we're explicitly calling AGX Dynamics but some components here
// in Unity relies on the AGXUnity.LicenseManager, so if successful, we
// have to call UpdateLicenseInformation() on the license manager.
var success = agx.Runtime.instance().activateEncryptedRuntime( s_activationContent,
activatedLicenseFilename );
if ( success ) {
Debug.Log( "Successfully activated license: " + activatedLicenseFilename );
// Make sure AGXUnity.LicenseManager.LicenseInfo is updated with our
// newly activated license.
AGXUnity.LicenseManager.UpdateLicenseInformation();
}
else
Debug.LogError( "Failed to activate license: " + agx.Runtime.instance().getStatus() );
return success;
}
catch ( System.Exception e ) {
Debug.LogException( e );
return false;
}
#endif
}
private static readonly string s_activationContent = @"RT=XPbueSzfBeG3K2MlxBpf" +
@"EOfkWfqhEbM3qlIYWVw73I1" +
@"Vbml0eVBsYAllci5kbGwAcb" +
@"DONQhHsf7VoSyLYhfMGA==";
}
}
2.3.6. Update Handler¶
Update Handler is a generic name of a self contained, editor only assembly, located in the
AGXUnity/AGXUnityUpdateHandler
directory, introduced in version 2.4.3 (2021-06-17).
The aim of this manager is to handle and resolve issues during imports/updates of
AGX Dynamics for Unity packages.
During an update to a new version, AGX Dynamics for Unity is deleting all scripts and assets under its
root directory, normally Assets/AGXUnity
, before importing the new version. This works
great in Unity versions 2019.3 and earlier but may result in various issues in Unity 2019.4
and newer. The source of the issues are unknown but the resulting errors are solely isolated
to AGX Dynamics for Unity, meaning it’s always possible close Unity, delete the AGXUnity
directory,
start Unity and import the new version - which is not a viable solution. This Update Handler
is trying to resolve the issues before manual delete and import is necessary.
2.3.6.1. Update from 2.4.2 and earlier to 2.4.3 and later¶
Given you’re a current user with AGX Dynamics for Unity version 2.4.2 (2021-06-03) or earlier, and desire to update to version 2.4.3 (2021-06-17) or later, please follow these steps:
Download the
AGXUnityUpdateHandler
package.Import the package into the project in which you desire to update AGX Dynamics for Unity.
Update AGX Dynamics for Unity following the steps described in Updating the plugin.
2.3.6.2. Manual recovery from errors after update¶
If update has been made in a Unity version 2019.4 or newer without this Update Handler, it’s possible to perform the steps manually.
Right click the
AGXUnity
directory in Project View and selectReimport
.If
Reimport
isn’t enough (Unity version 2020.1 or newer), add anyDefine Symbol
underEdit -> Project Settings... -> Player -> Scripting Define Symbols
and clickApply
to trigger a project wide compilation. The define symbol may be removed later on.
2.4. Assets¶
2.4.1. Shape Material¶
The Shape Material asset mainly used to define how two objects interact through a Contact Material which contains the parameters. Shape Material only has a few parameters which are used independent of Contact Material.
To create a new Shape Material, right click the project view and click AGXUnity -> Shape Material
.

Shape Material Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Density |
Density of an object with this material - affects the total mass of the object. |
1000 |
Youngs Wire Stretch |
Young’s modulus stretch of Wire instances with this material. |
1.0E10 |
Youngs Wire Bend |
Young’s modulus bend of Wire instances with this material. |
1.0E9 |
Density affects:
The total mass of Rigid Bodies but only Shapes can have Shape Materials. The value of the density is ignored when the rigid body has an explicit mass/inertia.
The total mass of Wires.
The total mass of Cables.
The total mass of Tracks.
2.4.2. Contact Material¶
The Contact Material asset is an essential piece for computational performance, accuracy and stability of objects in contact. A Contact Material defines how two interacting Shape Materials behaves.
To create a new Contact Material, right click the project view and click AGXUnity -> Contact Material
.

Contact Material Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Material 1 |
First Shape Material - may be the same as Material 2 but invalid if null. |
null |
Material 1 |
Second Shape Material - may be the same as Material 1 but invalid if null. |
null |
Friction Model |
Friction Model of the contact material - Default Friction Model if null. |
null |
Youngs Modulus |
Elasticity of the two interacting Shape Materials. |
4.0E8 |
Friction Coefficient |
Primary direction and secondary direction friction coefficients. |
(0.417, 0.417) |
Restitution |
Restitution when the Shape Materials are impacting. |
0.5 |
Damping |
Spook damping of the interacting Shape Materials. |
0.075 |
Adhesive Force |
Cohesion of the interacting Shape Materials. |
0 |
Adhesive Overlap |
Target overlap is by default 0, Adhesive Overlap enables x distance overlap to occur before the normal forces turns positive. This could be used to stabilize contacts or should be > 0 when Adhesive Force > 0. |
0 |
Use Contact Area |
Toggle calculation of the contact area between to interacting Shape Materials. Enabling this feature will make Youngs Modulus more accurate and the interactions more stable. |
false |
Contact Reduction Mode |
Contact reduction mode: None, Geometry (geometry vs. geometry) or All (rigid body vs. rigid body). |
None (no contact reduction) |
Contact Reduction Level |
Contact reduction Level: Minimal, Moderate or Aggressive. |
Moderate |
When a Contact Material asset has been created and configured it doesn’t affect simulations until the Contact Material has been registered to the Contact Material Manager in a scene.
2.4.3. Friction Model¶
The Friction Model asset defines how frictional contacts are solved. A Friction Model asset can be assigned to one or several Contact Materials.
To create a new Friction Model, right click the project view and click AGXUnity -> Friction Model
.

Friction Model Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Solve Type |
Frictional contact solve type: Direct, Iterative, Split or Direct And Iterative. |
Split |
Type |
Frictional contact algorithm type: Iterative Projected Friction, Scale Box Friction, Box Friction or Constant Normal Force Box Friction. |
Iterative Projected Cone Friction |
Box Friction is linear while Scale Box Friction is non-linear, meaning Box Friction is guessing the maximum friction forces, because the normal forces are unknown, while Scale Box Friction solves the system over and over again, adjusting the maximum friction forces given the current normal forces and friction coefficients.
Iterative Projected Friction is recovering the friction cone for any given solve type. This friction model is best suitable for grasping contacts and for anisotropic materials, where the primary and secondary friction coefficients aren’t equal.
Solve type Direct will feed the frictional contact to the direct solver, with accurate result but is likely to be more computationally expensive. Solve type Iterative will feed the frictional contact to the iterative solver, with far less accurate result but is far less computationally expensive. Solve type Split will warm start the iterative solver with normal forces calculated in the direct solver. Solve type Direct And Iterative solves the normal forces in the direct solver, estimates the frictional maximum force in the iterative solver (non-linear part solved in the iterative solver) and the maximum frictional force is fed to the direct solver.
2.4.3.1. Default Friction Model¶
The default friction model is Solve Type: Split and Type: Iterative Projected Friction.
2.4.4. Solver Settings¶
The Solver Settings asset containing AGX Dynamics solver and threading related settings. This asset can be added to the Simulation (Manager) in a scene.
To create a new Solver Settings asset, right click the project view and click AGXUnity -> Solver Settings
.

Solver Settings Inspector with default values.¶
Property |
Description |
Default |
---|---|---|
Number Of Threads |
Number of threads available for AGX Dynamics. The initial value is calculated given the number of logical CPU cores divided by two minus one, but max four. |
|
Warm Start Direct Contacts |
Toggle warm start of frictional contacts solved with the direct solver. |
false |
Resting Iterations |
Number of iterations in the iterative solver. |
16 |
Dry Friction Iterations |
Friction refinement iterations during couplings of direct and iterative systems. |
7 |
Mcp Algorithm |
Mixed Complementarity Problem Algorithm used by the direct solver: Hybrid Pivot, Keller or Block Pivot. |
Hybrid Pivot |
Mcp Inner Iterations |
Maximum number of iterations (in the direct solver) to reach inner tolerance. |
7 |
Mcp Inner Tolerance |
Maximum tolerated residual of the solution. |
1.0E-6 |
Mcp Outer Tolerance |
Maximum number of non-linear iterations (in the direct solver) to reach outer tolerance. |
5 |
Mcp Outer Tolerance |
Maximum tolerated non-linear residual of the solution. |
1.0E-2 |
PPGS Resting Iterations |
Resting iterations for the Parallel Projected Gauss Seidel (PPGS) solver used in, e.g., Deformable Terrain. |
25 |
Note
It’s normally not necessary to change these values.
2.4.5. Cable Properties¶
The Cable Properties asset contains properties that controls the material properties of one or several cable instances. See AGX Dynamics Cable Properties documentation for more information regarding the cable properties.
Note
Plasticity
Yield Point
is included in and the unused parameter Poisson's Ratio
is excluded
from AGXUnity.CableProperties
.
2.4.6. Deformable Terrain Material¶
Deformable Terrain Material properties related to Deformable Terrain instances. To create
a new Deformable Terrain Material asset, right click the project view and click
AGXUnity -> Deformable Terrain Material
.

Deformable Terrain Material Inspector with default values.¶
2.4.6.1. Material Library¶
Starting from 2.1.0 (2020-06-26), AGX Dynamics for Unity and AGX Dynamics supports terrain material libraries where the
material parameters are defined in json files. The files are located in AGXUnity/Plugins/x86_64/agx/data/TerrainMaterials
and available materials are listed under Preset
in the Inspector GUI.

Project view of the location of the deformable terrain material library.¶

Inspector of available terrain materials.¶
To add a new material to the library, create a new file in the TerrainMaterials
directory, e.g.,
my_soil_material.json
:
{
"BulkProperties" : {
"cohesion" : 12000.0,
"density" : 1300.0,
"dilatancyAngle" : 0.2268928027592629,
"frictionAngle" : 0.7504915783575616,
"maximumDensity" : 2000.0,
"poissonsRatio" : 0.150,
"swellFactor" : 1.280,
"youngsModulus" : 5000000.0
},
"CompactionProperties" : {
"angleOfReposeCompactionRate" : 24.0,
"bankStatePhi" : 0.6666666666666666,
"compactionTimeRelaxationConstant" : 0.050,
"compressionIndex" : 0.110,
"hardeningConstantKE" : 1.0,
"hardeningConstantNE" : 0.08333333333333333,
"preconsolidationStress" : 98000.0,
"stressCutOffFraction" : 0.010
},
"ExcavationContactProperties" : {
"aggregateStiffnessMultiplier" : 0.050,
"depthDecayFactor" : 2.0,
"depthIncreaseFactor" : 1.0,
"excavationStiffnessMultiplier" : 1.0,
"maximumAggregateNormalForce" : "inf",
"maximumContactDepth" : 1.0
},
"ParticleProperties" : {
"adhesionOverlapFactor" : 0.050,
"particleCohesion" : 200.0,
"particleFriction" : 0.40,
"particleRestitution" : 0.0,
"particleRollingResistance" : 0.10,
"particleTerrainCohesion" : 200.0,
"particleTerrainFriction" : 0.70,
"particleTerrainRestitution" : 0.0,
"particleTerrainRollingResistance" : 0.70,
"particleTerrainYoungsModulus" : 100000000.0,
"particleYoungsModulus" : 10000000.0
},
"description" : "This material specification is named my_soil_material."
}
Change Preset
in the Deformable Terrain instance(s) that should use the new material.

New terrain materials appears in the Deformable Terrain Material Inspector under Preset
.¶
2.4.7. Deformable Terrain Properties¶
Properties related to Deformable Terrain instances. To create a new Deformable Terrain
Properties asset, right click the project view and click AGXUnity -> Deformable Terrain Properties
.

Deformable Terrain Properties Inspector with default values.¶
2.4.8. Deformable Terrain Shovel Settings¶
Settings related to Deformable Terrain Shovel instances. To create
a new Deformable Terrain Shovel Settings asset, right click the project view and click
AGXUnity -> Deformable Terrain Shovel Settings
.

Deformable Terrain Shovel Settings Inspector with default values.¶
2.4.9. Track Properties¶
Properties related to Track instances. To create a new Track Properties asset, right
click the project view and click AGXUnity -> Track Properties
.

Track Properties Inspector with default values.¶
See Track Properties documentation for detailed information about each property.
2.4.10. Track Internal Merge Properties¶
Internal merge properties related to Track. To create a new Track Internal Merge Properties
asset, right click the project view and click AGXUnity -> Track Internal Merge Properties
.

Track Internal Merge Properties Inspector with default values.¶
These properties controls if and how the track instance merge neighboring nodes for increased
computational performance. Merged nodes split when in contact with Sprocket
or Idler
,
or with another Track Wheel type with Split Segments
property enabled.
2.4.11. Geometry Contact Merge Split Thresholds¶
Contact thresholds related to Merge Split Properties. To create a new Geometry Contact
Merge Split Thresholds asset, right click the project view and click
AGXUnity -> Geometry Contact Merge Split Thresholds
.

Geometry Contact Merge Split Thresholds Inspector with default values.¶
2.4.12. Constraint Merge Split Thresholds¶
Constraint thresholds related to Merge Split Properties. To create a new Constraint Merge
Split Thresholds asset, right click the project view and click
AGXUnity -> Constraint Merge Split Properties
.

Constraint Merge Split Thresholds Inspector with default values.¶
2.5. Tools¶
2.5.1.
Create constraint tool¶
Tool to create and configure a new constraint.

Create constraint Inspector dropdown tool.¶
Verify/select name.
Choose constraint type.
Configure reference frame.
Select parent of connected frame.
Select disabled collisions state - default is disabled.
Press Create to create the constraint - Cancel to discard any changes.
2.5.2.
Shape resize tool¶
Tool to change size of supported primitive shapes using arrow handles in Scene View. Supported shapes are:
The arrow handles are activated when this tool is active and when dragging any arrow in the
Scene View the shape is expanded in the direction of the mouse drag. For symmetric
resizing hold Left Shift
.
Symmetric Left Shift
and asymmetric resize of primitive shapes that supports
the shape resize tool.
Note
Previous to version 3.1.0 (2021-10-18), Left Ctrl
had to be held down for
the resize handles to appear, and Left Ctrl + Shift
for symmetric resizing.
2.5.3.
Shape given visual tool¶
Note
This tool is experimental and will be improved and documented in a later version.
Create additional shapes as children to this object given visual representations. Select child visual in Scene View and follow instructions in the Inspector.
2.5.4.
Create visual tool¶
Tool to create visual representation of a shape or several shapes, depending on context. When this tool is activated for a Rigid Body a list of all shapes that doesn’t already have a visual representation is shown. When this tool is activated for a Shapes instance, the tool will only affect that instance - independent of any further shape children to that shape.
All shapes are children to the rigid body. 1. Sphere visual is created using this tool with the sphere shape as context. 2. All the other shapes visuals is created using this tool with the rigid body as context. Note that the sphere doesn’t appear in the list when it already has visual representation. 3. Create a new material for the box and change color to red.
Note
AGX Dynamics for Unity has its own visual component to mark shapes with already created visuals.
This means that this tool will still try to create visual representations for objects
that already has a UnityEngine.MeshFilter
.
2.5.5.
Disable collisions tool¶
Simple utility tool that adds unique group names to objects and then adds the group pair to Collision Groups Manager.
Disabling collisions between the rigid body box and other objects by selecting objects in Scene View.
2.5.6.
Select parent tool¶
Tool to select/change a parent in a frame, by selecting an object in Scene View.
Configuring a hinge by choosing reference frame parent and alternating the connected frame parent between the box and the cylinder.
2.5.7.
Find edge tool¶
Finds a parent object and relative transform given a triangle edge and a direction. This tool is convenient for initializing frames in constraints, tire/wheel, cable and wire routs.
This tool contains four stages:
Select parent tool to find the parent to the frame.
Select edge.
Select point on the selected edge. Note that the point snaps to begin, middle and end of the edge. For free move hold
Ctrl
.Select z direction of the final transform.
Creating two hinges, one on each side of the frame, using the Find edge tool.
2.5.8.
Find point tool¶
Find a parent object and relative transform given an object surface position and a direction. This tool is convenient for initializing frames in constraints, tire/wheel, cable and wire routes.
Configuring a hinge using the Find point tool.
2.6. File Import/Export¶
Unity supports import of several 3D formats (.fbx
, .dae
, .3ds
, .dxf
,
.obj
, .skp
). AGX Dynamics for Unity supports additional imports, both pure mesh data (.stl
)
and physics decorated (.agx
, .aagx
, .urdf
).
2.6.1. URDF Import¶
AGX Dynamics for Unity supports reading Unified Robot Description Format (URDF) files
into an easily queryable structure (AGXUnity.IO.URDF.Model
) which contains all the data.
There are many options what to do with the model data - it can for example be instantiated in a scene with AGX Dynamics for Unity physics components and game objects.
Note
If the collision shape is an imported model, such as .fbx
or .dae
, make sure the
collision data is accessible for the collision mesh to be created,
before the URDF model is imported.
Below is an example of a link and a joint from ABB IRB 5400
where link_3
and joint3
are expanded in the model tree with their corresponding
AGXUnity.RigidBody
and AGXUnity.Constraint
.
<link name="link_3">
<visual>
<geometry>
<mesh filename="package://abb_irb5400_support/meshes/irb5400/visual/link_3.dae"/>
</geometry>
<material name="">
<color rgba="0.7372549 0.3490196 0.1607843 1"/>
</material>
</visual>
<collision>
<geometry>
<mesh filename="package://abb_irb5400_support/meshes/irb5400/collision/link_3.stl"/>
</geometry>
<material name="">
<color rgba="1 1 0 1"/>
</material>
</collision>
</link>


<joint name="joint3" type="revolute">
<parent link="link_2"/>
<child link="link_3"/>
<origin rpy="0 0 0" xyz="0 0 1.200"/>
<axis xyz="0 1 0"/>
<limit effort="100" lower="-1.308" upper="1.308" velocity="2.3911"/>
</joint>


Note that the link_3
element doesn’t include an <inertial>
definition so
the mass properties of link_3
is calculated given the shape defined under
<collision>
(with default density 1000 kg/m3).
All defined data for link
and link
is read and stored in an instantiated
model. When some data requires context, it’s possible to access the original data from
anywhere suitable. For example joint <limit ... velocity="2.3911" .../>
is, from
the specification, “An attribute for enforcing the maximum joint velocity.”. I.e., not the speed/velocity
to be assigned to the motor but rather a safety limit, defining the maximum velocity of the joint
(m/s for prismatic and rad/s for revolute/hinge). Below is an example script exemplifying how
to access the joint data and recover the joint <limit>
element from the file. The
script is attached to the game object containing the AGXUnity.Constraint
named joint3
.
using UnityEngine;
using AGXUnity;
using AGXUnity.IO.URDF;
namespace Scripts
{
public class UJointDataRead : ScriptComponent
{
protected override bool Initialize()
{
var jointData = GetComponent<ElementComponent>().Element as UJoint;
var limitData = jointData.Limit;
var maxVelocity = limitData.Velocity;
Debug.Log( name + ": Maximum velocity is " + maxVelocity + "." );
Debug.Log( "<limit effort=\"" + limitData.Effort + "\" " +
"lower=\"" + limitData.Lower + "\" " +
"upper=\"" + limitData.Upper + "\" " +
"velocity=\"" + limitData.Velocity + "\"/>" );
return true;
}
}
}

2.6.1.1. Reading an URDF model¶
Read a model given filename (including path) to an .urdf
file.
try {
var model = AGXUnity.IO.URDF.Model.Read( "Assets/URDF/my_robot.urdf" );
Debug.Log( "#links: " + model.Links.Length );
foreach ( var link in model.Links )
Debug.Log( " link: " + link.Name );
Debug.Log( "#joints: " + model.Joints.Length );
foreach ( var joint in model.Joints )
Debug.Log( " joint " + joint.Parent + " <-> " + joint.Child + ": " + joint.Name );
}
catch ( AGXUnity.UrdfIOException e ) {
Debug.LogException( e );
}
Any error found in the file during parse will throw an AGXUnity.UrdfIOException
stating
which line (in the URDF file) and what type of error occurred. If AGXUnity.IO.URDF.Model.Read
returns, the file is interpreted as valid and model
in the above example wont be null
.
To view the read data in the inspector - create a new game object, add the AGXUnity.IO.URDF.ElementComponent
to it and assign the model.
try {
var model = AGXUnity.IO.URDF.Model.Read( "Assets/URDF/my_robot.urdf" );
var go = new GameObject( model.name );
go.AddComponent<AGXUnity.IO.URDF.ElementComponent>().SetElement( model );
}
catch ( AGXUnity.UrdfIOException e ) {
Debug.LogException( e );
}

2.6.1.2. Instantiating an URDF model¶
There are several different scenarios where an URDF model can be instantiated in a scene. For example by selecting an URDF file in the Project tab, from an editor script or during runtime. Runtime instantiation is in general supported but it’s up to Unity and the user to manage any required resources. See URDF resources for further information.
Instantiate selected URDF file
Navigate to the URDF file in the project, right click and select AGXUnity -> Import -> Selected URDF [instance]
.
If the model requires external resources, such as visual/collision meshes or textures, the
AGXUnityEditor.IO.URDF.Reader.Instantiate
method (invoked from Selected URDF [instance]
)
will search the project directory hierarchy for matching directories. If exactly one match is found,
the model will be instantiated with the matching directory as package root. If zero or more than
one directory is found, a folder panel will show where the user manually must select the
package root directory.
Instantiate an URDF model from an editor script
If the model doesn’t require resources but you want undo/redo to work, hook on the onCreate
callback to register created instances.
try {
var undoId = Undo.GetCurrentGroup();
// Assuming "using AGXUnity.IO.URDF".
var instance = Model.ReadAndInstantiate( "Assets/URDF/my_robot.urdf",
null, // Resource loader
obj =>
Undo.RegisterCreatedObjectUndo( obj, "Created: " +
obj.name ) );
Undo.CollapseUndoOperations( undoId );
}
catch ( AGXUnity.UrdfIOException e ) {
Debug.LogException( e );
}
Reading and instantiating a model doesn’t require the Editor. The example above is exemplifying
how to support Editor specific undo/redo and is assuming that the model doesn’t requires any external
resources. External resources are in general different depending on if the resource is loaded from
within the Editor (UnityEditor.AssetDatabase
) or during runtime (UnityEngine.Resources
).
See URDF resources for further information.
2.6.1.3. URDF resources¶
URDF files either references external resources with relative path (with respect to the .urdf
file),
e.g, <mesh filename="../meshes/my_robot/visual/base.dae"/>
, or normally by using package://
,
e.g, <mesh filename="package://my_robot_model/meshes/my_robot/visual/base.dae"/>
, defining the resource
root directory. You either know the package root directory or you have to find it, and depending on in what context
the resource is loaded, the loading is different. During runtime the resource has to be found (and compatible
with Unity resources) in a Resources
directory hierarchy and in the Editor it’s either
AssetDatabase.LoadAssetAtPath<GameObject>
or manual handling if the format isn’t supported by Unity.
Instantiating a model will fail on any failed resource load.
Both AGXUnity.IO.URDF.Model
and AGXUnityEditor.IO.URDF.Reader
has a method CreateDefaultResourceLoader
taking dataDirectory
as argument, convenient when you know the package root directory and in which context
the model is instantiated (Editor vs runtime). The difference is that AGXUnity.IO.URDF.Model.CreateDefaultResourceLoader
takes an additional argument resourceLoad
which the AGXUnityEditor
version is implementing as:
return Model.CreateDefaultResourceLoader( dataDirectory,
( filename, type ) =>
AssetDatabase.LoadAssetAtPath<GameObject>( filename ) );
If the second argument is null
(the actual resource load call), the load of resources will default
to UnityEngine.Resources.Load<Object>( filename )
which requires filename
to be in the
Resources
directory hierarchy and supported by Unity, except for .stl
files which are handled
by the default resource loader.
Below is an example of a custom resource loader, assuming all resources referenced in the URDF file are STL files. The STL files are imported using STL Import which creates instances that has to be removed when the model has been instantiated.
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;
using AGXUnity.IO.URDF;
using AGXUnity.IO;
public static class IOUtils
{
// This example only support load/instantiate of STL resources.
public static Func<string,
Model.ResourceType,
Object> MyCustomResourceLoader( string dataDirectory = "",
Func<string,
Model.ResourceType,
Object> resourceLoad = null )
{
var loadedInstances = new List<GameObject>();
Func<string, Model.ResourceType, Object> resourceLoader = ( resourceFilename, type ) =>
{
// Final call to this resource loader. We'll receive this
// call even if the model contains errors. Destroy all
// created instances.
if ( type == Model.ResourceType.FinalizedLoad ) {
loadedInstances.ForEach( instance => Object.DestroyImmediate( instance ) );
loadedInstances = null;
return null;
}
// Remove "package://" and/or include given dataDirectory.
if ( resourceFilename.StartsWith( "package:/" ) )
resourceFilename = dataDirectory + resourceFilename.Substring( "package://".Length );
else if ( !string.IsNullOrEmpty( dataDirectory ) )
resourceFilename = dataDirectory + resourceFilename;
var isStlFile = Path.GetExtension( resourceFilename ).ToLower() == ".stl";
// STL file we instantiate it and delete them at FinalizeLoad.
if ( isStlFile ) {
var stlInstances = StlFileImporter.Instantiate( resourceFilename );
loadedInstances.AddRange( stlInstances );
return stlInstances.FirstOrDefault();
}
return null;
};
return resourceLoader;
}
}
2.6.1.4. Saving an URDF as prefab¶
URDF as assets and/or prefab was added in 3.1.0 (2021-10-18). It’s now possible to import an URDF model as
prefab by right clicking an URDF file in the project and navigate to AGXUnity -> Import -> Selected URDF [prefab]...
.
A folder panel will open for each selected, and successfully imported, model for the target directory of
the prefab and its assets.
Note
Re-import of a modified .urdf
file isn’t supported. A new prefab will be created with a
different name if the prefab already exist in the target directory.
An instantiated URDF model contains instances of AGXUnity.IO.URDF.Element
and may contain instances
of UnityEngine.Mesh
and UnityEngine.Material
. Unsaved mesh and material instances origins
from STL resources and URDF material declarations. If a game object of an URDF model is, e.g., drag-dropped
to the project to create a prefab, all the unsaved instances has to be saved as well before the prefab is
created. It’s not possible in Unity to know when a prefab is about to be created (e.g., when drag-dropped), so
saving the assets and/or prefab has to be done manually by clicking a button, using context menus or by
implementing a custom editor script.
Note
If all assets has been saved or already is on disk it’s possible to drag-drop the game object to create a prefab.
Game object context menu
Right click root game object in the Hierarchy where the root game object has at least one URDF model
in its children. In the context menu, navigate to AGXUnity -> Save -> URDF Model(s) as prefab...
or
AGXUnity -> Save -> URDF Model(s) assets...
. A folder panel will open to select which directory
the assets and prefab should be saved in the project.
All URDF model children of the selected game object will be exported to the given directory.
URDF model Inspector buttons
As for the context menu, there are two options in the Inspector of the model to save the data.

(1)
Save the URDF model assets and game object as prefab to a folder in the project.
(2)
Save the URDF model assets to a folder in the project. Both buttons will result
in a folder panel to open when pressed. (1)
is disabled when the model is a prefab
and (2)
is disabled when the assets has been saved.¶
Custom Editor script
The main features are implemented in the static editor class AGXUnityEditor.IO.URDF.Prefab
.
The following example is saving a selected URDF model game object in resources the
Assets/Resources/Robot
directory and the URDF model assets in the
Assets/URDF Assets
. Note that calling AGXUnityEditor.IO.URDF.Prefab.Create
will save
the prefab and its assets in the same folder. This example demonstrates how to separate the
assets from the prefab.
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEditor;
using AGXUnity.IO.URDF;
namespace Scripts.Editor
{
public static class SaveUrdfData
{
private static readonly string ModelAssetsPath = "Assets/URDF Assets/";
private static readonly string ModelPrefabPath = "Assets/Resources/Robots";
[MenuItem( "GameObject/My URDF/Save as prefab resource" )]
private static void SaveAsPrefab( MenuCommand command )
{
if ( command.context == null )
return;
// Create directories if at least one doesn't exist.
// It's important to save and refresh the assets
// database for Unity to be able to save assets there.
if ( !Directory.Exists( ModelAssetsPath ) ||
!Directory.Exists( ModelPrefabPath ) ) {
Directory.CreateDirectory( ModelAssetsPath );
Directory.CreateDirectory( ModelPrefabPath );
AssetDatabase.Refresh();
AssetDatabase.SaveAssets();
}
// Find our context from the current selection. If
// it's multi-select, SaveAsPrefab will be called
// for each selected object.
var selected = Selection.GetFiltered<GameObject>( SelectionMode.Editable |
SelectionMode.TopLevel )
.FirstOrDefault( go => go == command.context );
var isPrefab = selected != null &&
PrefabUtility.GetPrefabInstanceStatus( selected ) != PrefabInstanceStatus.NotAPrefab;
if ( selected == null ) {
Debug.LogError( "Unable to save URDF prefab - selected game object isn't editable.",
command.context );
return;
}
else if ( isPrefab ) {
Debug.LogError( "Unable to save URDF prefab - selected game object is already a " +
"prefab: " +
PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot( selected ) );
return;
}
var urdfModels = Utils.GetElementsInChildren<Model>( selected );
if ( urdfModels.Length == 0 ) {
Debug.LogError( "Unable to save URDF prefab - selected game object doesn't contain " +
"any URDF models." );
return;
}
foreach ( var urdfModel in urdfModels ) {
// Utility to find the game object the URDF model is located on.
var urdfModelGo = Utils.FindGameObjectWithElement( selected, urdfModel );
// Save the assets in our URDF Assets directory.
AGXUnityEditor.IO.URDF.Prefab.CreateAssets( urdfModel,
urdfModelGo,
ModelAssetsPath,
urdfModelGo.name );
// Save the prefab under resources.
AGXUnityEditor.IO.URDF.Prefab.Create( urdfModel,
urdfModelGo,
ModelPrefabPath );
}
}
}
}
2.6.2. STL Import¶
The STL file format contains raw, unstructured triangle mesh data, i.e., only three vertices per triangle and one normal. No color, texture or other attributes (not entirely true). The binary version of the format leaves only 16 bits for additional information (“Attribute byte count”), but there’s no standard way to interpret this data (to, e.g., color) so AGX Dynamics for Unity ignores these additional 16 bits.
The importer supports both binary and ASCII STL files and either returns meshes read or instantiates
game objects with UnityEngine.MeshFilter
and UnityEngine.MeshRenderer
components in
the current scene. In either case, the meshes are currently only stored in memory even though instances
will be saved in the scene file (when the scene is saved).
Note
To determine if a file is ASCII or binary is in general not possible. AGX Dynamics for Unity
checks the first 256 bytes of the file and if at least one of the bytes is a control character
that’s not \r || \n || \t
the file is interpreted as a binary file. This means that,
e.g, if the name of a solid in an ASCII file contains a control character, the file will be
parsed as a binary file. It’s hard to do it the other way around because there’s a good chance
you’ll stumble upon a binary STL file starting with the characters “solid”.
2.6.2.1. Normals of a STL file¶
Per-triangle normal isn’t suitable for visuals mesh data. That’s why UnityEngine.Mesh
is per-vertex
normal and AGX Dynamics for Unity STL importer is converting the STL normals to vertex normals with a smoothing angle
threshold - default 26 degrees. That means that when the angle between two triangle normals exceeds 26 degrees,
an average of the triangle normals will be used for the vertices involved.
Note
AGX Dynamics collision meshes recalculates the normals given vertices and triangle orientation so the smoothing angle threshold doesn’t affect the physics, meaning it’s possible, and suitable, to use the read meshes for both visual and collision meshes.
Below is an example of the default read STL mesh data (left) and the same mesh read with the default smoothing angle threshold (right).


2.6.2.2. Read a STL file¶
The AGX Dynamics for Unity STL reader StlFileImporter
is part of AGXUnity.IO
meaning it’s possible to read and
instantiate STL meshes at runtime. Since UnityEngine.Mesh
has a limit of 65535 vertices, the Read
methods returns an array of meshes rather than a single mesh.
Below is an example where a STL file is read and saved as an asset. If the STL file contains/is parse as several
meshes, the mesh data is stored in a single file but loaded as several UnityEngine.Mesh
instances.
public static Mesh[] SaveStlMeshesToAssets( string filename, string directory )
{
Mesh[] meshes = null;
try {
// Read meshes from given STL filename, e.g,
// "Assets/STL/my_stl_file.stl" and 'directory'
// is for example "Assets/STL_Exports".
meshes = AGXUnity.IO.StlFileImporter.Read( filename );
if ( meshes.Length == 0 )
throw new AGXUnity.Exception( "Unable to parse mesh(es) from: " + filename );
// Assuming 'directory' is relative to the project, i.e.,
// starts with "Assets".
directory = directory.Replace( '\\', '/' );
if ( !System.IO.Directory.Exists( directory ) ) {
System.IO.Directory.CreateDirectory( directory );
AssetDatabase.Refresh();
}
// Creating the main mesh asset. If there are more than
// one mesh this mesh will be main and the rest will be
// saved in the same file.
AssetDatabase.CreateAsset( meshes[ 0 ],
directory +
'/' +
System.IO.Path.GetFileName( filename ) +
".asset" );
AssetDatabase.SetMainObject( meshes[ 0 ], AssetDatabase.GetAssetPath( meshes[ 0 ] ) );
// We've already saved the first mesh, if there are more we
// add the additional meshes to our main mesh (same file,
// still individual meshes) - so for loop start from 1.
for ( int i = 1; i < meshes.Length; ++i ) {
if ( string.IsNullOrEmpty( meshes[ i ].name ) )
meshes[ i ].name = "{meshes[ 0 ].name} (" + i + ")";
AssetDatabase.AddObjectToAsset( meshes[ i ], meshes[ 0 ] );
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
catch ( AGXUnity.Exception e ) {
Debug.LogException( e );
}
return meshes;
}
2.6.2.3. Instantiate a STL file¶
Instantiating a STL file is similar to Read a STL file but the return value of AGXUnity.IO.StlFileImporter.Instantiate
is an array of game objects. An additional, optional, argument is a callback for each created UnityEngine.Object
to, e.g.,
manage undo/redo in the editor or to further decorate the instances.
Below is an editor script that manages undo/redo of a STL file instance.
public static GameObject[] InstatiateStlUndo( string filename )
{
var instances = new GameObject[] { };
// Increment undo group and store id so that we can collapse
// all changes into one undo/redo.
Undo.IncrementCurrentGroup();
var undoGroupId = Undo.GetCurrentGroup();
try {
// Callback from the STL Instantiate method for all
// UnityEngine.Object created.
System.Action<Object> onCreatedObject = createdObject =>
Undo.RegisterCreatedObjectUndo( createdObject,
"Created " +
createdObject.name );
// Instantiate given STL filename in the current scene.
instances = AGXUnity.IO.StlFileImporter.Instantiate( filename,
onCreatedObject );
}
catch ( AGXUnity.Exception e ) {
Debug.LogException( e );
}
finally {
// Collapse all registered undo from onCreatedObject so that
// the user doesn't have to press ctrl + z four times if one
// game object, one mesh filter, one mesh and one mesh renderer
// were created.
Undo.CollapseUndoOperations( undoGroupId );
}
return instances;
}
Two other editor examples that supports undo/redo but these creates an AGXUnity.RigidBody
with an
AGXUnity.Collide.Mesh
. The first example assumes the STL file is only a single mesh, while the second
doesn’t use AGXUnity.IO.StlFileImporter.Instantiate
(which creates one game object per created mesh)
and instead use AGXUnity.IO.StlFileImporter.Read
to get all meshes and instantiates one AGXUnity.RigidBody
with a child AGXUnity.Collide.Mesh
game object with all read meshes.
// Assumes 'filename' only contains one mesh, i.e., < 65535 vertices.
public static GameObject InstantiateSingleMeshRigidBodyStl( string filename )
{
GameObject rb = null;
// Handle undo/redo as in InstatiateStlUndo.
Undo.IncrementCurrentGroup();
var undoGroupId = Undo.GetCurrentGroup();
try {
System.Action<Object> onCreatedObject = createdObject =>
{
Undo.RegisterCreatedObjectUndo( createdObject, "Created " + createdObject.name );
// If this is the parent game object, add the RigidBody component.
if ( createdObject is GameObject go )
Undo.AddComponent<AGXUnity.RigidBody>( go );
// If this is the mesh filter, create an AGXUnity.Collide.Mesh.
else if ( createdObject is MeshFilter filter )
Undo.AddComponent<AGXUnity.Collide.Mesh>( filter.gameObject )
.SetSourceObject( filter.sharedMesh );
};
rb = AGXUnity.IO.StlFileImporter.Instantiate( filename,
onCreatedObject )[ 0 ];
}
catch ( AGXUnity.Exception e ) {
Debug.LogException( e );
}
finally {
Undo.CollapseUndoOperations( undoGroupId );
}
return rb;
}
// Instantiates a rigid body with child mesh. Assumes 'filename' is
// a single solid with any number of meshes.
public static GameObject InstantiateRigidBodyStl( string filename )
{
GameObject rb = null;
// Handle undo/redo as in InstatiateStlUndo.
Undo.IncrementCurrentGroup();
var undoGroupId = Undo.GetCurrentGroup();
try {
// Read the meshes and throw an error if was parsed.
var meshes = AGXUnity.IO.StlFileImporter.Read( filename );
if ( meshes.Length == 0 )
throw new AGXUnity.Exception( "Unable to parse mesh(es) from: " + filename );
// Create the game object of the rigid body and add the rigid body component.
rb = new GameObject( "RigidBody " + System.IO.Path.GetFileName( filename ) );
rb.AddComponent<AGXUnity.RigidBody>();
Undo.RegisterCreatedObjectUndo( rb, "Created " + rb.name );
// Create the child, note that this isn't completely necessary since
// the collision mesh component could be added to 'rb'. Still, it enables
// some further modeling capabilities.
var meshGo = new GameObject( System.IO.Path.GetFileName( filename ) );
meshGo.transform.parent = rb.transform;
// Create the collision mesh which supports several source meshes.
var collisionMesh = meshGo.AddComponent<AGXUnity.Collide.Mesh>();
foreach ( var mesh in meshes )
collisionMesh.AddSourceObject( mesh );
// Create visual in any way, this is one option.
AGXUnity.Rendering.ShapeVisual.Create( collisionMesh );
Undo.RegisterCompleteObjectUndo( meshGo, "Created " + meshGo.name );
}
catch ( AGXUnity.Exception e ) {
Debug.LogException( e );
}
finally {
Undo.CollapseUndoOperations( undoGroupId );
}
return rb;
}
2.6.2.4. STL ASCII file extensions¶
It’s not very well documented but an ASCII STL export from Ansys SpaceClaim
may contain several solid
endsolid
and the vertex unit baked into the solid’s name.
Note
Binary STL file doesn’t have name nor a definition of several solids in the definition of the format.
AGX Dynamics for Unity supports several definitions of solid
endsolid
in an ASCII file. AGX Dynamics for Unity also
supports vertex units if given in the name of a solid, e.g., solid "MySolid <stl unit = MM>
, where
<stl unit = MM>
is interpreted as millimeters and each vertex will be scaled by 0.001 (to meters). Supported
units are (case independent) M
(meters, scale 1.0, default), DM
(decimeters, scale 0.1),
CM
(centimeters, scale 0.01) and MM
(millimeters, scale 0.001).
2.6.3. AGX Dynamics Import¶
A serialized AGX Dynamics state can be loaded into Unity as a prefab. The importer supports incremental changes, making it possible to re-import the simulation state with arbitrary changes. The changes are propagated to all connected prefab instances.
The main purpose of this feature is to bring AGX Dynamics decorated CAD models into Unity. There are no dependencies.
The importer reads any .agx
(or .aagx
), independent of its origin. Still, the importer is 100%
compatible with CAD exports from Algoryx Momentum - an AGX Dynamics plugin
in Ansys SpaceClaim.
The importer supports:
Shapes of any type.
Rigid bodies.
Constraints (see Constraint for a list of supported constraints).
Contact materials.
Friction models.
Disabled collisions states (geometry and group pairs).
Render data.
Cables.
Wires.
Solver settings (not applied, but available).
Some of the imported objects are store on disk in the project (mesh data, render materials, shape materials,
contact materials, friction models, object and solver settings/properties). These objects are grouped together
given type and placed in a folder named <filename>_Data
, where <filename>
is the name of the
.agx
file without the extension.

Project view and Inspector of imported assets.¶
To import (create a prefab) a model, right click the .agx
file in the Project view and select
AGXUnity -> Import -> Selected AGX Dynamics file [prefab]
.
Or in an editor script (NOTE: return AGXUnityEditor.IO.AGXFileImporter.Import( filename );
is
enough, this example exemplifies how to access the assets of an imported model):
public static GameObject CreatePrefab( string filename )
{
// .agx or .aagx files supported.
if ( !System.IO.Path.GetExtension( filename ).ToLower().EndsWith( "agx" ) )
return null;
var prefab = AGXUnityEditor.IO.AGXFileImporter.Import( filename );
if ( prefab != null ) {
Debug.Log( "* Successfully imported " + filename + "." );
// This component contains assets dependent data.
var importedData = prefab.GetComponent<AGXUnity.IO.RestoredAGXFile>();
// The directory GUID the assets were written to.
var dir = AssetDatabase.GUIDToAssetPath( importedData.DataDirectoryId );
// RestoredAssetsRoot is the main assets of any imported asset type.
// These roots are always created even though there's no data.
var roots = AGXUnityEditor.IO.Utils.FindAssetsOfType<AGXUnity.IO.RestoredAssetsRoot>( dir );
// Printing list of UnityEngine.Material imported assets.
var rootContainingTypeToPrint = AGXUnity.IO.RestoredAssetsRoot.ContainingType.RenderMaterial;
// Finds System.Type given ContainingType enum.
var typeToPrint = AGXUnity.IO.RestoredAssetsRoot.GetType( rootContainingTypeToPrint );
// Finds and loads the materials. This is identical to
// AGXUnityEditor.IO.Utils.FindAssetsOfType<UnityEngine.Material>( dir ).
var renderMaterials = AGXUnityEditor.IO.Utils.FindAssetsOfType( dir, typeToPrint );
Debug.Log( " - Data directory: " + dir );
Debug.Log( " - Roots [" + roots.Length + "]:" );
foreach ( var root in roots ) {
var rootType = AGXUnity.IO.RestoredAssetsRoot.GetType( root.Type );
// root.Type == Unknown is for general types, i.e., there's no
// specific System.Type for this root type.
if ( rootType == null )
continue;
Debug.Log( " " + root.Type + " " +
"[" +
AGXUnityEditor.IO.Utils.FindAssetsOfType( dir, rootType ).Length +
"]" );
}
Debug.Log( " - Render materials:" );
foreach ( var renderMaterial in renderMaterials )
Debug.Log( " " + renderMaterial.name );
}
return prefab;
}

Result of the example above for a simple model with 2 contact materials, 2 friction models, 5 meshes, 3 render materials and 2 shape materials.¶
2.6.4. AGX Dynamics Export¶
AGX Dynamics supports complete and deterministic serialization. Exported AGX Dynamics files are important when something is wrong and you have to contact support. It’s possible to save the Initial state, i.e., the state in which the simulation was initialized in, or the Current state, saving the current state before the next step. See Simulation (Manager) for the Inspector interface for this.
Below is an example component which saves the simulation state at a given stride. The file is written before the simulation steps.
using System.IO;
using UnityEngine;
using AGXUnity;
public class SimulationExporter : MonoBehaviour
{
public string BaseFilename = "Exports/simulation";
public int Stride = 1;
private void Start()
{
Directory.CreateDirectory( Path.GetDirectoryName( BaseFilename + ".agx" ) );
Simulation.Instance.StepCallbacks.PreStepForward += OnPreStepForward;
}
private void OnDestroy()
{
if ( Simulation.HasInstance )
Simulation.Instance.StepCallbacks.PreStepForward -= OnPreStepForward;
}
private void OnPreStepForward()
{
// We count frames from 0 so that the initial state is
// saved independent of Stride.
var frameCount = Time.frameCount - 1;
var performExport = ( frameCount % Stride ) == 0;
if ( performExport ) {
// Filename at time 12.20s will become: simulation_t012.20.agx
var filename = BaseFilename +
"_t" +
Time.timeSinceLevelLoad.ToString( "000.00" ) +
".agx";
var success = Simulation.Instance.SaveToNativeFile( filename );
if ( success )
Debug.Log( "Exporting: " + filename );
else
Debug.LogWarning( "Failed to export: " + filename );
}
}
}