471 lines
16 KiB
C#
471 lines
16 KiB
C#
using DG.Tweening;
|
|
using UnityEngine;
|
|
using AibisDream.Utility;
|
|
|
|
namespace AibisDream
|
|
{
|
|
/// <summary>
|
|
/// Drives the unified EyeUnifiedSprite path for Peipei eye targets.
|
|
/// </summary>
|
|
public class EyeTargetVisual : MonoBehaviour
|
|
{
|
|
private static readonly int ColorRevealId = Shader.PropertyToID("_ColorReveal");
|
|
private static readonly int GrayAmountId = Shader.PropertyToID("_GrayAmount");
|
|
private static readonly int BlurAmountId = Shader.PropertyToID("_BlurAmount");
|
|
private static readonly int BlurSizeId = Shader.PropertyToID("_BlurSize");
|
|
private static readonly int DistortAmountId = Shader.PropertyToID("_DistortAmount");
|
|
private static readonly int WrongColorAmountId = Shader.PropertyToID("_WrongColorAmount");
|
|
private static readonly int SpriteFadeId = Shader.PropertyToID("_SpriteFade");
|
|
private static readonly int AsciiAmountId = Shader.PropertyToID("_AsciiAmount");
|
|
private static readonly int DreamAmountId = Shader.PropertyToID("_DreamAmount");
|
|
private static readonly int MemoryAmountId = Shader.PropertyToID("_MemoryAmount");
|
|
private static readonly int ScanlineAmountId = Shader.PropertyToID("_ScanlineAmount");
|
|
private static readonly int GlitchAmountId = Shader.PropertyToID("_GlitchAmount");
|
|
private static readonly int HsvShiftId = Shader.PropertyToID("_HsvShift");
|
|
private static readonly int HsvSaturationId = Shader.PropertyToID("_HsvSaturation");
|
|
private static readonly int RoundWaveStrengthId = Shader.PropertyToID("_RoundWaveStrength");
|
|
|
|
private static readonly int RevealWidthId = Shader.PropertyToID("_RevealWidth");
|
|
private static readonly int RevealRotationId = Shader.PropertyToID("_RevealRotation");
|
|
private static readonly int RevealNoiseId = Shader.PropertyToID("_RevealNoise");
|
|
private static readonly int WrongColorId = Shader.PropertyToID("_WrongColor");
|
|
|
|
[SerializeField] private SpriteRenderer spriteRenderer;
|
|
[SerializeField] private SpriteRenderer imageSpriteRenderer;
|
|
[SerializeField] private bool driveImageLayer = true;
|
|
|
|
private Material material;
|
|
private float activeBlurSize = 0.008f;
|
|
|
|
public bool IsReady => material != null && material.HasProperty(ColorRevealId);
|
|
public bool CanDriveImageLayer => driveImageLayer && imageSpriteRenderer != null;
|
|
public Material Material => material;
|
|
|
|
private void Awake()
|
|
{
|
|
EnsureMaterial();
|
|
}
|
|
|
|
public bool EnsureMaterial()
|
|
{
|
|
if (spriteRenderer == null)
|
|
{
|
|
spriteRenderer = GetComponent<SpriteRenderer>();
|
|
}
|
|
|
|
if (spriteRenderer == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
material = Application.isPlaying
|
|
? spriteRenderer.material
|
|
: spriteRenderer.sharedMaterial;
|
|
return IsReady;
|
|
}
|
|
|
|
public void Configure(SpriteRenderer mainRenderer, SpriteRenderer imageRenderer)
|
|
{
|
|
spriteRenderer = mainRenderer;
|
|
imageSpriteRenderer = imageRenderer;
|
|
EnsureMaterial();
|
|
}
|
|
|
|
public void ApplyTuning(EyeVisualSettings settings)
|
|
{
|
|
if (settings == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
activeBlurSize = settings.blurSize;
|
|
|
|
if (!EnsureMaterial())
|
|
{
|
|
return;
|
|
}
|
|
|
|
material.SetFloat(RevealWidthId, settings.revealWidth);
|
|
material.SetFloat(RevealRotationId, settings.revealRotation);
|
|
material.SetFloat(RevealNoiseId, settings.revealNoise);
|
|
material.SetColor(WrongColorId, settings.wrongColor);
|
|
SetFloatRaw(HsvSaturationId, settings.hsvSaturation);
|
|
SyncBlurSizeToMaterial();
|
|
}
|
|
|
|
public void SyncBlurSizeToMaterial()
|
|
{
|
|
if (!EnsureMaterial() || !material.HasProperty(BlurSizeId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
float blur = material.GetFloat(BlurAmountId);
|
|
material.SetFloat(BlurSizeId, blur > 0.01f ? activeBlurSize : 0f);
|
|
}
|
|
|
|
public void KillActiveTweens()
|
|
{
|
|
if (material != null)
|
|
{
|
|
material.DOKill();
|
|
}
|
|
|
|
if (driveImageLayer && imageSpriteRenderer != null)
|
|
{
|
|
imageSpriteRenderer.DOKill();
|
|
}
|
|
|
|
ClearTransientEffects(null);
|
|
}
|
|
|
|
public void ClearTransientEffects(EyeVisualSettings settings)
|
|
{
|
|
if (!EnsureMaterial())
|
|
{
|
|
return;
|
|
}
|
|
|
|
SetFloat(GlitchAmountId, 0f);
|
|
SetFloat(DistortAmountId, 0f);
|
|
SetFloat(ScanlineAmountId, 0f);
|
|
SetFloatRaw(HsvShiftId, 0f);
|
|
SetFloatRaw(RevealNoiseId, settings != null ? settings.revealNoise : 0f);
|
|
}
|
|
|
|
public void ResetVisual(float reveal)
|
|
{
|
|
if (!EnsureMaterial())
|
|
{
|
|
return;
|
|
}
|
|
|
|
SetFloat(ColorRevealId, reveal);
|
|
SetFloat(GrayAmountId, 1f - reveal);
|
|
SetFloat(BlurAmountId, 1f);
|
|
if (material.HasProperty(BlurSizeId))
|
|
{
|
|
material.SetFloat(BlurSizeId, activeBlurSize);
|
|
}
|
|
SetFloat(DistortAmountId, 0f);
|
|
SetFloat(WrongColorAmountId, 0f);
|
|
SetFloat(SpriteFadeId, 1f);
|
|
SetFloat(AsciiAmountId, 0f);
|
|
SetFloat(DreamAmountId, 0f);
|
|
SetFloat(MemoryAmountId, 0f);
|
|
SetFloat(ScanlineAmountId, 0f);
|
|
SetFloat(GlitchAmountId, 0f);
|
|
SetFloat(HsvShiftId, 0f);
|
|
SetFloat(HsvSaturationId, 1f);
|
|
SetFloat(RoundWaveStrengthId, 0f);
|
|
SetImageAlpha(0f);
|
|
}
|
|
|
|
public void SetColorReveal(float value)
|
|
{
|
|
SetFloat(ColorRevealId, value);
|
|
SetFloat(GrayAmountId, 1f - value);
|
|
}
|
|
|
|
public float GetColorReveal()
|
|
{
|
|
if (!EnsureMaterial() || !material.HasProperty(ColorRevealId))
|
|
{
|
|
return 0f;
|
|
}
|
|
|
|
return material.GetFloat(ColorRevealId);
|
|
}
|
|
|
|
public bool IsAtColorReveal(float target, float epsilon = 0.02f)
|
|
{
|
|
return Mathf.Abs(GetColorReveal() - target) <= epsilon;
|
|
}
|
|
|
|
public Tween TweenColorReveal(float value, float duration)
|
|
{
|
|
if (!EnsureMaterial())
|
|
{
|
|
return null;
|
|
}
|
|
|
|
value = Mathf.Clamp01(value);
|
|
Sequence sequence = DOTween.Sequence();
|
|
sequence.Join(material.DOFloat(value, ColorRevealId, duration));
|
|
sequence.Join(material.DOFloat(1f - value, GrayAmountId, duration));
|
|
return sequence;
|
|
}
|
|
|
|
public void SetBlur(float value)
|
|
{
|
|
SetFloat(BlurAmountId, value);
|
|
if (EnsureMaterial() && material.HasProperty(BlurSizeId))
|
|
{
|
|
material.SetFloat(BlurSizeId, value > 0.01f ? activeBlurSize : 0f);
|
|
}
|
|
}
|
|
|
|
public Tween TweenBlur(float value, float duration)
|
|
{
|
|
if (!EnsureMaterial())
|
|
{
|
|
return null;
|
|
}
|
|
|
|
Tween tween = material.DOFloat(value, BlurAmountId, duration);
|
|
tween.OnUpdate(SyncBlurSizeToMaterial);
|
|
tween.OnComplete(SyncBlurSizeToMaterial);
|
|
return tween;
|
|
}
|
|
|
|
/// <summary>
|
|
/// One focus transition: sharpen, brief defocus, settle. Total wall time equals <paramref name="duration"/>.
|
|
/// </summary>
|
|
public Tween TweenBlurFocusSettle(EyeVisualSettings settings, float duration)
|
|
{
|
|
if (!EnsureMaterial() || settings == null || duration <= 0f)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
float sharpBlur = settings.focusedBlurAmount;
|
|
float bumpBlur = Mathf.Clamp(
|
|
sharpBlur + settings.focusSettleDefocusBump,
|
|
sharpBlur,
|
|
settings.idleBlurAmount);
|
|
|
|
Vector3 ratios = settings.focusSettlePhaseRatios;
|
|
float ratioSum = ratios.x + ratios.y + ratios.z;
|
|
if (ratioSum <= 0.001f)
|
|
{
|
|
ratios = new Vector3(0.5f, 0.22f, 0.28f);
|
|
ratioSum = ratios.x + ratios.y + ratios.z;
|
|
}
|
|
|
|
float primaryDuration = duration * (ratios.x / ratioSum);
|
|
float defocusDuration = duration * (ratios.y / ratioSum);
|
|
float refocusDuration = duration * (ratios.z / ratioSum);
|
|
|
|
Sequence sequence = DOTween.Sequence();
|
|
|
|
Tween primaryFocus = TweenBlur(sharpBlur, primaryDuration);
|
|
if (primaryFocus != null)
|
|
{
|
|
primaryFocus.SetEase(Ease.InOutSine);
|
|
sequence.Append(primaryFocus);
|
|
}
|
|
|
|
Tween microDefocus = TweenBlur(bumpBlur, defocusDuration);
|
|
if (microDefocus != null)
|
|
{
|
|
microDefocus.SetEase(Ease.InOutSine);
|
|
sequence.Append(microDefocus);
|
|
}
|
|
|
|
Tween refocus = TweenBlur(sharpBlur, refocusDuration);
|
|
if (refocus != null)
|
|
{
|
|
refocus.SetEase(Ease.InOutSine);
|
|
sequence.Append(refocus);
|
|
}
|
|
|
|
return sequence;
|
|
}
|
|
|
|
public void SetWrongColor(float value)
|
|
{
|
|
SetFloat(WrongColorAmountId, value);
|
|
}
|
|
|
|
public Tween TweenWrongColor(float value, float duration)
|
|
{
|
|
return TweenFloat(WrongColorAmountId, value, duration);
|
|
}
|
|
|
|
public Tween PlayColorSweepTransition(EyeVisualSettings settings, float duration, bool colorIn)
|
|
{
|
|
if (!EnsureMaterial() || settings == null || duration <= 0f)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
duration = Mathf.Max(0.01f, duration);
|
|
float chromaPeak = settings.colorSweepChromaPeak;
|
|
float ramp = Mathf.Clamp(settings.colorSweepChromaRamp, 0.1f, 0.6f);
|
|
float rampDuration = duration * ramp;
|
|
float settleDuration = duration - rampDuration;
|
|
|
|
float targetReveal = colorIn ? settings.colorRevealMax : settings.colorRevealMin;
|
|
float targetBlur = colorIn ? settings.focusedBlurAmount : settings.idleBlurAmount;
|
|
Ease sweepEase = colorIn ? Ease.InOutSine : Ease.InSine;
|
|
|
|
ClearTransientEffects(null);
|
|
SetFloatRaw(RevealNoiseId, 0f);
|
|
|
|
Sequence sequence = DOTween.Sequence();
|
|
Tween colorTween = TweenColorReveal(targetReveal, duration);
|
|
if (colorTween != null)
|
|
{
|
|
colorTween.SetEase(sweepEase);
|
|
sequence.Join(colorTween);
|
|
}
|
|
|
|
Tween blurTween = TweenBlur(targetBlur, duration);
|
|
if (blurTween != null)
|
|
{
|
|
blurTween.SetEase(sweepEase);
|
|
sequence.Join(blurTween);
|
|
}
|
|
|
|
if (chromaPeak > 0.001f)
|
|
{
|
|
Sequence chromaEnvelope = DOTween.Sequence();
|
|
chromaEnvelope.Append(material.DOFloat(chromaPeak, GlitchAmountId, rampDuration)
|
|
.SetEase(Ease.OutSine));
|
|
chromaEnvelope.Append(material.DOFloat(0f, GlitchAmountId, settleDuration)
|
|
.SetEase(Ease.InSine));
|
|
sequence.Join(chromaEnvelope);
|
|
}
|
|
|
|
sequence.OnComplete(() => ClearTransientEffects(settings));
|
|
return sequence;
|
|
}
|
|
|
|
public void SetImageAlpha(float alpha)
|
|
{
|
|
if (!driveImageLayer || imageSpriteRenderer == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
alpha = Mathf.Clamp01(alpha);
|
|
if (alpha > 0f)
|
|
{
|
|
imageSpriteRenderer.gameObject.SetActive(true);
|
|
imageSpriteRenderer.enabled = true;
|
|
}
|
|
|
|
imageSpriteRenderer.SetAlpha(alpha);
|
|
|
|
if (alpha <= 0f)
|
|
{
|
|
imageSpriteRenderer.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
|
|
public Tween TweenImageAlpha(float alpha, float duration)
|
|
{
|
|
if (!driveImageLayer || imageSpriteRenderer == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
alpha = Mathf.Clamp01(alpha);
|
|
if (alpha > 0f)
|
|
{
|
|
imageSpriteRenderer.gameObject.SetActive(true);
|
|
imageSpriteRenderer.enabled = true;
|
|
}
|
|
|
|
return imageSpriteRenderer.DOFade(alpha, duration)
|
|
.OnComplete(() =>
|
|
{
|
|
if (alpha <= 0f && imageSpriteRenderer != null)
|
|
{
|
|
imageSpriteRenderer.gameObject.SetActive(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
public void SetUfWeights(float ascii, float dream, float memory)
|
|
{
|
|
SetFloat(AsciiAmountId, ascii);
|
|
SetFloat(DreamAmountId, dream);
|
|
SetFloat(MemoryAmountId, memory);
|
|
SetFloat(ScanlineAmountId, Mathf.Max(ascii, memory));
|
|
}
|
|
|
|
public Tween TweenUfWeights(float ascii, float dream, float memory, float duration)
|
|
{
|
|
if (!EnsureMaterial())
|
|
{
|
|
return null;
|
|
}
|
|
|
|
Sequence sequence = DOTween.Sequence();
|
|
sequence.Join(material.DOFloat(Mathf.Clamp01(ascii), AsciiAmountId, duration));
|
|
sequence.Join(material.DOFloat(Mathf.Clamp01(dream), DreamAmountId, duration));
|
|
sequence.Join(material.DOFloat(Mathf.Clamp01(memory), MemoryAmountId, duration));
|
|
sequence.Join(material.DOFloat(Mathf.Clamp01(Mathf.Max(ascii, memory)), ScanlineAmountId, duration));
|
|
return sequence;
|
|
}
|
|
|
|
public void SetSaturation(float saturation)
|
|
{
|
|
SetFloatRaw(HsvSaturationId, Mathf.Clamp(saturation, 0f, 2f));
|
|
}
|
|
|
|
public Tween TweenSaturation(float saturation, float duration)
|
|
{
|
|
return TweenFloat(HsvSaturationId, Mathf.Clamp(saturation, 0f, 2f), duration);
|
|
}
|
|
|
|
public Sequence StartGlitch(float duration = 1f)
|
|
{
|
|
if (!EnsureMaterial())
|
|
{
|
|
return null;
|
|
}
|
|
|
|
duration = Mathf.Max(0.01f, duration);
|
|
Sequence sequence = DOTween.Sequence();
|
|
sequence.Join(material.DOFloat(1f, GlitchAmountId, duration));
|
|
sequence.Join(material.DOFloat(0.02f, DistortAmountId, duration));
|
|
sequence.Join(material.DOFloat(360f, HsvShiftId, duration).SetLoops(-1, LoopType.Yoyo));
|
|
return sequence;
|
|
}
|
|
|
|
public void StopGlitch(float duration)
|
|
{
|
|
TweenFloat(GlitchAmountId, 0f, duration);
|
|
TweenFloat(DistortAmountId, 0f, duration);
|
|
TweenFloat(HsvShiftId, 0f, duration);
|
|
}
|
|
|
|
public Tween TweenRoundWave(float value, float duration)
|
|
{
|
|
return TweenFloat(RoundWaveStrengthId, value, duration);
|
|
}
|
|
|
|
private Tween TweenFloat(int propertyId, float value, float duration)
|
|
{
|
|
if (!EnsureMaterial() || !material.HasProperty(propertyId))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return material.DOFloat(value, propertyId, duration);
|
|
}
|
|
|
|
private void SetFloat(int propertyId, float value)
|
|
{
|
|
if (!EnsureMaterial() || !material.HasProperty(propertyId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
material.SetFloat(propertyId, Mathf.Clamp01(value));
|
|
}
|
|
|
|
private void SetFloatRaw(int propertyId, float value)
|
|
{
|
|
if (!EnsureMaterial() || !material.HasProperty(propertyId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
material.SetFloat(propertyId, value);
|
|
}
|
|
}
|
|
}
|