Files
Ipseity-Demo/Assets/_Content/Scripts/Features/Dialogue/UI/DialogueBlurEffectURP.cs
T

266 lines
8.0 KiB
C#

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using Unheimlich.Core;
using Unheimlich.Features.Player;
namespace Unheimlich.Features.Dialogue.UI
{
public class DialogueBlurEffectURP : Singleton<DialogueBlurEffectURP>
{
[Header("Volume Settings")]
[SerializeField] private Volume _globalVolume;
[Header("Depth of Field (Gaussian)")]
[SerializeField] private float _gaussianStart = 0f;
[SerializeField] private float _gaussianEnd = 15f;
[SerializeField] private float _maxGaussianRadius = 4f;
[Header("Brightness (Color Adjustments)")]
[SerializeField] private float _startPostExposure = 0f;
[SerializeField] private float _targetPostExposure = 0.3f;
[Header("Animation Settings")]
[SerializeField] private float _fadeDuration = 1.0f;
[SerializeField] private AnimationCurve _fadeCurve;
[Header("UI Configuration")]
[Tooltip("Layer(s) for dialogue (World Space UI) to render without blur")]
[SerializeField] private LayerMask _dialogueLayers;
[SerializeField] private bool _autoCreateDialogueCamera = true;
[Header("Hands Configuration")]
[Tooltip("Layer for player hands to render on top of dialogue")]
[SerializeField] private LayerMask _handsLayer;
[SerializeField] private bool _autoCreateHandsCamera = true;
private DepthOfField _dof;
private ColorAdjustments _color;
private VolumeProfile _profile;
private float _current = 0f;
private float _target = 0f;
private float _start = 0f;
private float _timer = 0f;
private bool _fading = false;
private Camera _baseCam;
private Camera _dialogueCam;
private Camera _handsCam;
protected override void OnAwake()
{
if (_fadeCurve == null || _fadeCurve.keys.Length == 0)
_fadeCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
if (_globalVolume == null)
{
Debug.LogError("[DialogueBlur] ERROR: Global Volume NOT ASSIGNED in inspector!");
enabled = false;
return;
}
if (_globalVolume.profile == null)
{
Debug.LogError("[DialogueBlur] ERROR: Global Volume has NO VolumeProfile assigned!");
enabled = false;
return;
}
_profile = _globalVolume.profile;
if (!_profile.TryGet(out _dof))
{
Debug.LogError("[DialogueBlur] ERROR: Depth Of Field NOT FOUND in Volume Profile!");
enabled = false;
return;
}
if (!_profile.TryGet(out _color))
{
Debug.LogWarning("[DialogueBlur] WARNING: Color Adjustments not found (not critical)");
}
_dof.mode.Override(DepthOfFieldMode.Gaussian);
_dof.gaussianStart.Override(_gaussianStart);
_dof.gaussianEnd.Override(_gaussianEnd);
_dof.gaussianMaxRadius.Override(0f);
_dof.active = false;
if (_color != null)
{
_color.postExposure.Override(_startPostExposure);
_color.active = false;
}
_globalVolume.weight = 0f;
_globalVolume.enabled = true;
}
void Start()
{
_baseCam = PlayerController.Instance.PlayerCamera;
if (_autoCreateDialogueCamera)
SetupDialogueOverlayCamera();
if (_autoCreateHandsCamera)
SetupHandsOverlayCamera();
}
void SetupDialogueOverlayCamera()
{
var baseData = _baseCam.GetComponent<UniversalAdditionalCameraData>();
if (baseData == null)
baseData = _baseCam.gameObject.AddComponent<UniversalAdditionalCameraData>();
baseData.renderType = CameraRenderType.Base;
baseData.renderPostProcessing = true;
if (_dialogueLayers.value == 0)
Debug.LogWarning("[DialogueBlur] WARNING: dialogueLayers is EMPTY! Ghost words will be blurred!");
_baseCam.cullingMask &= ~_dialogueLayers;
if (_handsLayer.value != 0)
_baseCam.cullingMask &= ~_handsLayer;
var go = new GameObject("Dialogue Camera (Overlay)");
go.transform.SetParent(_baseCam.transform);
go.transform.localPosition = Vector3.zero;
go.transform.localRotation = Quaternion.identity;
_dialogueCam = go.AddComponent<Camera>();
_dialogueCam.CopyFrom(_baseCam);
_dialogueCam.clearFlags = CameraClearFlags.Depth;
_dialogueCam.cullingMask = _dialogueLayers;
var overlayData = go.AddComponent<UniversalAdditionalCameraData>();
overlayData.renderType = CameraRenderType.Overlay;
overlayData.renderPostProcessing = false;
baseData.cameraStack.Add(_dialogueCam);
}
void SetupHandsOverlayCamera()
{
if (_handsLayer.value == 0)
{
Debug.LogWarning("[DialogueBlur] WARNING: handsLayer is EMPTY! Hands camera will not be created.");
return;
}
var baseData = _baseCam.GetComponent<UniversalAdditionalCameraData>();
if (baseData == null)
{
Debug.LogError("[DialogueBlur] ERROR: Base camera has no UniversalAdditionalCameraData!");
return;
}
var go = new GameObject("Hands Camera (Overlay)");
go.transform.SetParent(_baseCam.transform);
go.transform.localPosition = Vector3.zero;
go.transform.localRotation = Quaternion.identity;
_handsCam = go.AddComponent<Camera>();
_handsCam.CopyFrom(_baseCam);
_handsCam.clearFlags = CameraClearFlags.Depth;
_handsCam.cullingMask = _handsLayer;
var overlayData = go.AddComponent<UniversalAdditionalCameraData>();
overlayData.renderType = CameraRenderType.Overlay;
overlayData.renderPostProcessing = false;
baseData.cameraStack.Add(_handsCam);
}
void Update()
{
if (!_fading) return;
_timer += Time.deltaTime;
float t = Mathf.Clamp01(_timer / Mathf.Max(0.0001f, _fadeDuration));
float cv = _fadeCurve.Evaluate(t);
_current = Mathf.Lerp(_start, _target, cv);
ApplyEffects(_current);
if (t >= 1f)
{
_current = _target;
ApplyEffects(_current);
_fading = false;
}
}
void ApplyEffects(float s)
{
s = Mathf.Clamp01(s);
bool active = s > 0.01f;
_globalVolume.weight = s;
if (active)
{
_dof.active = true;
_dof.gaussianStart.value = _gaussianStart;
_dof.gaussianEnd.value = _gaussianEnd;
float radius = Mathf.Lerp(0f, _maxGaussianRadius, s);
_dof.gaussianMaxRadius.value = radius;
if (_color != null)
{
_color.active = true;
_color.postExposure.value = Mathf.Lerp(_startPostExposure, _targetPostExposure, s);
}
}
else
{
_dof.gaussianMaxRadius.value = 0f;
_dof.active = false;
if (_color != null)
{
_color.postExposure.value = _startPostExposure;
_color.active = false;
}
}
}
public void ShowBlur()
{
if (_dialogueCam == null && _autoCreateDialogueCamera)
{
if (_baseCam == null && PlayerController.Instance != null)
_baseCam = PlayerController.Instance.PlayerCamera;
if (_baseCam != null)
{
SetupDialogueOverlayCamera();
if (_autoCreateHandsCamera)
SetupHandsOverlayCamera();
}
else
Debug.LogWarning("[DialogueBlur] WARNING: Cannot create dialogue camera - PlayerCamera not ready!");
}
if (_fading && _target == 1f) return;
_start = _current;
_target = 1f;
_timer = 0f;
_fading = true;
}
public void HideBlur()
{
if (_fading && _target == 0f) return;
_start = _current;
_target = 0f;
_timer = 0f;
_fading = true;
}
}
}