141 lines
4.3 KiB
C#
141 lines
4.3 KiB
C#
|
|
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];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|