using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Rendering;
namespace GarmentButton.Culling
{
public partial struct CullingSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<EndSimulationEntityCommandBufferSystem.Singleton>();
state.RequireForUpdate<CameraFrustumPlanes>();
state.RequireForUpdate<VisibleTag>();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var ecbSingleton = SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>()
.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter();
var cameraFrustumPlanes = SystemAPI.GetSingleton<CameraFrustumPlanes>();
state.Dependency = new CullJob()
{
Planes = cameraFrustumPlanes,
Ecb = ecbSingleton
}.ScheduleParallel(state.Dependency);
}
}
[BurstCompile]
[WithAll(typeof(VisibleTag))]
[WithOptions(EntityQueryOptions.IgnoreComponentEnabledState)]
public partial struct CullJob : IJobEntity
{
public CameraFrustumPlanes Planes;
public EntityCommandBuffer.ParallelWriter Ecb;
[BurstCompile]
private void Execute([EntityIndexInQuery] int sortKey, Entity e, in WorldRenderBounds wrb)
{
var aabb = wrb.Value; // Unity.Mathematics.AABB (Center, Extents)
bool visible = AabbInsideFrustum(aabb.Center, aabb.Extents);
Ecb.SetComponentEnabled<VisibleTag>(sortKey, e, visible);
}
[BurstCompile]
private bool AabbInsideFrustum(float3 center, float3 extents)
{
return AabbInsidePlane(center, extents, Planes.P0)
&& AabbInsidePlane(center, extents, Planes.P1)
&& AabbInsidePlane(center, extents, Planes.P2)
&& AabbInsidePlane(center, extents, Planes.P3)
&& AabbInsidePlane(center, extents, Planes.P4)
&& AabbInsidePlane(center, extents, Planes.P5);
}
//
[BurstCompile]
private bool AabbInsidePlane(float3 c, float3 e, float4 plane)
{
float3 n = plane.xyz;
float d = plane.w;
// Project extents onto plane normal (abs(n) dot extents)
float r = math.dot(math.abs(n), e);
float s = math.dot(n, c) + d;
// Outside if s + r < 0
return (s + r) >= 0f;
}
}
}