public void TestBasics()
        {
            // Test get euler index
            var eulerCurve = new EulerCurve();

            Assert.That(EulerCurve.GetEulerIndex("localEulerAnglesRaw.y"), Is.EqualTo(1));
            Assert.That(EulerCurve.GetEulerIndex("localEulerAnglesRaw."), Is.EqualTo(-1));
            Assert.That(EulerCurve.GetEulerIndex("m_LocalRotation.x"), Is.EqualTo(-1));

            // Test get quaternion index
            var quaternionCurve = new QuaternionCurve();

            Assert.That(QuaternionCurve.GetQuaternionIndex("m_LocalRotation.w"), Is.EqualTo(3));
            Assert.That(QuaternionCurve.GetQuaternionIndex("m_LocalRotation"), Is.EqualTo(-1));
            Assert.That(QuaternionCurve.GetQuaternionIndex("localEulerAnglesRaw.y"), Is.EqualTo(-1));

            // Test SetCurve
            var animCurve = new AnimationCurve();

            eulerCurve.SetCurve(2, animCurve);
            Assert.That(eulerCurve.GetCurves()[2], Is.EqualTo(animCurve));

            Assert.That(() => eulerCurve.SetCurve(-1, animCurve), Throws.Exception.TypeOf <System.IndexOutOfRangeException>());
            Assert.That(() => eulerCurve.SetCurve(3, animCurve), Throws.Exception.TypeOf <System.IndexOutOfRangeException>());

            quaternionCurve.SetCurve(3, animCurve);
            Assert.That(quaternionCurve.GetCurves()[3], Is.EqualTo(animCurve));

            Assert.That(() => quaternionCurve.SetCurve(-5, animCurve), Throws.Exception.TypeOf <System.IndexOutOfRangeException>());
            Assert.That(() => quaternionCurve.SetCurve(4, animCurve), Throws.Exception.TypeOf <System.IndexOutOfRangeException>());
        }
示例#2
0
        public void ExportGenericData(IExportContainer container, YAMLMappingNode node, IReadOnlyDictionary <uint, string> tos)
        {
            StreamedClip streamedClip = MuscleClip.Clip.StreamedClip;
            DenseClip    denseClip    = MuscleClip.Clip.DenseClip;
            ConstantClip constantClip = MuscleClip.Clip.ConstantClip;

            IReadOnlyList <StreamedFrame>      streamedFrames = streamedClip.GenerateFrames(container);
            Dictionary <uint, Vector3Curve>    translations   = new Dictionary <uint, Vector3Curve>();
            Dictionary <uint, QuaternionCurve> rotations      = new Dictionary <uint, QuaternionCurve>();
            Dictionary <uint, Vector3Curve>    scales         = new Dictionary <uint, Vector3Curve>();
            Dictionary <uint, Vector3Curve>    eulers         = new Dictionary <uint, Vector3Curve>();
            Dictionary <uint, FloatCurve>      floats         = new Dictionary <uint, FloatCurve>();

            int frameCount = Math.Max(denseClip.FrameCount - 1, streamedFrames.Count - 2);

            float[] frameCurvesValue = new float[streamedClip.CurveCount];
            for (int frame = 0, streamFrame = 1; frame < frameCount; frame++, streamFrame++)
            {
                bool          isAdd = true;
                float         time;
                StreamedFrame streamedFrame = new StreamedFrame();
                if (streamFrame < streamedFrames.Count)
                {
                    streamedFrame = streamedFrames[streamFrame];
                    time          = streamedFrame.Time;
                }
                else
                {
                    time = (float)frame / SampleRate;
                }

                bool isStreamFrame = streamFrame < (streamedFrames.Count - 1);
                bool isDenseFrame  = frame < (denseClip.FrameCount - 1);

                // number of stream curves which has key in current frame
                int streamFrameCurveCount = isStreamFrame ? streamedFrame.Curves.Count : 0;
                int denseFrameCurveCount  = (int)denseClip.CurveCount;
                // total amount of curves which has key in current frame
                int frameCurveCount = streamFrameCurveCount + denseFrameCurveCount + constantClip.Constants.Count;
                int streamOffset    = (int)streamedClip.CurveCount - streamFrameCurveCount;
                for (int curve = 0; curve < frameCurveCount;)
                {
                    int curveIndex;
                    IReadOnlyList <float> curvesValue;
                    int offset;

                    if (isStreamFrame && curve < streamedFrame.Curves.Count)
                    {
#warning TODO: read TCB and convert to in/out slope
                        for (int key = curve; key < Math.Min(curve + 5, streamedFrame.Curves.Count); key++)
                        {
                            frameCurvesValue[key] = streamedFrame.Curves[key].Value;
                        }
                        curveIndex  = streamedFrame.Curves[curve].Index;
                        curvesValue = frameCurvesValue;
                        offset      = 0;
                    }
                    else if (isDenseFrame && curve < streamFrameCurveCount + denseFrameCurveCount)
                    {
                        curveIndex  = curve + streamOffset;
                        curvesValue = denseClip.SampleArray;
                        offset      = streamFrameCurveCount - frame * denseFrameCurveCount;
                    }
                    else if (!isDenseFrame && curve < streamFrameCurveCount + denseFrameCurveCount)
                    {
                        curve += denseFrameCurveCount;

                        curveIndex  = curve + streamOffset;
                        curvesValue = constantClip.Constants;
                        offset      = streamFrameCurveCount + denseFrameCurveCount;
                        isAdd       = frame == 0 || frame == frameCount - 1;
                    }
                    else
                    {
                        curveIndex  = curve + streamOffset;
                        curvesValue = constantClip.Constants;
                        offset      = streamFrameCurveCount + denseFrameCurveCount;
                        isAdd       = frame == 0 || frame == frameCount - 1;
                    }

                    GenericBinding binding  = ClipBindingConstant.FindBinding(curveIndex);
                    uint           pathHash = binding.Path;

                    if (pathHash == 0)
                    {
                        curve++;
                        continue;
                    }
                    if (!tos.TryGetValue(pathHash, out string path))
                    {
                        path = "dummy" + pathHash;
                        //Logger.Log(LogType.Debug, LogCategory.Export, $"Can't find path '{binding.Path}' in TOS for {ToLogString()}");
                    }

                    switch (binding.BindingType)
                    {
                    case BindingType.Translation:
                        // HACK: TEMP:
                        if (curve + 3 > curvesValue.Count)
                        {
                            curve += 3;
                            break;
                        }

                        float x = curvesValue[curve++ - offset];
                        float y = curvesValue[curve++ - offset];
                        float z = curvesValue[curve++ - offset];
                        float w = 0;
                        if (isAdd)
                        {
                            Vector3f trans = new Vector3f(x, y, z);
                            if (!translations.TryGetValue(pathHash, out Vector3Curve transCurve))
                            {
                                transCurve             = new Vector3Curve(path);
                                translations[pathHash] = transCurve;
                            }

                            Vector3f defWeight = new Vector3f(1.0f / 3.0f);
                            KeyframeTpl <Vector3f> transKey = new KeyframeTpl <Vector3f>(time, trans, defWeight);
                            transCurve.Curve.Curve.Add(transKey);
                        }
                        break;

                    case BindingType.Rotation:
                        // HACK: TEMP:
                        if (curve + 4 > curvesValue.Count)
                        {
                            curve += 4;
                            break;
                        }

                        x = curvesValue[curve++ - offset];
                        y = curvesValue[curve++ - offset];
                        z = curvesValue[curve++ - offset];
                        w = curvesValue[curve++ - offset];
                        if (isAdd)
                        {
                            Quaternionf rot = new Quaternionf(x, y, z, w);
                            if (!rotations.TryGetValue(pathHash, out QuaternionCurve rotCurve))
                            {
                                rotCurve            = new QuaternionCurve(path);
                                rotations[pathHash] = rotCurve;
                            }

                            Quaternionf defWeight            = new Quaternionf(1.0f / 3.0f);
                            KeyframeTpl <Quaternionf> rotKey = new KeyframeTpl <Quaternionf>(time, rot, defWeight);
                            rotCurve.Curve.Curve.Add(rotKey);
                        }
                        break;

                    case BindingType.Scaling:
                        // HACK: TEMP:
                        if (curve + 3 > curvesValue.Count)
                        {
                            curve += 3;
                            break;
                        }

                        x = curvesValue[curve++ - offset];
                        y = curvesValue[curve++ - offset];
                        z = curvesValue[curve++ - offset];
                        if (isAdd)
                        {
                            Vector3f scale = new Vector3f(x, y, z);
                            if (!scales.TryGetValue(pathHash, out Vector3Curve scaleCurve))
                            {
                                scaleCurve       = new Vector3Curve(path);
                                scales[pathHash] = scaleCurve;
                            }

                            Vector3f defWeight = new Vector3f(1.0f / 3.0f);
                            KeyframeTpl <Vector3f> scaleKey = new KeyframeTpl <Vector3f>(time, scale, defWeight);
                            scaleCurve.Curve.Curve.Add(scaleKey);
                        }
                        break;

                    case BindingType.EulerRotation:
                        // HACK: TEMP:
                        if (curve + 3 > curvesValue.Count)
                        {
                            curve += 3;
                            break;
                        }

                        x = curvesValue[curve++ - offset];
                        y = curvesValue[curve++ - offset];
                        z = curvesValue[curve++ - offset];
                        if (isAdd)
                        {
                            Vector3f euler = new Vector3f(x, y, z);
                            if (!eulers.TryGetValue(pathHash, out Vector3Curve eulerCurve))
                            {
                                eulerCurve       = new Vector3Curve(path);
                                eulers[pathHash] = eulerCurve;
                            }

                            Vector3f defWeight = new Vector3f(1.0f / 3.0f);
                            KeyframeTpl <Vector3f> eulerKey = new KeyframeTpl <Vector3f>(time, euler, defWeight);
                            eulerCurve.Curve.Curve.Add(eulerKey);
                        }
                        break;

                    case BindingType.Floats:
                        float value = curvesValue[curve++ - offset];
                        if (isAdd)
                        {
                            Float @float = new Float(value);
                            if (!floats.TryGetValue(pathHash, out FloatCurve floatCurve))
                            {
                                floatCurve       = new FloatCurve(path);
                                floats[pathHash] = floatCurve;
                            }

                            Float defWeight = new Float(1.0f / 3.0f);
                            KeyframeTpl <Float> floatKey = new KeyframeTpl <Float>(time, @float, defWeight);
                            floatCurve.Curve.Curve.Add(floatKey);
                        }
                        break;

                    default:
#warning TODO: ???
                        curve++;
                        //throw new NotImplementedException(binding.BindingType.ToString());
                        break;
                    }
                }
            }

            node.Add("m_RotationCurves", rotations.Values.ExportYAML(container));
            node.Add("m_CompressedRotationCurves", YAMLSequenceNode.Empty);
            node.Add("m_EulerCurves", eulers.Values.ExportYAML(container));
            node.Add("m_PositionCurves", translations.Values.ExportYAML(container));
            node.Add("m_ScaleCurves", scales.Values.ExportYAML(container));
            node.Add("m_FloatCurves", floats.Values.ExportYAML(container));
        }
示例#3
0
 /// <summary>Constructs a new named animation curve.</summary>
 /// <param name="name">Name of the curve.</param>
 /// <param name="flags">Flags that describe the animation curve.</param>
 /// <param name="curve">Curve containing the animation data.</param>
 public NamedQuaternionCurve(string name, AnimationCurveFlags flags, QuaternionCurve curve)
 {
     this.name  = name;
     this.flags = (AnimationCurveFlags)0;
     this.curve = curve;
 }
示例#4
0
 private static extern Vector3Curve Internal_quaternionToEulerCurve(QuaternionCurve quatCurve);
示例#5
0
 /// <summary>Converts a curve in quaternions into a curve using euler angles (in degrees).</summary>
 public static Vector3Curve QuaternionToEulerCurve(QuaternionCurve quatCurve)
 {
     return(Internal_quaternionToEulerCurve(quatCurve));
 }
示例#6
0
            /// <summary>
            /// Export an AnimationClip as a single take
            /// </summary>
            protected void ExportAnimationClip(AnimationClip unityAnimClip, GameObject unityRoot, FbxScene fbxScene)
            {
                if (Verbose)
                {
                    Debug.Log(string.Format("exporting clip {1} for {0}", unityRoot.name, unityAnimClip.name));
                }

                // setup anim stack
                FbxAnimStack fbxAnimStack = FbxAnimStack.Create(fbxScene, unityAnimClip.name);

                fbxAnimStack.Description.Set("Animation Take: " + unityAnimClip.name);

                // add one mandatory animation layer
                FbxAnimLayer fbxAnimLayer = FbxAnimLayer.Create(fbxScene, "Animation Base Layer");

                fbxAnimStack.AddMember(fbxAnimLayer);

                // Set up the FPS so our frame-relative math later works out
                // Custom frame rate isn't really supported in FBX SDK (there's
                // a bug), so try hard to find the nearest time mode.
                FbxTime.EMode timeMode  = FbxTime.EMode.eCustom;
                double        precision = 1e-6;

                while (timeMode == FbxTime.EMode.eCustom && precision < 1000)
                {
                    timeMode   = FbxTime.ConvertFrameRateToTimeMode(unityAnimClip.frameRate, precision);
                    precision *= 10;
                }
                if (timeMode == FbxTime.EMode.eCustom)
                {
                    timeMode = FbxTime.EMode.eFrames30;
                }
                FbxTime.SetGlobalTimeMode(timeMode);

                // set time correctly
                var fbxStartTime = FbxTime.FromSecondDouble(0);
                var fbxStopTime  = FbxTime.FromSecondDouble(unityAnimClip.length);

                fbxAnimStack.SetLocalTimeSpan(new FbxTimeSpan(fbxStartTime, fbxStopTime));

                /* The major difficulty: Unity uses quaternions for rotation
                 * (which is how it should be) but FBX uses euler angles. So we
                 * need to gather up the list of transform curves per object. */
                var quaternions = new Dictionary <UnityEngine.GameObject, QuaternionCurve> ();

                foreach (EditorCurveBinding unityCurveBinding in AnimationUtility.GetCurveBindings(unityAnimClip))
                {
                    Object unityObj = AnimationUtility.GetAnimatedObject(unityRoot, unityCurveBinding);
                    if (!unityObj)
                    {
                        continue;
                    }

                    AnimationCurve unityAnimCurve = AnimationUtility.GetEditorCurve(unityAnimClip, unityCurveBinding);
                    if (unityAnimCurve == null)
                    {
                        continue;
                    }

                    int index = QuaternionCurve.GetQuaternionIndex(unityCurveBinding.propertyName);
                    if (index == -1)
                    {
                        if (Verbose)
                        {
                            Debug.Log(string.Format("export binding {1} for {0}", unityCurveBinding.propertyName, unityObj.ToString()));
                        }

                        /* Some normal property (e.g. translation), export right away */
                        ExportAnimCurve(unityObj, unityAnimCurve, unityCurveBinding.propertyName,
                                        fbxScene, fbxAnimLayer);
                    }
                    else
                    {
                        /* Rotation property; save it to convert quaternion -> euler later. */

                        var unityGo = GetGameObject(unityObj);
                        if (!unityGo)
                        {
                            continue;
                        }

                        QuaternionCurve quat;
                        if (!quaternions.TryGetValue(unityGo, out quat))
                        {
                            quat = new QuaternionCurve();
                            quaternions.Add(unityGo, quat);
                        }
                        quat.SetCurve(index, unityAnimCurve);
                    }
                }

                /* now export all the quaternion curves */
                foreach (var kvp in quaternions)
                {
                    var unityGo = kvp.Key;
                    var quat    = kvp.Value;

                    FbxNode fbxNode;
                    if (!MapUnityObjectToFbxNode.TryGetValue(unityGo, out fbxNode))
                    {
                        Debug.LogError(string.Format("no fbxnode found for '0'", unityGo.name));
                        continue;
                    }
                    quat.Animate(unityGo.transform, fbxNode, fbxAnimLayer, Verbose);
                }
            }
示例#7
0
        private void AddTransformCurve(float time, TransformType transType, IReadOnlyList <float> curveValues,
                                       IReadOnlyList <float> inSlopeValues, IReadOnlyList <float> outSlopeValues, int offset, string path)
        {
            switch (transType)
            {
            case TransformType.Translation:
            {
                Vector3Curve curve = new Vector3Curve(path);
                if (!m_translations.TryGetValue(curve, out List <KeyframeTpl <Vector3f> > transCurve))
                {
                    transCurve = new List <KeyframeTpl <Vector3f> >();
                    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];

                Vector3f value    = new Vector3f(x, y, z);
                Vector3f inSlope  = new Vector3f(inX, inY, inZ);
                Vector3f outSlope = new Vector3f(outX, outY, outZ);
                KeyframeTpl <Vector3f> transKey = new KeyframeTpl <Vector3f>(time, value, inSlope, outSlope, KeyframeTpl <Vector3f> .DefaultVector3Weight);
                transCurve.Add(transKey);
            }
            break;

            case TransformType.Rotation:
            {
                QuaternionCurve curve = new QuaternionCurve(path);
                if (!m_rotations.TryGetValue(curve, out List <KeyframeTpl <Quaternionf> > rotCurve))
                {
                    rotCurve = new List <KeyframeTpl <Quaternionf> >();
                    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];

                Quaternionf value                = new Quaternionf(x, y, z, w);
                Quaternionf inSlope              = new Quaternionf(inX, inY, inZ, inW);
                Quaternionf outSlope             = new Quaternionf(outX, outY, outZ, outW);
                KeyframeTpl <Quaternionf> rotKey = new KeyframeTpl <Quaternionf>(time, value, inSlope, outSlope, KeyframeTpl <Quaternionf> .DefaultQuaternionWeight);
                rotCurve.Add(rotKey);
            }
            break;

            case TransformType.Scaling:
            {
                Vector3Curve curve = new Vector3Curve(path);
                if (!m_scales.TryGetValue(curve, out List <KeyframeTpl <Vector3f> > scaleCurve))
                {
                    scaleCurve = new List <KeyframeTpl <Vector3f> >();
                    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];

                Vector3f value    = new Vector3f(x, y, z);
                Vector3f inSlope  = new Vector3f(inX, inY, inZ);
                Vector3f outSlope = new Vector3f(outX, outY, outZ);
                KeyframeTpl <Vector3f> scaleKey = new KeyframeTpl <Vector3f>(time, value, inSlope, outSlope, KeyframeTpl <Vector3f> .DefaultVector3Weight);
                scaleCurve.Add(scaleKey);
            }
            break;

            case TransformType.EulerRotation:
            {
                Vector3Curve curve = new Vector3Curve(path);
                if (!m_eulers.TryGetValue(curve, out List <KeyframeTpl <Vector3f> > eulerCurve))
                {
                    eulerCurve = new List <KeyframeTpl <Vector3f> >();
                    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];

                Vector3f value    = new Vector3f(x, y, z);
                Vector3f inSlope  = new Vector3f(inX, inY, inZ);
                Vector3f outSlope = new Vector3f(outX, outY, outZ);
                KeyframeTpl <Vector3f> eulerKey = new KeyframeTpl <Vector3f>(time, value, inSlope, outSlope, KeyframeTpl <Vector3f> .DefaultVector3Weight);
                eulerCurve.Add(eulerKey);
            }
            break;

            default:
                throw new NotImplementedException(transType.ToString());
            }
        }
示例#8
0
 private static extern void Internal_TAnimationCurve(QuaternionCurve managedInstance, KeyFrameQuat[] keyframes);
示例#9
0
 /// <summary>Registers a new curve used for animating rotation.</summary>
 /// <param name="name">
 /// Unique name of the curve. This name will be used mapping the curve to the relevant bone in a skeleton, if any.
 /// </param>
 /// <param name="curve">Curve to add to the clip.</param>
 public void AddRotationCurve(string name, QuaternionCurve curve)
 {
     Internal_addRotationCurve(mCachedPtr, name, curve);
 }
示例#10
0
 private static extern void Internal_addRotationCurve(IntPtr thisPtr, string name, QuaternionCurve curve);