Force Fields

The Force Fields extension provides several methods that apply forces to the physics objects in the scene causing them to move in interesting ways. These methods, called force fields, can be added on top of each other to generate new behaviors. Each force field can be positioned, oriented and animated in the world to achieve the desired effect.

Getting Started

The PhysX Force Fields extension (omni.physx.forcefields) requires that the USD Force Field Schema (omni.usd.schema.forcefield) be enabled first. To enable both extensions, open the Extension Manager using the Window > Extensions menu item. Enter “force” into the search box to find the two extensions. The USD Force Field Schema must be auto loaded when Kit launches because the PhysX Force Fields extension depends on it. Click on the USD Force Field Schema and then check the Autoload check box. Next exit Kit using the File > Exit command and then relaunch it.

Re-open the Extension Manager, find the PhysX Force Fields extension and then check the Autoload check box, if it should be active every time Kit is launched, or slide the enabled switch to on to only use it temporarily.

Introduction to Force Fields

A force field is a mathematical function that computes a force vector to apply to a physics object as a function of time and its position, orientation, velocity and angular rate. The force fields are programmed and compiled in C++ because they are intended to act on very large numbers of objects and must execute very quickly. The current list of force fields include: Spherical, Planar, Linear, Drag, Wind and Noise. Additional force fields will be released in later versions.

These basic force fields are applied to a prim in the scene. Ideally, an Xform prim will be used so it can be positioned and oriented on the stage through its transformation matrix, but this is not required. Each force field does include a Position property that can be set, instead. However, the transform matrix takes precedence if both are available.

Multiple force fields can be applied to a single prim and multiple force fields can act on the physics objects. The forces are simply added together to determine the net force acting on it.

By default, force fields act on all of the physics objects in the scene. But this can be changed by editing the USD Collection to include or exclude prims and their children.

Demos

The Force Fields extension provides a few sample scenes that can be loaded quickly to see how force fields can be used. Open the Physics Demo Scenes: Window > Physics > Demo Scenes In the Physics Demo Scenes Tab, click on the Demos list to find the force field samples, which all start with the, “ForceField” prefix.

ForceFieldSamples

For the purposes of this introduction, select the ForceFieldExplode sample and click Load scene.

ForceFieldLoadScene

Press the Play button to start the simulation and watch the demonstration.

The following Python script is used to set up the force fields used in this demo and then animate their Enabled flags to achieve this result. An explanation of this script, how to programmatically set up force fields, which physics objects they affect and how to animate them is presented in Using Force Fields In Python

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
 import math
 import os
 import random

 from pxr import Gf, Sdf, Usd
 from pxr import UsdGeom, UsdUtils, UsdPhysics
 from pxr import PhysxSchema, PhysicsSchemaTools, ForceFieldSchema

 import omni.physx.scripts.physicsUtils as physicsUtils
 import omni.kit

 import omni.physxdemos as demo


 class ExplodeForceFieldDemo(demo.Base):
     title = "ForceFieldExplode"
     category = demo.Categories.DEMOS
     short_description = "Suck objects together before they are blown apart."
     description = "Use two spherical force fields to first attract objects to a central point and then explode them apart."

     def create(self, stage):
         numberOfBoxes = 20
         boxSpacing = 2
         boxPathName = "/box"
         groundPathName = "/ground"
         scenePathName = "/World/scene"
         explodePathName = "/World/explode"

         # Physics scene
         up = Gf.Vec3f(0.0)
         up[1] = 1.0
         gravityDirection = -up
         gravityMagnitude = 1000.0
         forceRange = Gf.Vec2f(-1.0)
         center = Gf.Vec3f(0.0)
         center[1] = 400.0

         scene = UsdPhysics.Scene.Define(stage, scenePathName)
         scene.CreateGravityDirectionAttr(gravityDirection)
         scene.CreateGravityMagnitudeAttr(gravityMagnitude)

         # Plane
         physicsUtils.add_ground_plane(stage, groundPathName, "Y", 750.0, Gf.Vec3f(0.0), Gf.Vec3f(0.5))

         # Create the force field prim
         xformPrim = UsdGeom.Xform.Define(stage, explodePathName)
         xformPrim.AddTranslateOp().Set(Gf.Vec3f(0.0, 300.0, 0.0))
         explodePrim = xformPrim.GetPrim()

         suckPrimApi = ForceFieldSchema.PhysxForceFieldSphericalAPI.Apply(explodePrim, "Suck")
         suckPrimApi.CreateConstantAttr(-1e10)
         suckPrimApi.CreateLinearAttr(0.0)
         suckPrimApi.CreateInverseSquareAttr(0.0)
         suckPrimApi.CreateEnabledAttr(False)
         suckPrimApi.CreatePositionAttr(Gf.Vec3f(0.0, 0.0, 0.0))
         suckPrimApi.CreateRangeAttr(Gf.Vec2f(-1.0, -1.0))

         explodePrimApi = ForceFieldSchema.PhysxForceFieldSphericalAPI.Apply(explodePrim, "Explode")
         explodePrimApi.CreateConstantAttr(4e10)
         explodePrimApi.CreateLinearAttr(0.0)
         explodePrimApi.CreateInverseSquareAttr(0.0)
         explodePrimApi.CreateEnabledAttr(False)
         explodePrimApi.CreatePositionAttr(Gf.Vec3f(0.0, 0.0, 0.0))
         explodePrimApi.CreateRangeAttr(Gf.Vec2f(-1.0, -1.0))

         dragPrimApi = ForceFieldSchema.PhysxForceFieldDragAPI.Apply(explodePrim, "Drag")
         dragPrimApi.CreateMinimumSpeedAttr(10.0)
         dragPrimApi.CreateLinearAttr(1.0e6)
         dragPrimApi.CreateSquareAttr(0.0)
         dragPrimApi.CreateEnabledAttr(False)
         dragPrimApi.CreatePositionAttr(Gf.Vec3f(0.0, 0.0, 0.0))
         dragPrimApi.CreateRangeAttr(Gf.Vec2f(-1.0, -1.0))

         # Add the collection
         collectionAPI = Usd.CollectionAPI.ApplyCollection(explodePrim, ForceFieldSchema.Tokens.forceFieldBodies)
         collectionAPI.CreateIncludesRel().AddTarget(stage.GetDefaultPrim().GetPath())

         # Boxes
         boxSize = Gf.Vec3f(100.0)
         boxPosition = Gf.Vec3f(0.0)
         m = (int)(math.sqrt(numberOfBoxes))

         for i in range(m):
             for j in range(m):
                 boxPath = boxPathName + str(i) + str(j)
                 boxPosition[0] = (i + 0.5 - (0.5 * m)) * boxSpacing * boxSize[0]
                 boxPosition[1] = 0.5 * boxSize[1]
                 boxPosition[2] = (j + 0.5 - (0.5 * m)) * boxSpacing * boxSize[2]
                 boxPrim = physicsUtils.add_rigid_box(stage, boxPath, position=boxPosition, size=boxSize)

         # Animate the force fields on and off
         global time
         time = 0.0

         def force_fields_step(deltaTime):
             global time
             time = time + deltaTime

             if time > 4.1:
                 suckPrimApi.GetEnabledAttr().Set(False)
                 explodePrimApi.GetEnabledAttr().Set(False)
                 dragPrimApi.GetEnabledAttr().Set(False)
             elif time > 4.0:
                 suckPrimApi.GetEnabledAttr().Set(False)
                 explodePrimApi.GetEnabledAttr().Set(True)
                 dragPrimApi.GetEnabledAttr().Set(False)
             elif time > 2.0:
                 suckPrimApi.GetEnabledAttr().Set(True)
                 explodePrimApi.GetEnabledAttr().Set(False)
                 dragPrimApi.GetEnabledAttr().Set(True)
             else:
                 suckPrimApi.GetEnabledAttr().Set(True)
                 explodePrimApi.GetEnabledAttr().Set(False)
                 dragPrimApi.GetEnabledAttr().Set(False)

         def timeline_event(event):
             # on play press
             if event.type == int(omni.timeline.TimelineEventType.PLAY):
                 global time
                 time = 0.0

             # on stop press
             if event.type == int(omni.timeline.TimelineEventType.STOP):
                 pass

         physxInterface = omni.physx.get_physx_interface()
         self._subscriptionId = physxInterface.subscribe_physics_step_events(force_fields_step)

         timelineInterface = omni.timeline.get_timeline_interface()
         stream = timelineInterface.get_timeline_event_stream()
         self._timeline_subscription = stream.create_subscription_to_pop(timeline_event)

Please feel free to explore the other demos and their scripts.

Adding Force Fields

There are two ways to apply force fields to a prim. The first method uses the Add button on in the Property window. Click on the desired prim. Click the Property tab and then click the Add button. A pop up menu will appear. Select the Physics submenu and then select the desired force field to add.

ForceFieldAddProperty

A second method involves right clicking on the prim itself in the Stage window. A pop up menu will appear with the Add > Physics sub menus. Then select the desired force field.

ForceFieldStageAddProperty

Spherical Force Field

The spherical force field attracts or repels objects to a central point while it is enabled. The following list of properties are available.

Property

Description

Enabled

Turns the force field on or off.

Position

The location of the force field in the world coordinate frame.

Range

Forces are only applied when the physics object is within this minimum and maximum distance from the force field position. A negative distance disables that value. e.g. Setting the minimum and maximum to (-1.0, -1.0) applies forces to objects regardless of their distance.

Constant

A constant force is applied to the physics object regardless of its distance to the force field position. Negative values attract and positive values repel.

Linear

A force that varies linearly with the distance from the force field position, i.e. F = k x d. Negative values attract and positive values repel.

Inverse Square

A force that is inversely proportional to the square of the distance from the force field. i.e. F = k / d^2. Negative values attract and positive values repel.
ForceFieldSphericalProperty

Drag Force Field

The drag force field generates forces that slow objects down by generating forces that oppose their velocity. The following list of properties are available.

Property

Description

Enabled

Turns the force field on or off.

Position

The location of the force field in the world coordinate frame.

Range

Forces are only applied when the physics object is within this minimum and maximum distance from the force field position. A negative distance disables that value. e.g. Setting the minimum and maximum to (-1.0, -1.0) applies forces to objects regardless of their distance.

Minimum Speed

Drag forces will not be applied when the speed of the physics object is below this minimum. A setting of -1.0 disables this minimum.

Linear

The force varies linearly with the speed of the physics object. D = k x s.

Square

The force varies with the square of the speed of the physics object. D = k x s^2. This is similar to an aerodynamic drag force.
ForceFieldDragProperty

Linear Force Field

The linear force field generates forces that attract or repel physics objects from the closest point on a line. No force is applied along the direction of the line. The following list of properties are available.

Property

Description

Enabled

Turns the force field on or off.

Position

The location of the force field in the world coordinate frame.

Range

Forces are only applied when the physics object is within this minimum and maximum distance from the force field position. A negative distance disables that value. e.g. Setting the minimum and maximum to (-1.0, -1.0) applies forces to objects regardless of their distance.

Direction

A vector with a length of one, in local space, that describes the orientation of the line.

Constant

A constant force is applied to the physics object regardless of its distance to the line. Negative values attract and positive values repel.

Linear

A force that varies linearly with the distance from the line, i.e. F = k x d. Negative values attract and positive values repel.

Inverse Square

A force that is inversely proportional to the square of the distance from the line. i.e. F = k / d^2. Negative values attract and positive values repel.
ForceFieldLinearProperty

Spin Force Field

The spin force field generates forces that cause physics objects to spin around a line. No force is applied along the direction of the spin axis. The only difference between this force field and the linear force field the is direction of the resulting force. This linear force field generates forces towards the line, while the spin force field generates forces that are perpendicular to the line. The following list of properties are available.

Property

Description

Enabled

Turns the force field on or off.

Position

The location of the force field in the world coordinate frame.

Range

Forces are only applied when the physics object is within this minimum and maximum distance from the force field position. A negative distance disables that value. e.g. Setting the minimum and maximum to (-1.0, -1.0) applies forces to objects regardless of their distance.

Spin Axis

A vector with a length of one, in local space, that describes the orientation of the line.

Constant

A constant force is applied to the physics object regardless of its distance to the spin axis. Negative values attract and positive values repel.

Linear

A force that varies linearly with the distance from the spin axis, i.e. F = k x d. Negative values attract and positive values repel.

Inverse Square

A force that is inversely proportional to the square of the distance from the spin axis. i.e. F = k / d^2. Negative values attract and positive values repel.
ForceFieldSpinProperty

Planar Force Field

The planar force field generates forces that cause physics objects to be attracted to or repelled away from a plane. The following list of properties are available.

Property

Description

Enabled

Turns the force field on or off.

Position

The location of the force field in the world coordinate frame.

Range

Forces are only applied when the physics object is within this minimum and maximum distance from the force field position. A negative distance disables that value. e.g. Setting the minimum and maximum to (-1.0, -1.0) applies forces to objects regardless of their distance.

Normal

A vector with a length of one, in local space, that describes the normal vector, or orientation, of the plane.

Constant

A constant force is applied to the physics object regardless of its distance to the plane. Negative values attract and positive values repel.

Linear

A force that varies linearly with the distance from the plane, i.e. F = k x d. Negative values attract and positive values repel.

Inverse Square

A force that is inversely proportional to the square of the distance from the plane. i.e. F = k / d^2. Negative values attract and positive values repel.
ForceFieldPlanarProperty

Noise Force Field

The noise force field generates random forces that cause physics objects to move in a chaotic fashion. The forces change their magnitude and direction smoothly over time. The following list of properties are available.

Property

Description

Enabled

Turns the force field on or off.

Position

The location of the force field in the world coordinate frame.

Range

Forces are only applied when the physics object is within this minimum and maximum distance from the force field position. A negative distance disables that value. e.g. Setting the minimum and maximum to (-1.0, -1.0) applies forces to objects regardless of their distance.

Drag

The drag coefficient determines the magnitude of the force that attempts to align the velocity of the physics object with the noise velocity. Higher values cause the physics objects to change direction more quickly.

Amplitude

The maximum magnitude of the noise signal.

Frequency

The frequency at which the noise signal oscillates.
ForceFieldNoiseProperty

Wind Force Field

The wind force field causes physics objects to move as if they are blowing in a wind. The wind can vary in wind speed and direction. The following list of properties are available.

Property

Description

Enabled

Turns the force field on or off.

Position

The location of the force field in the world coordinate frame.

Range

Forces are only applied when the physics object is within this minimum and maximum distance from the force field position. A negative distance disables that value. e.g. Setting the minimum and maximum to (-1.0, -1.0) applies forces to objects regardless of their distance.

Drag

The drag coefficient determines the magnitude of the force that attempts to align the velocity of the physics object with the wind velocity. Higher values cause the physics objects to change direction more quickly.

Average Speed

The average speed of the wind.

Speed Variation

The maximum magnitude of the change in wind speed.

Speed Variation Frequency

The frequency at which the wind speed changes.

Average Direction

A vector of unit length that describes the direction in which the wind is blowing.

Direction Variation

A vector of arbitrary length that describes the maximum magnitude of the changes in the wind direction vector along each axis of the local space. The wind direction will be re-normalized into a unit vector after the randomized component is applied.

Direction Frequency

The frequency at which the wind direction oscillates.
ForceFieldWindProperty

Collections

The forces generated by the force fields on a prim are applied to the set of rigid bodies specified by the, “forceFieldBodies” USD Collection. This USD collection is currently listed in the Raw USD Properties box, but will be moved into a more visible Property window of its own. Upon initialization, the default prim, “/World” is added to the includes list and the expansionRule is set to expandPrims. The expandPrims setting includes all of the children in the hierarchy of the prims listed, so in this case, every prim in the “/World” will be affected by the force fields.

Multiple prims can be added to the includes. Click the Add Target(s) button and select the prims to include from the list.

If the expansionRule is set to explicitOnly, then only the prims themselves, and none of their children will be affected by the force fields.

Another checkbox, includeRoot specifies whether the prim listed in the includes list should, itself, have forces applied to it. The default setting is to include the root.

To prevent specific rigid bodies from receiving forces, add the prims to the excludes list. Multiple prims can be added to the list. The rules work in the same way. If the expansionRule is set to expandPrims, then the children of the listed prims are also excluded. If the includeRoot checkbox is checked, then root itself is also excluded.

ForceFieldCollection

Multiple collections can also be used. Create a second prim, Add new force fields to that prim and then unique includes and excludes lists can be specified.

Tuning the Force Field Properties

The most difficult part of using the force fields extension is tuning the force coefficients labeled Constant, Linear, InverseSquare and Drag. These settings will depend on the masses of the rigid bodies that are being affected, so the more massive the object to be moved, the larger the setting should be. However, since lighter objects need to accelerate faster than heavier objects inside a force field, this difficulty is necessary. It just takes time to find settings that generate the desired results. The following suggestions should make it a bit easier.

A recommended approach is to first determine whether to use the Constant, Linear or Inverse Square as the primary property. Constant generates a force that will accelerate objects at a steady rate. The Linear force generates behaviors similar to a spring that results in sinusoidal motion. The Inverse Square term is how gravity is modelled. It tends to attract or repel very slowly at large distances but generates extremely strong forces nearby.

Do the tuning while the simulation is running. This avoid the necessity to continuously press the simulation Start and Stop buttons. Next, determine the correct order of magnitude for the force. Start by setting the coefficient to 1e0, and continue increasing the exponent until the rigid body objects start to move (1e1, 1e2, 1e3, etc.). Once the order of magnitude is known, adjust the mantissa to fine tune the results.

Using Force Fields In Python

Setting up force fields in Python uses script to run through the same steps as going through the UI. The only difference is that the “forceFieldBodies” USD Collection must be created manually.

The creation of a Physics scene, ground plane and the rigid bodies themselves is also required, but not covered here. The first step is to create a prim to hold all of the force fields. Add a translate operation to create a transformation matrix that can be positioned and animated.

1
2
3
4
5
6
 from pxr import ForceFieldSchema

     # Create the force field prim
     xformPrim = UsdGeom.Xform.Define(stage, "/World/Prim")
     xformPrim.AddTranslateOp().Set(Gf.Vec3f(0.0, 300.0, 0.0))
     prim = xformPrim.GetPrim()

Next, create the various force fields by applying them to the new prim and creating the attributes that need to be changed.

1
2
3
4
5
6
7
     explodePrimApi = ForceFieldSchema.PhysxForceFieldSphericalAPI.Apply(prim, "Explode")
     explodePrimApi.CreateConstantAttr(4e10)
     explodePrimApi.CreateLinearAttr(0.0)
     explodePrimApi.CreateInverseSquareAttr(0.0)
     explodePrimApi.CreateEnabledAttr(True)
     explodePrimApi.CreatePositionAttr(Gf.Vec3f(0.0, 0.0, 0.0))
     explodePrimApi.CreateRangeAttr(Gf.Vec2f(-1.0, -1.0))

To create the USD Collection, use the following lines of code. This will include all rigid bodies in the scene.

1
2
3
     # Add the collection
     collectionAPI = Usd.CollectionAPI.ApplyCollection(prim, ForceFieldSchema.Tokens.forceFieldBodies)
     collectionAPI.CreateIncludesRel().AddTarget(stage.GetDefaultPrim().GetPath())

The previous steps are sufficient to get the force fields to work and affecting the rigid bodies in the scene. But it is also possible to animate any of the USD properties while the simulation is running. To do this, add a call back in the script that can be used to update the settings. Be sure to save the subscription ID’s in the class or they will be destroyed and the callback functions will not be called.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
     global time
     time = 0.0

     def force_fields_step(deltaTime):
         global time
         time = time + deltaTime

         if time > 2.0:
             explodePrimApi.GetEnabledAttr().Set(False)
         else:
             explodePrimApi.GetEnabledAttr().Set(True)

     def timeline_event(event):
         # on play press
         if event.type == int(omni.timeline.TimelineEventType.PLAY):
             global time
             time = 0.0

         # on stop press
         if event.type == int(omni.timeline.TimelineEventType.STOP):
             pass

     physxInterface = omni.physx.get_physx_interface()
     self._subscriptionId = physxInterface.subscribe_physics_step_events(force_fields_step)

     timelineInterface = omni.timeline.get_timeline_interface()
     stream = timelineInterface.get_timeline_event_stream()
     self._timeline_subscription = stream.create_subscription_to_pop(timeline_event)