private bool IsAnEmptyAnimation(BabylonAnimation babylonAnimation) { if (babylonAnimation.keys == null) { return(true); } if (babylonAnimation.keys.Length == 0) { return(true); } var defaultValue = babylonAnimation.keysFull[0]; foreach (var animKey in babylonAnimation.keysFull) { for (int i = 0; i < animKey.values.Length; i++) { if (!animKey.values[i].IsEqualTo(defaultValue.values[i])) { return(false); } } } return(true); }
private GLTFAccessor _createAndPopulateInput(GLTF gltf, BabylonAnimation babylonAnimation) { var buffer = GLTFBufferService.Instance.GetBuffer(gltf); 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; return(accessorInput); }
private static bool ExportBabylonKeys(List <BabylonAnimationKey> keys, string property, List <BabylonAnimation> animations, BabylonAnimation.DataType dataType, BabylonAnimation.LoopBehavior loopBehavior) { if (keys.Count == 0) { return(false); } var end = Loader.Core.AnimRange.End; if (keys[keys.Count - 1].frame != end / Loader.Global.TicksPerFrame) { keys.Add(new BabylonAnimationKey() { frame = end / Loader.Global.TicksPerFrame, values = keys[keys.Count - 1].values }); } var babylonAnimation = new BabylonAnimation { dataType = (int)dataType, name = property + " animation", keys = keys.ToArray(), framePerSecond = Loader.Global.FrameRate, loopBehavior = (int)loopBehavior, property = property }; animations.Add(babylonAnimation); return(true); }
private static void ExportAnimation(string property, List <BabylonAnimation> animations, Func <int, float[]> extractValueFunc, BabylonAnimation.DataType dataType) { var start = Loader.Core.AnimRange.Start; var end = Loader.Core.AnimRange.End; float[] previous = null; var keys = new List <BabylonAnimationKey>(); for (var key = start; key <= end; key += Ticks) { var current = extractValueFunc(key); keys.Add(new BabylonAnimationKey() { frame = key / Ticks, values = current }); previous = current; } RemoveLinearAnimationKeys(keys); if (keys.Count > 0) { var animationPresent = true; if (keys.Count == 2) { if (keys[0].values.IsEqualTo(keys[1].values)) { animationPresent = false; } } if (animationPresent) { if (keys[keys.Count - 1].frame != end / Ticks) { keys.Add(new BabylonAnimationKey() { frame = end / Ticks, values = keys[keys.Count - 1].values }); } var babylonAnimation = new BabylonAnimation { dataType = dataType, name = property + " animation", keys = keys.ToArray(), framePerSecond = Loader.Global.FrameRate, loopBehavior = BabylonAnimation.LoopBehavior.Cycle, property = property }; animations.Add(babylonAnimation); } } }
private IList <BabylonAnimation> GetSubAnimations(BabylonBone babylonBone, float from, float to) { IList <BabylonAnimation> subAnimations = new List <BabylonAnimation>(); // clone the animation BabylonAnimation animation = (BabylonAnimation)babylonBone.animation.Clone(); // Select usefull keys var keys = animation.keysFull = animation.keysFull.FindAll(k => from <= k.frame && k.frame <= to); // Optimize these keys if (optimizeAnimations) { OptimizeAnimations(keys, true, out int keyRemovedCount); if (keyRemovedCount > 0) { logger?.RaiseMessage("Optimization | Removed " + keyRemovedCount + " keys from the animation '" + animation.property + "' of '" + babylonBone.name + "'"); } } // animation.keys = keys.ToArray(); subAnimations.Add(animation); return(subAnimations); }
private IList <BabylonAnimation> GetSubAnimations(BabylonNode babylonNode, float from, float to) { IList <BabylonAnimation> subAnimations = new List <BabylonAnimation>(); foreach (BabylonAnimation nodeAnimation in babylonNode.animations) { // clone the animation BabylonAnimation animation = (BabylonAnimation)nodeAnimation.Clone(); // Select usefull keys var keys = animation.keysFull = animation.keysFull.FindAll(k => from <= k.frame && k.frame <= to); // Optimize these keys if (optimizeAnimations) { OptimizeAnimations(keys, true); } // animation.keys = keys.ToArray(); subAnimations.Add(animation); } return(subAnimations); }
private BabylonAnimation CreateMatrixAnimation(float from, float to, float[] matrix) { BabylonAnimation animation = new BabylonAnimation { name = "_matrix animation", property = "_matrix", dataType = 3, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, framePerSecond = Loader.Global.FrameRate, keysFull = new List <BabylonAnimationKey>() }; animation.keysFull.Add(new BabylonAnimationKey { frame = (int)from, values = matrix }); animation.keysFull.Add(new BabylonAnimationKey { frame = (int)from, values = matrix }); animation.keys = animation.keysFull.ToArray(); return(animation); }
private BabylonAnimation CreatePositionAnimation(float from, float to, float[] position) { BabylonAnimation animation = new BabylonAnimation { name = "position animation", property = "position", dataType = 1, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, framePerSecond = Loader.GetFPS(), keysFull = new List <BabylonAnimationKey>() }; animation.keysFull.Add(new BabylonAnimationKey { frame = (int)from, values = position }); animation.keysFull.Add(new BabylonAnimationKey { frame = (int)to, values = position }); animation.keys = animation.keysFull.ToArray(); return(animation); }
private BabylonAnimation ExportAnimation(string property, Func <int, float[]> extractValueFunc, BabylonAnimation.DataType dataType, bool removeLinearAnimationKeys = true, bool optimizeAnimations = false, string name = null) { var start = Loader.Core.AnimRange.Start; var end = Loader.Core.AnimRange.End; float[] previous = null; var keys = new List <BabylonAnimationKey>(); for (var key = start; key <= end; key += Loader.Global.TicksPerFrame) { var current = extractValueFunc(key); keys.Add(new BabylonAnimationKey() { frame = key / Loader.Global.TicksPerFrame, values = current }); previous = current; } var keysFull = new List <BabylonAnimationKey>(keys); // Optimization process always keeps first and last frames if (optimizeAnimations) { OptimizeAnimations(keys, removeLinearAnimationKeys, out int keyRemovedCount); if (keyRemovedCount > 0) { logger?.RaiseMessage("Optimization | Removed " + keyRemovedCount + " keys from the animation '" + property + "' of '" + (name == null ? "" : name) + "'"); } } if (IsAnimationKeysRelevant(keys)) { if (keys[keys.Count - 1].frame != end / Loader.Global.TicksPerFrame) { keys.Add(new BabylonAnimationKey() { frame = end / Loader.Global.TicksPerFrame, values = (float[])keys[keys.Count - 1].values.Clone() }); } var babylonAnimation = new BabylonAnimation { dataType = (int)dataType, name = property + " animation", keys = keys.ToArray(), keysFull = keysFull, framePerSecond = Loader.Global.FrameRate, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, property = property }; return(babylonAnimation); } return(null); }
private BabylonAnimation GetAnimationsFrameByFrameMatrix(MFnTransform mFnTransform) { int start = GetMinTime()[0]; int end = GetMaxTime()[0]; BabylonAnimation animation = null; // get keys List <BabylonAnimationKey> keys = new List <BabylonAnimationKey>(); for (int currentFrame = start; currentFrame <= end; currentFrame++) { // Set the animation key BabylonAnimationKey key = new BabylonAnimationKey() { frame = currentFrame, values = GetBabylonMatrix(mFnTransform, currentFrame).m.ToArray() }; keys.Add(key); } // Optimization OptimizeAnimations(keys, false); // Do not remove linear animation keys for bones // Ensure animation has at least 2 frames if (keys.Count > 1) { var animationPresent = true; // Ensure animation has at least 2 non equal frames if (keys.Count == 2) { if (keys[0].values.IsEqualTo(keys[1].values)) { animationPresent = false; } } if (animationPresent) { // Create BabylonAnimation // Animations animation = new BabylonAnimation() { name = mFnTransform.name + "Animation", // override default animation name dataType = (int)BabylonAnimation.DataType.Matrix, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, framePerSecond = GetFPS(), keys = keys.ToArray(), property = "_matrix" }; } } return(animation); }
private BabylonAnimation ExportAnimation(string property, Func <int, float[]> extractValueFunc, BabylonAnimation.DataType dataType, bool removeLinearAnimationKeys = true) { var optimizeAnimations = !Loader.Core.RootNode.GetBoolProperty("babylonjs_donotoptimizeanimations"); // reverse negation for clarity var start = Loader.Core.AnimRange.Start; var end = Loader.Core.AnimRange.End; float[] previous = null; var keys = new List <BabylonAnimationKey>(); for (var key = start; key <= end; key += Loader.Global.TicksPerFrame) { var current = extractValueFunc(key); keys.Add(new BabylonAnimationKey() { frame = key / Loader.Global.TicksPerFrame, values = current }); previous = current; } var keysFull = new List <BabylonAnimationKey>(keys); // Optimization process always keeps first and last frames if (optimizeAnimations) { OptimizeAnimations(keys, removeLinearAnimationKeys); } if (IsAnimationKeysRelevant(keys)) { if (keys[keys.Count - 1].frame != end / Loader.Global.TicksPerFrame) { keys.Add(new BabylonAnimationKey() { frame = end / Loader.Global.TicksPerFrame, values = (float[])keys[keys.Count - 1].values.Clone() }); } var babylonAnimation = new BabylonAnimation { dataType = (int)dataType, name = property + " animation", keys = keys.ToArray(), keysFull = keysFull, framePerSecond = Loader.Global.FrameRate, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, property = property }; return(babylonAnimation); } return(null); }
private static void ExportSkeletonAnimationClipData(Animator animator, bool autoPlay, BabylonSkeleton skeleton, Transform[] bones, BabylonMesh babylonMesh, AnimationClip clip) { var frameTime = 1.0f / clip.frameRate; int animationFrameCount = (int)(clip.length * clip.frameRate); if (autoPlay) { babylonMesh.autoAnimate = true; babylonMesh.autoAnimateFrom = 0; babylonMesh.autoAnimateTo = animationFrameCount; babylonMesh.autoAnimateLoop = true; } foreach (var bone in skeleton.bones) { var keys = new List <BabylonAnimationKey>(); var transform = bones.Single(b => b.name == bone.name); AnimationMode.BeginSampling(); for (var i = 0; i < animationFrameCount; i++) { clip.SampleAnimation(animator.gameObject, i * frameTime); var local = (transform.parent.localToWorldMatrix.inverse * transform.localToWorldMatrix); float[] matrix = new[] { local[0, 0], local[1, 0], local[2, 0], local[3, 0], local[0, 1], local[1, 1], local[2, 1], local[3, 1], local[0, 2], local[1, 2], local[2, 2], local[3, 2], local[0, 3], local[1, 3], local[2, 3], local[3, 3] }; var key = new BabylonAnimationKey { frame = i, values = matrix, }; keys.Add(key); } AnimationMode.EndSampling(); var babylonAnimation = new BabylonAnimation { name = bone.name + "Animation", property = "_matrix", dataType = (int)BabylonAnimation.DataType.Matrix, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, framePerSecond = (int)clip.frameRate, keys = keys.ToArray() }; bone.animation = babylonAnimation; } }
public void RemoveStaticAnimations(ref IList <BabylonAnimation> babylonAnimations) { for (int i = babylonAnimations.Count - 1; i >= 0; i--) { BabylonAnimation anim = babylonAnimations[i]; if (IsAnEmptyAnimation(anim)) { logger?.RaiseMessage("Optimization | " + anim.name + " was removed "); babylonAnimations.RemoveAt(i); } } }
private GLTFAccessor _createAndPopulateInput(GLTF gltf, BabylonAnimation babylonAnimation, int startFrame, int endFrame, bool offsetToStartAtFrameZero = true) { var buffer = GLTFBufferService.Instance.GetBuffer(gltf); 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 babylonAnimationKey in babylonAnimation.keys) { if (babylonAnimationKey.frame < startFrame) { continue; } if (babylonAnimationKey.frame > endFrame) { continue; } numKeys++; float inputValue = babylonAnimationKey.frame; if (offsetToStartAtFrameZero) { inputValue -= startFrame; } inputValue /= 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 there are no keys // todo [KeyInterpolation]: bail out only when there are no keyframes at all (?) and otherwise add the appropriate (interpolated) keyframes if (numKeys == 0) { return(null); } return(accessorInput); }
/// <summary> /// Export the morph target influence animation. /// </summary> /// <param name="blendShapeDeformerName"></param> /// <param name="weightIndex"></param> /// <returns>A list containing all animations</returns> private IList <BabylonAnimation> GetAnimationsInfluence(string blendShapeDeformerName, int weightIndex) { IList <BabylonAnimation> animations = new List <BabylonAnimation>(); BabylonAnimation animation = null; IDictionary <double, IList <double> > morphWeights = GetMorphWeightsByFrame(blendShapeDeformerName); // get keys List <BabylonAnimationKey> keys = new List <BabylonAnimationKey>(); for (int index = 0; index < morphWeights.Count; index++) { KeyValuePair <double, IList <double> > keyValue = morphWeights.ElementAt(index); // Set the animation key BabylonAnimationKey key = new BabylonAnimationKey() { frame = (int)keyValue.Key, values = new float[] { (float)keyValue.Value[weightIndex] } }; keys.Add(key); } List <BabylonAnimationKey> keysFull = new List <BabylonAnimationKey>(keys); // Optimization OptimizeAnimations(keys, false); // Ensure animation has at least 2 frames if (IsAnimationKeysRelevant(keys)) { // Animations animation = new BabylonAnimation() { name = "influence animation", // override default animation name dataType = (int)BabylonAnimation.DataType.Float, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, framePerSecond = Loader.GetFPS(), keys = keys.ToArray(), keysFull = keysFull, property = "influence" }; animations.Add(animation); } return(animations); }
private GLTFAccessor _createAndPopulateInput(GLTF gltf, BabylonAnimation babylonAnimation, int startFrame, int endFrame, bool offsetToStartAtFrameZero = true) { var babylonAnimationKeysInRange = babylonAnimation.keys.Where(key => key.frame >= startFrame && key.frame <= endFrame); if (babylonAnimationKeysInRange.Count() <= 0) // do not make empty accessors, so bail out. { return(null); } var buffer = GLTFBufferService.Instance.GetBuffer(gltf); 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 babylonAnimationKey in babylonAnimationKeysInRange) { numKeys++; float inputValue = babylonAnimationKey.frame; if (offsetToStartAtFrameZero) { inputValue -= startFrame; } inputValue /= babylonAnimation.framePerSecond; // 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 input frames in GLTF Accessor for animation \"{0}\". This will cause an error in the output gltf.", babylonAnimation.name)); } return(accessorInput); }
/// <summary> /// Using MEL commands, it return the babylon animation /// </summary> /// <param name="objectName">The name of the Maya object</param> /// <param name="mayaProperty">The attribut in Maya</param> /// <param name="babylonProperty">The attribut in Babylon</param> /// <returns>A Babylon animation that represents the Maya animation</returns> public BabylonAnimation GetAnimationFloat(string objectName, string mayaProperty, string babylonProperty) { // Get keyframes IList <double> keyframes = GetKeyframes(objectName); BabylonAnimation animation = null; // set the key for each keyframe List <BabylonAnimationKey> keys = new List <BabylonAnimationKey>(); for (int index = 0; index < keyframes.Count; index++) { double keyframe = keyframes[index]; MGlobal.executeCommand($"getAttr -t {keyframe} {objectName}.{mayaProperty}", out double value); // Set the animation key BabylonAnimationKey key = new BabylonAnimationKey() { frame = (int)keyframe, values = new float[] { (float)value } }; keys.Add(key); } List <BabylonAnimationKey> keysFull = new List <BabylonAnimationKey>(keys); // Optimization OptimizeAnimations(keys, false); // Ensure animation has at least 2 frames if (IsAnimationKeysRelevant(keys)) { // Animations animation = new BabylonAnimation() { name = $"{babylonProperty} animation", // override default animation name dataType = (int)BabylonAnimation.DataType.Float, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, framePerSecond = Loader.GetFPS(), keys = keys.ToArray(), keysFull = keysFull, property = babylonProperty }; } return(animation); }
private BabylonAnimation GetAnimationsFrameByFrameMatrix(MFnTransform mFnTransform) { int start = Loader.GetMinTime(); int end = Loader.GetMaxTime(); BabylonAnimation animation = null; // get keys List <BabylonAnimationKey> keys = new List <BabylonAnimationKey>(); for (int currentFrame = start; currentFrame <= end; currentFrame++) { // Set the animation key BabylonAnimationKey key = new BabylonAnimationKey() { frame = currentFrame, values = GetBabylonMatrix(mFnTransform, currentFrame).m.ToArray() }; keys.Add(key); } var keysFull = new List <BabylonAnimationKey>(keys); // Optimization OptimizeAnimations(keys, false); // Do not remove linear animation keys for bones // Ensure animation has at least 2 frames if (IsAnimationKeysRelevant(keys)) { // Animations animation = new BabylonAnimation() { name = mFnTransform.name + "Animation", // override default animation name dataType = (int)BabylonAnimation.DataType.Matrix, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, framePerSecond = Loader.GetFPS(), keys = keys.ToArray(), keysFull = keysFull, property = "_matrix" }; } return(animation); }
private IList <BabylonAnimation> GetSubAnimations(BabylonBone babylonBone, float from, float to) { IList <BabylonAnimation> subAnimations = new List <BabylonAnimation>(); // clone the animation BabylonAnimation animation = (BabylonAnimation)babylonBone.animation.Clone(); // Select usefull keys var keys = animation.keysFull = animation.keysFull.FindAll(k => from <= k.frame && k.frame <= to); // Optimize these keys OptimizeAnimations(keys, false); // animation.keys = keys.ToArray(); subAnimations.Add(animation); return(subAnimations); }
private void SetNodePosition(ref BabylonNode node, ref BabylonScene babylonScene, float[] newPosition) { float[] offset = new float[] { newPosition[0] - node.position[0], newPosition[1] - node.position[1], newPosition[2] - node.position[2] }; node.position = newPosition; List <BabylonAnimation> animations = new List <BabylonAnimation>(node.animations); BabylonAnimation animationPosition = animations.Find(animation => animation.property.Equals("position")); if (animationPosition != null) { foreach (BabylonAnimationKey key in animationPosition.keys) { key.values = new float[] { key.values[0] + offset[0], key.values[1] + offset[1], key.values[2] + offset[2] }; } } }
bool DumpInterpolator(string name, string property, NovaFloatInterpolator interpolator, NovaScene scene, List <BabylonAnimation> animations, float mult = 1.0f) { if (interpolator.Ready && !IsInterpolatorIsEmpty(interpolator)) { var fps = scene.AnimationFramerate < 1 ? 30 : scene.AnimationFramerate; var babylonAnimation = new BabylonAnimation { name = name, property = property, dataType = BabylonAnimation.DataType.Float, framePerSecond = fps }; babylonAnimation.keys = interpolator.Datas.Select(value => new BabylonAnimationKey { frame = value.Key / scene.AnimationKeyStep, values = new[] { value.Value *mult } }).ToArray(); babylonAnimation.loopBehavior = interpolator.LoopAfter; animations.Add(babylonAnimation); return(true); } return(false); }
bool DumpInterpolator(string name, string property, NovaQuaternionInterpolator interpolator, NovaScene scene, List <BabylonAnimation> animations) { if (interpolator.Ready) { var fps = scene.AnimationFramerate < 1 ? 30 : scene.AnimationFramerate; var babylonAnimation = new BabylonAnimation { name = name, property = property, dataType = BabylonAnimation.DataType.Quaternion, framePerSecond = fps }; babylonAnimation.keys = interpolator.Datas.Select(value => new BabylonAnimationKey { frame = value.Key / scene.AnimationKeyStep, values = value.Value.ToArray() }).ToArray(); babylonAnimation.loopBehavior = interpolator.LoopAfter; animations.Add(babylonAnimation); return(true); } return(false); }
private IList <BabylonAnimation> GetSubAnimations(BabylonMorphTarget babylonMorphTarget, float from, float to) { IList <BabylonAnimation> subAnimations = new List <BabylonAnimation>(); foreach (BabylonAnimation morphTargetAnimation in babylonMorphTarget.animations) { // clone the animation BabylonAnimation animation = (BabylonAnimation)morphTargetAnimation.Clone(); // Select usefull keys var keys = animation.keysFull.FindAll(k => from <= k.frame && k.frame <= to); bool keysInRangeAreRelevant = true; // Optimize these keys if (exportParameters.optimizeAnimations) { // Optimize these keys OptimizeAnimations(keys, true); keysInRangeAreRelevant = IsAnimationKeysRelevant(keys, animation.property); // if we are baking the animation frames, then do a less efficient check against all frames in the scene for this animation channel if the first check fails. if (!keysInRangeAreRelevant && exportParameters.bakeAnimationFrames) { List <BabylonAnimationKey> optimizedKeysFull = new List <BabylonAnimationKey>(animation.keysFull); OptimizeAnimations(optimizedKeysFull, true); keysInRangeAreRelevant = IsAnimationKeysRelevant(optimizedKeysFull, animation.property); } } // If animation keys should be included in export, add to animation list. if (keysInRangeAreRelevant) { animation.keys = keys.ToArray(); subAnimations.Add(animation); } } return(subAnimations); }
private BabylonAnimation GetDummyAnimation(GLTFNode gltfNode, int startFrame, int endFrame) { BabylonAnimation dummyAnimation = new BabylonAnimation(); dummyAnimation.name = "Dummy"; dummyAnimation.property = "scaling"; dummyAnimation.framePerSecond = Loader.Global.FrameRate; dummyAnimation.dataType = (int)BabylonAnimation.DataType.Vector3; BabylonAnimationKey startKey = new BabylonAnimationKey(); startKey.frame = startFrame; startKey.values = gltfNode.scale; BabylonAnimationKey endKey = new BabylonAnimationKey(); endKey.frame = endFrame; endKey.values = gltfNode.scale; dummyAnimation.keys = new BabylonAnimationKey[] { startKey, endKey }; return(dummyAnimation); }
public BabylonAnimation GetDummyAnimation(GLTFNode gltfNode, int startFrame, int endFrame, BabylonScene babylonScene) { BabylonAnimation dummyAnimation = new BabylonAnimation(); dummyAnimation.name = "Dummy"; dummyAnimation.property = "scaling"; dummyAnimation.framePerSecond = babylonScene.TimelineFramesPerSecond; dummyAnimation.dataType = (int)BabylonAnimation.DataType.Vector3; BabylonAnimationKey startKey = new BabylonAnimationKey(); startKey.frame = startFrame; startKey.values = gltfNode.scale; BabylonAnimationKey endKey = new BabylonAnimationKey(); endKey.frame = endFrame; endKey.values = gltfNode.scale; dummyAnimation.keys = new BabylonAnimationKey[] { startKey, endKey }; return(dummyAnimation); }
private void ParseAnimationClip(SkinningData skinningData, BabylonSkeleton skeleton) { foreach (var clipKey in skinningData.AnimationClips.Keys) { var clip = skinningData.AnimationClips[clipKey]; var duration = clip.Duration.TotalMilliseconds; var dic = new Dictionary <int, List <BabylonAnimationKey> >(); foreach (var keyframe in clip.Keyframes) { if (!dic.ContainsKey(keyframe.Bone)) { dic.Add(keyframe.Bone, new List <BabylonAnimationKey>()); } var currentTime = (float)(keyframe.Time.TotalMilliseconds * 100.0 / duration); dic[keyframe.Bone].Add(new BabylonAnimationKey { frame = currentTime, values = keyframe.Transform.ToMatrix().ToArray() }); } foreach (var index in dic.Keys) { var bone = skeleton.bones[index]; var babylonAnimation = new BabylonAnimation { name = bone.name + "Animation", property = "_matrix", dataType = BabylonAnimation.DataType.Matrix, loopBehavior = InterpolationLoop.Cycle, framePerSecond = 60 }; babylonAnimation.keys = dic[index].ToArray(); bone.animation = babylonAnimation; } return; // Only one animation track } }
private static BabylonAnimation ExportAnimation(string property, Func <int, float[]> extractValueFunc, BabylonAnimation.DataType dataType, bool removeLinearAnimationKeys = true) { var optimizeAnimations = !Loader.Core.RootNode.GetBoolProperty("babylonjs_donotoptimizeanimations"); // reverse negation for clarity var start = Loader.Core.AnimRange.Start; var end = Loader.Core.AnimRange.End; float[] previous = null; var keys = new List <BabylonAnimationKey>(); for (var key = start; key <= end; key += Ticks) { var current = extractValueFunc(key); keys.Add(new BabylonAnimationKey() { frame = key / Ticks, values = current }); previous = current; } if (optimizeAnimations) { OptimizeAnimations(keys, removeLinearAnimationKeys); } if (keys.Count > 1) { var animationPresent = true; if (keys.Count == 2) { if (keys[0].values.IsEqualTo(keys[1].values)) { animationPresent = false; } } if (animationPresent) { if (keys[keys.Count - 1].frame != end / Ticks) { keys.Add(new BabylonAnimationKey() { frame = end / Ticks, values = keys[keys.Count - 1].values }); } var babylonAnimation = new BabylonAnimation { dataType = (int)dataType, name = property + " animation", keys = keys.ToArray(), framePerSecond = Loader.Global.FrameRate, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, property = property }; return(babylonAnimation); } } return(null); }
private static void ExportAnimation(string property, List <BabylonAnimation> animations, Func <int, float[]> extractValueFunc, BabylonAnimation.DataType dataType) { var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations"); var start = Loader.Core.AnimRange.Start; var end = Loader.Core.AnimRange.End; float[] previous = null; var keys = new List <BabylonAnimationKey>(); for (var key = start; key <= end; key += Ticks) { var current = extractValueFunc(key); if (exportNonOptimizedAnimations && previous != null && previous.IsEqualTo(current)) { continue; // Do not add key } keys.Add(new BabylonAnimationKey() { frame = key / Ticks, values = current }); previous = current; } if (!exportNonOptimizedAnimations) { RemoveLinearAnimationKeys(keys); } if (keys.Count > 1) { var animationPresent = true; if (keys.Count == 2) { if (keys[0].values.IsEqualTo(keys[1].values)) { animationPresent = false; } } if (animationPresent) { if (keys[keys.Count - 1].frame != end / Ticks) { keys.Add(new BabylonAnimationKey() { frame = end / Ticks, values = keys[keys.Count - 1].values }); } var babylonAnimation = new BabylonAnimation { dataType = (int)dataType, name = property + " animation", keys = keys.ToArray(), framePerSecond = Loader.Global.FrameRate, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, property = property }; animations.Add(babylonAnimation); } } }
private static bool ExportController(IControl control, string property, List <BabylonAnimation> animations, uint classId, BabylonAnimation.DataType dataType, Func <int, IIKeyControl, BabylonAnimationKey> generateFunc) { if (control == null) { return(false); } var keyControl = control.GetInterface(InterfaceID.Keycontrol) as IIKeyControl; if (keyControl == null) { return(false); } if (control.ClassID.PartA != classId) { return(false); } var keys = new List <BabylonAnimationKey>(); BabylonAnimation.LoopBehavior loopBehavior; switch (control.GetORT(2)) { case 2: loopBehavior = BabylonAnimation.LoopBehavior.Cycle; break; default: loopBehavior = BabylonAnimation.LoopBehavior.Relative; break; } for (var index = 0; index < keyControl.NumKeys; index++) { keys.Add(generateFunc(index, keyControl)); } if (keys.Count == 0) { return(false); } var end = Loader.Core.AnimRange.End; if (keys[keys.Count - 1].frame != end / Ticks) { keys.Add(new BabylonAnimationKey() { frame = end / Ticks, values = keys[keys.Count - 1].values }); } var babylonAnimation = new BabylonAnimation { dataType = (int)dataType, name = property + " animation", keys = keys.ToArray(), framePerSecond = Loader.Global.FrameRate, loopBehavior = (int)loopBehavior, property = property }; animations.Add(babylonAnimation); return(true); }
bool DumpInterpolator(string name, string property, NovaQuaternionInterpolator interpolator, NovaScene scene, List<BabylonAnimation> animations) { if (interpolator.Ready) { var fps = scene.AnimationFramerate < 1 ? 30 : scene.AnimationFramerate; var babylonAnimation = new BabylonAnimation { name = name, property = property, dataType = BabylonAnimation.DataType.Quaternion, framePerSecond = fps }; babylonAnimation.keys = interpolator.Datas.Select(value => new BabylonAnimationKey { frame = value.Key / scene.AnimationKeyStep, values = value.Value.ToArray() }).ToArray(); babylonAnimation.loopBehavior = interpolator.LoopAfter; animations.Add(babylonAnimation); return true; } return false; }
bool DumpInterpolator(string name, string property, NovaFloatInterpolator interpolator, NovaScene scene, List<BabylonAnimation> animations, float mult = 1.0f) { if (interpolator.Ready && !IsInterpolatorIsEmpty(interpolator)) { var fps = scene.AnimationFramerate < 1 ? 30 : scene.AnimationFramerate; var babylonAnimation = new BabylonAnimation { name = name, property = property, dataType = BabylonAnimation.DataType.Float, framePerSecond = fps }; babylonAnimation.keys = interpolator.Datas.Select(value => new BabylonAnimationKey { frame = value.Key / scene.AnimationKeyStep, values = new[] { value.Value * mult } }).ToArray(); babylonAnimation.loopBehavior = interpolator.LoopAfter; animations.Add(babylonAnimation); return true; } return false; }
private void ParseAnimationClip(SkinningData skinningData, BabylonSkeleton skeleton) { foreach (var clipKey in skinningData.AnimationClips.Keys) { var clip = skinningData.AnimationClips[clipKey]; var duration = clip.Duration.TotalMilliseconds; var dic = new Dictionary<int, List<BabylonAnimationKey>>(); foreach (var keyframe in clip.Keyframes) { if (!dic.ContainsKey(keyframe.Bone)) { dic.Add(keyframe.Bone, new List<BabylonAnimationKey>()); } var currentTime = (float)(keyframe.Time.TotalMilliseconds * 100.0 / duration); dic[keyframe.Bone].Add(new BabylonAnimationKey { frame = currentTime, values = keyframe.Transform.ToMatrix().ToArray() }); } foreach (var index in dic.Keys) { var bone = skeleton.bones[index]; var babylonAnimation = new BabylonAnimation { name = bone.name + "Animation", property = "_matrix", dataType = BabylonAnimation.DataType.Matrix, loopBehavior = InterpolationLoop.Cycle, framePerSecond = 60 }; babylonAnimation.keys = dic[index].ToArray(); bone.animation = babylonAnimation; } return; // Only one animation track } }
/// <summary> /// In 3DS Max default element can look in different direction than the same default element in Babylon or in glTF. /// This function correct the node rotation. /// </summary> /// <param name="node"></param> /// <param name="babylonScene"></param> /// <param name="angle"></param> private void FixNodeRotation(ref BabylonNode node, ref BabylonScene babylonScene, double angle) { string id = node.id; IList <BabylonMesh> meshes = babylonScene.MeshesList.FindAll(mesh => mesh.parentId == null ? false : mesh.parentId.Equals(id)); RaiseMessage($"{node.name}", 2); // fix the vue // Rotation around the axis X of PI / 2 in the indirect direction for camera // double angle = Math.PI / 2; // for camera // double angle = -Math.PI / 2; // for light if (node.rotation != null) { node.rotation[0] += (float)angle; } if (node.rotationQuaternion != null) { BabylonQuaternion rotationQuaternion = FixCameraQuaternion(node, angle); node.rotationQuaternion = rotationQuaternion.ToArray(); node.rotation = rotationQuaternion.toEulerAngles().ToArray(); } // animation List <BabylonAnimation> animations = new List <BabylonAnimation>(node.animations); BabylonAnimation animationRotationQuaternion = animations.Find(animation => animation.property.Equals("rotationQuaternion")); if (animationRotationQuaternion != null) { foreach (BabylonAnimationKey key in animationRotationQuaternion.keys) { key.values = FixCameraQuaternion(key.values, angle); } } else // if the camera has a lockedTargetId, it is the extraAnimations that stores the rotation animation { if (node.extraAnimations != null) { List <BabylonAnimation> extraAnimations = new List <BabylonAnimation>(node.extraAnimations); animationRotationQuaternion = extraAnimations.Find(animation => animation.property.Equals("rotationQuaternion")); if (animationRotationQuaternion != null) { foreach (BabylonAnimationKey key in animationRotationQuaternion.keys) { key.values = FixCameraQuaternion(key.values, angle); } } } } // fix direct children // Rotation around the axis X of -PI / 2 in the direct direction for camera children angle = -angle; foreach (var mesh in meshes) { RaiseVerbose($"{mesh.name}", 3); mesh.position = new float[] { mesh.position[0], mesh.position[2], -mesh.position[1] }; // Add a rotation of PI/2 axis X in direct direction if (mesh.rotationQuaternion != null) { // Rotation around the axis X of -PI / 2 in the direct direction BabylonQuaternion quaternion = FixChildQuaternion(mesh, angle); mesh.rotationQuaternion = quaternion.ToArray(); } if (mesh.rotation != null) { mesh.rotation[0] += (float)angle; } // Animations animations = new List <BabylonAnimation>(mesh.animations); // Position BabylonAnimation animationPosition = animations.Find(animation => animation.property.Equals("position")); if (animationPosition != null) { foreach (BabylonAnimationKey key in animationPosition.keys) { key.values = new float[] { key.values[0], key.values[2], -key.values[1] }; } } // Rotation animationRotationQuaternion = animations.Find(animation => animation.property.Equals("rotationQuaternion")); if (animationRotationQuaternion != null) { foreach (BabylonAnimationKey key in animationRotationQuaternion.keys) { key.values = FixChildQuaternion(key.values, angle); } } } }