private void ExportCurrentProject(MeshExportOptions exportOptions, string filepath) { var assimpScene = MeshConverter.PartProjectToAssimp(CurrentProject, exportOptions); AssimpContext.ExportFile(assimpScene, filepath, exportOptions.FileFormatID, Assimp.PostProcessSteps.FlipUVs); assimpScene.Clear(); }
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); } } }
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"); } } }
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); // } } }
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); // } } }
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); } } }
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); // } } }
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"); }
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); }
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); }
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); }
// 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!"); }
/// <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); }