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.1. Main and context menus

2.1.2. GameObject main and Hierarchy context menus

Inside the create section of GameObject main and Hierarchy context menu. When an object is created using the Hierarchy context menu the selected object will become parent of the new object. Main menu GameObject objects are create without parents regardless of current selection.

_images/gameobject_main_menu.png _images/gameobject_context_menu.png

2.1.3. Assets main and context menus

Create AGX Dynamics for Unity specific assets, such as shape and contact materials, friction models, model specific properties and settings. Assets created from the main menu will be created in the current open project folder.

_images/assets_main_menu.png _images/assets_context_menu.png

2.1.4. Component main and Inspector menus

Add component to selected game object(s).

_images/component_main_menu.png _images/component_context_menu.png

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.

_images/shape_inspector.png

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 (UnityEngin.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

shape-resize-tool-icon

Resize shape in Scene View holding Ctrl for asymmetric or Ctrl+Shift for symmetric resize of the shape. See Shape resize tool for details.

Supports Box, Sphere, Capsule and Cylinder.

shape-from-tool-icon

[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-tool-icon

Disable collisions between this object and objects selected in Scene View. See Disable collisions tool for details.

create-visual-tool-icon

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.

_images/shape_box_inspector.png

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.

_images/shape_sphere_inspector.png

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.

_images/shape_capsule_inspector.png

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.

_images/shape_cylinder_inspector.png

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.

_images/shape_mesh_inspector.png

Mesh Inspector properties.

Property

Description

Default

Source

Source mesh asset.

null

Options

Collision Mesh Options

Trimesh, vertex reduction disabled.

See also

Inherited properties and tools.

_images/example_shape_mesh_all.gif

Mesh and scale of its transform and parent transform.

2.2.1.5.1. 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 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

_images/shape_mesh_options_inspector.png

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.

_images/shape_mesh_options.gif

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.

2.2.1.6. Height Field

Height field is a static height map that reads the height data from an UnityEngine.Terrain instance.

_images/shape_height_field_inspector.png

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.

_images/shape_plane_inspector.png

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

_images/shape_hollow_cylinder_inspector.png

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

Cone

_images/shape_cone_inspector.png

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

Hollow Cone

_images/shape_hollow_cone_inspector.png

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.

_images/rigid_body_inspector.png

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

create-constraint-tool-icon

Configure and create constraints.

disable-collisions-tool-icon

Disable collisions between this object and objects selected in Scene View. See Disable collisions tool for details.

shape-from-tool-icon

[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-tool-icon

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.

_images/mass_properties_inspector.png

Mass properties Inspector with automatic calculation toggle, mass/inertia fields and explicit update button.

_images/mass_properties_inspector_anim.gif

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.

_images/create_rigid_body_box_components.gif

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.

_images/create_rigid_body_shape_children.gif

Rigid body game object with several shapes, of arbitrary relative transforms, as children.

2.2.2.3. Motion control

_images/rigid_body_motion_control.png

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.

_images/rigid_body_motion_control_anim.gif

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

_images/constraint_frames_inspector.png

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-tool-icon

Select parent in Scene View.

find-point-tool-icon

Find transform given a point on a mesh surface.

find-edge-tool-icon

Find transform given a triangle edge and surface.

transform-handle-active-icon

Toggle to enable/disable the transform handle in Scene View.

2.2.3.2. Properties

_images/constraint_inspector_collapsed.png

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.

_images/constraint_tp_inspector.png

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.

_images/constraint_rp_inspector.png

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)

_images/constraint_controllers_inspector.png

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

Screw controller (Cylindrical Joint)

_images/constraint_screw_controller_inspector.png

Controller that, when enabled, defines a relation between the rotational and translational constraint angles in a Cylindrical Joint.

Property

Description

Default

Lead

The distance along the screw’s axis that is covered by one complete rotation.

0

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:

  1. Find constraint (reference) frame parent and transform.

  2. Select connected frame parent.

  3. Assign initial values and/or enable and configure controllers.

Tools, such as Find point tool find-point-tool-icon-small, Find edge tool find-edge-tool-icon-small and Select parent tool select-parent-tool-icon-small, can be used to complete (1) and (2).

_images/create_constraint_anim.gif

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.

_images/wire_inspector.png

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.

_images/wire_route_inspector_numbered.png

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.

_images/wire_route_error_min.png
_images/wire_route_error_exp.png

Route error displaying tooltip: Body Fixed Node can only be at the begin or at the end of wire.

_images/wire_route.gif

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.

_images/cable_inspector.png

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.

_images/cable_route.gif

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.

_images/deformable_terrain_inspector.png

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.

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

  1. Store UnityEngine.TerrainData initial height data into array.

  2. Add Maximum Depth to all heights in the UnityEngine.TerrainData object.

  3. Move the terrain game object Maximum Depth down.

Uninitialization summary

  1. Set UnityEngine.TerrainData heights to the ones stored during initialization.

  2. 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>();
_images/deformable_terrain_shovel_add_component.png

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

_images/deformable_terrain_shovel_inspector.png

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.

_images/deformable_terrain_add_shovel.gif

Configuring the edges

See AGX Dynamics Terrain Shovel Setup documentation for detailed information about the edges and cutting direction.

_images/deformable_terrain_shovel_edges.gif

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.

_images/deformable_shovel_edges_errors.gif

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.

_images/deformable_terrain_renderer_inspector.png

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 UnityEngine.Graphics.DrawMeshInstanced and Game Object is instancing and managing Game Objects and their transforms.

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 UnityEngine.MeshFilter and one UnityEngine.MeshRenderer with a UnityEngine.Material. It’s also required that the material has GPU Instancing Enable enabled. Game Object mode doesn’t have such requirements but may not perform as well as Draw Mesh Instanced.

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();
}
_images/deformable_terrain_particle_renderer.gif

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.

_images/track_inspector.png

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.

_images/track_using_tools.gif

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.

_images/track_using_components.gif

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.

_images/track_wheel_inspector.png

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.

_images/hydrodynamics_parameters_inspector.png

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.

_images/aerodynamics_parameters_inspector.png

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.

_images/wind_and_water_controller_aero.gif

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.

_images/amor_enable_merge_split_handler.gif

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.

_images/merge_split_properties_inspector.png

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.

_images/collision_groups_inspector.png

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>().

_images/articulated_root_hierarchy.png

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

_images/articulated_root_inspector.png

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.

_images/rigid_body_emitter_inspector.png

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

_images/rigid_body_emitter_template_inspector.png

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 context-drop-down-icon-small on the right for a list of valid prefabs that can be added.

_images/rigid_body_emitter_add_template.png

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.

_images/rigid_body_emitter.gif

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.

_images/rigid_body_emitter_sink_inspector.png

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

_images/rigid_body_emitter_sink.gif

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.

_images/simulation_instance.gif

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.

_images/simulation_inspector.png

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

Toggle Adaptive Model Order Reduction - AMOR.

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.

_images/contact_material_manager_create.gif

Add Contact Material Manager to current scene by clicking AGXUnity -> Managers -> Contact Material Manager from the main menu.

_images/contact_material_manager.gif

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.

_images/collision_groups_manager_create.png

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 context-drop-down-icon-small for a list of all current Collision groups in the current scene.

_images/collision_groups_manager_inspector.png

Add new disabled pair by typing the group name or click context-drop-down-icon-small for a list of all current Collision groups in the scene.

_images/collision_groups_manager.gif

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.

_images/wind_and_water_manager_inspector.png

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).

_images/wind_and_water_manager_hydro.gif

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.

_images/license_manager_window_default.png

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, the filename was constrained to be agx.lic and located in pre-defined directories, but may from 3.0.0 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.

_images/license_manager_window_info.png

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.

_images/license_manager_encrypted_window.png

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 {
        var success = agx.Runtime.instance().activateEncryptedRuntime( s_activationContent,
                                                                       activatedLicenseFilename );
        if ( success )
          Debug.Log( "Successfully activated license: " + activatedLicenseFilename );
        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. 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 or earlier, and desire to update to version 2.4.3 or later, please follow these steps:

  1. Download the AGXUnityUpdateHandler package.

  2. Import the package into the project in which you desire to update AGX Dynamics for Unity.

  3. 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.

  1. Right click the AGXUnity directory in Project View and select Reimport.

    _images/update_handler_manual_reimport.png
  2. If Reimport isn’t enough (Unity version 2020.1 or newer), add any Define Symbol under Edit -> Project Settings... -> Player -> Scripting Define Symbols and click Apply to trigger a project wide compilation. The define symbol may be removed later on.

    _images/update_handler_manual_define.png

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.

_images/shape_material_inspector.png

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.

_images/contact_material_inspector.png

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.

_images/friction_model_inspector.png

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 estimating the normal forces while Scale Box Friction solves the system over and over again given the current normal forces, adjusting the maximum friction forces of the contact. Iterative Projected Friction is a Scale Box Friction type.

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.

_images/solver_settings_inspector.png

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.

_images/cable_properties.gif

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.

_images/deformable_terrain_material_inspector.png

Deformable Terrain Material Inspector with default values.

2.4.6.1. Material Library

Starting from 2.1.0, 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.

_images/deformable_terrain_material_library_project_view.png

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

_images/deformable_terrain_material_library_inspector.png

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.

_images/deformable_terrain_material_library_custom.png

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.

_images/deformable_terrain_properties_inspector.png

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.

_images/deformable_terrain_shovel_settings_inspector.png

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.

_images/track_properties_inspector.png

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.

_images/track_internal_merge_properties_inspector.png

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.

_images/contact_thresholds_inspector.png

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.

_images/constraint_thresholds_inspector.png

Constraint Merge Split Thresholds Inspector with default values.

2.5. Tools

2.5.1. create-constraint-tool-icon-small Create constraint tool

Tool to create and configure a new constraint.

_images/create_constraint_tool_inspector.png

Create constraint Inspector dropdown tool.

  1. Verify/select name.

  2. Choose constraint type.

  3. Configure reference frame.

  4. Select parent of connected frame.

  5. Select disabled collisions state - default is disabled.

  6. Press Create to create the constraint - Cancel to discard any changes.

_images/create_constraint_tool.gif

2.5.2. shape-resize-tool-icon-small 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 holding Left Ctrl 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 Ctrl + Shift.

_images/shape_resize_tool.gif

Symmetric Left Ctrl + Shift and asymmetric Left Ctrl resize of primitive shapes that supports the shape resize tool.

2.5.3. shape-from-tool-icon-small 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-icon-small 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.

_images/create_visual_tool.gif

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-icon-small Disable collisions tool

Simple utility tool that adds unique group names to objects and then adds the group pair to Collision Groups Manager.

_images/disable_collisions_tool.gif

Disabling collisions between the rigid body box and other objects by selecting objects in Scene View.

2.5.6. select-parent-tool-icon-small Select parent tool

Tool to select/change a parent in a frame, by selecting an object in Scene View.

_images/select_parent_tool.gif

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-icon-small 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:

  1. Select parent tool to find the parent to the frame.

    _images/find_edge_tool_1.png
  2. Select edge.

    _images/find_edge_tool_2.png
  3. Select point on the selected edge. Note that the point snaps to begin, middle and end of the edge. For free move hold Ctrl.

    _images/find_edge_tool_3.png
  4. Select z direction of the final transform.

    _images/find_edge_tool_4.png
_images/find_edge_tool.gif

Creating two hinges, one on each side of the frame, using the Find edge tool.

2.5.8. find-point-tool-icon-small 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.

_images/find_point_tool.gif

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.

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>
_images/urdf_model_link_inspector.png _images/urdf_model_link_rb_inspector.png
<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>
_images/urdf_model_joint_inspector.png _images/urdf_model_joint_constraint_inspector.png

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;
    }
  }
}
_images/urdf_joint_data_example_console.png

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 );
}
_images/urdf_read_my_robot_inspector.png

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].

_images/urdf_model_instantiate_editor.gif

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.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).

_images/stl_normal_no_normal_angle_threshold.png _images/stl_normal_default_normal_angle_threshold.png

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).

  • Materials.

  • 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.

_images/agx_import_assets_inspector.png

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].

_images/agx_import_wheel_loader.gif

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;
}
_images/agx_import_assets_example.png

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 );
    }
  }
}