PO/Library/PackageCache/com.unity.2d.animation@5.0.7/Editor/SkinningModule/SpriteMeshData/EditableBoneWeightUtility.cs

263 lines
8.7 KiB
C#

using UnityEngine;
using System;
using System.Collections.Generic;
namespace UnityEditor.U2D.Animation
{
internal struct BoneWeightData : IComparable<BoneWeightData>
{
public int boneIndex;
public float weight;
public int CompareTo(BoneWeightData other)
{
return other.weight.CompareTo(weight);
}
}
internal static class EditableBoneWeightUtility
{
private static List<BoneWeightData> s_BoneWeightDataList = new List<BoneWeightData>();
private static EditableBoneWeight s_LerpFirst = new EditableBoneWeight();
private static EditableBoneWeight s_LerpSecond = new EditableBoneWeight();
private static EditableBoneWeight s_LerpResult = new EditableBoneWeight();
public static EditableBoneWeight CreateFromBoneWeight(BoneWeight boneWeight)
{
EditableBoneWeight editableBoneWeight = new EditableBoneWeight();
editableBoneWeight.SetFromBoneWeight(boneWeight);
editableBoneWeight.UnifyChannelsWithSameBoneIndex();
return editableBoneWeight;
}
public static void SetFromBoneWeight(this EditableBoneWeight editableBoneWeight, BoneWeight boneWeight)
{
editableBoneWeight.Clamp(4, false);
while (editableBoneWeight.Count < 4)
editableBoneWeight.AddChannel(0, 0f, false);
for (var i = 0; i < 4; ++i)
{
var weight = boneWeight.GetWeight(i);
editableBoneWeight[i].boneIndex = boneWeight.GetBoneIndex(i);
editableBoneWeight[i].weight = weight;
editableBoneWeight[i].enabled = weight > 0f;
}
}
public static BoneWeight ToBoneWeight(this EditableBoneWeight editableBoneWeight, bool sortByWeight)
{
var boneWeight = new BoneWeight();
if (editableBoneWeight.Count > 0)
{
s_BoneWeightDataList.Clear();
s_BoneWeightDataList.Capacity = editableBoneWeight.Count;
for (var i = 0; i < editableBoneWeight.Count; ++i)
{
s_BoneWeightDataList.Add(new BoneWeightData()
{
boneIndex = editableBoneWeight[i].boneIndex,
weight = editableBoneWeight[i].weight
});
}
if (sortByWeight)
s_BoneWeightDataList.Sort();
var count = Mathf.Min(editableBoneWeight.Count, 4);
for (var i = 0; i < count; ++i)
{
BoneWeightExtensions.SetBoneIndex(ref boneWeight, i, s_BoneWeightDataList[i].boneIndex);
BoneWeightExtensions.SetWeight(ref boneWeight, i, s_BoneWeightDataList[i].weight);
}
}
return boneWeight;
}
public static bool ContainsBoneIndex(this EditableBoneWeight editableBoneWeight, int boneIndex)
{
return GetChannelFromBoneIndex(editableBoneWeight, boneIndex) > -1;
}
public static int GetChannelFromBoneIndex(this EditableBoneWeight editableBoneWeight, int boneIndex)
{
for (int i = 0; i < editableBoneWeight.Count; ++i)
if (editableBoneWeight[i].enabled && editableBoneWeight[i].boneIndex == boneIndex)
return i;
return -1;
}
public static void Clamp(this EditableBoneWeight editableBoneWeight, int numChannels, bool sortChannels = true)
{
if (sortChannels)
editableBoneWeight.Sort();
while (editableBoneWeight.Count > numChannels)
editableBoneWeight.RemoveChannel(numChannels);
}
public static void ValidateChannels(this EditableBoneWeight editableBoneWeight)
{
for (int i = 0; i < editableBoneWeight.Count; ++i)
{
var weight = editableBoneWeight[i].weight;
if (!editableBoneWeight[i].enabled)
weight = 0f;
weight = Mathf.Clamp01(weight);
editableBoneWeight[i].weight = weight;
}
}
public static float Sum(this EditableBoneWeight editableBoneWeight)
{
var sum = 0f;
for (var i = 0; i < editableBoneWeight.Count; ++i)
if (editableBoneWeight[i].enabled)
sum += editableBoneWeight[i].weight;
return sum;
}
public static void Normalize(this EditableBoneWeight editableBoneWeight)
{
ValidateChannels(editableBoneWeight);
var sum = editableBoneWeight.Sum();
if (sum == 0f || sum == 1f)
return;
var sumInv = 1f / sum;
for (var i = 0; i < editableBoneWeight.Count; ++i)
if (editableBoneWeight[i].enabled)
editableBoneWeight[i].weight *= sumInv;
}
public static void CompensateOtherChannels(this EditableBoneWeight editableBoneWeight, int masterChannel)
{
ValidateChannels(editableBoneWeight);
var validChannelCount = 0;
var sum = 0f;
for (int i = 0; i < editableBoneWeight.Count; ++i)
{
if (i != masterChannel && editableBoneWeight[i].enabled)
{
sum += editableBoneWeight[i].weight;
++validChannelCount;
}
}
if (validChannelCount == 0)
return;
var targetSum = 1f - editableBoneWeight[masterChannel].weight;
for (var i = 0; i < editableBoneWeight.Count; ++i)
{
if (i != masterChannel && editableBoneWeight[i].enabled)
{
if (sum == 0f)
editableBoneWeight[i].weight = targetSum / validChannelCount;
else
editableBoneWeight[i].weight *= targetSum / sum;
}
}
}
public static void UnifyChannelsWithSameBoneIndex(this EditableBoneWeight editableBoneWeight)
{
for (var i = 0; i < editableBoneWeight.Count; ++i)
{
if (!editableBoneWeight[i].enabled)
continue;
bool weightChanged = false;
for (var j = i + 1; j < editableBoneWeight.Count; ++j)
{
if (editableBoneWeight[j].boneIndex == editableBoneWeight[i].boneIndex)
{
weightChanged = true;
editableBoneWeight[i].weight += editableBoneWeight[j].weight;
editableBoneWeight[j].enabled = false;
}
}
if (weightChanged)
editableBoneWeight.CompensateOtherChannels(i);
}
}
public static void FilterChannels(this EditableBoneWeight editableBoneWeight, float weightTolerance)
{
for (var i = 0; i < editableBoneWeight.Count; ++i)
{
if (editableBoneWeight[i].weight <= weightTolerance)
{
editableBoneWeight[i].boneIndex = 0;
editableBoneWeight[i].weight = 0f;
editableBoneWeight[i].enabled = false;
}
}
}
public static BoneWeight Lerp(BoneWeight first, BoneWeight second, float t)
{
s_LerpFirst.SetFromBoneWeight(first);
s_LerpSecond.SetFromBoneWeight(second);
Lerp(s_LerpFirst, s_LerpSecond, ref s_LerpResult, t);
return s_LerpResult.ToBoneWeight(true);
}
private static void Lerp(EditableBoneWeight first, EditableBoneWeight second, ref EditableBoneWeight result, float t)
{
result.Clear();
foreach (BoneWeightChannel channel in first)
{
if (!channel.enabled)
continue;
var weight = channel.weight * (1f - t);
if (weight > 0f)
result.AddChannel(channel.boneIndex, weight, true);
}
foreach (BoneWeightChannel channel in second)
{
if (!channel.enabled)
continue;
var weight = channel.weight * t;
if (weight > 0f)
result.AddChannel(channel.boneIndex, weight, true);
}
result.UnifyChannelsWithSameBoneIndex();
result.Clamp(4);
if (result.Sum() > 1f)
result.Normalize();
result.FilterChannels(0f);
}
}
}