multiple material support in viewer

This commit is contained in:
iAmAsval 2021-11-15 15:48:06 +01:00
parent 6c5a83409b
commit 177ae1dc0a
4 changed files with 72 additions and 100 deletions

View File

@ -109,13 +109,13 @@
<PackageReference Include="CSCore" Version="1.2.1.2" />
<PackageReference Include="DiscordRichPresence" Version="1.0.175" />
<PackageReference Include="EpicManifestParser" Version="1.2.69-temp" />
<PackageReference Include="HelixToolkit.SharpDX.Core.Wpf" Version="2.18.0" />
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.2.12" />
<PackageReference Include="HelixToolkit.SharpDX.Core.Wpf" Version="2.20.0" />
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.2.15" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NVorbis" Version="0.10.3" />
<PackageReference Include="NVorbis" Version="0.10.4" />
<PackageReference Include="Oodle.NET" Version="1.0.1" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="3.1.0" />
<PackageReference Include="RestSharp" Version="106.12.0" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.0" />
<PackageReference Include="RestSharp" Version="106.13.0" />
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="SkiaSharp.HarfBuzz" Version="2.80.3" />

View File

@ -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<Geometry3D> Lods { get; }
public Material MainMaterial { get; } = PhongMaterials.White;
private readonly int[] _FACES_INDEX = { 1, 0, 2 };
public ModelViewerViewModel()
{
Lods = new ObservableCollection<Geometry3D>();
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<UMaterialInterface>(out var unrealMaterial))
if (section.Material == null || !section.Material.TryLoad<UMaterialInterface>(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();
}
}
}
}

View File

@ -31,17 +31,15 @@
<MouseBinding Command="helix:ViewportCommands.Zoom" Gesture="RightClick" />
<MouseBinding Command="helix:ViewportCommands.Pan" Gesture="MiddleClick" />
</helix:Viewport3DX.InputBindings>
<helix:DirectionalLight3D Direction="0, 0, -1" Color="White" />
<helix:DirectionalLight3D Direction="0, -1, 0" Color="White"/>
<helix:LineGeometryModel3D Geometry="{Binding ModelViewer.XAxis}" Color="#FC3854" />
<helix:LineGeometryModel3D Geometry="{Binding ModelViewer.YAxis}" Color="#85CB22" />
<helix:LineGeometryModel3D Geometry="{Binding ModelViewer.ZAxis}" Color="#388EED" />
<helix:MeshGeometryModel3D Geometry="{Binding ModelViewer.Mesh}"
Material="{Binding ModelViewer.MeshMat}"
RenderWireframe="{Binding ModelViewer.ShowWireframe}" />
<helix:GroupModel3D ItemsSource="{Binding ModelViewer.Group3d}" />
</helix:Viewport3DX>
</Grid>
</adonisControls:AdonisWindow>

View File

@ -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;
}
}
}
}