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.
177 lines
5.7 KiB
177 lines
5.7 KiB
|
1 month ago
|
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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|