documentation? non-existent, pain? 100%, choose something else? probably

This commit is contained in:
iAmAsval 2021-07-15 18:15:20 +02:00
parent db7fb35bd2
commit feee89f2e2
6 changed files with 157 additions and 79 deletions

@ -1 +1 @@
Subproject commit 85c993e2a1cab603654905ce58e5f38455edeb52
Subproject commit 6e6bce4f63ce4c3115649ae3e18404130843edd2

View File

@ -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:
{

View File

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

View File

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

View File

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

View File

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