375 lines
13 KiB
C#
375 lines
13 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using DG.Tweening;
|
|
|
|
namespace AibisDream.MiniGame.Language
|
|
{
|
|
/// <summary>
|
|
/// CRT复古显示器效果控制器
|
|
/// 放在 LanguageParticleSystem 的最顶层 Image 上
|
|
/// </summary>
|
|
[RequireComponent(typeof(Image))]
|
|
public class CRTOverlayController : MonoBehaviour
|
|
{
|
|
[Header("效果强度预设")]
|
|
[SerializeField] private CRTPreset currentPreset = CRTPreset.Retro;
|
|
|
|
[Header("自定义参数")]
|
|
[SerializeField, Range(0f, 1f)] private float scanlineIntensity = 0.3f;
|
|
[SerializeField, Range(50f, 800f)] private float scanlineCount = 300f;
|
|
[SerializeField, Range(0f, 5f)] private float scanlineSpeed = 0.5f;
|
|
|
|
[SerializeField, Range(0f, 1f)] private float noiseIntensity = 0.15f;
|
|
[SerializeField, Range(0f, 50f)] private float noiseSpeed = 15f;
|
|
[SerializeField, Range(1f, 100f)] private float noiseScale = 50f;
|
|
|
|
[SerializeField, Range(0f, 0.02f)] private float chromaticAberration = 0.003f;
|
|
|
|
[SerializeField, Range(0f, 1f)] private float vignetteIntensity = 0.3f;
|
|
[SerializeField, Range(0.01f, 1f)] private float vignetteSmoothness = 0.4f;
|
|
|
|
[SerializeField, Range(0f, 0.1f)] private float curvatureAmount = 0.02f;
|
|
|
|
[SerializeField, Range(0f, 0.1f)] private float flickerIntensity = 0.02f;
|
|
[SerializeField, Range(0f, 30f)] private float flickerSpeed = 8f;
|
|
|
|
[SerializeField, Range(0f, 1f)] private float glowIntensity = 0.1f;
|
|
[SerializeField] private Color glowColor = new Color(0.2f, 0.8f, 1f, 1f);
|
|
|
|
[Header("动态效果")]
|
|
[SerializeField] private bool enableDynamicNoise = true;
|
|
[SerializeField] private float noiseVariation = 0.05f;
|
|
[SerializeField] private float noiseVariationSpeed = 2f;
|
|
|
|
private Image overlayImage;
|
|
private Material material;
|
|
private Material instanceMaterial;
|
|
|
|
// Shader 属性 ID(缓存以提高性能)
|
|
private static readonly int ScanlineIntensityID = Shader.PropertyToID("_ScanlineIntensity");
|
|
private static readonly int ScanlineCountID = Shader.PropertyToID("_ScanlineCount");
|
|
private static readonly int ScanlineSpeedID = Shader.PropertyToID("_ScanlineSpeed");
|
|
private static readonly int NoiseIntensityID = Shader.PropertyToID("_NoiseIntensity");
|
|
private static readonly int NoiseSpeedID = Shader.PropertyToID("_NoiseSpeed");
|
|
private static readonly int NoiseScaleID = Shader.PropertyToID("_NoiseScale");
|
|
private static readonly int ChromaticAberrationID = Shader.PropertyToID("_ChromaticAberration");
|
|
private static readonly int VignetteIntensityID = Shader.PropertyToID("_VignetteIntensity");
|
|
private static readonly int VignetteSmoothnessID = Shader.PropertyToID("_VignetteSmoothness");
|
|
private static readonly int CurvatureAmountID = Shader.PropertyToID("_CurvatureAmount");
|
|
private static readonly int FlickerIntensityID = Shader.PropertyToID("_FlickerIntensity");
|
|
private static readonly int FlickerSpeedID = Shader.PropertyToID("_FlickerSpeed");
|
|
private static readonly int GlowIntensityID = Shader.PropertyToID("_GlowIntensity");
|
|
private static readonly int GlowColorID = Shader.PropertyToID("_GlowColor");
|
|
|
|
public enum CRTPreset
|
|
{
|
|
Custom, // 使用自定义参数
|
|
Subtle, // 轻微效果
|
|
Retro, // 复古效果(默认)
|
|
Damaged, // 受损/故障效果
|
|
Hologram // 全息投影效果
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
overlayImage = GetComponent<Image>();
|
|
SetupMaterial();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
ApplyPreset(currentPreset);
|
|
}
|
|
|
|
private void SetupMaterial()
|
|
{
|
|
// 查找 CRT Shader
|
|
Shader crtShader = Shader.Find("UI/CRTOverlayEffect");
|
|
if (crtShader == null)
|
|
{
|
|
Debug.LogError("CRTOverlayController: 找不到 UI/CRTOverlayEffect shader!");
|
|
return;
|
|
}
|
|
|
|
// 创建材质实例
|
|
instanceMaterial = new Material(crtShader);
|
|
instanceMaterial.name = "CRTOverlay_Instance";
|
|
overlayImage.material = instanceMaterial;
|
|
material = instanceMaterial;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (material == null) return;
|
|
|
|
// 动态噪点变化
|
|
if (enableDynamicNoise)
|
|
{
|
|
float dynamicNoise = noiseIntensity +
|
|
Mathf.Sin(Time.time * noiseVariationSpeed) * noiseVariation;
|
|
material.SetFloat(NoiseIntensityID, dynamicNoise);
|
|
}
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
if (Application.isPlaying && material != null)
|
|
{
|
|
if (currentPreset == CRTPreset.Custom)
|
|
{
|
|
ApplyCustomParameters();
|
|
}
|
|
else
|
|
{
|
|
ApplyPreset(currentPreset);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 应用预设效果
|
|
/// </summary>
|
|
public void ApplyPreset(CRTPreset preset)
|
|
{
|
|
currentPreset = preset;
|
|
|
|
switch (preset)
|
|
{
|
|
case CRTPreset.Subtle:
|
|
SetSubtlePreset();
|
|
break;
|
|
case CRTPreset.Retro:
|
|
SetRetroPreset();
|
|
break;
|
|
case CRTPreset.Damaged:
|
|
SetDamagedPreset();
|
|
break;
|
|
case CRTPreset.Hologram:
|
|
SetHologramPreset();
|
|
break;
|
|
case CRTPreset.Custom:
|
|
ApplyCustomParameters();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void SetSubtlePreset()
|
|
{
|
|
scanlineIntensity = 0.15f;
|
|
scanlineCount = 200f;
|
|
scanlineSpeed = 0.3f;
|
|
noiseIntensity = 0.08f;
|
|
noiseSpeed = 10f;
|
|
noiseScale = 40f;
|
|
chromaticAberration = 0.001f;
|
|
vignetteIntensity = 0.2f;
|
|
vignetteSmoothness = 0.5f;
|
|
curvatureAmount = 0.01f;
|
|
flickerIntensity = 0.01f;
|
|
flickerSpeed = 5f;
|
|
glowIntensity = 0.05f;
|
|
glowColor = new Color(0.3f, 0.9f, 1f, 1f);
|
|
|
|
ApplyCustomParameters();
|
|
}
|
|
|
|
private void SetRetroPreset()
|
|
{
|
|
// 参考用户提供的图片 - 典型的复古CRT效果
|
|
scanlineIntensity = 0.35f;
|
|
scanlineCount = 300f;
|
|
scanlineSpeed = 0.5f;
|
|
noiseIntensity = 0.18f;
|
|
noiseSpeed = 15f;
|
|
noiseScale = 50f;
|
|
chromaticAberration = 0.004f;
|
|
vignetteIntensity = 0.35f;
|
|
vignetteSmoothness = 0.4f;
|
|
curvatureAmount = 0.025f;
|
|
flickerIntensity = 0.025f;
|
|
flickerSpeed = 8f;
|
|
glowIntensity = 0.12f;
|
|
glowColor = new Color(0.2f, 0.8f, 1f, 1f);
|
|
|
|
ApplyCustomParameters();
|
|
}
|
|
|
|
private void SetDamagedPreset()
|
|
{
|
|
scanlineIntensity = 0.5f;
|
|
scanlineCount = 250f;
|
|
scanlineSpeed = 1.5f;
|
|
noiseIntensity = 0.3f;
|
|
noiseSpeed = 25f;
|
|
noiseScale = 60f;
|
|
chromaticAberration = 0.01f;
|
|
vignetteIntensity = 0.5f;
|
|
vignetteSmoothness = 0.3f;
|
|
curvatureAmount = 0.04f;
|
|
flickerIntensity = 0.06f;
|
|
flickerSpeed = 15f;
|
|
glowIntensity = 0.08f;
|
|
glowColor = new Color(1f, 0.5f, 0.3f, 1f);
|
|
|
|
ApplyCustomParameters();
|
|
}
|
|
|
|
private void SetHologramPreset()
|
|
{
|
|
scanlineIntensity = 0.4f;
|
|
scanlineCount = 400f;
|
|
scanlineSpeed = 2f;
|
|
noiseIntensity = 0.12f;
|
|
noiseSpeed = 20f;
|
|
noiseScale = 30f;
|
|
chromaticAberration = 0.008f;
|
|
vignetteIntensity = 0.15f;
|
|
vignetteSmoothness = 0.6f;
|
|
curvatureAmount = 0f;
|
|
flickerIntensity = 0.04f;
|
|
flickerSpeed = 12f;
|
|
glowIntensity = 0.25f;
|
|
glowColor = new Color(0.3f, 1f, 0.8f, 1f);
|
|
|
|
ApplyCustomParameters();
|
|
}
|
|
|
|
private void ApplyCustomParameters()
|
|
{
|
|
if (material == null) return;
|
|
|
|
material.SetFloat(ScanlineIntensityID, scanlineIntensity);
|
|
material.SetFloat(ScanlineCountID, scanlineCount);
|
|
material.SetFloat(ScanlineSpeedID, scanlineSpeed);
|
|
material.SetFloat(NoiseIntensityID, noiseIntensity);
|
|
material.SetFloat(NoiseSpeedID, noiseSpeed);
|
|
material.SetFloat(NoiseScaleID, noiseScale);
|
|
material.SetFloat(ChromaticAberrationID, chromaticAberration);
|
|
material.SetFloat(VignetteIntensityID, vignetteIntensity);
|
|
material.SetFloat(VignetteSmoothnessID, vignetteSmoothness);
|
|
material.SetFloat(CurvatureAmountID, curvatureAmount);
|
|
material.SetFloat(FlickerIntensityID, flickerIntensity);
|
|
material.SetFloat(FlickerSpeedID, flickerSpeed);
|
|
material.SetFloat(GlowIntensityID, glowIntensity);
|
|
material.SetColor(GlowColorID, glowColor);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置效果强度(0-1,整体缩放所有效果)
|
|
/// </summary>
|
|
public void SetEffectIntensity(float intensity)
|
|
{
|
|
intensity = Mathf.Clamp01(intensity);
|
|
|
|
if (material == null) return;
|
|
|
|
// 根据 intensity 缩放所有效果
|
|
material.SetFloat(ScanlineIntensityID, scanlineIntensity * intensity);
|
|
material.SetFloat(NoiseIntensityID, noiseIntensity * intensity);
|
|
material.SetFloat(ChromaticAberrationID, chromaticAberration * intensity);
|
|
material.SetFloat(VignetteIntensityID, vignetteIntensity * intensity);
|
|
material.SetFloat(CurvatureAmountID, curvatureAmount * intensity);
|
|
material.SetFloat(FlickerIntensityID, flickerIntensity * intensity);
|
|
material.SetFloat(GlowIntensityID, glowIntensity * intensity);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 动画过渡到指定强度
|
|
/// </summary>
|
|
public Tween TweenEffectIntensity(float targetIntensity, float duration)
|
|
{
|
|
float currentIntensity = 1f;
|
|
return DOTween.To(
|
|
() => currentIntensity,
|
|
x => {
|
|
currentIntensity = x;
|
|
SetEffectIntensity(x);
|
|
},
|
|
targetIntensity,
|
|
duration
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 触发故障效果(短暂的强烈干扰)
|
|
/// </summary>
|
|
public void TriggerGlitch(float duration = 0.3f)
|
|
{
|
|
if (material == null) return;
|
|
|
|
// 保存当前值
|
|
float originalNoise = noiseIntensity;
|
|
float originalChroma = chromaticAberration;
|
|
float originalFlicker = flickerIntensity;
|
|
|
|
// 设置故障效果
|
|
material.SetFloat(NoiseIntensityID, 0.5f);
|
|
material.SetFloat(ChromaticAberrationID, 0.015f);
|
|
material.SetFloat(FlickerIntensityID, 0.1f);
|
|
|
|
// 恢复原始值
|
|
DOVirtual.DelayedCall(duration, () =>
|
|
{
|
|
if (material != null)
|
|
{
|
|
material.SetFloat(NoiseIntensityID, originalNoise);
|
|
material.SetFloat(ChromaticAberrationID, originalChroma);
|
|
material.SetFloat(FlickerIntensityID, originalFlicker);
|
|
}
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置噪点强度
|
|
/// </summary>
|
|
public void SetNoiseIntensity(float intensity)
|
|
{
|
|
noiseIntensity = Mathf.Clamp01(intensity);
|
|
if (material != null)
|
|
{
|
|
material.SetFloat(NoiseIntensityID, noiseIntensity);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置扫描线强度
|
|
/// </summary>
|
|
public void SetScanlineIntensity(float intensity)
|
|
{
|
|
scanlineIntensity = Mathf.Clamp01(intensity);
|
|
if (material != null)
|
|
{
|
|
material.SetFloat(ScanlineIntensityID, scanlineIntensity);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置发光颜色
|
|
/// </summary>
|
|
public void SetGlowColor(Color color)
|
|
{
|
|
glowColor = color;
|
|
if (material != null)
|
|
{
|
|
material.SetColor(GlowColorID, glowColor);
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
// 清理材质实例
|
|
if (instanceMaterial != null)
|
|
{
|
|
if (Application.isPlaying)
|
|
{
|
|
Destroy(instanceMaterial);
|
|
}
|
|
else
|
|
{
|
|
DestroyImmediate(instanceMaterial);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|