123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- using System;
- using System.Collections.Generic;
- using UnityEngine;
-
- namespace UnityEditor.U2D.Animation
- {
- internal enum WeightEditorMode
- {
- AddAndSubtract,
- GrowAndShrink,
- Smooth
- }
-
- internal class WeightEditor
- {
- public BaseSpriteMeshData spriteMeshData
- {
- get => m_SpriteMeshDataController.spriteMeshData;
- set => m_SpriteMeshDataController.spriteMeshData = value;
- }
-
- public ICacheUndo cacheUndo { get; set; }
- public WeightEditorMode mode { get; set; }
- public int boneIndex { get; set; }
- public ISelection<int> selection { get; set; }
- public bool emptySelectionEditsAll { get; set; }
- public bool autoNormalize { get; set; }
-
- WeightEditorMode currentMode { get; set; }
- bool useRelativeValues { get; set; }
-
- SpriteMeshDataController m_SpriteMeshDataController = new SpriteMeshDataController();
- const int k_MaxSmoothIterations = 8;
- float[] m_SmoothValues;
- readonly List<BoneWeight[]> m_SmoothedBoneWeights = new List<BoneWeight[]>();
- readonly List<BoneWeight> m_StoredBoneWeights = new List<BoneWeight>();
- int boneCount => spriteMeshData != null ? spriteMeshData.boneCount : 0;
-
- public WeightEditor()
- {
- autoNormalize = true;
- }
-
- public void OnEditStart(bool relative)
- {
- Validate();
-
- RegisterUndo();
- currentMode = mode;
- useRelativeValues = relative;
-
- if (!useRelativeValues)
- StoreBoneWeights();
-
- if (mode == WeightEditorMode.Smooth)
- PrepareSmoothingBuffers();
- }
-
- public void OnEditEnd()
- {
- Validate();
-
- if (currentMode == WeightEditorMode.AddAndSubtract)
- {
- for (int i = 0; i < spriteMeshData.vertexCount; ++i)
- spriteMeshData.vertexWeights[i].Clamp(4);
- }
-
- if (autoNormalize)
- m_SpriteMeshDataController.NormalizeWeights(null);
-
- m_SpriteMeshDataController.SortTrianglesByDepth();
- }
-
- public void DoEdit(float value)
- {
- Validate();
-
- if (!useRelativeValues)
- RestoreBoneWeights();
-
- if (currentMode == WeightEditorMode.AddAndSubtract)
- SetWeight(value);
- else if (currentMode == WeightEditorMode.GrowAndShrink)
- SetWeight(value, false);
- else if (currentMode == WeightEditorMode.Smooth)
- SmoothWeights(value);
- }
-
- void Validate()
- {
- if (spriteMeshData == null)
- throw (new Exception(TextContent.noSpriteSelected));
- }
-
- void RegisterUndo()
- {
- Debug.Assert(cacheUndo != null);
-
- cacheUndo.BeginUndoOperation(TextContent.editWeights);
- }
-
- void SetWeight(float value, bool createNewChannel = true)
- {
- if (boneIndex == -1 || spriteMeshData == null)
- return;
-
- Debug.Assert(selection != null);
-
- for (var i = 0; i < spriteMeshData.vertexCount; ++i)
- {
- if (selection.Count == 0 && emptySelectionEditsAll ||
- selection.Count > 0 && selection.Contains(i))
- {
- var editableBoneWeight = spriteMeshData.vertexWeights[i];
- var channel = editableBoneWeight.GetChannelFromBoneIndex(boneIndex);
-
- if (channel == -1)
- {
- if (createNewChannel && value > 0f)
- {
- editableBoneWeight.AddChannel(boneIndex, 0f, true);
- channel = editableBoneWeight.GetChannelFromBoneIndex(boneIndex);
- }
- else
- {
- continue;
- }
- }
-
- editableBoneWeight[channel].weight += value;
-
- if (editableBoneWeight.Sum() > 1f)
- editableBoneWeight.CompensateOtherChannels(channel);
-
- editableBoneWeight.FilterChannels(0f);
- }
- }
- }
-
- void SmoothWeights(float value)
- {
- Debug.Assert(selection != null);
-
- for (var i = 0; i < spriteMeshData.vertexCount; ++i)
- {
- if (selection.Count == 0 && emptySelectionEditsAll ||
- selection.Count > 0 && selection.Contains(i))
- {
- var smoothValue = m_SmoothValues[i];
-
- if (smoothValue >= k_MaxSmoothIterations)
- continue;
-
- m_SmoothValues[i] = Mathf.Clamp(smoothValue + value, 0f, k_MaxSmoothIterations);
-
- var lerpValue = GetLerpValue(m_SmoothValues[i]);
- var lerpIndex = GetLerpIndex(m_SmoothValues[i]);
- var smoothedBoneWeightsFloor = GetSmoothedBoneWeights(lerpIndex - 1);
- var smoothedBoneWeightsCeil = GetSmoothedBoneWeights(lerpIndex);
-
- var boneWeight = EditableBoneWeightUtility.Lerp(smoothedBoneWeightsFloor[i], smoothedBoneWeightsCeil[i], lerpValue);
- spriteMeshData.vertexWeights[i].SetFromBoneWeight(boneWeight);
- }
- }
- }
-
- void PrepareSmoothingBuffers()
- {
- if (m_SmoothValues == null || m_SmoothValues.Length != spriteMeshData.vertexCount)
- m_SmoothValues = new float[spriteMeshData.vertexCount];
-
- Array.Clear(m_SmoothValues, 0, m_SmoothValues.Length);
-
- m_SmoothedBoneWeights.Clear();
-
- var boneWeights = new BoneWeight[spriteMeshData.vertexCount];
-
- for (var i = 0; i < spriteMeshData.vertexCount; i++)
- {
- var editableBoneWeight = spriteMeshData.vertexWeights[i];
- boneWeights[i] = editableBoneWeight.ToBoneWeight(false);
- }
-
- m_SmoothedBoneWeights.Add(boneWeights);
- }
-
- BoneWeight[] GetSmoothedBoneWeights(int lerpIndex)
- {
- Debug.Assert(lerpIndex >= 0);
-
- while (lerpIndex >= m_SmoothedBoneWeights.Count && lerpIndex <= k_MaxSmoothIterations)
- {
- SmoothingUtility.SmoothWeights(m_SmoothedBoneWeights[^1], spriteMeshData.indices, boneCount, out var boneWeights);
- m_SmoothedBoneWeights.Add(boneWeights);
- }
-
- return m_SmoothedBoneWeights[Mathf.Min(lerpIndex, k_MaxSmoothIterations)];
- }
-
- static float GetLerpValue(float smoothValue)
- {
- Debug.Assert(smoothValue >= 0f);
- return smoothValue - Mathf.Floor(smoothValue);
- }
-
- static int GetLerpIndex(float smoothValue)
- {
- Debug.Assert(smoothValue >= 0f);
- return Mathf.RoundToInt(Mathf.Floor(smoothValue) + 1);
- }
-
- void StoreBoneWeights()
- {
- Debug.Assert(selection != null);
-
- m_StoredBoneWeights.Clear();
-
- for (var i = 0; i < spriteMeshData.vertexCount; i++)
- {
- var editableBoneWeight = spriteMeshData.vertexWeights[i];
- m_StoredBoneWeights.Add(editableBoneWeight.ToBoneWeight(false));
- }
- }
-
- void RestoreBoneWeights()
- {
- Debug.Assert(selection != null);
-
- for (var i = 0; i < spriteMeshData.vertexCount; i++)
- {
- var editableBoneWeight = spriteMeshData.vertexWeights[i];
- editableBoneWeight.SetFromBoneWeight(m_StoredBoneWeights[i]);
- }
-
- if (m_SmoothValues != null)
- Array.Clear(m_SmoothValues, 0, m_SmoothValues.Length);
- }
- }
- }
|