215 lines
6.0 KiB
C#
215 lines
6.0 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.Universal;
|
|
|
|
namespace Unheimlich.UI
|
|
{
|
|
[RequireComponent(typeof(Camera))]
|
|
public class DialogueBlurEffectURP : MonoBehaviour
|
|
{
|
|
public static DialogueBlurEffectURP Instance { get; private set; }
|
|
|
|
[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;
|
|
|
|
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;
|
|
|
|
void Awake()
|
|
{
|
|
if (Instance != null && Instance != this)
|
|
{
|
|
Destroy(this);
|
|
return;
|
|
}
|
|
Instance = this;
|
|
|
|
_baseCam = GetComponent<Camera>();
|
|
|
|
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()
|
|
{
|
|
if (_autoCreateDialogueCamera)
|
|
SetupDialogueOverlayCamera();
|
|
}
|
|
|
|
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;
|
|
|
|
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 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 (_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;
|
|
}
|
|
}
|
|
}
|