private BabylonNode BoneToNode(BabylonBone babylonBone) { BabylonNode babylonNode = new BabylonNode(); babylonNode.id = babylonBone.id; babylonNode.parentId = babylonBone.parentNodeId; babylonNode.name = babylonBone.name; babylonNode.animations = new[] { babylonBone.animation }; var tm_babylon = new BabylonMatrix(); tm_babylon.m = babylonBone.matrix.ToArray(); var s_babylon = new BabylonVector3(); var q_babylon = new BabylonQuaternion(); var t_babylon = new BabylonVector3(); tm_babylon.decompose(s_babylon, q_babylon, t_babylon); babylonNode.position = t_babylon.ToArray(); babylonNode.rotationQuaternion = q_babylon.ToArray(); babylonNode.scaling = s_babylon.ToArray(); return(babylonNode); }
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); }
/// <summary> /// Export the bones and their animation for the given skin /// </summary> /// <param name="skin">The skin to export</param> /// <returns></returns> private BabylonBone[] ExportBones(IIGameSkin skin) { List <BabylonBone> bones = new List <BabylonBone>(); List <int> nodeIndices = GetNodeIndices(skin); List <IIGameNode> revelantNodes = GetSkinnedBones(skin); foreach (IIGameNode node in revelantNodes) { int parentIndex = (node.NodeParent == null) ? -1 : nodeIndices.IndexOf(node.NodeParent.NodeID); string boneId = node.MaxNode.GetGuid().ToString(); // create the bone BabylonBone bone = new BabylonBone() { id = (isGltfExported)?boneId:boneId + "-bone",// the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs parentNodeId = (parentIndex != -1)?node.NodeParent.MaxNode.GetGuid().ToString():null, name = node.Name, index = nodeIndices.IndexOf(node.NodeID), parentBoneIndex = parentIndex, matrix = (parentIndex == -1)?node.GetWorldTM(0).ToArray():node.GetLocalTM(0).ToArray() }; // Apply unit conversion factor to meter // Affect translation only bone.matrix[12] *= scaleFactorToMeters; bone.matrix[13] *= scaleFactorToMeters; bone.matrix[14] *= scaleFactorToMeters; if (exportParameters.exportAnimations) { // export its animation var babylonAnimation = ExportMatrixAnimation("_matrix", key => { IGMatrix mat = node.GetLocalTM(key); float[] matrix = mat.ToArray(); // Apply unit conversion factor to meter // Affect translation only matrix[12] *= scaleFactorToMeters; matrix[13] *= scaleFactorToMeters; matrix[14] *= scaleFactorToMeters; return(matrix); }, false); // Do not remove linear animation keys for bones if (babylonAnimation != null) { babylonAnimation.name = node.Name + "Animation"; // override default animation name bone.animation = babylonAnimation; } } bones.Add(bone); } return(bones.ToArray()); }
/// <summary> /// Return the bones to export. /// </summary> /// <param name="skin">the skin to export</param> /// <returns>Array of BabylonBone to export</returns> private BabylonBone[] ExportBones(MFnSkinCluster skin) { int logRank = 1; int skinIndex = GetSkeletonIndex(skin); List <BabylonBone> bones = new List <BabylonBone>(); Dictionary <string, int> indexByFullPathName = GetIndexByFullPathNameDictionary(skin); List <MObject> revelantNodes = GetRevelantNodes(skin); progressBoneStep = progressSkinStep / revelantNodes.Count; foreach (MObject node in revelantNodes) { MFnDagNode dagNode = new MFnDagNode(node); MFnTransform currentNodeTransform = new MFnTransform(node); string currentFullPathName = dagNode.fullPathName; int index = indexByFullPathName[currentFullPathName]; int parentIndex = -1; string parentId = null; // find the parent node to get its index if (!dagNode.parent(0).hasFn(MFn.Type.kWorld)) { MFnTransform firstParentTransform = new MFnTransform(dagNode.parent(0)); parentId = firstParentTransform.uuid().asString(); parentIndex = indexByFullPathName[firstParentTransform.fullPathName]; } string boneId = currentNodeTransform.uuid().asString(); // create the bone BabylonBone bone = new BabylonBone() { id = (!isBabylonExported)?boneId:boneId + "-bone",// the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs parentNodeId = parentId, name = dagNode.name, index = indexByFullPathName[currentFullPathName], parentBoneIndex = parentIndex, matrix = GetBabylonMatrix(currentNodeTransform, frameBySkeletonID[skinIndex]).m, animation = GetAnimationsFrameByFrameMatrix(currentNodeTransform) }; bones.Add(bone); RaiseVerbose($"Bone: name={bone.name}, index={bone.index}, parentBoneIndex={bone.parentBoneIndex}, matrix={string.Join(" ", bone.matrix)}", logRank + 1); // Progress bar progressSkin += progressBoneStep; ReportProgressChanged(progressSkin); CheckCancelled(); } // sort List <BabylonBone> sorted = new List <BabylonBone>(); sorted = bones.OrderBy(bone => bone.index).ToList(); bones = sorted; RaiseMessage($"{bones.Count} bone(s) exported", logRank + 1); return(bones.ToArray()); }
private BabylonSkeleton ConvertUnitySkeletonToBabylon(Transform[] bones, Matrix4x4[] bindPoses, Transform transform, GameObject gameObject, float progress) { ExporterWindow.ReportProgress(progress, "Exporting Skeleton: " + gameObject.name); BabylonSkeleton babylonSkeleton = new BabylonSkeleton(); babylonSkeleton.name = gameObject.name; babylonSkeleton.id = Math.Abs(GetID(transform.gameObject).GetHashCode()); babylonSkeleton.needInitialSkinMatrix = false; // Prefilled to keep order and track parents. var transformToBoneMap = new Dictionary <Transform, BabylonBone>(); for (var i = 0; i < bones.Length; i++) { var unityBone = bones[i]; ExporterWindow.ReportProgress(progress, "Exporting bone: " + unityBone.name + " at index " + i); var babylonBone = new BabylonBone(); babylonBone.name = unityBone.name; babylonBone.index = i; transformToBoneMap.Add(unityBone, babylonBone); } // Attaches Matrix and parent. for (var i = 0; i < bones.Length; i++) { var unityBone = bones[i]; var babylonBone = transformToBoneMap[unityBone]; Matrix4x4 localTransform; // Unity BindPose is already inverse so take the inverse again :-) if (transformToBoneMap.ContainsKey(unityBone.parent)) { var babylonParentBone = transformToBoneMap[unityBone.parent]; babylonBone.parentBoneIndex = babylonParentBone.index; localTransform = bindPoses[babylonBone.parentBoneIndex] * bindPoses[i].inverse; } else { babylonBone.parentBoneIndex = -1; localTransform = bindPoses[i].inverse; } transformToBoneMap[unityBone].matrix = new[] { localTransform[0, 0], localTransform[1, 0], localTransform[2, 0], localTransform[3, 0], localTransform[0, 1], localTransform[1, 1], localTransform[2, 1], localTransform[3, 1], localTransform[0, 2], localTransform[1, 2], localTransform[2, 2], localTransform[3, 2], localTransform[0, 3], localTransform[1, 3], localTransform[2, 3], localTransform[3, 3] }; } // Reorder and attach the skeleton. babylonSkeleton.bones = transformToBoneMap.Values.OrderBy(b => b.index).ToArray(); babylonScene.SkeletonsList.Add(babylonSkeleton); return(babylonSkeleton); }
private GLTFNode _exportBone(BabylonBone babylonBone, GLTF gltf, BabylonSkeleton babylonSkeleton, List <BabylonBone> bones) { if (alreadyExportedBones.ContainsKey(babylonBone)) { return(alreadyExportedBones[babylonBone]); } // Node var gltfNode = new GLTFNode { name = babylonBone.name }; gltfNode.index = gltf.NodesList.Count; gltf.NodesList.Add(gltfNode); alreadyExportedBones.Add(babylonBone, gltfNode); boneToGltfNodeMap.Add(babylonBone, gltfNode); // Hierarchy if (babylonBone.parentBoneIndex >= 0) { var babylonParentBone = bones.Find(_babylonBone => _babylonBone.index == babylonBone.parentBoneIndex); var gltfParentNode = _exportBone(babylonParentBone, gltf, babylonSkeleton, bones); RaiseMessage("GLTFExporter.Skin | Add " + babylonBone.name + " as child to " + gltfParentNode.name, 3); gltfParentNode.ChildrenList.Add(gltfNode.index); gltfNode.parent = gltfParentNode; } else { // It's a root node // Only root nodes are listed in a gltf scene RaiseMessage("GLTFExporter.Skin | Add " + babylonBone.name + " as root node to scene", 3); gltf.scenes[0].NodesList.Add(gltfNode.index); } // Transform // Bones transform are exported through translation/rotation/scale (TRS) rather than matrix // Because gltf node animation can only target TRS properties, not the matrix one // Create matrix from array var babylonMatrix = new BabylonMatrix(); babylonMatrix.m = babylonBone.matrix; // Decompose matrix into TRS var translationBabylon = new BabylonVector3(); var rotationQuatBabylon = new BabylonQuaternion(); var scaleBabylon = new BabylonVector3(); babylonMatrix.decompose(scaleBabylon, rotationQuatBabylon, translationBabylon); // Store TRS values gltfNode.translation = translationBabylon.ToArray(); gltfNode.rotation = rotationQuatBabylon.ToArray(); gltfNode.scale = scaleBabylon.ToArray(); // Animations //ExportBoneAnimation(babylonBone, gltf, gltfNode); return(gltfNode); }
/// <summary> /// Return the bones to export. /// </summary> /// <param name="skin">the skin to export</param> /// <returns>Array of BabylonBone to export</returns> private BabylonBone[] ExportBones(MFnSkinCluster skin) { int logRank = 1; int skinIndex = GetSkeletonIndex(skin); List <BabylonBone> bones = new List <BabylonBone>(); Dictionary <string, int> indexByFullPathName = GetIndexByFullPathNameDictionary(skin); List <MObject> revelantNodes = GetRevelantNodes(skin); progressBoneStep = progressSkinStep / revelantNodes.Count; foreach (MObject node in revelantNodes) { MFnDagNode dagNode = new MFnDagNode(node); MFnTransform currentNodeTransform = new MFnTransform(node); string currentFullPathName = dagNode.fullPathName; int index = indexByFullPathName[currentFullPathName]; int parentIndex = -1; // find the parent node to get its index if (!dagNode.parent(0).hasFn(MFn.Type.kWorld)) { MFnTransform firstParentTransform = new MFnTransform(dagNode.parent(0)); parentIndex = indexByFullPathName[firstParentTransform.fullPathName]; } // create the bone BabylonBone bone = new BabylonBone() { name = currentFullPathName, index = indexByFullPathName[currentFullPathName], parentBoneIndex = parentIndex, matrix = ConvertMayaToBabylonMatrix(currentNodeTransform.transformationMatrix).m.ToArray(), animation = GetAnimationsFrameByFrameMatrix(currentNodeTransform) }; bones.Add(bone); RaiseMessage($"Bone: name={bone.name}, index={bone.index}, parentBoneIndex={bone.parentBoneIndex}, matrix={string.Join(" ", bone.matrix)}", logRank + 1); // Progress bar progressSkin += progressBoneStep; ReportProgressChanged(progressSkin); CheckCancelled(); } // sort List <BabylonBone> sorted = new List <BabylonBone>(); sorted = bones.OrderBy(bone => bone.index).ToList(); bones = sorted; RaiseMessage($"{bones.Count} bone(s) exported", logRank + 1); return(bones.ToArray()); }
/// <summary> /// Export the bones and their animation for the given skin /// </summary> /// <param name="skin">The skin to export</param> /// <returns></returns> private BabylonBone[] ExportBones(IIGameSkin skin, IIGameNode meshNode) { List <BabylonBone> bones = new List <BabylonBone>(); List <int> nodeIndices = GetNodeIndices(skin, meshNode); List <IIGameNode> revelantNodes = GetSkinnedBones(skin, meshNode); foreach (IIGameNode node in revelantNodes) { int parentIndex = (node.NodeParent == null) ? -1 : nodeIndices.IndexOf(node.NodeParent.NodeID); string boneId = node.MaxNode.GetGuid().ToString(); string animationTargetID = node.MaxNode.GetUniqueID(); // create the bone BabylonBone bone = new BabylonBone() { id = (isGltfExported)?boneId:boneId + "-bone",// the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs AnimationTargetId = animationTargetID, parentNodeId = (parentIndex != -1)?node.NodeParent.MaxNode.GetGuid().ToString():null, name = node.Name, index = nodeIndices.IndexOf(node.NodeID), parentBoneIndex = parentIndex, matrix = (parentIndex == -1)?node.GetWorldTM(0).ToArray():node.GetLocalTM(0).ToArray() }; // export its animation var babylonAnimation = ExportMatrixAnimation("_matrix", key => { var objectTM = node.GetObjectTM(key); var parentNode = node.NodeParent; IGMatrix mat; if (parentNode == null || bone.parentBoneIndex == -1) { mat = objectTM; } else { mat = node.GetLocalTM(key); } return(mat.ToArray()); }, false, true, node.Name); // Do not remove linear animation keys for bones; Always optimize animations if (babylonAnimation != null) { babylonAnimation.name = node.Name + "Animation"; // override default animation name bone.animation = babylonAnimation; } bones.Add(bone); } return(bones.ToArray()); }
/// <summary> /// Export the bones and their animation for the given skin /// </summary> /// <param name="skin">The skin to export</param> /// <returns></returns> private BabylonBone[] ExportBones(IIGameSkin skin) { List <BabylonBone> bones = new List <BabylonBone>(); List <int> nodeIndices = GetNodeIndices(skin); List <IIGameNode> revelantNodes = GetRevelantNodes(skin); foreach (IIGameNode node in revelantNodes) { int parentIndex = (node.NodeParent == null) ? -1 : nodeIndices.IndexOf(node.NodeParent.NodeID); // create the bone BabylonBone bone = new BabylonBone() { id = node.MaxNode.GetGuid().ToString(), name = node.Name, index = nodeIndices.IndexOf(node.NodeID), parentBoneIndex = parentIndex, matrix = node.GetLocalTM(0).ToArray() }; // export its animation var babylonAnimation = ExportMatrixAnimation("_matrix", key => { var objectTM = node.GetObjectTM(key); var parentNode = node.NodeParent; IGMatrix mat; if (parentNode == null || bone.parentBoneIndex == -1) { mat = objectTM; } else { mat = objectTM.Multiply(parentNode.GetObjectTM(key).Inverse); } return(mat.ToArray()); }, false); // Do not remove linear animation keys for bones if (babylonAnimation != null) { babylonAnimation.name = node.Name + "Animation"; // override default animation name bone.animation = babylonAnimation; } bones.Add(bone); } return(bones.ToArray()); }
private BabylonMatrix _getBoneWorldMatrix(BabylonBone babylonBone, List <BabylonBone> bones) { var boneLocalMatrix = new BabylonMatrix(); boneLocalMatrix.m = babylonBone.matrix; if (babylonBone.parentBoneIndex == -1) { return(boneLocalMatrix); } else { var parentBabylonBone = bones.Find(bone => bone.index == babylonBone.parentBoneIndex); var parentWorldMatrix = _getBoneWorldMatrix(parentBabylonBone, bones); return(boneLocalMatrix * parentWorldMatrix); } }
private void ParseBones(SkinningData skinningData, BabylonSkeleton skeleton) { // Bones var bones = new List <BabylonBone>(); for (int boneIndex = 0; boneIndex < skinningData.BindPose.Count; boneIndex++) { var newBone = new BabylonBone(); bones.Add(newBone); newBone.name = "bone" + boneIndex; newBone.index = boneIndex; newBone.matrix = skinningData.BindPose[boneIndex].ToMatrix().ToArray(); newBone.parentBoneIndex = skinningData.SkeletonHierarchy[boneIndex]; } skeleton.bones = bones.ToArray(); }
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 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.FindAll(k => from <= k.frame && k.frame <= to); bool keysInRangeAreRelevant = true; // Optimize these keys if (exportParameters.optimizeAnimations) { // Optimize these keys OptimizeAnimations(keys, false); 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 void ParseBones(SkinningData skinningData, BabylonSkeleton skeleton) { // Bones var bones = new List<BabylonBone>(); for (int boneIndex = 0; boneIndex < skinningData.BindPose.Count; boneIndex++) { var newBone = new BabylonBone(); bones.Add(newBone); newBone.name = "bone" + boneIndex; newBone.index = boneIndex; newBone.matrix = skinningData.BindPose[boneIndex].ToMatrix().ToArray(); newBone.parentBoneIndex = skinningData.SkeletonHierarchy[boneIndex]; } skeleton.bones = bones.ToArray(); }
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); }
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); }
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); } } }
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); } } }
private IList <BabylonAnimationGroup> ExportAnimationGroups(BabylonScene babylonScene) { IList <BabylonAnimationGroup> animationGroups = new List <BabylonAnimationGroup>(); // Retrieve and parse animation group data AnimationGroupList animationList = InitAnimationGroups(); foreach (AnimationGroup animGroup in animationList) { RaiseMessage("Exporter.animationGroups | " + animGroup.Name, 1); BabylonAnimationGroup animationGroup = new BabylonAnimationGroup { name = animGroup.Name, from = animGroup.FrameStart, to = animGroup.FrameEnd, targetedAnimations = new List <BabylonTargetedAnimation>() }; // add animations of each nodes contained in the animGroup foreach (uint nodeHandle in animGroup.NodeHandles) { IINode maxNode = Loader.Core.RootNode.FindChildNode(nodeHandle); // node could have been deleted, silently ignore it if (maxNode == null) { continue; } // Helpers can be exported as dummies and as bones string nodeId = maxNode.GetGuid().ToString(); string boneId = maxNode.GetGuid().ToString() + "-bone"; // the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs // Node BabylonNode node = babylonScene.MeshesList.FirstOrDefault(m => m.id == nodeId); if (node == null) { node = babylonScene.CamerasList.FirstOrDefault(c => c.id == nodeId); } if (node == null) { node = babylonScene.LightsList.FirstOrDefault(l => l.id == nodeId); } if (node != null) { if (node.animations != null && node.animations.Length != 0) { IList <BabylonAnimation> animations = GetSubAnimations(node, animationGroup.from, animationGroup.to); foreach (BabylonAnimation animation in animations) { BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation { animation = animation, targetId = nodeId }; animationGroup.targetedAnimations.Add(targetedAnimation); } } else if (exportNonAnimated) { BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation { animation = CreatePositionAnimation(animationGroup.from, animationGroup.to, node.position), targetId = node.id }; animationGroup.targetedAnimations.Add(targetedAnimation); } } // bone BabylonBone bone = null; int index = 0; while (index < babylonScene.SkeletonsList.Count && bone == null) { BabylonSkeleton skel = babylonScene.SkeletonsList[index]; bone = skel.bones.FirstOrDefault(b => b.id == boneId); index++; } if (bone != null) { if (bone.animation != null) { IList <BabylonAnimation> animations = GetSubAnimations(bone, animationGroup.from, animationGroup.to); foreach (BabylonAnimation animation in animations) { BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation { animation = animation, targetId = boneId }; animationGroup.targetedAnimations.Add(targetedAnimation); } } else if (exportNonAnimated) { BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation { animation = CreateMatrixAnimation(animationGroup.from, animationGroup.to, bone.matrix), targetId = bone.id }; animationGroup.targetedAnimations.Add(targetedAnimation); } } } if (animationGroup.targetedAnimations.Count > 0) { animationGroups.Add(animationGroup); } } return(animationGroups); }
private IList <BabylonAnimationGroup> ExportAnimationGroups(BabylonScene babylonScene) { IList <BabylonAnimationGroup> animationGroups = new List <BabylonAnimationGroup>(); // Retrieve and parse animation group data AnimationGroupList animationList = AnimationGroupList.InitAnimationGroups(logger); foreach (AnimationGroup animGroup in animationList) { logger?.RaiseMessage("Exporter.animationGroups | " + animGroup.Name, 1); BabylonAnimationGroup animationGroup = new BabylonAnimationGroup { name = animGroup.Name, from = animGroup.FrameStart, to = animGroup.FrameEnd, keepNonAnimated = animGroup.KeepNonAnimated, targetedAnimations = new List <BabylonTargetedAnimation>() }; // add animations of each nodes contained in the animGroup foreach (Guid guid in animGroup.NodeGuids) { IINode maxNode = Tools.GetINodeByGuid(guid); // node could have been deleted, silently ignore it if (maxNode == null) { continue; } if (exportParameters.exportAsSubmodel && !maxNode.Selected) { continue; } // Helpers can be exported as dummies and as bones string nodeId = maxNode.GetGuid().ToString(); string boneId = isGltfExported?maxNode.GetGuid().ToString(): maxNode.GetGuid().ToString() + "-bone"; // the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs // Node BabylonNode node = null; babylonScene.NodeMap.TryGetValue(nodeId, out node); if (node != null) { if (node.animations != null && node.animations.Length != 0) { IList <BabylonAnimation> animations = GetSubAnimations(node, animationGroup.from, animationGroup.to); if (!animGroup.KeepStaticAnimation) { RemoveStaticAnimations(ref animations); } foreach (BabylonAnimation animation in animations) { BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation { animation = animation, targetId = nodeId }; animationGroup.targetedAnimations.Add(targetedAnimation); } } } // bone BabylonBone bone = null; int index = 0; while (index < babylonScene.SkeletonsList.Count && bone == null) { BabylonSkeleton skel = babylonScene.SkeletonsList[index]; bone = skel.bones.FirstOrDefault(b => b.id == boneId); index++; } if (bone != null) { if (bone.animation != null) { IList <BabylonAnimation> animations = GetSubAnimations(bone, animationGroup.from, animationGroup.to); foreach (BabylonAnimation animation in animations) { BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation { animation = animation, targetId = boneId }; animationGroup.targetedAnimations.Add(targetedAnimation); } } } } // add animations of each nodes contained in the animGroup foreach (Guid guid in animGroup.MaterialGuids) { IMtl maxMtl = Tools.GetIMtlByGuid(guid); // mat could have been deleted, silently ignore it if (maxMtl == null) { continue; } string matId = maxMtl.GetGuid().ToString(); // Material BabylonMaterial material = null; material = babylonScene.MaterialsList.FirstOrDefault(x => x.id == matId); if (material != null) { if (material.animations != null && material.animations.Length != 0) { IList <BabylonAnimation> animations = GetSubAnimations(material, animationGroup.from, animationGroup.to); foreach (BabylonAnimation animation in animations) { BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation { animation = animation, targetId = matId }; animationGroup.targetedAnimations.Add(targetedAnimation); } } } } if (animationGroup.targetedAnimations.Count > 0) { animationGroups.Add(animationGroup); } } return(animationGroups); }