示例#1
0
        private void ExportNodeAnimation(GLTFAnimation gltfAnimation, int startFrame, int endFrame, GLTF gltf, BabylonNode babylonNode, GLTFNode gltfNode, BabylonScene babylonScene)
        {
            var channelList = gltfAnimation.ChannelList;
            var samplerList = gltfAnimation.SamplerList;

            bool exportNonAnimated = Loader.GetBoolProperty("babylonjs_animgroup_exportnonanimated");

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

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

            // Optimize animations to only keep ones animated between start and end frames
            var optimizeAnimations = true; // TODO - Retreive from Maya

            if (optimizeAnimations)
            {
                List <BabylonAnimation> babylonAnimationsOptimized = new List <BabylonAnimation>();
                foreach (BabylonAnimation babylonAnimation in babylonAnimations)
                {
                    // 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, true);
                    bool keysInRangeAreRelevant = IsAnimationKeysRelevant(keysInRangeFull, babylonAnimation.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 && _bakeAnimationFrames)
                    {
                        List <BabylonAnimationKey> optimizedKeysFull = new List <BabylonAnimationKey>(babylonAnimation.keysFull);
                        OptimizeAnimations(optimizedKeysFull, true);
                        keysInRangeAreRelevant = IsAnimationKeysRelevant(optimizedKeysFull, babylonAnimation.property);
                    }

                    // If we have any significant animation keys in this channel
                    // (or if we are baking the animation track and have any relevant (non-identity) animation keys in the whole track)
                    // then add the optimized keys in range to the animation track
                    if (keysInRangeAreRelevant)
                    {
                        // Override animation keys
                        babylonAnimation.keys = keysInRangeFull.ToArray();

                        babylonAnimationsOptimized.Add(babylonAnimation);
                    }
                }

                // From now, use optimized animations instead
                babylonAnimations = babylonAnimationsOptimized;
            }

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

                foreach (BabylonAnimation babylonAnimation in babylonAnimations)
                {
                    // 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 babylonAnimation.keys)
                    {
                        if (babylonAnimationKey.frame < startFrame)
                        {
                            continue;
                        }

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

                        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;

                    // bail out if no keyframes to export (?)
                    // todo [KeyInterpolation]: bail out only when there are no keyframes at all (?) and otherwise add the appropriate (interpolated) keyframes
                    if (numKeys == 0)
                    {
                        continue;
                    }

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

            if (babylonNode.GetType() == typeof(BabylonMesh))
            {
                var babylonMesh = babylonNode as BabylonMesh;

                // Morph targets
                var babylonMorphTargetManager = GetBabylonMorphTargetManager(babylonScene, babylonMesh);
                if (babylonMorphTargetManager != null)
                {
                    ExportMorphTargetWeightAnimation(babylonMorphTargetManager, gltf, gltfNode, channelList, samplerList, startFrame, endFrame);
                }
            }
        }
示例#2
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);
        }