2 Commits

Author SHA1 Message Date
Radu
ac864c31f3 Update README.md 2015-11-20 22:18:23 +02:00
Radu
1f2635c877 - 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
2015-11-13 14:45:39 +02:00
4 changed files with 168 additions and 80 deletions

View File

@@ -1,6 +1,6 @@
**Unity Studio** is a tool meant for exploring, extracting and exporting assets from Unity games and apps. **Unity Studio** is a tool meant for exploring, extracting and exporting assets from Unity games and apps.
It was built upon a lot of research and reverse engineering, with more than 400 apps and games tested from every version and every platform. It was built on a few years of research and reverse engineering, with more than 400 apps and games tested from every version and every platform.
As such, it is compatible with Unity builds starting from 2.5.0 up until 5.2.2, the latest version to date, and platforms ranging from Web, PC, Linux, MacOS to Xbox360, PS3, Android and iOS. As such, it is compatible with Unity builds starting from 2.5.0 up until 5.2.2, the latest version to date, and platforms ranging from Web, PC, Linux, MacOS to Xbox360, PS3, Android and iOS.
#### Current features #### Current features

View File

@@ -23,6 +23,7 @@ namespace Unity_Studio
exportColors.Checked = (bool)Properties.Settings.Default["exportColors"]; exportColors.Checked = (bool)Properties.Settings.Default["exportColors"];
exportDeformers.Checked = (bool)Properties.Settings.Default["exportDeformers"]; exportDeformers.Checked = (bool)Properties.Settings.Default["exportDeformers"];
convertDummies.Checked = (bool)Properties.Settings.Default["convertDummies"]; convertDummies.Checked = (bool)Properties.Settings.Default["convertDummies"];
convertDummies.Enabled = (bool)Properties.Settings.Default["exportDeformers"];
scaleFactor.Value = (decimal)Properties.Settings.Default["scaleFactor"]; scaleFactor.Value = (decimal)Properties.Settings.Default["scaleFactor"];
upAxis.SelectedIndex = (int)Properties.Settings.Default["upAxis"]; upAxis.SelectedIndex = (int)Properties.Settings.Default["upAxis"];
showExpOpt.Checked = (bool)Properties.Settings.Default["showExpOpt"]; showExpOpt.Checked = (bool)Properties.Settings.Default["showExpOpt"];

View File

@@ -113,7 +113,7 @@ namespace Unity_Studio
public List<BoneInfluence>[] m_Skin; public List<BoneInfluence>[] m_Skin;
//public Dictionary<int, float>[] m_Skin; //public Dictionary<int, float>[] m_Skin;
public float[][,] m_BindPose; public float[][,] m_BindPose;
public uint m_VertexCount; public int m_VertexCount;
public float[] m_Vertices; public float[] m_Vertices;
public float[] m_Normals; public float[] m_Normals;
public float[] m_Colors; public float[] m_Colors;
@@ -159,7 +159,7 @@ namespace Unity_Studio
public class PackedBitVector public class PackedBitVector
{ {
public uint m_NumItems; public int m_NumItems;
public float m_Range = 1.0f; public float m_Range = 1.0f;
public float m_Start = 0.0f; public float m_Start = 0.0f;
public byte[] m_Data; public byte[] m_Data;
@@ -392,8 +392,7 @@ namespace Unity_Studio
} }
#endregion #endregion
#region BlendShapeData #region BlendShapeData for 4.1.0 to 4.2.x, excluding 4.1.0 alpha
#region 4.1.0 to 4.2.x, excluding 4.1.0 alpha
if (version[0] == 4 && ((version[1] == 1 && MeshPD.sourceFile.buildType[0] != "a") || if (version[0] == 4 && ((version[1] == 1 && MeshPD.sourceFile.buildType[0] != "a") ||
(version[1] > 1 && version[1] <= 2))) (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 a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index
} }
#endregion #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)) else if (version[0] >= 5 || (version[0] == 4 && version[1] >= 3))
{ {
int m_ShapeVertices_size = a_Stream.ReadInt32(); int m_ShapeVertices_size = a_Stream.ReadInt32();
@@ -451,7 +450,6 @@ namespace Unity_Studio
uint m_RootBoneNameHash = a_Stream.ReadUInt32(); uint m_RootBoneNameHash = a_Stream.ReadUInt32();
} }
#endregion #endregion
#endregion
#region Index Buffer for 2.6.0 and later #region Index Buffer for 2.6.0 and later
if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) 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 #region Vertex Buffer for 3.4.2 and earlier
if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) 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]; m_Vertices = new float[m_VertexCount * 3];
for (int v = 0; v < m_VertexCount * 3; v++) { m_Vertices[v] = a_Stream.ReadSingle(); } 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 BitArray m_CurrentChannels = new BitArray(new int[1] { a_Stream.ReadInt32() });
m_VertexCount = a_Stream.ReadUInt32(); 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 (version[0] < 4)
{ {
if (m_MeshCompression != 0 && version[2] == 0) //special case not just on platform 9 if (m_MeshCompression != 0 && version[2] == 0) //special case not just on platform 9
@@ -607,10 +605,11 @@ namespace Unity_Studio
} }
} }
#endregion #endregion
#region 4.0.0 and later #region channels and streams for 4.0.0 and later
else 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()]; m_Channels = new ChannelInfo[a_Stream.ReadInt32()];
for (int c = 0; c < m_Channels.Length; c++) for (int c = 0; c < m_Channels.Length; c++)
@@ -622,7 +621,9 @@ namespace Unity_Studio
m_Channels[c].dimension = a_Stream.ReadByte(); m_Channels[c].dimension = a_Stream.ReadByte();
//calculate stride for Unity 5 //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) if (version[0] < 5)
@@ -638,13 +639,21 @@ namespace Unity_Studio
m_Streams[s].frequency = a_Stream.ReadUInt16(); 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 = new StreamInfo[streamCount];
m_Streams[0] = new StreamInfo(); for (int s = 0; s < streamCount; s++)
m_Streams[0].channelMask = new BitArray(new int[1] { m_CurrentChannels }); {
m_Streams[0].offset = 0; m_Streams[s] = new StreamInfo();
m_Streams[0].stride = singleStreamStride; 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 #endregion
@@ -672,7 +681,8 @@ namespace Unity_Studio
for (int b = 0; b < 8; b++) 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 // 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; } 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_Stream.channelMask.Set(b, false);
m_CurrentChannels.Set(b, false);
componentBytes = null; componentBytes = null;
componentsArray = null; componentsArray = null;
break; //go to next channel break; //go to next channel
@@ -810,8 +821,10 @@ namespace Unity_Studio
if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6))
{ {
//remember there can be combinations of packed and regular vertex properties //remember there can be combinations of packed and regular vertex properties
#region m_Vertices
PackedBitVector m_Vertices_Packed = new PackedBitVector(); 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_Range = a_Stream.ReadSingle();
m_Vertices_Packed.m_Start = a_Stream.ReadSingle(); m_Vertices_Packed.m_Start = a_Stream.ReadSingle();
m_Vertices_Packed.m_Data = new byte[a_Stream.ReadInt32()]; 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]; m_Vertices = new float[m_Vertices_Packed.m_NumItems];
for (int v = 0; v < m_Vertices_Packed.m_NumItems; v++) 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 #region m_UV
m_UV_Packed.m_NumItems = a_Stream.ReadUInt32(); 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_Range = a_Stream.ReadSingle();
m_UV_Packed.m_Start = a_Stream.ReadSingle(); m_UV_Packed.m_Start = a_Stream.ReadSingle();
m_UV_Packed.m_Data = new byte[a_Stream.ReadInt32()]; 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++) 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) if (m_UV_Packed.m_NumItems >= m_VertexCount * 4)
@@ -861,7 +876,7 @@ namespace Unity_Studio
m_UV2 = new float[m_VertexCount * 2]; m_UV2 = new float[m_VertexCount * 2];
for (uint v = 0; v < m_VertexCount * 2; v++) 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) if (m_UV_Packed.m_NumItems >= m_VertexCount * 6)
@@ -869,7 +884,7 @@ namespace Unity_Studio
m_UV3 = new float[m_VertexCount * 2]; m_UV3 = new float[m_VertexCount * 2];
for (uint v = 0; v < m_VertexCount * 2; v++) 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) if (m_UV_Packed.m_NumItems == m_VertexCount * 8)
@@ -877,17 +892,19 @@ namespace Unity_Studio
m_UV4 = new float[m_VertexCount * 2]; m_UV4 = new float[m_VertexCount * 2];
for (uint v = 0; v < m_VertexCount * 2; v++) 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) if (version[0] < 5)
{ {
PackedBitVector m_BindPoses_Packed = new PackedBitVector(); 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_Range = a_Stream.ReadSingle();
m_BindPoses_Packed.m_Start = a_Stream.ReadSingle(); m_BindPoses_Packed.m_Start = a_Stream.ReadSingle();
m_BindPoses_Packed.m_Data = new byte[a_Stream.ReadInt32()]; m_BindPoses_Packed.m_Data = new byte[a_Stream.ReadInt32()];
@@ -895,10 +912,32 @@ namespace Unity_Studio
a_Stream.AlignStream(4); a_Stream.AlignStream(4);
m_BindPoses_Packed.m_BitSize = a_Stream.ReadByte(); m_BindPoses_Packed.m_BitSize = a_Stream.ReadByte();
a_Stream.Position += 3; //4 byte alignment 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(); 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_Range = a_Stream.ReadSingle();
m_Normals_Packed.m_Start = a_Stream.ReadSingle(); m_Normals_Packed.m_Start = a_Stream.ReadSingle();
m_Normals_Packed.m_Data = new byte[a_Stream.ReadInt32()]; m_Normals_Packed.m_Data = new byte[a_Stream.ReadInt32()];
@@ -908,7 +947,7 @@ namespace Unity_Studio
a_Stream.Position += 3; //4 byte alignment a_Stream.Position += 3; //4 byte alignment
PackedBitVector m_Tangents_Packed = new PackedBitVector(); 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_Range = a_Stream.ReadSingle();
m_Tangents_Packed.m_Start = a_Stream.ReadSingle(); m_Tangents_Packed.m_Start = a_Stream.ReadSingle();
m_Tangents_Packed.m_Data = new byte[a_Stream.ReadInt32()]; 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(); m_Tangents_Packed.m_BitSize = a_Stream.ReadByte();
a_Stream.Position += 3; //4 byte alignment a_Stream.Position += 3; //4 byte alignment
PackedBitVector m_Weights_Packed = new PackedBitVector(); PackedBitVector m_Weights = new PackedBitVector();
m_Weights_Packed.m_NumItems = a_Stream.ReadUInt32(); m_Weights.m_NumItems = a_Stream.ReadInt32();
m_Weights_Packed.m_Data = new byte[a_Stream.ReadInt32()]; m_Weights.m_Data = new byte[a_Stream.ReadInt32()];
a_Stream.Read(m_Weights_Packed.m_Data, 0, m_Weights_Packed.m_Data.Length); a_Stream.Read(m_Weights.m_Data, 0, m_Weights.m_Data.Length);
a_Stream.AlignStream(4); 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 a_Stream.Position += 3; //4 byte alignment
#region m_Normals
PackedBitVector m_NormalSigns_packed = new PackedBitVector(); 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()]; 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.Read(m_NormalSigns_packed.m_Data, 0, m_NormalSigns_packed.m_Data.Length);
a_Stream.AlignStream(4); a_Stream.AlignStream(4);
@@ -948,9 +988,11 @@ namespace Unity_Studio
if (m_NormalSigns[v] == 0) { m_Normals[v * 3 + 2] *= -1; } if (m_NormalSigns[v] == 0) { m_Normals[v * 3 + 2] *= -1; }
} }
} }
#endregion
#region m_Tangents
PackedBitVector m_TangentSigns_packed = new PackedBitVector(); 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()]; 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.Read(m_TangentSigns_packed.m_Data, 0, m_TangentSigns_packed.m_Data.Length);
a_Stream.AlignStream(4); a_Stream.AlignStream(4);
@@ -972,11 +1014,13 @@ namespace Unity_Studio
if (m_TangentSigns[v] == 0) { m_Tangents[v * 3 + 2] *= -1; } if (m_TangentSigns[v] == 0) { m_Tangents[v * 3 + 2] *= -1; }
} }
} }
#endregion
#region m_FloatColors
if (version[0] >= 5) if (version[0] >= 5)
{ {
PackedBitVector m_FloatColors = new PackedBitVector(); 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_Range = a_Stream.ReadSingle();
m_FloatColors.m_Start = a_Stream.ReadSingle(); m_FloatColors.m_Start = a_Stream.ReadSingle();
m_FloatColors.m_Data = new byte[a_Stream.ReadInt32()]; 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(); 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()]; m_BoneIndices.m_Data = new byte[a_Stream.ReadInt32()];
a_Stream.Read(m_BoneIndices.m_Data, 0, m_BoneIndices.m_Data.Length); a_Stream.Read(m_BoneIndices.m_Data, 0, m_BoneIndices.m_Data.Length);
a_Stream.AlignStream(4); a_Stream.AlignStream(4);
m_BoneIndices.m_BitSize = a_Stream.ReadByte(); m_BoneIndices.m_BitSize = a_Stream.ReadByte();
a_Stream.Position += 3; //4 byte alignment 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<BoneInfluence>[m_BoneIndices.m_NumItems / 4];
for (int s = 0; s < m_Skin.Length; s++)
{
m_Skin[s] = new List<BoneInfluence>();
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(); 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()]; m_Triangles.m_Data = new byte[a_Stream.ReadInt32()];
a_Stream.Read(m_Triangles.m_Data, 0, m_Triangles.m_Data.Length); a_Stream.Read(m_Triangles.m_Data, 0, m_Triangles.m_Data.Length);
a_Stream.AlignStream(4); a_Stream.AlignStream(4);
@@ -1039,7 +1107,7 @@ namespace Unity_Studio
if (version[0] < 5) if (version[0] < 5)
{ {
PackedBitVector m_Colors_Packed = new PackedBitVector(); 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()]; 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.Read(m_Colors_Packed.m_Data, 0, m_Colors_Packed.m_Data.Length);
a_Stream.AlignStream(4); 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 a_Stream.Position += 24; //Axis-Aligned Bounding Box
} }

View File

@@ -619,7 +619,7 @@ namespace Unity_Studio
var fileGen = assetsFile.fileGen; var fileGen = assetsFile.fileGen;
//var m_version = assetsFile.m_version; //var m_version = assetsFile.m_version;
var version = assetsFile.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)); //ListViewGroup assetGroup = new ListViewGroup(Path.GetFileName(assetsFile.filePath));
@@ -1684,6 +1684,19 @@ namespace Unity_Studio
HashSet<AssetPreloadData> Textures = new HashSet<AssetPreloadData>(); HashSet<AssetPreloadData> Textures = new HashSet<AssetPreloadData>();
int DeformerCount = 0; 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 #region loop nodes and collect objects for export
foreach (var assetsFile in assetsfileList) foreach (var assetsFile in assetsfileList)
@@ -1705,8 +1718,10 @@ namespace Unity_Studio
{ {
Meshes.Add(MeshPD); 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\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); Materials.Add(MaterialPD);
cb2.AppendFormat("\n\n\t;Material::, Model::{0}", m_GameObject.m_Name); 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); Materials.Add(MaterialPD);
cb2.AppendFormat("\n\n\t;Material::, Model::{0}", m_GameObject.m_Name); 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); 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\tVersion: 102");
mb.Append("\n\t\tShadingModel: \"phong\""); mb.Append("\n\t\tShadingModel: \"phong\"");
mb.Append("\n\t\tMultiLayer: 0"); mb.Append("\n\t\tMultiLayer: 0");
@@ -1859,8 +1874,8 @@ namespace Unity_Studio
foreach (var m_TexEnv in m_Material.m_TexEnvs) foreach (var m_TexEnv in m_Material.m_TexEnvs)
{ {
AssetPreloadData TexturePD; AssetPreloadData TexturePD;
if (assetsfileList.TryGetPD(m_TexEnv.m_Texture, out TexturePD)) { } #region get Porsche material from json
else if (jsonMats != null) if (!assetsfileList.TryGetPD(m_TexEnv.m_Texture, out TexturePD) && jsonMats != null)
{ {
Dictionary<string, string> matProp; Dictionary<string, string> matProp;
if (jsonMats.TryGetValue(m_Material.m_Name, out 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); Textures.Add(TexturePD);
cb2.AppendFormat("\n\n\t;Texture::, Material::{0}", m_Material.m_Name); 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) switch (m_TexEnv.name)
{ {
case "_MainTex": case "_MainTex":
@@ -2032,14 +2049,13 @@ namespace Unity_Studio
{ {
if (m_GameObject.m_MeshFilter == null && m_GameObject.m_SkinnedMeshRenderer == null) 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)) 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.AppendFormat("\n\tNodeAttribute: 2{0}, \"NodeAttribute::\", \"LimbNode\" {{", m_GameObject.uniqueID);
ob.Append("\n\t\tTypeFlags: \"Skeleton\""); ob.Append("\n\t\tTypeFlags: \"Skeleton\"");
ob.Append("\n\t}"); 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 else
{ {
@@ -2047,16 +2063,16 @@ namespace Unity_Studio
ob.Append("\n\t\tTypeFlags: \"Null\""); ob.Append("\n\t\tTypeFlags: \"Null\"");
ob.Append("\n\t}"); 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 //connect NodeAttribute to Model
cb.AppendFormat("\n\n\t;NodeAttribute::, Model::{0}", m_GameObject.m_Name); 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 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"); ob.Append("\n\t\tVersion: 232");
@@ -2086,12 +2102,12 @@ namespace Unity_Studio
if (GameObjects.Contains(parentObject)) if (GameObjects.Contains(parentObject))
{ {
cb.AppendFormat("\n\n\t;Model::{0}, Model::{1}", m_GameObject.m_Name, parentObject.m_Name); 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 else
{ {
cb.AppendFormat("\n\n\t;Model::{0}, Model::RootNode", m_GameObject.m_Name); 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(); } { FBXwriter.Write(ob); ob.Clear(); }
cb2.AppendFormat("\n\n\t;Geometry::, Model::{0}", m_GameObject.m_Name); 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"]) if ((bool)Properties.Settings.Default["exportDeformers"])
{ {
//add BindPose node //add BindPose node
pb.Append("\n\t\tPoseNode: {"); 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\tMatrix: *16 {");
//pb.Append("\n\t\t\t\ta: "); //pb.Append("\n\t\t\t\ta: ");
//pb.Append("\n\t\t\t} "); //pb.Append("\n\t\t\t} ");
pb.Append("\n\t\t}"); pb.Append("\n\t\t}");
//write DisplayLayer with SkinnedMeshRenderer ID preceded by "3" ob.AppendFormat("\n\tCollectionExclusive: 5{0}, \"DisplayLayer::{1}\", \"DisplayLayer\" {{", SkinnedMeshPD.uniqueID, m_GameObject.m_Name);
ob.AppendFormat("\n\tCollectionExclusive: 3{0}, \"DisplayLayer::{0}\", \"DisplayLayer\" {{", SkinnedMeshPD.uniqueID);
ob.Append("\n\t\tProperties70: {"); ob.Append("\n\t\tProperties70: {");
ob.Append("\n\t\t}"); ob.Append("\n\t\t}");
ob.Append("\n\t}"); ob.Append("\n\t}");
//connect Model to DisplayLayer //connect Model to DisplayLayer
cb2.AppendFormat("\n\n\t;Model::{0}, DisplayLayer::", m_GameObject.m_Name); 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 //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 //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\tVersion: 101");
ob.Append("\n\t\tLink_DeformAcuracy: 50"); ob.Append("\n\t\tLink_DeformAcuracy: 50");
ob.Append("\n\t}"); //Deformer end ob.Append("\n\t}"); //Deformer end
//connect Skin Deformer to Geometry //connect Skin Deformer to Geometry
cb2.Append("\n\t;Deformer::, Geometry::"); cb2.Append("\n\n\t;Deformer::, Geometry::");
cb2.AppendFormat("\n\tC: \"OO\",{0},{1}", SkinnedMeshPD.uniqueID, MeshPD.uniqueID); cb2.AppendFormat("\n\tC: \"OO\",4{0},3{1}", SkinnedMeshPD.uniqueID, MeshPD.uniqueID);
for (int b = 0; b < m_SkinnedMeshRenderer.m_Bones.Length; b++) for (int b = 0; b < m_SkinnedMeshRenderer.m_Bones.Length; b++)
{ {
@@ -2225,8 +2240,8 @@ namespace Unity_Studio
wb.Length--;//remove last comma wb.Length--;//remove last comma
} }
//SubDeformer objects need unique IDs because 2 or more deformers can be attached to the same bone //SubDeformer objects need unique IDs because 2 or more deformers can be linked to the same bone
ob.AppendFormat("\n\tDeformer: 1{0}{1}, \"SubDeformer::\", \"Cluster\" {{", b, SkinnedMeshPD.uniqueID); ob.AppendFormat("\n\tDeformer: 4{0}{1}, \"SubDeformer::\", \"Cluster\" {{", b, SkinnedMeshPD.uniqueID);
ob.Append("\n\t\tVersion: 100"); ob.Append("\n\t\tVersion: 100");
ob.Append("\n\t\tUserData: \"\", \"\""); ob.Append("\n\t\tUserData: \"\", \"\"");
@@ -2253,15 +2268,19 @@ namespace Unity_Studio
//connect SubDeformer to Skin Deformer //connect SubDeformer to Skin Deformer
cb2.Append("\n\n\t;SubDeformer::, 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\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 //add BindPose node
pb.Append("\n\t\tPoseNode: {"); 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\tMatrix: *16 {");
//pb.Append("\n\t\t\t\ta: "); //pb.Append("\n\t\t\t\ta: ");
//pb.Append("\n\t\t\t} "); //pb.Append("\n\t\t\t} ");
@@ -2342,7 +2361,7 @@ namespace Unity_Studio
} }
#endregion #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\tType: \"TextureVideoClip\"");
ob.Append("\n\t\tVersion: 202"); ob.Append("\n\t\tVersion: 202");
ob.AppendFormat("\n\t\tTextureName: \"Texture::{0}\"", TexturePD.Text); 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.AppendFormat("\n\t\tRelativeFilename: \"Texture2D\\{0}\"", Path.GetFileName(texPath));
ob.Append("\n\t}"); ob.Append("\n\t}");
//Video ID is prefixed by 1 ob.AppendFormat("\n\tVideo: 8{0}, \"Video::{1}\", \"Clip\" {{", TexturePD.uniqueID, TexturePD.Text);
ob.AppendFormat("\n\tVideo: 1{0}, \"Video::{1}\", \"Clip\" {{", TexturePD.uniqueID, TexturePD.Text);
ob.Append("\n\t\tType: \"Clip\""); ob.Append("\n\t\tType: \"Clip\"");
ob.Append("\n\t\tProperties70: {"); ob.Append("\n\t\tProperties70: {");
ob.AppendFormat("\n\t\t\tP: \"Path\", \"KString\", \"XRefUrl\", \"\", \"{0}\"", texPath); ob.AppendFormat("\n\t\t\tP: \"Path\", \"KString\", \"XRefUrl\", \"\", \"{0}\"", texPath);
@@ -2367,7 +2385,7 @@ namespace Unity_Studio
//connect video to texture //connect video to texture
cb.AppendFormat("\n\n\t;Video::{0}, Texture::{0}", TexturePD.Text); 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 #endregion
@@ -2388,7 +2406,7 @@ namespace Unity_Studio
{ {
StatusStripUpdate("Writing Geometry: " + m_Mesh.m_Name); 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: {"); ob.Append("\n\t\tProperties70: {");
var randomColor = RandomColorGenerator(m_Mesh.m_Name); 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)); ob.AppendFormat("\n\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",{0},{1},{2}", ((float)randomColor[0] / 255), ((float)randomColor[1] / 255), ((float)randomColor[2] / 255));