The Fish Boids sample scene demonstrates how to use Flora for large-scale, runtime-driven instance animation by adapting Unity’s original ECS BoidSample. It showcases how to spawn, update, and synchronize thousands of animated instances efficiently — with full support for motion vectors.
Key Concepts
Each fish is represented as a Flora instance, without requiring GameObjects.
Boid movement is simulated using jobs and native collections, then synced to Flora each frame.
Flora handles rendering, culling, batching, and motion vectors automatically.
NativeArray<FloraInstanceTransform> m_Transforms; // Transform storage
NativeArray<FloraInstanceHandle> m_InstanceHandles; // Handle storage (instance id)
JobHandle m_Dependency; // Update job dependency
void OnEnable()
{
// Create the native storage for the instance handles and transforms
m_Transforms = new NativeArray<FloraInstanceTransform>(SpawnCount, Allocator.Persistent);
m_InstanceHandles = new NativeArray<FloraInstanceHandle>(SpawnCount, Allocator.Persistent);
// A simple job that distributes the instances within a sphere
new InitFishTransformsJob {
Seed = (uint)UnityEngine.Random.Range(0, int.MaxValue),
Center = transform.position,
Radius = transform.localScale.x * SpawnRadius,
FishTransforms = m_Transforms,
}.Schedule(m_Transforms.Length, 64).Complete();
// Register the fish instances with the Flora system
FloraSystem.GetOrCreate().CreateInstances(Prefab, gameObject, m_InstanceHandles, m_Transforms);
}
void OnDisable()
{
// Ensure the job is completed before destroying the instances
m_Dependency.Complete();
// Destroy the fish instances in the Flora system
FloraSystem.Instance?.DestroyInstances(m_InstanceHandles);
// Dispose our native data
m_Transforms.Dispose();
m_InstanceHandles.Dispose();
}
/// <summary>
/// Uploads the local-to-world matrices to the Flora system.
/// </summary>
public void CompleteAndUpload()
{
// This dependency is used by the fish simulation,
// make sure it's done before uploading the instances
m_Dependency.Complete();
// The main function for changing instance transforms
FloraSystem.Instance?.UpdateInstanceWorldTransforms(m_InstanceHandles, m_Transforms);
}
void OnEnable()
{
// Find all the schools in the scene
m_Schools = FindObjectsByType<FishSchool>(FindObjectsSortMode.None);
}
void Update()
{
// Ensure Flora is running
if (!FloraSystem.Active)
return;
// Ensure last frames jobs have all finished, and then upload the transforms
foreach (var school in m_Schools)
school.CompleteAndUpload();
// The function that updates each school's array of transforms
float deltaTime = math.min(0.05f, Time.deltaTime);
foreach (var school in m_Schools)
school.Dependency = ScheduleUpdate(deltaTime, school.Settings, school.Transforms);
}