Пример #1
0
        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;
        }
Пример #2
0
        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;
        }
Пример #3
0
        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);
        }