mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
multiple material support in viewer
This commit is contained in:
parent
6c5a83409b
commit
177ae1dc0a
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user