Skip to content

Instantly share code, notes, and snippets.

@mafaca
Created March 23, 2018 11:26
Show Gist options
  • Save mafaca/ae05fb84ad851a61a6326aa7a46f5b24 to your computer and use it in GitHub Desktop.
Save mafaca/ae05fb84ad851a61a6326aa7a46f5b24 to your computer and use it in GitHub Desktop.
Animation export for US
public static void WriteFBX(string FBXfile, bool allNodes)
{
// original code
// original write & extract Textures
#region write Animation nodes and curves
if (exportAnimation)
{
for (int i = 0; i < Animations.Count; i++)
{
const ulong fbxTimeRate = 46186158000;
const string stackPrefix = "96239";
const string layerPrefix = "80190";
const string transPrefix = "19260";
const string rotPrefix = "19480";
const string scalePrefix = "19910";
AssetPreloadData animation = Animations.ElementAt(i);
AnimationClip animationClip = AnimationClips.ElementAt(i);
List<AnimationClip.Vector3Curve> rotations = new List<AnimationClip.Vector3Curve>(animationClip.RotationCurves.Count);
foreach (AnimationClip.QuaternionCurve curve in animationClip.RotationCurves)
{
rotations.Add(curve.ToFBXRotation());
}
List<AnimationClip.Vector3Curve> translations = new List<AnimationClip.Vector3Curve>(animationClip.PositionCurves.Count);
foreach (AnimationClip.Vector3Curve curve in animationClip.PositionCurves)
{
translations.Add(curve.ToFBXTranslation());
}
List<AnimationClip.Vector3Curve> scales = animationClip.ScaleCurves;
float rotDuration = rotations.Max(t => t.Curve.Curve.Max(j => j.Time));
//float rotDuration = 0.0f;
float transDuration = translations.Max(t => t.Curve.Curve.Max(j => j.Time));
float scaleDuration = scales.Max(t => t.Curve.Curve.Max(j => j.Time));
float duration = Math.Max(Math.Max(rotDuration, transDuration), scaleDuration);
long fbxDuration = (long)(fbxTimeRate * duration);
int stackIndex = i + 1;
ob.AppendFormat("\n\tAnimationStack: {0}{1}, \"AnimStack::Take {2:000}\", \"\" {{", stackPrefix, animation.uniqueID, stackIndex);
ob.Append("\n\t\tProperties70: {");
ob.AppendFormat("\n\t\t\tP: \"LocalStop\", \"KTime\", \"Time\", \"\",{0}", fbxDuration);
ob.AppendFormat("\n\t\t\tP: \"ReferenceStop\", \"KTime\", \"Time\", \"\",{0}", fbxDuration);
ob.Append("\n\t\t}");
ob.Append("\n\t}");
ob.AppendFormat("\n\tAnimationLayer: {0}{1}, \"AnimLayer::BaseLayer\", \"\" {{", layerPrefix, animation.uniqueID);
ob.Append("\n\t}");
cb.AppendFormat("\n\n\t;AnimLayer::BaseLayer, AnimStack::Take {0:000}", stackIndex);
cb.AppendFormat("\n\tC: \"OO\",{0}{1},{2}{1}", layerPrefix, animation.uniqueID, stackPrefix);
foreach (GameObject limbNode in LimbNodes)
{
string fullPath = limbNode.FullPath;
string rootName = selectedNode;
int index = fullPath.LastIndexOf(rootName, StringComparison.Ordinal);
if (index == -1)
{
continue;
}
index += rootName.Length + 1;
if (index >= fullPath.Length)
{
fullPath = string.Empty;
}
else
{
fullPath = fullPath.Substring(index);
fullPath = fullPath.Replace("\\", "/");
}
for (int j = 0; j < translations.Count; j++)
{
AnimationClip.Vector3Curve trans = translations[j];
if (trans.Path.String == fullPath)
{
FBXWriterHelper.WriteAnimCurveNode(ob, cb, transPrefix, j, layerPrefix, animation.uniqueID,
"T", "Lcl Translation",
limbNode.m_Name, limbNode.uniqueID, trans, null);
}
}
for (int j = 0; j < rotations.Count; j++)
{
AnimationClip.Vector3Curve rot = rotations[j];
if (rot.Path.String == fullPath)
{
FBXWriterHelper.WriteAnimCurveNode(ob, cb, rotPrefix, j, layerPrefix, animation.uniqueID,
"R", "Lcl Rotation",
limbNode.m_Name, limbNode.uniqueID, rot, animationClip.RotationCurves[j]);
}
}
for (int j = 0; j < scales.Count; j++)
{
AnimationClip.Vector3Curve scale = scales[j];
if (scale.Path.String == fullPath)
{
FBXWriterHelper.WriteAnimCurveNode(ob, cb, scalePrefix, j, layerPrefix, animation.uniqueID,
"S", "Lcl Scaling",
limbNode.m_Name, limbNode.uniqueID, scale, null);
}
}
}
}
}
#endregion
// original code
}
public static class FBXWriterHelper
{
public static void WriteAnimCurveNode(StringBuilder ob, StringBuilder cb, string prefix, int index, string layerPrefix, string uniqueID,
string subType, string fullSubType, string modelName, string modelId, AnimationClip.Vector3Curve curve, AnimationClip.QuaternionCurve orCurve)
{
ob.AppendFormat("\n\tAnimationCurveNode: {0}{1:000}{2}, \"AnimCurveNode::{3}\", \"\" {{", prefix, index, uniqueID, subType);
ob.Append("\n\t\tProperties70: {");
ob.AppendFormat("\n\t\t\tP: \"d|X\", \"Number\", \"\", \"A\",{0}", curve.Curve.Curve[0].Value.X);
ob.AppendFormat("\n\t\t\tP: \"d|Y\", \"Number\", \"\", \"A\",{0}", curve.Curve.Curve[0].Value.Y);
ob.AppendFormat("\n\t\t\tP: \"d|Z\", \"Number\", \"\", \"A\",{0}", curve.Curve.Curve[0].Value.Z);
ob.Append("\n\t\t}");
ob.Append("\n\t}");
cb.AppendFormat("\n\n\t;AnimCurveNode::{0}, AnimLayer::BaseLayer", subType);
cb.AppendFormat("\n\tC: \"OO\",{0}{1:000}{2},{3}{2}", prefix, index, uniqueID, layerPrefix);
cb.AppendFormat("\n\n\t;AnimCurveNode::{0}, Model::{1}", subType, modelName);
cb.AppendFormat("\n\tC: \"OP\",{0}{1:000}{2},1{3}, \"{4}\"", prefix, index, uniqueID, modelId, fullSubType);
const string curvePrefix = "20079";
int extra = 0;
if (subType == "R")
{
extra = 1;
}
else if (subType == "S")
{
extra = 2;
}
WriteAnimCurve(ob, cb, curvePrefix, index, index * 9 + extra * 3, uniqueID, curve, orCurve, 0, "d|X", subType, prefix);
WriteAnimCurve(ob, cb, curvePrefix, index, index * 9 + extra * 3 + 1, uniqueID, curve, orCurve, 1, "d|Y", subType, prefix);
WriteAnimCurve(ob, cb, curvePrefix, index, index * 9 + extra * 3 + 2, uniqueID, curve, orCurve, 2, "d|Z", subType, prefix);
}
public static void WriteAnimCurve(StringBuilder ob, StringBuilder cb, string prefix, int nodeIdex, int index, string uniqueID,
AnimationClip.Vector3Curve curve, AnimationClip.QuaternionCurve orCurve, int memIndex, string memName, string subType, string nodePrefix)
{
const ulong fbxTimeRate = 46186158000;
ob.AppendFormat("\n\tAnimationCurve: {0}{1:000}{2}, \"AnimCurve::\", \"\" {{", prefix, index, uniqueID);
ob.AppendFormat("\n\t\tDefault: {0}", curve.Curve.Curve[0].Value.GetMember(memIndex));
ob.Append("\n\t\tKeyVer: 4008");
ob.AppendFormat("\n\t\tKeyTime: *{0} {{", curve.Curve.Curve.Count);
ob.Append("\n\t\t\ta: ");
foreach (AnimationClip.KeyframeTpl<Vector3f> tpl in curve.Curve.Curve)
{
ob.AppendFormat("{0},", (long)(tpl.Time * fbxTimeRate));
}
ob.Length--;
ob.Append("\n\t\t}");
ob.AppendFormat("\n\t\tKeyValueFloat: *{0} {{", curve.Curve.Curve.Count);
if (orCurve != null)
{
ob.Append("\n\t\t\t;");
foreach (AnimationClip.KeyframeTpl<Quaternionf> tpl in orCurve.Curve.Curve)
{
ob.AppendFormat("{0},", UnityUtils.UnityRotationToFBX(tpl.Value).GetMember(memIndex));
}
ob.Length--;
}
ob.Append("\n\t\t\ta: ");
foreach (AnimationClip.KeyframeTpl<Vector3f> tpl in curve.Curve.Curve)
{
ob.AppendFormat("{0},", tpl.Value.GetMember(memIndex));
}
ob.Length--;
ob.Append("\n\t\t}");
ob.Append(@"
;KeyAttrFlags: Cubic|TangeantTCB
;KeyAttrFlags: *1 {
; a: 520
;}
;KeyAttrFlags: Cubic|TangeantAuto|GenericTimeIndependent|GenericClampProgressive
KeyAttrFlags: *1 {
a: 24840
}
;KeyAttrDataFloat: TCBTension:0, TCBContinuity:0, TCBBias:4.09995e-031
;KeyAttrDataFloat: *4 {
; a: 0,0,218434821,0
;}");
ob.AppendFormat("\n\t\tKeyAttrRefCount: *1 {{");
ob.AppendFormat("\n\t\t\ta: {0}", curve.Curve.Curve.Count);
ob.Append("\n\t\t}");
ob.Append("\n\t}");
cb.AppendFormat("\n\n\t;AnimCurve::, AnimCurveNode::{0}", subType);
cb.AppendFormat("\n\tC: \"OP\",{0}{1:000}{2},{3}{5:000}{2}, \"{4}\"", prefix, index, uniqueID, nodePrefix, memName, nodeIdex);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment