Ejemplo n.º 1
0
        private bool ExportMorphTargetWeightAnimation(BabylonMorphTargetManager babylonMorphTargetManager, GLTF gltf, GLTFNode gltfNode, List <GLTFChannel> channelList, List <GLTFAnimationSampler> samplerList)
        {
            if (!_isBabylonMorphTargetManagerAnimationValid(babylonMorphTargetManager))
            {
                return(false);
            }

            RaiseMessage("GLTFExporter.Animation | Export animation of morph target manager with id: " + babylonMorphTargetManager.id, 2);

            var influencesPerFrame = _getTargetManagerAnimationsData(babylonMorphTargetManager);
            var frames             = new List <int>(influencesPerFrame.Keys);

            frames.Sort(); // Mandatory otherwise gltf loader of babylon doesn't understand

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

            gltfTarget.path = "weights";

            // Buffer
            var buffer = GLTFBufferService.Instance.GetBuffer(gltf);

            // --- Input ---
            var accessorInput = GLTFBufferService.Instance.CreateAccessor(
                gltf,
                GLTFBufferService.Instance.GetBufferViewAnimationFloatScalar(gltf, buffer),
                "accessorAnimationInput",
                GLTFAccessor.ComponentType.FLOAT,
                GLTFAccessor.TypeEnum.SCALAR
                );

            // Populate accessor
            accessorInput.min = new float[] { float.MaxValue };
            accessorInput.max = new float[] { float.MinValue };

            foreach (var frame in frames)
            {
                var inputValue = frame / FPS_FACTOR;
                // Store values as bytes
                accessorInput.bytesList.AddRange(BitConverter.GetBytes(inputValue));
                // Update min and max values
                GLTFBufferService.UpdateMinMaxAccessor(accessorInput, inputValue);
            }
            accessorInput.count = influencesPerFrame.Count;

            // --- Output ---
            GLTFAccessor accessorOutput = GLTFBufferService.Instance.CreateAccessor(
                gltf,
                GLTFBufferService.Instance.GetBufferViewAnimationFloatScalar(gltf, buffer),
                "accessorAnimationWeights",
                GLTFAccessor.ComponentType.FLOAT,
                GLTFAccessor.TypeEnum.SCALAR
                );

            // Populate accessor
            foreach (var frame in frames)
            {
                var outputValues = influencesPerFrame[frame];
                // Store values as bytes
                foreach (var outputValue in outputValues)
                {
                    accessorOutput.count++;
                    accessorOutput.bytesList.AddRange(BitConverter.GetBytes(outputValue));
                }
            }

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

            return(true);
        }
Ejemplo n.º 2
0
        private bool ExportMorphTargetWeightAnimation(BabylonMorphTargetManager babylonMorphTargetManager, GLTF gltf, GLTFNode gltfNode, List <GLTFChannel> channelList, List <GLTFAnimationSampler> samplerList, int startFrame, int endFrame)
        {
            if (!_isBabylonMorphTargetManagerAnimationValid(babylonMorphTargetManager))
            {
                return(false);
            }

            RaiseMessage("GLTFExporter.Animation | Export animation of morph target manager with id: " + babylonMorphTargetManager.id, 2);

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

            gltfTarget.path = "weights";

            // Buffer
            var buffer = GLTFBufferService.Instance.GetBuffer(gltf);

            // --- Input ---
            var accessorInput = GLTFBufferService.Instance.CreateAccessor(
                gltf,
                GLTFBufferService.Instance.GetBufferViewAnimationFloatScalar(gltf, buffer),
                "accessorAnimationInput",
                GLTFAccessor.ComponentType.FLOAT,
                GLTFAccessor.TypeEnum.SCALAR
                );

            // Populate accessor
            accessorInput.min = new float[] { float.MaxValue };
            accessorInput.max = new float[] { float.MinValue };

            var influencesPerFrame = _getTargetManagerAnimationsData(babylonMorphTargetManager);
            var frames             = new List <int>(influencesPerFrame.Keys);

            frames.Sort(); // Mandatory otherwise gltf loader of babylon doesn't understand

            int numKeys = 0;

            foreach (var frame in frames)
            {
                if (frame < startFrame)
                {
                    continue;
                }

                if (frame > endFrame)
                {
                    continue;
                }

                numKeys++;
                var inputValue = frame / (float)Loader.Global.FrameRate;
                // Store values as bytes
                accessorInput.bytesList.AddRange(BitConverter.GetBytes(inputValue));
                // Update min and max values
                GLTFBufferService.UpdateMinMaxAccessor(accessorInput, inputValue);
            }
            accessorInput.count = numKeys;

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

            // --- Output ---
            GLTFAccessor accessorOutput = GLTFBufferService.Instance.CreateAccessor(
                gltf,
                GLTFBufferService.Instance.GetBufferViewAnimationFloatScalar(gltf, buffer),
                "accessorAnimationWeights",
                GLTFAccessor.ComponentType.FLOAT,
                GLTFAccessor.TypeEnum.SCALAR
                );

            // Populate accessor
            foreach (var frame in frames)
            {
                if (frame < startFrame)
                {
                    continue;
                }

                if (frame > endFrame)
                {
                    continue;
                }

                var outputValues = influencesPerFrame[frame];
                // Store values as bytes
                foreach (var outputValue in outputValues)
                {
                    accessorOutput.count++;
                    accessorOutput.bytesList.AddRange(BitConverter.GetBytes(outputValue));
                }
            }

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

            return(true);
        }
Ejemplo n.º 3
0
        private static float FPS_FACTOR = 60.0f; // TODO - Which FPS factor ?

        private GLTFAnimation ExportNodeAnimation(BabylonNode babylonNode, GLTF gltf, GLTFNode gltfNode, BabylonScene babylonScene = null)
        {
            var channelList = new List <GLTFChannel>();
            var samplerList = new List <GLTFAnimationSampler>();

            if (babylonNode.animations != null && babylonNode.animations.Length > 0)
            {
                RaiseMessage("GLTFExporter.Animation | Export animation of node named: " + babylonNode.name, 2);

                foreach (BabylonAnimation babylonAnimation in babylonNode.animations)
                {
                    // Target
                    var gltfTarget = new GLTFChannelTarget
                    {
                        node = gltfNode.index
                    };
                    gltfTarget.path = _getTargetPath(babylonAnimation.property);
                    if (gltfTarget.path == null)
                    {
                        // Unkown babylon animation property
                        RaiseWarning("GLTFExporter.Animation | Unkown animation property '" + babylonAnimation.property + "'", 3);
                        // Ignore this babylon animation
                        continue;
                    }

                    // Buffer
                    var buffer = GLTFBufferService.Instance.GetBuffer(gltf);

                    // --- Input ---
                    var accessorInput = GLTFBufferService.Instance.CreateAccessor(
                        gltf,
                        GLTFBufferService.Instance.GetBufferViewAnimationFloatScalar(gltf, buffer),
                        "accessorAnimationInput",
                        GLTFAccessor.ComponentType.FLOAT,
                        GLTFAccessor.TypeEnum.SCALAR
                        );
                    // Populate accessor
                    accessorInput.min = new float[] { float.MaxValue };
                    accessorInput.max = new float[] { float.MinValue };
                    foreach (var babylonAnimationKey in babylonAnimation.keys)
                    {
                        var inputValue = babylonAnimationKey.frame / FPS_FACTOR;
                        // Store values as bytes
                        accessorInput.bytesList.AddRange(BitConverter.GetBytes(inputValue));
                        // Update min and max values
                        GLTFBufferService.UpdateMinMaxAccessor(accessorInput, inputValue);
                    }
                    ;
                    accessorInput.count = babylonAnimation.keys.Length;

                    // --- Output ---
                    GLTFAccessor accessorOutput = null;
                    switch (gltfTarget.path)
                    {
                    case "translation":
                        accessorOutput = GLTFBufferService.Instance.CreateAccessor(
                            gltf,
                            GLTFBufferService.Instance.GetBufferViewAnimationFloatVec3(gltf, buffer),
                            "accessorAnimationPositions",
                            GLTFAccessor.ComponentType.FLOAT,
                            GLTFAccessor.TypeEnum.VEC3
                            );
                        break;

                    case "rotation":
                        accessorOutput = GLTFBufferService.Instance.CreateAccessor(
                            gltf,
                            GLTFBufferService.Instance.GetBufferViewAnimationFloatVec4(gltf, buffer),
                            "accessorAnimationRotations",
                            GLTFAccessor.ComponentType.FLOAT,
                            GLTFAccessor.TypeEnum.VEC4
                            );
                        break;

                    case "scale":
                        accessorOutput = GLTFBufferService.Instance.CreateAccessor(
                            gltf,
                            GLTFBufferService.Instance.GetBufferViewAnimationFloatVec3(gltf, buffer),
                            "accessorAnimationScales",
                            GLTFAccessor.ComponentType.FLOAT,
                            GLTFAccessor.TypeEnum.VEC3
                            );
                        break;
                    }
                    // Populate accessor
                    foreach (var babylonAnimationKey in babylonAnimation.keys)
                    {
                        var outputValues = babylonAnimationKey.values;
                        // Store values as bytes
                        foreach (var outputValue in outputValues)
                        {
                            accessorOutput.bytesList.AddRange(BitConverter.GetBytes(outputValue));
                        }
                    }
                    ;
                    accessorOutput.count = babylonAnimation.keys.Length;

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

            // Do not export empty arrays
            if (channelList.Count > 0)
            {
                // Animation
                var gltfAnimation = new GLTFAnimation
                {
                    channels = channelList.ToArray(),
                    samplers = samplerList.ToArray()
                };
                gltf.AnimationsList.Add(gltfAnimation);
                return(gltfAnimation);
            }
            else
            {
                return(null);
            }
        }
Ejemplo n.º 4
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.Core.RootNode.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 = !Loader.Core.RootNode.GetBoolProperty("babylonjs_donotoptimizeanimations"); // reverse negation for clarity

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

                    if (IsAnimationKeysRelevant(keysInRangeFull))
                    {
                        // 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;
                    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;
                        }

                        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")
                        {
                            quatCorr.Quat = new BabylonQuaternion(outputValues[0], outputValues[1], outputValues[2], outputValues[3]);
                            if (exportParameters.kuesaContQuats)
                            {
                                quatCorr.Quat   = new BabylonQuaternion(outputValues[0], outputValues[1], outputValues[2], outputValues[3]);
                                outputValues[0] = quatCorr.Quat.X;
                                outputValues[1] = quatCorr.Quat.Y;
                                outputValues[2] = quatCorr.Quat.Z;
                                outputValues[3] = quatCorr.Quat.W;
                            }
                            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);
                }
            }
        }
Ejemplo n.º 5
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);
                }
            }
        }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 7
0
        private bool ExportMorphTargetWeightAnimation(BabylonMorphTargetManager babylonMorphTargetManager, GLTF gltf, GLTFNode gltfNode, List <GLTFChannel> channelList, List <GLTFAnimationSampler> samplerList, int startFrame, int endFrame, BabylonScene babylonScene, bool offsetToStartAtFrameZero = true)
        {
            if (exportedMorphTargets.Contains(babylonMorphTargetManager) || !_isBabylonMorphTargetManagerAnimationValid(babylonMorphTargetManager))
            {
                return(false);
            }

            var influencesPerFrame = _getTargetManagerAnimationsData(babylonMorphTargetManager);
            var frames             = new List <float>(influencesPerFrame.Keys);

            var framesInRange = frames.Where(frame => frame >= startFrame && frame <= endFrame).ToList();

            framesInRange.Sort(); // Mandatory to sort otherwise gltf loader of babylon doesn't understand
            if (framesInRange.Count() <= 0)
            {
                return(false);
            }

            logger.RaiseMessage("GLTFExporter.Animation | Export animation of morph target manager with id: " + babylonMorphTargetManager.id, 2);

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

            gltfTarget.path = "weights";

            // Buffer
            var buffer = GLTFBufferService.Instance.GetBuffer(gltf);

            // --- Input ---
            var accessorInput = GLTFBufferService.Instance.CreateAccessor(
                gltf,
                GLTFBufferService.Instance.GetBufferViewAnimationFloatScalar(gltf, buffer),
                "accessorAnimationInput",
                GLTFAccessor.ComponentType.FLOAT,
                GLTFAccessor.TypeEnum.SCALAR
                );

            // Populate accessor
            accessorInput.min = new float[] { float.MaxValue };
            accessorInput.max = new float[] { float.MinValue };

            int numKeys = 0;

            foreach (var frame in framesInRange)
            {
                numKeys++;
                float inputValue = frame;
                if (offsetToStartAtFrameZero)
                {
                    inputValue -= startFrame;
                }
                inputValue /= (float)babylonScene.TimelineFramesPerSecond;
                // Store values as bytes
                accessorInput.bytesList.AddRange(BitConverter.GetBytes(inputValue));
                // Update min and max values
                GLTFBufferService.UpdateMinMaxAccessor(accessorInput, inputValue);
            }
            accessorInput.count = numKeys;

            if (accessorInput.count == 0)
            {
                logger.RaiseWarning(String.Format("GLTFExporter.Animation | No frames to export in morph target animation \"weight\" for mesh named \"{0}\". This will cause an error in the output gltf.", babylonMorphTargetManager.sourceMesh.name));
            }

            // --- Output ---
            GLTFAccessor accessorOutput = GLTFBufferService.Instance.CreateAccessor(
                gltf,
                GLTFBufferService.Instance.GetBufferViewAnimationFloatScalar(gltf, buffer),
                "accessorAnimationWeights",
                GLTFAccessor.ComponentType.FLOAT,
                GLTFAccessor.TypeEnum.SCALAR
                );

            // Populate accessor
            foreach (var frame in framesInRange)
            {
                var outputValues = influencesPerFrame[frame];
                // Store values as bytes
                foreach (var outputValue in outputValues)
                {
                    accessorOutput.count++;
                    accessorOutput.bytesList.AddRange(BitConverter.GetBytes(outputValue));
                }
            }

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

            // Mark this morph target as exported.
            exportedMorphTargets.Add(babylonMorphTargetManager);
            return(true);
        }
Ejemplo n.º 8
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);
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        private static float FPS_FACTOR = 30.0f; // TODO - Which FPS factor ?

        private GLTFAnimation ExportNodeAnimation(BabylonNode babylonNode, GLTF gltf, GLTFNode gltfNode, BabylonScene babylonScene = null)
        {
            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 ((babylonNode.animations != null && babylonNode.animations.Length > 0) ||
                (babylonNode.extraAnimations != null && babylonNode.extraAnimations.Count > 0))
            {
                RaiseMessage("GLTFExporter.Animation | Export animation of node named: " + babylonNode.name, 2);

                // 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);
                }
                foreach (BabylonAnimation babylonAnimation in babylonAnimations)
                {
                    // Target
                    var gltfTarget = new GLTFChannelTarget
                    {
                        node = gltfNode.index
                    };
                    gltfTarget.path = _getTargetPath(babylonAnimation.property);
                    if (gltfTarget.path == null)
                    {
                        // Unkown babylon animation property
                        //RaiseWarning("GLTFExporter.Animation | Unkown animation property '" + babylonAnimation.property + "'", 3);
                        // Ignore this babylon animation
                        continue;
                    }

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

                    // --- Output ---
                    GLTFAccessor accessorOutput = _createAccessorOfPath(gltfTarget.path, gltf);
                    // Populate accessor
                    foreach (var babylonAnimationKey in babylonAnimation.keys)
                    {
                        var outputValues = babylonAnimationKey.values;

                        // 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 = babylonAnimation.keys.Length;

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

            return(gltfAnimation);
        }
        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;

            if ((babylonNode.animations != null && babylonNode.animations.Length > 0) ||
                (babylonNode.extraAnimations != null && babylonNode.extraAnimations.Count > 0))
            {
                RaiseMessage("GLTFExporter.Animation | Export animation of node named: " + babylonNode.name, 2);

                // 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);
                }
                foreach (BabylonAnimation babylonAnimation in babylonAnimations)
                {
                    // Target
                    var gltfTarget = new GLTFChannelTarget
                    {
                        node = gltfNode.index
                    };
                    gltfTarget.path = _getTargetPath(babylonAnimation.property);
                    if (gltfTarget.path == null)
                    {
                        // Unkown babylon animation property
                        //RaiseWarning("GLTFExporter.Animation | Unkown animation property '" + babylonAnimation.property + "'", 3);
                        // Ignore this babylon animation
                        continue;
                    }

                    // --- 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++;
                        var outputValues = babylonAnimationKey.values;
                        // 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);
                }
            }
        }
Ejemplo n.º 12
0
        private static float FPS_FACTOR = 30.0f; // TODO - Which FPS factor ?

        private GLTFAnimation ExportNodeAnimation(BabylonNode babylonNode, GLTF gltf, GLTFNode gltfNode, BabylonScene babylonScene = null)
        {
            var channelList = new List <GLTFChannel>();
            var samplerList = new List <GLTFAnimationSampler>();

            if (babylonNode.animations != null && babylonNode.animations.Length > 0)
            {
                RaiseMessage("GLTFExporter.Animation | Export animation of node named: " + babylonNode.name, 2);

                foreach (BabylonAnimation babylonAnimation in babylonNode.animations)
                {
                    // Target
                    var gltfTarget = new GLTFChannelTarget
                    {
                        node = gltfNode.index
                    };
                    gltfTarget.path = _getTargetPath(babylonAnimation.property);
                    if (gltfTarget.path == null)
                    {
                        // Unkown babylon animation property
                        RaiseWarning("GLTFExporter.Animation | Unkown animation property '" + babylonAnimation.property + "'", 3);
                        // Ignore this babylon animation
                        continue;
                    }

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

                    // --- Output ---
                    GLTFAccessor accessorOutput = _createAccessorOfPath(gltfTarget.path, gltf);
                    // Populate accessor
                    foreach (var babylonAnimationKey in babylonAnimation.keys)
                    {
                        var outputValues = babylonAnimationKey.values;
                        // Store values as bytes
                        foreach (var outputValue in outputValues)
                        {
                            accessorOutput.bytesList.AddRange(BitConverter.GetBytes(outputValue));
                        }
                    }
                    ;
                    accessorOutput.count = babylonAnimation.keys.Length;

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

            // Do not export empty arrays
            if (channelList.Count > 0)
            {
                // Animation
                var gltfAnimation = new GLTFAnimation
                {
                    channels = channelList.ToArray(),
                    samplers = samplerList.ToArray()
                };
                gltf.AnimationsList.Add(gltfAnimation);
                return(gltfAnimation);
            }
            else
            {
                return(null);
            }
        }
        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.Core.RootNode.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);

            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);
                }
            }
        }
Ejemplo n.º 14
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);
                }
            }
        }