public static int CalculateEndFrameFromAnimationGroupNodes(AnimationGroup animationGroup) { int endFrame = 0; foreach (Guid nodeGuid in animationGroup.NodeGuids) { IINode node = Tools.GetINodeByGuid(nodeGuid); if (node.IsAnimated && node.TMController != null) { int lastKey = 0; if (node.TMController.PositionController != null) { int posKeys = node.TMController.PositionController.NumKeys; lastKey = Math.Max(lastKey, node.TMController.PositionController.GetKeyTime(posKeys - 1)); } if (node.TMController.RotationController != null) { int rotKeys = node.TMController.RotationController.NumKeys; lastKey = Math.Max(lastKey, node.TMController.RotationController.GetKeyTime(rotKeys - 1)); } if (node.TMController.ScaleController != null) { int scaleKeys = node.TMController.ScaleController.NumKeys; lastKey = Math.Max(lastKey, node.TMController.ScaleController.GetKeyTime(scaleKeys - 1)); } decimal keyTime = Decimal.Ceiling(lastKey / 160); endFrame = Math.Max(endFrame, Decimal.ToInt32(keyTime)); } } return((endFrame != 0)? endFrame : animationGroup.FrameEnd); }
public void AutoAssignLodInAnimationGroup() { AnimationGroupList animationGroupList = new AnimationGroupList(); animationGroupList.LoadFromData(); var nodes = Loader.Core.RootNode.NodeTree(); List <IINode> nodeToAdd = new List <IINode>(); foreach (AnimationGroup anim in animationGroupList) { nodeToAdd.Clear(); foreach (Guid guid in anim.NodeGuids) { IINode n = Tools.GetINodeByGuid(guid); if (n == null) { continue; } if (!Regex.IsMatch(n.Name, "(?i)x[0-9]_")) { continue; } string noLodName = n.Name.Substring(3); foreach (IINode node in nodes) { if (Regex.IsMatch(node.Name, $"(?i)x[0-9]_{noLodName}$")) { nodeToAdd.Add(node); } } } foreach (IINode n in nodeToAdd) { List <Guid> newGuids = anim.NodeGuids.ToList(); newGuids.Add(n.GetGuid()); anim.NodeGuids = newGuids; } anim.SaveToData(); } }
public void LoadFromData(string propertyName, IINode dataNode) { if (!Guid.TryParse(propertyName, out serializedId)) { throw new Exception("Invalid ID, can't deserialize."); } string propertiesString = string.Empty; if (!dataNode.GetUserPropString(propertyName, ref propertiesString)) { return; } string[] properties = propertiesString.Split(s_PropertySeparator); if (properties.Length < 4) { throw new Exception("Invalid number of properties, can't deserialize."); } // set dirty explicitly just before we start loading, set to false when loading is done // if any exception is thrown, it will have a correct value IsDirty = true; name = properties[0]; if (!int.TryParse(properties[1], out ticksStart)) { throw new Exception("Failed to parse FrameStart property."); } if (!int.TryParse(properties[2], out ticksEnd)) { throw new Exception("Failed to parse FrameEnd property."); } if (string.IsNullOrEmpty(properties[3])) { return; } int numNodeIDs = properties.Length - 3; if (nodeGuids.Capacity < numNodeIDs) { nodeGuids.Capacity = numNodeIDs; } int numFailed = 0; for (int i = 0; i < numNodeIDs; ++i) { Guid guid; if (!Guid.TryParse(properties[3 + i], out guid)) { uint id; if (!uint.TryParse(properties[3 + i], out id)) { ++numFailed; continue; } //node is serialized in the old way ,force the reassignation of a new Guid on IINode node = Loader.Core.GetINodeByHandle(id); if (node != null) { guid = node.GetGuid(); } } nodeGuids.Add(guid); } AnimationGroupNodes = new List <AnimationGroupNode>(); foreach (Guid nodeGuid in nodeGuids) { IINode node = Tools.GetINodeByGuid(nodeGuid); if (node != null) { string name = node.Name; string parentName = node.ParentNode.Name; AnimationGroupNode nodeData = new AnimationGroupNode(nodeGuid, name, parentName); AnimationGroupNodes.Add(nodeData); } } if (numFailed > 0) { throw new Exception(string.Format("Failed to parse {0} node ids.", numFailed)); } IsDirty = false; }
private IList <BabylonAnimationGroup> ExportAnimationGroups(BabylonScene babylonScene) { IList <BabylonAnimationGroup> animationGroups = new List <BabylonAnimationGroup>(); // Retrieve and parse animation group data AnimationGroupList animationList = AnimationGroupList.InitAnimationGroups(this); 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 (Guid guid in animGroup.NodeGuids) { IINode maxNode = Tools.GetINodeByGuid(guid); // node could have been deleted, silently ignore it if (maxNode == null) { continue; } // Helpers can be exported as dummies and as bones string nodeId = guid.ToString(); string boneId = guid.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); 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); }
public static AnimationGroupList InitAnimationGroups(ILoggingProvider logger) { AnimationGroupList animationList = new AnimationGroupList(); animationList.LoadFromData(Loader.Core.RootNode); if (animationList.Count > 0) { int timelineStart = Loader.Core.AnimRange.Start / Loader.Global.TicksPerFrame; int timelineEnd = Loader.Core.AnimRange.End / Loader.Global.TicksPerFrame; List <string> warnings = new List <string>(); foreach (AnimationGroup animGroup in animationList) { // ensure min <= start <= end <= max warnings.Clear(); if (animGroup.FrameStart < timelineStart || animGroup.FrameStart > timelineEnd) { warnings.Add("Start frame '" + animGroup.FrameStart + "' outside of timeline range [" + timelineStart + ", " + timelineEnd + "]. Set to timeline start time '" + timelineStart + "'"); animGroup.FrameStart = timelineStart; } if (animGroup.FrameEnd < timelineStart || animGroup.FrameEnd > timelineEnd) { warnings.Add("End frame '" + animGroup.FrameEnd + "' outside of timeline range [" + timelineStart + ", " + timelineEnd + "]. Set to timeline end time '" + timelineEnd + "'"); animGroup.FrameEnd = timelineEnd; } if (animGroup.FrameEnd <= animGroup.FrameStart) { if (animGroup.FrameEnd < animGroup.FrameStart) { // Strict warnings.Add("End frame '" + animGroup.FrameEnd + "' lower than Start frame '" + animGroup.FrameStart + "'. Start frame set to timeline start time '" + timelineStart + "'. End frame set to timeline end time '" + timelineEnd + "'."); } else { // Equal warnings.Add("End frame '" + animGroup.FrameEnd + "' equal to Start frame '" + animGroup.FrameStart + "'. Single frame animation are not allowed. Start frame set to timeline start time '" + timelineStart + "'. End frame set to timeline end time '" + timelineEnd + "'."); } animGroup.FrameStart = timelineStart; animGroup.FrameEnd = timelineEnd; } foreach (Guid guid in animGroup.NodeGuids) { IINode node = Tools.GetINodeByGuid(guid); if (node != null) { if (!(node.TMController.IsKeyAtTime(animGroup.TicksStart, (1 << 0)) || node.TMController.IsKeyAtTime(animGroup.TicksStart, (1 << 1)) || node.TMController.IsKeyAtTime(animGroup.TicksStart, (1 << 2)))) { int key = animGroup.TicksStart / 160; string msg = string.Format("Node {0} has no key on min frame: {1} of animation group {2}", node.NodeName, key, animGroup.Name); warnings.Add(msg); } if (!(node.TMController.IsKeyAtTime(animGroup.TicksEnd, (1 << 0)) || node.TMController.IsKeyAtTime(animGroup.TicksEnd, (1 << 1)) || node.TMController.IsKeyAtTime(animGroup.TicksEnd, (1 << 2)))) { int key = animGroup.TicksEnd / 160; string msg = string.Format("Node {0} has no key on max frame: {1} of animation group {2}", node.NodeName, key, animGroup.Name); warnings.Add(msg); } } } // Print animation group warnings if any // Nothing printed otherwise if (warnings.Count > 0) { logger.RaiseWarning(animGroup.Name, 1); foreach (string warning in warnings) { logger.RaiseWarning(warning, 2); } } } } return(animationList); }
public void LoadFromData(string propertyName, IINode dataNode, Dictionary <string, string> rootNodePropDictionary = null) { if (!Guid.TryParse(propertyName, out serializedId)) { throw new Exception("Invalid ID, can't deserialize."); } string propertiesString = string.Empty; if (rootNodePropDictionary == null) { if (!dataNode.GetUserPropString(propertyName, ref propertiesString)) { return; } } else { if (!rootNodePropDictionary.TryGetValue(propertyName, out propertiesString)) { return; } } int numFailed = 0; try // Try using the new way, if it's not working use the old way. { SerializableAnimationGroup serialAnimGroup = new SerializableAnimationGroup(propertiesString); serialAnimGroup.FillSerializedData(this); } catch { int indexOfguidPart = propertiesString .Select((c, i) => new { c, i }) .Where(x => x.c == s_PropertySeparator) .Skip(2) .FirstOrDefault().i; string[] baseProperties = propertiesString.Substring(0, indexOfguidPart)?.Split(s_PropertySeparator); string guidPart = propertiesString.Substring(indexOfguidPart + 1); if (baseProperties.Length != 3) { throw new Exception("Invalid number of properties, can't deserialize."); } // set dirty explicitly just before we start loading, set to false when loading is done // if any exception is thrown, it will have a correct value IsDirty = true; name = baseProperties[0]; if (!int.TryParse(baseProperties[1], out ticksStart)) { throw new Exception("Failed to parse FrameStart property."); } if (!int.TryParse(baseProperties[2], out ticksEnd)) { throw new Exception("Failed to parse FrameEnd property."); } if (string.IsNullOrEmpty(guidPart) || guidPart == s_GUIDTypeSeparator.ToString()) { return; } if (!guidPart.Contains(s_GUIDTypeSeparator)) { // to grant retro-compatiblity numFailed = ParseOldProperties(guidPart); } else { //new format with nodes and node materials guid numFailed = ParseNewProperties(guidPart); } } AnimationGroupNodes = new List <AnimationGroupNode>(); foreach (Guid nodeGuid in nodeGuids) { IINode node = Tools.GetINodeByGuid(nodeGuid); if (node != null) { string name = node.Name; string parentName = node.ParentNode.Name; AnimationGroupNode nodeData = new AnimationGroupNode(nodeGuid, name, parentName); AnimationGroupNodes.Add(nodeData); } } AnimationGroupMaterials = new List <AnimationGroupMaterial>(); foreach (Guid materialGUID in materialsGuids) { IMtl mat = Tools.GetIMtlByGuid(materialGUID); if (mat != null) { string name = mat.Name; AnimationGroupMaterial matData = new AnimationGroupMaterial(materialGUID, name); AnimationGroupMaterials.Add(matData); } } if (numFailed > 0) { throw new Exception(string.Format("Failed to parse {0} node ids.", numFailed)); } IsDirty = false; }
public void LoadFromData(string propertyName) { if (!propertyName.StartsWith(s_PropertyNamePrefix)) { throw new Exception("Invalid property name, can't deserialize."); } string itemGuidStr = propertyName.Remove(0, s_PropertyNamePrefix.Length); if (!Guid.TryParse(itemGuidStr, out itemGuid)) { Loader.Core.PushPrompt("Error: Invalid ID, can't deserialize."); return; } IINode iNode = Tools.GetINodeByGuid(itemGuid); if (iNode == null) { iNode = Loader.Core.RootNode; } // set dirty explicitly just before we start loading, set to false when loading is done // if any exception is thrown, it will have a correct value IsDirty = true; NodeHandle = iNode.Handle; string propertiesString = string.Empty; if (!iNode.GetUserPropString(propertyName, ref propertiesString)) { return; // node has no properties yet } string[] properties = propertiesString.Split(s_PropertySeparator); if (properties.Length < 2) { throw new Exception("Invalid number of properties, can't deserialize."); } if (!bool.TryParse(properties[0], out selected)) { throw new Exception(string.Format("Failed to parse selected property from string {0}", properties[0])); } SetExportFilePath(properties[1]); SetExportTexturesFolderPath(properties[2]); List <IILayer> layers = StringToLayers(properties[3]); if (layers.Count > 0) { SetExportLayers(layers); } IsDirty = false; }
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); }