This document is about: QUANTUM 3
SWITCH TO

Frustum Prediction Culling

The snippet shows how to apply simple frustum culling to Quantum entities.

Culled entities in Quantum will not be updated when simulating predicted frames which is a performance improvement.

Read more about Profiling in Quantum.

Implementing a custom culling system involves three main steps:

Custom culling callback definition

Declare the callback that will be lately used for defining the actual culling logic:

C#

namespace Quantum
{
  using Photon.Deterministic;

  partial class FrameContextUser
  {
    public delegate bool CullingDelegate(FPVector3 position);

    public CullingDelegate CullingCallback;
  }
}

Custom culling System

Create a new system which triggers the callback.
P.S: this system should replace the regular culling systems which are provided by default on the SystemsConfig asset.

C#

namespace Quantum
{
  using UnityEngine.Scripting;
  using Quantum.Task;

  [Preserve]
  public unsafe class CustomCullingSystem : SystemBase
  {
    private TaskDelegateHandle _updateTask;

    public override void OnInit(Frame f)
    {
      f.Context.TaskContext.RegisterDelegate(Update, "CustomCullingSystem Update", ref _updateTask);
    }

    private void Update(FrameThreadSafe frame, int start, int count, void* arg)
    {
      var f = (Frame)frame;
      var context = f.Context;
      var filter = f.Filter<Transform3D>();
      while (filter.NextUnsafe(out var entity, out var transform))
      {
        if (context.CullingCallback(transform->Position))
        {
          f.Cull(entity);
        }
      }
    }

    protected override TaskHandle Schedule(Frame f, TaskHandle taskHandle)
    {
      if (f.IsVerified)
      {
        return taskHandle;
      }

      if (f.Context.CullingCallback != null)
      {
        var handle = f.Context.TaskContext.AddMainThreadTask(_updateTask, null);
        handle.AddDependency(taskHandle);
        return handle;
      }

      return taskHandle;
    }
  }
}

Frustum culling logic

Create a new script in which the culling logic is implemented and set in the callback previusly created:

C#

namespace Quantum
{
  using Photon.Deterministic;
  using UnityEngine;

  public class FrustumPredictionCulling : QuantumSceneViewComponent
  {
    public float ProximityRadiusOverhaul = 20;

    public override void OnActivate(Frame frame)
    {
      Game.Frames.Verified.Context.CullingCallback = Callback;
    }

    private bool Callback(FPVector3 position)
    {
      var unityPosition = position.ToUnityVector3();
      var distance = (unityPosition - Camera.main.transform.position).sqrMagnitude;

      if (distance < ProximityRadiusOverhaul * ProximityRadiusOverhaul) return false;

      var normalizedPos = Camera.main.WorldToViewportPoint(unityPosition);
      if (normalizedPos.z <= 0) return true;

      if (normalizedPos.y < 0 || normalizedPos.y > 1) return true;
      if (normalizedPos.x < 0 || normalizedPos.x > 1) return true;

      return false;
    }
  }
}
Back to top