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