v1.00.00
This commit is contained in:
538
AssetStudioUtility/YAML/AnimationClipConverter.cs
Normal file
538
AssetStudioUtility/YAML/AnimationClipConverter.cs
Normal file
@@ -0,0 +1,538 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using SevenZip;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class AnimationClipConverter
|
||||
{
|
||||
public static readonly Regex UnknownPathRegex = new Regex($@"^{UnknownPathPrefix}[0-9]{{1,10}}$", RegexOptions.Compiled);
|
||||
|
||||
private const string UnknownPathPrefix = "path_";
|
||||
private const string MissedPropertyPrefix = "missed_";
|
||||
private const string ScriptPropertyPrefix = "script_";
|
||||
private const string TypeTreePropertyPrefix = "typetree_";
|
||||
|
||||
private readonly Game game;
|
||||
private readonly AnimationClip animationClip;
|
||||
private readonly CustomCurveResolver m_customCurveResolver;
|
||||
|
||||
private readonly Dictionary<Vector3Curve, List<Keyframe<Vector3>>> m_translations = new Dictionary<Vector3Curve, List<Keyframe<Vector3>>>();
|
||||
private readonly Dictionary<QuaternionCurve, List<Keyframe<Quaternion>>> m_rotations = new Dictionary<QuaternionCurve, List<Keyframe<Quaternion>>>();
|
||||
private readonly Dictionary<Vector3Curve, List<Keyframe<Vector3>>> m_scales = new Dictionary<Vector3Curve, List<Keyframe<Vector3>>>();
|
||||
private readonly Dictionary<Vector3Curve, List<Keyframe<Vector3>>> m_eulers = new Dictionary<Vector3Curve, List<Keyframe<Vector3>>>();
|
||||
private readonly Dictionary<FloatCurve, List<Keyframe<Float>>> m_floats = new Dictionary<FloatCurve, List<Keyframe<Float>>>();
|
||||
private readonly Dictionary<PPtrCurve, List<PPtrKeyframe>> m_pptrs = new Dictionary<PPtrCurve, List<PPtrKeyframe>>();
|
||||
|
||||
public Vector3Curve[] Translations { get; private set; }
|
||||
public QuaternionCurve[] Rotations { get; private set; }
|
||||
public Vector3Curve[] Scales { get; private set; }
|
||||
public Vector3Curve[] Eulers { get; private set; }
|
||||
public FloatCurve[] Floats { get; private set; }
|
||||
public PPtrCurve[] PPtrs { get; private set; }
|
||||
|
||||
public AnimationClipConverter(AnimationClip clip)
|
||||
{
|
||||
game = clip.assetsFile.game;
|
||||
animationClip = clip;
|
||||
m_customCurveResolver = new CustomCurveResolver(animationClip);
|
||||
}
|
||||
|
||||
public static AnimationClipConverter Process(AnimationClip clip)
|
||||
{
|
||||
var converter = new AnimationClipConverter(clip);
|
||||
converter.ProcessInner();
|
||||
return converter;
|
||||
}
|
||||
private void ProcessInner()
|
||||
{
|
||||
var m_Clip = animationClip.m_MuscleClip.m_Clip;
|
||||
var bindings = animationClip.m_ClipBindingConstant;
|
||||
var tos = animationClip.FindTOS();
|
||||
|
||||
var streamedFrames = m_Clip.m_StreamedClip.ReadData();
|
||||
var lastDenseFrame = m_Clip.m_DenseClip.m_FrameCount / m_Clip.m_DenseClip.m_SampleRate;
|
||||
var lastSampleFrame = streamedFrames.Count > 1 ? streamedFrames[streamedFrames.Count - 2].time : 0.0f;
|
||||
var lastFrame = Math.Max(lastDenseFrame, lastSampleFrame);
|
||||
|
||||
if (!m_Clip.m_ACLClip.m_ClipData.IsNullOrEmpty() && !game.Type.IsSRGroup())
|
||||
{
|
||||
var lastACLFrame = ProcessACLClip(m_Clip, bindings, tos);
|
||||
lastFrame = Math.Max(lastFrame, lastACLFrame);
|
||||
animationClip.m_Compressed = false;
|
||||
}
|
||||
ProcessStreams(streamedFrames, bindings, tos, m_Clip.m_DenseClip.m_SampleRate);
|
||||
ProcessDenses(m_Clip, bindings, tos);
|
||||
if (!m_Clip.m_ACLClip.m_ClipData.IsNullOrEmpty() && game.Type.IsSRGroup())
|
||||
{
|
||||
var lastACLFrame = ProcessACLClip(m_Clip, bindings, tos);
|
||||
lastFrame = Math.Max(lastFrame, lastACLFrame);
|
||||
animationClip.m_Compressed = false;
|
||||
}
|
||||
if (m_Clip.m_ConstantClip != null)
|
||||
{
|
||||
ProcessConstant(m_Clip, bindings, tos, lastFrame);
|
||||
}
|
||||
CreateCurves();
|
||||
}
|
||||
|
||||
private void CreateCurves()
|
||||
{
|
||||
m_translations.AsEnumerable().ToList().ForEach(x => x.Key.curve.m_Curve.AddRange(x.Value));
|
||||
Translations = m_translations.Keys.ToArray();
|
||||
m_rotations.AsEnumerable().ToList().ForEach(x => x.Key.curve.m_Curve.AddRange(x.Value));
|
||||
Rotations = m_rotations.Keys.ToArray();
|
||||
m_scales.AsEnumerable().ToList().ForEach(x => x.Key.curve.m_Curve.AddRange(x.Value));
|
||||
Scales = m_scales.Keys.ToArray();
|
||||
m_eulers.AsEnumerable().ToList().ForEach(x => x.Key.curve.m_Curve.AddRange(x.Value));
|
||||
Eulers = m_eulers.Keys.ToArray();
|
||||
m_floats.AsEnumerable().ToList().ForEach(x => x.Key.curve.m_Curve.AddRange(x.Value));
|
||||
Floats = m_floats.Keys.ToArray();
|
||||
m_pptrs.AsEnumerable().ToList().ForEach(x => x.Key.curve.AddRange(x.Value));
|
||||
PPtrs = m_pptrs.Keys.ToArray();
|
||||
}
|
||||
|
||||
private void ProcessStreams(List<StreamedClip.StreamedFrame> streamFrames, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos, float sampleRate)
|
||||
{
|
||||
var curveValues = new float[4];
|
||||
var inSlopeValues = new float[4];
|
||||
var outSlopeValues = new float[4];
|
||||
var interval = 1.0f / sampleRate;
|
||||
|
||||
// first (index [0]) stream frame is for slope calculation for the first real frame (index [1])
|
||||
// last one (index [count - 1]) is +Infinity
|
||||
// it is made for slope processing, but we don't need them
|
||||
for (var frameIndex = 1; frameIndex < streamFrames.Count - 1; frameIndex++)
|
||||
{
|
||||
var frame = streamFrames[frameIndex];
|
||||
for (var curveIndex = 0; curveIndex < frame.keyList.Length;)
|
||||
{
|
||||
var curve = frame.keyList[curveIndex];
|
||||
var index = curve.index;
|
||||
if (!game.Type.IsSRGroup())
|
||||
index += (int)animationClip.m_MuscleClip.m_Clip.m_ACLClip.m_CurveCount;
|
||||
var binding = bindings.FindBinding(index);
|
||||
|
||||
var path = GetCurvePath(tos, binding.path);
|
||||
if (binding.typeID == ClassIDType.Transform)
|
||||
{
|
||||
GetPreviousFrame(streamFrames, curve.index, frameIndex, out var prevFrameIndex, out var prevCurveIndex);
|
||||
var dimension = binding.GetDimension();
|
||||
for (int key = 0; key < dimension; key++)
|
||||
{
|
||||
var keyCurve = frame.keyList[curveIndex];
|
||||
var prevFrame = streamFrames[prevFrameIndex];
|
||||
var prevKeyCurve = prevFrame.keyList[prevCurveIndex + key];
|
||||
var deltaTime = frame.time - prevFrame.time;
|
||||
curveValues[key] = keyCurve.value;
|
||||
inSlopeValues[key] = prevKeyCurve.CalculateNextInSlope(deltaTime, keyCurve);
|
||||
outSlopeValues[key] = keyCurve.outSlope;
|
||||
curveIndex = GetNextCurve(frame, curveIndex);
|
||||
}
|
||||
|
||||
AddTransformCurve(frame.time, binding.attribute, curveValues, inSlopeValues, outSlopeValues, 0, path);
|
||||
}
|
||||
else if ((BindingCustomType)binding.customType == BindingCustomType.None)
|
||||
{
|
||||
AddDefaultCurve(binding, path, frame.time, frame.keyList[curveIndex].value);
|
||||
curveIndex = GetNextCurve(frame, curveIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCustomCurve(bindings, binding, path, frame.time, frame.keyList[curveIndex].value);
|
||||
curveIndex = GetNextCurve(frame, curveIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessDenses(Clip clip, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos)
|
||||
{
|
||||
var dense = clip.m_DenseClip;
|
||||
var streamCount = clip.m_StreamedClip.curveCount;
|
||||
var slopeValues = new float[4]; // no slopes - 0 values
|
||||
for (var frameIndex = 0; frameIndex < dense.m_FrameCount; frameIndex++)
|
||||
{
|
||||
var time = frameIndex / dense.m_SampleRate;
|
||||
var frameOffset = frameIndex * (int)dense.m_CurveCount;
|
||||
for (var curveIndex = 0; curveIndex < dense.m_CurveCount;)
|
||||
{
|
||||
var index = (int)streamCount + curveIndex;
|
||||
if (!game.Type.IsSRGroup())
|
||||
index += (int)clip.m_ACLClip.m_CurveCount;
|
||||
var binding = bindings.FindBinding(index);
|
||||
var path = GetCurvePath(tos, binding.path);
|
||||
var framePosition = frameOffset + curveIndex;
|
||||
if (binding.typeID == ClassIDType.Transform)
|
||||
{
|
||||
AddTransformCurve(time, binding.attribute, dense.m_SampleArray, slopeValues, slopeValues, framePosition, path);
|
||||
curveIndex += binding.GetDimension();
|
||||
}
|
||||
else if ((BindingCustomType)binding.customType == BindingCustomType.None)
|
||||
{
|
||||
AddDefaultCurve(binding, path, time, dense.m_SampleArray[framePosition]);
|
||||
curveIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCustomCurve(bindings, binding, path, time, dense.m_SampleArray[framePosition]);
|
||||
curveIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private float ProcessACLClip(Clip clip, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos)
|
||||
{
|
||||
var acl = clip.m_ACLClip;
|
||||
acl.Process(game, out var values, out var times);
|
||||
float[] slopeValues = new float[4]; // no slopes - 0 values
|
||||
|
||||
int frameCount = times.Length;
|
||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
|
||||
{
|
||||
float time = times[frameIndex];
|
||||
int frameOffset = frameIndex * (int)acl.m_CurveCount;
|
||||
for (int curveIndex = 0; curveIndex < acl.m_CurveCount;)
|
||||
{
|
||||
var index = curveIndex;
|
||||
if (game.Type.IsSRGroup())
|
||||
index += (int)(clip.m_DenseClip.m_CurveCount + clip.m_StreamedClip.curveCount);
|
||||
GenericBinding binding = bindings.FindBinding(index);
|
||||
string path = GetCurvePath(tos, binding.path);
|
||||
int framePosition = frameOffset + curveIndex;
|
||||
if (binding.typeID == ClassIDType.Transform)
|
||||
{
|
||||
AddTransformCurve(time, binding.attribute, values, slopeValues, slopeValues, framePosition, path);
|
||||
curveIndex += binding.GetDimension();
|
||||
}
|
||||
else if ((BindingCustomType)binding.customType == BindingCustomType.None)
|
||||
{
|
||||
AddDefaultCurve(binding, path, time, values[framePosition]);
|
||||
curveIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCustomCurve(bindings, binding, path, time, values[framePosition]);
|
||||
curveIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return times[frameCount - 1];
|
||||
}
|
||||
private void ProcessConstant(Clip clip, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos, float lastFrame)
|
||||
{
|
||||
var constant = clip.m_ConstantClip;
|
||||
var streamCount = clip.m_StreamedClip.curveCount;
|
||||
var denseCount = clip.m_DenseClip.m_CurveCount;
|
||||
var slopeValues = new float[4]; // no slopes - 0 values
|
||||
|
||||
// only first and last frames
|
||||
var time = 0.0f;
|
||||
for (var i = 0; i < 2; i++, time += lastFrame)
|
||||
{
|
||||
for (var curveIndex = 0; curveIndex < constant.data.Length;)
|
||||
{
|
||||
var index = (int)(streamCount + denseCount + curveIndex);
|
||||
if (!clip.m_ACLClip.m_ClipData.IsNullOrEmpty())
|
||||
index += (int)clip.m_ACLClip.m_CurveCount;
|
||||
GenericBinding binding = bindings.FindBinding(index);
|
||||
string path = GetCurvePath(tos, binding.path);
|
||||
if (binding.typeID == ClassIDType.Transform)
|
||||
{
|
||||
AddTransformCurve(time, binding.attribute, constant.data, slopeValues, slopeValues, curveIndex, path);
|
||||
curveIndex += binding.GetDimension();
|
||||
}
|
||||
else if ((BindingCustomType)binding.customType == BindingCustomType.None)
|
||||
{
|
||||
AddDefaultCurve(binding, path, time, constant.data[curveIndex]);
|
||||
curveIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCustomCurve(bindings, binding, path, time, constant.data[curveIndex]);
|
||||
curveIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCustomCurve(AnimationClipBindingConstant bindings, GenericBinding binding, string path, float time, float value)
|
||||
{
|
||||
switch ((BindingCustomType)binding.customType)
|
||||
{
|
||||
case BindingCustomType.AnimatorMuscle:
|
||||
AddAnimatorMuscleCurve(binding, time, value);
|
||||
break;
|
||||
default:
|
||||
string attribute = m_customCurveResolver.ToAttributeName((BindingCustomType)binding.customType, binding.attribute, path);
|
||||
if (binding.isPPtrCurve == 0x01)
|
||||
{
|
||||
PPtrCurve curve = new PPtrCurve(path, attribute, binding.typeID, binding.script.Cast<MonoScript>());
|
||||
AddPPtrKeyframe(curve, bindings, time, (int)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
FloatCurve curve = new FloatCurve(path, attribute, binding.typeID, binding.script.Cast<MonoScript>());
|
||||
AddFloatKeyframe(curve, time, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddTransformCurve(float time, uint transType, float[] curveValues,
|
||||
float[] inSlopeValues, float[] outSlopeValues, int offset, string path)
|
||||
{
|
||||
switch (transType)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
var curve = new Vector3Curve(path);
|
||||
if (!m_translations.TryGetValue(curve, out List<Keyframe<Vector3>> transCurve))
|
||||
{
|
||||
transCurve = new List<Keyframe<Vector3>>();
|
||||
m_translations.Add(curve, transCurve);
|
||||
}
|
||||
|
||||
float x = curveValues[offset + 0];
|
||||
float y = curveValues[offset + 1];
|
||||
float z = curveValues[offset + 2];
|
||||
|
||||
float inX = inSlopeValues[0];
|
||||
float inY = inSlopeValues[1];
|
||||
float inZ = inSlopeValues[2];
|
||||
|
||||
float outX = outSlopeValues[0];
|
||||
float outY = outSlopeValues[1];
|
||||
float outZ = outSlopeValues[2];
|
||||
|
||||
Vector3 value = new Vector3(x, y, z);
|
||||
Vector3 inSlope = new Vector3(inX, inY, inZ);
|
||||
Vector3 outSlope = new Vector3(outX, outY, outZ);
|
||||
Keyframe<Vector3> transKey = new Keyframe<Vector3>(time, value, inSlope, outSlope, AnimationClipExtensions.DefaultVector3Weight);
|
||||
transCurve.Add(transKey);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
var curve = new QuaternionCurve(path);
|
||||
if (!m_rotations.TryGetValue(curve, out List<Keyframe<Quaternion>> rotCurve))
|
||||
{
|
||||
rotCurve = new List<Keyframe<Quaternion>>();
|
||||
m_rotations.Add(curve, rotCurve);
|
||||
}
|
||||
|
||||
float x = curveValues[offset + 0];
|
||||
float y = curveValues[offset + 1];
|
||||
float z = curveValues[offset + 2];
|
||||
float w = curveValues[offset + 3];
|
||||
|
||||
float inX = inSlopeValues[0];
|
||||
float inY = inSlopeValues[1];
|
||||
float inZ = inSlopeValues[2];
|
||||
float inW = inSlopeValues[3];
|
||||
|
||||
float outX = outSlopeValues[0];
|
||||
float outY = outSlopeValues[1];
|
||||
float outZ = outSlopeValues[2];
|
||||
float outW = outSlopeValues[3];
|
||||
|
||||
Quaternion value = new Quaternion(x, y, z, w);
|
||||
Quaternion inSlope = new Quaternion(inX, inY, inZ, inW);
|
||||
Quaternion outSlope = new Quaternion(outX, outY, outZ, outW);
|
||||
Keyframe<Quaternion> rotKey = new Keyframe<Quaternion>(time, value, inSlope, outSlope, AnimationClipExtensions.DefaultQuaternionWeight);
|
||||
rotCurve.Add(rotKey);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
var curve = new Vector3Curve(path);
|
||||
if (!m_scales.TryGetValue(curve, out List<Keyframe<Vector3>> scaleCurve))
|
||||
{
|
||||
scaleCurve = new List<Keyframe<Vector3>>();
|
||||
m_scales.Add(curve, scaleCurve);
|
||||
}
|
||||
|
||||
float x = curveValues[offset + 0];
|
||||
float y = curveValues[offset + 1];
|
||||
float z = curveValues[offset + 2];
|
||||
|
||||
float inX = inSlopeValues[0];
|
||||
float inY = inSlopeValues[1];
|
||||
float inZ = inSlopeValues[2];
|
||||
|
||||
float outX = outSlopeValues[0];
|
||||
float outY = outSlopeValues[1];
|
||||
float outZ = outSlopeValues[2];
|
||||
|
||||
Vector3 value = new Vector3(x, y, z);
|
||||
Vector3 inSlope = new Vector3(inX, inY, inZ);
|
||||
Vector3 outSlope = new Vector3(outX, outY, outZ);
|
||||
Keyframe<Vector3> scaleKey = new Keyframe<Vector3>(time, value, inSlope, outSlope, AnimationClipExtensions.DefaultVector3Weight);
|
||||
scaleCurve.Add(scaleKey);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
var curve = new Vector3Curve(path);
|
||||
if (!m_eulers.TryGetValue(curve, out List<Keyframe<Vector3>> eulerCurve))
|
||||
{
|
||||
eulerCurve = new List<Keyframe<Vector3>>();
|
||||
m_eulers.Add(curve, eulerCurve);
|
||||
}
|
||||
|
||||
float x = curveValues[offset + 0];
|
||||
float y = curveValues[offset + 1];
|
||||
float z = curveValues[offset + 2];
|
||||
|
||||
float inX = inSlopeValues[0];
|
||||
float inY = inSlopeValues[1];
|
||||
float inZ = inSlopeValues[2];
|
||||
|
||||
float outX = outSlopeValues[0];
|
||||
float outY = outSlopeValues[1];
|
||||
float outZ = outSlopeValues[2];
|
||||
|
||||
Vector3 value = new Vector3(x, y, z);
|
||||
Vector3 inSlope = new Vector3(inX, inY, inZ);
|
||||
Vector3 outSlope = new Vector3(outX, outY, outZ);
|
||||
Keyframe<Vector3> eulerKey = new Keyframe<Vector3>(time, value, inSlope, outSlope, AnimationClipExtensions.DefaultVector3Weight);
|
||||
eulerCurve.Add(eulerKey);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(transType.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void AddDefaultCurve(GenericBinding binding, string path, float time, float value)
|
||||
{
|
||||
switch (binding.typeID)
|
||||
{
|
||||
case ClassIDType.GameObject:
|
||||
{
|
||||
AddGameObjectCurve(binding, path, time, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ClassIDType.MonoBehaviour:
|
||||
{
|
||||
AddScriptCurve(binding, path, time, value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
AddEngineCurve(binding, path, time, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddGameObjectCurve(GenericBinding binding, string path, float time, float value)
|
||||
{
|
||||
if (binding.attribute == CRC.CalculateDigestAscii("m_IsActive"))
|
||||
{
|
||||
FloatCurve curve = new FloatCurve(path, "m_IsActive", ClassIDType.GameObject, new PPtr<MonoScript>(0, 0, null));
|
||||
AddFloatKeyframe(curve, time, value);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// that means that dev exported animation clip with missing component
|
||||
FloatCurve curve = new FloatCurve(path, MissedPropertyPrefix + binding.attribute, ClassIDType.GameObject, new PPtr<MonoScript>(0, 0, null));
|
||||
AddFloatKeyframe(curve, time, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddScriptCurve(GenericBinding binding, string path, float time, float value)
|
||||
{
|
||||
#warning TODO:
|
||||
FloatCurve curve = new FloatCurve(path, ScriptPropertyPrefix + binding.attribute, ClassIDType.MonoBehaviour, binding.script.Cast<MonoScript>());
|
||||
AddFloatKeyframe(curve, time, value);
|
||||
}
|
||||
|
||||
private void AddEngineCurve(GenericBinding binding, string path, float time, float value)
|
||||
{
|
||||
#warning TODO:
|
||||
FloatCurve curve = new FloatCurve(path, TypeTreePropertyPrefix + binding.attribute, binding.typeID, new PPtr<MonoScript>(0, 0, null));
|
||||
AddFloatKeyframe(curve, time, value);
|
||||
}
|
||||
|
||||
private void AddAnimatorMuscleCurve(GenericBinding binding, float time, float value)
|
||||
{
|
||||
FloatCurve curve = new FloatCurve(string.Empty, binding.GetHumanoidMuscle().ToAttributeString(), ClassIDType.Animator, new PPtr<MonoScript>(0, 0, null));
|
||||
AddFloatKeyframe(curve, time, value);
|
||||
}
|
||||
|
||||
private void AddFloatKeyframe(FloatCurve curve, float time, float value)
|
||||
{
|
||||
if (!m_floats.TryGetValue(curve, out List<Keyframe<Float>> floatCurve))
|
||||
{
|
||||
floatCurve = new List<Keyframe<Float>>();
|
||||
m_floats.Add(curve, floatCurve);
|
||||
}
|
||||
|
||||
Keyframe<Float> floatKey = new Keyframe<Float>(time, value, default, default, AnimationClipExtensions.DefaultFloatWeight);
|
||||
floatCurve.Add(floatKey);
|
||||
}
|
||||
|
||||
private void AddPPtrKeyframe(PPtrCurve curve, AnimationClipBindingConstant bindings, float time, int index)
|
||||
{
|
||||
if (!m_pptrs.TryGetValue(curve, out List<PPtrKeyframe> pptrCurve))
|
||||
{
|
||||
pptrCurve = new List<PPtrKeyframe>();
|
||||
m_pptrs.Add(curve, pptrCurve);
|
||||
AddPPtrKeyframe(curve, bindings, 0.0f, index - 1);
|
||||
}
|
||||
|
||||
PPtr<Object> value = bindings.pptrCurveMapping[index];
|
||||
PPtrKeyframe pptrKey = new PPtrKeyframe(time, value);
|
||||
pptrCurve.Add(pptrKey);
|
||||
}
|
||||
|
||||
private void GetPreviousFrame(List<StreamedClip.StreamedFrame> streamFrames, int curveID, int currentFrame, out int frameIndex, out int curveIndex)
|
||||
{
|
||||
for (frameIndex = currentFrame - 1; frameIndex >= 0; frameIndex--)
|
||||
{
|
||||
var frame = streamFrames[frameIndex];
|
||||
for (curveIndex = 0; curveIndex < frame.keyList.Length; curveIndex++)
|
||||
{
|
||||
var curve = frame.keyList[curveIndex];
|
||||
if (curve.index == curveID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Exception($"There is no curve with index {curveID} in any of previous frames");
|
||||
}
|
||||
|
||||
private int GetNextCurve(StreamedClip.StreamedFrame frame, int currentCurve)
|
||||
{
|
||||
var curve = frame.keyList[currentCurve];
|
||||
int i = currentCurve + 1;
|
||||
for (; i < frame.keyList.Length; i++)
|
||||
{
|
||||
if (frame.keyList[i].index != curve.index)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
private static string GetCurvePath(Dictionary<uint, string> tos, uint hash)
|
||||
{
|
||||
if (tos.TryGetValue(hash, out string path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
else
|
||||
{
|
||||
return UnknownPathPrefix + hash;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
335
AssetStudioUtility/YAML/AnimationClipExtensions.cs
Normal file
335
AssetStudioUtility/YAML/AnimationClipExtensions.cs
Normal file
@@ -0,0 +1,335 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using SevenZip;
|
||||
using System;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class AnimationClipExtensions
|
||||
{
|
||||
public static float DefaultFloatWeight => 1.0f / 3.0f;
|
||||
public static Vector3 DefaultVector3Weight => new Vector3(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f);
|
||||
public static Quaternion DefaultQuaternionWeight => new Quaternion(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f);
|
||||
|
||||
#region AnimationClip
|
||||
public static IEnumerable<GameObject> FindRoots(this AnimationClip clip)
|
||||
{
|
||||
foreach (var asset in clip.assetsFile.assetsManager.assetsFileList.SelectMany(x => x.Objects))
|
||||
{
|
||||
switch (asset.type)
|
||||
{
|
||||
case ClassIDType.Animator:
|
||||
Animator animator = (Animator)asset;
|
||||
if (clip.IsAnimatorContainsClip(animator))
|
||||
{
|
||||
if (animator.m_GameObject.TryGet(out var go))
|
||||
{
|
||||
yield return go;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ClassIDType.Animation:
|
||||
Animation animation = (Animation)asset;
|
||||
if (clip.IsAnimationContainsClip(animation))
|
||||
{
|
||||
if (animation.m_GameObject.TryGet(out var go))
|
||||
{
|
||||
yield return go;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
public static Dictionary<uint, string> FindTOS(this AnimationClip clip)
|
||||
{
|
||||
var tos = new Dictionary<uint, string>() { { 0, string.Empty } };
|
||||
foreach (var asset in clip.assetsFile.assetsManager.assetsFileList.SelectMany(x => x.Objects).OrderBy(x => x.type).ToArray())
|
||||
{
|
||||
switch (asset.type)
|
||||
{
|
||||
case ClassIDType.Avatar:
|
||||
var avatar = asset as Avatar;
|
||||
if (clip.AddAvatarTOS(avatar, tos))
|
||||
{
|
||||
return tos;
|
||||
}
|
||||
break;
|
||||
case ClassIDType.Animator:
|
||||
var animator = asset as Animator;
|
||||
if (clip.IsAnimatorContainsClip(animator))
|
||||
{
|
||||
if (clip.AddAnimatorTOS(animator, tos))
|
||||
{
|
||||
return tos;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ClassIDType.Animation:
|
||||
var animation = asset as Animation;
|
||||
if (clip.IsAnimationContainsClip(animation))
|
||||
{
|
||||
if (clip.AddAnimationTOS(animation, tos))
|
||||
{
|
||||
return tos;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return tos;
|
||||
}
|
||||
private static bool AddAvatarTOS(this AnimationClip clip, Avatar avatar, Dictionary<uint, string> tos)
|
||||
{
|
||||
return clip.AddTOS(avatar.m_TOS.ToDictionary(x => x.Key, x => x.Value), tos);
|
||||
}
|
||||
private static bool AddAnimatorTOS(this AnimationClip clip, Animator animator, Dictionary<uint, string> tos)
|
||||
{
|
||||
if (animator.m_Avatar.TryGet(out var avatar))
|
||||
{
|
||||
if (clip.AddAvatarTOS(avatar, tos))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<uint, string> animatorTOS = animator.BuildTOS();
|
||||
return clip.AddTOS(animatorTOS, tos);
|
||||
}
|
||||
private static bool AddAnimationTOS(this AnimationClip clip, Animation animation, Dictionary<uint, string> tos)
|
||||
{
|
||||
if (animation.m_GameObject.TryGet(out var go))
|
||||
{
|
||||
Dictionary<uint, string> animationTOS = go.BuildTOS();
|
||||
return clip.AddTOS(animationTOS, tos);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static bool AddTOS(this AnimationClip clip, Dictionary<uint, string> src, Dictionary<uint, string> dest)
|
||||
{
|
||||
int tosCount = clip.m_ClipBindingConstant.genericBindings.Length;
|
||||
for (int i = 0; i < tosCount; i++)
|
||||
{
|
||||
ref GenericBinding binding = ref clip.m_ClipBindingConstant.genericBindings[i];
|
||||
if (src.TryGetValue(binding.path, out string path))
|
||||
{
|
||||
dest[binding.path] = path;
|
||||
if (dest.Count == tosCount)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static bool IsAnimationContainsClip(this AnimationClip clip, Animation animation)
|
||||
{
|
||||
return animation.IsContainsAnimationClip(clip);
|
||||
}
|
||||
private static bool IsAnimatorContainsClip(this AnimationClip clip, Animator animator)
|
||||
{
|
||||
if (animator.m_Controller.TryGet(out var runtime))
|
||||
{
|
||||
return runtime.IsContainsAnimationClip(clip);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static string Convert(this AnimationClip clip)
|
||||
{
|
||||
var converter = AnimationClipConverter.Process(clip);
|
||||
clip.m_RotationCurves = converter.Rotations.Union(clip.m_RotationCurves).ToArray();
|
||||
clip.m_EulerCurves = converter.Eulers.Union(clip.m_EulerCurves).ToArray();
|
||||
clip.m_PositionCurves = converter.Translations.Union(clip.m_PositionCurves).ToArray();
|
||||
clip.m_ScaleCurves = converter.Scales.Union(clip.m_ScaleCurves).ToArray();
|
||||
clip.m_FloatCurves = converter.Floats.Union(clip.m_FloatCurves).ToArray();
|
||||
clip.m_PPtrCurves = converter.PPtrs.Union(clip.m_PPtrCurves).ToArray();
|
||||
return ConvertSerializedAnimationClip(clip);
|
||||
}
|
||||
public static string ConvertSerializedAnimationClip(AnimationClip animationClip)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
using (var stringWriter = new StringWriter(sb))
|
||||
{
|
||||
YAMLWriter writer = new YAMLWriter();
|
||||
YAMLDocument doc = ExportYAMLDocument(animationClip);
|
||||
writer.AddDocument(doc);
|
||||
writer.Write(stringWriter);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static YAMLDocument ExportYAMLDocument(AnimationClip animationClip)
|
||||
{
|
||||
var document = new YAMLDocument();
|
||||
var root = document.CreateMappingRoot();
|
||||
root.Tag = ((int)ClassIDType.AnimationClip).ToString();
|
||||
root.Anchor = ((int)ClassIDType.AnimationClip * 100000).ToString();
|
||||
var node = animationClip.ExportYAML(animationClip.version);
|
||||
root.Add(ClassIDType.AnimationClip.ToString(), node);
|
||||
return document;
|
||||
}
|
||||
public static YAMLMappingNode ExportYAML(this AnimationClip clip, int[] version)
|
||||
{
|
||||
var node = new YAMLMappingNode();
|
||||
node.Add(nameof(clip.m_Name), clip.m_Name);
|
||||
node.AddSerializedVersion(ToSerializedVersion(version));
|
||||
node.Add(nameof(clip.m_Legacy), clip.m_Legacy);
|
||||
node.Add(nameof(clip.m_Compressed), clip.m_Compressed);
|
||||
node.Add(nameof(clip.m_UseHighQualityCurve), clip.m_UseHighQualityCurve);
|
||||
node.Add(nameof(clip.m_RotationCurves), clip.m_RotationCurves.ExportYAML(version));
|
||||
node.Add(nameof(clip.m_CompressedRotationCurves), clip.m_CompressedRotationCurves.ExportYAML(version));
|
||||
node.Add(nameof(clip.m_EulerCurves), clip.m_EulerCurves.ExportYAML(version));
|
||||
node.Add(nameof(clip.m_PositionCurves), clip.m_PositionCurves.ExportYAML(version));
|
||||
node.Add(nameof(clip.m_ScaleCurves), clip.m_ScaleCurves.ExportYAML(version));
|
||||
node.Add(nameof(clip.m_FloatCurves), clip.m_FloatCurves.ExportYAML(version));
|
||||
node.Add(nameof(clip.m_PPtrCurves), clip.m_PPtrCurves.ExportYAML(version));
|
||||
node.Add(nameof(clip.m_SampleRate), clip.m_SampleRate);
|
||||
node.Add(nameof(clip.m_WrapMode), clip.m_WrapMode);
|
||||
node.Add(nameof(clip.m_Bounds), clip.m_Bounds.ExportYAML(version));
|
||||
node.Add(nameof(clip.m_ClipBindingConstant), clip.m_ClipBindingConstant.ExportYAML(version));
|
||||
node.Add("m_AnimationClipSettings", clip.m_MuscleClip.ExportYAML(version));
|
||||
node.Add(nameof(clip.m_Events), clip.m_Events.ExportYAML(version));
|
||||
return node;
|
||||
}
|
||||
|
||||
public static int ToSerializedVersion(int[] version)
|
||||
{
|
||||
if (version[0] >= 5)
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3))
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
if (version[0] > 2 || (version[0] == 2 && version[1] >= 6))
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Others
|
||||
private static bool IsContainsAnimationClip(this Animation animation, AnimationClip clip)
|
||||
{
|
||||
foreach (PPtr<AnimationClip> ptr in animation.m_Animations)
|
||||
{
|
||||
if (ptr.TryGet(out var animationClip) && animationClip.Equals(clip))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Dictionary<uint, string> BuildTOS(this Animator animator)
|
||||
{
|
||||
if (animator.version[0] > 4 || (animator.version[0] == 4 && animator.version[1] >= 3))
|
||||
{
|
||||
if (animator.m_HasTransformHierarchy)
|
||||
{
|
||||
if (animator.m_GameObject.TryGet(out var go))
|
||||
{
|
||||
return go.BuildTOS();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Dictionary<uint, string>() { { 0, string.Empty } };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (animator.m_GameObject.TryGet(out var go))
|
||||
{
|
||||
return go.BuildTOS();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static Dictionary<uint, string> BuildTOS(this GameObject gameObject)
|
||||
{
|
||||
Dictionary<uint, string> tos = new Dictionary<uint, string>() { { 0, string.Empty } };
|
||||
gameObject.BuildTOS(string.Empty, tos);
|
||||
return tos;
|
||||
}
|
||||
private static void BuildTOS(this GameObject parent, string parentPath, Dictionary<uint, string> tos)
|
||||
{
|
||||
Transform transform = parent.m_Transform;
|
||||
foreach (PPtr<Transform> childPtr in transform.m_Children)
|
||||
{
|
||||
if (childPtr.TryGet(out var childTransform))
|
||||
{
|
||||
if (childTransform.m_GameObject.TryGet(out var child))
|
||||
{
|
||||
string path = parentPath != string.Empty ? parentPath + '/' + child.m_Name : child.m_Name;
|
||||
var pathHash = CRC.CalculateDigestUTF8(path);
|
||||
tos[pathHash] = path;
|
||||
BuildTOS(child, path, tos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static bool IsContainsAnimationClip(this RuntimeAnimatorController runtimeAnimatorController, AnimationClip clip)
|
||||
{
|
||||
if (runtimeAnimatorController is AnimatorController animatorController)
|
||||
{
|
||||
foreach (PPtr<AnimationClip> ptr in animatorController.m_AnimationClips)
|
||||
{
|
||||
if (ptr.TryGet(out var animationClip) && animationClip.Equals(clip))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static int GetDimension(this GenericBinding binding)
|
||||
{
|
||||
return binding.attribute == 2 ? 4 : 3;
|
||||
}
|
||||
|
||||
public static HumanoidMuscleType GetHumanoidMuscle(this GenericBinding binding)
|
||||
{
|
||||
return ((HumanoidMuscleType)binding.attribute).Update(binding.version);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum BindingCustomType : byte
|
||||
{
|
||||
None = 0,
|
||||
Transform = 4,
|
||||
AnimatorMuscle = 8,
|
||||
|
||||
BlendShape = 20,
|
||||
Renderer = 21,
|
||||
RendererMaterial = 22,
|
||||
SpriteRenderer = 23,
|
||||
MonoBehaviour = 24,
|
||||
Light = 25,
|
||||
RendererShadows = 26,
|
||||
ParticleSystem = 27,
|
||||
RectTransform = 28,
|
||||
LineRenderer = 29,
|
||||
TrailRenderer = 30,
|
||||
PositionConstraint = 31,
|
||||
RotationConstraint = 32,
|
||||
ScaleConstraint = 33,
|
||||
AimConstraint = 34,
|
||||
ParentConstraint = 35,
|
||||
LookAtConstraint = 36,
|
||||
Camera = 37,
|
||||
}
|
||||
}
|
||||
672
AssetStudioUtility/YAML/CustomCurveResolver.cs
Normal file
672
AssetStudioUtility/YAML/CustomCurveResolver.cs
Normal file
@@ -0,0 +1,672 @@
|
||||
using System;
|
||||
using SevenZip;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class CustomCurveResolver
|
||||
{
|
||||
public CustomCurveResolver(AnimationClip clip)
|
||||
{
|
||||
if (clip == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(clip));
|
||||
}
|
||||
m_clip = clip;
|
||||
}
|
||||
|
||||
public string ToAttributeName(BindingCustomType type, uint attribute, string path)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BindingCustomType.BlendShape:
|
||||
{
|
||||
const string Prefix = "blendShape.";
|
||||
if (AnimationClipConverter.UnknownPathRegex.IsMatch(path))
|
||||
{
|
||||
return Prefix + attribute;
|
||||
}
|
||||
|
||||
foreach (GameObject root in Roots)
|
||||
{
|
||||
var rootTransform = root.m_Transform;
|
||||
var child = rootTransform.FindChild(path);
|
||||
if (child == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
SkinnedMeshRenderer skin = null;
|
||||
if (child.m_GameObject.TryGet(out var go))
|
||||
{
|
||||
skin = go.m_SkinnedMeshRenderer;
|
||||
}
|
||||
if (skin == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!skin.m_Mesh.TryGet(out var mesh))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string shapeName = mesh.FindBlendShapeNameByCRC(attribute);
|
||||
if (shapeName == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return Prefix + shapeName;
|
||||
}
|
||||
return Prefix + attribute;
|
||||
}
|
||||
|
||||
case BindingCustomType.Renderer:
|
||||
return "m_Materials." + CommonString.StringBuffer[0x31] + "." + CommonString.StringBuffer[0x6A] + $"[{attribute}]";
|
||||
|
||||
case BindingCustomType.RendererMaterial:
|
||||
{
|
||||
const string Prefix = "material.";
|
||||
if (AnimationClipConverter.UnknownPathRegex.IsMatch(path))
|
||||
{
|
||||
return Prefix + attribute;
|
||||
}
|
||||
|
||||
foreach (GameObject root in Roots)
|
||||
{
|
||||
Transform rootTransform = root.m_Transform;
|
||||
Transform child = rootTransform.FindChild(path);
|
||||
if (child == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint crc28 = attribute & 0xFFFFFFF;
|
||||
Renderer renderer = null;
|
||||
if (child.m_GameObject.TryGet(out var go))
|
||||
{
|
||||
renderer = (Renderer)go.m_SkinnedMeshRenderer ?? go.m_MeshRenderer;
|
||||
}
|
||||
if (renderer == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string property = renderer.FindMaterialPropertyNameByCRC28(crc28);
|
||||
if (property == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((attribute & 0x80000000) != 0)
|
||||
{
|
||||
return Prefix + property;
|
||||
}
|
||||
char subProperty;
|
||||
uint subPropIndex = attribute >> 28 & 3;
|
||||
bool isRgba = (attribute & 0x40000000) != 0;
|
||||
switch (subPropIndex)
|
||||
{
|
||||
case 0:
|
||||
subProperty = isRgba ? 'r' : 'x';
|
||||
break;
|
||||
case 1:
|
||||
subProperty = isRgba ? 'g' : 'y';
|
||||
break;
|
||||
case 2:
|
||||
subProperty = isRgba ? 'b' : 'z';
|
||||
break;
|
||||
|
||||
default:
|
||||
subProperty = isRgba ? 'a' : 'w';
|
||||
break;
|
||||
}
|
||||
return Prefix + property + "." + subProperty;
|
||||
}
|
||||
return Prefix + attribute;
|
||||
}
|
||||
|
||||
case BindingCustomType.SpriteRenderer:
|
||||
{
|
||||
if (attribute == 0)
|
||||
{
|
||||
return "m_Sprite";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
case BindingCustomType.MonoBehaviour:
|
||||
{
|
||||
if (attribute == CRC.CalculateDigestAscii("m_Enabled"))
|
||||
{
|
||||
return "m_Enabled";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
case BindingCustomType.Light:
|
||||
{
|
||||
string ColorR = "m_Color.r";
|
||||
if (attribute == CRC.CalculateDigestAscii(ColorR))
|
||||
{
|
||||
return ColorR;
|
||||
}
|
||||
string ColorG = "m_Color.g";
|
||||
if (attribute == CRC.CalculateDigestAscii(ColorG))
|
||||
{
|
||||
return ColorG;
|
||||
}
|
||||
string ColorB = "m_Color.b";
|
||||
if (attribute == CRC.CalculateDigestAscii(ColorB))
|
||||
{
|
||||
return ColorB;
|
||||
}
|
||||
string ColorA = "m_Color.a";
|
||||
if (attribute == CRC.CalculateDigestAscii(ColorA))
|
||||
{
|
||||
return ColorA;
|
||||
}
|
||||
if (attribute == CRC.CalculateDigestAscii("m_CookieSize"))
|
||||
{
|
||||
return "m_CookieSize";
|
||||
}
|
||||
if (attribute == CRC.CalculateDigestAscii("m_DrawHalo"))
|
||||
{
|
||||
return "m_DrawHalo";
|
||||
}
|
||||
if (attribute == CRC.CalculateDigestAscii("m_Intensity"))
|
||||
{
|
||||
return "m_Intensity";
|
||||
}
|
||||
if (attribute == CRC.CalculateDigestAscii("m_Range"))
|
||||
{
|
||||
return "m_Range";
|
||||
}
|
||||
const string ShadowsStrength = "m_Shadows.m_Strength";
|
||||
if (attribute == CRC.CalculateDigestAscii(ShadowsStrength))
|
||||
{
|
||||
return ShadowsStrength;
|
||||
}
|
||||
const string ShadowsBias = "m_Shadows.m_Bias";
|
||||
if (attribute == CRC.CalculateDigestAscii(ShadowsBias))
|
||||
{
|
||||
return ShadowsBias;
|
||||
}
|
||||
const string ShadowsNormalBias = "m_Shadows.m_NormalBias";
|
||||
if (attribute == CRC.CalculateDigestAscii(ShadowsNormalBias))
|
||||
{
|
||||
return ShadowsNormalBias;
|
||||
}
|
||||
const string ShadowsNearPlane = "m_Shadows.m_NearPlane";
|
||||
if (attribute == CRC.CalculateDigestAscii(ShadowsNearPlane))
|
||||
{
|
||||
return ShadowsNearPlane;
|
||||
}
|
||||
if (attribute == CRC.CalculateDigestAscii("m_SpotAngle"))
|
||||
{
|
||||
return "m_SpotAngle";
|
||||
}
|
||||
if (attribute == CRC.CalculateDigestAscii("m_ColorTemperature"))
|
||||
{
|
||||
return "m_ColorTemperature";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
case BindingCustomType.RendererShadows:
|
||||
{
|
||||
if (attribute == CRC.CalculateDigestAscii("m_ReceiveShadows"))
|
||||
{
|
||||
return "m_ReceiveShadows";
|
||||
}
|
||||
if (attribute == CRC.CalculateDigestAscii("m_SortingOrder"))
|
||||
{
|
||||
return "m_SortingOrder";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
#warning TODO:
|
||||
case BindingCustomType.ParticleSystem:
|
||||
return "ParticleSystem_" + attribute;
|
||||
/*{
|
||||
// TODO: ordinal propertyName
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {_this}");*/
|
||||
|
||||
case BindingCustomType.RectTransform:
|
||||
{
|
||||
string LocalPositionZ = "m_LocalPosition.z";
|
||||
if (attribute == CRC.CalculateDigestAscii(LocalPositionZ))
|
||||
{
|
||||
return LocalPositionZ;
|
||||
}
|
||||
string AnchoredPositionX = "m_AnchoredPosition.x";
|
||||
if (attribute == CRC.CalculateDigestAscii(AnchoredPositionX))
|
||||
{
|
||||
return AnchoredPositionX;
|
||||
}
|
||||
string AnchoredPositionY = "m_AnchoredPosition.y";
|
||||
if (attribute == CRC.CalculateDigestAscii(AnchoredPositionY))
|
||||
{
|
||||
return AnchoredPositionY;
|
||||
}
|
||||
string AnchorMinX = "m_AnchorMin.x";
|
||||
if (attribute == CRC.CalculateDigestAscii(AnchorMinX))
|
||||
{
|
||||
return AnchorMinX;
|
||||
}
|
||||
string AnchorMinY = "m_AnchorMin.y";
|
||||
if (attribute == CRC.CalculateDigestAscii(AnchorMinY))
|
||||
{
|
||||
return AnchorMinY;
|
||||
}
|
||||
string AnchorMaxX = "m_AnchorMax.x";
|
||||
if (attribute == CRC.CalculateDigestAscii(AnchorMaxX))
|
||||
{
|
||||
return AnchorMaxX;
|
||||
}
|
||||
string AnchorMaxY = "m_AnchorMax.y";
|
||||
if (attribute == CRC.CalculateDigestAscii(AnchorMaxY))
|
||||
{
|
||||
return AnchorMaxY;
|
||||
}
|
||||
string SizeDeltaX = "m_SizeDelta.x";
|
||||
if (attribute == CRC.CalculateDigestAscii(SizeDeltaX))
|
||||
{
|
||||
return SizeDeltaX;
|
||||
}
|
||||
string SizeDeltaY = "m_SizeDelta.y";
|
||||
if (attribute == CRC.CalculateDigestAscii(SizeDeltaY))
|
||||
{
|
||||
return SizeDeltaY;
|
||||
}
|
||||
string PivotX = "m_Pivot.x";
|
||||
if (attribute == CRC.CalculateDigestAscii(PivotX))
|
||||
{
|
||||
return PivotX;
|
||||
}
|
||||
string PivotY = "m_Pivot.y";
|
||||
if (attribute == CRC.CalculateDigestAscii(PivotY))
|
||||
{
|
||||
return PivotY;
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
#warning TODO:
|
||||
case BindingCustomType.LineRenderer:
|
||||
{
|
||||
const string ParametersWidthMultiplier = "m_Parameters" + "." + "widthMultiplier";
|
||||
if (attribute == CRC.CalculateDigestAscii(ParametersWidthMultiplier))
|
||||
{
|
||||
return ParametersWidthMultiplier;
|
||||
}
|
||||
}
|
||||
// TODO: old versions animate all properties as custom curves
|
||||
return "LineRenderer_" + attribute;
|
||||
|
||||
#warning TODO:
|
||||
case BindingCustomType.TrailRenderer:
|
||||
{
|
||||
const string ParametersWidthMultiplier = "m_Parameters" + "." + "widthMultiplier";
|
||||
if (attribute == CRC.CalculateDigestAscii(ParametersWidthMultiplier))
|
||||
{
|
||||
return ParametersWidthMultiplier;
|
||||
}
|
||||
}
|
||||
// TODO: old versions animate all properties as custom curves
|
||||
return "TrailRenderer_" + attribute;
|
||||
|
||||
#warning TODO:
|
||||
case BindingCustomType.PositionConstraint:
|
||||
{
|
||||
uint property = attribute & 0xF;
|
||||
switch (property)
|
||||
{
|
||||
case 0:
|
||||
return "m_RestTranslation.x";
|
||||
case 1:
|
||||
return "m_RestTranslation.y";
|
||||
case 2:
|
||||
return "m_RestTranslation.z";
|
||||
case 3:
|
||||
return "m_Weight";
|
||||
case 4:
|
||||
return "m_TranslationOffset.x";
|
||||
case 5:
|
||||
return "m_TranslationOffset.y";
|
||||
case 6:
|
||||
return "m_TranslationOffset.z";
|
||||
case 7:
|
||||
return "m_AffectTranslationX";
|
||||
case 8:
|
||||
return "m_AffectTranslationY";
|
||||
case 9:
|
||||
return "m_AffectTranslationZ";
|
||||
case 10:
|
||||
return "m_Active";
|
||||
case 11:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||
case 12:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
#warning TODO:
|
||||
case BindingCustomType.RotationConstraint:
|
||||
{
|
||||
uint property = attribute & 0xF;
|
||||
switch (property)
|
||||
{
|
||||
case 0:
|
||||
return "m_RestRotation.x";
|
||||
case 1:
|
||||
return "m_RestRotation.y";
|
||||
case 2:
|
||||
return "m_RestRotation.z";
|
||||
case 3:
|
||||
return "m_Weight";
|
||||
case 4:
|
||||
return "m_RotationOffset.x";
|
||||
case 5:
|
||||
return "m_RotationOffset.y";
|
||||
case 6:
|
||||
return "m_RotationOffset.z";
|
||||
case 7:
|
||||
return "m_AffectRotationX";
|
||||
case 8:
|
||||
return "m_AffectRotationY";
|
||||
case 9:
|
||||
return "m_AffectRotationZ";
|
||||
case 10:
|
||||
return "m_Active";
|
||||
case 11:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||
case 12:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
#warning TODO:
|
||||
case BindingCustomType.ScaleConstraint:
|
||||
{
|
||||
uint property = attribute & 0xF;
|
||||
switch (property)
|
||||
{
|
||||
case 0:
|
||||
return "m_ScaleAtRest.x";
|
||||
case 1:
|
||||
return "m_ScaleAtRest.y";
|
||||
case 2:
|
||||
return "m_ScaleAtRest.z";
|
||||
case 3:
|
||||
return "m_Weight";
|
||||
case 4:
|
||||
return "m_ScalingOffset.x";
|
||||
case 5:
|
||||
return "m_ScalingOffset.y";
|
||||
case 6:
|
||||
return "m_ScalingOffset.z";
|
||||
case 7:
|
||||
return "m_AffectScalingX";
|
||||
case 8:
|
||||
return "m_AffectScalingY";
|
||||
case 9:
|
||||
return "m_AffectScalingZ";
|
||||
case 10:
|
||||
return "m_Active";
|
||||
case 11:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||
case 12:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
#warning TODO:
|
||||
case BindingCustomType.AimConstraint:
|
||||
{
|
||||
uint property = attribute & 0xF;
|
||||
switch (property)
|
||||
{
|
||||
case 0:
|
||||
return "m_Weight";
|
||||
case 1:
|
||||
return "m_AffectRotationX";
|
||||
case 2:
|
||||
return "m_AffectRotationY";
|
||||
case 3:
|
||||
return "m_AffectRotationZ";
|
||||
case 4:
|
||||
return "m_Active";
|
||||
case 5:
|
||||
return "m_WorldUpObject";
|
||||
case 6:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||
case 7:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
#warning TODO:
|
||||
case BindingCustomType.ParentConstraint:
|
||||
{
|
||||
uint property = attribute & 0xF;
|
||||
switch (property)
|
||||
{
|
||||
case 0:
|
||||
return "m_Weight";
|
||||
case 1:
|
||||
return "m_AffectTranslationX";
|
||||
case 2:
|
||||
return "m_AffectTranslationY";
|
||||
case 3:
|
||||
return "m_AffectTranslationZ";
|
||||
case 4:
|
||||
return "m_AffectRotationX";
|
||||
case 5:
|
||||
return "m_AffectRotationY";
|
||||
case 6:
|
||||
return "m_AffectRotationZ";
|
||||
case 7:
|
||||
return "m_Active";
|
||||
case 8:
|
||||
return $"m_TranslationOffsets.Array.data[{attribute >> 8}].x";
|
||||
case 9:
|
||||
return $"m_TranslationOffsets.Array.data[{attribute >> 8}].y";
|
||||
case 10:
|
||||
return $"m_TranslationOffsets.Array.data[{attribute >> 8}].z";
|
||||
case 11:
|
||||
return $"m_RotationOffsets.Array.data[{attribute >> 8}].x";
|
||||
case 12:
|
||||
return $"m_RotationOffsets.Array.data[{attribute >> 8}].y";
|
||||
case 13:
|
||||
return $"m_RotationOffsets.Array.data[{attribute >> 8}].z";
|
||||
case 14:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||
case 15:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
#warning TODO:
|
||||
case BindingCustomType.LookAtConstraint:
|
||||
{
|
||||
uint property = attribute & 0xF;
|
||||
switch (property)
|
||||
{
|
||||
case 0:
|
||||
return "m_Weight";
|
||||
case 1:
|
||||
return "m_Active";
|
||||
case 2:
|
||||
return "m_WorldUpObject";
|
||||
case 3:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].sourceTransform";
|
||||
case 4:
|
||||
return $"m_Sources.Array.data[{attribute >> 8}].weight";
|
||||
case 5:
|
||||
return "m_Roll";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
case BindingCustomType.Camera:
|
||||
{
|
||||
if (attribute == CRC.CalculateDigestAscii("field of view"))
|
||||
{
|
||||
return "field of view";
|
||||
}
|
||||
if (attribute == CRC.CalculateDigestAscii("m_FocalLength"))
|
||||
{
|
||||
return "m_FocalLength";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Unknown attribute {attribute} for {type}");
|
||||
|
||||
default:
|
||||
throw new ArgumentException(type.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private GameObject[] Roots
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!m_rootInited)
|
||||
{
|
||||
m_roots = m_clip.FindRoots().ToArray();
|
||||
m_rootInited = true;
|
||||
}
|
||||
return m_roots;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly AnimationClip m_clip = null;
|
||||
|
||||
private GameObject[] m_roots = null;
|
||||
private bool m_rootInited = false;
|
||||
}
|
||||
|
||||
public static class CustomCurveResolverExtensions
|
||||
{
|
||||
public static Transform FindChild(this Transform transform, string path)
|
||||
{
|
||||
if (path.Length == 0)
|
||||
{
|
||||
return transform;
|
||||
}
|
||||
return transform.FindChild(path, 0);
|
||||
}
|
||||
|
||||
private static Transform FindChild(this Transform transform, string path, int startIndex)
|
||||
{
|
||||
int separatorIndex = path.IndexOf('/', startIndex);
|
||||
string childName = separatorIndex == -1 ?
|
||||
path.Substring(startIndex, path.Length - startIndex) :
|
||||
path.Substring(startIndex, separatorIndex - startIndex);
|
||||
|
||||
foreach (PPtr<Transform> childPtr in transform.m_Children)
|
||||
{
|
||||
if (childPtr.TryGet(out var child))
|
||||
{
|
||||
if (child.m_GameObject.TryGet(out var childGO) && childGO.m_Name == childName)
|
||||
{
|
||||
return separatorIndex == -1 ? child : child.FindChild(path, separatorIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string FindBlendShapeNameByCRC(this Mesh mesh, uint crc)
|
||||
{
|
||||
if (mesh.version[0] > 4 || (mesh.version[0] == 4 && mesh.version[1] >= 3))
|
||||
{
|
||||
return mesh.m_Shapes.FindShapeNameByCRC(crc);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var blendShape in mesh.m_Shapes.shapes)
|
||||
{
|
||||
if (CRC.VerifyDigestUTF8(blendShape.name, crc))
|
||||
{
|
||||
return blendShape.name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static string FindShapeNameByCRC(this BlendShapeData blendShapeData, uint crc)
|
||||
{
|
||||
foreach (var blendChannel in blendShapeData.channels)
|
||||
{
|
||||
if (blendChannel.nameHash == crc)
|
||||
{
|
||||
return blendChannel.name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string FindMaterialPropertyNameByCRC28(this Renderer renderer, uint crc)
|
||||
{
|
||||
foreach (PPtr<Material> materialPtr in renderer.m_Materials)
|
||||
{
|
||||
if (!materialPtr.TryGet(out var material))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string property = material.FindPropertyNameByCRC28(crc);
|
||||
if (property == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string FindPropertyNameByCRC28(this Material material, uint crc)
|
||||
{
|
||||
foreach (var property in material.m_SavedProperties.m_TexEnvs.Keys)
|
||||
{
|
||||
string hdrName = $"{property}_HDR";
|
||||
if (CRC.Verify28DigestUTF8(hdrName, crc))
|
||||
{
|
||||
return hdrName;
|
||||
}
|
||||
string stName = $"{property}_ST";
|
||||
if (CRC.Verify28DigestUTF8(stName, crc))
|
||||
{
|
||||
return stName;
|
||||
}
|
||||
string texelName = $"{property}_TexelSize";
|
||||
if (CRC.Verify28DigestUTF8(texelName, crc))
|
||||
{
|
||||
return texelName;
|
||||
}
|
||||
}
|
||||
foreach (var property in material.m_SavedProperties.m_Floats.Keys)
|
||||
{
|
||||
if (CRC.Verify28DigestUTF8(property, crc))
|
||||
{
|
||||
return property;
|
||||
}
|
||||
}
|
||||
foreach (var property in material.m_SavedProperties.m_Colors.Keys)
|
||||
{
|
||||
if (CRC.Verify28DigestUTF8(property, crc))
|
||||
{
|
||||
return property;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
648
AssetStudioUtility/YAML/MuscleHelper.cs
Normal file
648
AssetStudioUtility/YAML/MuscleHelper.cs
Normal file
@@ -0,0 +1,648 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum HumanoidMuscleType
|
||||
{
|
||||
Motion = 0,
|
||||
Root = Motion + 7,
|
||||
Limbs = Root + 7,
|
||||
Muscles = Limbs + LimbType.Last * 7,
|
||||
Fingers = Muscles + MuscleType.Last,
|
||||
TDoFBones = Fingers + ArmType.Last * FingerType.Last * FingerDoFType.Last,
|
||||
|
||||
Last = TDoFBones + TDoFBoneType.Last * 3,
|
||||
}
|
||||
|
||||
public static class AnimationMuscleTypeExtensions
|
||||
{
|
||||
public static HumanoidMuscleType Update(this HumanoidMuscleType _this, int[] version)
|
||||
{
|
||||
if (_this < HumanoidMuscleType.Muscles)
|
||||
{
|
||||
return _this;
|
||||
}
|
||||
|
||||
MuscleType muscle = (MuscleType)(_this - HumanoidMuscleType.Muscles);
|
||||
MuscleType fixedMuscle = muscle.Update(version);
|
||||
_this = HumanoidMuscleType.Muscles + (int)fixedMuscle;
|
||||
if (_this < HumanoidMuscleType.TDoFBones)
|
||||
{
|
||||
return _this;
|
||||
}
|
||||
|
||||
TDoFBoneType tdof = (TDoFBoneType)(_this - HumanoidMuscleType.TDoFBones);
|
||||
TDoFBoneType fixedTdof = tdof.Update(version);
|
||||
_this = HumanoidMuscleType.TDoFBones + (int)fixedTdof;
|
||||
return _this;
|
||||
}
|
||||
|
||||
public static string ToAttributeString(this HumanoidMuscleType _this)
|
||||
{
|
||||
if (_this < HumanoidMuscleType.Root)
|
||||
{
|
||||
int delta = _this - HumanoidMuscleType.Motion;
|
||||
return nameof(HumanoidMuscleType.Motion) + GetTransformPostfix(delta % 7);
|
||||
}
|
||||
if (_this < HumanoidMuscleType.Limbs)
|
||||
{
|
||||
int delta = _this - HumanoidMuscleType.Root;
|
||||
return nameof(HumanoidMuscleType.Root) + GetTransformPostfix(delta % 7);
|
||||
}
|
||||
if (_this < HumanoidMuscleType.Muscles)
|
||||
{
|
||||
int delta = _this - HumanoidMuscleType.Limbs;
|
||||
LimbType limb = (LimbType)(delta / 7);
|
||||
return limb.ToBoneType().ToAttributeString() + GetTransformPostfix(delta % 7);
|
||||
}
|
||||
if (_this < HumanoidMuscleType.Fingers)
|
||||
{
|
||||
int delta = _this - HumanoidMuscleType.Muscles;
|
||||
MuscleType muscle = (MuscleType)delta;
|
||||
return muscle.ToAttributeString();
|
||||
}
|
||||
if (_this < HumanoidMuscleType.TDoFBones)
|
||||
{
|
||||
const int armSize = (int)FingerType.Last * (int)FingerDoFType.Last;
|
||||
const int dofSize = (int)FingerDoFType.Last;
|
||||
int delta = _this - HumanoidMuscleType.Fingers;
|
||||
ArmType arm = (ArmType)(delta / armSize);
|
||||
delta = delta % armSize;
|
||||
FingerType finger = (FingerType)(delta / dofSize);
|
||||
delta = delta % dofSize;
|
||||
FingerDoFType dof = (FingerDoFType)delta;
|
||||
return $"{arm.ToBoneType().ToAttributeString()}.{finger.ToAttributeString()}.{dof.ToAttributeString()}";
|
||||
}
|
||||
if (_this < HumanoidMuscleType.Last)
|
||||
{
|
||||
int delta = _this - HumanoidMuscleType.TDoFBones;
|
||||
TDoFBoneType tdof = (TDoFBoneType)(delta / 3);
|
||||
return $"{tdof.ToBoneType().ToAttributeString()}{GetTDoFTransformPostfix(delta % 3)}";
|
||||
}
|
||||
throw new ArgumentException(_this.ToString());
|
||||
}
|
||||
|
||||
private static string GetTransformPostfix(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return "T.x";
|
||||
case 1:
|
||||
return "T.y";
|
||||
case 2:
|
||||
return "T.z";
|
||||
|
||||
case 3:
|
||||
return "Q.x";
|
||||
case 4:
|
||||
return "Q.y";
|
||||
case 5:
|
||||
return "Q.z";
|
||||
case 6:
|
||||
return "Q.w";
|
||||
|
||||
default:
|
||||
throw new ArgumentException(index.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetTDoFTransformPostfix(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return "TDOF.x";
|
||||
case 1:
|
||||
return "TDOF.y";
|
||||
case 2:
|
||||
return "TDOF.z";
|
||||
|
||||
default:
|
||||
throw new ArgumentException(index.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum LimbType
|
||||
{
|
||||
LeftFoot = 0,
|
||||
RightFoot = 1,
|
||||
LeftHand = 2,
|
||||
RightHand = 3,
|
||||
|
||||
Last,
|
||||
}
|
||||
|
||||
public static class LimbTypeExtensions
|
||||
{
|
||||
public static BoneType ToBoneType(this LimbType _this)
|
||||
{
|
||||
switch (_this)
|
||||
{
|
||||
case LimbType.LeftFoot:
|
||||
return BoneType.LeftFoot;
|
||||
case LimbType.RightFoot:
|
||||
return BoneType.RightFoot;
|
||||
case LimbType.LeftHand:
|
||||
return BoneType.LeftHand;
|
||||
case LimbType.RightHand:
|
||||
return BoneType.RightHand;
|
||||
|
||||
default:
|
||||
throw new ArgumentException(_this.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum MuscleType
|
||||
{
|
||||
SpineFrontBack = 0,
|
||||
SpineLeftRight = 1,
|
||||
SpineTwistLeftRight = 2,
|
||||
ChestFrontBack = 3,
|
||||
ChestLeftRight = 4,
|
||||
ChestTwistLeftRight = 5,
|
||||
UpperchestFrontBack = 6,
|
||||
UpperchestLeftRight = 7,
|
||||
UpperchestTwisLeftRight = 8,
|
||||
NeckNodDownUp = 9,
|
||||
NeckTiltLeftRight = 10,
|
||||
NeckTurnLeftRight = 11,
|
||||
HeadNodDownUp = 12,
|
||||
HeadTiltLeftRight = 13,
|
||||
HeadTurnLeftRight = 14,
|
||||
LeftEyeDownUp = 15,
|
||||
LeftEyeInOut = 16,
|
||||
RightEyeDownUp = 17,
|
||||
RightEyeInOut = 18,
|
||||
JawClose = 19,
|
||||
JawLeftRight = 20,
|
||||
LeftUpperLegFrontBack = 21,
|
||||
LeftUpperLegInOut = 22,
|
||||
LeftUpperLegTwistInOut = 23,
|
||||
LeftLowerLegStretch = 24,
|
||||
LeftLowerLegTwistInOut = 25,
|
||||
LeftFootUpDown = 26,
|
||||
LeftFootTwistInOut = 27,
|
||||
LeftToesUpDown = 28,
|
||||
RightUpperLegFrontBack = 29,
|
||||
RightUpperLegInOut = 30,
|
||||
RightUpperLegTwistInOut = 31,
|
||||
RightLowerLegStretch = 32,
|
||||
RightLowerLegTwistInOut = 33,
|
||||
RightFootUpDown = 34,
|
||||
RightFootTwistInOut = 35,
|
||||
RightToesUpDown = 36,
|
||||
LeftShoulderDownUp = 37,
|
||||
LeftShoulderFrontBack = 38,
|
||||
LeftArmDownUp = 39,
|
||||
LeftArmFrontBack = 40,
|
||||
LeftArmTwistInOut = 41,
|
||||
LeftForearmStretch = 42,
|
||||
LeftForearmTwistInOut = 43,
|
||||
LeftHandDownUp = 44,
|
||||
LeftHandInOut = 45,
|
||||
RightShoulderDownUp = 46,
|
||||
RightShoulderFrontBack = 47,
|
||||
RightArmDownUp = 48,
|
||||
RightArmFrontBack = 49,
|
||||
RightArmTwistInOut = 50,
|
||||
RightForearmStretch = 51,
|
||||
RightForearmTwistInOut = 52,
|
||||
RightHandDownUp = 53,
|
||||
RightHandInOut = 54,
|
||||
|
||||
Last,
|
||||
}
|
||||
|
||||
public static class MuscleTypeExtensions
|
||||
{
|
||||
public static MuscleType Update(this MuscleType _this, int[] version)
|
||||
{
|
||||
if (!(version[0] > 5 || (version[0] == 5 && version[1] >= 6)))
|
||||
{
|
||||
if (_this >= MuscleType.UpperchestFrontBack)
|
||||
{
|
||||
_this += 3;
|
||||
}
|
||||
}
|
||||
return _this;
|
||||
}
|
||||
|
||||
public static string ToAttributeString(this MuscleType _this)
|
||||
{
|
||||
switch (_this)
|
||||
{
|
||||
case MuscleType.SpineFrontBack:
|
||||
return "Spine Front-Back";
|
||||
case MuscleType.SpineLeftRight:
|
||||
return "Spine Left-Right";
|
||||
case MuscleType.SpineTwistLeftRight:
|
||||
return "Spine Twist Left-Right";
|
||||
case MuscleType.ChestFrontBack:
|
||||
return "Chest Front-Back";
|
||||
case MuscleType.ChestLeftRight:
|
||||
return "Chest Left-Right";
|
||||
case MuscleType.ChestTwistLeftRight:
|
||||
return "Chest Twist Left-Right";
|
||||
case MuscleType.UpperchestFrontBack:
|
||||
return "UpperChest Front-Back";
|
||||
case MuscleType.UpperchestLeftRight:
|
||||
return "UpperChest Left-Right";
|
||||
case MuscleType.UpperchestTwisLeftRight:
|
||||
return "UpperChest Twist Left-Right";
|
||||
case MuscleType.NeckNodDownUp:
|
||||
return "Neck Nod Down-Up";
|
||||
case MuscleType.NeckTiltLeftRight:
|
||||
return "Neck Tilt Left-Right";
|
||||
case MuscleType.NeckTurnLeftRight:
|
||||
return "Neck Turn Left-Right";
|
||||
case MuscleType.HeadNodDownUp:
|
||||
return "Head Nod Down-Up";
|
||||
case MuscleType.HeadTiltLeftRight:
|
||||
return "Head Tilt Left-Right";
|
||||
case MuscleType.HeadTurnLeftRight:
|
||||
return "Head Turn Left-Right";
|
||||
case MuscleType.LeftEyeDownUp:
|
||||
return "Left Eye Down-Up";
|
||||
case MuscleType.LeftEyeInOut:
|
||||
return "Left Eye In-Out";
|
||||
case MuscleType.RightEyeDownUp:
|
||||
return "Right Eye Down-Up";
|
||||
case MuscleType.RightEyeInOut:
|
||||
return "Right Eye In-Out";
|
||||
case MuscleType.JawClose:
|
||||
return "Jaw Close";
|
||||
case MuscleType.JawLeftRight:
|
||||
return "Jaw Left-Right";
|
||||
case MuscleType.LeftUpperLegFrontBack:
|
||||
return "Left Upper Leg Front-Back";
|
||||
case MuscleType.LeftUpperLegInOut:
|
||||
return "Left Upper Leg In-Out";
|
||||
case MuscleType.LeftUpperLegTwistInOut:
|
||||
return "Left Upper Leg Twist In-Out";
|
||||
case MuscleType.LeftLowerLegStretch:
|
||||
return "Left Lower Leg Stretch";
|
||||
case MuscleType.LeftLowerLegTwistInOut:
|
||||
return "Left Lower Leg Twist In-Out";
|
||||
case MuscleType.LeftFootUpDown:
|
||||
return "Left Foot Up-Down";
|
||||
case MuscleType.LeftFootTwistInOut:
|
||||
return "Left Foot Twist In-Out";
|
||||
case MuscleType.LeftToesUpDown:
|
||||
return "Left Toes Up-Down";
|
||||
case MuscleType.RightUpperLegFrontBack:
|
||||
return "Right Upper Leg Front-Back";
|
||||
case MuscleType.RightUpperLegInOut:
|
||||
return "Right Upper Leg In-Out";
|
||||
case MuscleType.RightUpperLegTwistInOut:
|
||||
return "Right Upper Leg Twist In-Out";
|
||||
case MuscleType.RightLowerLegStretch:
|
||||
return "Right Lower Leg Stretch";
|
||||
case MuscleType.RightLowerLegTwistInOut:
|
||||
return "Right Lower Leg Twist In-Out";
|
||||
case MuscleType.RightFootUpDown:
|
||||
return "Right Foot Up-Down";
|
||||
case MuscleType.RightFootTwistInOut:
|
||||
return "Right Foot Twist In-Out";
|
||||
case MuscleType.RightToesUpDown:
|
||||
return "Right Toes Up-Down";
|
||||
case MuscleType.LeftShoulderDownUp:
|
||||
return "Left Shoulder Down-Up";
|
||||
case MuscleType.LeftShoulderFrontBack:
|
||||
return "Left Shoulder Front-Back";
|
||||
case MuscleType.LeftArmDownUp:
|
||||
return "Left Arm Down-Up";
|
||||
case MuscleType.LeftArmFrontBack:
|
||||
return "Left Arm Front-Back";
|
||||
case MuscleType.LeftArmTwistInOut:
|
||||
return "Left Arm Twist In-Out";
|
||||
case MuscleType.LeftForearmStretch:
|
||||
return "Left Forearm Stretch";
|
||||
case MuscleType.LeftForearmTwistInOut:
|
||||
return "Left Forearm Twist In-Out";
|
||||
case MuscleType.LeftHandDownUp:
|
||||
return "Left Hand Down-Up";
|
||||
case MuscleType.LeftHandInOut:
|
||||
return "Left Hand In-Out";
|
||||
case MuscleType.RightShoulderDownUp:
|
||||
return "Right Shoulder Down-Up";
|
||||
case MuscleType.RightShoulderFrontBack:
|
||||
return "Right Shoulder Front-Back";
|
||||
case MuscleType.RightArmDownUp:
|
||||
return "Right Arm Down-Up";
|
||||
case MuscleType.RightArmFrontBack:
|
||||
return "Right Arm Front-Back";
|
||||
case MuscleType.RightArmTwistInOut:
|
||||
return "Right Arm Twist In-Out";
|
||||
case MuscleType.RightForearmStretch:
|
||||
return "Right Forearm Stretch";
|
||||
case MuscleType.RightForearmTwistInOut:
|
||||
return "Right Forearm Twist In-Out";
|
||||
case MuscleType.RightHandDownUp:
|
||||
return "Right Hand Down-Up";
|
||||
case MuscleType.RightHandInOut:
|
||||
return "Right Hand In-Out";
|
||||
|
||||
default:
|
||||
throw new ArgumentException(_this.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum BoneType
|
||||
{
|
||||
Hips = 0,
|
||||
LeftUpperLeg = 1,
|
||||
RightUpperLeg = 2,
|
||||
LeftLowerLeg = 3,
|
||||
RightLowerLeg = 4,
|
||||
LeftFoot = 5,
|
||||
RightFoot = 6,
|
||||
Spine = 7,
|
||||
Chest = 8,
|
||||
UpperChest = 9,
|
||||
Neck = 10,
|
||||
Head = 11,
|
||||
LeftShoulder = 12,
|
||||
RightShoulder = 13,
|
||||
LeftUpperArm = 14,
|
||||
RightUpperArm = 15,
|
||||
LeftLowerArm = 16,
|
||||
RightLowerArm = 17,
|
||||
LeftHand = 18,
|
||||
RightHand = 19,
|
||||
LeftToes = 20,
|
||||
RightToes = 21,
|
||||
LeftEye = 22,
|
||||
RightEye = 23,
|
||||
Jaw = 24,
|
||||
|
||||
Last,
|
||||
}
|
||||
|
||||
public static class BoneTypeExtensions
|
||||
{
|
||||
public static BoneType Update(this BoneType _this, int[] version)
|
||||
{
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6))
|
||||
{
|
||||
if (_this >= BoneType.UpperChest)
|
||||
{
|
||||
_this++;
|
||||
}
|
||||
}
|
||||
return _this;
|
||||
}
|
||||
|
||||
public static string ToAttributeString(this BoneType _this)
|
||||
{
|
||||
if (_this < BoneType.Last)
|
||||
{
|
||||
return _this.ToString();
|
||||
}
|
||||
throw new ArgumentException(_this.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public enum TransformType
|
||||
{
|
||||
Translation = 1,
|
||||
Rotation = 2,
|
||||
Scaling = 3,
|
||||
EulerRotation = 4,
|
||||
}
|
||||
|
||||
public static class BindingTypeExtensions
|
||||
{
|
||||
public static bool IsValid(this TransformType _this)
|
||||
{
|
||||
return _this >= TransformType.Translation && _this <= TransformType.EulerRotation;
|
||||
}
|
||||
|
||||
public static int GetDimension(this TransformType _this)
|
||||
{
|
||||
switch (_this)
|
||||
{
|
||||
case TransformType.Translation:
|
||||
case TransformType.Scaling:
|
||||
case TransformType.EulerRotation:
|
||||
return 3;
|
||||
|
||||
case TransformType.Rotation:
|
||||
return 4;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"Binding type {_this} is not implemented");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ArmType
|
||||
{
|
||||
LeftHand = 0,
|
||||
RightHand = 1,
|
||||
|
||||
Last,
|
||||
}
|
||||
|
||||
public static class ArmTypeExtensions
|
||||
{
|
||||
public static BoneType ToBoneType(this ArmType _this)
|
||||
{
|
||||
switch (_this)
|
||||
{
|
||||
case ArmType.LeftHand:
|
||||
return BoneType.LeftHand;
|
||||
case ArmType.RightHand:
|
||||
return BoneType.RightHand;
|
||||
|
||||
default:
|
||||
throw new ArgumentException(_this.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum FingerType
|
||||
{
|
||||
Thumb = 0,
|
||||
Index = 1,
|
||||
Middle = 2,
|
||||
Ring = 3,
|
||||
Little = 4,
|
||||
|
||||
Last,
|
||||
}
|
||||
|
||||
public static class FingerTypeExtensions
|
||||
{
|
||||
public static string ToAttributeString(this FingerType _this)
|
||||
{
|
||||
if (_this < FingerType.Last)
|
||||
{
|
||||
return _this.ToString();
|
||||
}
|
||||
throw new ArgumentException(_this.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public enum FingerDoFType
|
||||
{
|
||||
_1Stretched = 0,
|
||||
Spread = 1,
|
||||
_2Stretched = 2,
|
||||
_3Stretched = 3,
|
||||
|
||||
Last,
|
||||
}
|
||||
|
||||
public static class FingerDoFTypeExtensions
|
||||
{
|
||||
public static string ToAttributeString(this FingerDoFType _this)
|
||||
{
|
||||
switch (_this)
|
||||
{
|
||||
case FingerDoFType._1Stretched:
|
||||
return "1 Stretched";
|
||||
case FingerDoFType.Spread:
|
||||
return "Spread";
|
||||
case FingerDoFType._2Stretched:
|
||||
return "2 Stretched";
|
||||
case FingerDoFType._3Stretched:
|
||||
return "3 Stretched";
|
||||
|
||||
default:
|
||||
throw new ArgumentException(_this.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum TDoFBoneType
|
||||
{
|
||||
Spine = 0,
|
||||
Chest = 1,
|
||||
UpperChest = 2,
|
||||
Neck = 3,
|
||||
Head = 4,
|
||||
LeftUpperLeg = 5,
|
||||
LeftLowerLeg = 6,
|
||||
LeftFoot = 7,
|
||||
LeftToes = 8,
|
||||
RightUpperLeg = 9,
|
||||
RightLowerLeg = 10,
|
||||
RightFoot = 11,
|
||||
RightToes = 12,
|
||||
LeftShoulder = 13,
|
||||
LeftUpperArm = 14,
|
||||
LeftLowerArm = 15,
|
||||
LeftHand = 16,
|
||||
RightShoulder = 17,
|
||||
RightUpperArm = 18,
|
||||
RightLowerArm = 19,
|
||||
RightHand = 20,
|
||||
|
||||
Last,
|
||||
}
|
||||
|
||||
public static class TDoFBoneTypeExtensions
|
||||
{
|
||||
public static TDoFBoneType Update(this TDoFBoneType _this, int[] version)
|
||||
{
|
||||
if (!(version[0] > 5 || (version[0] == 5 && version[1] >= 6)))
|
||||
{
|
||||
if (_this >= TDoFBoneType.UpperChest)
|
||||
{
|
||||
_this++;
|
||||
}
|
||||
}
|
||||
if (!(version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)))
|
||||
{
|
||||
if (_this >= TDoFBoneType.Head)
|
||||
{
|
||||
_this++;
|
||||
}
|
||||
}
|
||||
if (!(version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)))
|
||||
{
|
||||
if (_this >= TDoFBoneType.LeftLowerLeg)
|
||||
{
|
||||
_this += 3;
|
||||
}
|
||||
}
|
||||
if (!(version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)))
|
||||
{
|
||||
if (_this >= TDoFBoneType.RightLowerLeg)
|
||||
{
|
||||
_this += 3;
|
||||
}
|
||||
}
|
||||
if (!(version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)))
|
||||
{
|
||||
if (_this >= TDoFBoneType.LeftUpperArm)
|
||||
{
|
||||
_this += 3;
|
||||
}
|
||||
}
|
||||
if (!(version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)))
|
||||
{
|
||||
if (_this >= TDoFBoneType.RightUpperArm)
|
||||
{
|
||||
_this += 3;
|
||||
}
|
||||
}
|
||||
return _this;
|
||||
}
|
||||
|
||||
public static BoneType ToBoneType(this TDoFBoneType _this)
|
||||
{
|
||||
switch (_this)
|
||||
{
|
||||
case TDoFBoneType.Spine:
|
||||
return BoneType.Spine;
|
||||
case TDoFBoneType.Chest:
|
||||
return BoneType.Chest;
|
||||
case TDoFBoneType.UpperChest:
|
||||
return BoneType.UpperChest;
|
||||
case TDoFBoneType.Neck:
|
||||
return BoneType.Neck;
|
||||
case TDoFBoneType.Head:
|
||||
return BoneType.Head;
|
||||
case TDoFBoneType.LeftUpperLeg:
|
||||
return BoneType.LeftUpperLeg;
|
||||
case TDoFBoneType.LeftLowerLeg:
|
||||
return BoneType.LeftLowerLeg;
|
||||
case TDoFBoneType.LeftFoot:
|
||||
return BoneType.LeftFoot;
|
||||
case TDoFBoneType.LeftToes:
|
||||
return BoneType.LeftToes;
|
||||
case TDoFBoneType.RightUpperLeg:
|
||||
return BoneType.RightUpperLeg;
|
||||
case TDoFBoneType.RightLowerLeg:
|
||||
return BoneType.RightLowerLeg;
|
||||
case TDoFBoneType.RightFoot:
|
||||
return BoneType.RightFoot;
|
||||
case TDoFBoneType.RightToes:
|
||||
return BoneType.RightToes;
|
||||
case TDoFBoneType.LeftShoulder:
|
||||
return BoneType.LeftShoulder;
|
||||
case TDoFBoneType.LeftUpperArm:
|
||||
return BoneType.LeftUpperArm;
|
||||
case TDoFBoneType.LeftLowerArm:
|
||||
return BoneType.LeftLowerArm;
|
||||
case TDoFBoneType.LeftHand:
|
||||
return BoneType.LeftHand;
|
||||
case TDoFBoneType.RightShoulder:
|
||||
return BoneType.RightShoulder;
|
||||
case TDoFBoneType.RightUpperArm:
|
||||
return BoneType.RightUpperArm;
|
||||
case TDoFBoneType.RightLowerArm:
|
||||
return BoneType.RightLowerArm;
|
||||
case TDoFBoneType.RightHand:
|
||||
return BoneType.RightHand;
|
||||
|
||||
default:
|
||||
throw new ArgumentException(_this.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user