From 845542a6bfcea7644cde254cf8cc732a02857765 Mon Sep 17 00:00:00 2001 From: MountainFlash Date: Mon, 6 Dec 2021 22:32:27 +0530 Subject: [PATCH] save models as scene Ctrl + S -> Save Ctrl + Shift + S -> Save as Scene --- FModel/ViewModels/ModelViewerViewModel.cs | 106 ++++++++++++++++++++++ FModel/Views/ModelViewer.xaml.cs | 6 ++ 2 files changed, 112 insertions(+) diff --git a/FModel/ViewModels/ModelViewerViewModel.cs b/FModel/ViewModels/ModelViewerViewModel.cs index decc2d93..4b8cc2c5 100644 --- a/FModel/ViewModels/ModelViewerViewModel.cs +++ b/FModel/ViewModels/ModelViewerViewModel.cs @@ -1,8 +1,10 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; +using System.Numerics; using System.Threading.Tasks; using System.Windows; using System.Windows.Data; @@ -13,7 +15,10 @@ using CUE4Parse.UE4.Assets.Exports.SkeletalMesh; using CUE4Parse.UE4.Assets.Exports.StaticMesh; using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Objects.Core.Math; +using CUE4Parse.Utils; +using CUE4Parse_Conversion.Materials; using CUE4Parse_Conversion.Meshes; +using CUE4Parse_Conversion.Meshes.glTF; using CUE4Parse_Conversion.Meshes.PSK; using CUE4Parse_Conversion.Textures; using FModel.Framework; @@ -25,10 +30,18 @@ using HelixToolkit.Wpf.SharpDX; using Ookii.Dialogs.Wpf; using Serilog; using SharpDX; +using SharpGLTF.Geometry; +using SharpGLTF.Geometry.VertexTypes; +using SharpGLTF.Scenes; +using SharpGLTF.Schema2; +using SharpGLTF.Transforms; using SkiaSharp; using Camera = HelixToolkit.Wpf.SharpDX.Camera; using Geometry3D = HelixToolkit.SharpDX.Core.Geometry3D; using PerspectiveCamera = HelixToolkit.Wpf.SharpDX.PerspectiveCamera; +using Vector2 = SharpDX.Vector2; +using Vector3 = SharpDX.Vector3; +using VERTEX = SharpGLTF.Geometry.VertexTypes.VertexPositionNormalTangent; namespace FModel.ViewModels { @@ -188,6 +201,99 @@ namespace FModel.ViewModels } } + public bool CheckIfSaved(string path) + { + if (File.Exists(path)) + { + Log.Information("Successfully saved {FileName}", path); + FLogger.AppendInformation(); + FLogger.AppendText($"Successfully saved {path}", Constants.WHITE, true); + return true; + } + else + { + Log.Error("{FileName} could not be saved", path); + FLogger.AppendError(); + FLogger.AppendText($"Could not save '{path}'", Constants.WHITE, true); + return false; + } + } + + public void SaveAsScene() + { + if (_loadedModels.Count < 1) return; + + var fileBrowser = new VistaSaveFileDialog() + { + Title = "Save Loaded Models As...", + DefaultExt = ".glb", + Filter = "glTF Binary File (*.glb)|*.glb|glTF ASCII File (*.gltf)|*.gltf|All Files(*.*)|*.*", + AddExtension = true, + OverwritePrompt = true, + CheckPathExists = true, + }; + + if (fileBrowser.ShowDialog() == false || string.IsNullOrEmpty(fileBrowser.FileName)) return; + + var sceneBuilder = new SceneBuilder(); + var materialExports = new List(); + foreach (var model in _loadedModels) + { + switch (model.Export) + { + case UStaticMesh sm: + { + var mesh = new MeshBuilder(sm.Name); + if (sm.TryConvert(out var convertedMesh) && convertedMesh.LODs.Count > 0) + { + var lod = convertedMesh.LODs.First(); + for (var i = 0; i < lod.Sections.Value.Length; i++) + { + Gltf.ExportStaticMeshSections(i, lod, lod.Sections.Value[i], materialExports, mesh); + } + sceneBuilder.AddRigidMesh(mesh, AffineTransform.Identity); + } + break; + } + case USkeletalMesh sk: + { + var mesh = new MeshBuilder(sk.Name); + + if (sk.TryConvert(out var convertedMesh) && convertedMesh.LODs.Count > 0) + { + var lod = convertedMesh.LODs.First(); + for (var i = 0; i < lod.Sections.Value.Length; i++) + { + Gltf.ExportSkelMeshSections(i, lod, lod.Sections.Value[i], materialExports, mesh); + } + var armatureNodeBuilder = new NodeBuilder(sk.Name+".ao"); + var armature = Gltf.CreateGltfSkeleton(convertedMesh.RefSkeleton, armatureNodeBuilder); + sceneBuilder.AddSkinnedMesh(mesh, Matrix4x4.Identity, armature); + } + break; + } + } + } + + var scene = sceneBuilder.ToGltf2(); + var fileName = fileBrowser.FileName; + if (fileName.EndsWith(".glb", StringComparison.OrdinalIgnoreCase)) + scene.SaveGLB(fileName); + else if (fileName.EndsWith(".gltf", StringComparison.OrdinalIgnoreCase)) + scene.SaveGLTF(fileName); + else if (fileName.EndsWith(".obj", StringComparison.OrdinalIgnoreCase)) + scene.SaveAsWavefront(fileName); + else + throw new ArgumentOutOfRangeException(nameof(fileName),$@"Unknown file format {fileName. SubstringAfterWithLast('.')}"); + + if (!CheckIfSaved(fileName)) return; + foreach (var materialExport in materialExports) + { + materialExport.TryWriteToDir(new DirectoryInfo(StringUtils.SubstringBeforeWithLast(fileName, '\\')), + out var _); + } + } + public void CopySelectedMaterialName() { if (SelectedModel is not { } m || m.SelectedGeometry is null) diff --git a/FModel/Views/ModelViewer.xaml.cs b/FModel/Views/ModelViewer.xaml.cs index 6f0ef587..0993e361 100644 --- a/FModel/Views/ModelViewer.xaml.cs +++ b/FModel/Views/ModelViewer.xaml.cs @@ -71,6 +71,12 @@ namespace FModel.Views case Key.Decimal: _applicationView.ModelViewer.FocusOnSelectedMesh(); break; + case Key.S when Keyboard.Modifiers.HasFlag(ModifierKeys.Control) && Keyboard.Modifiers.HasFlag(ModifierKeys.Shift): + _applicationView.ModelViewer.SaveAsScene(); + break; + case Key.S when Keyboard.Modifiers.HasFlag(ModifierKeys.Control): + _applicationView.ModelViewer.SaveLoadedModels(); + break; } }