Houdini 18.0 Crowd simulations

Agent Primitives

About agents, the moving "actors" that make up a crowd simulation.

On this page

Overview

Agent primitives are a type of packed primitive, and are typically used to represent a character (agent) in a crowd simulation. As with other packed primitive types, agent primitives contain a single point, and so can be treated as a particle in many situations.

Agent Definition

An agent primitive stores a reference to several pieces of data, which are shared between copies of the agent and are often referred to as the agent definition. The agent definition consists of: a rig, a shape library, a set of layers, a set of clips, and an optional set of transform groups. An agent’s current layer, transforms, and channel values determine the geometry produced when the agent is unpacked.

When saving a set of agent primitives to disk, the components of the agent definition are also embedded in the geometry file (similar to a packed geometry primitive). Each component of the definition can also be saved separately to disk and treated as an external reference by the agent primitive - this can significantly reduce redundant data when, for example, saving out a sequence of frames from a crowd simulation. In such cases, only the path to the agent definition component (e.g. the shape library) will be stored in the geometry file (similar to a packed disk primitive). The Agent ROP can be used to write the agent definition of an existing agent primitive to disk, or can create an agent definition from a character rig or FBX file.

Rig

The rig stores the agent’s transform hierarchy (a tree of named transforms) and channels. Each transform either has a single parent, or is a root of the hierarchy. Each channel can provide a default value (used when the channel is not present in an animation clip) and can optionally be associated with a transform in the rig.

File Format
VEX Functions
HOM

Rigs are stored in JSON format. The hierarchy is represented as a map from parents to a list of their children, and the transform names may appear in any order.

{
    "rig_version": 1,
    "transforms": {
        "root": ["LUpperArm", "RUpperArm"],
        "LUpperArm": ["LLowerArm"],
        "LLowerArm": [],
        "RUpperArm": ["RLowerArm"],
        "RLowerArm": [],
    },
    "channels": {
        "blendshape1": {
            "default_value": 0,
            "transform": ""
        },
        "blendshape2": {
            "default_value": 0,
            "transform": ""
        },
        "RLowerArm.channel1": {
            "default_value": 0,
            "transform": "RLowerArm"
        }
    }
}

The following VEX functions can be used to query information about an agent’s rig:

The following HOM classes and methods can be used query information about or create an agent’s rig:

Shape Library

The shape library provides a collection of geometry (shapes) that can be used by the agent. Each shape in the library has a unique name.

File Format
HOM

Each shape is stored as a packed primitive, where the name primitive attribute contains the name of the shape and the shape’s geometry is the packed primitive’s contents. As such, the shape library is saved to disk as a single geometry file in the standard geo/bgeo format.

The shapelib_includes string array detail attribute can be used to specify additional shape libraries that should be included when the library is loaded. This attribute is expected to have a tuple size of 2, with each pair containing the condensed path (e.g. a path relative to $HIP or $JOB) along with the absolute path to the shape library file.

The following HOM classes and methods can be used query information about or modify an agent’s shape library:

Layers

Layers control the agent’s geometry: which shapes from the shape library should be used when the agent is unpacked, along with how those shapes should be transformed or deformed.

A layer consists of a set of shape bindings, which attach a shape from the shape library to a transform in the rig (for example, attaching the shape named "sword_1" to the "RHand" transform). Each shape binding can also specify a scale factor for the shape’s bounding box, and a deformer to use when unpacking the shape. If the shape binding does not have a deformer, the shape binding is static and the shape is simply transformed by the joint it is attached to.

File Format
VEX Functions
HOM

Layers are stored in JSON format, with separate lists of static and deforming shape bindings.

{
    "version": 1,
    "name": "soldier_display",
    "static": [
        {
            "transform": "LLowerArm",
            "shape": "shield",
            "bounds_scale": 1,
            "deformer": ""
        },
        {
            "transform": "RLowerArm",
            "shape": "sword",
            "bounds_scale": 1,
            "deformer": ""
        }
    ],
    "deforming": [
        {
            "transform": "",
            "shape": "skin",
            "bounds_scale": 1,
            "deformer": "linearskinning"
        }
    ]
}

The following VEX functions can be used to query information about or change an agent’s layers:

Deformers

There are several deformer types available for use in a shape binding.

Skinning

These deformers are equivalent to the Skinning Method options on the Bone Deform SOP. The shape’s geometry is expected to be in its rest pose and contain capture attributes describing how the geometry is influenced by the transforms in the rig. The geometry is deformed based on the capture attributes and the agent’s current transforms.

  • linearskinning

    Equivalent to the Bone Deform SOP’s Linear Skinning method. This is the standard and fastest method, and currently is the only method used for GPU skinning in the viewport.

  • dualquatskinning

    Equivalent to the Bone Deform SOP’s Dual Quaternion Skinning method.

  • dualquatblendskinning

    Equivalent to the Bone Deform SOP’s Blend Dual Quaternion and Linear Skinning method. The blend attribute’s name is specified by the deformDualQuaternionBlendAttrib detail attribute.

Blend Shapes

Blends between a set of input shapes using weights provided by the agent’s channel values. This is equivalent to the operations performed by the Blend Shapes SOP.

The shape’s geometry is interpreted as the base shape, and additional inputs (separate shapes in the shape library) are specified by the blendshape_shapenames string array detail attribute. The blendshape_channels string array detail attribute specifies the channel name (defined in the agent’s rig) to use for each blendshape input. The agent’s values for these channels will be used as the blendshape weights.

The id point attribute can be used to match up points between the different inputs, instead of matching by point number. This is equivalent to the Point ID Attribute option on the Blend Shapes SOP, and can be used to encode sparse blendshapes where only a subset of the points are deformed. The blendshape_ptidattr string detail attribute can be added to the base shape to override the default value of id. Similarly, the blendshape_primidattr string detail attribute can be used to specify the Primitive ID Attribute parameter (which is the empty string by default).

The blendshape_attribs string detail attribute can be used to specify which attributes are blended (corresponding to the Attributes parameter on the Blend Shapes SOP). The default behavior is to only blend point positions (P).

Additionally, each blendshape input can define in-between shapes, which are corrective shapes applied at particular weights to adjust the interpolation behavior. The in-between shapes are specified by the blendshape_shapenames string array detail attribute on the primary shape’s geometry, and the blendshape_inbetweenweights float array detail attribute specifies the weight that each in-between shape corresponds to. In-between shapes cannot have a weight of 1 (the weight that the primary shape is applied at) or a weight of 0.

  • blendshape

    Applies the Blend Shapes deformer to the geometry.

  • blendshape+linearskinning, blendshape+dualquatskinning, and blendshape+dualquatblendskinning

    These deformers apply the blendshape deformer followed by one of the skinning deformers.

HOM
HDK

Custom deformers can be implemented in the HDK by subclassing GU_AgentShapeDeformer. Deformers are registered by calling GU_AgentLayer::registerDeformer() from the GUregisterAgentShapeDeformer() entry point.

Clips

Clips provide animation data that can be used to drive an agent’s transforms and channel values.

File Format
VEX Functions
HOM

Clips are saved in the standard .bclip format.

Channels for an agent’s transforms are stored in local space and are named in the format transform_name:channel, where channel is t[xyz], r[xyz], or s[xyz].

Note

The [srt] channels describe the full local transform of each joint, and will not match the objects' [srt] channels from the source animation if there were pre-transforms.

The following VEX functions can be used to query information about or change an agent’s clips:

The following HOM classes and methods can be used query information about, create, or change an agent’s clips:

Transform Groups

A transform group is a named subset of the transforms and channels in an agent’s rig. Transform groups can be used when applying clips to parts of an agent’s skeleton. A weight value from 0 to 1 can also be assigned to each transform in the group.

File Format
VEX Functions
HOM

Transform groups are stored in JSON format.

{
    "version": 2,
    "name": "upper_arms",
    "members": [
        {
            "name": "LUpperArm",
            "weight": 1
        },
        {
            "name": "RUpperArm",
            "weight": 1
        }
    ],
    "channels": [
        {
            "name": "arm_blendshape_L"
        },
        {
            "name": "arm_blendshape_R"
        }
    ]
}

The following VEX functions can be used to query information about an agent’s transform groups:

The following HOM classes and methods can be used query information about or create transform groups:

Per-Agent Data

Transforms

Overview
VEX Functions
HOM

Each agent stores a set of current transforms (a 4×4 matrix for each transform in its rig). The transforms may be driven by the agent’s current animation clips, or the transforms can be controlled manually. The transforms are accessible through the agentworldtransforms and agentlocaltransforms primitive intrinsics.

As with other packed primitive types, agents also have an overall transform (controlled by the P and orient point attributes) that can be used to position the agent.

Channel Values

Overview
VEX Functions
HOM

Each agent stores a set of channel values (a float for each channel in its rig). The channel values may be driven by the agent’s current animation clips, or the channel values can be controlled manually.

The channel values are primarily used for the Blend Shapes deformer, but can be utilized for other applications as well.

The channel values are accessible through the agentchannelvalues primitive intrinsic.

The following VEX functions can be used to read or modify an agent’s channel values:

The following HOM methods can be used to read or modify an agent’s channel values:

Clips

Overview
VEX Functions
HOM

Each agent has a list of current animation clips from its agent definition. The lists of clips, clip times, and blend weights are used to drive the agent’s stored transforms and channel values. These properties are accessible through the following primitive intrinsics:

  • agentclipnames: A list of animation clip names.

  • agentcliptimes: A list of the times that the clips should be sampled at.

  • agentclipweights: A list of the blend weights for the animation clips. The weights will be normalized before blending.

The following primitive intrinsics extend the basic animation blending model to describe a tree structure for layering and blending animation clips. Each layer has a blend mode, and one or more input poses that each have an associated weight. The output of the layer is a new pose computed from its inputs. An input pose can either be a pose sampled from a clip, or the pose produced by another layer.

  • agentcliptransformgroups: Specifies the name of the transform group to use for each clip. This is used to apply clips to a subset of the transforms or channels in the rig.

  • agentcliplayerids: Specifies the layer index (into agentcliplayermodes) that each clip is an input for.

  • agentcliplayermodes: Specifies the blend mode for each layer (the length of this list controls the number of layers in the hierarchy). The valid values are 0 (the default interpolate blend mode) and 1 (additive blend mode). The additive blend mode applies a percentage (controlled by the blend weight) of the other clips' translations and rotations to the first input clip, rather than interpolating between the inputs.

  • agentcliplayerweights: Specifies the blend weight for each layer. Like agentclipweights, this is used when the layer’s output is used as the input for another layer, and so the weight is unused for the topmost layer.

  • agentcliplayerparents: Similar to agentcliplayerids, specifies the layer index that the layer is an input for. The topmost layer has a parent index of -1.

The following VEX functions can be used to read or modify an agent’s current clips:

The following HOM methods can be used to read or modify an agent’s current clips:

Layers

Overview
VEX Functions
HOM

Each agent has a current layer from its agent definition, which specifies the geometry to use when the agent is unpacked, displayed in the viewport, or rendered.

Additionally, an agent may have a collision layer, which is the layer to be used when a simple representation of the agent is needed (for example, a ragdoll simulation with the Bullet Solver). The collision layer, if present, is also used when determining the agent’s bounding box.

The current layer and collision layer are accessible through the agentcurrentlayer and agentcollisionlayer primitive intrinsics.

The following VEX functions can be used to read or modify an agent’s current layers:

The following HOM methods can be used to read or modify an agent’s current layers:

Bounding Box

If the agent has a collision layer, that layer will be used when computing the agent’s bounding box. If no collision layer is set, the agent’s current layer will be used instead. The bounding box of a layer is computed by combining the bounding boxes of each shape that is referenced by the layer.

For a static shape, the shape’s bounding box is expanded by the shape binding’s bounds scale, and then transformed according to the joint the shape is bound to. For a deforming shape, the shape’s bounding box is computed from the positions of the joints referenced by the capture weights, and then expanded by the shape binding’s bounds scale.

See also

Crowd simulations

Getting started

  • Basics

    An overview of Houdini crowd simulation concepts.

  • Setup

    How to set up and edit a crowd simulation.

The moving parts

  • Agents

    About agents, the moving "actors" that make up a crowd simulation.

  • States

    About agent states, the virtual "mood" of each agent which controls the agent’s animation and which behaviors it runs.

  • Triggers

    How to specify conditions that cause agents to change from one state to another.

  • Caches

    Tips for efficiently caching and loading crowd sims.

Behavior

Appearance

  • Diversity

    How to create a more realistic crowd by making agents look and act differently.

  • Attaching cloth

    You can add and constrain vellum cloth as part of agent shape geometry, and then simulate the cloth based on agent movements.

Terrain

  • Foot planting

    How to set up agents to adapt their animation to terrain and prevent skating.

  • Terrain

    How to specify terrain geometry for agents to walk across.

  • Obstacles

    How to set up obstacles for agents to avoid.