# Rendering Agents

The crowd actor is **simulation only**: it tracks each agent's position, velocity, facing and
ground height, but it draws nothing. You decide how agents look by reading their transforms
each frame and feeding them to a renderer - typically an **Instanced Static Mesh (ISM)** so
thousands of agents cost a handful of draw calls.

::: tip
Every Blueprint graph on this page already exists, fully wired, in the **`BP_CrowdRenderer`**
example Blueprint in the plugin's **content folder** (enable *Show Plugin Content* in the
Content Browser). Open it to see the finished setup instead of rebuilding it.
:::

## Set up the renderer

Make an Actor with an **Instanced Static Mesh** component and assign the mesh your agents
should use.

![Instanced Static Mesh component on the renderer actor](../assets/get-started/render-ism-component.png)

## What `GetAgentTransforms` gives you

Each transform is ready to render - no extra math needed:

- **Location** - the agent's world position, including its tracked **Z** (see [Ground Snapping](../concepts/06-ground_snapping.md)).
- **Rotation** - faces the agent's **travel direction**, holding the last facing while idle (so meshes don't snap back to identity). Tilted to the ground normal when `bAlignTransformsToGround` is on.
- **Scale** - `TransformScale` on every axis (a property on the crowd actor).

Pass an empty array for **all** agents, or a list of indices to get just those.

## The render loop

The simplest correct version, on your renderer's **Tick**:

![Render loop on Tick](../assets/get-started/render-tick-update.png)
*This graph is already wired in `BP_CrowdRenderer` in the plugin's content folder.*

==- C++
```cpp
TArray<FTransform> Transforms = Crowd->GetAgentTransforms({});

ISM->ClearInstances();
ISM->AddInstances(Transforms, /*bReturnIndices*/ false, /*bWorldSpace*/ true);
```
===

### Updating in place (recommended)

`ClearInstances` + `AddInstances` every frame works, but rebuilds the whole instance buffer.
When the agent count is stable, update transforms in place instead - add the instances once,
then batch-update each tick:

![In-place batch update](../assets/get-started/render-batch-update.png)
*This graph is already wired in `BP_CrowdRenderer` in the plugin's content folder.*

==- C++
```cpp
if (ISM->GetInstanceCount() != Transforms.Num())
{
    ISM->ClearInstances();
    ISM->AddInstances(Transforms, /*bReturnIndices*/ false, /*bWorldSpace*/ true);
}
else
{
    ISM->BatchUpdateInstancesTransforms(0, Transforms, /*world*/ true, /*markDirty*/ true, /*teleport*/ true);
}
```
===

Hook the crowd's [`OnAgentsSpawned` / `OnAgentsRemoved`](../concepts/05-events.md) events to
resize only when the population actually changes.

## Driving an animation

`GetAgentVelocities` and `GetAgentSettled` let you pick an animation state per agent (idle vs
walk/run) without extra bookkeeping - feed the velocity magnitude into a per-instance custom
data float and let the material/animation pick a pose from it. For a fully GPU-instanced
animated crowd, combine this with a vertex-animation-texture material.
