public static void SaveToCollada(RwAnimationNode animation, RwFrameListNode frameList, string path) { var aiScene = ToAssimpScene(animation, frameList); using (var aiContext = new Assimp.AssimpContext()) { if (!aiContext.ExportFile(aiScene, path, "collada")) { throw new Exception("Failed to export"); } } }
public static RwAnimationNode FromAssimpScene(RwNode parent, RwFrameListNode frameList, string path) { var aiContext = new Assimp.AssimpContext(); var aiScene = aiContext.ImportFile(path); var aiAnimation = aiScene.Animations.FirstOrDefault(); RwAnimationNode animationNode; if (aiAnimation != null) { animationNode = new RwAnimationNode(parent, RwKeyFrameType.Uncompressed, ( float )(aiAnimation.DurationInTicks / aiAnimation.TicksPerSecond)); var nodeNameToHAnimId = aiAnimation.NodeAnimationChannels.ToDictionary(x => x.NodeName, x => frameList.GetNameIdByName(x.NodeName)); var nodeKeyframeTimes = aiAnimation.NodeAnimationChannels.SelectMany(x => x.PositionKeys) .Select(x => x.Time) .Concat(aiAnimation.NodeAnimationChannels.SelectMany(x => x.RotationKeys.Select(y => y.Time))) .Distinct() .OrderBy(x => x) .ToList(); var previousKeyFrames = new Dictionary <int, RwKeyFrame>(); var nodeKeyFrames = new Dictionary <int, List <RwKeyFrame> >(); // Add initial pose foreach (var hierarchyNode in frameList.AnimationRootNode.HAnimFrameExtensionNode.Hierarchy.Nodes) { var frame = frameList[frameList.GetFrameIndexByNameId(hierarchyNode.NodeId)]; var firstRotation = Quaternion.CreateFromRotationMatrix(frame.Transform); var firstTranslation = frame.Transform.Translation; var channel = aiAnimation.NodeAnimationChannels.FirstOrDefault(x => nodeNameToHAnimId[x.NodeName] == hierarchyNode.NodeId); if (channel != null) { if (channel.HasRotationKeys) { firstRotation = ToQuaternion(channel.RotationKeys.First().Value); } if (channel.HasPositionKeys) { firstTranslation = ToVector3(channel.PositionKeys.First().Value); } } var keyFrame = new RwKeyFrame(0, firstRotation, firstTranslation, null); animationNode.KeyFrames.Add(keyFrame); previousKeyFrames[hierarchyNode.NodeId] = keyFrame; nodeKeyFrames[hierarchyNode.NodeId] = new List <RwKeyFrame>(); } foreach (var keyFrameTime in nodeKeyframeTimes) { if (keyFrameTime == 0.0f) { continue; } foreach (var channel in aiAnimation.NodeAnimationChannels) { if (!channel.HasPositionKeys && !channel.HasRotationKeys) { continue; } if (!channel.RotationKeys.Any(x => x.Time == keyFrameTime) || !channel.PositionKeys.Any(x => x.Time == keyFrameTime)) { continue; } var hierarchAnimNodeId = nodeNameToHAnimId[channel.NodeName]; var previousKeyFrame = previousKeyFrames[hierarchAnimNodeId]; var rotation = previousKeyFrame.Rotation; var translation = previousKeyFrame.Translation; var rotationKeys = channel.RotationKeys.Where(x => x.Time == keyFrameTime); if (rotationKeys.Any()) { var aiRotation = rotationKeys.First().Value; rotation = new Quaternion(aiRotation.X, aiRotation.Y, aiRotation.Z, aiRotation.W); } var translationKeys = channel.PositionKeys.Where(x => x.Time == keyFrameTime); if (translationKeys.Any()) { var aiTranslation = translationKeys.First().Value; translation = new Vector3(aiTranslation.X, aiTranslation.Y, aiTranslation.Z); } var keyFrame = new RwKeyFrame(( float )(keyFrameTime / aiAnimation.TicksPerSecond), rotation, translation, previousKeyFrame); nodeKeyFrames[hierarchAnimNodeId].Add(keyFrame); previousKeyFrames[hierarchAnimNodeId] = keyFrame; } } while (!nodeKeyFrames.All(x => x.Value.Count == 0)) { foreach (var kvp in nodeKeyFrames) { if (animationNode.KeyFrames.Count == 0) { continue; } var keyFrame = kvp.Value.First(); animationNode.KeyFrames.Add(keyFrame); kvp.Value.Remove(keyFrame); if (animationNode.KeyFrames.Count == 0) { var previousKeyFrame = previousKeyFrames[kvp.Key]; if (previousKeyFrame.Time != animationNode.Duration) { var lastRotation = previousKeyFrame.Rotation; var lastTranslation = previousKeyFrame.Translation; var channel = aiAnimation.NodeAnimationChannels.SingleOrDefault(x => nodeNameToHAnimId[x.NodeName] == kvp.Key); if (channel != null) { if (channel.HasRotationKeys) { lastRotation = ToQuaternion(channel.RotationKeys.Last().Value); } if (channel.HasPositionKeys) { lastTranslation = ToVector3(channel.PositionKeys.Last().Value); } } animationNode.KeyFrames.Add(new RwKeyFrame(animationNode.Duration, lastRotation, lastTranslation, previousKeyFrame)); } } } } } else { animationNode = new RwAnimationNode(null, RwKeyFrameType.Uncompressed, 0f); } return(animationNode); }
public static Assimp.Scene ToAssimpScene(RwAnimationNode animation, RwFrameListNode frameList) { var aiScene = new Assimp.Scene(); // RootNode var rootFrame = frameList[0]; var aiRootNode = new Assimp.Node("RootNode", null); aiRootNode.Transform = new Assimp.Matrix4x4(rootFrame.Transform.M11, rootFrame.Transform.M21, rootFrame.Transform.M31, rootFrame.Transform.M41, rootFrame.Transform.M12, rootFrame.Transform.M22, rootFrame.Transform.M32, rootFrame.Transform.M42, rootFrame.Transform.M13, rootFrame.Transform.M23, rootFrame.Transform.M33, rootFrame.Transform.M43, rootFrame.Transform.M14, rootFrame.Transform.M24, rootFrame.Transform.M34, rootFrame.Transform.M44); aiScene.RootNode = aiRootNode; for (int i = 1; i < frameList.Count; i++) { var frame = frameList[i]; var frameName = "_" + frame.HAnimFrameExtensionNode.NameId; Assimp.Node aiParentNode = null; if (frame.Parent != null) { string parentName = "RootNode"; if (frame.Parent.HasHAnimExtension) { parentName = "_" + frame.Parent.HAnimFrameExtensionNode.NameId; } aiParentNode = aiRootNode.FindNode(parentName); } var aiNode = new Assimp.Node(frameName, aiParentNode); aiNode.Transform = new Assimp.Matrix4x4(frame.Transform.M11, frame.Transform.M21, frame.Transform.M31, frame.Transform.M41, frame.Transform.M12, frame.Transform.M22, frame.Transform.M32, frame.Transform.M42, frame.Transform.M13, frame.Transform.M23, frame.Transform.M33, frame.Transform.M43, frame.Transform.M14, frame.Transform.M24, frame.Transform.M34, frame.Transform.M44); aiParentNode.Children.Add(aiNode); } var aiAnimation = new Assimp.Animation(); aiAnimation.TicksPerSecond = FPS; aiAnimation.DurationInTicks = animation.Duration * FPS; aiAnimation.Name = "Take 01"; aiScene.Animations.Add(aiAnimation); var keyFrameToNodeAnimationChannel = new Dictionary <RwKeyFrame, Assimp.NodeAnimationChannel>(); for (var i = 0; i < frameList.AnimationRootNode.HAnimFrameExtensionNode.Hierarchy.Nodes.Count; i++) { var hierarchyNode = frameList.AnimationRootNode.HAnimFrameExtensionNode.Hierarchy.Nodes[i]; var keyFrame = animation.KeyFrames[i]; // Create channel var aiNodeAnimationChannel = new Assimp.NodeAnimationChannel(); aiNodeAnimationChannel.NodeName = "_" + hierarchyNode.NodeId; aiNodeAnimationChannel.PostState = Assimp.AnimationBehaviour.Default; aiNodeAnimationChannel.PreState = Assimp.AnimationBehaviour.Default; aiNodeAnimationChannel.PositionKeys.Add(new Assimp.VectorKey(0, new Assimp.Vector3D(keyFrame.Translation.X, keyFrame.Translation.Y, keyFrame.Translation.Z))); aiNodeAnimationChannel.RotationKeys.Add(new Assimp.QuaternionKey(0, new Assimp.Quaternion(keyFrame.Rotation.X, keyFrame.Rotation.Y, keyFrame.Rotation.Z, keyFrame.Rotation.W))); aiNodeAnimationChannel.ScalingKeys.Add(new Assimp.VectorKey(0, new Assimp.Vector3D(1, 1, 1))); aiNodeAnimationChannel.ScalingKeys.Add(new Assimp.VectorKey(Math.Round(animation.Duration * FPS), new Assimp.Vector3D(1, 1, 1))); keyFrameToNodeAnimationChannel[keyFrame] = aiNodeAnimationChannel; aiAnimation.NodeAnimationChannels.Add(aiNodeAnimationChannel); } for (int i = frameList.AnimationRootNode.HAnimFrameExtensionNode.Hierarchy.Nodes.Count; i < animation.KeyFrames.Count; i++) { var keyFrame = animation.KeyFrames[i]; // Add keys var aiNodeAnimationChannel = keyFrameToNodeAnimationChannel[keyFrame.Previous]; aiNodeAnimationChannel.PositionKeys.Add(new Assimp.VectorKey(keyFrame.Time * FPS, new Assimp.Vector3D(keyFrame.Translation.X, keyFrame.Translation.Y, keyFrame.Translation.Z))); aiNodeAnimationChannel.RotationKeys.Add(new Assimp.QuaternionKey(keyFrame.Time * FPS, new Assimp.Quaternion(keyFrame.Rotation.X, keyFrame.Rotation.Y, keyFrame.Rotation.Z, keyFrame.Rotation.W))); keyFrameToNodeAnimationChannel[keyFrame] = aiNodeAnimationChannel; } return(aiScene); }