public ExporterForm() { InitializeComponent(); this.Text = $"Babylon.js - Export scene to babylon or glTF format v{BabylonExporter.exporterVersion}"; // Check if the gltf-pipeline module is installed gltfPipelineInstalled = GLTFPipelineUtilities.IsGLTFPipelineInstalled(); groupBox1.MouseMove += groupBox1_MouseMove; }
public ExporterForm(BabylonExportActionItem babylonExportAction) { InitializeComponent(); RegisterFilePostOpen(); this.Text = $"Babylon.js - Export scene to babylon or glTF format v{BabylonExporter.exporterVersion}"; this.babylonExportAction = babylonExportAction; // Check if the gltf-pipeline module is installed this.gltfPipelineInstalled = GLTFPipelineUtilities.IsGLTFPipelineInstalled(); groupBox1.MouseMove += groupBox1_MouseMove; }
public void ExportGltf(ExportParameters exportParameters, BabylonScene babylonScene, string outputDirectory, string outputFileName, bool generateBinary, ILoggingProvider logger) { this.exportParameters = exportParameters; this.logger = logger; logger.RaiseMessage("GLTFExporter | Exportation started", Color.Blue); #if DEBUG var watch = new Stopwatch(); watch.Start(); #endif this.babylonScene = babylonScene; // Force output file extension to be gltf outputFileName = Path.ChangeExtension(outputFileName, "gltf"); // Update path of output .gltf file to include subdirectory var outputFile = Path.Combine(outputDirectory, outputFileName); float progressionStep; var progression = 0.0f; logger.ReportProgressChanged((int)progression); babylonMaterialsToExport = new List <BabylonMaterial>(); var gltf = new GLTF(outputFile); // Asset gltf.asset = new GLTFAsset { version = "2.0" // no minVersion }; var softwarePackageName = babylonScene.producer != null ? babylonScene.producer.name : ""; var softwareVersion = babylonScene.producer != null ? babylonScene.producer.version : ""; var exporterVersion = babylonScene.producer != null ? babylonScene.producer.exporter_version : ""; gltf.asset.generator = $"babylon.js glTF exporter for {softwarePackageName} {softwareVersion} v{exporterVersion}"; // Scene gltf.scene = 0; // Scenes GLTFScene scene = new GLTFScene(); ExportGLTFExtension(babylonScene, ref scene, gltf); GLTFScene[] scenes = { scene }; gltf.scenes = scenes; // Initialization initBabylonNodes(babylonScene, gltf); // Root nodes logger.RaiseMessage("GLTFExporter | Exporting nodes"); progression = 30.0f; logger.ReportProgressChanged((int)progression); List <BabylonNode> babylonRootNodes = babylonNodes.FindAll(node => node.parentId == null); progressionStep = 30.0f / babylonRootNodes.Count; alreadyExportedSkeletons = new Dictionary <BabylonSkeleton, BabylonSkeletonExportData>(); nodeToGltfNodeMap = new Dictionary <BabylonNode, GLTFNode>(); NbNodesByName = new Dictionary <string, int>(); babylonRootNodes.ForEach(babylonNode => { exportNodeRec(babylonNode, gltf, babylonScene); progression += progressionStep; logger.ReportProgressChanged((int)progression); logger.CheckCancelled(); }); #if DEBUG var nodesExportTime = watch.ElapsedMilliseconds / 1000.0; logger.RaiseMessage(string.Format("GLTFNodes exported in {0:0.00}s", nodesExportTime), Color.Blue); #endif // Meshes logger.RaiseMessage("GLTFExporter | Exporting meshes"); progression = 10.0f; logger.ReportProgressChanged((int)progression); progressionStep = 40.0f / babylonScene.meshes.Length; foreach (var babylonMesh in babylonScene.meshes) { ExportMesh(babylonMesh, gltf, babylonScene); progression += progressionStep; logger.ReportProgressChanged((int)progression); logger.CheckCancelled(); } #if DEBUG var meshesExportTime = watch.ElapsedMilliseconds / 1000.0 - nodesExportTime; logger.RaiseMessage(string.Format("GLTFMeshes exported in {0:0.00}s", meshesExportTime), Color.Blue); #endif //Mesh Skins, light and Cameras logger.RaiseMessage("GLTFExporter | Exporting skins, lights and cameras"); progression = 50.0f; logger.ReportProgressChanged((int)progression); progressionStep = 50.0f / babylonRootNodes.Count; babylonRootNodes.ForEach(babylonNode => { exportNodeTypeRec(babylonNode, gltf, babylonScene); progression += progressionStep; logger.ReportProgressChanged((int)progression); logger.CheckCancelled(); }); #if DEBUG var skinLightCameraExportTime = watch.ElapsedMilliseconds / 1000.0 - meshesExportTime; logger.RaiseMessage(string.Format("GLTFSkin GLTFLights GLTFCameras exported in {0:0.00}s", skinLightCameraExportTime), Color.Blue); #endif // Materials progression = 70.0f; logger.ReportProgressChanged((int)progression); logger.RaiseMessage("GLTFExporter | Exporting materials"); if (exportParameters.tryToReuseOpaqueAndBlendTexture) { // we MUST sort the material in order to let BabylonPBRMetallicRoughnessMaterial with Alpha first. // the reason is the sequential write pattern babylonMaterialsToExport = SortMaterialPriorToOptimizeTextureUsage(gltf, babylonMaterialsToExport).ToList(); } foreach (var babylonMaterial in babylonMaterialsToExport) { ExportMaterial(babylonMaterial, gltf); logger.CheckCancelled(); } ; logger.RaiseMessage(string.Format("GLTFExporter | Nb materials exported: {0}", gltf.MaterialsList.Count), Color.Gray, 1); #if DEBUG var materialsExportTime = watch.ElapsedMilliseconds / 1000.0 - nodesExportTime; logger.RaiseMessage(string.Format("GLTFMaterials exported in {0:0.00}s", materialsExportTime), Color.Blue); #endif // Animations progression = 90.0f; logger.ReportProgressChanged((int)progression); logger.RaiseMessage("GLTFExporter | Exporting Animations"); ExportAnimationGroups(gltf, babylonScene); #if DEBUG var animationGroupsExportTime = watch.ElapsedMilliseconds / 1000.0 - materialsExportTime; logger.RaiseMessage(string.Format("GLTFAnimations exported in {0:0.00}s", animationGroupsExportTime), Color.Blue); #endif // Prepare buffers gltf.BuffersList.ForEach(buffer => { buffer.BufferViews.ForEach(bufferView => { bufferView.Accessors.ForEach(accessor => { // Chunk must be padded with trailing zeros (0x00) to satisfy alignment requirements accessor.bytesList = new List <byte>(padChunk(accessor.bytesList.ToArray(), 4, 0x00)); // Update byte properties accessor.byteOffset = bufferView.byteLength; bufferView.byteLength += accessor.bytesList.Count; // Merge bytes bufferView.bytesList.AddRange(accessor.bytesList); }); // Update byte properties bufferView.byteOffset = buffer.byteLength; buffer.byteLength += bufferView.bytesList.Count; // Merge bytes buffer.bytesList.AddRange(bufferView.bytesList); }); }); // Cast lists to arrays gltf.Prepare(); // Output logger.RaiseMessage("GLTFExporter | Saving to output file"); if (!generateBinary) { // Write .gltf file string outputGltfFile = Path.ChangeExtension(outputFile, "gltf"); File.WriteAllText(outputGltfFile, gltfToJson(gltf)); // Write .bin file string outputBinaryFile = Path.ChangeExtension(outputFile, "bin"); using (BinaryWriter writer = new BinaryWriter(File.Open(outputBinaryFile, FileMode.Create))) { gltf.BuffersList.ForEach(buffer => { buffer.bytesList.ForEach(b => writer.Write(b)); }); } } else { // Export glTF data to binary format .glb // 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; } // Switch images to binary gltf.Prepare(); // Serialize gltf data to JSON string then convert it to bytes byte[] chunkDataJson = Encoding.UTF8.GetBytes(gltfToJson(gltf)); // JSON chunk must be padded with trailing Space chars (0x20) to satisfy alignment requirements chunkDataJson = padChunk(chunkDataJson, 4, 0x20); 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)); } }; } // Draco compression if (exportParameters.dracoCompression) { logger.RaiseMessage("GLTFExporter | Draco compression"); GLTFPipelineUtilities.DoDracoCompression(logger, generateBinary, outputFile, exportParameters.dracoParams); } logger.ReportProgressChanged(100); }