mirror of
https://github.com/4sval/FModel.git
synced 2026-03-23 02:04:26 -05:00
documentation? non-existent, pain? 100%, choose something else? probably
This commit is contained in:
parent
db7fb35bd2
commit
feee89f2e2
|
|
@ -1 +1 @@
|
|||
Subproject commit 85c993e2a1cab603654905ce58e5f38455edeb52
|
||||
Subproject commit 6e6bce4f63ce4c3115649ae3e18404130843edd2
|
||||
|
|
@ -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:
|
||||
{
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ namespace FModel.ViewModels
|
|||
private DeleteDirectoryCommand _deleteDirectoryCommand;
|
||||
public DeleteDirectoryCommand DeleteDirectoryCommand => _deleteDirectoryCommand ??= new DeleteDirectoryCommand(this);
|
||||
|
||||
public readonly ObservableCollection<Control> _directories;
|
||||
private readonly ObservableCollection<Control> _directories;
|
||||
public ReadOnlyObservableCollection<Control> Directories { get; }
|
||||
|
||||
private readonly FGame _game;
|
||||
|
|
|
|||
|
|
@ -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<Geometry3D> Lods { get; }
|
||||
|
||||
public ModelViewerViewModel()
|
||||
{
|
||||
Lods = new ObservableCollection<Geometry3D>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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'}">
|
||||
<adonisControls:AdonisWindow.Style>
|
||||
<Style TargetType="adonisControls:AdonisWindow" BasedOn="{StaticResource {x:Type adonisControls:AdonisWindow}}" >
|
||||
|
|
@ -20,45 +21,27 @@
|
|||
</ResourceDictionary>
|
||||
</adonisControls:AdonisWindow.Resources>
|
||||
<Grid>
|
||||
<helix:Viewport3DX Title="{Binding Title}"
|
||||
ShowCoordinateSystem="True"
|
||||
IsCoordinateSystemMoverEnabled="False"
|
||||
CoordinateSystemAxisXColor="#FC3854"
|
||||
CoordinateSystemAxisYColor="#85CB22"
|
||||
CoordinateSystemAxisZColor="#388EED"
|
||||
IsChangeFieldOfViewEnabled="False"
|
||||
ShowViewCube="False"
|
||||
ShowCameraTarget="False"
|
||||
Camera="{Binding ModelViewer.Cam}"
|
||||
IsShadowMappingEnabled="True"
|
||||
EnableSSAO="True"
|
||||
MSAA="Maximum"
|
||||
FXAALevel="Ultra"
|
||||
SSAOQuality="High"
|
||||
UseDefaultGestures="False"
|
||||
EffectsManager="{Binding ModelViewer.EffectManager}"
|
||||
<helix:Viewport3DX EffectsManager="{Binding ModelViewer.EffectManager}" Camera="{Binding ModelViewer.Cam}"
|
||||
IsChangeFieldOfViewEnabled="False" IsMoveEnabled="False" UseDefaultGestures="False"
|
||||
ShowViewCube="False" ShowCameraTarget="False" ModelUpDirection="0,0,1"
|
||||
EnableSSAO="True" MSAA="Maximum" FXAALevel="Ultra" SSAOQuality="High"
|
||||
BackgroundColor="#262630">
|
||||
<helix:Viewport3DX.InputBindings>
|
||||
<MouseBinding Command="helix:ViewportCommands.Rotate" Gesture="MiddleClick" />
|
||||
<MouseBinding Command="helix:ViewportCommands.Pan" Gesture="Shift+MiddleClick"></MouseBinding>
|
||||
<MouseBinding Command="helix:ViewportCommands.Rotate" Gesture="LeftClick" />
|
||||
<MouseBinding Command="helix:ViewportCommands.Zoom" Gesture="RightClick" />
|
||||
<MouseBinding Command="helix:ViewportCommands.Pan" Gesture="MiddleClick" />
|
||||
</helix:Viewport3DX.InputBindings>
|
||||
|
||||
<helix:GroupModel3D>
|
||||
<helix:DirectionalLight3D Direction="0, 0, -1" Color="White" />
|
||||
<helix:DirectionalLight3D Direction="0, -1, 0" Color="White"/>
|
||||
</helix:GroupModel3D>
|
||||
<helix:DirectionalLight3D Direction="0, 0, -1" Color="White" />
|
||||
<helix:DirectionalLight3D Direction="0, -1, 0" Color="White"/>
|
||||
|
||||
<helix:GroupModel3D>
|
||||
<helix:MeshGeometryModel3D Geometry="{Binding ModelViewer.Mesh}" Material="{Binding ModelViewer.MeshMat}">
|
||||
<helix:MeshGeometryModel3D.Transform>
|
||||
<RotateTransform3D>
|
||||
<RotateTransform3D.Rotation>
|
||||
<AxisAngleRotation3D Axis="1,0,0" Angle="-90"/>
|
||||
</RotateTransform3D.Rotation>
|
||||
</RotateTransform3D>
|
||||
</helix:MeshGeometryModel3D.Transform>
|
||||
</helix:MeshGeometryModel3D>
|
||||
</helix:GroupModel3D>
|
||||
<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:Viewport3DX>
|
||||
</Grid>
|
||||
</adonisControls:AdonisWindow>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using System.Windows.Input;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
using FModel.ViewModels;
|
||||
|
||||
namespace FModel.Views
|
||||
|
|
@ -15,5 +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))
|
||||
_applicationView.ModelViewer.PreviousLod();
|
||||
else if (UserSettings.Default.DirRightTab.IsTriggered(e.Key))
|
||||
_applicationView.ModelViewer.NextLod();
|
||||
else if (e.Key == Key.W)
|
||||
_applicationView.ModelViewer.ShowWireframe = !_applicationView.ModelViewer.ShowWireframe;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user