示例#1
0
        private void ExportCurrentProject(MeshExportOptions exportOptions, string filepath)
        {
            var assimpScene = MeshConverter.PartProjectToAssimp(CurrentProject, exportOptions);

            AssimpContext.ExportFile(assimpScene, filepath,
                                     exportOptions.FileFormatID,
                                     Assimp.PostProcessSteps.FlipUVs);
            assimpScene.Clear();
        }
示例#2
0
        private void exportToAssimp(object sender, EventArgs e)
        {
            Debug.WriteLine("Exporting to assimp");

            if (RenderState.rootObject != null)
            {
                Assimp.AssimpContext ctx = new Assimp.AssimpContext();

                Dictionary <int, int> meshImportStatus = new Dictionary <int, int>();
                Assimp.Scene          aScene           = new Assimp.Scene();
                Assimp.Node           rootNode         = RenderState.rootObject.assimpExport(ref aScene, ref meshImportStatus);
                aScene.RootNode = rootNode;

                //add a single material for now
                Assimp.Material aMat = new Assimp.Material();
                aMat.Name = "testMaterial";
                aScene.Materials.Add(aMat);

                Assimp.ExportFormatDescription[] supported_formats = ctx.GetSupportedExportFormats();
                //Assimp.Scene blenderScene = ctx.ImportFile("SimpleSkin.gltf");
                //ctx.ExportFile(blenderScene, "SimpleSkin.glb", "glb2");
                try
                {
                    ctx.ExportFile(aScene, "test.glb", "glb2");
                    //ctx.ExportFile(aScene, "test.fbx", "fbx");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
示例#3
0
        public static void SaveToCollada(RwAnimationNode animation, RwFrameListNode frameList, string path)
        {
            var aiScene = ToAssimpScene(animation, frameList);

            using (var aiContext = new Assimp.AssimpContext())
            {
                if (!aiContext.ExportFile(aiScene, path, "collada"))
                {
                    throw new Exception("Failed to export");
                }
            }
        }
示例#4
0
        public void ExportModel()
        {
            using (System.Windows.Forms.SaveFileDialog a = new System.Windows.Forms.SaveFileDialog
            {
                DefaultExt = "dae",
                Filter = "SAModel Files|*.sa1mdl|Collada|*.dae|Wavefront|*.obj"
            })
            {
                if (a.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    string ftype = "collada";
                    switch (System.IO.Path.GetExtension(a.FileName).ToLowerInvariant())
                    {
                    case ".sa1mdl":
                        ModelFile.CreateFile(a.FileName, COL.Model, null, null, null, null, COL.Model.GetModelFormat());
                        return;

                    case ".fbx":
                        ftype = "fbx";
                        break;

                    case ".obj":
                        ftype = "obj";
                        break;
                    }
                    Assimp.AssimpContext context = new Assimp.AssimpContext();
                    Assimp.Scene         scene   = new Assimp.Scene();
                    scene.Materials.Add(new Assimp.Material());
                    Assimp.Node n = new Assimp.Node();
                    n.Name         = "RootNode";
                    scene.RootNode = n;
                    string        rootPath     = System.IO.Path.GetDirectoryName(a.FileName);
                    List <string> texturePaths = new List <string>();
                    int           numSteps     = 0;
                    if (LevelData.TextureBitmaps != null && LevelData.TextureBitmaps.Count > 0)
                    {
                        numSteps = LevelData.TextureBitmaps[LevelData.leveltexs].Length;
                    }
                    for (int i = 0; i < numSteps; i++)
                    {
                        BMPInfo bmp = LevelData.TextureBitmaps[LevelData.leveltexs][i];
                        texturePaths.Add(System.IO.Path.Combine(rootPath, bmp.Name + ".png"));
                        bmp.Image.Save(System.IO.Path.Combine(rootPath, bmp.Name + ".png"));
                    }
                    SAEditorCommon.Import.AssimpStuff.AssimpExport(COL.Model, scene, Matrix.Identity, texturePaths.Count > 0 ? texturePaths.ToArray() : null, scene.RootNode);
                    context.ExportFile(scene, a.FileName, ftype, Assimp.PostProcessSteps.ValidateDataStructure | Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.FlipUVs);                    //
                }
            }
        }
示例#5
0
        private void ASSIMPExportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (SaveFileDialog a = new SaveFileDialog
            {
                DefaultExt = "dae",
                Filter = "Model Files|*.obj;*.fbx;*.dae",
                FileName = "test"
            })
            {
                if (a.ShowDialog() == DialogResult.OK)
                {
                    Assimp.AssimpContext context = new Assimp.AssimpContext();
                    Assimp.Scene         scene   = new Assimp.Scene();
                    scene.Materials.Add(new Assimp.Material());
                    Assimp.Node n = new Assimp.Node();
                    n.Name         = "RootNode";
                    scene.RootNode = n;
                    string        rootPath     = Path.GetDirectoryName(a.FileName);
                    List <string> texturePaths = new List <string>();

                    if (LevelData.TextureBitmaps != null)
                    {
                        foreach (BMPInfo[] bmp_ in LevelData.TextureBitmaps.Values)                         //???????
                        {
                            foreach (BMPInfo bmp in bmp_)
                            {
                                texturePaths.Add(Path.Combine(rootPath, bmp.Name + ".png"));
                                bmp.Image.Save(Path.Combine(rootPath, bmp.Name + ".png"));
                            }
                        }
                    }

                    foreach (COL col in LevelData.geo.COL)
                    {
                        SAEditorCommon.Import.AssimpStuff.AssimpExport(col.Model, scene, Matrix.Identity, texturePaths.Count > 0 ? texturePaths.ToArray() : null, scene.RootNode);
                    }

                    context.ExportFile(scene, a.FileName, "collada", Assimp.PostProcessSteps.ValidateDataStructure | Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.FlipUVs);                    //
                }
            }
        }
示例#6
0
        public static void WriteModelFile(IGeometryModel model, string fileName, string formatId)
        {
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }

            if (string.IsNullOrWhiteSpace(fileName))
            {
                throw new ArgumentNullException(nameof(fileName));
            }

            formatId = (formatId ?? Settings.DefaultSaveFormat).ToLower();
            if (!ExportFormats.Any(f => f.FormatId == formatId))
            {
                throw new ArgumentException($"{formatId} is not a supported format.", nameof(formatId));
            }

            var ext = "." + GetFormatExtension(formatId);

            if (!fileName.EndsWith(ext, StringComparison.OrdinalIgnoreCase))
            {
                fileName += ext;
            }

            var format = ExportFormats.First(f => f.FormatId == formatId);

            if (format.ExportFunction != null)
            {
                format.ExportFunction(model, fileName);
            }
            else
            {
                using (var context = new Assimp.AssimpContext())
                {
                    var scene = model.CreateAssimpScene(context, formatId);
                    context.ExportFile(scene, fileName, formatId);
                }
            }
        }
示例#7
0
        public void ExportModel()
        {
            using (System.Windows.Forms.SaveFileDialog a = new System.Windows.Forms.SaveFileDialog
            {
                DefaultExt = "dae",
                Filter = "SAModel Files|*.sa1mdl|Collada|*.dae|Wavefront|*.obj"
            })
            {
                if (a.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    string ftype = "collada";
                    switch (System.IO.Path.GetExtension(a.FileName).ToLowerInvariant())
                    {
                    case ".sa1mdl":
                        ModelFile.CreateFile(a.FileName, Model, null, null, null, null, Model.GetModelFormat());
                        return;

                    case ".fbx":
                        ftype = "fbx";
                        break;

                    case ".obj":
                        ftype = "obj";
                        break;
                    }
                    Assimp.AssimpContext context = new Assimp.AssimpContext();
                    Assimp.Scene         scene   = new Assimp.Scene();
                    scene.Materials.Add(new Assimp.Material());
                    Assimp.Node n = new Assimp.Node();
                    n.Name         = "RootNode";
                    scene.RootNode = n;
                    string rootPath = System.IO.Path.GetDirectoryName(a.FileName);
                    SAEditorCommon.Import.AssimpStuff.AssimpExport(Model, scene, Matrix.Identity, null, scene.RootNode);
                    context.ExportFile(scene, a.FileName, ftype, Assimp.PostProcessSteps.ValidateDataStructure | Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.FlipUVs);                    //
                }
            }
        }
示例#8
0
 private static void ExportOBJFile(ResourceWrapper res, string path)
 {
     var scene = (res as RWSceneWrapper).WrappedObject;
     var ctx = new Assimp.AssimpContext();
     ctx.ExportFile(RWScene.ToAssimpScene(scene), path, "obj");
 }
示例#9
0
        public override void Export(Model model, Motion motion, string filepath, Config config)
        {
            var aiScene = AssimpModelExporter.Instance.ConvertToScene(model, new AssimpModelExporter.Config());

            var aiAnimation = new Assimp.Animation
            {
                DurationInTicks = motion.Duration,
                TicksPerSecond  = 30
            };

            var aiChannelLookup = new Dictionary <int, Assimp.NodeAnimationChannel>();

            for (var i = 0; i < model.Nodes.Count; i++)
            {
                var node = model.Nodes[i];
                aiAnimation.NodeAnimationChannels.Add(aiChannelLookup[i] = new Assimp.NodeAnimationChannel()
                {
                    NodeName = node.Name.Replace(" ", "_"),
                });
            }

            var aiChannelLookupRev = new Dictionary <Assimp.NodeAnimationChannel, int>();

            foreach (var lookup in aiChannelLookup)
            {
                aiChannelLookupRev[lookup.Value] = lookup.Key;
            }

            foreach (var controller in motion.Controllers)
            {
                if (!aiChannelLookup.TryGetValue(controller.NodeIndex, out var aiChannel))
                {
                    throw new InvalidOperationException();
                }

                switch (controller.Type)
                {
                case ControllerType.Position:
                    foreach (var key in controller.Keys)
                    {
                        switch (key)
                        {
                        case Vector3Key positionKey:
                            aiChannel.PositionKeys.RemoveAll(x => x.Time == positionKey.Time);
                            aiChannel.PositionKeys.Add(new Assimp.VectorKey(positionKey.Time, positionKey.Value.ToAssimp()));
                            break;
                        }
                    }
                    break;

                case ControllerType.Type1:
                    break;

                case ControllerType.Scale:
                    foreach (var key in controller.Keys)
                    {
                        switch (key)
                        {
                        case Vector3Key scaleKey:
                            aiChannel.ScalingKeys.RemoveAll(x => x.Time == scaleKey.Time);
                            aiChannel.ScalingKeys.Add(new Assimp.VectorKey(scaleKey.Time, scaleKey.Value.ToAssimp()));
                            break;
                        }
                    }
                    break;

                case ControllerType.Rotation:
                    foreach (var key in controller.Keys)
                    {
                        switch (key)
                        {
                        case QuaternionKey rotationKey:
                            aiChannel.RotationKeys.RemoveAll(x => x.Time == rotationKey.Time);
                            aiChannel.RotationKeys.Add(new Assimp.QuaternionKey(rotationKey.Time, Quaternion.Inverse(rotationKey.Value).ToAssimp()));
                            break;
                        }
                    }
                    break;

                case ControllerType.Morph:
                    break;

                case ControllerType.Type5:
                    break;

                case ControllerType.Type8:
                    break;
                }
            }

            foreach (var aiChannel in aiAnimation.NodeAnimationChannels)
            {
                if (aiChannel.PositionKeys.Count == 0 || aiChannel.PositionKeys[0].Time != 0)
                {
                    aiChannel.PositionKeys.Insert(0, new Assimp.VectorKey(0, model.Nodes[aiChannelLookupRev[aiChannel]].Position.ToAssimp()));
                }

                if (aiChannel.RotationKeys.Count == 0 || aiChannel.RotationKeys[0].Time != 0)
                {
                    var rotation = model.Nodes[aiChannelLookupRev[aiChannel]].Rotation;
                    aiChannel.RotationKeys.Insert(0, new Assimp.QuaternionKey(0, Quaternion.Inverse(Quaternion.CreateFromRotationMatrix((Matrix4x4.CreateRotationX(rotation.X) *
                                                                                                                                         Matrix4x4.CreateRotationY(rotation.Y) *
                                                                                                                                         Matrix4x4.CreateRotationZ(rotation.Z)))).ToAssimp()));
                }

                if (aiChannel.ScalingKeys.Count == 0 || aiChannel.ScalingKeys[0].Time != 0)
                {
                    aiChannel.ScalingKeys.Insert(0, new Assimp.VectorKey(0, model.Nodes[aiChannelLookupRev[aiChannel]].Scale.ToAssimp()));
                }


                var keyCount =
                    Math.Max(1, Math.Max(aiChannel.PositionKeyCount, Math.Max(aiChannel.RotationKeyCount, aiChannel.ScalingKeyCount)));

                if (aiChannel.PositionKeyCount < keyCount)
                {
                    var lastKey = aiChannel.PositionKeyCount == 0
                        ? new Assimp.VectorKey(-1, model.Nodes[aiChannelLookupRev[aiChannel]].Position.ToAssimp())
                        : aiChannel.PositionKeys[aiChannel.PositionKeyCount - 1];

                    while (aiChannel.PositionKeyCount < keyCount)
                    {
                        lastKey.Time++;
                        if (lastKey.Time > aiAnimation.DurationInTicks)
                        {
                            break;
                        }
                        aiChannel.PositionKeys.Add(lastKey);
                    }
                }

                if (aiChannel.RotationKeyCount < keyCount)
                {
                    var rotation = model.Nodes[aiChannelLookupRev[aiChannel]].Rotation;

                    var lastKey = aiChannel.RotationKeyCount == 0
                        ? new Assimp.QuaternionKey(-1, Quaternion.Inverse(Quaternion.CreateFromRotationMatrix((Matrix4x4.CreateRotationX(rotation.X) *
                                                                                                               Matrix4x4.CreateRotationY(rotation.Y) *
                                                                                                               Matrix4x4.CreateRotationZ(rotation.Z)))).ToAssimp())
                        : aiChannel.RotationKeys[aiChannel.RotationKeyCount - 1];

                    while (aiChannel.RotationKeyCount < keyCount)
                    {
                        lastKey.Time++;
                        if (lastKey.Time > aiAnimation.DurationInTicks)
                        {
                            break;
                        }
                        aiChannel.RotationKeys.Add(lastKey);
                    }
                }

                if (aiChannel.ScalingKeyCount < keyCount)
                {
                    var lastKey = aiChannel.ScalingKeyCount == 0
                        ? new Assimp.VectorKey(-1, model.Nodes[aiChannelLookupRev[aiChannel]].Scale.ToAssimp())
                        : aiChannel.ScalingKeys[aiChannel.ScalingKeyCount - 1];

                    while (aiChannel.ScalingKeyCount < keyCount)
                    {
                        lastKey.Time++;
                        if (lastKey.Time > aiAnimation.DurationInTicks)
                        {
                            break;
                        }
                        aiChannel.ScalingKeys.Add(lastKey);
                    }
                }
            }

            aiScene.Animations.Add(aiAnimation);

            //aiScene.ExportColladaFile( filepath );
            using (var aiContext = new Assimp.AssimpContext())
                aiContext.ExportFile(aiScene, filepath, "collada", Assimp.PostProcessSteps.FlipUVs);
        }
示例#10
0
        public void ExportToDae(string path)
        {
            var atomicSectors = new List <RwAtomicSector>();

            void RecursivelyFindAtomicSectors(RwNode node)
            {
                if (node.Id == RwNodeId.RwAtomicSector)
                {
                    atomicSectors.Add(( RwAtomicSector )node);
                }

                foreach (var child in node.Children)
                {
                    RecursivelyFindAtomicSectors(child);
                }
            }

            RecursivelyFindAtomicSectors(this);

            if (atomicSectors.Count == 0)
            {
                return;
            }

            var aiScene = new Assimp.Scene();

            for (var i = 0; i < Materials.Count; i++)
            {
                var material   = Materials[i];
                var aiMaterial = new Assimp.Material();

                if (material.IsTextured)
                {
                    // TextureDiffuse
                    var texture = material.TextureReferenceNode;
                    aiMaterial.TextureDiffuse = new Assimp.TextureSlot(
                        texture.Name + ".png", Assimp.TextureType.Diffuse, 0, Assimp.TextureMapping.FromUV, 0, 0, Assimp.TextureOperation.Add,
                        Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0);
                }

                // Name
                aiMaterial.Name = $"Material{i}";
                if (material.IsTextured)
                {
                    aiMaterial.Name = material.TextureReferenceNode.Name;
                }

                aiMaterial.ShadingMode = Assimp.ShadingMode.Phong;
                aiScene.Materials.Add(aiMaterial);
            }

            for (var i = 0; i < atomicSectors.Count; i++)
            {
                var atomicSector = atomicSectors[i];
                var header       = atomicSector.Header;
                if (header.VertexCount == 0)
                {
                    continue;
                }

                foreach (var materialGroup in header.Triangles.GroupBy(x => x.MatId))
                {
                    var materialId = materialGroup.Key;

                    var aiMesh = new Assimp.Mesh($"AtomicSector{i}_Material{materialId}", Assimp.PrimitiveType.Triangle);
                    aiMesh.MaterialIndex = materialId;

                    foreach (var triangle in materialGroup)
                    {
                        var pos1 = header.Positions[triangle.A];
                        var pos2 = header.Positions[triangle.B];
                        var pos3 = header.Positions[triangle.C];

                        aiMesh.Vertices.Add(new Assimp.Vector3D(pos1.X, pos1.Y, pos1.Z));
                        aiMesh.Vertices.Add(new Assimp.Vector3D(pos2.X, pos2.Y, pos2.Z));
                        aiMesh.Vertices.Add(new Assimp.Vector3D(pos3.X, pos3.Y, pos3.Z));

                        if (header.TextureCoordinateChannels != null && header.TextureCoordinateChannels.Length > 0)
                        {
                            var tex1 = header.TextureCoordinateChannels[0][triangle.A];
                            var tex2 = header.TextureCoordinateChannels[0][triangle.B];
                            var tex3 = header.TextureCoordinateChannels[0][triangle.C];

                            aiMesh.TextureCoordinateChannels[0].Add(new Assimp.Vector3D(tex1.X, 1f - tex1.Y, 0));
                            aiMesh.TextureCoordinateChannels[0].Add(new Assimp.Vector3D(tex2.X, 1f - tex2.Y, 0));
                            aiMesh.TextureCoordinateChannels[0].Add(new Assimp.Vector3D(tex3.X, 1f - tex3.Y, 0));
                        }

                        if (header.Colors != null && header.Colors.Length > 0)
                        {
                            var color1 = header.Colors[triangle.A];
                            var color2 = header.Colors[triangle.B];
                            var color3 = header.Colors[triangle.C];

                            aiMesh.VertexColorChannels[0].Add(new Assimp.Color4D((float)color1.R / 255f, ( float )color1.G / 255f, ( float )color1.B / 255f, ( float )color1.A / 255f));
                            aiMesh.VertexColorChannels[0].Add(new Assimp.Color4D(( float )color2.R / 255f, ( float )color2.G / 255f, ( float )color2.B / 255f, ( float )color2.A / 255f));
                            aiMesh.VertexColorChannels[0].Add(new Assimp.Color4D(( float )color3.R / 255f, ( float )color3.G / 255f, ( float )color3.B / 255f, ( float )color3.A / 255f));
                        }
                    }

                    for (int j = 0; j < aiMesh.VertexCount; j += 3)
                    {
                        aiMesh.Faces.Add(new Assimp.Face(new[] { j, j + 1, j + 2 }));
                    }

                    aiScene.Meshes.Add(aiMesh);
                }
            }

            aiScene.RootNode = new Assimp.Node("RootNode");
            aiScene.RootNode.MeshIndices.AddRange(Enumerable.Range(0, aiScene.Meshes.Count));

            var aiContext = new Assimp.AssimpContext();

            aiContext.ExportFile(aiScene, path, "collada",
                                 Assimp.PostProcessSteps.GenerateSmoothNormals | Assimp.PostProcessSteps.JoinIdenticalVertices |
                                 Assimp.PostProcessSteps.ImproveCacheLocality);
        }
示例#11
0
 protected static void ExportCollada(Assimp.Scene aiScene, string path)
 {
     using (var aiContext = new Assimp.AssimpContext())
         aiContext.ExportFile(aiScene, path, "collada", Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.FlipUVs | Assimp.PostProcessSteps.GenerateSmoothNormals);
 }
示例#12
0
        // Export models from stage (Assimp)
        private void ExportLevelObj(string fileName, bool selectedOnly)
        {
            int stepCount = 0;
            int numSteps  = 0;

            if (LevelData.TextureBitmaps != null && LevelData.TextureBitmaps.Count > 0)
            {
                stepCount = LevelData.TextureBitmaps[LevelData.leveltexs].Length;
                numSteps  = stepCount;
            }
            List <COL>         cols  = LevelData.geo.COL;
            List <GeoAnimData> anims = LevelData.geo.Anim;

            if (selectedOnly)
            {
                cols  = selectedItems.Items.OfType <LevelItem>().Select(a => a.CollisionData).ToList();
                anims = selectedItems.Items.OfType <LevelAnim>().Select(a => a.GeoAnimationData).ToList();
            }
            stepCount += cols.Count;
            stepCount += anims.Count;

            Assimp.AssimpContext context = new Assimp.AssimpContext();
            Assimp.Scene         scene   = new Assimp.Scene();
            scene.Materials.Add(new Assimp.Material());
            Assimp.Node n = new Assimp.Node();
            n.Name         = "RootNode";
            scene.RootNode = n;
            string        rootPath     = Path.GetDirectoryName(fileName);
            List <string> texturePaths = new List <string>();

            ProgressDialog progress = new ProgressDialog("Exporting stage: " + levelName, stepCount, true, false);

            progress.Show(this);
            progress.SetTaskAndStep("Exporting...");

            List <string> texlist = new List <string>();

            for (int i = 0; i < numSteps; i++)
            {
                BMPInfo bmp = LevelData.TextureBitmaps[LevelData.leveltexs][i];
                texlist.Add(bmp.Name);
                texturePaths.Add(Path.Combine(rootPath, bmp.Name + ".png"));
                if (!File.Exists(Path.Combine(rootPath, bmp.Name + ".png")))
                {
                    bmp.Image.Save(Path.Combine(rootPath, bmp.Name + ".png"));
                }
                progress.Step = $"Texture {i + 1}/{numSteps}";
                progress.StepProgress();
                Application.DoEvents();
            }

            // Save texture list
            SplitTools.NJS_TEXLIST textureNamesArray = new SplitTools.NJS_TEXLIST(texlist.ToArray());
            textureNamesArray.Save(Path.Combine(rootPath, Path.GetFileNameWithoutExtension(fileName) + ".satex"));

            for (int i = 0; i < cols.Count; i++)
            {
                SAEditorCommon.Import.AssimpStuff.AssimpExport(cols[i].Model, scene, Matrix.Identity, texturePaths.Count > 0 ? texturePaths.ToArray() : null, scene.RootNode);

                progress.Step = $"Mesh {i + 1}/{cols.Count}";
                progress.StepProgress();
                Application.DoEvents();
            }

            for (int i = 0; i < anims.Count; i++)
            {
                SAEditorCommon.Import.AssimpStuff.AssimpExport(anims[i].Model, scene, Matrix.Identity, texturePaths.Count > 0 ? texturePaths.ToArray() : null, scene.RootNode);
                progress.Step = $"Animation {i + 1}/{anims.Count}";
                progress.StepProgress();
                Application.DoEvents();
            }

            string ftype = "collada";

            switch (Path.GetExtension(fileName).ToLowerInvariant())
            {
            case ".fbx":
                ftype = "fbx";
                break;

            case ".obj":
                ftype = "obj";
                break;
            }
            context.ExportFile(scene, fileName, ftype, Assimp.PostProcessSteps.ValidateDataStructure | Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.FlipUVs);

            progress.SetTaskAndStep("Export complete!");
        }
示例#13
0
        /// <summary>
        /// Converts a given .GR2 file to a .dae file for rendering and further conversion.
        /// </summary>
        /// <param name="filename">The file name.</param>
        /// <returns>The .dae converted model file.</returns>
        private static HelixToolkitScene LoadFile(string filename)
        {
            var dae = $"{filename}.dae";

            if (!File.Exists(dae))
            {
                GeneralHelper.WriteToConsole($"Converting model to .dae for rendering...\n");
                var divine    = $" -g \"bg3\" --action \"convert-model\" --output-format \"dae\" --source \"\\\\?\\{filename}.GR2\" --destination \"\\\\?\\{dae}\" -l \"all\"";
                var process   = new Process();
                var startInfo = new ProcessStartInfo
                {
                    FileName               = Properties.Settings.Default.divineExe,
                    Arguments              = divine,
                    WindowStyle            = ProcessWindowStyle.Hidden,
                    CreateNoWindow         = true,
                    UseShellExecute        = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError  = true
                };
                process.StartInfo = startInfo;
                process.Start();
                process.WaitForExit();
                GeneralHelper.WriteToConsole(process.StandardOutput.ReadToEnd());
                GeneralHelper.WriteToConsole(process.StandardError.ReadToEnd());
            }
            try
            {
                var importer = new Importer();
                // Update material here?
                var file = importer.Load(dae);
                if (file == null && File.Exists(dae))
                {
                    GeneralHelper.WriteToConsole("Fixing vertices...\n");
                    try
                    {
                        var xml          = XDocument.Load(dae);
                        var geometryList = xml.Descendants().Where(x => x.Name.LocalName == "geometry").ToList();
                        foreach (var lod in geometryList)
                        {
                            var vertexId = lod.Descendants().Where(x => x.Name.LocalName == "vertices").Select(x => x.Attribute("id").Value).First();
                            var vertex   = lod.Descendants().Single(x => x.Name.LocalName == "input" && x.Attribute("semantic").Value == "VERTEX");
                            vertex.Attribute("source").Value = $"#{vertexId}";
                        }
                        xml.Save(dae);
                        GeneralHelper.WriteToConsole("Model conversion complete!\n");
                        file = importer.Load(dae);
                    }
                    catch (Exception ex)
                    {
                        // in use by another process
                        GeneralHelper.WriteToConsole($"Error : {ex.Message}\n");
                    }
                }

                if (!File.Exists($"{filename}.fbx"))
                {
                    var converter     = new Assimp.AssimpContext();
                    var exportFormats = converter.GetSupportedExportFormats().Select(e => e.FormatId);
                    var importFormats = converter.GetSupportedImportFormats();
                    var imported      = converter.ImportFile(dae);
                    converter.ExportFile(imported, $"{filename}.fbx", "fbx");
                }
                importer.Dispose();
                return(file);
            }
            catch (Exception ex)
            {
                GeneralHelper.WriteToConsole($"Error loading .dae: {ex.Message}. Inner exception: {ex.InnerException?.Message}\n");
            }
            return(null);
        }