diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index 623f5a84..d0056336 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -109,13 +109,13 @@ - - + + - + - - + + diff --git a/FModel/ViewModels/ModelViewerViewModel.cs b/FModel/ViewModels/ModelViewerViewModel.cs index 2cc7e260..7b3ccbf8 100644 --- a/FModel/ViewModels/ModelViewerViewModel.cs +++ b/FModel/ViewModels/ModelViewerViewModel.cs @@ -1,6 +1,4 @@ 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; @@ -10,11 +8,14 @@ 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; using SharpDX; +using Camera = HelixToolkit.Wpf.SharpDX.Camera; +using Geometry3D = HelixToolkit.SharpDX.Core.Geometry3D; +using Material = HelixToolkit.Wpf.SharpDX.Material; +using PerspectiveCamera = HelixToolkit.Wpf.SharpDX.PerspectiveCamera; namespace FModel.ViewModels { @@ -26,28 +27,28 @@ namespace FModel.ViewModels get => _effectManager; set => SetProperty(ref _effectManager, value); } - + private Camera _cam; public Camera Cam { get => _cam; 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 { @@ -62,43 +63,25 @@ namespace FModel.ViewModels set => SetProperty(ref _showWireframe, value); } - private Geometry3D _mesh; - public Geometry3D Mesh + private ObservableElement3DCollection _group3d; + public ObservableElement3DCollection Group3d { - get => _mesh; - set => SetProperty(ref _mesh, value); + get => _group3d; + set => SetProperty(ref _group3d, value); } - - private Material _meshMat; - public Material MeshMat - { - get => _meshMat; - set => SetProperty(ref _meshMat, value); - } - - public ObservableCollection Lods { get; } + public Material MainMaterial { get; } = PhongMaterials.White; + + private readonly int[] _FACES_INDEX = { 1, 0, 2 }; public ModelViewerViewModel() { - Lods = new ObservableCollection(); EffectManager = new DefaultEffectsManager(); - Cam = new PerspectiveCamera - { - NearPlaneDistance = 0.1, - FarPlaneDistance = 10000000, - FieldOfView = 80 - }; + Cam = new PerspectiveCamera { NearPlaneDistance = 0.1, FarPlaneDistance = 99999999, FieldOfView = 80 }; } - 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; - + Group3d = new ObservableElement3DCollection(); switch (export) { case UStaticMesh st: @@ -111,31 +94,24 @@ namespace FModel.ViewModels throw new ArgumentOutOfRangeException(); } } - + private void LoadStaticMesh(UStaticMesh mesh) { if (!mesh.TryConvert(out var convertedMesh) || convertedMesh.LODs.Count <= 0) { return; } - + SetupCameraAndAxis(convertedMesh.BoundingBox.Min, convertedMesh.BoundingBox.Max); - var pushedMaterial = false; foreach (var lod in convertedMesh.LODs) { if (lod.SkipLod) continue; - - PushLod(lod.Verts, lod.Indices.Value); - if (!pushedMaterial) - { - PushMaterial(lod.Sections.Value); - pushedMaterial = true; - } + PushLod(lod.Sections.Value, lod.Verts, lod.Indices.Value); + break; } - Mesh = Lods.First(); } - + private void LoadSkeletalMesh(USkeletalMesh mesh) { if (!mesh.TryConvert(out var convertedMesh) || convertedMesh.LODs.Count <= 0) @@ -145,52 +121,50 @@ namespace FModel.ViewModels SetupCameraAndAxis(convertedMesh.BoundingBox.Min, convertedMesh.BoundingBox.Max); - var pushedMaterial = false; foreach (var lod in convertedMesh.LODs) { if (lod.SkipLod) continue; - - PushLod(lod.Verts, lod.Indices.Value); - if (!pushedMaterial) + PushLod(lod.Sections.Value, lod.Verts, lod.Indices.Value); + break; + } + } + + private void PushLod(CMeshSection[] sections, CMeshVertex[] verts, FRawStaticIndexBuffer indices) + { + foreach (var section in sections) // each section is a mesh part with its own material + { + var builder = new MeshBuilder(); + // NumFaces * 3 (triangle) = next section FirstIndex + for (var j = 0; j < section.NumFaces; j++) // draw a triangle for each face { - PushMaterial(lod.Sections.Value); - pushedMaterial = true; + foreach (var t in _FACES_INDEX) // triangle face 1 then 0 then 2 + { + var id = section.FirstIndex + j * 3 + t; + var vert = verts[indices[id]]; + var p = new Vector3(vert.Position.X, -vert.Position.Y, vert.Position.Z); + var n = new Vector3(vert.Normal.X, -vert.Normal.Y, vert.Normal.Z); + var uv = new Vector2(vert.UV.U, vert.UV.V); + builder.AddNode(p, n, uv); + builder.TriangleIndices.Add(j * 3 + t); // one mesh part is "j * 3 + k" use "id" if you're building the full mesh + } } - } - 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 == null || !sections[j].Material.TryLoad(out var unrealMaterial)) + if (section.Material == null || !section.Material.TryLoad(out var 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; + if (parameters.Diffuse is not UTexture2D diffuse) + continue; + + Group3d.Add(new MeshGeometryModel3D + { + Geometry = builder.ToMeshGeometry3D(), + Material = new PhongMaterial + { + DiffuseMap = new TextureModel(diffuse.Decode()?.Encode().AsStream()) + } + }); } } @@ -201,7 +175,7 @@ namespace FModel.ViewModels 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(); @@ -213,4 +187,4 @@ namespace FModel.ViewModels ZAxis = lineBuilder.ToLineGeometry3D(); } } -} \ No newline at end of file +} diff --git a/FModel/Views/ModelViewer.xaml b/FModel/Views/ModelViewer.xaml index 9037a229..cf144f61 100644 --- a/FModel/Views/ModelViewer.xaml +++ b/FModel/Views/ModelViewer.xaml @@ -31,17 +31,15 @@ - + - + - - + + diff --git a/FModel/Views/ModelViewer.xaml.cs b/FModel/Views/ModelViewer.xaml.cs index d7810b67..2b041001 100644 --- a/FModel/Views/ModelViewer.xaml.cs +++ b/FModel/Views/ModelViewer.xaml.cs @@ -9,7 +9,7 @@ namespace FModel.Views public partial class ModelViewer { private ApplicationViewModel _applicationView => ApplicationService.ApplicationView; - + public ModelViewer() { DataContext = _applicationView; @@ -17,15 +17,15 @@ namespace FModel.Views } public void Load(UObject export) => _applicationView.ModelViewer.LoadExport(export); - + private void OnWindowKeyDown(object sender, KeyEventArgs e) { - if (UserSettings.Default.DirLeftTab.IsTriggered(e.Key)) + /*if (UserSettings.Default.DirLeftTab.IsTriggered(e.Key)) _applicationView.ModelViewer.PreviousLod(); else if (UserSettings.Default.DirRightTab.IsTriggered(e.Key)) _applicationView.ModelViewer.NextLod(); - else if (e.Key == Key.W) + else */if (e.Key == Key.W) _applicationView.ModelViewer.ShowWireframe = !_applicationView.ModelViewer.ShowWireframe; } } -} \ No newline at end of file +}