using UnityEngine;
using Shapes;
namespace AibisDream.MiniGame.Language
{
///
/// 复古噪点叠加渲染器 - 在指定区域上方绘制复古显示器效果
/// 使用 Shapes 库绘制,与粒子系统使用相同的渲染方式
///
[ExecuteAlways]
public class NoiseOverlayRenderer : ImmediateModeShapeDrawer
{
[Header("区域设置")]
[Tooltip("效果覆盖的世界空间区域中心")]
public Vector3 areaCenter = Vector3.zero;
[Tooltip("效果覆盖的区域大小")]
public Vector2 areaSize = new Vector2(10f, 10f);
[Header("噪点效果")]
[Tooltip("启用噪点效果")]
public bool enableNoise = true;
[Range(0f, 1f)]
[Tooltip("噪点强度")]
public float noiseIntensity = 0.15f;
[Range(1, 100)]
[Tooltip("噪点密度(点数)")]
public int noiseDensity = 50;
[Tooltip("噪点颜色")]
public Color noiseColor = new Color(1f, 1f, 1f, 0.3f);
[Range(0.001f, 0.05f)]
[Tooltip("噪点大小")]
public float noiseSize = 0.02f;
[Header("扫描线效果")]
[Tooltip("启用扫描线")]
public bool enableScanlines = true;
[Range(0f, 1f)]
[Tooltip("扫描线强度")]
public float scanlineIntensity = 0.1f;
[Range(10, 200)]
[Tooltip("扫描线数量")]
public int scanlineCount = 60;
[Tooltip("扫描线颜色")]
public Color scanlineColor = new Color(0f, 0f, 0f, 0.15f);
[Range(0.001f, 0.02f)]
[Tooltip("扫描线厚度")]
public float scanlineThickness = 0.005f;
[Header("闪烁效果")]
[Tooltip("启用闪烁")]
public bool enableFlicker = true;
[Range(0f, 0.5f)]
[Tooltip("闪烁强度")]
public float flickerIntensity = 0.05f;
[Range(1f, 30f)]
[Tooltip("闪烁频率")]
public float flickerFrequency = 10f;
[Header("边框暗角")]
[Tooltip("启用边框暗角")]
public bool enableVignette = true;
[Range(0f, 1f)]
[Tooltip("暗角强度")]
public float vignetteIntensity = 0.3f;
[Tooltip("暗角颜色")]
public Color vignetteColor = new Color(0f, 0f, 0f, 0.5f);
[Header("颜色失真")]
[Tooltip("启用色差")]
public bool enableChromaticAberration = false;
[Range(0f, 0.05f)]
[Tooltip("色差偏移量")]
public float chromaticOffset = 0.01f;
// 内部状态
private float noiseTimer = 0f;
private float flickerValue = 1f;
private System.Random noiseRandom;
private void OnEnable()
{
noiseRandom = new System.Random(42);
}
private void Update()
{
// 更新噪点动画
noiseTimer += Time.deltaTime * 20f;
if (noiseTimer > 1000f) noiseTimer = 0f;
// 更新闪烁
if (enableFlicker)
{
flickerValue = 1f - flickerIntensity * Mathf.PerlinNoise(Time.time * flickerFrequency, 0f);
}
else
{
flickerValue = 1f;
}
// 重新生成噪点种子
noiseRandom = new System.Random((int)(Time.time * 60f) % 10000);
}
public override void DrawShapes(Camera cam)
{
if (!enabled) return;
using (Draw.Command(cam))
{
Draw.BlendMode = ShapesBlendMode.Transparent;
Draw.ZTest = UnityEngine.Rendering.CompareFunction.Always;
// 绘制暗角
if (enableVignette)
{
DrawVignette();
}
// 绘制扫描线
if (enableScanlines)
{
DrawScanlines();
}
// 绘制噪点
if (enableNoise)
{
DrawNoise();
}
}
}
private void DrawNoise()
{
float halfWidth = areaSize.x / 2f;
float halfHeight = areaSize.y / 2f;
// 根据闪烁调整噪点数量
int actualDensity = Mathf.RoundToInt(noiseDensity * noiseIntensity * flickerValue);
for (int i = 0; i < actualDensity; i++)
{
// 使用随机数生成器获取位置
float x = areaCenter.x + (float)(noiseRandom.NextDouble() * 2 - 1) * halfWidth;
float y = areaCenter.y + (float)(noiseRandom.NextDouble() * 2 - 1) * halfHeight;
float z = areaCenter.z;
// 随机亮度
float brightness = (float)noiseRandom.NextDouble();
Color pointColor = noiseColor;
pointColor.a = noiseColor.a * brightness * flickerValue;
// 随机大小
float size = noiseSize * (0.5f + (float)noiseRandom.NextDouble());
Draw.Disc(new Vector3(x, y, z), size, pointColor);
}
}
private void DrawScanlines()
{
float halfWidth = areaSize.x / 2f;
float halfHeight = areaSize.y / 2f;
// 计算扫描线间距
float spacing = areaSize.y / scanlineCount;
Draw.LineGeometry = LineGeometry.Flat2D;
Draw.Thickness = scanlineThickness;
Color lineColor = scanlineColor;
lineColor.a = scanlineColor.a * scanlineIntensity * flickerValue;
for (int i = 0; i < scanlineCount; i++)
{
float y = areaCenter.y - halfHeight + spacing * i + spacing * 0.5f;
// 添加轻微的闪烁变化
float lineAlpha = lineColor.a * (0.8f + 0.2f * Mathf.Sin(y * 10f + Time.time * 5f));
Color finalColor = lineColor;
finalColor.a = lineAlpha;
Vector3 start = new Vector3(areaCenter.x - halfWidth, y, areaCenter.z);
Vector3 end = new Vector3(areaCenter.x + halfWidth, y, areaCenter.z);
Draw.Line(start, end, finalColor);
}
}
private void DrawVignette()
{
float halfWidth = areaSize.x / 2f;
float halfHeight = areaSize.y / 2f;
// 绘制四个角落的暗角渐变(使用多个半透明矩形模拟)
int steps = 8;
for (int i = 0; i < steps; i++)
{
float t = (float)i / steps;
float alpha = vignetteColor.a * vignetteIntensity * (1f - t) * flickerValue;
Color cornerColor = vignetteColor;
cornerColor.a = alpha * 0.3f;
float cornerSize = Mathf.Lerp(areaSize.x * 0.3f, 0.1f, t);
float offset = cornerSize * 0.5f;
// 四个角落
Vector3[] corners = new Vector3[]
{
new Vector3(areaCenter.x - halfWidth + offset, areaCenter.y + halfHeight - offset, areaCenter.z),
new Vector3(areaCenter.x + halfWidth - offset, areaCenter.y + halfHeight - offset, areaCenter.z),
new Vector3(areaCenter.x - halfWidth + offset, areaCenter.y - halfHeight + offset, areaCenter.z),
new Vector3(areaCenter.x + halfWidth - offset, areaCenter.y - halfHeight + offset, areaCenter.z)
};
foreach (var corner in corners)
{
Draw.Disc(corner, cornerSize, cornerColor);
}
}
}
///
/// 设置覆盖区域(可以从 LanguageParticleManager 获取 Canvas 区域)
///
public void SetArea(Vector3 center, Vector2 size)
{
areaCenter = center;
areaSize = size;
}
///
/// 设置效果强度(0-1)
///
public void SetIntensity(float intensity)
{
intensity = Mathf.Clamp01(intensity);
noiseIntensity = intensity * 0.15f;
scanlineIntensity = intensity * 0.1f;
flickerIntensity = intensity * 0.05f;
vignetteIntensity = intensity * 0.3f;
}
private void OnDrawGizmosSelected()
{
// 在编辑器中显示效果区域
Gizmos.color = new Color(0f, 1f, 0f, 0.3f);
Gizmos.DrawWireCube(areaCenter, new Vector3(areaSize.x, areaSize.y, 0.01f));
}
}
}