using MalbersAnimations.Events; using System.Collections.Generic; using UnityEngine; namespace MalbersAnimations.Utilities { /// Manage the Blend Shapes of a Mesh [AddComponentMenu("Malbers/Utilities/Mesh/Blend Shapes")] public class BlendShape : MonoBehaviour { [CreateScriptableAsset] public BlendShapePreset preset; public bool LoadPresetOnStart = true; [RequiredField] public SkinnedMeshRenderer mesh; public SkinnedMeshRenderer[] LODs; [Range(0, 100)] public float[] blendShapes; //Value of the Blend Shape public bool random; public int PinnedShape; /// Does the mesh has Blend Shapes? internal bool HasBlendShapes => mesh && mesh.sharedMesh.blendShapeCount > 0; private void Start() { if (LoadPresetOnStart) LoadPreset(); else if (random) Randomize(); } private void Reset() { mesh = GetComponentInChildren(); if (mesh) { blendShapes = new float[mesh.sharedMesh.blendShapeCount]; for (int i = 0; i < blendShapes.Length; i++) blendShapes[i] = mesh.GetBlendShapeWeight(i); } } /// Returns the current Blend Shapes Values public virtual float[] GetBlendShapeValues() { if (HasBlendShapes) { float[] BS = new float[mesh.sharedMesh.blendShapeCount]; for (int i = 0; i < BS.Length; i++) { BS[i] = mesh.GetBlendShapeWeight(i); } return BS; } return null; } public void SmoothBlendShape(BlendShapePreset preset) => LoadSmoothPreset(preset); public void LoadSmoothPreset(BlendShapePreset preset) { StopAllCoroutines(); preset.SmoothBlend(mesh); } public void SavePreset() { if (preset) { preset.blendShapes = new float[blendShapes.Length]; for (int i = 0; i < preset.blendShapes.Length; i++) { preset.blendShapes[i] = blendShapes[i]; } Debug.Log("Preset: " + preset.name + " Saved"); MTools.SetDirty(preset); } } public void LoadPreset() => LoadPreset(preset); public void LoadPreset(BlendShapePreset preset) { if (preset) { blendShapes = new float[preset.blendShapes.Length]; for (int i = 0; i < preset.blendShapes.Length; i++) { blendShapes[i] = preset.blendShapes[i]; } Debug.Log("Preset: " + preset.name + " Loaded"); UpdateBlendShapes(); MTools.SetDirty(preset); } } public virtual void SetShapesCount() { if (mesh) { blendShapes = new float[mesh.sharedMesh.blendShapeCount]; for (int i = 0; i < blendShapes.Length; i++) { blendShapes[i] = mesh.GetBlendShapeWeight(i); } } } /// Set Random Values to the Mesh Blend Shapes public virtual void Randomize() { if (HasBlendShapes) { for (int i = 0; i < blendShapes.Length; i++) { blendShapes[i] = Random.Range(0, 100); mesh.SetBlendShapeWeight(i, blendShapes[i]); } UpdateLODs(); } } /// Set a weight of a Blend Shape by its name public virtual void SetWeight(string name, float value) { if (HasBlendShapes) { PinnedShape = mesh.sharedMesh.GetBlendShapeIndex(name); if (PinnedShape != -1) { mesh.SetBlendShapeWeight(PinnedShape, value); } } } /// Set a weight of a Blend Shape by its index public virtual void SetWeight(int index, float value) { if (HasBlendShapes) mesh.SetBlendShapeWeight(PinnedShape = index, value); } public virtual void _PinShape(string name) { PinnedShape = mesh.sharedMesh.GetBlendShapeIndex(name); } public virtual void _PinShape(int index) { PinnedShape = index; } public virtual void _PinnedShapeSetValue(float value) { if (PinnedShape != -1) { value = Mathf.Clamp(value, 0, 100); blendShapes[PinnedShape] = value; mesh.SetBlendShapeWeight(PinnedShape, value); UpdateLODs(PinnedShape); } } public virtual void UpdateBlendShapes() { if (mesh && blendShapes != null) { int Length = Mathf.Min(mesh.sharedMesh.blendShapeCount, blendShapes.Length); for (int i = 0; i < Length; i++) { mesh.SetBlendShapeWeight(i, blendShapes[i]); } UpdateLODs(); } } /// Update the LODs Values protected virtual void UpdateLODs() { for (int i = 0; i < blendShapes.Length; i++) { UpdateLODs(i); } } /// Updates Only a Shape in all LODS protected virtual void UpdateLODs(int index) { if (LODs != null) { foreach (var lods in LODs) { if (lods != null && lods.sharedMesh.blendShapeCount > index) lods.SetBlendShapeWeight(index, blendShapes[index]); } } } #if UNITY_EDITOR [ContextMenu("Create Event Listeners")] void CreateListeners() { MEventListener listener = this.FindComponent(); if (listener == null) listener = transform.root.gameObject.AddComponent(); if (listener.Events == null) listener.Events = new List(); MEvent BlendS = MTools.GetInstance("Blend Shapes"); if (listener.Events.Find(item => item.Event == BlendS) == null) { var item = new MEventItemListener() { Event = BlendS, useVoid = false, useString = true, useInt = true, useFloat = true }; UnityEditor.Events.UnityEventTools.AddPersistentListener(item.ResponseInt, _PinShape); UnityEditor.Events.UnityEventTools.AddPersistentListener(item.ResponseString, _PinShape); UnityEditor.Events.UnityEventTools.AddPersistentListener(item.ResponseFloat, _PinnedShapeSetValue); listener.Events.Add(item); Debug.Log("Blend Shapes Added to the Event Listeners"); MTools.SetDirty(listener); } } #endif } }