Example #1
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);
        }
        private void ExportBoneAnimation(GLTFAnimation gltfAnimation, int startFrame, int endFrame, GLTF gltf, BabylonNode babylonNode, GLTFNode gltfNode, BabylonAnimationGroup animationGroup = null)
        {
            var channelList = gltfAnimation.ChannelList;
            var samplerList = gltfAnimation.SamplerList;

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

                BabylonAnimation babylonAnimation = null;
                if (animationGroup != null)
                {
                    var targetedAnimation = animationGroup.targetedAnimations.FirstOrDefault(animation => animation.targetId == babylonNode.id);
                    if (targetedAnimation != null)
                    {
                        babylonAnimation = targetedAnimation.animation;
                    }
                }

                // otherwise fall back to the full animation track on the node.
                if (babylonAnimation == null)
                {
                    babylonAnimation = babylonNode.animations[0];
                }

                var babylonAnimationKeysInRange = babylonAnimation.keys.Where(key => key.frame >= startFrame && key.frame <= endFrame);
                if (babylonAnimationKeysInRange.Count() <= 0)
                {
                    return;
                }

                // --- 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 babylonAnimationKeysInRange)
                {
                    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;
                    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);
                }
            }

            ExportGLTFExtension(babylonNode, ref gltfAnimation, gltf);
        }
        private void ExportNodeAnimation(GLTFAnimation gltfAnimation, int startFrame, int endFrame, GLTF gltf, BabylonNode babylonNode, GLTFNode gltfNode, BabylonScene babylonScene, BabylonAnimationGroup animationGroup = null)
        {
            var channelList = gltfAnimation.ChannelList;
            var samplerList = gltfAnimation.SamplerList;

            bool exportNonAnimated = exportParameters.animgroupExportNonAnimated;

            // Combine babylon animations from .babylon file and cached ones
            var babylonAnimations = new List <BabylonAnimation>();

            if (animationGroup != null)
            {
                var targetedAnimations = animationGroup.targetedAnimations.Where(animation => animation.targetId == babylonNode.id);
                foreach (var targetedAnimation in targetedAnimations)
                {
                    babylonAnimations.Add(targetedAnimation.animation);
                }
            }

            // Do not include the node animations if a provided animation group already includes them.
            if (babylonAnimations.Count <= 0)
            {
                if (babylonNode.animations != null)
                {
                    babylonAnimations.AddRange(babylonNode.animations);
                }

                if (babylonNode.extraAnimations != null)
                {
                    babylonAnimations.AddRange(babylonNode.extraAnimations);
                }
            }

            // Filter animations to only keep TRS ones
            babylonAnimations = babylonAnimations.FindAll(babylonAnimation => _getTargetPath(babylonAnimation.property) != null);

            if (babylonAnimations.Count > 0 || exportNonAnimated)
            {
                if (babylonAnimations.Count > 0)
                {
                    logger.RaiseMessage("GLTFExporter.Animation | Export animations of node named: " + babylonNode.name, 2);
                }
                else if (exportNonAnimated)
                {
                    logger.RaiseMessage("GLTFExporter.Animation | Export dummy animation for node named: " + babylonNode.name, 2);
                    // Export a dummy animation
                    babylonAnimations.Add(GetDummyAnimation(gltfNode, startFrame, endFrame, babylonScene));
                }


                foreach (BabylonAnimation babylonAnimation in babylonAnimations)
                {
                    var babylonAnimationKeysInRange = babylonAnimation.keys.Where(key => key.frame >= startFrame && key.frame <= endFrame);
                    if (babylonAnimationKeysInRange.Count() <= 0)
                    {
                        continue;
                    }

                    // Target
                    var gltfTarget = new GLTFChannelTarget
                    {
                        node = gltfNode.index
                    };
                    gltfTarget.path = _getTargetPath(babylonAnimation.property);

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

                    // --- Output ---
                    GLTFAccessor accessorOutput = _createAccessorOfPath(gltfTarget.path, gltf);

                    // Populate accessor
                    int numKeys = 0;
                    foreach (var babylonAnimationKey in babylonAnimationKeysInRange)
                    {
                        numKeys++;

                        // copy data before changing it in case animation groups overlap
                        float[] outputValues = new float[babylonAnimationKey.values.Length];
                        babylonAnimationKey.values.CopyTo(outputValues, 0);

                        // Switch coordinate system at object level
                        if (babylonAnimation.property == "position")
                        {
                            outputValues[2] *= -1;
                        }
                        else if (babylonAnimation.property == "rotationQuaternion")
                        {
                            outputValues[0] *= -1;
                            outputValues[1] *= -1;
                        }

                        // Store values as bytes
                        foreach (var outputValue in outputValues)
                        {
                            accessorOutput.bytesList.AddRange(BitConverter.GetBytes(outputValue));
                        }
                    }
                    ;
                    accessorOutput.count = numKeys;
                    if (accessorOutput.count == 0)
                    {
                        logger.RaiseWarning(String.Format("GLTFExporter.Animation | No frames to export in node animation \"{1}\" of node named \"{0}\". This will cause an error in the output gltf.", babylonNode.name, babylonAnimation.name));
                    }

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

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

            ExportGLTFExtension(babylonNode, ref gltfAnimation, gltf);
        }
Example #4
0
        private IList <BabylonAnimationGroup> ExportAnimationGroups(BabylonScene babylonScene)
        {
            IList <BabylonAnimationGroup> animationGroups = new List <BabylonAnimationGroup>();

            // Retrieve and parse animation group data
            AnimationGroupList animationList = InitAnimationGroups();
            bool exportNonAnimated           = Loader.GetBoolProperty("babylonjs_animgroup_exportnonanimated");

            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 in the animGroup
                List <BabylonNode> nodes = new List <BabylonNode>();
                nodes.AddRange(babylonScene.MeshesList);
                nodes.AddRange(babylonScene.CamerasList);
                nodes.AddRange(babylonScene.LightsList);

                foreach (BabylonMorphTargetManager morphTargetManager in babylonScene.MorphTargetManagersList)
                {
                    var morphTargets = morphTargetManager.targets;

                    foreach (BabylonMorphTarget morphTarget in morphTargets)
                    {
                        var animations = GetSubAnimations(morphTarget, animationGroup.from, animationGroup.to);
                        foreach (BabylonAnimation animation in animations)
                        {
                            BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                            {
                                animation = animation,
                                targetId  = morphTarget.id
                            };
                            animationGroup.targetedAnimations.Add(targetedAnimation);
                        }
                    }
                }

                foreach (BabylonNode node in nodes)
                {
                    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  = node.id
                            };

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


                foreach (BabylonSkeleton skel in babylonScene.SkeletonsList)
                {
                    foreach (BabylonBone bone in skel.bones)
                    {
                        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  = bone.id
                                };

                                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);
        }
Example #5
0
        private void ExportAnimatedNode(GLTF gltf, BabylonNode node, GLTFNode gltfNode, GLTFAnimation gltfAnimation, int startFrame, int endFrame, BabylonAnimationGroup animGroup = null)
        {
            bool        nodeHasAnimations      = node.animations != null && node.animations.Length > 0 && node.animations[0] != null;
            bool        nodeHasExtraAnimations = node.extraAnimations != null && node.extraAnimations.Count > 0 && node.extraAnimations[0] != null;
            BabylonMesh meshNode = node as BabylonMesh;
            BabylonMorphTargetManager morphTargetManager = null;
            bool nodeHasAnimatedMorphTargets             = false;

            if (meshNode != null && meshNode.morphTargetManagerId != null)
            {
                morphTargetManager = GetBabylonMorphTargetManager(babylonScene, meshNode);
                if (morphTargetManager != null)
                {
                    nodeHasAnimatedMorphTargets = morphTargetManager.targets.Any(target => target.animations != null && target.animations.Length > 0 && target.animations[0] != null);
                }
            }

            if (!nodeHasAnimations && !nodeHasExtraAnimations && !nodeHasAnimatedMorphTargets)
            {
                return;
            }
            if (nodeHasAnimations && node.animations[0].property == "_matrix")
            {
                ExportBoneAnimation(gltfAnimation, startFrame, endFrame, gltf, node, gltfNode, animGroup);
            }
            else
            {
                ExportNodeAnimation(gltfAnimation, startFrame, endFrame, gltf, node, gltfNode, babylonScene, animGroup);
            }

            if (nodeHasAnimatedMorphTargets)
            {
                ExportMorphTargetWeightAnimation(morphTargetManager, gltf, gltfNode, gltfAnimation.ChannelList, gltfAnimation.SamplerList, startFrame, endFrame, babylonScene);
            }
        }
Example #6
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);
        }