232 lines
6.8 KiB
C#
Raw Normal View History

2025-06-23 19:18:41 +08:00
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<MeshRenderer> 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<MeshRenderer>())
{
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];
2025-06-24 21:26:55 +08:00
if (rdr && cullResult.ResultArray.IsCreated)
2025-06-23 19:18:41 +08:00
{
2025-06-25 15:01:58 +08:00
bool needCull = cullResult.ResultArray[i] > 0.5f;
2025-06-23 19:18:41 +08:00
#if UNITY_EDITOR
if (ShowDebug && rdr.GetComponent<CullDebug>() 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();
}
}
}