You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
5.7 KiB
176 lines
5.7 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using UnityEngine; |
|
|
|
namespace UDE_HAND_INTERACTION |
|
{ |
|
[RequireComponent(typeof(InteractableObject))] |
|
public class InteractableObjectOutline : MonoBehaviour |
|
{ |
|
private Renderer[] renderers; |
|
private MeshFilter[] meshFilters; |
|
|
|
private Material MaskOutlineMat; |
|
private Material FillOutlineMat; |
|
|
|
[SerializeField] |
|
private Color outlineColor = new Color(1, 0, 0, 1); |
|
|
|
[SerializeField, Range(0f, 10f)] |
|
private float outlineWidth = 6f; |
|
|
|
[SerializeField, HideInInspector] |
|
private List<Mesh> bakeKeys = new List<Mesh>(); |
|
|
|
[SerializeField, HideInInspector] |
|
private List<List<Vector3>> bakeValues = new List<List<Vector3>>(); |
|
|
|
public List<Renderer> ObjectRenderers { get; private set; } = new List<Renderer>(); |
|
public List<MeshFilter> ObjectMeshFilters { get; private set; } = new List<MeshFilter>(); |
|
|
|
private static HashSet<Mesh> registeredMeshes = new HashSet<Mesh>(); |
|
|
|
bool[] TwoHandEnable = new bool[2] { false, false }; |
|
void Awake() |
|
{ |
|
FindObjectRenders(transform); |
|
renderers = ObjectRenderers.ToArray(); |
|
meshFilters = ObjectMeshFilters.ToArray(); |
|
|
|
MaskOutlineMat = Instantiate(Resources.Load<Material>(@"Mask")); |
|
FillOutlineMat = Instantiate(Resources.Load<Material>(@"Fill")); |
|
|
|
MaskOutlineMat.name = "Mask(TempClone)"; |
|
FillOutlineMat.name = "Fill(TempClone)"; |
|
|
|
foreach (var meshFilter in meshFilters) |
|
{ |
|
if (!registeredMeshes.Add(meshFilter.sharedMesh)) continue; |
|
|
|
var index = bakeKeys.IndexOf(meshFilter.sharedMesh); |
|
var smoothNormals = (index >= 0) ? bakeValues[index] : SmoothNormals(meshFilter.sharedMesh); |
|
meshFilter.sharedMesh.SetUVs(3, smoothNormals); |
|
|
|
var renderer = meshFilter.GetComponent<Renderer>(); |
|
if (renderer != null) |
|
{ |
|
CombineSubmeshes(meshFilter.sharedMesh, renderer.sharedMaterials); |
|
} |
|
} |
|
|
|
FillOutlineMat.SetColor("_OutlineColor", outlineColor); |
|
FillOutlineMat.SetFloat("_OutlineWidth", outlineWidth); |
|
|
|
enabled = false; |
|
} |
|
|
|
public void EnableWithHand(int hand, bool enable) |
|
{ |
|
TwoHandEnable[hand] = enable; |
|
enabled = TwoHandEnable[0] || TwoHandEnable[1]; |
|
} |
|
|
|
void OnEnable() |
|
{ |
|
foreach (var renderer in renderers) |
|
{ |
|
var materials = renderer.sharedMaterials.ToList(); |
|
materials.Add(MaskOutlineMat); |
|
materials.Add(FillOutlineMat); |
|
renderer.materials = materials.ToArray(); |
|
} |
|
} |
|
|
|
void OnDisable() |
|
{ |
|
foreach (var renderer in renderers) |
|
{ |
|
var materials = renderer.sharedMaterials.ToList(); |
|
materials.Remove(MaskOutlineMat); |
|
materials.Remove(FillOutlineMat); |
|
renderer.materials = materials.ToArray(); |
|
} |
|
} |
|
|
|
void OnValidate() |
|
{ |
|
if (bakeKeys.Count != bakeValues.Count) |
|
{ |
|
bakeKeys.Clear(); |
|
bakeValues.Clear(); |
|
} |
|
|
|
if (bakeKeys.Count == 0) |
|
{ |
|
var bakedMeshes = new HashSet<Mesh>(); |
|
|
|
foreach (var meshFilter in GetComponentsInChildren<MeshFilter>()) |
|
{ |
|
if (!bakedMeshes.Add(meshFilter.sharedMesh)) continue; |
|
var smoothNormals = SmoothNormals(meshFilter.sharedMesh); |
|
bakeKeys.Add(meshFilter.sharedMesh); |
|
bakeValues.Add(smoothNormals); |
|
} |
|
} |
|
} |
|
|
|
void Update() |
|
{ |
|
FillOutlineMat.SetColor("_OutlineColor", outlineColor); |
|
FillOutlineMat.SetFloat("_OutlineWidth", outlineWidth); |
|
} |
|
|
|
void OnDestroy() |
|
{ |
|
Destroy(MaskOutlineMat); |
|
Destroy(FillOutlineMat); |
|
} |
|
|
|
void FindObjectRenders(Transform trans) |
|
{ |
|
if (trans.TryGetComponent<Renderer>(out var render)) |
|
{ |
|
ObjectRenderers.Add(render); |
|
} |
|
if (trans.TryGetComponent<MeshFilter>(out var filter)) |
|
{ |
|
ObjectMeshFilters.Add(filter); |
|
} |
|
|
|
for (int i = 0; i < trans.childCount; ++i) |
|
{ |
|
FindObjectRenders(trans.GetChild(i)); |
|
} |
|
} |
|
|
|
List<Vector3> SmoothNormals(Mesh mesh) |
|
{ |
|
var groups = mesh.vertices.Select((vertex, index) => new KeyValuePair<Vector3, int>(vertex, index)).GroupBy(pair => pair.Key); |
|
var smoothNormals = new List<Vector3>(mesh.normals); |
|
|
|
foreach (var group in groups) |
|
{ |
|
if (group.Count() == 1) continue; |
|
var smoothNormal = Vector3.zero; |
|
foreach (var pair in group) |
|
{ |
|
smoothNormal += smoothNormals[pair.Value]; |
|
} |
|
smoothNormal.Normalize(); |
|
foreach (var pair in group) |
|
{ |
|
smoothNormals[pair.Value] = smoothNormal; |
|
} |
|
} |
|
return smoothNormals; |
|
} |
|
|
|
void CombineSubmeshes(Mesh mesh, Material[] materials) |
|
{ |
|
if (mesh.subMeshCount == 1 || mesh.subMeshCount > materials.Length) return; |
|
mesh.subMeshCount++; |
|
mesh.SetTriangles(mesh.triangles, mesh.subMeshCount - 1); |
|
} |
|
} |
|
}
|
|
|