Files
Echo/Assets/_Project/Scripts/Interaction/InteractOutlineTarget.cs
T

141 lines
4.3 KiB
C#
Raw Normal View History

2026-07-08 19:53:15 +08:00
using UnityEngine;
namespace Interaction
{
public class InteractOutlineTarget : MonoBehaviour
{
[SerializeField] private Renderer[] renderers;
[SerializeField] private bool autoFindRenderers = true;
[SerializeField] private float outlineWidth = 0.02f;
[SerializeField] private float emission = 1f;
[Header("Debug")]
[SerializeField] private bool debugLog;
private bool highlighted;
private Material outlineMaterial;
private MaterialPropertyBlock mpb;
private Material[][] originalSharedMaterials;
private static readonly int OutlineColorId = Shader.PropertyToID("_OutlineColor");
private static readonly int OutlineWidthId = Shader.PropertyToID("_OutlineWidth");
private static readonly int EmissionId = Shader.PropertyToID("_Emission");
public void SetOutlineMaterial(Material material)
{
outlineMaterial = material;
}
public void SetHighlighted(bool value, Color color)
{
if (outlineMaterial == null)
{
if (debugLog) Debug.Log($"[InteractOutlineTarget] Missing outlineMaterial on '{name}'", this);
return;
}
if (renderers == null || renderers.Length == 0)
{
if (autoFindRenderers)
{
renderers = GetComponentsInChildren<Renderer>(true);
}
}
if (renderers == null || renderers.Length == 0) return;
if (mpb == null) mpb = new MaterialPropertyBlock();
if (value)
{
mpb.SetColor(OutlineColorId, color);
mpb.SetFloat(OutlineWidthId, outlineWidth);
mpb.SetFloat(EmissionId, emission);
}
if (value && !highlighted)
{
CacheOriginalMaterialsIfNeeded();
AppendOutlineMaterial();
highlighted = true;
}
else if (!value && highlighted)
{
RestoreOriginalMaterials();
highlighted = false;
}
for (int i = 0; i < renderers.Length; i++)
{
var r = renderers[i];
if (r == null) continue;
r.SetPropertyBlock(value ? mpb : null);
}
}
private void CacheOriginalMaterialsIfNeeded()
{
if (originalSharedMaterials != null && originalSharedMaterials.Length == (renderers == null ? 0 : renderers.Length))
{
return;
}
if (renderers == null)
{
originalSharedMaterials = null;
return;
}
originalSharedMaterials = new Material[renderers.Length][];
for (int i = 0; i < renderers.Length; i++)
{
var r = renderers[i];
originalSharedMaterials[i] = r != null ? r.sharedMaterials : null;
}
}
private void AppendOutlineMaterial()
{
if (renderers == null) return;
for (int i = 0; i < renderers.Length; i++)
{
var r = renderers[i];
if (r == null) continue;
var mats = r.sharedMaterials;
if (mats == null)
{
r.sharedMaterials = new[] { outlineMaterial };
continue;
}
for (int j = 0; j < mats.Length; j++)
{
if (mats[j] == outlineMaterial) goto NextRenderer;
}
var newMats = new Material[mats.Length + 1];
for (int j = 0; j < mats.Length; j++) newMats[j] = mats[j];
newMats[mats.Length] = outlineMaterial;
r.sharedMaterials = newMats;
NextRenderer: ;
}
}
private void RestoreOriginalMaterials()
{
if (renderers == null || originalSharedMaterials == null) return;
int count = Mathf.Min(renderers.Length, originalSharedMaterials.Length);
for (int i = 0; i < count; i++)
{
var r = renderers[i];
if (r == null) continue;
r.sharedMaterials = originalSharedMaterials[i];
}
}
}
}