using System.Collections.Generic; using Unity.Mathematics; using UnityEngine; using UnityEngine.Experimental.Rendering; namespace X.Rendering.Feature { public class HizObjectsManager : MonoBehaviour { public bool ShowDebug = false; Texture2D centerTex; Texture2D sizeTex; private static HizObjectsManager intstance; public static HizObjectsManager Instance => intstance; private float4[] centers; private float4[] extents; private float3x2[] aabbs; private List renderers = new(); private bool[] cullResults; private bool needUpdateAABB = true; public int culledCnt = 0; private void Awake() { intstance = new(); } void Start() { int texSize = 64; centerTex = new Texture2D(texSize, texSize, TextureFormat.RGBAFloat, 0, true); centerTex.filterMode = FilterMode.Point; sizeTex = new Texture2D(texSize, texSize, TextureFormat.RGBAFloat, 0, true); sizeTex.filterMode = FilterMode.Point; Shader.SetGlobalTexture(HizShaderIds.ObjectAABBCenterId, centerTex); Shader.SetGlobalTexture(HizShaderIds.ObjectAABBSizeId, sizeTex); } void Update() { if (needUpdateAABB) { needUpdateAABB = false; UpdateAABB(centerTex, sizeTex); } } private void OnDestroy() { Texture.DestroyImmediate(centerTex); Texture.DestroyImmediate(sizeTex); } private void LateUpdate() { ApplyCull(HierarchicalZOcclusionCullFeature.GetCullResult()); } public void Register(MeshRenderer renderer) { if (!renderers.Contains(renderer)) { renderers.Add(renderer); needUpdateAABB = true; } } public void UnRegister(MeshRenderer renderer) { if(renderers.Remove(renderer)) { needUpdateAABB = true; } } public void UpdateAABB(ComputeBuffer aabbBuffer) { if (aabbBuffer == null || aabbs.Length != renderers.Count) { aabbs = new float3x2[renderers.Count]; } for (int i = 0; i < renderers.Count; i++) { var rdr = renderers[i]; if (rdr != null) { Bounds bounds = rdr.bounds; aabbs[i] = new float3x2(bounds.center, bounds.size); } else { aabbs[i] = float3x2.zero; } } aabbBuffer.SetData(aabbs); } public void UpdateAABB(Texture2D centerTex, Texture2D sizeTex) { if (centers == null || centers.Length != centerTex.width * centerTex.height) { centers = new float4[centerTex.width * centerTex.height]; extents = new float4[centerTex.width * centerTex.height]; } if (renderers.Count == 0) { foreach (var item in GameObject.FindObjectsOfType()) { if (item.gameObject.isStatic) { Register(item); } } } if (cullResults == null || cullResults.Length != renderers.Count) { cullResults = new bool[renderers.Count]; } int nullCnt = 0; for (int i = 0; i < renderers.Count; i++) { var rdr = renderers[i]; if (rdr != null) { Bounds bounds = rdr.bounds; centers[i] = new float4(bounds.center, 1); extents[i] = new float4(bounds.extents, 1); } else { nullCnt++; centers[i] = float4.zero; extents[i] = float4.zero; } } if (nullCnt == renderers.Count) { renderers.Clear(); } centerTex.SetPixelData(centers, 0); centerTex.Apply(); sizeTex.SetPixelData(extents, 0); sizeTex.Apply(); Shader.SetGlobalTexture(HizShaderIds.ObjectAABBCenterId, centerTex); Shader.SetGlobalTexture(HizShaderIds.ObjectAABBSizeId, sizeTex); } private void ApplyCull(CullResult cullResult) { if (cullResult.ReadDone) { culledCnt = 0; for (var i = 0; i < renderers.Count; i++) { var rdr = renderers[i]; if (rdr && cullResult.ResultArray.IsCreated) { bool needCull = cullResult.ResultArray[i] > 0.5f; #if UNITY_EDITOR if (ShowDebug && rdr.GetComponent() is CullDebug cullDebug && cullDebug) { cullDebug.Index = i; cullDebug.IsCulled = needCull; cullDebug.Position = centers[i].xyz; cullDebug.Size = extents[i].xyz; } #endif if (needCull) { culledCnt++; } if (cullResults[i] != needCull) { if (needCull) { culledCnt++; rdr.renderingLayerMask = 0; } else { rdr.renderingLayerMask = 1; } cullResults[i] = needCull; } } } //Debug.Log("frameCount: " + Time.frameCount + " Buffer index " + Time.frameCount % 3 + " : cullcount = " + culledCnt); } else { ResetRenderer(); } } private void ResetRenderer() { for (var i = 0; i < renderers.Count; i++) { var rdr = renderers[i]; if (rdr) { if (cullResults[i]) { rdr.renderingLayerMask = 1; cullResults[i] = false; } } } } private void OnDisable() { ResetRenderer(); } } }