#if !RUKHANKA_NO_DEBUG_DRAWER using Rukhanka.DebugDrawer; #endif using Rukhanka.Toolbox; using Unity.Collections; using Unity.Entities; using Unity.Jobs; using Unity.Mathematics; #if RUKHANKA_WITH_NETCODE using Unity.NetCode; #endif using UnityEditor; using UnityEngine; ///////////////////////////////////////////////////////////////////////////////// namespace Rukhanka { [DisableAutoCreation] [UpdateAfter(typeof(FillAnimationsFromControllerSystem))] public partial class AnimationCullingContextUpdateSystem: SystemBase { internal struct CullingCameraData { public float3 pos; public float3 viewDir; public float4x4 cullingMatrix; public float fieldOfView; public bool isOrthographic; public float orthographicSize; } internal struct LightData { public float4 posOrDir; public float range; } ///////////////////////////////////////////////////////////////////////////////// protected override void OnCreate() { #if RUKHANKA_WITH_NETCODE bool isServer = World.IsServer(); if (isServer) Enabled = false; #endif } ///////////////////////////////////////////////////////////////////////////////// protected override void OnUpdate() { var acc = AnimationCullingConfig.Instance; if (acc == null) return; if (!SystemAPI.TryGetSingletonRW(out var actx)) { var newContext = new AnimationCullingContext(); newContext.cullingPlanes = new (32, Allocator.Persistent); newContext.cullingVolumePlaneRanges = new (32, Allocator.Persistent); newContext.lodAffectors = new (32, Allocator.Persistent); EntityManager.CreateSingleton(newContext, "Rukhanka.AnimationCullingContextSingleton"); actx = SystemAPI.GetSingletonRW(); } var cullingCameras = new NativeList(acc.cullingCameras.Length, CheckedStateRef.WorldUpdateAllocator); foreach (var cullingCam in acc.cullingCameras) { AddCullingCamera(cullingCam, ref cullingCameras); } var shadowCastingLights = new NativeList(acc.shadowCastingLights.Length, CheckedStateRef.WorldUpdateAllocator); foreach (var l in acc.shadowCastingLights) { AddShadowCastingLight(l, ref shadowCastingLights); } #if UNITY_EDITOR if (acc.addEditorSceneCamera) { var sceneCam = SceneView.lastActiveSceneView?.camera; AddCullingCamera(sceneCam, ref cullingCameras); } #endif Dependency = BuildCullingContext(cullingCameras, shadowCastingLights, ref actx.ValueRW, acc, Dependency); } ///////////////////////////////////////////////////////////////////////////////// void AddShadowCastingLight(Light l, ref NativeList shadowCastingLights) { if (l == null || l.shadows == LightShadows.None || !l.isActiveAndEnabled) return; var lt = l.transform; var ld = new LightData() { posOrDir = l.type == LightType.Directional ? new float4(-lt.forward, 0) : new float4(lt.position, 1), range = l.range, }; shadowCastingLights.Add(ld); } ///////////////////////////////////////////////////////////////////////////////// void AddCullingCamera(Camera cam, ref NativeList cullingCameras) { if (cam == null) return; var camTransform = cam.transform; var ccd = new CullingCameraData() { pos = camTransform.position, viewDir = camTransform.forward, cullingMatrix = cam.cullingMatrix, fieldOfView = cam.fieldOfView, isOrthographic = cam.orthographic, orthographicSize = cam.orthographicSize }; cullingCameras.Add(ccd); } ///////////////////////////////////////////////////////////////////////////////// JobHandle BuildCullingContext(NativeList cullingCameras, NativeList shadowCastingLights, ref AnimationCullingContext actx, AnimationCullingConfig acc, JobHandle dependsOn) { #if (RUKHANKA_DEBUG_INFO && !RUKHANKA_NO_DEBUG_DRAWER) SystemAPI.TryGetSingletonRW(out var dd); #endif var buildCullingContextJob = new BuildCullingContextJob() { cullingCameras = cullingCameras.AsArray(), shadowCastingLights = shadowCastingLights.AsArray(), lodBias = QualitySettings.lodBias, actx = actx, #if (RUKHANKA_DEBUG_INFO && !RUKHANKA_NO_DEBUG_DRAWER) dd = dd.ValueRW, #endif }; var rv = buildCullingContextJob.Schedule(dependsOn); #if (RUKHANKA_DEBUG_INFO && !RUKHANKA_NO_DEBUG_DRAWER) actx.invisibleChunkColor = ColorTools.ToUint(acc.invisibleChunkColor); actx.visibleChunkColor = ColorTools.ToUint(acc.visibleChunkColor); actx.invisibleRendererColor = ColorTools.ToUint(acc.invisibleRendererColor); actx.visibleRendererColor = ColorTools.ToUint(acc.visibleRendererColor); actx.drawSceneBoundingBoxes = acc.drawSceneBoundingBoxes; actx.drawCullingVolumes = acc.drawCullingVolumes; actx.cullingVolumeColor = ColorTools.ToUint(acc.cullingVolumeColor); #endif return rv; } ///////////////////////////////////////////////////////////////////////////////// protected override void OnDestroy() { if (SystemAPI.TryGetSingleton(out var actx)) { actx.Dispose(); EntityManager.DestroyEntity(SystemAPI.GetSingletonEntity()); } } } }