From 1f2635c877fad1748dbd86984c2bf70198a82e7d Mon Sep 17 00:00:00 2001 From: Radu Date: Fri, 13 Nov 2015 14:45:39 +0200 Subject: [PATCH] - added code to handle vertex buffer streams for Unity 5 - new method of creatign unique numeric IDs for FBX objects - added code to decompress Skin data; further research needed for data interpretation --- Unity Studio/ExportOptions.cs | 1 + Unity Studio/Unity Classes/Mesh.cs | 155 +++++++++++++++++++++-------- Unity Studio/UnityStudioForm.cs | 90 ++++++++++------- 3 files changed, 167 insertions(+), 79 deletions(-) diff --git a/Unity Studio/ExportOptions.cs b/Unity Studio/ExportOptions.cs index 25a401a..084a7ce 100644 --- a/Unity Studio/ExportOptions.cs +++ b/Unity Studio/ExportOptions.cs @@ -23,6 +23,7 @@ namespace Unity_Studio exportColors.Checked = (bool)Properties.Settings.Default["exportColors"]; exportDeformers.Checked = (bool)Properties.Settings.Default["exportDeformers"]; convertDummies.Checked = (bool)Properties.Settings.Default["convertDummies"]; + convertDummies.Enabled = (bool)Properties.Settings.Default["exportDeformers"]; scaleFactor.Value = (decimal)Properties.Settings.Default["scaleFactor"]; upAxis.SelectedIndex = (int)Properties.Settings.Default["upAxis"]; showExpOpt.Checked = (bool)Properties.Settings.Default["showExpOpt"]; diff --git a/Unity Studio/Unity Classes/Mesh.cs b/Unity Studio/Unity Classes/Mesh.cs index 5ac590b..be11842 100644 --- a/Unity Studio/Unity Classes/Mesh.cs +++ b/Unity Studio/Unity Classes/Mesh.cs @@ -113,7 +113,7 @@ namespace Unity_Studio public List[] m_Skin; //public Dictionary[] m_Skin; public float[][,] m_BindPose; - public uint m_VertexCount; + public int m_VertexCount; public float[] m_Vertices; public float[] m_Normals; public float[] m_Colors; @@ -159,7 +159,7 @@ namespace Unity_Studio public class PackedBitVector { - public uint m_NumItems; + public int m_NumItems; public float m_Range = 1.0f; public float m_Start = 0.0f; public byte[] m_Data; @@ -391,9 +391,8 @@ namespace Unity_Studio } } #endregion - - #region BlendShapeData - #region 4.1.0 to 4.2.x, excluding 4.1.0 alpha + + #region BlendShapeData for 4.1.0 to 4.2.x, excluding 4.1.0 alpha if (version[0] == 4 && ((version[1] == 1 && MeshPD.sourceFile.buildType[0] != "a") || (version[1] > 1 && version[1] <= 2))) { @@ -412,7 +411,7 @@ namespace Unity_Studio a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index } #endregion - #region 4.3.0 and later + #region BlendShapeData and BindPose for 4.3.0 and later else if (version[0] >= 5 || (version[0] == 4 && version[1] >= 3)) { int m_ShapeVertices_size = a_Stream.ReadInt32(); @@ -451,7 +450,6 @@ namespace Unity_Studio uint m_RootBoneNameHash = a_Stream.ReadUInt32(); } #endregion - #endregion #region Index Buffer for 2.6.0 and later if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) @@ -486,7 +484,7 @@ namespace Unity_Studio #region Vertex Buffer for 3.4.2 and earlier if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) { - m_VertexCount = a_Stream.ReadUInt32(); + m_VertexCount = a_Stream.ReadInt32(); m_Vertices = new float[m_VertexCount * 3]; for (int v = 0; v < m_VertexCount * 3; v++) { m_Vertices[v] = a_Stream.ReadSingle(); } @@ -583,10 +581,10 @@ namespace Unity_Studio } } - int m_CurrentChannels = a_Stream.ReadInt32();//defined as uint in Unity - m_VertexCount = a_Stream.ReadUInt32(); + BitArray m_CurrentChannels = new BitArray(new int[1] { a_Stream.ReadInt32() }); + m_VertexCount = a_Stream.ReadInt32(); - #region 3.5.0 - 3.5.7 + #region streams for 3.5.0 - 3.5.7 if (version[0] < 4) { if (m_MeshCompression != 0 && version[2] == 0) //special case not just on platform 9 @@ -607,10 +605,11 @@ namespace Unity_Studio } } #endregion - #region 4.0.0 and later + #region channels and streams for 4.0.0 and later else { - int singleStreamStride = 0;//used tor unity 5 + //int singleStreamStride = 0;//used tor unity 5 + int streamCount = 0; m_Channels = new ChannelInfo[a_Stream.ReadInt32()]; for (int c = 0; c < m_Channels.Length; c++) @@ -622,7 +621,9 @@ namespace Unity_Studio m_Channels[c].dimension = a_Stream.ReadByte(); //calculate stride for Unity 5 - singleStreamStride += m_Channels[c].dimension * (4 / (int)Math.Pow(2, m_Channels[c].format)); + //singleStreamStride += m_Channels[c].dimension * (4 / (int)Math.Pow(2, m_Channels[c].format)); + + if (m_Channels[c].stream >= streamCount) { streamCount = m_Channels[c].stream + 1; } } if (version[0] < 5) @@ -638,13 +639,21 @@ namespace Unity_Studio m_Streams[s].frequency = a_Stream.ReadUInt16(); } } - else //it's just easier to create my own stream here + else //create streams { - m_Streams = new StreamInfo[1]; - m_Streams[0] = new StreamInfo(); - m_Streams[0].channelMask = new BitArray(new int[1] { m_CurrentChannels }); - m_Streams[0].offset = 0; - m_Streams[0].stride = singleStreamStride; + m_Streams = new StreamInfo[streamCount]; + for (int s = 0; s < streamCount; s++) + { + m_Streams[s] = new StreamInfo(); + m_Streams[s].channelMask = new BitArray(new int[1] { 0 }); + m_Streams[s].offset = 0; + if (s > 0) { m_Streams[s].offset = m_Streams[s - 1].offset + m_Streams[s - 1].stride * m_VertexCount; } + m_Streams[s].stride = 0; + foreach (var m_Channel in m_Channels) + { + if (m_Channel.stream == s) { m_Streams[s].stride += m_Channel.dimension * (4 / (int)Math.Pow(2, m_Channel.format)); } + } + } } } #endregion @@ -672,7 +681,8 @@ namespace Unity_Studio for (int b = 0; b < 8; b++) { - if (m_Stream.channelMask.Get(b)) + //in the future, try to use only m_CurrentChannels + if ((version[0] < 5 && m_Stream.channelMask.Get(b)) || (version[0] >= 5 && m_CurrentChannels.Get(b))) { // in Unity 4.x the colors channel has 1 dimension, as in 1 color with 4 components if (b == 2 && m_Channel.format == 2) { m_Channel.dimension = 4; } @@ -723,6 +733,7 @@ namespace Unity_Studio } m_Stream.channelMask.Set(b, false); + m_CurrentChannels.Set(b, false); componentBytes = null; componentsArray = null; break; //go to next channel @@ -810,8 +821,10 @@ namespace Unity_Studio if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) { //remember there can be combinations of packed and regular vertex properties + + #region m_Vertices PackedBitVector m_Vertices_Packed = new PackedBitVector(); - m_Vertices_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_Vertices_Packed.m_NumItems = a_Stream.ReadInt32(); m_Vertices_Packed.m_Range = a_Stream.ReadSingle(); m_Vertices_Packed.m_Start = a_Stream.ReadSingle(); m_Vertices_Packed.m_Data = new byte[a_Stream.ReadInt32()]; @@ -829,12 +842,14 @@ namespace Unity_Studio m_Vertices = new float[m_Vertices_Packed.m_NumItems]; for (int v = 0; v < m_Vertices_Packed.m_NumItems; v++) { - m_Vertices[v] = (float)m_Vertices_Unpacked[v] / bitmax * m_Vertices_Packed.m_Range + m_Vertices_Packed.m_Start; + m_Vertices[v] = (float)((double)m_Vertices_Unpacked[v] / bitmax) * m_Vertices_Packed.m_Range + m_Vertices_Packed.m_Start; } } + #endregion - PackedBitVector m_UV_Packed = new PackedBitVector(); //contains both channels - m_UV_Packed.m_NumItems = a_Stream.ReadUInt32(); + #region m_UV + PackedBitVector m_UV_Packed = new PackedBitVector(); //contains all channels + m_UV_Packed.m_NumItems = a_Stream.ReadInt32(); m_UV_Packed.m_Range = a_Stream.ReadSingle(); m_UV_Packed.m_Start = a_Stream.ReadSingle(); m_UV_Packed.m_Data = new byte[a_Stream.ReadInt32()]; @@ -853,7 +868,7 @@ namespace Unity_Studio for (int v = 0; v < m_VertexCount * 2; v++) { - m_UV1[v] = (float)m_UV_Unpacked[v] / bitmax * m_UV_Packed.m_Range + m_UV_Packed.m_Start; + m_UV1[v] = (float)((double)m_UV_Unpacked[v] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } if (m_UV_Packed.m_NumItems >= m_VertexCount * 4) @@ -861,7 +876,7 @@ namespace Unity_Studio m_UV2 = new float[m_VertexCount * 2]; for (uint v = 0; v < m_VertexCount * 2; v++) { - m_UV2[v] = (float)m_UV_Unpacked[v + m_VertexCount * 2] / bitmax * m_UV_Packed.m_Range + m_UV_Packed.m_Start; + m_UV2[v] = (float)((double)m_UV_Unpacked[v + m_VertexCount * 2] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } if (m_UV_Packed.m_NumItems >= m_VertexCount * 6) @@ -869,7 +884,7 @@ namespace Unity_Studio m_UV3 = new float[m_VertexCount * 2]; for (uint v = 0; v < m_VertexCount * 2; v++) { - m_UV3[v] = (float)m_UV_Unpacked[v + m_VertexCount * 4] / bitmax * m_UV_Packed.m_Range + m_UV_Packed.m_Start; + m_UV3[v] = (float)((double)m_UV_Unpacked[v + m_VertexCount * 4] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } if (m_UV_Packed.m_NumItems == m_VertexCount * 8) @@ -877,17 +892,19 @@ namespace Unity_Studio m_UV4 = new float[m_VertexCount * 2]; for (uint v = 0; v < m_VertexCount * 2; v++) { - m_UV4[v] = (float)m_UV_Unpacked[v + m_VertexCount * 6] / bitmax * m_UV_Packed.m_Range + m_UV_Packed.m_Start; + m_UV4[v] = (float)((double)m_UV_Unpacked[v + m_VertexCount * 6] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } } } } } + #endregion + #region m_BindPose if (version[0] < 5) { PackedBitVector m_BindPoses_Packed = new PackedBitVector(); - m_BindPoses_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_BindPoses_Packed.m_NumItems = a_Stream.ReadInt32(); m_BindPoses_Packed.m_Range = a_Stream.ReadSingle(); m_BindPoses_Packed.m_Start = a_Stream.ReadSingle(); m_BindPoses_Packed.m_Data = new byte[a_Stream.ReadInt32()]; @@ -895,10 +912,32 @@ namespace Unity_Studio a_Stream.AlignStream(4); m_BindPoses_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment + + if (m_BindPoses_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportDeformers"]) + { + uint[] m_BindPoses_Unpacked = UnpackBitVector(m_BindPoses_Packed); + int bitmax = 0;//used to convert int value to float + for (int b = 0; b < m_BindPoses_Packed.m_BitSize; b++) { bitmax |= (1 << b); } + + m_BindPose = new float[m_BindPoses_Packed.m_NumItems / 16][,]; + + for (int i = 0; i < m_BindPose.Length; i++) + { + m_BindPose[i] = new float[4, 4]; + for (int j = 0; j < 4; j++) + { + for (int k = 0; k < 4; k++) + { + m_BindPose[i][j,k] = (float)((double)m_BindPoses_Unpacked[i * 16 + j * 4 + k] / bitmax) * m_BindPoses_Packed.m_Range + m_BindPoses_Packed.m_Start; + } + } + } + } } + #endregion PackedBitVector m_Normals_Packed = new PackedBitVector(); - m_Normals_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_Normals_Packed.m_NumItems = a_Stream.ReadInt32(); m_Normals_Packed.m_Range = a_Stream.ReadSingle(); m_Normals_Packed.m_Start = a_Stream.ReadSingle(); m_Normals_Packed.m_Data = new byte[a_Stream.ReadInt32()]; @@ -908,7 +947,7 @@ namespace Unity_Studio a_Stream.Position += 3; //4 byte alignment PackedBitVector m_Tangents_Packed = new PackedBitVector(); - m_Tangents_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_Tangents_Packed.m_NumItems = a_Stream.ReadInt32(); m_Tangents_Packed.m_Range = a_Stream.ReadSingle(); m_Tangents_Packed.m_Start = a_Stream.ReadSingle(); m_Tangents_Packed.m_Data = new byte[a_Stream.ReadInt32()]; @@ -917,16 +956,17 @@ namespace Unity_Studio m_Tangents_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment - PackedBitVector m_Weights_Packed = new PackedBitVector(); - m_Weights_Packed.m_NumItems = a_Stream.ReadUInt32(); - m_Weights_Packed.m_Data = new byte[a_Stream.ReadInt32()]; - a_Stream.Read(m_Weights_Packed.m_Data, 0, m_Weights_Packed.m_Data.Length); + PackedBitVector m_Weights = new PackedBitVector(); + m_Weights.m_NumItems = a_Stream.ReadInt32(); + m_Weights.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_Weights.m_Data, 0, m_Weights.m_Data.Length); a_Stream.AlignStream(4); - m_Weights_Packed.m_BitSize = a_Stream.ReadByte(); + m_Weights.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment + #region m_Normals PackedBitVector m_NormalSigns_packed = new PackedBitVector(); - m_NormalSigns_packed.m_NumItems = a_Stream.ReadUInt32(); + m_NormalSigns_packed.m_NumItems = a_Stream.ReadInt32(); m_NormalSigns_packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_NormalSigns_packed.m_Data, 0, m_NormalSigns_packed.m_Data.Length); a_Stream.AlignStream(4); @@ -948,9 +988,11 @@ namespace Unity_Studio if (m_NormalSigns[v] == 0) { m_Normals[v * 3 + 2] *= -1; } } } + #endregion + #region m_Tangents PackedBitVector m_TangentSigns_packed = new PackedBitVector(); - m_TangentSigns_packed.m_NumItems = a_Stream.ReadUInt32(); + m_TangentSigns_packed.m_NumItems = a_Stream.ReadInt32(); m_TangentSigns_packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_TangentSigns_packed.m_Data, 0, m_TangentSigns_packed.m_Data.Length); a_Stream.AlignStream(4); @@ -972,11 +1014,13 @@ namespace Unity_Studio if (m_TangentSigns[v] == 0) { m_Tangents[v * 3 + 2] *= -1; } } } + #endregion + #region m_FloatColors if (version[0] >= 5) { PackedBitVector m_FloatColors = new PackedBitVector(); - m_FloatColors.m_NumItems = a_Stream.ReadUInt32(); + m_FloatColors.m_NumItems = a_Stream.ReadInt32(); m_FloatColors.m_Range = a_Stream.ReadSingle(); m_FloatColors.m_Start = a_Stream.ReadSingle(); m_FloatColors.m_Data = new byte[a_Stream.ReadInt32()]; @@ -999,17 +1043,41 @@ namespace Unity_Studio } } } + #endregion + #region m_Skin PackedBitVector m_BoneIndices = new PackedBitVector(); - m_BoneIndices.m_NumItems = a_Stream.ReadUInt32(); + m_BoneIndices.m_NumItems = a_Stream.ReadInt32(); m_BoneIndices.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_BoneIndices.m_Data, 0, m_BoneIndices.m_Data.Length); a_Stream.AlignStream(4); m_BoneIndices.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment + //how the hell does this work?? + if (m_BoneIndices.m_NumItems > 0 && m_BoneIndices.m_NumItems == m_Weights.m_NumItems && (bool)Properties.Settings.Default["exportDeformers"]) + { + uint[] m_Weights_Unpacked = UnpackBitVector(m_Weights); + int bitmax = 0; + for (int b = 0; b < m_Weights.m_BitSize; b++) { bitmax |= (1 << b); } + + uint[] m_BoneIndices_Unpacked = UnpackBitVector(m_BoneIndices); + + m_Skin = new List[m_BoneIndices.m_NumItems / 4]; + for (int s = 0; s < m_Skin.Length; s++) + { + m_Skin[s] = new List(); + for (int i = 0; i < 4; i++) + { + m_Skin[s].Add(new BoneInfluence() { weight = (float)((double)m_Weights_Unpacked[s * 4 + i] / bitmax), + boneIndex = (int)m_BoneIndices_Unpacked[s * 4 + i] }); + } + } + } + #endregion + PackedBitVector m_Triangles = new PackedBitVector(); - m_Triangles.m_NumItems = a_Stream.ReadUInt32(); + m_Triangles.m_NumItems = a_Stream.ReadInt32(); m_Triangles.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Triangles.m_Data, 0, m_Triangles.m_Data.Length); a_Stream.AlignStream(4); @@ -1039,7 +1107,7 @@ namespace Unity_Studio if (version[0] < 5) { PackedBitVector m_Colors_Packed = new PackedBitVector(); - m_Colors_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_Colors_Packed.m_NumItems = a_Stream.ReadInt32(); m_Colors_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Colors_Packed.m_Data, 0, m_Colors_Packed.m_Data.Length); a_Stream.AlignStream(4); @@ -1070,6 +1138,7 @@ namespace Unity_Studio } } } + else { uint m_UVInfo = a_Stream.ReadUInt32(); } a_Stream.Position += 24; //Axis-Aligned Bounding Box } diff --git a/Unity Studio/UnityStudioForm.cs b/Unity Studio/UnityStudioForm.cs index 9bc9dfe..92e94cc 100644 --- a/Unity Studio/UnityStudioForm.cs +++ b/Unity Studio/UnityStudioForm.cs @@ -619,7 +619,7 @@ namespace Unity_Studio var fileGen = assetsFile.fileGen; //var m_version = assetsFile.m_version; var version = assetsFile.version; - string fileID = "1" + assetsfileList.IndexOf(assetsFile).ToString(fileIDfmt); + string fileID = assetsfileList.IndexOf(assetsFile).ToString(fileIDfmt); //ListViewGroup assetGroup = new ListViewGroup(Path.GetFileName(assetsFile.filePath)); @@ -1684,6 +1684,19 @@ namespace Unity_Studio HashSet Textures = new HashSet(); int DeformerCount = 0; + /* + uniqueIDs can begin with zero, so they are preceded by a number specific to their type + this will also make it easier to debug FBX files + 1: Model + 2: NodeAttribute + 3: Geometry + 4: Deformer + 5: CollectionExclusive + 6: Material + 7: Texture + 8: Video + 9: + */ #region loop nodes and collect objects for export foreach (var assetsFile in assetsfileList) @@ -1705,8 +1718,10 @@ namespace Unity_Studio { Meshes.Add(MeshPD); + //write connections here and Mesh objects separately without having to backtrack through their MEshFilter to het the GameObject ID + //also note that MeshFilters are not unique, they cannot be used for instancing geometry cb2.AppendFormat("\n\n\t;Geometry::, Model::{0}", m_GameObject.m_Name); - cb2.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); + cb2.AppendFormat("\n\tC: \"OO\",3{0},1{1}", MeshPD.uniqueID, m_GameObject.uniqueID); } } @@ -1723,7 +1738,7 @@ namespace Unity_Studio { Materials.Add(MaterialPD); cb2.AppendFormat("\n\n\t;Material::, Model::{0}", m_GameObject.m_Name); - cb2.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); + cb2.AppendFormat("\n\tC: \"OO\",6{0},1{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); } } } @@ -1744,7 +1759,7 @@ namespace Unity_Studio { Materials.Add(MaterialPD); cb2.AppendFormat("\n\n\t;Material::, Model::{0}", m_GameObject.m_Name); - cb2.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); + cb2.AppendFormat("\n\tC: \"OO\",6{0},1{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); } } @@ -1806,7 +1821,7 @@ namespace Unity_Studio { Material m_Material = new Material(MaterialPD); - mb.AppendFormat("\n\tMaterial: {0}, \"Material::{1}\", \"\" {{", MaterialPD.uniqueID, m_Material.m_Name); + mb.AppendFormat("\n\tMaterial: 6{0}, \"Material::{1}\", \"\" {{", MaterialPD.uniqueID, m_Material.m_Name); mb.Append("\n\t\tVersion: 102"); mb.Append("\n\t\tShadingModel: \"phong\""); mb.Append("\n\t\tMultiLayer: 0"); @@ -1859,8 +1874,8 @@ namespace Unity_Studio foreach (var m_TexEnv in m_Material.m_TexEnvs) { AssetPreloadData TexturePD; - if (assetsfileList.TryGetPD(m_TexEnv.m_Texture, out TexturePD)) { } - else if (jsonMats != null) + #region get Porsche material from json + if (!assetsfileList.TryGetPD(m_TexEnv.m_Texture, out TexturePD) && jsonMats != null) { Dictionary matProp; if (jsonMats.TryGetValue(m_Material.m_Name, out matProp)) @@ -1879,13 +1894,15 @@ namespace Unity_Studio } } } + #endregion - if (TexturePD != null) + if (TexturePD != null && TexturePD.Type2 == 28) { Textures.Add(TexturePD); cb2.AppendFormat("\n\n\t;Texture::, Material::{0}", m_Material.m_Name); - cb2.AppendFormat("\n\tC: \"OP\",{0},{1}, \"", TexturePD.uniqueID, MaterialPD.uniqueID); + cb2.AppendFormat("\n\tC: \"OP\",7{0},6{1}, \"", TexturePD.uniqueID, MaterialPD.uniqueID); + switch (m_TexEnv.name) { case "_MainTex": @@ -2032,14 +2049,13 @@ namespace Unity_Studio { if (m_GameObject.m_MeshFilter == null && m_GameObject.m_SkinnedMeshRenderer == null) { - //NodeAttribute objects will have the same GameObject ID preceded by "2" if ((bool)Properties.Settings.Default["exportDeformers"] && (bool)Properties.Settings.Default["convertDummies"] && LimbNodes.Contains(m_GameObject)) { ob.AppendFormat("\n\tNodeAttribute: 2{0}, \"NodeAttribute::\", \"LimbNode\" {{", m_GameObject.uniqueID); ob.Append("\n\t\tTypeFlags: \"Skeleton\""); ob.Append("\n\t}"); - ob.AppendFormat("\n\tModel: {0}, \"Model::{1}\", \"LimbNode\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); + ob.AppendFormat("\n\tModel: 1{0}, \"Model::{1}\", \"LimbNode\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); } else { @@ -2047,16 +2063,16 @@ namespace Unity_Studio ob.Append("\n\t\tTypeFlags: \"Null\""); ob.Append("\n\t}"); - ob.AppendFormat("\n\tModel: {0}, \"Model::{1}\", \"Null\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); + ob.AppendFormat("\n\tModel: 1{0}, \"Model::{1}\", \"Null\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); } //connect NodeAttribute to Model cb.AppendFormat("\n\n\t;NodeAttribute::, Model::{0}", m_GameObject.m_Name); - cb.AppendFormat("\n\tC: \"OO\",2{0},{0}", m_GameObject.uniqueID); + cb.AppendFormat("\n\tC: \"OO\",2{0},1{0}", m_GameObject.uniqueID); } else { - ob.AppendFormat("\n\tModel: {0}, \"Model::{1}\", \"Mesh\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); + ob.AppendFormat("\n\tModel: 1{0}, \"Model::{1}\", \"Mesh\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); } ob.Append("\n\t\tVersion: 232"); @@ -2086,12 +2102,12 @@ namespace Unity_Studio if (GameObjects.Contains(parentObject)) { cb.AppendFormat("\n\n\t;Model::{0}, Model::{1}", m_GameObject.m_Name, parentObject.m_Name); - cb.AppendFormat("\n\tC: \"OO\",{0},{1}", m_GameObject.uniqueID, parentObject.uniqueID); + cb.AppendFormat("\n\tC: \"OO\",1{0},1{1}", m_GameObject.uniqueID, parentObject.uniqueID); } else { cb.AppendFormat("\n\n\t;Model::{0}, Model::RootNode", m_GameObject.m_Name); - cb.AppendFormat("\n\tC: \"OO\",{0},0", m_GameObject.uniqueID); + cb.AppendFormat("\n\tC: \"OO\",1{0},0", m_GameObject.uniqueID); } @@ -2135,40 +2151,39 @@ namespace Unity_Studio { FBXwriter.Write(ob); ob.Clear(); } cb2.AppendFormat("\n\n\t;Geometry::, Model::{0}", m_GameObject.m_Name); - cb2.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); + cb2.AppendFormat("\n\tC: \"OO\",3{0},1{1}", MeshPD.uniqueID, m_GameObject.uniqueID); if ((bool)Properties.Settings.Default["exportDeformers"]) { //add BindPose node pb.Append("\n\t\tPoseNode: {"); - pb.AppendFormat("\n\t\t\tNode: {0}", m_GameObject.uniqueID); + pb.AppendFormat("\n\t\t\tNode: 1{0}", m_GameObject.uniqueID); //pb.Append("\n\t\t\tMatrix: *16 {"); //pb.Append("\n\t\t\t\ta: "); //pb.Append("\n\t\t\t} "); pb.Append("\n\t\t}"); - //write DisplayLayer with SkinnedMeshRenderer ID preceded by "3" - ob.AppendFormat("\n\tCollectionExclusive: 3{0}, \"DisplayLayer::{0}\", \"DisplayLayer\" {{", SkinnedMeshPD.uniqueID); + ob.AppendFormat("\n\tCollectionExclusive: 5{0}, \"DisplayLayer::{1}\", \"DisplayLayer\" {{", SkinnedMeshPD.uniqueID, m_GameObject.m_Name); ob.Append("\n\t\tProperties70: {"); ob.Append("\n\t\t}"); ob.Append("\n\t}"); //connect Model to DisplayLayer cb2.AppendFormat("\n\n\t;Model::{0}, DisplayLayer::", m_GameObject.m_Name); - cb2.AppendFormat("\n\tC: \"OO\",{0},3{1}", m_GameObject.uniqueID, SkinnedMeshPD.uniqueID); + cb2.AppendFormat("\n\tC: \"OO\",1{0},5{1}", m_GameObject.uniqueID, SkinnedMeshPD.uniqueID); //write Deformers - if (m_Mesh.m_Skin.Length > 0) + if (m_Mesh.m_Skin.Length > 0 && m_Mesh.m_BindPose.Length >= m_SkinnedMeshRenderer.m_Bones.Length) { //write main Skin Deformer - ob.AppendFormat("\n\tDeformer: {0}, \"Deformer::\", \"Skin\" {{", SkinnedMeshPD.uniqueID); + ob.AppendFormat("\n\tDeformer: 4{0}, \"Deformer::\", \"Skin\" {{", SkinnedMeshPD.uniqueID); ob.Append("\n\t\tVersion: 101"); ob.Append("\n\t\tLink_DeformAcuracy: 50"); ob.Append("\n\t}"); //Deformer end //connect Skin Deformer to Geometry - cb2.Append("\n\t;Deformer::, Geometry::"); - cb2.AppendFormat("\n\tC: \"OO\",{0},{1}", SkinnedMeshPD.uniqueID, MeshPD.uniqueID); + cb2.Append("\n\n\t;Deformer::, Geometry::"); + cb2.AppendFormat("\n\tC: \"OO\",4{0},3{1}", SkinnedMeshPD.uniqueID, MeshPD.uniqueID); for (int b = 0; b < m_SkinnedMeshRenderer.m_Bones.Length; b++) { @@ -2225,8 +2240,8 @@ namespace Unity_Studio wb.Length--;//remove last comma } - //SubDeformer objects need unique IDs because 2 or more deformers can be attached to the same bone - ob.AppendFormat("\n\tDeformer: 1{0}{1}, \"SubDeformer::\", \"Cluster\" {{", b, SkinnedMeshPD.uniqueID); + //SubDeformer objects need unique IDs because 2 or more deformers can be linked to the same bone + ob.AppendFormat("\n\tDeformer: 4{0}{1}, \"SubDeformer::\", \"Cluster\" {{", b, SkinnedMeshPD.uniqueID); ob.Append("\n\t\tVersion: 100"); ob.Append("\n\t\tUserData: \"\", \"\""); @@ -2253,15 +2268,19 @@ namespace Unity_Studio //connect SubDeformer to Skin Deformer cb2.Append("\n\n\t;SubDeformer::, Deformer::"); - cb2.AppendFormat("\n\tC: \"OO\",1{0}{1},{1}", b, SkinnedMeshPD.uniqueID); + cb2.AppendFormat("\n\tC: \"OO\",4{0}{1},4{1}", b, SkinnedMeshPD.uniqueID); - //connect dummy to SubDeformer + //connect dummy Model to SubDeformer cb2.AppendFormat("\n\n\t;Model::{0}, SubDeformer::", m_Bone.m_Name); - cb2.AppendFormat("\n\tC: \"OO\",{0},1{1}{2}", m_Bone.uniqueID, b, SkinnedMeshPD.uniqueID); + cb2.AppendFormat("\n\tC: \"OO\",1{0},4{1}{2}", m_Bone.uniqueID, b, SkinnedMeshPD.uniqueID); } } } } + else + { + bool stop = true; + } } } } @@ -2272,7 +2291,7 @@ namespace Unity_Studio { //add BindPose node pb.Append("\n\t\tPoseNode: {"); - pb.AppendFormat("\n\t\t\tNode: {0}", m_Bone.uniqueID); + pb.AppendFormat("\n\t\t\tNode: 1{0}", m_Bone.uniqueID); //pb.Append("\n\t\t\tMatrix: *16 {"); //pb.Append("\n\t\t\t\ta: "); //pb.Append("\n\t\t\t} "); @@ -2342,7 +2361,7 @@ namespace Unity_Studio } #endregion - ob.AppendFormat("\n\tTexture: {0}, \"Texture::{1}\", \"\" {{", TexturePD.uniqueID, TexturePD.Text); + ob.AppendFormat("\n\tTexture: 7{0}, \"Texture::{1}\", \"\" {{", TexturePD.uniqueID, TexturePD.Text); ob.Append("\n\t\tType: \"TextureVideoClip\""); ob.Append("\n\t\tVersion: 202"); ob.AppendFormat("\n\t\tTextureName: \"Texture::{0}\"", TexturePD.Text); @@ -2355,8 +2374,7 @@ namespace Unity_Studio ob.AppendFormat("\n\t\tRelativeFilename: \"Texture2D\\{0}\"", Path.GetFileName(texPath)); ob.Append("\n\t}"); - //Video ID is prefixed by 1 - ob.AppendFormat("\n\tVideo: 1{0}, \"Video::{1}\", \"Clip\" {{", TexturePD.uniqueID, TexturePD.Text); + ob.AppendFormat("\n\tVideo: 8{0}, \"Video::{1}\", \"Clip\" {{", TexturePD.uniqueID, TexturePD.Text); ob.Append("\n\t\tType: \"Clip\""); ob.Append("\n\t\tProperties70: {"); ob.AppendFormat("\n\t\t\tP: \"Path\", \"KString\", \"XRefUrl\", \"\", \"{0}\"", texPath); @@ -2367,7 +2385,7 @@ namespace Unity_Studio //connect video to texture cb.AppendFormat("\n\n\t;Video::{0}, Texture::{0}", TexturePD.Text); - cb.AppendFormat("\n\tC: \"OO\",1{0},{1}", TexturePD.uniqueID, TexturePD.uniqueID); + cb.AppendFormat("\n\tC: \"OO\",8{0},7{1}", TexturePD.uniqueID, TexturePD.uniqueID); } #endregion @@ -2388,7 +2406,7 @@ namespace Unity_Studio { StatusStripUpdate("Writing Geometry: " + m_Mesh.m_Name); - ob.AppendFormat("\n\tGeometry: {0}, \"Geometry::\", \"Mesh\" {{", MeshID); + ob.AppendFormat("\n\tGeometry: 3{0}, \"Geometry::\", \"Mesh\" {{", MeshID); ob.Append("\n\t\tProperties70: {"); var randomColor = RandomColorGenerator(m_Mesh.m_Name); ob.AppendFormat("\n\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",{0},{1},{2}", ((float)randomColor[0] / 255), ((float)randomColor[1] / 255), ((float)randomColor[2] / 255));