/// <summary> /// /// </summary> /// <param name="FileName"></param> /// <param name="animation"></param> /// <param name="skeleton"></param> private void ExportFigaTree(string FileName, SBAnimation animation, SBSkeleton skeleton) { HSDRawFile file = new HSDRawFile(); HSDRootNode root = new HSDRootNode(); if (HSDSettings.RootName == "" || HSDSettings.RootName == null) { HSDSettings.RootName = System.IO.Path.GetFileNameWithoutExtension(FileName); } if (HSDSettings.RootName == "" || HSDSettings.RootName == null) { HSDSettings.RootName = animation.Name; } root.Name = HSDSettings.RootName; if (root.Name == null || !root.Name.EndsWith("_figatree")) { System.Windows.Forms.MessageBox.Show($"Warning, the root name does not end with \"_figatree\"\n{root.Name}"); } file.Roots.Add(root); var nodes = new List <FigaTreeNode>(); int boneIndex = -1; foreach (var skelnode in skeleton.Bones) { FigaTreeNode animNode = new FigaTreeNode(); nodes.Add(animNode); boneIndex++; // skip trans n and rotn tracks if (boneIndex == 0) { continue; } var node = animation.TransformNodes.Find(e => e.Name == skelnode.Name); if (node == null) { continue; } foreach (var track in node.Tracks) { HSD_Track animTrack = new HSD_Track(); animTrack.FOBJ = EncodeFOBJ(track); animTrack.DataLength = (short)animTrack.FOBJ.Buffer.Length; animNode.Tracks.Add(animTrack); } } HSD_FigaTree tree = new HSD_FigaTree(); tree.FrameCount = animation.FrameCount; tree.Type = 1; tree.Nodes = nodes; root.Data = tree; file.Save(FileName); }
public IOModel ImportIOModel(string FileName) { IOModel model = new IOModel(); SBSkeleton skeleton = new SBSkeleton(); model.Skeleton = skeleton; var test = Fbx.FbxIO.ReadBinary(FileName); if (test.Version != Fbx.FbxVersion.v7_4) { throw new NotSupportedException($"Only FBX version 7.4 is currently supported: Imported version = {test.Version}"); } // global settings float Scale = 1; // read global settings var settings = test.GetNodesByName("GlobalSettings"); if (settings.Length != 0) { var prop70 = settings[0].GetNodesByName("Properties70"); if (prop70.Length != 0) { foreach (var property in prop70[0].Nodes) { if (property == null) { continue; } if (property.Properties.Count > 0 && property.Name == "P") { //TODO: this is inaccurate... //if (property.Properties[0].Equals("UnitScaleFactor")) // Scale = (float)(double)property.Properties[4]; } } } } FbxAccessor accessor = new FbxAccessor(FileName); //Bones var limbs = accessor.GetLimbNodes(); SBConsole.WriteLine($"Limb Node Count: {limbs.Length}"); foreach (var limb in limbs) { skeleton.AddRoot(ConvertLimbToSBBone(limb)); } foreach (var root in skeleton.Roots) { root.Scale *= Scale; } // Fast access to bone indices Dictionary <string, int> BoneNameToIndex = new Dictionary <string, int>(); foreach (var b in skeleton.Bones) { BoneNameToIndex.Add(b.Name, skeleton.IndexOfBone(b)); } // Mesh var models = accessor.GetModels(); SBConsole.WriteLine($"Model Node Count: {models.Count}"); int YupAxis = accessor.GetOriginalXAxis(); SBConsole.WriteLine("Yup: " + YupAxis); foreach (var mod in models) { // rotation 90 Matrix4 transform = (ImportSettings.Rotate90 ? Matrix4.CreateRotationX(-90 * DegToRag) : Matrix4.Identity) * GetModelTransform(mod); foreach (var geom in mod.Geometries) { IOMesh mesh = new IOMesh(); mesh.Name = mod.Name; model.Meshes.Add(mesh); // Create Rigging information Vector4[] BoneIndices = new Vector4[geom.Vertices.Length]; Vector4[] BoneWeights = new Vector4[geom.Vertices.Length]; foreach (var deformer in geom.Deformers) { //TODO: this shouldn't happen... if (!BoneNameToIndex.ContainsKey(deformer.Name)) { continue; } int index = BoneNameToIndex[deformer.Name]; for (int i = 0; i < deformer.Indices.Length; i++) { int vertexIndex = deformer.Indices[i]; for (int j = 0; j < 4; j++) { if (BoneWeights[vertexIndex][j] == 0) { BoneIndices[vertexIndex][j] = index; BoneWeights[vertexIndex][j] = (float)deformer.Weights[i]; break; } } } //SBConsole.WriteLine(deformer.Name + " " + deformer.Weights.Length + " " + deformer.Indices.Length + " " + index); } // Explanation: // negative values are used to indicate a stopping point for the face // so every 3rd index needed to be adjusted for (int i = 0; i < geom.Indices.Length; i += 3) { mesh.Indices.Add((uint)i); mesh.Indices.Add((uint)i + 1); mesh.Indices.Add((uint)i + 2); mesh.Vertices.Add(CreateVertex(transform, geom, i, BoneIndices, BoneWeights, Scale)); mesh.Vertices.Add(CreateVertex(transform, geom, i + 1, BoneIndices, BoneWeights, Scale)); mesh.Vertices.Add(CreateVertex(transform, geom, i + 2, BoneIndices, BoneWeights, Scale)); } mesh.HasPositions = true; //SBConsole.WriteLine(geom.Vertices.Length); foreach (var layer in geom.Layers) { switch (layer.Name) { case "LayerElementNormal": case "LayerElementUV": case "LayerElementColor": break; default: SBConsole.WriteLine(layer.Name + " " + layer.ReferenceInformationType + " " + layer.Data.Length + " " + (layer.ReferenceInformationType.Equals("IndexToDirect") ? layer.Indices.Length.ToString() : "")); break; } } mesh.Optimize(); } } return(model); }
public SBAnimation ImportSBAnimation(string FileName, SBSkeleton skeleton) { SBAnimation anim = new SBAnimation(); HSDRawFile f = new HSDRawFile(FileName); foreach (var root in f.Roots) { if (root == null || root.Data == null) { continue; } anim.Name = root.Name; if (root.Data is HSD_AnimJoint joint) { var joints = joint.BreathFirstList; int nodeIndex = -1; foreach (var j in joints) { nodeIndex++; if (j.AOBJ == null || j.AOBJ.FObjDesc == null) { continue; } SBConsole.WriteLine(nodeIndex + " " + j.Flags.ToString("X8") + " " + j.AOBJ.Flags.ToString()); SBTransformAnimation a = new SBTransformAnimation(); if (nodeIndex < skeleton.Bones.Length) { a.Name = skeleton.Bones[nodeIndex].Name; } else { a.Name = "JOBJ_" + nodeIndex; } anim.TransformNodes.Add(a); anim.FrameCount = Math.Max(anim.FrameCount, j.AOBJ.EndFrame); foreach (var fobj in j.AOBJ.FObjDesc.List) { a.Tracks.Add(DecodeFOBJ(fobj.ToFOBJ())); } } } if (root.Data is HSD_FigaTree tree) { anim.FrameCount = tree.FrameCount; int nodeIndex = 0; foreach (var node in tree.Nodes) { SBTransformAnimation a = new SBTransformAnimation(); a.Name = skeleton.Bones[nodeIndex++].Name; anim.TransformNodes.Add(a); foreach (var att in node.Tracks) { if (att.FOBJ == null) { continue; } a.Tracks.Add(DecodeFOBJ(att.FOBJ)); } } } if (root.Data is HSD_MatAnimJoint matjoint) { var joints = matjoint.BreathFirstList; anim.FrameCount = 0; int nodeIndex = -1; foreach (var j in joints) { if (j.MaterialAnimation == null) { continue; } var matAnims = j.MaterialAnimation.List; foreach (var manim in matAnims) { nodeIndex++; var aobj = manim.AnimationObject; if (aobj != null) { anim.FrameCount = Math.Max(anim.FrameCount, aobj.EndFrame); } var texanim = manim.TextureAnimation; if (texanim == null) { continue; } var texAOBJ = texanim.AnimationObject; if (texAOBJ == null || texAOBJ.FObjDesc == null) { continue; } anim.FrameCount = Math.Max(anim.FrameCount, texAOBJ.EndFrame); //TODO: tex anim is a list if (texanim != null) { SBTextureAnimation textureAnim = new SBTextureAnimation(); anim.TextureNodes.Add(textureAnim); textureAnim.MeshName = "DOBJ_" + nodeIndex; textureAnim.TextureAttibute = texanim.GXTexMapID.ToString(); textureAnim.Keys = DecodeFOBJ(texAOBJ.FObjDesc.ToFOBJ()).Keys; for (int i = 0; i < texanim.ImageCount; i++) { HSD_TOBJ tobj = new HSD_TOBJ(); tobj.ImageData = texanim.ImageBuffers.Array[i].Data; if (texanim.TlutCount > i) { tobj.TlutData = texanim.TlutBuffers.Array[i].Data; } var surface = new SBSurface(); surface.Arrays.Add(new MipArray() { Mipmaps = new List <byte[]>() { tobj.GetDecodedImageData() } }); surface.Width = tobj.ImageData.Width; surface.Height = tobj.ImageData.Height; surface.PixelFormat = PixelFormat.Bgra; surface.PixelType = PixelType.UnsignedByte; surface.InternalFormat = InternalFormat.Rgba; textureAnim.Surfaces.Add(surface); } } } } SBConsole.WriteLine(nodeIndex); } } return(anim); }
public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton) { ExportIOAnimationAsANIM(FileName, animation, skeleton); }
public static void ExportIOAnimationAsANIM(string fname, SBAnimation animation, SBSkeleton Skeleton) { IO_MayaANIM anim = new IO_MayaANIM(); anim.header.endTime = animation.FrameCount + 1; if (!MayaSettings.UseRadians) { anim.header.angularUnit = "deg"; } // get bone order List <SBBone> BonesInOrder = getBoneTreeOrder(Skeleton); if (MayaSettings.Maya2015) { BonesInOrder = BonesInOrder.OrderBy(f => f.Name, StringComparer.Ordinal).ToList(); } if (MayaSettings.RemoveRedundantFrames) { animation.Optimize(); } foreach (SBBone b in BonesInOrder) { AnimBone animBone = new AnimBone() { name = b.Name }; anim.Bones.Add(animBone); // Add Tracks SBTransformAnimation node = null; foreach (var animNode in animation.TransformNodes) { if (animNode.Name.Equals(b.Name)) { node = animNode; break; } } if (node == null) { continue; } //TODO: bake scale for compensate scale... foreach (var track in node.Tracks) { switch (track.Type) { case SBTrackType.TranslateX: AddAnimData(animBone, track.Keys, ControlType.translate, TrackType.translateX); break; case SBTrackType.TranslateY: AddAnimData(animBone, track.Keys, ControlType.translate, TrackType.translateY); break; case SBTrackType.TranslateZ: AddAnimData(animBone, track.Keys, ControlType.translate, TrackType.translateZ); break; case SBTrackType.RotateX: AddAnimData(animBone, track.Keys, ControlType.rotate, TrackType.rotateX); break; case SBTrackType.RotateY: AddAnimData(animBone, track.Keys, ControlType.rotate, TrackType.rotateY); break; case SBTrackType.RotateZ: AddAnimData(animBone, track.Keys, ControlType.rotate, TrackType.rotateZ); break; case SBTrackType.ScaleX: AddAnimData(animBone, track.Keys, ControlType.scale, TrackType.scaleX); break; case SBTrackType.ScaleY: AddAnimData(animBone, track.Keys, ControlType.scale, TrackType.scaleY); break; case SBTrackType.ScaleZ: AddAnimData(animBone, track.Keys, ControlType.scale, TrackType.scaleZ); break; } } } anim.Save(fname); }
public IOModel ImportIOModel(string FileName) { IOModel model = new IOModel(); SBSkeleton skeleton = new SBSkeleton(); Dictionary <int, SBBone> indexToBone = new Dictionary <int, SBBone>(); Dictionary <string, IOMesh> materialToMesh = new Dictionary <string, IOMesh>(); List <SBBone> PostProcessBones = new List <SBBone>(); List <int> boneParents = new List <int>(); string[] lines = File.ReadAllLines(FileName); string CurrentSection = ""; for (int i = 0; i < lines.Length; i++) { string[] args = Regex.Replace(lines[i].Trim(), @"\s+", " ").Split(' '); if (args[0].Equals("end")) { CurrentSection = ""; } else if (args[0].Equals("time")) { } else if (args[0].Equals("nodes")) { CurrentSection = args[0]; } else if (args[0].Equals("skeleton")) { CurrentSection = args[0]; } else if (args[0].Equals("triangles")) { CurrentSection = args[0]; } else { switch (CurrentSection) { case "nodes": var bone = new SBBone(); bone.Name = args[1].Replace("\"", ""); Console.WriteLine(bone.Name + " " + args[2]); boneParents.Add(int.Parse(args[2])); PostProcessBones.Add(bone); indexToBone.Add(int.Parse(args[0]), bone); break; case "skeleton": var skel = PostProcessBones[int.Parse(args[0])]; skel.Transform = Matrix4.Identity; skel.X = float.Parse(args[1]); skel.Y = float.Parse(args[2]); skel.Z = float.Parse(args[3]); skel.RX = float.Parse(args[4]); skel.RY = float.Parse(args[5]); skel.RZ = float.Parse(args[6]); break; case "triangles": string material = args[0]; if (!materialToMesh.ContainsKey(material)) { var iomesh = new IOMesh(); iomesh.HasPositions = true; iomesh.HasNormals = true; iomesh.HasUV0 = true; iomesh.HasBoneWeights = true; iomesh.Name = material; materialToMesh.Add(material, iomesh); } var mesh = materialToMesh[material]; mesh.Vertices.Add(ReadVertex(Regex.Replace(lines[i + 1].Trim(), @"\s+", " ").Split(' '))); mesh.Vertices.Add(ReadVertex(Regex.Replace(lines[i + 2].Trim(), @"\s+", " ").Split(' '))); mesh.Vertices.Add(ReadVertex(Regex.Replace(lines[i + 3].Trim(), @"\s+", " ").Split(' '))); i += 3; break; } } } //PostProcessBones int boneIndex = 0; foreach (var bone in PostProcessBones) { if (boneParents[boneIndex] == -1) { skeleton.AddRoot(bone); } else { bone.Parent = indexToBone[boneParents[boneIndex]]; } boneIndex++; } model.Skeleton = skeleton; // finalize meshes foreach (var pair in materialToMesh) { model.Meshes.Add(pair.Value); pair.Value.Optimize(); SBConsole.WriteLine($"Imported {pair.Key} from SMD"); //finalize rigging for (int i = 0; i < pair.Value.Vertices.Count; i++) { var vertex = pair.Value.Vertices[i]; vertex.BoneIndices.X = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.X]); vertex.BoneIndices.Y = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.Y]); vertex.BoneIndices.Z = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.Z]); vertex.BoneIndices.W = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.W]); pair.Value.Vertices[i] = vertex; } } return(model); }
public SBAnimation ImportSBAnimation(string FileName, SBSkeleton skeleton) { SBAnimation anim = new SBAnimation(); using (StreamReader r = new StreamReader(new FileStream(FileName, FileMode.Open))) { if (r.ReadLine() != "#SBAnimation Version 1") { return(anim); } while (!r.EndOfStream) { var line = r.ReadLine(); var args = line.Trim().Split(' '); switch (args[0]) { case "comment": break; case "FrameCount": anim.FrameCount = int.Parse(args[1]); break; case "visibility": SBVisibilityAnimation visAnim = new SBVisibilityAnimation(); visAnim.MeshName = args[1]; var visLien = r.ReadLine(); if (visLien == "{") { visLien = r.ReadLine(); while (!r.EndOfStream && visLien != "}") { visLien = visLien.Replace(" ", ""); var frame = visLien.Substring(0, visLien.IndexOf(":")).Trim(); var value = visLien.Substring(visLien.IndexOf(":") + 1, visLien.Length - (visLien.IndexOf(":") + 1)).Trim(); visAnim.Visibility.AddKey(float.Parse(frame), bool.Parse(value)); visLien = r.ReadLine(); } } anim.VisibilityNodes.Add(visAnim); break; case "bone": if (args[1].Contains(".anim")) { IO_MayaANIM manim = new IO_MayaANIM(); var bones = manim.ImportSBAnimation(Path.GetDirectoryName(FileName) + "/" + args[1], skeleton); anim.TransformNodes.AddRange(bones.TransformNodes); } break; case "material": SBMaterialAnimation matAnim = new SBMaterialAnimation(); matAnim.MaterialName = args[1]; matAnim.AttributeName = args[2]; var matLien = r.ReadLine(); if (matLien == "{") { matLien = r.ReadLine(); while (!r.EndOfStream && matLien != "}") { matLien = matLien.Replace(" ", ""); var frame = matLien.Substring(0, matLien.IndexOf(":")).Trim(); var value = matLien.Substring(matLien.IndexOf(":") + 1, matLien.Length - (matLien.IndexOf(":") + 1)).Trim(); var vector = value.Replace(")", "").Replace("(", "").Split(','); if (vector.Length != 4) { continue; } matAnim.Keys.AddKey(float.Parse(frame), new Vector4(float.Parse(vector[0]), float.Parse(vector[1]), float.Parse(vector[2]), float.Parse(vector[3]))); matLien = r.ReadLine(); } } anim.MaterialNodes.Add(matAnim); break; } } } return(anim); }