private void ExportAnimation(string property, List<BabylonAnimation> animations, Func<int, float[]> extractValueFunc, BabylonAnimation.DataType dataType) { const int ticks = 160; 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 (key == start || key == end || !(previous.IsEqualTo(current))) { keys.Add(new BabylonAnimationKey() { frame = key / ticks, values = current }); } previous = current; } if (keys.Count > 0) { var animationPresent = true; if (keys.Count == 2) { if (keys[0].values.IsEqualTo(keys[1].values)) { animationPresent = false; } } if (animationPresent) { var babylonAnimation = new BabylonAnimation { dataType = dataType, name = property + " animation", keys = keys.ToArray(), framePerSecond = Loader.Global.FrameRate, loopBehavior = BabylonAnimation.LoopBehavior.Relative, property = property }; animations.Add(babylonAnimation); } } }
public static float[] Interpolate(BabylonAnimation animation, BabylonAnimationKey fromKey, BabylonAnimationKey toKey, float frame) { switch (animation.property) { case "_matrix": var fromMatrix = new BabylonMatrix(); fromMatrix.m = new List <float>(fromKey.values).ToArray(); var toMatrix = new BabylonMatrix(); toMatrix.m = new List <float>(toKey.values).ToArray(); var fromPosition = new BabylonVector3(); var fromRotation = new BabylonQuaternion(); var fromScaling = new BabylonVector3(); var toPosition = new BabylonVector3(); var toRotation = new BabylonQuaternion(); var toScaling = new BabylonVector3(); fromMatrix.decompose(fromScaling, fromRotation, fromPosition); toMatrix.decompose(toScaling, toRotation, toPosition); var lerpFactor = MathUtilities.GetLerpFactor(fromKey.frame, toKey.frame, frame); var interpolatedKeyPosition = BabylonVector3.FromArray(MathUtilities.Lerp(fromPosition.ToArray(), toPosition.ToArray(), lerpFactor)); var interpolatedKeyRotation = BabylonQuaternion.Slerp(fromRotation, toRotation, lerpFactor); var interpolatedKeyScaling = BabylonVector3.FromArray(MathUtilities.Lerp(fromScaling.ToArray(), toScaling.ToArray(), lerpFactor)); return(BabylonMatrix.Compose(interpolatedKeyScaling, interpolatedKeyRotation, interpolatedKeyPosition).m); case "rotationQuaternion": return(BabylonQuaternion.Slerp(BabylonQuaternion.FromArray(fromKey.values), BabylonQuaternion.FromArray(toKey.values), MathUtilities.GetLerpFactor(fromKey.frame, toKey.frame, frame)).ToArray()); case "scaling": case "position": default: return(MathUtilities.Lerp(fromKey.values, toKey.values, MathUtilities.GetLerpFactor(fromKey.frame, toKey.frame, frame))); } }
private static void ExportAnimationClip(AnimationClip clip, bool autoPlay, BabylonIAnimatable animatable) { var curveBindings = AnimationUtility.GetCurveBindings(clip); var animations = new List<BabylonAnimation>(); var maxFrame = 0; foreach (var binding in curveBindings) { var curve = AnimationUtility.GetEditorCurve(clip, binding); string property; switch (binding.propertyName) { case "m_LocalPosition.x": property = "position.x"; break; case "m_LocalPosition.y": property = "position.y"; break; case "m_LocalPosition.z": property = "position.z"; break; case "m_LocalRotation.x": property = "rotationQuaternion.x"; break; case "m_LocalRotation.y": property = "rotationQuaternion.y"; break; case "m_LocalRotation.z": property = "rotationQuaternion.z"; break; case "m_LocalRotation.w": property = "rotationQuaternion.w"; break; case "m_LocalScale.x": property = "scaling.x"; break; case "m_LocalScale.y": property = "scaling.y"; break; case "m_LocalScale.z": property = "scaling.z"; break; default: continue; } var babylonAnimation = new BabylonAnimation { dataType = (int)BabylonAnimation.DataType.Float, name = property + " animation", keys = curve.keys.Select(keyFrame => new BabylonAnimationKey { frame = (int)(keyFrame.time * clip.frameRate), values = new[] { keyFrame.value } }).ToArray(), framePerSecond = (int)clip.frameRate, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, property = property }; maxFrame = Math.Max(babylonAnimation.keys.Last().frame, maxFrame); animations.Add(babylonAnimation); } if (animations.Count > 0) { animatable.animations = animations.ToArray(); if (autoPlay) { animatable.autoAnimate = true; animatable.autoAnimateFrom = 0; animatable.autoAnimateTo = maxFrame; animatable.autoAnimateLoop = clip.isLooping; } } }
private void ExportSkin(IIGameSkin skin, BabylonScene babylonScene) { var babylonSkeleton = new BabylonSkeleton { id = skins.IndexOf(skin) }; babylonSkeleton.name = "skeleton #" + babylonSkeleton.id; RaiseMessage(babylonSkeleton.name, 1); var skinIndex = skins.IndexOf(skin); var bones = new List<BabylonBone>(); var gameBones = new List<IIGameNode>(); var boneIds = new List<int>(); var bindPoseInfos = new List<BonePoseInfo>(); for(int i = 0; i < skin.TotalSkinBoneCount; ++i) { bones.Add(null); gameBones.Add(null); boneIds.Add(-1); bindPoseInfos.Add(null); } for (var index = 0; index < skin.TotalSkinBoneCount; index++) { var gameBone = skin.GetIGameBone(index, false); var sortedIndex = skinSortedBones[skin].IndexOf(gameBone.NodeID); gameBones[sortedIndex] = (gameBone); boneIds[sortedIndex] =(gameBone.NodeID); bones[sortedIndex]=(new BabylonBone { index = sortedIndex, name = gameBone.Name }); var boneInitMatrix = gameBone.GetObjectTM(0); bindPoseInfos[sortedIndex] = (new BonePoseInfo { AbsoluteTransform = boneInitMatrix }); } // fix hierarchy an generate animation keys var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations"); for (var index = 0; index < skin.TotalSkinBoneCount; index++) { var gameBone = gameBones[index]; var parent = gameBone.NodeParent; var babBone = bones[index]; if (parent != null) { babBone.parentBoneIndex = boneIds.IndexOf(parent.NodeID); } if (babBone.parentBoneIndex == -1) { bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform; } else { var parentBindPoseInfos = bindPoseInfos[babBone.parentBoneIndex]; bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(parentBindPoseInfos.AbsoluteTransform.Inverse); } babBone.matrix = bindPoseInfos[index].LocalTransform.ToArray(); var babylonAnimation = new BabylonAnimation { name = gameBone.Name + "Animation", property = "_matrix", dataType = (int)BabylonAnimation.DataType.Matrix, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, framePerSecond = Loader.Global.FrameRate }; var start = Loader.Core.AnimRange.Start; var end = Loader.Core.AnimRange.End; float[] previous = null; var keys = new List<BabylonAnimationKey>(); for (var key = start; key <= end; key += Ticks) { var objectTM = gameBone.GetObjectTM(key); var parentNode = gameBone.NodeParent; IGMatrix mat; if (parentNode == null || babBone.parentBoneIndex == -1) { mat = objectTM; } else { mat = objectTM.Multiply(parentNode.GetObjectTM(key).Inverse); } var current = mat.ToArray(); if (key == start || key == end || exportNonOptimizedAnimations || !(previous.IsEqualTo(current))) { keys.Add(new BabylonAnimationKey { frame = key / Ticks, values = current }); } previous = current; } babylonAnimation.keys = keys.ToArray(); babBone.animation = babylonAnimation; } babylonSkeleton.needInitialSkinMatrix = true; babylonSkeleton.bones = bones.ToArray(); babylonScene.SkeletonsList.Add(babylonSkeleton); }
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; }
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; } }
private void ExportSkin(IISkin skin, BabylonScene babylonScene) { var babylonSkeleton = new BabylonSkeleton {id = skins.IndexOf(skin)}; babylonSkeleton.name = "skeleton #" + babylonSkeleton.id; RaiseMessage(babylonSkeleton.name, 1); var bones = new List<BabylonBone>(); for (var index = 0; index < skin.NumBones; index++) { var bone = new BabylonBone {name = skin.GetBoneName(index), index = index}; var maxBone = skin.GetBone(index); var parentNode = maxBone.ParentNode; if (parentNode != null) { for (var recurseIndex = 0; recurseIndex < index; recurseIndex++) { if (skin.GetBone(recurseIndex).GetGuid() == parentNode.GetGuid()) { bone.parentBoneIndex = recurseIndex; break; } } } var hasParent = bone.parentBoneIndex != -1; bone.matrix = GetBoneMatrix(skin, maxBone, 0, hasParent); // Animation var babylonAnimation = new BabylonAnimation { name = bone.name + "Animation", property = "_matrix", dataType = BabylonAnimation.DataType.Matrix, loopBehavior = BabylonAnimation.LoopBehavior.Cycle, framePerSecond = Loader.Global.FrameRate }; var start = Loader.Core.AnimRange.Start; var end = Loader.Core.AnimRange.End; float[] previous = null; var keys = new List<BabylonAnimationKey>(); for (var key = start; key <= end; key += Ticks) { var current = GetBoneMatrix(skin, maxBone, key, hasParent); if (key == start || key == end || !(previous.IsEqualTo(current))) { keys.Add(new BabylonAnimationKey { frame = key / Ticks, values = current }); } previous = current; } babylonAnimation.keys = keys.ToArray(); bone.animation = babylonAnimation; bones.Add(bone); } babylonSkeleton.bones = bones.ToArray(); babylonScene.SkeletonsList.Add(babylonSkeleton); }