Page cover image

Fish

The fish sample scene shows off a modified version of Unity's ECS BoidSample, and showcases how to create thousands of instances, update them and sync the changes to Flora.

Additionally, each instance is culled performantly and with correct motion vectors.

The important areas of the sample are in two 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