private BabylonNode BoneToNode(BabylonBone babylonBone)
        {
            BabylonNode babylonNode = new BabylonNode();

            babylonNode.id       = babylonBone.id;
            babylonNode.parentId = babylonBone.parentNodeId;
            babylonNode.name     = babylonBone.name;


            babylonNode.animations = new[] { babylonBone.animation };

            var tm_babylon = new BabylonMatrix();

            tm_babylon.m = babylonBone.matrix.ToArray();
            var s_babylon = new BabylonVector3();
            var q_babylon = new BabylonQuaternion();
            var t_babylon = new BabylonVector3();

            tm_babylon.decompose(s_babylon, q_babylon, t_babylon);
            babylonNode.position           = t_babylon.ToArray();
            babylonNode.rotationQuaternion = q_babylon.ToArray();
            babylonNode.scaling            = s_babylon.ToArray();

            return(babylonNode);
        }
Esempio n. 2
0
        private IList <BabylonAnimation> GetSubAnimations(BabylonBone babylonBone, float from, float to)
        {
            IList <BabylonAnimation> subAnimations = new List <BabylonAnimation>();

            // clone the animation
            BabylonAnimation animation = (BabylonAnimation)babylonBone.animation.Clone();

            // Select usefull keys
            var keys = animation.keysFull = animation.keysFull.FindAll(k => from <= k.frame && k.frame <= to);

            // Optimize these keys
            if (optimizeAnimations)
            {
                OptimizeAnimations(keys, true, out int keyRemovedCount);
                if (keyRemovedCount > 0)
                {
                    logger?.RaiseMessage("Optimization | Removed " + keyRemovedCount + " keys from the animation '" + animation.property + "' of '" + babylonBone.name + "'");
                }
            }
            //
            animation.keys = keys.ToArray();
            subAnimations.Add(animation);

            return(subAnimations);
        }
Esempio n. 3
0
        /// <summary>
        /// Export the bones and their animation for the given skin
        /// </summary>
        /// <param name="skin">The skin to export</param>
        /// <returns></returns>
        private BabylonBone[] ExportBones(IIGameSkin skin)
        {
            List <BabylonBone> bones         = new List <BabylonBone>();
            List <int>         nodeIndices   = GetNodeIndices(skin);
            List <IIGameNode>  revelantNodes = GetSkinnedBones(skin);

            foreach (IIGameNode node in revelantNodes)
            {
                int parentIndex = (node.NodeParent == null) ? -1 : nodeIndices.IndexOf(node.NodeParent.NodeID);

                string boneId = node.MaxNode.GetGuid().ToString();
                // create the bone
                BabylonBone bone = new BabylonBone()
                {
                    id              = (isGltfExported)?boneId:boneId + "-bone",// the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs
                    parentNodeId    = (parentIndex != -1)?node.NodeParent.MaxNode.GetGuid().ToString():null,
                    name            = node.Name,
                    index           = nodeIndices.IndexOf(node.NodeID),
                    parentBoneIndex = parentIndex,
                    matrix          = (parentIndex == -1)?node.GetWorldTM(0).ToArray():node.GetLocalTM(0).ToArray()
                };

                // Apply unit conversion factor to meter
                // Affect translation only
                bone.matrix[12] *= scaleFactorToMeters;
                bone.matrix[13] *= scaleFactorToMeters;
                bone.matrix[14] *= scaleFactorToMeters;

                if (exportParameters.exportAnimations)
                {
                    // export its animation
                    var babylonAnimation = ExportMatrixAnimation("_matrix", key =>
                    {
                        IGMatrix mat = node.GetLocalTM(key);

                        float[] matrix = mat.ToArray();

                        // Apply unit conversion factor to meter
                        // Affect translation only
                        matrix[12] *= scaleFactorToMeters;
                        matrix[13] *= scaleFactorToMeters;
                        matrix[14] *= scaleFactorToMeters;

                        return(matrix);
                    },
                                                                 false); // Do not remove linear animation keys for bones

                    if (babylonAnimation != null)
                    {
                        babylonAnimation.name = node.Name + "Animation"; // override default animation name
                        bone.animation        = babylonAnimation;
                    }
                }

                bones.Add(bone);
            }

            return(bones.ToArray());
        }
        /// <summary>
        /// Return the bones to export.
        /// </summary>
        /// <param name="skin">the skin to export</param>
        /// <returns>Array of BabylonBone to export</returns>
        private BabylonBone[] ExportBones(MFnSkinCluster skin)
        {
            int logRank   = 1;
            int skinIndex = GetSkeletonIndex(skin);
            List <BabylonBone>       bones = new List <BabylonBone>();
            Dictionary <string, int> indexByFullPathName = GetIndexByFullPathNameDictionary(skin);
            List <MObject>           revelantNodes       = GetRevelantNodes(skin);

            progressBoneStep = progressSkinStep / revelantNodes.Count;

            foreach (MObject node in revelantNodes)
            {
                MFnDagNode   dagNode = new MFnDagNode(node);
                MFnTransform currentNodeTransform = new MFnTransform(node);
                string       currentFullPathName  = dagNode.fullPathName;
                int          index       = indexByFullPathName[currentFullPathName];
                int          parentIndex = -1;
                string       parentId    = null;
                // find the parent node to get its index
                if (!dagNode.parent(0).hasFn(MFn.Type.kWorld))
                {
                    MFnTransform firstParentTransform = new MFnTransform(dagNode.parent(0));
                    parentId    = firstParentTransform.uuid().asString();
                    parentIndex = indexByFullPathName[firstParentTransform.fullPathName];
                }

                string boneId = currentNodeTransform.uuid().asString();
                // create the bone
                BabylonBone bone = new BabylonBone()
                {
                    id              = (!isBabylonExported)?boneId:boneId + "-bone",// the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs
                    parentNodeId    = parentId,
                    name            = dagNode.name,
                    index           = indexByFullPathName[currentFullPathName],
                    parentBoneIndex = parentIndex,
                    matrix          = GetBabylonMatrix(currentNodeTransform, frameBySkeletonID[skinIndex]).m,
                    animation       = GetAnimationsFrameByFrameMatrix(currentNodeTransform)
                };

                bones.Add(bone);
                RaiseVerbose($"Bone: name={bone.name}, index={bone.index}, parentBoneIndex={bone.parentBoneIndex}, matrix={string.Join(" ", bone.matrix)}", logRank + 1);

                // Progress bar
                progressSkin += progressBoneStep;
                ReportProgressChanged(progressSkin);
                CheckCancelled();
            }

            // sort
            List <BabylonBone> sorted = new List <BabylonBone>();

            sorted = bones.OrderBy(bone => bone.index).ToList();
            bones  = sorted;

            RaiseMessage($"{bones.Count} bone(s) exported", logRank + 1);

            return(bones.ToArray());
        }
Esempio n. 5
0
        private BabylonSkeleton ConvertUnitySkeletonToBabylon(Transform[] bones, Matrix4x4[] bindPoses, Transform transform, GameObject gameObject, float progress)
        {
            ExporterWindow.ReportProgress(progress, "Exporting Skeleton: " + gameObject.name);
            BabylonSkeleton babylonSkeleton = new BabylonSkeleton();

            babylonSkeleton.name = gameObject.name;
            babylonSkeleton.id   = Math.Abs(GetID(transform.gameObject).GetHashCode());
            babylonSkeleton.needInitialSkinMatrix = false;

            // Prefilled to keep order and track parents.
            var transformToBoneMap = new Dictionary <Transform, BabylonBone>();

            for (var i = 0; i < bones.Length; i++)
            {
                var unityBone = bones[i];
                ExporterWindow.ReportProgress(progress, "Exporting bone: " + unityBone.name + " at index " + i);

                var babylonBone = new BabylonBone();
                babylonBone.name  = unityBone.name;
                babylonBone.index = i;

                transformToBoneMap.Add(unityBone, babylonBone);
            }

            // Attaches Matrix and parent.
            for (var i = 0; i < bones.Length; i++)
            {
                var       unityBone   = bones[i];
                var       babylonBone = transformToBoneMap[unityBone];
                Matrix4x4 localTransform;

                // Unity BindPose is already inverse so take the inverse again :-)
                if (transformToBoneMap.ContainsKey(unityBone.parent))
                {
                    var babylonParentBone = transformToBoneMap[unityBone.parent];
                    babylonBone.parentBoneIndex = babylonParentBone.index;
                    localTransform = bindPoses[babylonBone.parentBoneIndex] * bindPoses[i].inverse;
                }
                else
                {
                    babylonBone.parentBoneIndex = -1;
                    localTransform = bindPoses[i].inverse;
                }

                transformToBoneMap[unityBone].matrix = new[] {
                    localTransform[0, 0], localTransform[1, 0], localTransform[2, 0], localTransform[3, 0],
                    localTransform[0, 1], localTransform[1, 1], localTransform[2, 1], localTransform[3, 1],
                    localTransform[0, 2], localTransform[1, 2], localTransform[2, 2], localTransform[3, 2],
                    localTransform[0, 3], localTransform[1, 3], localTransform[2, 3], localTransform[3, 3]
                };
            }

            // Reorder and attach the skeleton.
            babylonSkeleton.bones = transformToBoneMap.Values.OrderBy(b => b.index).ToArray();
            babylonScene.SkeletonsList.Add(babylonSkeleton);

            return(babylonSkeleton);
        }
Esempio n. 6
0
        private GLTFNode _exportBone(BabylonBone babylonBone, GLTF gltf, BabylonSkeleton babylonSkeleton, List <BabylonBone> bones)
        {
            if (alreadyExportedBones.ContainsKey(babylonBone))
            {
                return(alreadyExportedBones[babylonBone]);
            }

            // Node
            var gltfNode = new GLTFNode
            {
                name = babylonBone.name
            };

            gltfNode.index = gltf.NodesList.Count;
            gltf.NodesList.Add(gltfNode);
            alreadyExportedBones.Add(babylonBone, gltfNode);
            boneToGltfNodeMap.Add(babylonBone, gltfNode);

            // Hierarchy
            if (babylonBone.parentBoneIndex >= 0)
            {
                var babylonParentBone = bones.Find(_babylonBone => _babylonBone.index == babylonBone.parentBoneIndex);
                var gltfParentNode    = _exportBone(babylonParentBone, gltf, babylonSkeleton, bones);
                RaiseMessage("GLTFExporter.Skin | Add " + babylonBone.name + " as child to " + gltfParentNode.name, 3);
                gltfParentNode.ChildrenList.Add(gltfNode.index);
                gltfNode.parent = gltfParentNode;
            }
            else
            {
                // It's a root node
                // Only root nodes are listed in a gltf scene
                RaiseMessage("GLTFExporter.Skin | Add " + babylonBone.name + " as root node to scene", 3);
                gltf.scenes[0].NodesList.Add(gltfNode.index);
            }

            // Transform
            // Bones transform are exported through translation/rotation/scale (TRS) rather than matrix
            // Because gltf node animation can only target TRS properties, not the matrix one
            // Create matrix from array
            var babylonMatrix = new BabylonMatrix();

            babylonMatrix.m = babylonBone.matrix;
            // Decompose matrix into TRS
            var translationBabylon  = new BabylonVector3();
            var rotationQuatBabylon = new BabylonQuaternion();
            var scaleBabylon        = new BabylonVector3();

            babylonMatrix.decompose(scaleBabylon, rotationQuatBabylon, translationBabylon);
            // Store TRS values
            gltfNode.translation = translationBabylon.ToArray();
            gltfNode.rotation    = rotationQuatBabylon.ToArray();
            gltfNode.scale       = scaleBabylon.ToArray();

            // Animations
            //ExportBoneAnimation(babylonBone, gltf, gltfNode);

            return(gltfNode);
        }
Esempio n. 7
0
        /// <summary>
        /// Return the bones to export.
        /// </summary>
        /// <param name="skin">the skin to export</param>
        /// <returns>Array of BabylonBone to export</returns>
        private BabylonBone[] ExportBones(MFnSkinCluster skin)
        {
            int logRank   = 1;
            int skinIndex = GetSkeletonIndex(skin);
            List <BabylonBone>       bones = new List <BabylonBone>();
            Dictionary <string, int> indexByFullPathName = GetIndexByFullPathNameDictionary(skin);
            List <MObject>           revelantNodes       = GetRevelantNodes(skin);

            progressBoneStep = progressSkinStep / revelantNodes.Count;

            foreach (MObject node in revelantNodes)
            {
                MFnDagNode   dagNode = new MFnDagNode(node);
                MFnTransform currentNodeTransform = new MFnTransform(node);
                string       currentFullPathName  = dagNode.fullPathName;
                int          index       = indexByFullPathName[currentFullPathName];
                int          parentIndex = -1;

                // find the parent node to get its index
                if (!dagNode.parent(0).hasFn(MFn.Type.kWorld))
                {
                    MFnTransform firstParentTransform = new MFnTransform(dagNode.parent(0));
                    parentIndex = indexByFullPathName[firstParentTransform.fullPathName];
                }

                // create the bone
                BabylonBone bone = new BabylonBone()
                {
                    name            = currentFullPathName,
                    index           = indexByFullPathName[currentFullPathName],
                    parentBoneIndex = parentIndex,
                    matrix          = ConvertMayaToBabylonMatrix(currentNodeTransform.transformationMatrix).m.ToArray(),
                    animation       = GetAnimationsFrameByFrameMatrix(currentNodeTransform)
                };

                bones.Add(bone);
                RaiseMessage($"Bone: name={bone.name}, index={bone.index}, parentBoneIndex={bone.parentBoneIndex}, matrix={string.Join(" ", bone.matrix)}", logRank + 1);

                // Progress bar
                progressSkin += progressBoneStep;
                ReportProgressChanged(progressSkin);
                CheckCancelled();
            }

            // sort
            List <BabylonBone> sorted = new List <BabylonBone>();

            sorted = bones.OrderBy(bone => bone.index).ToList();
            bones  = sorted;

            RaiseMessage($"{bones.Count} bone(s) exported", logRank + 1);

            return(bones.ToArray());
        }
Esempio n. 8
0
        /// <summary>
        /// Export the bones and their animation for the given skin
        /// </summary>
        /// <param name="skin">The skin to export</param>
        /// <returns></returns>
        private BabylonBone[] ExportBones(IIGameSkin skin, IIGameNode meshNode)
        {
            List <BabylonBone> bones         = new List <BabylonBone>();
            List <int>         nodeIndices   = GetNodeIndices(skin, meshNode);
            List <IIGameNode>  revelantNodes = GetSkinnedBones(skin, meshNode);

            foreach (IIGameNode node in revelantNodes)
            {
                int parentIndex = (node.NodeParent == null) ? -1 : nodeIndices.IndexOf(node.NodeParent.NodeID);

                string boneId            = node.MaxNode.GetGuid().ToString();
                string animationTargetID = node.MaxNode.GetUniqueID();
                // create the bone
                BabylonBone bone = new BabylonBone()
                {
                    id = (isGltfExported)?boneId:boneId + "-bone",// the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs
                    AnimationTargetId = animationTargetID,
                    parentNodeId      = (parentIndex != -1)?node.NodeParent.MaxNode.GetGuid().ToString():null,
                    name            = node.Name,
                    index           = nodeIndices.IndexOf(node.NodeID),
                    parentBoneIndex = parentIndex,
                    matrix          = (parentIndex == -1)?node.GetWorldTM(0).ToArray():node.GetLocalTM(0).ToArray()
                };

                // export its animation
                var babylonAnimation = ExportMatrixAnimation("_matrix", key =>
                {
                    var objectTM   = node.GetObjectTM(key);
                    var parentNode = node.NodeParent;
                    IGMatrix mat;
                    if (parentNode == null || bone.parentBoneIndex == -1)
                    {
                        mat = objectTM;
                    }
                    else
                    {
                        mat = node.GetLocalTM(key);
                    }
                    return(mat.ToArray());
                },
                                                             false, true, node.Name); // Do not remove linear animation keys for bones; Always optimize animations

                if (babylonAnimation != null)
                {
                    babylonAnimation.name = node.Name + "Animation"; // override default animation name
                    bone.animation        = babylonAnimation;
                }

                bones.Add(bone);
            }

            return(bones.ToArray());
        }
Esempio n. 9
0
        /// <summary>
        /// Export the bones and their animation for the given skin
        /// </summary>
        /// <param name="skin">The skin to export</param>
        /// <returns></returns>
        private BabylonBone[] ExportBones(IIGameSkin skin)
        {
            List <BabylonBone> bones         = new List <BabylonBone>();
            List <int>         nodeIndices   = GetNodeIndices(skin);
            List <IIGameNode>  revelantNodes = GetRevelantNodes(skin);

            foreach (IIGameNode node in revelantNodes)
            {
                int parentIndex = (node.NodeParent == null) ? -1 : nodeIndices.IndexOf(node.NodeParent.NodeID);

                // create the bone
                BabylonBone bone = new BabylonBone()
                {
                    id              = node.MaxNode.GetGuid().ToString(),
                    name            = node.Name,
                    index           = nodeIndices.IndexOf(node.NodeID),
                    parentBoneIndex = parentIndex,
                    matrix          = node.GetLocalTM(0).ToArray()
                };

                // export its animation
                var babylonAnimation = ExportMatrixAnimation("_matrix", key =>
                {
                    var objectTM   = node.GetObjectTM(key);
                    var parentNode = node.NodeParent;
                    IGMatrix mat;
                    if (parentNode == null || bone.parentBoneIndex == -1)
                    {
                        mat = objectTM;
                    }
                    else
                    {
                        mat = objectTM.Multiply(parentNode.GetObjectTM(key).Inverse);
                    }
                    return(mat.ToArray());
                },
                                                             false); // Do not remove linear animation keys for bones

                if (babylonAnimation != null)
                {
                    babylonAnimation.name = node.Name + "Animation"; // override default animation name
                    bone.animation        = babylonAnimation;
                }

                bones.Add(bone);
            }

            return(bones.ToArray());
        }
Esempio n. 10
0
        private BabylonMatrix _getBoneWorldMatrix(BabylonBone babylonBone, List <BabylonBone> bones)
        {
            var boneLocalMatrix = new BabylonMatrix();

            boneLocalMatrix.m = babylonBone.matrix;
            if (babylonBone.parentBoneIndex == -1)
            {
                return(boneLocalMatrix);
            }
            else
            {
                var parentBabylonBone = bones.Find(bone => bone.index == babylonBone.parentBoneIndex);
                var parentWorldMatrix = _getBoneWorldMatrix(parentBabylonBone, bones);
                return(boneLocalMatrix * parentWorldMatrix);
            }
        }
Esempio n. 11
0
        private void ParseBones(SkinningData skinningData, BabylonSkeleton skeleton)
        {
            // Bones
            var bones = new List <BabylonBone>();

            for (int boneIndex = 0; boneIndex < skinningData.BindPose.Count; boneIndex++)
            {
                var newBone = new BabylonBone();
                bones.Add(newBone);

                newBone.name            = "bone" + boneIndex;
                newBone.index           = boneIndex;
                newBone.matrix          = skinningData.BindPose[boneIndex].ToMatrix().ToArray();
                newBone.parentBoneIndex = skinningData.SkeletonHierarchy[boneIndex];
            }

            skeleton.bones = bones.ToArray();
        }
Esempio n. 12
0
        private IList <BabylonAnimation> GetSubAnimations(BabylonBone babylonBone, float from, float to)
        {
            IList <BabylonAnimation> subAnimations = new List <BabylonAnimation>();

            // clone the animation
            BabylonAnimation animation = (BabylonAnimation)babylonBone.animation.Clone();

            // Select usefull keys
            var keys = animation.keysFull = animation.keysFull.FindAll(k => from <= k.frame && k.frame <= to);

            // Optimize these keys
            OptimizeAnimations(keys, false);

            //
            animation.keys = keys.ToArray();
            subAnimations.Add(animation);

            return(subAnimations);
        }
Esempio n. 13
0
        private IList <BabylonAnimation> GetSubAnimations(BabylonBone babylonBone, float from, float to)
        {
            IList <BabylonAnimation> subAnimations = new List <BabylonAnimation>();

            // clone the animation
            BabylonAnimation animation = (BabylonAnimation)babylonBone.animation.Clone();

            // Select usefull keys
            var keys = animation.keysFull.FindAll(k => from <= k.frame && k.frame <= to);

            bool keysInRangeAreRelevant = true;

            // Optimize these keys
            if (exportParameters.optimizeAnimations)
            {
                // Optimize these keys
                OptimizeAnimations(keys, false);
                keysInRangeAreRelevant = IsAnimationKeysRelevant(keys, animation.property);

                // if we are baking the animation frames, then do a less efficient check against all frames in the scene for this animation channel if the first check fails.
                if (!keysInRangeAreRelevant && exportParameters.bakeAnimationFrames)
                {
                    List <BabylonAnimationKey> optimizedKeysFull = new List <BabylonAnimationKey>(animation.keysFull);
                    OptimizeAnimations(optimizedKeysFull, true);
                    keysInRangeAreRelevant = IsAnimationKeysRelevant(optimizedKeysFull, animation.property);
                }
            }

            // If animation keys should be included in export, add to animation list.
            if (keysInRangeAreRelevant)
            {
                animation.keys = keys.ToArray();
                subAnimations.Add(animation);
            }

            return(subAnimations);
        }
Esempio n. 14
0
        private void ParseBones(SkinningData skinningData, BabylonSkeleton skeleton)
        {
            // Bones
            var bones = new List<BabylonBone>();
            for (int boneIndex = 0; boneIndex < skinningData.BindPose.Count; boneIndex++)
            {
                var newBone = new BabylonBone();
                bones.Add(newBone);

                newBone.name = "bone" + boneIndex;
                newBone.index = boneIndex;
                newBone.matrix = skinningData.BindPose[boneIndex].ToMatrix().ToArray();
                newBone.parentBoneIndex = skinningData.SkeletonHierarchy[boneIndex];
            }

            skeleton.bones = bones.ToArray();
        }
Esempio n. 15
0
        private GLTFAnimation ExportBoneAnimation(BabylonBone babylonBone, GLTF gltf, GLTFNode gltfNode)
        {
            GLTFAnimation gltfAnimation = null;

            if (gltf.AnimationsList.Count > 0)
            {
                gltfAnimation = gltf.AnimationsList[0];
            }
            else
            {
                gltfAnimation = new GLTFAnimation();
                gltf.AnimationsList.Add(gltfAnimation);
            }

            var channelList = gltfAnimation.ChannelList;
            var samplerList = gltfAnimation.SamplerList;

            if (babylonBone.animation != null && babylonBone.animation.property == "_matrix")
            {
                RaiseMessage("GLTFExporter.Animation | Export animation of bone named: " + babylonBone.name, 2);

                var babylonAnimation = babylonBone.animation;

                // --- Input ---
                var accessorInput = _createAndPopulateInput(gltf, babylonAnimation);

                // --- Output ---
                var paths = new string[] { "translation", "rotation", "scale" };
                var accessorOutputByPath = new Dictionary <string, GLTFAccessor>();

                foreach (string path in paths)
                {
                    GLTFAccessor accessorOutput = _createAccessorOfPath(path, gltf);
                    accessorOutputByPath.Add(path, accessorOutput);
                }

                // Populate accessors
                foreach (var babylonAnimationKey in babylonAnimation.keys)
                {
                    var matrix = new BabylonMatrix();
                    matrix.m = babylonAnimationKey.values;

                    var translationBabylon  = new BabylonVector3();
                    var rotationQuatBabylon = new BabylonQuaternion();
                    var scaleBabylon        = new BabylonVector3();
                    matrix.decompose(scaleBabylon, rotationQuatBabylon, translationBabylon);

                    translationBabylon.Z *= -1;
                    BabylonVector3 rotationVector3 = rotationQuatBabylon.toEulerAngles();
                    rotationVector3.X  *= -1;
                    rotationVector3.Y  *= -1;
                    rotationQuatBabylon = rotationVector3.toQuaternion();

                    var outputValuesByPath = new Dictionary <string, float[]>();
                    outputValuesByPath.Add("translation", translationBabylon.ToArray());
                    outputValuesByPath.Add("rotation", rotationQuatBabylon.ToArray());
                    outputValuesByPath.Add("scale", scaleBabylon.ToArray());

                    // Store values as bytes
                    foreach (string path in paths)
                    {
                        var accessorOutput = accessorOutputByPath[path];
                        var outputValues   = outputValuesByPath[path];

                        foreach (var outputValue in outputValues)
                        {
                            accessorOutput.bytesList.AddRange(BitConverter.GetBytes(outputValue));
                        }
                        accessorOutput.count++;
                    }
                }
                ;

                foreach (string path in paths)
                {
                    var accessorOutput = accessorOutputByPath[path];

                    // Animation sampler
                    var gltfAnimationSampler = new GLTFAnimationSampler
                    {
                        input  = accessorInput.index,
                        output = accessorOutput.index
                    };
                    gltfAnimationSampler.index = samplerList.Count;
                    samplerList.Add(gltfAnimationSampler);

                    // Target
                    var gltfTarget = new GLTFChannelTarget
                    {
                        node = gltfNode.index
                    };
                    gltfTarget.path = path;

                    // Channel
                    var gltfChannel = new GLTFChannel
                    {
                        sampler = gltfAnimationSampler.index,
                        target  = gltfTarget
                    };
                    channelList.Add(gltfChannel);
                }
            }

            return(gltfAnimation);
        }
        private void ExportSkin(IISkin skin, BabylonScene babylonScene)
        {
            var babylonSkeleton = new BabylonSkeleton {
                id = skins.IndexOf(skin)
            };

            babylonSkeleton.name = "skeleton #" + babylonSkeleton.id;

            RaiseMessage(babylonSkeleton.name, 1);

            var bones = new List <BabylonBone>();

            for (var index = 0; index < skin.NumBones; index++)
            {
                var bone = new BabylonBone {
                    name = skin.GetBoneName(index), index = index
                };

                var maxBone    = skin.GetBone(index);
                var parentNode = maxBone.ParentNode;

                if (parentNode != null)
                {
                    for (var recurseIndex = 0; recurseIndex < index; recurseIndex++)
                    {
                        if (skin.GetBone(recurseIndex).GetGuid() == parentNode.GetGuid())
                        {
                            bone.parentBoneIndex = recurseIndex;
                            break;
                        }
                    }
                }
                var hasParent = bone.parentBoneIndex != -1;
                bone.matrix = GetBoneMatrix(skin, maxBone, 0, hasParent);

                // Animation
                var babylonAnimation = new BabylonAnimation
                {
                    name           = bone.name + "Animation",
                    property       = "_matrix",
                    dataType       = BabylonAnimation.DataType.Matrix,
                    loopBehavior   = BabylonAnimation.LoopBehavior.Cycle,
                    framePerSecond = Loader.Global.FrameRate
                };

                var start = Loader.Core.AnimRange.Start;
                var end   = Loader.Core.AnimRange.End;

                float[] previous = null;
                var     keys     = new List <BabylonAnimationKey>();
                for (var key = start; key <= end; key += Ticks)
                {
                    var current = GetBoneMatrix(skin, maxBone, key, hasParent);

                    if (key == start || key == end || !(previous.IsEqualTo(current)))
                    {
                        keys.Add(new BabylonAnimationKey
                        {
                            frame  = key / Ticks,
                            values = current
                        });
                    }

                    previous = current;
                }

                babylonAnimation.keys = keys.ToArray();
                bone.animation        = babylonAnimation;

                bones.Add(bone);
            }

            babylonSkeleton.bones = bones.ToArray();

            babylonScene.SkeletonsList.Add(babylonSkeleton);
        }
Esempio n. 17
0
        private void ExportBoneAnimation(GLTFAnimation gltfAnimation, int startFrame, int endFrame, GLTF gltf, BabylonBone babylonBone, GLTFNode gltfNode)
        {
            var channelList = gltfAnimation.ChannelList;
            var samplerList = gltfAnimation.SamplerList;

            if (babylonBone.animation != null && babylonBone.animation.property == "_matrix")
            {
                logger.RaiseMessage("GLTFExporter.Animation | Export animation of bone named: " + babylonBone.name, 2);

                var babylonAnimation = babylonBone.animation;

                // --- Input ---
                var accessorInput = _createAndPopulateInput(gltf, babylonAnimation, startFrame, endFrame);
                if (accessorInput == null)
                {
                    return;
                }

                // --- Output ---
                var paths = new string[] { "translation", "rotation", "scale" };
                var accessorOutputByPath = new Dictionary <string, GLTFAccessor>();

                foreach (string path in paths)
                {
                    GLTFAccessor accessorOutput = _createAccessorOfPath(path, gltf);
                    accessorOutputByPath.Add(path, accessorOutput);
                }

                // Populate accessors
                foreach (var babylonAnimationKey in babylonAnimation.keys)
                {
                    if (babylonAnimationKey.frame < startFrame)
                    {
                        continue;
                    }

                    if (babylonAnimationKey.frame > endFrame)
                    {
                        continue;
                    }

                    var matrix = new BabylonMatrix();
                    matrix.m = babylonAnimationKey.values;

                    var translationBabylon  = new BabylonVector3();
                    var rotationQuatBabylon = new BabylonQuaternion();
                    var scaleBabylon        = new BabylonVector3();
                    matrix.decompose(scaleBabylon, rotationQuatBabylon, translationBabylon);

                    // Switch coordinate system at object level
                    translationBabylon.Z  *= -1;
                    translationBabylon    *= exportParameters.scaleFactor;
                    rotationQuatBabylon.X *= -1;
                    rotationQuatBabylon.Y *= -1;

                    var outputValuesByPath = new Dictionary <string, float[]>();
                    outputValuesByPath.Add("translation", translationBabylon.ToArray());
                    outputValuesByPath.Add("rotation", rotationQuatBabylon.ToArray());
                    outputValuesByPath.Add("scale", scaleBabylon.ToArray());

                    // Store values as bytes
                    foreach (string path in paths)
                    {
                        var accessorOutput = accessorOutputByPath[path];
                        var outputValues   = outputValuesByPath[path];

                        foreach (var outputValue in outputValues)
                        {
                            accessorOutput.bytesList.AddRange(BitConverter.GetBytes(outputValue));
                        }
                        accessorOutput.count++;
                    }
                }
                ;

                foreach (string path in paths)
                {
                    var accessorOutput = accessorOutputByPath[path];

                    // Animation sampler
                    var gltfAnimationSampler = new GLTFAnimationSampler
                    {
                        input  = accessorInput.index,
                        output = accessorOutput.index
                    };
                    gltfAnimationSampler.index = samplerList.Count;
                    samplerList.Add(gltfAnimationSampler);

                    // Target
                    var gltfTarget = new GLTFChannelTarget
                    {
                        node = gltfNode.index
                    };
                    gltfTarget.path = path;

                    // Channel
                    var gltfChannel = new GLTFChannel
                    {
                        sampler = gltfAnimationSampler.index,
                        target  = gltfTarget
                    };
                    channelList.Add(gltfChannel);
                }
            }
        }
Esempio n. 18
0
        private void ExportBoneAnimation(GLTFAnimation gltfAnimation, int startFrame, int endFrame, GLTF gltf, BabylonBone babylonBone, GLTFNode gltfNode)
        {
            var channelList = gltfAnimation.ChannelList;
            var samplerList = gltfAnimation.SamplerList;

            if (babylonBone.animation != null && babylonBone.animation.property == "_matrix")
            {
                RaiseMessage("GLTFExporter.Animation | Export animation of bone named: " + babylonBone.name, 2);

                var babylonAnimation = babylonBone.animation;

                // Optimize animation
                var optimizeAnimations = !Loader.Core.RootNode.GetBoolProperty("babylonjs_donotoptimizeanimations"); // reverse negation for clarity
                if (optimizeAnimations)
                {
                    // Filter animation keys to only keep frames between start and end
                    List <BabylonAnimationKey> keysInRangeFull = babylonAnimation.keysFull.FindAll(babylonAnimationKey => babylonAnimationKey.frame >= startFrame && babylonAnimationKey.frame <= endFrame);

                    // Optimization process always keeps first and last frames
                    OptimizeAnimations(keysInRangeFull, false);

                    if (IsAnimationKeysRelevant(keysInRangeFull))
                    {
                        // From now, use optimized animation instead
                        // Override animation keys
                        babylonAnimation.keys = keysInRangeFull.ToArray();
                    }
                }

                // --- Input ---
                var accessorInput = _createAndPopulateInput(gltf, babylonAnimation, startFrame, endFrame);
                if (accessorInput == null)
                {
                    return;
                }

                // --- Output ---
                var paths = new string[] { "translation", "rotation", "scale" };
                var accessorOutputByPath = new Dictionary <string, GLTFAccessor>();

                foreach (string path in paths)
                {
                    GLTFAccessor accessorOutput = _createAccessorOfPath(path, gltf);
                    accessorOutputByPath.Add(path, accessorOutput);
                }

                // Populate accessors
                QuatCorrection quatCorr = new QuatCorrection(); // restart correction for each curve
                foreach (var babylonAnimationKey in babylonAnimation.keys)
                {
                    if (babylonAnimationKey.frame < startFrame)
                    {
                        continue;
                    }

                    if (babylonAnimationKey.frame > endFrame)
                    {
                        continue;
                    }

                    var matrix = new BabylonMatrix();
                    matrix.m = babylonAnimationKey.values;

                    var translationBabylon  = new BabylonVector3();
                    var rotationQuatBabylon = new BabylonQuaternion();
                    var scaleBabylon        = new BabylonVector3();
                    matrix.decompose(scaleBabylon, rotationQuatBabylon, translationBabylon);

                    translationBabylon.Z *= -1;
                    if (exportParameters.kuesaContQuats)
                    {
                        quatCorr.Quat       = rotationQuatBabylon;
                        rotationQuatBabylon = quatCorr.Quat;
                    }
                    rotationQuatBabylon.X *= -1;
                    rotationQuatBabylon.Y *= -1;

                    var outputValuesByPath = new Dictionary <string, float[]>();
                    outputValuesByPath.Add("translation", translationBabylon.ToArray());
                    outputValuesByPath.Add("rotation", rotationQuatBabylon.ToArray());
                    outputValuesByPath.Add("scale", scaleBabylon.ToArray());

                    // Store values as bytes
                    foreach (string path in paths)
                    {
                        var accessorOutput = accessorOutputByPath[path];
                        var outputValues   = outputValuesByPath[path];

                        foreach (var outputValue in outputValues)
                        {
                            accessorOutput.bytesList.AddRange(BitConverter.GetBytes(outputValue));
                        }
                        accessorOutput.count++;
                    }
                }
                ;

                foreach (string path in paths)
                {
                    var accessorOutput = accessorOutputByPath[path];

                    // Animation sampler
                    var gltfAnimationSampler = new GLTFAnimationSampler
                    {
                        input  = accessorInput.index,
                        output = accessorOutput.index
                    };
                    gltfAnimationSampler.index = samplerList.Count;
                    samplerList.Add(gltfAnimationSampler);

                    // Target
                    var gltfTarget = new GLTFChannelTarget
                    {
                        node = gltfNode.index
                    };
                    gltfTarget.path = path;

                    // Channel
                    var gltfChannel = new GLTFChannel
                    {
                        sampler = gltfAnimationSampler.index,
                        target  = gltfTarget
                    };
                    channelList.Add(gltfChannel);
                }
            }
        }
Esempio n. 19
0
        private IList <BabylonAnimationGroup> ExportAnimationGroups(BabylonScene babylonScene)
        {
            IList <BabylonAnimationGroup> animationGroups = new List <BabylonAnimationGroup>();

            // Retrieve and parse animation group data
            AnimationGroupList animationList = InitAnimationGroups();

            foreach (AnimationGroup animGroup in animationList)
            {
                RaiseMessage("Exporter.animationGroups | " + animGroup.Name, 1);

                BabylonAnimationGroup animationGroup = new BabylonAnimationGroup
                {
                    name = animGroup.Name,
                    from = animGroup.FrameStart,
                    to   = animGroup.FrameEnd,
                    targetedAnimations = new List <BabylonTargetedAnimation>()
                };

                // add animations of each nodes contained in the animGroup
                foreach (uint nodeHandle in animGroup.NodeHandles)
                {
                    IINode maxNode = Loader.Core.RootNode.FindChildNode(nodeHandle);

                    // node could have been deleted, silently ignore it
                    if (maxNode == null)
                    {
                        continue;
                    }


                    // Helpers can be exported as dummies and as bones
                    string nodeId = maxNode.GetGuid().ToString();
                    string boneId = maxNode.GetGuid().ToString() + "-bone";   // the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs


                    // Node
                    BabylonNode node = babylonScene.MeshesList.FirstOrDefault(m => m.id == nodeId);
                    if (node == null)
                    {
                        node = babylonScene.CamerasList.FirstOrDefault(c => c.id == nodeId);
                    }
                    if (node == null)
                    {
                        node = babylonScene.LightsList.FirstOrDefault(l => l.id == nodeId);
                    }

                    if (node != null)
                    {
                        if (node.animations != null && node.animations.Length != 0)
                        {
                            IList <BabylonAnimation> animations = GetSubAnimations(node, animationGroup.from, animationGroup.to);
                            foreach (BabylonAnimation animation in animations)
                            {
                                BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                                {
                                    animation = animation,
                                    targetId  = nodeId
                                };

                                animationGroup.targetedAnimations.Add(targetedAnimation);
                            }
                        }
                        else if (exportNonAnimated)
                        {
                            BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                            {
                                animation = CreatePositionAnimation(animationGroup.from, animationGroup.to, node.position),
                                targetId  = node.id
                            };

                            animationGroup.targetedAnimations.Add(targetedAnimation);
                        }
                    }

                    // bone
                    BabylonBone bone  = null;
                    int         index = 0;
                    while (index < babylonScene.SkeletonsList.Count && bone == null)
                    {
                        BabylonSkeleton skel = babylonScene.SkeletonsList[index];
                        bone = skel.bones.FirstOrDefault(b => b.id == boneId);
                        index++;
                    }

                    if (bone != null)
                    {
                        if (bone.animation != null)
                        {
                            IList <BabylonAnimation> animations = GetSubAnimations(bone, animationGroup.from, animationGroup.to);
                            foreach (BabylonAnimation animation in animations)
                            {
                                BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                                {
                                    animation = animation,
                                    targetId  = boneId
                                };

                                animationGroup.targetedAnimations.Add(targetedAnimation);
                            }
                        }
                        else if (exportNonAnimated)
                        {
                            BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                            {
                                animation = CreateMatrixAnimation(animationGroup.from, animationGroup.to, bone.matrix),
                                targetId  = bone.id
                            };

                            animationGroup.targetedAnimations.Add(targetedAnimation);
                        }
                    }
                }

                if (animationGroup.targetedAnimations.Count > 0)
                {
                    animationGroups.Add(animationGroup);
                }
            }

            return(animationGroups);
        }
Esempio n. 20
0
        private IList <BabylonAnimationGroup> ExportAnimationGroups(BabylonScene babylonScene)
        {
            IList <BabylonAnimationGroup> animationGroups = new List <BabylonAnimationGroup>();

            // Retrieve and parse animation group data
            AnimationGroupList animationList = AnimationGroupList.InitAnimationGroups(logger);

            foreach (AnimationGroup animGroup in animationList)
            {
                logger?.RaiseMessage("Exporter.animationGroups | " + animGroup.Name, 1);
                BabylonAnimationGroup animationGroup = new BabylonAnimationGroup
                {
                    name               = animGroup.Name,
                    from               = animGroup.FrameStart,
                    to                 = animGroup.FrameEnd,
                    keepNonAnimated    = animGroup.KeepNonAnimated,
                    targetedAnimations = new List <BabylonTargetedAnimation>()
                };

                // add animations of each nodes contained in the animGroup
                foreach (Guid guid in animGroup.NodeGuids)
                {
                    IINode maxNode = Tools.GetINodeByGuid(guid);

                    // node could have been deleted, silently ignore it
                    if (maxNode == null)
                    {
                        continue;
                    }

                    if (exportParameters.exportAsSubmodel && !maxNode.Selected)
                    {
                        continue;
                    }


                    // Helpers can be exported as dummies and as bones
                    string nodeId = maxNode.GetGuid().ToString();
                    string boneId = isGltfExported?maxNode.GetGuid().ToString(): maxNode.GetGuid().ToString() + "-bone";   // the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs

                    // Node
                    BabylonNode node = null;
                    babylonScene.NodeMap.TryGetValue(nodeId, out node);
                    if (node != null)
                    {
                        if (node.animations != null && node.animations.Length != 0)
                        {
                            IList <BabylonAnimation> animations = GetSubAnimations(node, animationGroup.from, animationGroup.to);

                            if (!animGroup.KeepStaticAnimation)
                            {
                                RemoveStaticAnimations(ref animations);
                            }

                            foreach (BabylonAnimation animation in animations)
                            {
                                BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                                {
                                    animation = animation,
                                    targetId  = nodeId
                                };

                                animationGroup.targetedAnimations.Add(targetedAnimation);
                            }
                        }
                    }

                    // bone
                    BabylonBone bone  = null;
                    int         index = 0;
                    while (index < babylonScene.SkeletonsList.Count && bone == null)
                    {
                        BabylonSkeleton skel = babylonScene.SkeletonsList[index];
                        bone = skel.bones.FirstOrDefault(b => b.id == boneId);
                        index++;
                    }

                    if (bone != null)
                    {
                        if (bone.animation != null)
                        {
                            IList <BabylonAnimation> animations = GetSubAnimations(bone, animationGroup.from, animationGroup.to);
                            foreach (BabylonAnimation animation in animations)
                            {
                                BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                                {
                                    animation = animation,
                                    targetId  = boneId
                                };

                                animationGroup.targetedAnimations.Add(targetedAnimation);
                            }
                        }
                    }
                }

                // add animations of each nodes contained in the animGroup
                foreach (Guid guid in animGroup.MaterialGuids)
                {
                    IMtl maxMtl = Tools.GetIMtlByGuid(guid);

                    // mat could have been deleted, silently ignore it
                    if (maxMtl == null)
                    {
                        continue;
                    }

                    string matId = maxMtl.GetGuid().ToString();

                    // Material
                    BabylonMaterial material = null;
                    material = babylonScene.MaterialsList.FirstOrDefault(x => x.id == matId);
                    if (material != null)
                    {
                        if (material.animations != null && material.animations.Length != 0)
                        {
                            IList <BabylonAnimation> animations = GetSubAnimations(material, animationGroup.from, animationGroup.to);
                            foreach (BabylonAnimation animation in animations)
                            {
                                BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                                {
                                    animation = animation,
                                    targetId  = matId
                                };

                                animationGroup.targetedAnimations.Add(targetedAnimation);
                            }
                        }
                    }
                }

                if (animationGroup.targetedAnimations.Count > 0)
                {
                    animationGroups.Add(animationGroup);
                }
            }

            return(animationGroups);
        }