227 lines
5.4 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|