Page cover

Runtime Samples

Samples showcasing Flora's runtime features.

Fish Boids

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.

Core Classes

FishSchool

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

FishSimulation

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

Last updated