133 lines
4.3 KiB
C#
133 lines
4.3 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
using UnityEngine.Rendering.RenderGraphModule.Util;
|
|
using UnityEngine.Rendering.Universal;
|
|
|
|
/// <summary>
|
|
/// Scene-local "altered perception" fullscreen effect (Custom/LiminalPerception) for the main camera.
|
|
/// The pass is injected only while this component is enabled, so the shared renderer asset and the
|
|
/// other scenes are untouched. Fade it in/out from UnityEvents; while active, its intensity slowly
|
|
/// swells and recedes in irregular waves.
|
|
/// Photosensitivity: the shader and the swell only use slow, smooth variations (no flashes).
|
|
/// </summary>
|
|
public class LiminalPerception : MonoBehaviour
|
|
{
|
|
[SerializeField] private Material _material;
|
|
[SerializeField, Range(0f, 1f)] private float _initialWeight = 0f;
|
|
[SerializeField, Min(0f)] private float _fadeDuration = 4f;
|
|
|
|
[Tooltip("Speed of the irregular intensity waves (lower = slower)")]
|
|
[SerializeField, Min(0f)] private float _swellSpeed = 0.05f;
|
|
|
|
private static readonly int WeightId = Shader.PropertyToID("_Weight");
|
|
private static readonly int SwellId = Shader.PropertyToID("_Swell");
|
|
|
|
private LiminalPerceptionPass _pass;
|
|
private Material _instance;
|
|
private float _weight;
|
|
private Coroutine _fade;
|
|
private float _seed;
|
|
|
|
private void OnEnable()
|
|
{
|
|
if (!_material)
|
|
return;
|
|
|
|
_instance = new Material(_material) { hideFlags = HideFlags.HideAndDontSave };
|
|
_pass = new LiminalPerceptionPass(_instance);
|
|
_weight = _initialWeight;
|
|
_seed = Random.Range(0f, 100f);
|
|
|
|
RenderPipelineManager.beginCameraRendering += OnBeginCamera;
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
RenderPipelineManager.beginCameraRendering -= OnBeginCamera;
|
|
|
|
if (_instance)
|
|
Destroy(_instance);
|
|
|
|
_instance = null;
|
|
_pass = null;
|
|
}
|
|
|
|
public void FadeIn() => FadeTo(1f);
|
|
|
|
public void FadeOut() => FadeTo(0f);
|
|
|
|
public void FadeTo(float weight)
|
|
{
|
|
if (_fade != null)
|
|
StopCoroutine(_fade);
|
|
|
|
_fade = StartCoroutine(Fade(Mathf.Clamp01(weight)));
|
|
}
|
|
|
|
private IEnumerator Fade(float target)
|
|
{
|
|
float start = _weight;
|
|
|
|
for (float t = 0f; t < _fadeDuration; t += Time.deltaTime)
|
|
{
|
|
_weight = Mathf.Lerp(start, target, Mathf.SmoothStep(0f, 1f, t / _fadeDuration));
|
|
yield return null;
|
|
}
|
|
|
|
_weight = target;
|
|
_fade = null;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!_instance)
|
|
return;
|
|
|
|
// Irregular waves: mostly calm, sometimes a slow swell lasting several seconds
|
|
float noise = Mathf.PerlinNoise(Time.time * _swellSpeed, _seed);
|
|
float swell = Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.35f, 0.75f, noise));
|
|
|
|
_instance.SetFloat(WeightId, _weight);
|
|
_instance.SetFloat(SwellId, swell);
|
|
}
|
|
|
|
private void OnBeginCamera(ScriptableRenderContext context, Camera camera)
|
|
{
|
|
if (_weight <= 0.001f || camera.cameraType != CameraType.Game || !camera.CompareTag("MainCamera"))
|
|
return;
|
|
|
|
camera.GetUniversalAdditionalCameraData().scriptableRenderer.EnqueuePass(_pass);
|
|
}
|
|
|
|
private class LiminalPerceptionPass : ScriptableRenderPass
|
|
{
|
|
private readonly Material _material;
|
|
|
|
public LiminalPerceptionPass(Material material)
|
|
{
|
|
_material = material;
|
|
renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
|
|
requiresIntermediateTexture = true;
|
|
}
|
|
|
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
|
|
{
|
|
UniversalResourceData resources = frameData.Get<UniversalResourceData>();
|
|
|
|
if (resources.isActiveTargetBackBuffer)
|
|
return;
|
|
|
|
TextureHandle source = resources.activeColorTexture;
|
|
TextureDesc desc = renderGraph.GetTextureDesc(source);
|
|
desc.name = "_LiminalPerception";
|
|
desc.clearBuffer = false;
|
|
TextureHandle destination = renderGraph.CreateTexture(desc);
|
|
|
|
renderGraph.AddBlitPass(new RenderGraphUtils.BlitMaterialParameters(source, destination, _material, 0), "Liminal Perception");
|
|
resources.cameraColor = destination;
|
|
}
|
|
}
|
|
}
|