Exemple #1
0
        private BabylonAnimation GetAnimationsFrameByFrameMatrix(MFnTransform mFnTransform)
        {
            int start = GetMinTime()[0];
            int end   = GetMaxTime()[0];
            BabylonAnimation animation = null;

            // get keys
            List <BabylonAnimationKey> keys = new List <BabylonAnimationKey>();

            for (int currentFrame = start; currentFrame <= end; currentFrame++)
            {
                // Set the animation key
                BabylonAnimationKey key = new BabylonAnimationKey()
                {
                    frame  = currentFrame,
                    values = GetBabylonMatrix(mFnTransform, currentFrame).m.ToArray()
                };

                keys.Add(key);
            }

            // Optimization
            OptimizeAnimations(keys, false); // Do not remove linear animation keys for bones

            // Ensure animation has at least 2 frames
            if (keys.Count > 1)
            {
                var animationPresent = true;

                // Ensure animation has at least 2 non equal frames
                if (keys.Count == 2)
                {
                    if (keys[0].values.IsEqualTo(keys[1].values))
                    {
                        animationPresent = false;
                    }
                }

                if (animationPresent)
                {
                    // Create BabylonAnimation
                    // Animations
                    animation = new BabylonAnimation()
                    {
                        name           = mFnTransform.name + "Animation", // override default animation name
                        dataType       = (int)BabylonAnimation.DataType.Matrix,
                        loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                        framePerSecond = GetFPS(),
                        keys           = keys.ToArray(),
                        property       = "_matrix"
                    };
                }
            }

            return(animation);
        }
Exemple #2
0
        private static void ExportSkeletonAnimationClipData(Animator animator, bool autoPlay, BabylonSkeleton skeleton, Transform[] bones, BabylonMesh babylonMesh, AnimationClip clip)
        {
            var frameTime           = 1.0f / clip.frameRate;
            int animationFrameCount = (int)(clip.length * clip.frameRate);

            if (autoPlay)
            {
                babylonMesh.autoAnimate     = true;
                babylonMesh.autoAnimateFrom = 0;
                babylonMesh.autoAnimateTo   = animationFrameCount;
                babylonMesh.autoAnimateLoop = true;
            }

            foreach (var bone in skeleton.bones)
            {
                var keys      = new List <BabylonAnimationKey>();
                var transform = bones.Single(b => b.name == bone.name);

                AnimationMode.BeginSampling();
                for (var i = 0; i < animationFrameCount; i++)
                {
                    clip.SampleAnimation(animator.gameObject, i * frameTime);

                    var     local  = (transform.parent.localToWorldMatrix.inverse * transform.localToWorldMatrix);
                    float[] matrix = new[] {
                        local[0, 0], local[1, 0], local[2, 0], local[3, 0],
                        local[0, 1], local[1, 1], local[2, 1], local[3, 1],
                        local[0, 2], local[1, 2], local[2, 2], local[3, 2],
                        local[0, 3], local[1, 3], local[2, 3], local[3, 3]
                    };

                    var key = new BabylonAnimationKey
                    {
                        frame  = i,
                        values = matrix,
                    };
                    keys.Add(key);
                }
                AnimationMode.EndSampling();

                var babylonAnimation = new BabylonAnimation
                {
                    name           = bone.name + "Animation",
                    property       = "_matrix",
                    dataType       = (int)BabylonAnimation.DataType.Matrix,
                    loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                    framePerSecond = (int)clip.frameRate,
                    keys           = keys.ToArray()
                };

                bone.animation = babylonAnimation;
            }
        }
Exemple #3
0
        /// <summary>
        /// Export the morph target influence animation.
        /// </summary>
        /// <param name="blendShapeDeformerName"></param>
        /// <param name="weightIndex"></param>
        /// <returns>A list containing all animations</returns>
        private IList <BabylonAnimation> GetAnimationsInfluence(string blendShapeDeformerName, int weightIndex)
        {
            IList <BabylonAnimation> animations = new List <BabylonAnimation>();
            BabylonAnimation         animation  = null;

            IDictionary <double, IList <double> > morphWeights = GetMorphWeightsByFrame(blendShapeDeformerName);

            // get keys
            List <BabylonAnimationKey> keys = new List <BabylonAnimationKey>();

            for (int index = 0; index < morphWeights.Count; index++)
            {
                KeyValuePair <double, IList <double> > keyValue = morphWeights.ElementAt(index);
                // Set the animation key
                BabylonAnimationKey key = new BabylonAnimationKey()
                {
                    frame  = (int)keyValue.Key,
                    values = new float[] { (float)keyValue.Value[weightIndex] }
                };

                keys.Add(key);
            }

            List <BabylonAnimationKey> keysFull = new List <BabylonAnimationKey>(keys);

            // Optimization
            OptimizeAnimations(keys, false);

            // Ensure animation has at least 2 frames
            if (IsAnimationKeysRelevant(keys))
            {
                // Animations
                animation = new BabylonAnimation()
                {
                    name           = "influence animation", // override default animation name
                    dataType       = (int)BabylonAnimation.DataType.Float,
                    loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                    framePerSecond = Loader.GetFPS(),
                    keys           = keys.ToArray(),
                    keysFull       = keysFull,
                    property       = "influence"
                };

                animations.Add(animation);
            }

            return(animations);
        }
Exemple #4
0
        /// <summary>
        /// Using MEL commands, it return the babylon animation
        /// </summary>
        /// <param name="objectName">The name of the Maya object</param>
        /// <param name="mayaProperty">The attribut in Maya</param>
        /// <param name="babylonProperty">The attribut in Babylon</param>
        /// <returns>A Babylon animation that represents the Maya animation</returns>
        public BabylonAnimation GetAnimationFloat(string objectName, string mayaProperty, string babylonProperty)
        {
            // Get keyframes
            IList <double>   keyframes = GetKeyframes(objectName);
            BabylonAnimation animation = null;

            // set the key for each keyframe
            List <BabylonAnimationKey> keys = new List <BabylonAnimationKey>();

            for (int index = 0; index < keyframes.Count; index++)
            {
                double keyframe = keyframes[index];
                MGlobal.executeCommand($"getAttr -t {keyframe} {objectName}.{mayaProperty}", out double value);

                // Set the animation key
                BabylonAnimationKey key = new BabylonAnimationKey()
                {
                    frame  = (int)keyframe,
                    values = new float[] { (float)value }
                };

                keys.Add(key);
            }

            List <BabylonAnimationKey> keysFull = new List <BabylonAnimationKey>(keys);

            // Optimization
            OptimizeAnimations(keys, false);

            // Ensure animation has at least 2 frames
            if (IsAnimationKeysRelevant(keys))
            {
                // Animations
                animation = new BabylonAnimation()
                {
                    name           = $"{babylonProperty} animation", // override default animation name
                    dataType       = (int)BabylonAnimation.DataType.Float,
                    loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                    framePerSecond = Loader.GetFPS(),
                    keys           = keys.ToArray(),
                    keysFull       = keysFull,
                    property       = babylonProperty
                };
            }

            return(animation);
        }
Exemple #5
0
        private BabylonAnimation GetAnimationsFrameByFrameMatrix(MFnTransform mFnTransform)
        {
            int start = Loader.GetMinTime();
            int end   = Loader.GetMaxTime();
            BabylonAnimation animation = null;

            // get keys
            List <BabylonAnimationKey> keys = new List <BabylonAnimationKey>();

            for (int currentFrame = start; currentFrame <= end; currentFrame++)
            {
                // Set the animation key
                BabylonAnimationKey key = new BabylonAnimationKey()
                {
                    frame  = currentFrame,
                    values = GetBabylonMatrix(mFnTransform, currentFrame).m.ToArray()
                };

                keys.Add(key);
            }

            var keysFull = new List <BabylonAnimationKey>(keys);

            // Optimization
            OptimizeAnimations(keys, false); // Do not remove linear animation keys for bones

            // Ensure animation has at least 2 frames
            if (IsAnimationKeysRelevant(keys))
            {
                // Animations
                animation = new BabylonAnimation()
                {
                    name           = mFnTransform.name + "Animation", // override default animation name
                    dataType       = (int)BabylonAnimation.DataType.Matrix,
                    loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                    framePerSecond = Loader.GetFPS(),
                    keys           = keys.ToArray(),
                    keysFull       = keysFull,
                    property       = "_matrix"
                };
            }

            return(animation);
        }
        private List <BabylonAnimationKey> ExportBabylonKeysFromGameController(IIGameControl control, IGameControlType type, Func <IIGameKey, float[]> extractValueFunc)
        {
            if (control == null)
            {
                return(null);
            }

            ITab <IIGameKey> gameKeyTab = GlobalInterface.Instance.Tab.Create <IIGameKey>();

            control.GetQuickSampledKeys(gameKeyTab, type);

            if (gameKeyTab == null)
            {
                return(null);
            }

            var keys = new List <BabylonAnimationKey>();

            for (int indexKey = 0; indexKey < gameKeyTab.Count; indexKey++)
            {
#if MAX2017 || MAX2018
                var gameKey = gameKeyTab[indexKey];
#else
                var indexer = Marshal.AllocHGlobal(sizeof(int));
                Marshal.WriteInt32(indexer, indexKey);
                var gameKey = gameKeyTab[indexer];
                Marshal.FreeHGlobal(indexer);
#endif

                var key = new BabylonAnimationKey()
                {
                    frame  = gameKey.T / Ticks,
                    values = extractValueFunc(gameKey)
                };
                keys.Add(key);
            }

            return(keys);
        }
Exemple #7
0
        private BabylonAnimation GetDummyAnimation(GLTFNode gltfNode, int startFrame, int endFrame)
        {
            BabylonAnimation dummyAnimation = new BabylonAnimation();

            dummyAnimation.name           = "Dummy";
            dummyAnimation.property       = "scaling";
            dummyAnimation.framePerSecond = Loader.Global.FrameRate;
            dummyAnimation.dataType       = (int)BabylonAnimation.DataType.Vector3;

            BabylonAnimationKey startKey = new BabylonAnimationKey();

            startKey.frame  = startFrame;
            startKey.values = gltfNode.scale;

            BabylonAnimationKey endKey = new BabylonAnimationKey();

            endKey.frame  = endFrame;
            endKey.values = gltfNode.scale;

            dummyAnimation.keys = new BabylonAnimationKey[] { startKey, endKey };

            return(dummyAnimation);
        }
Exemple #8
0
        public BabylonAnimation GetDummyAnimation(GLTFNode gltfNode, int startFrame, int endFrame, BabylonScene babylonScene)
        {
            BabylonAnimation dummyAnimation = new BabylonAnimation();

            dummyAnimation.name           = "Dummy";
            dummyAnimation.property       = "scaling";
            dummyAnimation.framePerSecond = babylonScene.TimelineFramesPerSecond;
            dummyAnimation.dataType       = (int)BabylonAnimation.DataType.Vector3;

            BabylonAnimationKey startKey = new BabylonAnimationKey();

            startKey.frame  = startFrame;
            startKey.values = gltfNode.scale;

            BabylonAnimationKey endKey = new BabylonAnimationKey();

            endKey.frame  = endFrame;
            endKey.values = gltfNode.scale;

            dummyAnimation.keys = new BabylonAnimationKey[] { startKey, endKey };

            return(dummyAnimation);
        }
Exemple #9
0
        private List <BabylonAnimationKey> ExportBabylonKeysFromGameController(IIGameControl control, IGameControlType type, Func <IIGameKey, float[]> extractValueFunc)
        {
            if (control == null)
            {
                return(null);
            }

            ITab <IIGameKey> gameKeyTab = GlobalInterface.Instance.Tab.Create <IIGameKey>();

            control.GetQuickSampledKeys(gameKeyTab, type);

            if (gameKeyTab == null)
            {
                return(null);
            }

            var keys = new List <BabylonAnimationKey>();

            for (int indexKey = 0; indexKey < gameKeyTab.Count; indexKey++)
            {
#if MAX2017 || MAX2018 || MAX2019
                var gameKey = gameKeyTab[indexKey];
#else
                var gameKey = gameKeyTab[new IntPtr(indexKey)];
#endif

                var key = new BabylonAnimationKey()
                {
                    frame  = gameKey.T / Loader.Global.TicksPerFrame,
                    values = extractValueFunc(gameKey)
                };
                keys.Add(key);
            }

            return(keys);
        }
Exemple #10
0
        /// <summary>
        /// The keys of each BabylonMorphTarget animation ARE NOT assumed to be identical.
        /// This function merges together all keys and binds to each an influence value for all targets.
        /// A target influence value is automatically computed when necessary.
        /// Computation rules are:
        /// - linear interpolation between target key range
        /// - constant value outside target key range
        /// </summary>
        /// <example>
        /// When:
        /// animation1.keys = {0, 25, 50, 100}
        /// animation2.keys = {50, 75, 100}
        ///
        /// Gives:
        /// mergedKeys = {0, 25, 50, 100, 75}
        /// range1=[0, 100]
        /// range2=[50, 100]
        /// for animation1, the value associated to key=75 is the interpolation of its values between 50 and 100
        /// for animation2, the value associated to key=0 is equal to the one at key=50 since 0 is out of range [50, 100] (same for key=25)</example>
        /// <param name="babylonMorphTargetManager"></param>
        /// <returns>A map which for each frame, gives the influence value of all targets</returns>
        private Dictionary <int, List <float> > _getTargetManagerAnimationsData(BabylonMorphTargetManager babylonMorphTargetManager)
        {
            // Merge all keys into a single set (no duplicated frame)
            var mergedFrames = new HashSet <int>();

            foreach (var babylonMorphTarget in babylonMorphTargetManager.targets)
            {
                if (babylonMorphTarget.animations != null)
                {
                    var animation = babylonMorphTarget.animations[0];
                    foreach (BabylonAnimationKey animationKey in animation.keys)
                    {
                        mergedFrames.Add(animationKey.frame);
                    }
                }
            }

            // For each frame, gives the influence value of all targets (gltf structure)
            var influencesPerFrame = new Dictionary <int, List <float> >();

            foreach (var frame in mergedFrames)
            {
                influencesPerFrame.Add(frame, new List <float>());
            }
            foreach (var babylonMorphTarget in babylonMorphTargetManager.targets)
            {
                // For a given target, for each frame, gives the influence value of the target (babylon structure)
                var influencePerFrameForTarget = new Dictionary <int, float>();

                if (babylonMorphTarget.animations != null && babylonMorphTarget.animations.Length > 0)
                {
                    var animation = babylonMorphTarget.animations[0];

                    if (animation.keys.Length == 1)
                    {
                        // Same influence for all frames
                        var influence = animation.keys[0].values[0];
                        foreach (var frame in mergedFrames)
                        {
                            influencePerFrameForTarget.Add(frame, influence);
                        }
                    }
                    else
                    {
                        // Retreive target animation key range [min, max]
                        var babylonAnimationKeys = new List <BabylonAnimationKey>(animation.keys);
                        babylonAnimationKeys.Sort();
                        var minAnimationKey = babylonAnimationKeys[0];
                        var maxAnimationKey = babylonAnimationKeys[babylonAnimationKeys.Count - 1];

                        foreach (var frame in mergedFrames)
                        {
                            // Surround the current frame with closest keys available for the target
                            BabylonAnimationKey lowerAnimationKey = minAnimationKey;
                            BabylonAnimationKey upperAnimationKey = maxAnimationKey;
                            foreach (BabylonAnimationKey animationKey in animation.keys)
                            {
                                if (lowerAnimationKey.frame < animationKey.frame && animationKey.frame <= frame)
                                {
                                    lowerAnimationKey = animationKey;
                                }
                                if (frame <= animationKey.frame && animationKey.frame < upperAnimationKey.frame)
                                {
                                    upperAnimationKey = animationKey;
                                }
                            }

                            // In case the target has a key for this frame
                            // or the current frame is out of target animation key range
                            if (lowerAnimationKey.frame == upperAnimationKey.frame)
                            {
                                influencePerFrameForTarget.Add(frame, lowerAnimationKey.values[0]);
                            }
                            else
                            {
                                // Interpolate influence values
                                var t         = 1.0f * (frame - lowerAnimationKey.frame) / (upperAnimationKey.frame - lowerAnimationKey.frame);
                                var influence = Tools.Lerp(lowerAnimationKey.values[0], upperAnimationKey.values[0], t);
                                influencePerFrameForTarget.Add(frame, influence);
                            }
                        }
                    }
                }
                else
                {
                    // Target is not animated
                    // Fill all frames with 0
                    foreach (var frame in mergedFrames)
                    {
                        influencePerFrameForTarget.Add(frame, 0);
                    }
                }

                // Switch from babylon to gltf storage representation
                foreach (var frame in mergedFrames)
                {
                    List <float> influences = influencesPerFrame[frame];
                    influences.Add(influencePerFrameForTarget[frame]);
                }
            }

            return(influencesPerFrame);
        }
Exemple #11
0
        private static void ExportSkeletonAnimationClipData(GameObject source, BabylonSkeleton skeleton, SkinnedMeshRenderer skinnedMesh, BabylonMesh babylonMesh, UnityEditor.AnimationState animationState, ref List <AnimationClip> states, ref UnityMetaData metaData, Animator animator)
        {
            ExporterWindow.ReportProgress(1, "Exporting skeleton clips: " + skinnedMesh.name);
            //string sourceId = GetID(source);
            int frameRate       = 0;
            int firstClipEnd    = 0;
            int totalFrameCount = 0;

            Transform[]   bones          = skinnedMesh.bones;
            List <string> stateNameCache = new List <string>();

            if (!AnimationMode.InAnimationMode())
            {
                AnimationMode.StartAnimationMode();
            }
            //var anims = new List<BabylonAnimation>();
            //var pxkeys = new List<BabylonAnimationKey>();
            float playbackSpeed      = (animationState != null) ? animationState.playbackSpeed : 1.0f;
            float clampFeetPositions = (animationState != null) ? animationState.clampFeetPositions : 0.0f;
            BabylonAnimationBaking bakeRootTransforms = (animationState != null) ? animationState.bakeRootTransforms : BabylonAnimationBaking.GameBlend;

            foreach (var bone in skeleton.bones)
            {
                int       frameOffest = 0;
                var       keys        = new List <BabylonAnimationKey>();
                Transform transform   = bones.Single(b => b.name == bone.name);
                foreach (var state in states)
                {
                    if (state == null)
                    {
                        continue;
                    }
                    AnimationClip clip = state as AnimationClip;
                    if (frameRate <= 0)
                    {
                        frameRate = (int)clip.frameRate;
                    }
                    var frameTime      = 1.0f / frameRate;
                    int clipFrameCount = (int)(clip.length * frameRate);
                    if (firstClipEnd <= 0)
                    {
                        firstClipEnd = (clipFrameCount - 1);
                    }
                    var settings = AnimationUtility.GetAnimationClipSettings(clip);
                    BabylonLoopBehavior behavior = (settings.loopTime) ? BabylonLoopBehavior.Cycle : BabylonLoopBehavior.Constant;
                    if (settings.loopTime && settings.loopBlend)
                    {
                        behavior = BabylonLoopBehavior.Relative;
                    }
                    ExporterWindow.ReportProgress(1, "Sampling: " + babylonMesh.name + " - " + bone.name + " - " + clip.name);
                    // Set Animation State Meta Data
                    if (!stateNameCache.Contains(clip.name))
                    {
                        stateNameCache.Add(clip.name);
                        // Animation Clip Information
                        Dictionary <string, object> animStateInfo = new Dictionary <string, object>();
                        animStateInfo.Add("type", "skeleton");
                        animStateInfo.Add("name", clip.name);
                        animStateInfo.Add("start", frameOffest);
                        animStateInfo.Add("stop", (frameOffest + clipFrameCount - 1));
                        animStateInfo.Add("rate", frameRate);
                        animStateInfo.Add("behavior", (int)behavior);
                        animStateInfo.Add("playback", playbackSpeed);
                        metaData.animationClips.Add(animStateInfo);
                    }
                    AnimationMode.BeginSampling();
                    for (var i = 0; i < clipFrameCount; i++)
                    {
                        Matrix4x4 local;
                        int       frameIndex = (i + frameOffest);
                        float     originalPX = transform.localPosition.x;
                        float     originalPY = transform.localPosition.y;
                        float     originalPZ = transform.localPosition.z;
                        float     originalRY = transform.localRotation.eulerAngles.y;
                        clip.SampleAnimation(source, i * frameTime);
                        if (transform == skinnedMesh.rootBone)
                        {
                            float      positionX  = transform.localPosition.x;
                            float      positionY  = transform.localPosition.y;
                            float      positionZ  = transform.localPosition.z;
                            Quaternion rotationQT = transform.localRotation;
                            if (settings.loopBlendOrientation || settings.keepOriginalOrientation)
                            {
                                if (settings.keepOriginalOrientation)
                                {
                                    // Original Rotation - ???
                                    rotationQT = Quaternion.Euler(rotationQT.eulerAngles.x, originalRY, rotationQT.eulerAngles.z);
                                }
                                else
                                {
                                    // Body Orientation - ???
                                    rotationQT = Quaternion.Euler(rotationQT.eulerAngles.x, settings.orientationOffsetY, rotationQT.eulerAngles.z);
                                }
                            }
                            if (settings.loopBlendPositionY || settings.keepOriginalPositionY)
                            {
                                if (settings.keepOriginalPositionY)
                                {
                                    // Original Position Y
                                    positionY = originalPY;
                                }
                                else if (settings.heightFromFeet)
                                {
                                    // Feet Position Y
                                    positionY = (settings.level + clampFeetPositions);
                                }
                                else
                                {
                                    // Center Of Mass
                                    positionY = 0.0f;
                                }
                            }
                            if (settings.loopBlendPositionXZ || settings.keepOriginalPositionXZ)
                            {
                                if (settings.keepOriginalPositionXZ)
                                {
                                    // Original Position XZ
                                    positionX = originalPX;
                                    positionZ = originalPZ;
                                }
                                else
                                {
                                    // Center Of Mass
                                    positionX = 0.0f;
                                    positionZ = 0.0f;
                                }
                            }
                            if (bakeRootTransforms == BabylonAnimationBaking.GameBlend)
                            {
                                positionX = 0.0f;
                                positionZ = 0.0f;
                            }
                            local = Matrix4x4.TRS(new Vector3(positionX, positionY, positionZ), rotationQT, transform.localScale);
                        }
                        else
                        {
                            // DEPRECIATED: local = (transform.parent.localToWorldMatrix.inverse * transform.localToWorldMatrix);
                            local = Matrix4x4.TRS(transform.localPosition, transform.localRotation, transform.localScale);
                        }
                        float[] matrix = new[] {
                            local[0, 0], local[1, 0], local[2, 0], local[3, 0],
                            local[0, 1], local[1, 1], local[2, 1], local[3, 1],
                            local[0, 2], local[1, 2], local[2, 2], local[3, 2],
                            local[0, 3], local[1, 3], local[2, 3], local[3, 3]
                        };
                        var key = new BabylonAnimationKey
                        {
                            frame  = frameIndex,
                            values = matrix
                        };
                        keys.Add(key);
                    }
                    AnimationMode.EndSampling();
                    frameOffest     += clipFrameCount;
                    totalFrameCount += clipFrameCount;
                }
                var babylonAnimation = new BabylonAnimation
                {
                    name           = bone.name + "Animation",
                    property       = "_matrix",
                    dataType       = (int)BabylonAnimation.DataType.Matrix,
                    loopBehavior   = (int)BabylonAnimation.LoopBehavior.Relative,
                    enableBlending = false,
                    blendingSpeed  = 0.0f,
                    framePerSecond = frameRate,
                    keys           = keys.ToArray()
                };
                bone.animation = babylonAnimation;
            }
            if (AnimationMode.InAnimationMode())
            {
                AnimationMode.StopAnimationMode();
            }

            /*
             * //
             * // TODO: Format Custom Curve Keys
             * //
             * string property = "none";
             * if (pxkeys.Count > 0)
             * {
             *  property = "metadata.state.animPosition.x";
             *  anims.Add(new BabylonAnimation
             *  {
             *      dataType = (int)BabylonAnimation.DataType.Float,
             *      name = property + " animation",
             *      keys = pxkeys.ToArray(),
             *      framePerSecond = frameRate,
             *      enableBlending = false,
             *      blendingSpeed = 0.0f,
             *      loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle,
             *      property = property
             *  });
             * }
             * //
             * // Cache Babylon Animation Keys
             * //
             * if (anims.Count > 0)
             * {
             *  List<BabylonAnimation> sourceAnimiamtions = null;
             *  if (SceneBuilder.AnimationCurveKeys.ContainsKey(sourceId)) {
             *      sourceAnimiamtions = SceneBuilder.AnimationCurveKeys[sourceId];
             *  } else {
             *      sourceAnimiamtions = new List<BabylonAnimation>();
             *      SceneBuilder.AnimationCurveKeys.Add(sourceId, sourceAnimiamtions);
             *  }
             *  foreach (var anim in anims) {
             *      sourceAnimiamtions.Add(anim);
             *  }
             * }
             */
        }
Exemple #12
0
        private List <BabylonAnimation> GetAnimationsFrameByFrame(MFnTransform mFnTransform)
        {
            int start = Loader.GetMinTime();
            int end   = Loader.GetMaxTime();

            // Animations
            List <BabylonAnimation> animations = new List <BabylonAnimation>();

            string[] babylonAnimationProperties = new string[] { "scaling", "rotationQuaternion", "position", "visibility" };


            Dictionary <string, List <BabylonAnimationKey> > keysPerProperty = new Dictionary <string, List <BabylonAnimationKey> >();

            keysPerProperty.Add("scaling", new List <BabylonAnimationKey>());
            keysPerProperty.Add("rotationQuaternion", new List <BabylonAnimationKey>());
            keysPerProperty.Add("position", new List <BabylonAnimationKey>());
            keysPerProperty.Add("visibility", new List <BabylonAnimationKey>());

            // get keys
            for (int currentFrame = start; currentFrame <= end; currentFrame++)
            {
                // get transformation matrix at this frame
                MDoubleArray mDoubleMatrix = new MDoubleArray();
                MGlobal.executeCommand($"getAttr -t {currentFrame} {mFnTransform.fullPathName}.matrix", mDoubleMatrix);
                mDoubleMatrix.get(out float[] localMatrix);
                MMatrix matrix = new MMatrix(localMatrix);
                var     transformationMatrix = new MTransformationMatrix(matrix);

                // Retreive TRS vectors from matrix
                var position           = transformationMatrix.getTranslation();
                var rotationQuaternion = transformationMatrix.getRotationQuaternion();
                var scaling            = transformationMatrix.getScale();

                // Switch coordinate system at object level
                position[2]           *= -1;
                rotationQuaternion[0] *= -1;
                rotationQuaternion[1] *= -1;

                // create animation key for each property
                for (int indexAnimation = 0; indexAnimation < babylonAnimationProperties.Length; indexAnimation++)
                {
                    string babylonAnimationProperty = babylonAnimationProperties[indexAnimation];

                    BabylonAnimationKey key = new BabylonAnimationKey();
                    key.frame = currentFrame;
                    switch (indexAnimation)
                    {
                    case 0:     // scaling
                        key.values = scaling.ToArray();
                        break;

                    case 1:     // rotationQuaternion
                        key.values = rotationQuaternion.ToArray();
                        break;

                    case 2:     // position
                        key.values = position.ToArray();
                        break;

                    case 3:     // visibility
                        key.values = new float[] { Loader.GetVisibility(mFnTransform.fullPathName, currentFrame) };
                        break;
                    }

                    keysPerProperty[babylonAnimationProperty].Add(key);
                }
            }

            // create animation for each property
            for (int indexAnimation = 0; indexAnimation < babylonAnimationProperties.Length; indexAnimation++)
            {
                string babylonAnimationProperty = babylonAnimationProperties[indexAnimation];

                List <BabylonAnimationKey> keys = keysPerProperty[babylonAnimationProperty];

                var keysFull = new List <BabylonAnimationKey>(keys);

                // Optimization
                OptimizeAnimations(keys, true);

                // Ensure animation has at least 2 frames
                if (IsAnimationKeysRelevant(keys))
                {
                    int dataType = 0;                               // "scaling", "rotationQuaternion", "position", "visibility"
                    if (indexAnimation == 0 || indexAnimation == 2) // scaling and position
                    {
                        dataType = (int)BabylonAnimation.DataType.Vector3;
                    }
                    else if (indexAnimation == 1)    // rotationQuaternion
                    {
                        dataType = (int)BabylonAnimation.DataType.Quaternion;
                    }
                    else   // visibility
                    {
                        dataType = (int)BabylonAnimation.DataType.Float;
                    }
                    // Create BabylonAnimation
                    animations.Add(new BabylonAnimation()
                    {
                        dataType       = dataType,
                        name           = babylonAnimationProperty + " animation",
                        framePerSecond = Loader.GetFPS(),
                        loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                        property       = babylonAnimationProperty,
                        keys           = keys.ToArray(),
                        keysFull       = keysFull
                    });
                }
            }
            return(animations);
        }
Exemple #13
0
        /// <summary>
        /// Get TRS and visiblity animations of the transform
        /// </summary>
        /// <param name="transform">Transform above mesh/camera/light</param>
        /// <returns></returns>
        private List <BabylonAnimation> GetAnimation(MFnTransform transform)
        {
            // Animations
            MPlugArray   connections  = new MPlugArray();
            MStringArray animCurvList = new MStringArray();
            MIntArray    keysTime     = new MIntArray();
            MDoubleArray keysValue    = new MDoubleArray();

            MFloatArray translateValues  = new MFloatArray();
            MFloatArray rotateValues     = new MFloatArray();
            MFloatArray scaleValues      = new MFloatArray();
            MFloatArray visibilityValues = new MFloatArray();
            MFloatArray keyTimes         = new MFloatArray();

            List <BabylonAnimationKey> keys             = new List <BabylonAnimationKey>();
            List <BabylonAnimation>    animationsObject = new List <BabylonAnimation>();

            //Get the animCurve
            MGlobal.executeCommand("listConnections -type \"animCurve\" " + transform.fullPathName + ";", animCurvList);

            List <AnimCurvData> animCurvesData = new List <AnimCurvData>();

            foreach (String animCurv in animCurvList)
            {
                AnimCurvData animCurvData = new AnimCurvData();
                animCurvesData.Add(animCurvData);

                animCurvData.animCurv = animCurv;

                //Get the key time for each curves
                MGlobal.executeCommand("keyframe -q " + animCurv + ";", keysTime);

                //Get the value for each curves
                MGlobal.executeCommand("keyframe - q -vc -absolute " + animCurv + ";", keysValue);

                if (animCurv.EndsWith("translateZ") || animCurv.EndsWith("rotateX") || animCurv.EndsWith("rotateY"))
                {
                    for (int index = 0; index < keysTime.Count; index++)
                    {
                        // Switch coordinate system at object level
                        animCurvData.valuePerFrame.Add(keysTime[index], (float)keysValue[index] * -1.0f);
                    }
                }
                else
                {
                    for (int index = 0; index < keysTime.Count; index++)
                    {
                        animCurvData.valuePerFrame.Add(keysTime[index], (float)keysValue[index]);
                    }
                }
            }

            string[] mayaAnimationProperties    = new string[] { "translate", "rotate", "scale" };
            string[] babylonAnimationProperties = new string[] { "position", "rotationQuaternion", "scaling" };
            string[] axis = new string[] { "X", "Y", "Z" };

            // Init TRS default values
            Dictionary <string, float> defaultValues = new Dictionary <string, float>();

            float[] position           = null;
            float[] rotationQuaternion = null;
            float[] rotation           = null;
            float[] scaling            = null;
            GetTransform(transform, ref position, ref rotationQuaternion, ref rotation, ref scaling); // coordinate system already switched
            defaultValues.Add("translateX", position[0]);
            defaultValues.Add("translateY", position[1]);
            defaultValues.Add("translateZ", position[2]);
            defaultValues.Add("rotateX", rotation[0]);
            defaultValues.Add("rotateY", rotation[1]);
            defaultValues.Add("rotateZ", rotation[2]);
            defaultValues.Add("scaleX", scaling[0]);
            defaultValues.Add("scaleY", scaling[1]);
            defaultValues.Add("scaleZ", scaling[2]);

            for (int indexAnimationProperty = 0; indexAnimationProperty < mayaAnimationProperties.Length; indexAnimationProperty++)
            {
                string mayaAnimationProperty = mayaAnimationProperties[indexAnimationProperty];

                // Retreive animation curves data for current animation property
                // Ex: all "translate" data are "translateX", "translateY", "translateZ"
                List <AnimCurvData> animDataProperty = animCurvesData.Where(data => data.animCurv.Contains(mayaAnimationProperty)).ToList();

                if (animDataProperty.Count == 0)
                {
                    // Property is not animated
                    continue;
                }

                // Get all frames for this property
                List <int> framesProperty = new List <int>();
                foreach (var animData in animDataProperty)
                {
                    framesProperty.AddRange(animData.valuePerFrame.Keys);
                }
                framesProperty = framesProperty.Distinct().ToList();
                framesProperty.Sort();

                // Get default values for this property
                BabylonAnimationKey lastBabylonAnimationKey = new BabylonAnimationKey();
                lastBabylonAnimationKey.frame  = 0;
                lastBabylonAnimationKey.values = new float[] { defaultValues[mayaAnimationProperty + "X"], defaultValues[mayaAnimationProperty + "Y"], defaultValues[mayaAnimationProperty + "Z"] };

                // Compute all values for this property
                List <BabylonAnimationKey> babylonAnimationKeys = new List <BabylonAnimationKey>();
                foreach (var frameProperty in framesProperty)
                {
                    BabylonAnimationKey babylonAnimationKey = new BabylonAnimationKey();
                    babylonAnimationKeys.Add(babylonAnimationKey);

                    // Frame
                    babylonAnimationKey.frame = frameProperty;

                    // Values
                    float[] valuesProperty = new float[3];
                    for (int indexAxis = 0; indexAxis < axis.Length; indexAxis++)
                    {
                        AnimCurvData animCurvDataAxis = animDataProperty.Find(data => data.animCurv.EndsWith(axis[indexAxis]));

                        float value;
                        if (animCurvDataAxis != null && animCurvDataAxis.valuePerFrame.ContainsKey(frameProperty))
                        {
                            value = animCurvDataAxis.valuePerFrame[frameProperty];
                        }
                        else
                        {
                            value = lastBabylonAnimationKey.values[indexAxis];
                        }
                        valuesProperty[indexAxis] = value;
                    }
                    babylonAnimationKey.values = valuesProperty.ToArray();

                    // Update last known values
                    lastBabylonAnimationKey = babylonAnimationKey;
                }

                // Convert euler to quaternion angles
                if (indexAnimationProperty == 1) // Rotation
                {
                    foreach (var babylonAnimationKey in babylonAnimationKeys)
                    {
                        BabylonVector3    eulerAngles      = BabylonVector3.FromArray(babylonAnimationKey.values);
                        BabylonQuaternion quaternionAngles = eulerAngles.toQuaternion();
                        babylonAnimationKey.values = quaternionAngles.ToArray();
                    }
                }

                var keysFull = new List <BabylonAnimationKey>(babylonAnimationKeys);

                // Optimization
                OptimizeAnimations(babylonAnimationKeys, true);

                // Ensure animation has at least 2 frames
                if (IsAnimationKeysRelevant(keys))
                {
                    // Create BabylonAnimation
                    string babylonAnimationProperty = babylonAnimationProperties[indexAnimationProperty];
                    animationsObject.Add(new BabylonAnimation()
                    {
                        dataType       = indexAnimationProperty == 1 ? (int)BabylonAnimation.DataType.Quaternion : (int)BabylonAnimation.DataType.Vector3,
                        name           = babylonAnimationProperty + " animation",
                        framePerSecond = 30,
                        loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                        property       = babylonAnimationProperty,
                        keys           = babylonAnimationKeys.ToArray(),
                        keysFull       = keysFull
                    });
                }
            }

            return(animationsObject);
        }
Exemple #14
0
        private List <BabylonAnimation> GetAnimationsFrameByFrame(MFnTransform mFnTransform)
        {
            int start = GetMinTime()[0];
            int end   = GetMaxTime()[0];

            // Animations
            List <BabylonAnimation> animations = new List <BabylonAnimation>();

            string[] babylonAnimationProperties = new string[] { "scaling", "rotationQuaternion", "position" };


            Dictionary <string, List <BabylonAnimationKey> > keysPerProperty = new Dictionary <string, List <BabylonAnimationKey> >();

            keysPerProperty.Add("scaling", new List <BabylonAnimationKey>());
            keysPerProperty.Add("rotationQuaternion", new List <BabylonAnimationKey>());
            keysPerProperty.Add("position", new List <BabylonAnimationKey>());

            // get keys
            for (int currentFrame = start; currentFrame <= end; currentFrame++)
            {
                // get transformation matrix at this frame
                MDoubleArray mDoubleMatrix = new MDoubleArray();
                MGlobal.executeCommand($"getAttr -t {currentFrame} {mFnTransform.fullPathName}.matrix", mDoubleMatrix);
                mDoubleMatrix.get(out float[] localMatrix);
                MMatrix matrix = new MMatrix(localMatrix);
                var     transformationMatrix = new MTransformationMatrix(matrix);

                // Retreive TRS vectors from matrix
                var position           = transformationMatrix.getTranslation();
                var rotationQuaternion = transformationMatrix.getRotationQuaternion();
                var scaling            = transformationMatrix.getScale();

                // Switch coordinate system at object level
                position[2]           *= -1;
                rotationQuaternion[0] *= -1;
                rotationQuaternion[1] *= -1;

                // create animation key for each property
                for (int indexAnimation = 0; indexAnimation < babylonAnimationProperties.Length; indexAnimation++)
                {
                    string babylonAnimationProperty = babylonAnimationProperties[indexAnimation];

                    BabylonAnimationKey key = new BabylonAnimationKey();
                    key.frame = currentFrame;
                    switch (indexAnimation)
                    {
                    case 0:     // scaling
                        key.values = scaling.ToArray();
                        break;

                    case 1:     // rotationQuaternion
                        key.values = rotationQuaternion.ToArray();
                        break;

                    case 2:     // position
                        key.values = position.ToArray();
                        break;
                    }

                    keysPerProperty[babylonAnimationProperty].Add(key);
                }
            }

            // create animation for each property
            for (int indexAnimation = 0; indexAnimation < babylonAnimationProperties.Length; indexAnimation++)
            {
                string babylonAnimationProperty = babylonAnimationProperties[indexAnimation];

                List <BabylonAnimationKey> keys = keysPerProperty[babylonAnimationProperty];

                // Optimization
                OptimizeAnimations(keys, true);

                // Ensure animation has at least 2 frames
                if (keys.Count > 1)
                {
                    var animationPresent = true;

                    // Ensure animation has at least 2 non equal frames
                    if (keys.Count == 2)
                    {
                        if (keys[0].values.IsEqualTo(keys[1].values))
                        {
                            animationPresent = false;
                        }
                    }

                    if (animationPresent)
                    {
                        // Create BabylonAnimation
                        animations.Add(new BabylonAnimation()
                        {
                            dataType       = indexAnimation == 1 ? (int)BabylonAnimation.DataType.Quaternion : (int)BabylonAnimation.DataType.Vector3,
                            name           = babylonAnimationProperty + " animation",
                            framePerSecond = GetFPS(),
                            loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                            property       = babylonAnimationProperty,
                            keys           = keys.ToArray()
                        });
                    }
                }
            }

            return(animations);
        }
        private static void ExportSkeletonAnimationClipData(GameObject source, BabylonSkeleton skeleton, SkinnedMeshRenderer skinnedMesh, BabylonMesh babylonMesh, ref List <AnimationClip> clips, ref UnityMetaData metaData, List <UnityEditor.AnimationParameters> aparams)
        {
            ExporterWindow.ReportProgress(1, "Baking " + skinnedMesh.name.ToLower() + " skeleton... This may take a while.");
            string sourceId  = GetID(source);
            int    frameRate = 0;

            Transform[]         bones          = skinnedMesh.bones;
            var                 anims          = new List <BabylonAnimation>();
            List <BabylonRange> ranges         = new List <BabylonRange>();
            List <string>       stateNameCache = new List <string>();

            if (!AnimationMode.InAnimationMode())
            {
                AnimationMode.StartAnimationMode();
            }
            foreach (var bone in skeleton.bones)
            {
                int       frameOffest = 0;
                var       keys        = new List <BabylonAnimationKey>();
                Transform transform   = bones.Single(b => b.name == bone.name);
                foreach (var clip in clips)
                {
                    if (clip == null)
                    {
                        continue;
                    }
                    string clipName = FormatSafeClipName(clip.name);
                    var    settings = AnimationUtility.GetAnimationClipSettings(clip);
                    BabylonLoopBehavior behavior = (settings.loopTime) ? BabylonLoopBehavior.Relative : BabylonLoopBehavior.Constant;
                    if (settings.loopTime && settings.loopBlend)
                    {
                        behavior = BabylonLoopBehavior.Cycle;
                    }
                    // ..
                    int   framePadding = 1;
                    float deltaTime    = 1.0f / clip.frameRate;
                    if (frameRate <= 0)
                    {
                        frameRate = (int)clip.frameRate;
                    }
                    float clipFrameTotal = clip.length * clip.frameRate;
                    int   clipFrameCount = (int)clipFrameTotal + framePadding;
                    int   lastFrameCount = clipFrameCount - 1;
                    // ..
                    AnimationMode.BeginSampling();
                    for (int i = 0; i < clipFrameCount; i++)
                    {
                        Matrix4x4 local;
                        int       frameIndex = (int)(i + frameOffest);
                        float     sampleTime = (i < lastFrameCount) ? (i * deltaTime) : clip.length;
                        clip.SampleAnimation(source, sampleTime);
                        if (transform == skinnedMesh.rootBone)
                        {
                            float      positionX  = transform.localPosition.x;
                            float      positionY  = transform.localPosition.y;
                            float      positionZ  = transform.localPosition.z;
                            Quaternion rotationQT = transform.localRotation;
                            if (settings.loopBlendOrientation)
                            {
                                if (settings.keepOriginalOrientation)
                                {
                                    rotationQT = Quaternion.Euler(rotationQT.eulerAngles.x, (rotationQT.eulerAngles.y + settings.orientationOffsetY), rotationQT.eulerAngles.z);
                                }
                                else
                                {
                                    rotationQT = Quaternion.Euler(rotationQT.eulerAngles.x, settings.orientationOffsetY, rotationQT.eulerAngles.z);
                                }
                            }
                            if (settings.loopBlendPositionY)
                            {
                                if (settings.keepOriginalPositionY || settings.heightFromFeet)
                                {
                                    positionY += settings.level;
                                }
                                else
                                {
                                    positionY = settings.level;
                                }
                            }
                            if (settings.loopBlendPositionXZ)
                            {
                                positionX = 0.0f;
                                positionZ = 0.0f;
                            }
                            local = Matrix4x4.TRS(new Vector3(positionX, positionY, positionZ), rotationQT, transform.localScale);
                        }
                        else
                        {
                            local = Matrix4x4.TRS(transform.localPosition, transform.localRotation, transform.localScale);
                        }
                        float[] matrix = new[] {
                            local[0, 0], local[1, 0], local[2, 0], local[3, 0],
                            local[0, 1], local[1, 1], local[2, 1], local[3, 1],
                            local[0, 2], local[1, 2], local[2, 2], local[3, 2],
                            local[0, 3], local[1, 3], local[2, 3], local[3, 3]
                        };
                        var key = new BabylonAnimationKey
                        {
                            frame  = frameIndex,
                            values = matrix
                        };
                        keys.Add(key);
                    }
                    AnimationMode.EndSampling();
                    // ..
                    // Set Animation State Meta Data
                    // ..
                    if (!stateNameCache.Contains(clipName))
                    {
                        stateNameCache.Add(clipName);
                        // Animation Clip Information
                        int fromFrame = frameOffest, toFrame = frameOffest + lastFrameCount;
                        Dictionary <string, object> animStateInfo = new Dictionary <string, object>();
                        animStateInfo.Add("type", "skeleton");
                        animStateInfo.Add("wrap", clip.wrapMode);
                        animStateInfo.Add("name", clipName);
                        animStateInfo.Add("start", fromFrame);
                        animStateInfo.Add("stop", toFrame);
                        animStateInfo.Add("rate", clip.frameRate);
                        animStateInfo.Add("frames", clipFrameCount);
                        animStateInfo.Add("weight", 1.0f);
                        animStateInfo.Add("behavior", (int)behavior);
                        animStateInfo.Add("apparentSpeed", clip.apparentSpeed);
                        animStateInfo.Add("averageSpeed", clip.averageSpeed.ToFloat());
                        animStateInfo.Add("averageDuration", clip.averageDuration);
                        animStateInfo.Add("averageAngularSpeed", clip.averageAngularSpeed);
                        List <string> customCurveKeyNames = new List <string>();
                        // ..
                        // UnityEditor.AnimationParameters;
                        // ..
                        if (aparams != null && aparams.Count > 0)
                        {
                            foreach (var aparam in aparams)
                            {
                                if (aparam.curve == true)
                                {
                                    var curve = Tools.GetAnimationCurve(clip, aparam.name);
                                    if (curve != null)
                                    {
                                        IEnumerable <BabylonAnimationKey> cx_keys = curve.keys.Select(keyFrame => new BabylonAnimationKey {
                                            frame  = (int)(keyFrame.time * frameRate),
                                            values = new[] { keyFrame.value }
                                        });
                                        BabylonAnimationKey[] xkeys = (cx_keys != null && cx_keys.Count() > 0) ? cx_keys.ToArray() : null;
                                        if (xkeys != null && xkeys.Length > 0)
                                        {
                                            string xkey  = aparam.name;
                                            string xprop = "metadata.state.floats." + xkey;
                                            string xname = "curve:" + clipName.Replace(" ", "") + ":" + System.Guid.NewGuid().ToString();
                                            customCurveKeyNames.Add(xname);
                                            anims.Add(new BabylonAnimation
                                            {
                                                dataType       = (int)BabylonAnimation.DataType.Float,
                                                name           = xname,
                                                keys           = xkeys,
                                                framePerSecond = frameRate,
                                                enableBlending = false,
                                                blendingSpeed  = 0.0f,
                                                loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                                                property       = xprop
                                            });
                                        }
                                    }
                                }
                            }
                        }
                        animStateInfo.Add("customCurveKeyNames", (customCurveKeyNames.Count > 0) ? customCurveKeyNames.ToArray() : null);
                        metaData.animationClips.Add(animStateInfo);
                        ranges.Add(new BabylonRange {
                            name = clipName, from = fromFrame, to = toFrame
                        });
                    }
                    // ..
                    frameOffest += clipFrameCount;
                }
                var babylonAnimation = new BabylonAnimation
                {
                    name           = "skeleton:" + bone.name.ToLower() + ":animation",
                    property       = "_matrix",
                    dataType       = (int)BabylonAnimation.DataType.Matrix,
                    loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                    enableBlending = false,
                    blendingSpeed  = 0.0f,
                    framePerSecond = frameRate,
                    keys           = keys.ToArray()
                };
                bone.animation = babylonAnimation;
            }
            if (AnimationMode.InAnimationMode())
            {
                AnimationMode.StopAnimationMode();
            }
            //
            // Serialize Skeleton Clip Ranges
            //
            skeleton.ranges = (ranges.Count > 0) ? ranges.ToArray() : null;
            //
            // Cache Babylon Animation Keys
            //
            if (anims.Count > 0)
            {
                List <BabylonAnimation> sourceAnimiamtions = null;
                if (SceneBuilder.AnimationCurveKeys.ContainsKey(sourceId))
                {
                    sourceAnimiamtions = SceneBuilder.AnimationCurveKeys[sourceId];
                }
                else
                {
                    sourceAnimiamtions = new List <BabylonAnimation>();
                    SceneBuilder.AnimationCurveKeys.Add(sourceId, sourceAnimiamtions);
                }
                foreach (var anim in anims)
                {
                    sourceAnimiamtions.Add(anim);
                }
            }
        }