253 lines
8.5 KiB
C#
253 lines
8.5 KiB
C#
using UnityEngine;
|
||
using Shapes;
|
||
|
||
namespace AibisDream.MiniGame.Language
|
||
{
|
||
/// <summary>
|
||
/// 复古噪点叠加渲染器 - 在指定区域上方绘制复古显示器效果
|
||
/// 使用 Shapes 库绘制,与粒子系统使用相同的渲染方式
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置覆盖区域(可以从 LanguageParticleManager 获取 Canvas 区域)
|
||
/// </summary>
|
||
public void SetArea(Vector3 center, Vector2 size)
|
||
{
|
||
areaCenter = center;
|
||
areaSize = size;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置效果强度(0-1)
|
||
/// </summary>
|
||
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));
|
||
}
|
||
}
|
||
}
|