Forráskód Böngészése

Export from babylon to glb format

noalak 8 éve
szülő
commit
b739412559

+ 6 - 0
Exporters/3ds Max/GltfExport.Entities/GLTF.cs

@@ -58,6 +58,12 @@ namespace GLTFExport.Entities
         public List<GLTFImage> ImagesList { get; private set; }
         public List<GLTFSampler> SamplersList { get; private set; }
 
+        public GLTFBuffer buffer;
+        public GLTFBufferView bufferViewScalar;
+        public GLTFBufferView bufferViewFloatVec3;
+        public GLTFBufferView bufferViewFloatVec4;
+        public GLTFBufferView bufferViewFloatVec2;
+
         public GLTF(string outputPath)
         {
             OutputPath = outputPath;

+ 4 - 1
Exporters/3ds Max/GltfExport.Entities/GLTFBuffer.cs

@@ -1,4 +1,5 @@
-using System.Runtime.Serialization;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
 
 namespace GLTFExport.Entities
 {
@@ -10,5 +11,7 @@ namespace GLTFExport.Entities
 
         [DataMember(IsRequired = true)]
         public int byteLength { get; set; }
+
+        public List<byte> bytesList;
     }
 }

+ 3 - 1
Exporters/3ds Max/GltfExport.Entities/GLTFBufferView.cs

@@ -1,4 +1,5 @@
-using System.Runtime.Serialization;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
 
 namespace GLTFExport.Entities
 {
@@ -18,5 +19,6 @@ namespace GLTFExport.Entities
         public int? byteStride { get; set; }
 
         public GLTFBuffer Buffer;
+        public List<byte> bytesList = new List<byte>();
     }
 }

+ 103 - 75
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Mesh.cs

@@ -92,64 +92,89 @@ namespace Max2Babylon
             gltfMesh.idGroupInstance = babylonMesh.idGroupInstance;
 
             // Buffer
-            var buffer = new GLTFBuffer
+            var buffer = gltf.buffer;
+            if (buffer == null)
             {
-                uri = gltfMesh.name + ".bin"
-            };
-            buffer.index = gltf.BuffersList.Count;
-            gltf.BuffersList.Add(buffer);
+                buffer = new GLTFBuffer
+                {
+                    uri = gltfMesh.name + ".bin"
+                };
+                buffer.index = gltf.BuffersList.Count;
+                gltf.BuffersList.Add(buffer);
+                gltf.buffer = buffer;
+            }
 
             // BufferView - Scalar
-            var bufferViewScalar = new GLTFBufferView
+            var bufferViewScalar = gltf.bufferViewScalar;
+            if (bufferViewScalar == null)
             {
-                name = "bufferViewScalar",
-                buffer = buffer.index,
-                Buffer = buffer
-            };
-            bufferViewScalar.index = gltf.BufferViewsList.Count;
-            gltf.BufferViewsList.Add(bufferViewScalar);
+                bufferViewScalar = new GLTFBufferView
+                {
+                    name = "bufferViewScalar",
+                    buffer = buffer.index,
+                    Buffer = buffer
+                };
+                bufferViewScalar.index = gltf.BufferViewsList.Count;
+                gltf.BufferViewsList.Add(bufferViewScalar);
+                gltf.bufferViewScalar = bufferViewScalar;
+            }
 
             // BufferView - Vector3
-            var bufferViewFloatVec3 = new GLTFBufferView
+            var bufferViewFloatVec3 = gltf.bufferViewFloatVec3;
+            if (bufferViewFloatVec3 == null)
             {
-                name = "bufferViewFloatVec3",
-                buffer = buffer.index,
-                Buffer = buffer,
-                byteOffset = 0,
-                byteStride = 12 // Field only defined for buffer views that contain vertex attributes. A vertex needs 3 * 4 bytes
-            };
-            bufferViewFloatVec3.index = gltf.BufferViewsList.Count;
-            gltf.BufferViewsList.Add(bufferViewFloatVec3);
+                bufferViewFloatVec3 = new GLTFBufferView
+                {
+                    name = "bufferViewFloatVec3",
+                    buffer = buffer.index,
+                    Buffer = buffer,
+                    byteOffset = 0,
+                    byteStride = 12 // Field only defined for buffer views that contain vertex attributes. A vertex needs 3 * 4 bytes
+                };
+                bufferViewFloatVec3.index = gltf.BufferViewsList.Count;
+                gltf.BufferViewsList.Add(bufferViewFloatVec3);
+                gltf.bufferViewFloatVec3 = bufferViewFloatVec3;
+            }
 
             // BufferView - Vector4
             GLTFBufferView bufferViewFloatVec4 = null;
             if (hasColor)
             {
-                bufferViewFloatVec4 = new GLTFBufferView
+                bufferViewFloatVec4 = gltf.bufferViewFloatVec4;
+                if (bufferViewFloatVec4 == null)
                 {
-                    name = "bufferViewFloatVec4",
-                    buffer = buffer.index,
-                    Buffer = buffer,
-                    byteOffset = 0,
-                    byteStride = 16 // Field only defined for buffer views that contain vertex attributes. A vertex needs 4 * 4 bytes
-                };
-                bufferViewFloatVec4.index = gltf.BufferViewsList.Count;
-                gltf.BufferViewsList.Add(bufferViewFloatVec4);
+                    bufferViewFloatVec4 = new GLTFBufferView
+                    {
+                        name = "bufferViewFloatVec4",
+                        buffer = buffer.index,
+                        Buffer = buffer,
+                        byteOffset = 0,
+                        byteStride = 16 // Field only defined for buffer views that contain vertex attributes. A vertex needs 4 * 4 bytes
+                    };
+                    bufferViewFloatVec4.index = gltf.BufferViewsList.Count;
+                    gltf.BufferViewsList.Add(bufferViewFloatVec4);
+                    gltf.bufferViewFloatVec4 = bufferViewFloatVec4;
+                }
             }
 
             // BufferView - Vector2
             GLTFBufferView bufferViewFloatVec2 = null;
             if (hasUV || hasUV2)
             {
-                bufferViewFloatVec2 = new GLTFBufferView
+                bufferViewFloatVec2 = gltf.bufferViewFloatVec2;
+                if (bufferViewFloatVec2 == null)
                 {
-                    name = "bufferViewFloatVec2",
-                    buffer = buffer.index,
-                    Buffer = buffer,
-                    byteStride = 8 // Field only defined for buffer views that contain vertex attributes. A vertex needs 2 * 4 bytes
-                };
-                bufferViewFloatVec2.index = gltf.BufferViewsList.Count;
-                gltf.BufferViewsList.Add(bufferViewFloatVec2);
+                    bufferViewFloatVec2 = new GLTFBufferView
+                    {
+                        name = "bufferViewFloatVec2",
+                        buffer = buffer.index,
+                        Buffer = buffer,
+                        byteStride = 8 // Field only defined for buffer views that contain vertex attributes. A vertex needs 2 * 4 bytes
+                    };
+                    bufferViewFloatVec2.index = gltf.BufferViewsList.Count;
+                    gltf.BufferViewsList.Add(bufferViewFloatVec2);
+                    gltf.bufferViewFloatVec2 = bufferViewFloatVec2;
+                }
             }
 
             // --------------------------
@@ -391,51 +416,54 @@ namespace Max2Babylon
             // --------- Saving ---------
             // --------------------------
 
-            string outputBinaryFile = Path.Combine(gltf.OutputPath, gltfMesh.name + ".bin");
-            RaiseMessage("GLTFExporter.Mesh | Saving " + outputBinaryFile, 2);
+            RaiseMessage("GLTFExporter.Mesh | saving", 2);
 
-            // Write data to binary file
-            using (BinaryWriter writer = new BinaryWriter(File.Open(outputBinaryFile, FileMode.Create)))
+            // BufferView - Scalar
+            gltfIndices.ForEach(n => bufferViewScalar.bytesList.AddRange(BitConverter.GetBytes(n)));
+
+            // BufferView - Vector3
+            globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
             {
-                // BufferView - Scalar
-                gltfIndices.ForEach(n => writer.Write(n));
+                List<float> vertices = globalVerticesSubMesh.SelectMany(v => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToList();
+                vertices.ForEach(n => bufferViewFloatVec3.bytesList.AddRange(BitConverter.GetBytes(n)));
 
-                // BufferView - Vector3
-                globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
-                {
-                    List<float> vertices = globalVerticesSubMesh.SelectMany(v => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToList();
-                    vertices.ForEach(n => writer.Write(n));
+                List<float> normals = globalVerticesSubMesh.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToList();
+                normals.ForEach(n => bufferViewFloatVec3.bytesList.AddRange(BitConverter.GetBytes(n)));
+            });
 
-                    List<float> normals = globalVerticesSubMesh.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToList();
-                    normals.ForEach(n => writer.Write(n));
-                });
+            // BufferView - Vector4
+            globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
+            {
+                if (hasColor)
+                {
+                    List<float> colors = globalVerticesSubMesh.SelectMany(v => new[] { v.Color[0], v.Color[1], v.Color[2], v.Color[3] }).ToList();
+                    colors.ForEach(n => bufferViewFloatVec4.bytesList.AddRange(BitConverter.GetBytes(n)));
+                }
+            });
 
-                // BufferView - Vector4
-                globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
+            // BufferView - Vector2
+            globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
+            {
+                if (hasUV)
                 {
-                    if (hasColor)
-                    {
-                        List<float> colors = globalVerticesSubMesh.SelectMany(v => new[] { v.Color[0], v.Color[1], v.Color[2], v.Color[3] }).ToList();
-                        colors.ForEach(n => writer.Write(n));
-                    }
-                });
+                    List<float> uvs = globalVerticesSubMesh.SelectMany(v => new[] { v.UV.X, v.UV.Y }).ToList();
+                    uvs.ForEach(n => bufferViewFloatVec2.bytesList.AddRange(BitConverter.GetBytes(n)));
+                }
 
-                // BufferView - Vector2
-                globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
+                if (hasUV2)
                 {
-                    if (hasUV)
-                    {
-                        List<float> uvs = globalVerticesSubMesh.SelectMany(v => new[] { v.UV.X, v.UV.Y }).ToList();
-                        uvs.ForEach(n => writer.Write(n));
-                    }
-                    
-                    if (hasUV2)
-                    {
-                        List<float> uvs2 = globalVerticesSubMesh.SelectMany(v => new[] { v.UV2.X, v.UV2.Y }).ToList();
-                        uvs2.ForEach(n => writer.Write(n));
-                    }
-                });
-            }
+                    List<float> uvs2 = globalVerticesSubMesh.SelectMany(v => new[] { v.UV2.X, v.UV2.Y }).ToList();
+                    uvs2.ForEach(n => bufferViewFloatVec2.bytesList.AddRange(BitConverter.GetBytes(n)));
+                }
+            });
+
+            //// Write data to binary file
+            //string outputBinaryFile = Path.Combine(gltf.OutputPath, gltfMesh.name + ".bin");
+            //RaiseMessage("GLTFExporter.Mesh | Saving " + outputBinaryFile, 2);
+            //using (BinaryWriter writer = new BinaryWriter(File.Open(outputBinaryFile, FileMode.Create)))
+            //{
+            //    bytesList.ForEach(b => writer.Write(b));
+            //}
 
             return gltfMesh;
         }

+ 93 - 12
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.cs

@@ -101,25 +101,90 @@ namespace Max2Babylon
             RaiseMessage("GLTFExporter | Saving to output file");
             // Cast lists to arrays
             gltf.Prepare();
-            var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings());
-            var sb = new StringBuilder();
-            var sw = new StringWriter(sb, CultureInfo.InvariantCulture);
+            string outputGltfFile = Path.ChangeExtension(outputFile, "gltf");
+            File.WriteAllText(outputGltfFile, gltfToJson(gltf));
 
-            // Do not use the optimized writer because it's not necessary to truncate values
-            // Use the bounded writer in case some values are infinity ()
-            using (var jsonWriter = new JsonTextWriterBounded(sw))
+            // Write data to binary file
+            string outputBinaryFile = Path.ChangeExtension(outputFile, "bin");
+            using (BinaryWriter writer = new BinaryWriter(File.Open(outputBinaryFile, FileMode.Create)))
             {
-                jsonWriter.Formatting = Formatting.None;
-                jsonSerializer.Serialize(jsonWriter, gltf);
+                gltf.BuffersList.ForEach(buffer =>
+                {
+                    buffer.bytesList = new List<byte>();
+                    gltf.BufferViewsList.FindAll(bufferView => bufferView.buffer == buffer.index).ForEach(bufferView =>
+                    {
+                        bufferView.bytesList.ForEach(b => writer.Write(b));
+                        buffer.bytesList.AddRange(bufferView.bytesList);
+                    });
+                });
             }
-            string outputGltfFile = Path.ChangeExtension(outputFile, "gltf");
-            File.WriteAllText(outputGltfFile, sb.ToString());
 
             // Binary
             if (generateBinary)
             {
-                // TODO - Export glTF data to binary format .glb
-                RaiseError("GLTFExporter | TODO - Generating binary files");
+                // Export glTF data to binary format .glb
+                RaiseMessage("GLTFExporter | Generating .glb file");
+
+                // Header
+                UInt32 magic = 0x46546C67; // ASCII code for glTF
+                UInt32 version = 2;
+                UInt32 length = 12; // Header length
+
+                // --- JSON chunk ---
+                UInt32 chunkTypeJson = 0x4E4F534A; // ASCII code for JSON
+                // Remove buffers uri
+                foreach (GLTFBuffer gltfBuffer in gltf.BuffersList)
+                {
+                    gltfBuffer.uri = null;
+                }
+                // Serialize gltf data to JSON string then convert it to bytes
+                byte[] chunkDataJson = Encoding.ASCII.GetBytes(gltfToJson(gltf));
+                // JSON chunk must be padded with trailing Space chars (0x20) to satisfy alignment requirements 
+                var nbSpaceToAdd = chunkDataJson.Length % 4 == 0 ? 0 : (4 - chunkDataJson.Length % 4);
+                var chunkDataJsonList = new List<byte>(chunkDataJson);
+                for (int i = 0; i < nbSpaceToAdd; i++)
+                {
+                    chunkDataJsonList.Add(0x20);
+                }
+                chunkDataJson = chunkDataJsonList.ToArray();
+                UInt32 chunkLengthJson = (UInt32)chunkDataJson.Length;
+                length += chunkLengthJson + 8; // 8 = JSON chunk header length
+                
+                // bin chunk
+                UInt32 chunkTypeBin = 0x004E4942; // ASCII code for BIN
+                UInt32 chunkLengthBin = 0;
+                if (gltf.BuffersList.Count > 0)
+                {
+                    foreach (GLTFBuffer gltfBuffer in gltf.BuffersList)
+                    {
+                        chunkLengthBin += (uint)gltfBuffer.byteLength;
+                    }
+                    length += chunkLengthBin + 8; // 8 = bin chunk header length
+                }
+                
+
+                // Write binary file
+                string outputGlbFile = Path.ChangeExtension(outputFile, "glb");
+                using (BinaryWriter writer = new BinaryWriter(File.Open(outputGlbFile, FileMode.Create)))
+                {
+                    // Header
+                    writer.Write(magic);
+                    writer.Write(version);
+                    writer.Write(length);
+                    
+                    // JSON chunk
+                    writer.Write(chunkLengthJson);
+                    writer.Write(chunkTypeJson);
+                    writer.Write(chunkDataJson);
+
+                    // bin chunk
+                    if (gltf.BuffersList.Count > 0)
+                    {
+                        writer.Write(chunkLengthBin);
+                        writer.Write(chunkTypeBin);
+                        gltf.BuffersList[0].bytesList.ForEach(b => writer.Write(b));
+                    }
+                };
             }
 
             ReportProgressChanged(100);
@@ -236,5 +301,21 @@ namespace Max2Babylon
             // No relevant node found in hierarchy
             return false;
         }
+
+        private string gltfToJson(GLTF gltf)
+        {
+            var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings());
+            var sb = new StringBuilder();
+            var sw = new StringWriter(sb, CultureInfo.InvariantCulture);
+
+            // Do not use the optimized writer because it's not necessary to truncate values
+            // Use the bounded writer in case some values are infinity ()
+            using (var jsonWriter = new JsonTextWriterBounded(sw))
+            {
+                jsonWriter.Formatting = Formatting.None;
+                jsonSerializer.Serialize(jsonWriter, gltf);
+            }
+            return sb.ToString();
+        }
     }
 }