hamish-milne / FbxWriter

An FBX reader and writer for .NET
174 stars 44 forks source link

FBXDocument Reader and Writer are incompatible WRT byte data #8

Open kianzarrin opened 3 years ago

kianzarrin commented 3 years ago

Intro:

I am trying to dump unity mesh as fbx binary. I successfully managed to dump the mesh as fbxascii using code from https://github.com/KellanHiggins/UnityFBXExporter then I executed this code:

string ascii =  UnityFBXExporter.FBXExporter.MeshToString(gameObject,"");
var reader = new FbxAsciiReader(ascii.ToStream()); 
FbxDocument doc = reader.Read();
FbxIO.WriteBinary(doc, path)

Stream ToStream(this string val) => new MemoryStream(Encoding.UTF8.GetBytes(val))

problem:

I got this error

FbxException: Invalid property type System.Byte, at Month/CreationTimeStamp/FBXHeaderExtension[0]
  at Fbx.FbxBinaryWriter.WriteProperty (System.Object obj, Int32 id) [0x00027] in \FbxUtil\FbxWriter\FbxBinaryWriter.cs:155 
  at Fbx.FbxBinaryWriter.WriteNode (Fbx.FbxDocument document, Fbx.FbxNode node) [0x001a9] in \FbxUtil\FbxWriter\FbxBinaryWriter.cs:212 
  at Fbx.FbxBinaryWriter.WriteNode (Fbx.FbxDocument document, Fbx.FbxNode node) [0x0028a] in \FbxUtil\FbxWriter\FbxBinaryWriter.cs:229 
  at Fbx.FbxBinaryWriter.WriteNode (Fbx.FbxDocument document, Fbx.FbxNode node) [0x0028a] in \FbxUtil\FbxWriter\FbxBinaryWriter.cs:229 
  at Fbx.FbxBinaryWriter.Write (Fbx.FbxDocument document) [0x0005a] in \FbxUtil\FbxWriter\FbxBinaryWriter.cs:259 
  at Fbx.FbxIO.WriteBinary (Fbx.FbxDocument document, System.String path) [0x00024] in \FbxUtil\FbxWriter\FbxIO.cs:57 
...

the writer does not handle byte : https://github.com/Ploaj/IONET/blob/ca42ce6c9cadaf73312cc3cbe73f94e7feed509c/IONET/Fbx/IO/FbxBinaryWriter.cs#L54

but the reader does read as byte : https://github.com/Ploaj/IONET/blob/ca42ce6c9cadaf73312cc3cbe73f94e7feed509c/IONET/Fbx/IO/FbxAsciiReader.cs#L229

So this is problem number 1. writer does not handle byte produced by reader.

Problem 2:

I looked at the code that generates the ascii code and I found this (which matches the error message):

// Creationg Date Stamp
System.DateTime currentDate = System.DateTime.Now;
sb.AppendLine("\tCreationTimeStamp:  {");
sb.AppendLine("\t\tVersion: 1000");
sb.AppendLine("\t\tYear: " + currentDate.Year);
sb.AppendLine("\t\tMonth: " + currentDate.Month); // <----!!!!!!! type of Month is int !!!!!!!!!
sb.AppendLine("\t\tDay: " + currentDate.Day);
sb.AppendLine("\t\tHour: " + currentDate.Hour);
sb.AppendLine("\t\tMinute: " + currentDate.Minute);
sb.AppendLine("\t\tSecond: " + currentDate.Second);
sb.AppendLine("\t\tMillisecond: " + currentDate.Millisecond);
sb.AppendLine("\t}");

if the written type is int then why the time that is read is byte? i guess because the data was small?

Solution

So I think the solution would be that the reader should treat byte as int?

                { typeof(byte), new WriterInfo('I', (sw, obj) => sw.Write((int)(byte)obj)) }, // write as int
                { typeof(int),  new WriterInfo('I', (sw, obj) => sw.Write((int)obj)) },

or should I write is as byte?

                { typeof(byte), new WriterInfo('B', (sw, obj) => sw.Write((byte)obj)) }, // write as bye
                { typeof(int),  new WriterInfo('I', (sw, obj) => sw.Write((int)obj)) },

Please fix this issue.

kianzarrin commented 3 years ago

btw does your library capable of producing binary fbx directly from unity without the need to use UnityFBXExporter.FBXExporter.MeshToString?

kianzarrin commented 3 years ago

I also had to add a special case here to read byte https://github.com/hamish-milne/FbxWriter/blob/53d9479af87639307b7443bae70ca0c8cc58e48d/Fbx/FbxBinary.cs#L103

that solved all the exceptions.

but I still cannot open the generated file even though I can open the original ascii fbx files.zip

can you please tell me what I should do? .

kianzarrin commented 3 years ago

I wrote this code to understand where is the problem:

            var doc = FbxIO.ReadAscii(dir + file1);
            string fileA = "testA_" + file1;
            FbxIO.WriteAscii(doc, dir + fileA);

            doc = FbxIO.ReadAscii(dir + fileA);
            string fileB = "testB_" + file1;
            FbxIO.WriteBinary(doc, dir + fileB); // i can't open this

            doc = FbxIO.ReadBinary(dir + fileB);
            FbxIO.WriteAscii(doc, dir + "testC_" + file1); // i can open this

the code does not throw an exception (after the fixes I made to FbxWriter). I tried view the files using FBX viewer https://overbits.herokuapp.com/fbxgltf/ using the FBX viewer above I can open the ascii outputs but not the binary outputs. if I read the binary output and write it again as ascii then I can view it again.

blender gave me the following error when I opened the binary fbx file image

kianzarrin commented 3 years ago

I converted the ascii fbx to binary fbx with this tool and it worked: https://github.com/BobbyAnguelov/FbxFormatConverter unfortunately, it's in c. I need in c#

I ran this test to gain more debugging info:

            string file1 = "RoadMediumNode.binary.fbx"; // can open this

            var doc = FbxIO.ReadBinary(dir + file1); 
            string fileA = "testA_" + file1;
            FbxIO.WriteBinary(doc, dir + fileA); // can open this

            doc = FbxIO.ReadBinary(dir + file1);
            string fileB = "testB_" + file1;
            FbxIO.WriteAscii(doc, dir + fileB); // can open this

            doc = FbxIO.ReadAscii(dir + fileB);
            FbxIO.WriteBinary(doc, dir + "testC_" + file1);  // can' open this

read working binary fbx -> write as binary fbx -> works read working ascii fbx created FbxFormatConverter -> write as binary fbx -> does not work.

conclusion: I am suspecting that the bug is an incompatibility between ascii reader and binary writer. Note that I ran these tests after applying the fixes I suggested in the comments bellow