From feee89f2e2f2ffa0210fb7615457845a23f333de Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Thu, 15 Jul 2021 18:15:20 +0200 Subject: [PATCH] documentation? non-existent, pain? 100%, choose something else? probably --- CUE4Parse | 2 +- FModel/ViewModels/CUE4ParseViewModel.cs | 2 +- .../ViewModels/CustomDirectoriesViewModel.cs | 2 +- FModel/ViewModels/ModelViewerViewModel.cs | 161 +++++++++++++----- FModel/Views/ModelViewer.xaml | 55 +++--- FModel/Views/ModelViewer.xaml.cs | 14 +- 6 files changed, 157 insertions(+), 79 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 85c993e2..6e6bce4f 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 85c993e2a1cab603654905ce58e5f38455edeb52 +Subproject commit 6e6bce4f63ce4c3115649ae3e18404130843edd2 diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 3351f3dc..0c48d679 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -567,7 +567,7 @@ namespace FModel.ViewModels SaveAndPlaySound(Path.Combine(TabControl.SelectedTab.Directory, TabControl.SelectedTab.Header.SubstringBeforeLast('.')).Replace('\\', '/'), audioFormat, data); return false; } - case UMaterialInterface: + case UMaterialInterface when UserSettings.Default.IsAutoSaveMaterials: case UStaticMesh: case USkeletalMesh: { diff --git a/FModel/ViewModels/CustomDirectoriesViewModel.cs b/FModel/ViewModels/CustomDirectoriesViewModel.cs index c0659bfb..567001c7 100644 --- a/FModel/ViewModels/CustomDirectoriesViewModel.cs +++ b/FModel/ViewModels/CustomDirectoriesViewModel.cs @@ -51,7 +51,7 @@ namespace FModel.ViewModels private DeleteDirectoryCommand _deleteDirectoryCommand; public DeleteDirectoryCommand DeleteDirectoryCommand => _deleteDirectoryCommand ??= new DeleteDirectoryCommand(this); - public readonly ObservableCollection _directories; + private readonly ObservableCollection _directories; public ReadOnlyObservableCollection Directories { get; } private readonly FGame _game; diff --git a/FModel/ViewModels/ModelViewerViewModel.cs b/FModel/ViewModels/ModelViewerViewModel.cs index ba8b06da..19f29046 100644 --- a/FModel/ViewModels/ModelViewerViewModel.cs +++ b/FModel/ViewModels/ModelViewerViewModel.cs @@ -1,8 +1,16 @@ using System; +using System.Collections.ObjectModel; +using System.Linq; using CUE4Parse.UE4.Assets.Exports; +using CUE4Parse.UE4.Assets.Exports.Material; 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_Conversion.Meshes; +using CUE4Parse_Conversion.Meshes.PSK; +using CUE4Parse_Conversion.Textures; +using FModel.Extensions; using FModel.Framework; using HelixToolkit.SharpDX.Core; using HelixToolkit.Wpf.SharpDX; @@ -26,6 +34,34 @@ namespace FModel.ViewModels set => SetProperty(ref _cam, value); } + private Geometry3D _xAxis; + public Geometry3D XAxis + { + get => _xAxis; + set => SetProperty(ref _xAxis, value); + } + + private Geometry3D _yAxis; + public Geometry3D YAxis + { + get => _yAxis; + set => SetProperty(ref _yAxis, value); + } + + private Geometry3D _zAxis; + public Geometry3D ZAxis + { + get => _zAxis; + set => SetProperty(ref _zAxis, value); + } + + private bool _showWireframe; + public bool ShowWireframe + { + get => _showWireframe; + set => SetProperty(ref _showWireframe, value); + } + private Geometry3D _mesh; public Geometry3D Mesh { @@ -39,9 +75,12 @@ namespace FModel.ViewModels get => _meshMat; set => SetProperty(ref _meshMat, value); } + + public ObservableCollection Lods { get; } public ModelViewerViewModel() { + Lods = new ObservableCollection(); EffectManager = new DefaultEffectsManager(); Cam = new PerspectiveCamera { @@ -51,8 +90,15 @@ namespace FModel.ViewModels }; } + public void NextLod() => Mesh = Lods.Next(Mesh); + public void PreviousLod() => Mesh = Lods.Previous(Mesh); + public void LoadExport(UObject export) { + Lods.Clear(); + Mesh = null; + MeshMat = PhongMaterials.Bisque; + switch (export) { case UStaticMesh st: @@ -72,31 +118,23 @@ namespace FModel.ViewModels { return; } - - var max = convertedMesh.BoundingBox.Max.Max(); - Cam.UpDirection = new System.Windows.Media.Media3D.Vector3D(0, 1, 0); - Cam.Position = new System.Windows.Media.Media3D.Point3D(max / 2, max, max / 2); - Cam.LookDirection = new System.Windows.Media.Media3D.Vector3D(-Cam.Position.X, -Cam.Position.Y / 2, -Cam.Position.Z); - var builder = new MeshBuilder(); - for (var i = 0; i < convertedMesh.LODs.Length; i++) - { - for (var j = 0; j < convertedMesh.LODs[i].NumVerts; j++) - { - var suv = convertedMesh.LODs[i].Verts[j]; - builder.Positions.Add(new Vector3(suv.Position.X, suv.Position.Y, suv.Position.Z)); - builder.Normals.Add(new Vector3(suv.Normal.X, suv.Normal.Y, suv.Normal.Z)); - } + SetupCameraAndAxis(convertedMesh.BoundingBox.Min, convertedMesh.BoundingBox.Max); - var numIndices = convertedMesh.LODs[i].Indices.Value.Length; - for (var j = 0; j < numIndices; j++) + var pushedMaterial = false; + foreach (var lod in convertedMesh.LODs) + { + if (lod?.Sections.Value.Length <= 0) + continue; + + PushLod(lod.Verts, lod.Indices.Value); + if (!pushedMaterial) { - builder.TriangleIndices.Add(convertedMesh.LODs[i].Indices.Value[j]); + PushMaterial(lod.Sections.Value); + pushedMaterial = true; } - break; } - Mesh = builder.ToMesh(); - MeshMat = DiffuseMaterials.White; + Mesh = Lods.First(); } private void LoadSkeletalMesh(USkeletalMesh mesh) @@ -106,30 +144,75 @@ namespace FModel.ViewModels return; } - var max = convertedMesh.BoundingBox.Max.Max(); - Cam.UpDirection = new System.Windows.Media.Media3D.Vector3D(0, 1, 0); - Cam.Position = new System.Windows.Media.Media3D.Point3D(max / 2, max, max / 2); - Cam.LookDirection = new System.Windows.Media.Media3D.Vector3D(-Cam.Position.X, -Cam.Position.Y / 2, -Cam.Position.Z); - - var builder = new MeshBuilder(); - for (var i = 0; i < convertedMesh.LODs.Length; i++) - { - for (var j = 0; j < convertedMesh.LODs[i].NumVerts; j++) - { - var suv = convertedMesh.LODs[i].Verts[j]; - builder.Positions.Add(new Vector3(suv.Position.X, suv.Position.Y, suv.Position.Z)); - builder.Normals.Add(new Vector3(suv.Normal.X, suv.Normal.Y, suv.Normal.Z)); - } + SetupCameraAndAxis(convertedMesh.BoundingBox.Min, convertedMesh.BoundingBox.Max); - var numIndices = convertedMesh.LODs[i].Indices.Value.Length; - for (var j = 0; j < numIndices; j++) + var pushedMaterial = false; + foreach (var lod in convertedMesh.LODs) + { + if (lod?.Sections.Value.Length <= 0) + continue; + + PushLod(lod.Verts, lod.Indices.Value); + if (!pushedMaterial) { - builder.TriangleIndices.Add(convertedMesh.LODs[i].Indices.Value[j]); + PushMaterial(lod.Sections.Value); + pushedMaterial = true; } + } + Mesh = Lods.First(); + } + + private void PushLod(CMeshVertex[] verts, FRawStaticIndexBuffer indices) + { + var builder = new MeshBuilder {TextureCoordinates = new Vector2Collection()}; + for (var i = 0; i < verts.Length; i++) + { + builder.AddNode( + new Vector3(verts[i].Position.X, verts[i].Position.Y, verts[i].Position.Z), + new Vector3(verts[i].Normal.X, verts[i].Normal.Y, verts[i].Normal.Z), + new Vector2(verts[i].UV.U, verts[i].UV.V)); + } + + for (var i = 0; i < indices.Length; i++) + { + builder.TriangleIndices.Add(indices[i]); + } + + Lods.Add(builder.ToMesh()); + } + + private void PushMaterial(CMeshSection[] sections) + { + for (var j = 0; j < sections.Length; j++) + { + if (sections[j].Material.Value is not { } unrealMaterial) + continue; + + var parameters = new CMaterialParams(); + unrealMaterial.GetParams(parameters); + if (parameters.Diffuse is not UTexture2D diffuse) continue; + MeshMat = new DiffuseMaterial {DiffuseMap = new TextureModel(diffuse.Decode().Encode().AsStream())}; break; } - Mesh = builder.ToMesh(); - MeshMat = DiffuseMaterials.White; + } + + private void SetupCameraAndAxis(FVector min, FVector max) + { + var minOfMin = min.Min(); + var maxOfMax = max.Max(); + Cam.UpDirection = new System.Windows.Media.Media3D.Vector3D(0, 0, 1); + Cam.Position = new System.Windows.Media.Media3D.Point3D(maxOfMax, maxOfMax, (minOfMin + maxOfMax) / 1.25); + Cam.LookDirection = new System.Windows.Media.Media3D.Vector3D(-Cam.Position.X, -Cam.Position.Y, 0); + + var lineBuilder = new LineBuilder(); + lineBuilder.AddLine(new Vector3(0, 0, 0), new Vector3(max.X, 0, 0)); + XAxis = lineBuilder.ToLineGeometry3D(); + lineBuilder = new LineBuilder(); + lineBuilder.AddLine(new Vector3(0, 0, 0), new Vector3(0, max.Y, 0)); + YAxis = lineBuilder.ToLineGeometry3D(); + lineBuilder = new LineBuilder(); + lineBuilder.AddLine(new Vector3(0, 0, 0), new Vector3(0, 0, max.Z)); + ZAxis = lineBuilder.ToLineGeometry3D(); } } } \ No newline at end of file diff --git a/FModel/Views/ModelViewer.xaml b/FModel/Views/ModelViewer.xaml index 346418f7..9037a229 100644 --- a/FModel/Views/ModelViewer.xaml +++ b/FModel/Views/ModelViewer.xaml @@ -4,8 +4,9 @@ xmlns:converters="clr-namespace:FModel.Views.Resources.Converters" xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI" xmlns:helix="http://helix-toolkit.org/wpf/SharpDX" - WindowStartupLocation="CenterScreen" ResizeMode="CanResize" IconVisibility="Collapsed" - Height="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.50'}" + WindowStartupLocation="CenterScreen" ResizeMode="CanResize" IconVisibility="Collapsed" Background="#262630" + PreviewKeyDown="OnWindowKeyDown" + Height="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.60'}" Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.50'}">