/// <summary>
            /// Exports all animation
            /// </summary>
            private void ExportAnimationClip(AnimationClip unityAnimClip, GameObject unityRoot, FbxScene fbxScene)
            {
                if (unityAnimClip == null)
                {
                    return;
                }

                // 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));

                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;
                    }

                    ExportAnimCurve(unityObj, unityAnimCurve, unityCurveBinding.propertyName, fbxAnimLayer);
                }
            }
        protected FbxAnimStack CreateAnimStack(FbxScene scene)
        {
            FbxAnimStack fbxAnimStack = FbxAnimStack.Create(scene, "animClip");

            fbxAnimStack.Description.Set("Animation Take");

            FbxTime.EMode timeMode = FbxTime.EMode.eFrames30;
            scene.GetGlobalSettings().SetTimeMode(timeMode);

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

            fbxAnimStack.SetLocalTimeSpan(new FbxTimeSpan(fbxStartTime, fbxStopTime));
            return(fbxAnimStack);
        }
            /// <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);
                }
            }
Exemple #4
0
    void ExportAnimSequenceToFbx(AnimSequence AnimSeq,
                                 ref List <FbxNode> BoneNodes,
                                 FbxAnimLayer InAnimLayer,
                                 float AnimStartOffset,
                                 float AnimEndOffset,
                                 float AnimPlayRate,
                                 float StartTime)
    {
        if (AnimSeq.SequenceLength == 0)
        {
            return;
        }

        FbxTime ExportedStartTime = new FbxTime();
        FbxTime ExportedStopTime  = new FbxTime();

        if (IsNearlyEqual(AnimSeq.FrameRate, DEFAULT_SAMPLERATE, 1.0f))
        {
            FbxTime.SetGlobalTimeMode(FbxTime.EMode.eFrames30);
            //FbxTime.SetGlobalTimeMode(FbxTime.EMode.eFrames30);
        }
        else
        {
            FbxTime.SetGlobalTimeMode(FbxTime.EMode.eCustom, AnimSeq.FrameRate);
            //ExportedStopTime.SetGlobalTimeMode(FbxTime::eCustom, FrameRate);
        }

        ExportedStartTime.SetSecondDouble(0.0f);
        ExportedStopTime.SetSecondDouble(AnimSeq.SequenceLength);
        FbxTimeSpan ExportedTimeSpan = new FbxTimeSpan();

        ExportedTimeSpan.Set(ExportedStartTime, ExportedStopTime);
        AnimStack.SetLocalTimeSpan(ExportedTimeSpan);


        // Add the animation data to the bone nodes
        for (int BoneIndex = 0; BoneIndex < BoneNodes.Count; ++BoneIndex)
        {
            FbxNode CurrentBoneNode = BoneNodes[BoneIndex];
            // Create the AnimCurves
            int            NumberOfCurves = 9;
            FbxAnimCurve[] Curves         = new FbxAnimCurve[NumberOfCurves];

            Curves[0] = CurrentBoneNode.LclTranslation.GetCurve(InAnimLayer, "X", true);
            Curves[1] = CurrentBoneNode.LclTranslation.GetCurve(InAnimLayer, "Y", true);
            Curves[2] = CurrentBoneNode.LclTranslation.GetCurve(InAnimLayer, "Z", true);

            Curves[3] = CurrentBoneNode.LclRotation.GetCurve(InAnimLayer, "X", true);
            Curves[4] = CurrentBoneNode.LclRotation.GetCurve(InAnimLayer, "Y", true);
            Curves[5] = CurrentBoneNode.LclRotation.GetCurve(InAnimLayer, "Z", true);

            Curves[6] = CurrentBoneNode.LclScaling.GetCurve(InAnimLayer, "X", true);
            Curves[7] = CurrentBoneNode.LclScaling.GetCurve(InAnimLayer, "Y", true);
            Curves[8] = CurrentBoneNode.LclScaling.GetCurve(InAnimLayer, "Z", true);

            float AnimTime    = AnimStartOffset;
            float AnimEndTime = (AnimSeq.SequenceLength - AnimEndOffset);
            // Subtracts 1 because NumFrames includes an initial pose for 0.0 second
            float   TimePerKey        = AnimSeq.StepFrame;
            float   AnimTimeIncrement = TimePerKey * AnimPlayRate;
            FbxTime ExportTime        = new FbxTime();
            ExportTime.SetSecondDouble(StartTime);

            FbxTime ExportTimeIncrement = new FbxTime();
            ExportTimeIncrement.SetSecondDouble(TimePerKey);


            //int BoneTreeIndex = Skeleton.GetSkeletonBoneIndexFromMeshBoneIndex(SkelMesh, BoneIndex);
            //int BoneTrackIndex = Skeleton.GetAnimationTrackIndex(BoneTreeIndex, AnimSeq, true);
            //if (BoneTrackIndex == INDEX_NONE)
            //{
            //    // If this sequence does not have a track for the current bone, then skip it
            //    continue;
            //}

            foreach (FbxAnimCurve Curve in Curves)
            {
                Curve.KeyModifyBegin();
            }

            bool bLastKey   = false;
            int  FrameIndex = 0;
            foreach (var v in AnimSeq.animationFames)
            {
                int lKeyIndex;
                FrameIndex++;
                if (FrameIndex == AnimSeq.animationFames.Count)
                {
                    bLastKey = true;
                }

                BoneTransformInfo BoneAtom = v[BoneIndex].BoneTransform;

                FbxDouble3    Translation = FbxDataConverter.ConvertToFbxPos(BoneAtom.position);
                FbxDouble3    Rotation    = FbxDataConverter.ConvertToFbxRot(BoneAtom.rotation);
                FbxDouble3    Scale       = FbxDataConverter.ConvertToFbxScale(BoneAtom.scale);
                FbxDouble3 [] Vectors     = new FbxDouble3[3] {
                    Translation, Rotation, Scale
                };

                // Loop over each curve and channel to set correct values
                for (int CurveIndex = 0; CurveIndex < 3; ++CurveIndex)
                {
                    for (int ChannelIndex = 0; ChannelIndex < 3; ++ChannelIndex)
                    {
                        int OffsetCurveIndex = (CurveIndex * 3) + ChannelIndex;

                        lKeyIndex = Curves[OffsetCurveIndex].KeyAdd(ExportTime);

                        Curves[OffsetCurveIndex].KeySetValue(lKeyIndex, (float)Vectors[CurveIndex].getDataValue(ChannelIndex));
                        Curves[OffsetCurveIndex].KeySetInterpolation(lKeyIndex, bLastKey ? FbxAnimCurveDef.EInterpolationType.eInterpolationConstant : FbxAnimCurveDef.EInterpolationType.eInterpolationCubic);

                        if (bLastKey)
                        {
                            Curves[OffsetCurveIndex].KeySetConstantMode(lKeyIndex, FbxAnimCurveDef.EConstantMode.eConstantStandard);
                        }
                    }
                }

                ExportTime = ExportTime.add(ExportTimeIncrement);
            }


            while (!bLastKey)
            {
                //FTransform BoneAtom;
                //AnimSeq.GetBoneTransform(BoneAtom, BoneTrackIndex, AnimTime, true);

                //FbxVector4 Translation = Converter.ConvertToFbxPos(BoneAtom.GetTranslation());
                //FbxVector4 Rotation = Converter.ConvertToFbxRot(BoneAtom.GetRotation().Euler());
                //FbxVector4 Scale = Converter.ConvertToFbxScale(BoneAtom.GetScale3D());
                //FbxVector4 Vectors[3] = { Translation, Rotation, Scale };

                //int lKeyIndex;

                //bLastKey = AnimTime >= AnimEndTime;

                //// Loop over each curve and channel to set correct values
                //for (uint CurveIndex = 0; CurveIndex < 3; ++CurveIndex)
                //{
                //    for (uint ChannelIndex = 0; ChannelIndex < 3; ++ChannelIndex)
                //    {
                //        uint OffsetCurveIndex = (CurveIndex * 3) + ChannelIndex;

                //        lKeyIndex = Curves[OffsetCurveIndex].KeyAdd(ExportTime);
                //        Curves[OffsetCurveIndex].KeySetValue(lKeyIndex, Vectors[CurveIndex][ChannelIndex]);
                //        Curves[OffsetCurveIndex].KeySetInterpolation(lKeyIndex, bLastKey ? FbxAnimCurveDef::eInterpolationConstant : FbxAnimCurveDef::eInterpolationCubic);

                //        if (bLastKey)
                //        {
                //            Curves[OffsetCurveIndex].KeySetConstantMode(lKeyIndex, FbxAnimCurveDef::eConstantStandard);
                //        }
                //    }
                //}

                //ExportTime += ExportTimeIncrement;
                //AnimTime += AnimTimeIncrement;
            }

            foreach (FbxAnimCurve Curve in Curves)
            {
                Curve.KeyModifyEnd();
            }
        }
    }