Files
UltimateFishing/Assets/Scripts/Assembly-CSharp/Moonlit/FootstepPro/FootprintSystem.cs
2026-02-21 16:45:37 +08:00

227 lines
5.4 KiB
C#

using System.Collections.Generic;
using System.Linq;
using Moonlit.Utils;
using UnityEngine;
using UnityEngine.Rendering;
namespace Moonlit.FootstepPro
{
[AddComponentMenu("FootprintSystem/System")]
[ExecuteInEditMode]
public class FootprintSystem : Singleton<FootprintSystem>
{
public enum FadeType
{
Time = 0,
Count = 1,
TimeOrCount = 2
}
[SerializeField]
private Mesh _CubeMesh;
[SerializeField]
private Material _MaskMaterial;
public FadeType Fade;
[Header("Time fade settings")]
public float FadeLength;
[Header("Count fade settings")]
public int FadeCount = 100;
[Header("Settings")]
public bool HideInHierarchy = true;
public bool FrustumCulling = true;
[Header("Debug")]
public bool DrawEditorGizmos = true;
private List<Footprint> _Footprints = new List<Footprint>();
private Dictionary<Camera, CommandBuffer> _Cameras = new Dictionary<Camera, CommandBuffer>();
private List<Camera> _CameraSettings = new List<Camera>();
private List<DynamicMask> _Masks = new List<DynamicMask>();
private void Update()
{
for (int i = 0; i < _Footprints.Count; i++)
{
Footprint footprint = _Footprints[i];
footprint.Advance();
}
}
private void OnWillRenderObject()
{
Camera current = Camera.current;
CameraSettings component = current.GetComponent<CameraSettings>();
if (component != null && component.Disable)
{
ReleaseCamera(current);
return;
}
Plane[] frustumPlanes = GeometryUtility.CalculateFrustumPlanes(current);
CreateCameraCommandBuffer(current);
Render(_Cameras[current], frustumPlanes);
}
private void OnDisable()
{
foreach (KeyValuePair<Camera, CommandBuffer> camera in _Cameras)
{
ReleaseCamera(camera, false);
}
_Cameras.Clear();
}
private void OnValidate()
{
foreach (Footprint footprint in _Footprints)
{
HierarchyHide(footprint);
}
}
public void Register(Footprint footprint)
{
if (!RemoveByCount() && !_Footprints.Contains(footprint))
{
HierarchyHide(footprint);
AddToRenderQueue(footprint);
}
}
public void Unregister(Footprint footprint)
{
RemoveFromRenderQueue(footprint);
}
public void RegisterMask(DynamicMask mask)
{
if (!_Masks.Contains(mask))
{
_Masks.Add(mask);
}
}
public void UnregisterMask(DynamicMask mask)
{
_Masks.Remove(mask);
}
private bool RemoveByCount()
{
if ((Fade == FadeType.Count || Fade == FadeType.TimeOrCount) && _Footprints.Count > FadeCount && _Footprints.Count > 0)
{
Object.Destroy(_Footprints[0]);
return true;
}
return false;
}
private void Render(CommandBuffer commandBuffer, Plane[] frustumPlanes)
{
int num = Shader.PropertyToID("_NormalsCopy");
int num2 = Shader.PropertyToID("_MaskTexture");
commandBuffer.GetTemporaryRT(num, -1, -1);
commandBuffer.GetTemporaryRT(num2, 800, 600);
RenderMaskTexture(commandBuffer, num2);
commandBuffer.Blit(BuiltinRenderTextureType.GBuffer2, num);
RenderTargetIdentifier[] colors = new RenderTargetIdentifier[2]
{
BuiltinRenderTextureType.GBuffer0,
BuiltinRenderTextureType.GBuffer2
};
commandBuffer.SetRenderTarget(colors, BuiltinRenderTextureType.CameraTarget);
for (int i = 0; i < _Footprints.Count; i++)
{
Footprint footprint = _Footprints[i];
if (!FrustumCulling || IsDecalVisible(frustumPlanes, _CubeMesh, footprint.transform.position))
{
commandBuffer.DrawMesh(_CubeMesh, footprint.transform.localToWorldMatrix, footprint.Material);
}
}
commandBuffer.ReleaseTemporaryRT(num);
}
private void CreateCameraCommandBuffer(Camera camera)
{
if (_Cameras.ContainsKey(camera))
{
_Cameras[camera].Clear();
return;
}
_Cameras[camera] = new CommandBuffer();
_Cameras[camera].name = "Screen Space Decals";
camera.AddCommandBuffer(CameraEvent.BeforeLighting, _Cameras[camera]);
}
private void AddToRenderQueue(Footprint footprint)
{
if (!_Footprints.Contains(footprint))
{
_Footprints.Add(footprint);
}
}
private void RemoveFromRenderQueue(Footprint footprint)
{
if (_Footprints.Contains(footprint))
{
_Footprints.Remove(footprint);
}
}
private void RenderMaskTexture(CommandBuffer commandBuffer, int maskID)
{
commandBuffer.SetRenderTarget(maskID);
commandBuffer.ClearRenderTarget(false, true, Color.black);
for (int i = 0; i < _Masks.Count; i++)
{
Renderer component = _Masks[i].GetComponent<Renderer>();
if (component != null)
{
commandBuffer.DrawRenderer(component, _MaskMaterial);
}
}
}
private void ReleaseCamera(KeyValuePair<Camera, CommandBuffer> entry, bool removeFromList = true)
{
if (entry.Key != null && entry.Value != null)
{
entry.Key.RemoveCommandBuffer(CameraEvent.BeforeLighting, entry.Value);
entry.Value.Release();
if (removeFromList)
{
_Cameras.Remove(entry.Key);
}
}
}
private void ReleaseCamera(Camera camera)
{
if (_Cameras.ContainsKey(camera))
{
ReleaseCamera(_Cameras.First((KeyValuePair<Camera, CommandBuffer> x) => x.Key == camera));
}
}
private void HierarchyHide(Footprint footprint)
{
footprint.gameObject.hideFlags = (HideInHierarchy ? HideFlags.HideInHierarchy : HideFlags.None);
}
private bool IsDecalVisible(Plane[] frustumPlanes, Mesh mesh, Vector3 position)
{
Bounds bounds = new Bounds(position, mesh.bounds.size);
return GeometryUtility.TestPlanesAABB(frustumPlanes, bounds);
}
}
}