Files
gold_dolphin/unity/Assets/Light/scripts/LightMaskSystem.cs
2026-06-27 03:36:50 +08:00

180 lines
6.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using UnityEngine;
namespace IndianOceanAssets.Engine2_5D
{
/// <summary>
/// 黑暗遮罩管理器 v2 —— 乘法混合 + 编辑器开关(不含回声)。
/// 回声描边已独立到 EchoSystem + SpriteEchoOutline shader。
///
/// 单例模式:收集场景中所有 LightSource每帧把位置/半径/强度
/// 写入 DarknessOverlay 材质的 _LightData 数组。
///
/// 使用方式:
/// 1. 在场景中创建一个空物体,挂上此脚本
/// 2. 创建一个大平面覆盖可视区域Y 稍高于精灵
/// 3. 给平面分配使用 DarknessOverlay shader 的材质
/// 4. 把该材质拖到此脚本的 darknessMaterial 字段
/// </summary>
public class LightMaskSystem : MonoBehaviour
{
public static LightMaskSystem Instance { get; private set; }
[Header("遮罩材质(使用 DarknessOverlay shader")]
[SerializeField] private Material darknessMaterial;
[Header("编辑器开关")]
[Tooltip("勾选后关闭黑暗,所有物件完全可见,方便摆放场景。\n取消勾选恢复黑暗效果。")]
[SerializeField] private bool debugShowAll = false;
[Header("黑暗设置")]
[Tooltip("最小亮度0=纯黑精灵完全看不见0.05=微微看到轮廓")]
[SerializeField, Range(0f, 0.3f)] private float minBrightness = 0f;
[Tooltip("黑暗底色:夜间微光色调,接近纯黑")]
[SerializeField] private Color darknessColor = new Color(0.01f, 0.01f, 0.02f, 1f);
[Tooltip("光线边缘柔和度0 = 硬边1 = 最柔")]
[SerializeField, Range(0.01f, 1f)] private float lightSoftness = 0.35f;
[Header("遮罩平面跟随设置")]
[Tooltip("如果勾选,遮罩平面会跟随摄像机移动(适合大地图)")]
[SerializeField] private bool followCamera = true;
[SerializeField] private Transform maskPlane;
[SerializeField] private Vector3 maskOffset = new Vector3(0f, 5f, 0f);
[SerializeField] private float planeSize = 50f;
// Shader Property IDs
private static readonly int LightDataID = Shader.PropertyToID("_LightData");
private static readonly int LightCountID = Shader.PropertyToID("_LightCount");
private static readonly int DarknessColorID = Shader.PropertyToID("_DarknessColor");
private static readonly int MinBrightnessID = Shader.PropertyToID("_MinBrightness");
private static readonly int LightSoftnessID = Shader.PropertyToID("_LightSoftness");
private readonly List<LightSource> _lights = new List<LightSource>();
private Vector4[] _lightData = new Vector4[64];
private Camera _mainCamera;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(this);
return;
}
Instance = this;
}
private void Start()
{
_mainCamera = Camera.main;
UpdateMaterialProperties();
}
private void Update()
{
UpdateLightData();
UpdateMaskPosition();
}
private void UpdateMaterialProperties()
{
if (darknessMaterial == null) return;
darknessMaterial.SetColor(DarknessColorID, darknessColor);
darknessMaterial.SetFloat(LightSoftnessID, lightSoftness);
if (debugShowAll)
darknessMaterial.SetFloat(MinBrightnessID, 1.0f);
else
darknessMaterial.SetFloat(MinBrightnessID, minBrightness);
}
private void UpdateLightData()
{
if (darknessMaterial == null) return;
int writeIndex = 0;
for (int i = 0; i < _lights.Count && writeIndex < 64; i++)
{
var src = _lights[i];
if (src == null || !src.gameObject.activeInHierarchy)
continue;
Vector2 pos = src.GetWorldPositionXZ();
_lightData[writeIndex] = new Vector4(pos.x, pos.y, src.Radius, src.Intensity);
writeIndex++;
}
darknessMaterial.SetVectorArray(LightDataID, _lightData);
darknessMaterial.SetInt(LightCountID, writeIndex);
}
private void UpdateMaskPosition()
{
if (!followCamera || maskPlane == null || _mainCamera == null) return;
Vector3 camPos = _mainCamera.transform.position;
maskPlane.position = new Vector3(camPos.x + maskOffset.x, maskOffset.y, camPos.z + maskOffset.z);
}
// ===== 光源注册/注销 =====
public void RegisterLight(LightSource source)
{
if (!_lights.Contains(source))
_lights.Add(source);
}
public void UnregisterLight(LightSource source)
{
_lights.Remove(source);
}
// ===== Inspector 同步 =====
private void OnValidate()
{
if (darknessMaterial == null) return;
darknessMaterial.SetColor(DarknessColorID, darknessColor);
darknessMaterial.SetFloat(LightSoftnessID, lightSoftness);
if (debugShowAll)
darknessMaterial.SetFloat(MinBrightnessID, 1.0f);
else
darknessMaterial.SetFloat(MinBrightnessID, minBrightness);
}
/// <summary>
/// 快捷切换黑暗开关(右键组件 > Toggle Darkness
/// </summary>
[ContextMenu("Toggle Darkness (Debug)")]
private void ToggleDarknessDebug()
{
debugShowAll = !debugShowAll;
OnValidate();
Debug.Log($"[LightMaskSystem] Darkness {(debugShowAll ? "OFF (debug)" : "ON")}");
}
// ===== 运行时动态调整 =====
/// <summary>
/// 动态调整最小亮度(白天/黑夜切换、Q键过场点亮等
/// 0 = 纯黑完全看不见0.3 = 能模糊看到东西
/// </summary>
public void SetMinBrightness(float value)
{
minBrightness = Mathf.Clamp01(value);
if (darknessMaterial != null && !debugShowAll)
darknessMaterial.SetFloat(MinBrightnessID, minBrightness);
}
/// <summary>
/// 动态调整黑暗底色
/// </summary>
public void SetDarknessColor(Color color)
{
darknessColor = color;
if (darknessMaterial != null)
darknessMaterial.SetColor(DarknessColorID, darknessColor);
}
}
}