mirror of
https://github.com/4sval/FModel.git
synced 2026-04-16 14:37:05 -05:00
scuffed but working model viewer
This commit is contained in:
parent
08050aee78
commit
983d9da845
|
|
@ -1 +1 @@
|
|||
Subproject commit 291277cdfe645f8c9759961f0851366bffa2f233
|
||||
Subproject commit e5861dac2390041a9b70c6623a99646c1503d4e5
|
||||
|
|
@ -108,6 +108,7 @@
|
|||
<PackageReference Include="CSCore" Version="1.2.1.2" />
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.0.175" />
|
||||
<PackageReference Include="EpicManifestParser" Version="1.2.0" />
|
||||
<PackageReference Include="HelixToolkit.SharpDX.Core.Wpf" Version="2.17.0" />
|
||||
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="NVorbis" Version="0.10.1" />
|
||||
|
|
|
|||
|
|
@ -160,6 +160,8 @@ namespace FModel.ViewModels.ApiEndpoints
|
|||
{
|
||||
var request = new RestRequest(args.ChangelogURL, Method.GET);
|
||||
var response = await _client.ExecuteAsync(request).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(response.Content)) return;
|
||||
|
||||
_applicationView.CUE4Parse.TabControl.AddTab($"Release Notes: {args.CurrentVersion}");
|
||||
_applicationView.CUE4Parse.TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("changelog");
|
||||
_applicationView.CUE4Parse.TabControl.SelectedTab.SetDocumentText(response.Content, false);
|
||||
|
|
|
|||
|
|
@ -590,7 +590,10 @@ namespace FModel.ViewModels
|
|||
}
|
||||
else
|
||||
{
|
||||
// preview
|
||||
Application.Current.Dispatcher.Invoke(delegate
|
||||
{
|
||||
Helper.OpenWindow<AdonisWindow>("Model Viewer", () => new ModelViewer(export).Show());
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
146
FModel/ViewModels/ModelViewerViewModel.cs
Normal file
146
FModel/ViewModels/ModelViewerViewModel.cs
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||
using FModel.Framework;
|
||||
using HelixToolkit.SharpDX.Core;
|
||||
using HelixToolkit.Wpf.SharpDX;
|
||||
using SharpDX;
|
||||
|
||||
namespace FModel.ViewModels
|
||||
{
|
||||
public class ModelViewerViewModel : ViewModel
|
||||
{
|
||||
private EffectsManager _effectManager;
|
||||
public EffectsManager EffectManager
|
||||
{
|
||||
get => _effectManager;
|
||||
set => SetProperty(ref _effectManager, value);
|
||||
}
|
||||
|
||||
private Camera _cam;
|
||||
public Camera Cam
|
||||
{
|
||||
get => _cam;
|
||||
set => SetProperty(ref _cam, value);
|
||||
}
|
||||
|
||||
private Geometry3D _cubeMesh;
|
||||
public Geometry3D CubeMesh
|
||||
{
|
||||
get => _cubeMesh;
|
||||
set => SetProperty(ref _cubeMesh, value);
|
||||
}
|
||||
|
||||
private Material _red;
|
||||
public Material Red
|
||||
{
|
||||
get => _red;
|
||||
set => SetProperty(ref _red, value);
|
||||
}
|
||||
|
||||
public ModelViewerViewModel(UStaticMesh? mesh)
|
||||
{
|
||||
EffectManager = new DefaultEffectsManager();
|
||||
Cam = new PerspectiveCamera();
|
||||
if (mesh?.RenderData == null || mesh.RenderData.LODs.Length < 1) return;
|
||||
|
||||
var builder = new MeshBuilder();
|
||||
for (var i = 0; i < mesh.RenderData.LODs.Length; i++)
|
||||
{
|
||||
if (mesh.RenderData.LODs[i] is not
|
||||
{
|
||||
VertexBuffer: not null,
|
||||
PositionVertexBuffer: not null,
|
||||
ColorVertexBuffer: not null,
|
||||
IndexBuffer: not null
|
||||
} srcLod) continue;
|
||||
|
||||
var numVerts = srcLod.PositionVertexBuffer.Verts.Length;
|
||||
for (var j = 0; j < numVerts; j++)
|
||||
{
|
||||
var suv = srcLod.VertexBuffer.UV[j];
|
||||
builder.Positions.Add(new Vector3(srcLod.PositionVertexBuffer.Verts[j].X, srcLod.PositionVertexBuffer.Verts[j].Y, srcLod.PositionVertexBuffer.Verts[j].Z));
|
||||
builder.Normals.Add(new Vector3(suv.Normal[2].X, suv.Normal[2].Y, suv.Normal[2].Z));
|
||||
}
|
||||
|
||||
for (var j = 0; j < srcLod.IndexBuffer.Indices16.Length; j++)
|
||||
{
|
||||
builder.TriangleIndices.Add(srcLod.IndexBuffer[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
builder.Scale(0.05, 0.05, 0.05);
|
||||
CubeMesh = builder.ToMesh();
|
||||
Red = PhongMaterials.Red;
|
||||
}
|
||||
|
||||
public ModelViewerViewModel(USkeletalMesh? mesh)
|
||||
{
|
||||
EffectManager = new DefaultEffectsManager();
|
||||
Cam = new PerspectiveCamera();
|
||||
if (mesh == null || mesh.LODModels?.Length < 1) return;
|
||||
|
||||
var builder = new MeshBuilder();
|
||||
for (var i = 0; i < mesh.LODModels.Length; i++)
|
||||
{
|
||||
if (mesh.LODModels[i] is not { } srcLod) continue;
|
||||
|
||||
var bUseVerticesFromSections = false;
|
||||
var vertexCount = srcLod.VertexBufferGPUSkin.GetVertexCount();
|
||||
if (vertexCount == 0 && srcLod.Sections.Length > 0 && srcLod.Sections[0].SoftVertices.Length > 0)
|
||||
{
|
||||
bUseVerticesFromSections = true;
|
||||
for (var j = 0; j < srcLod.Sections.Length; j++)
|
||||
{
|
||||
vertexCount += srcLod.Sections[i].SoftVertices.Length;
|
||||
}
|
||||
}
|
||||
|
||||
var chunkIndex = -1;
|
||||
var chunkVertexIndex = 0;
|
||||
long lastChunkVertex = -1;
|
||||
var vertBuffer = srcLod.VertexBufferGPUSkin;
|
||||
|
||||
for (var j = 0; j < vertexCount; j++)
|
||||
{
|
||||
while (j >= lastChunkVertex) // this will fix any issues with empty chunks or sections
|
||||
{
|
||||
// proceed to next chunk or section
|
||||
if (srcLod.Chunks.Length > 0)
|
||||
{
|
||||
// pre-UE4.13 code: chunks
|
||||
var c = srcLod.Chunks[++chunkIndex];
|
||||
lastChunkVertex = c.BaseVertexIndex + c.NumRigidVertices + c.NumSoftVertices;
|
||||
}
|
||||
else
|
||||
{
|
||||
// UE4.13+ code: chunk information migrated to sections
|
||||
var s = srcLod.Sections[++chunkIndex];
|
||||
lastChunkVertex = s.BaseVertexIndex + s.NumVertices;
|
||||
}
|
||||
chunkVertexIndex = 0;
|
||||
}
|
||||
|
||||
FSkelMeshVertexBase v;
|
||||
if (bUseVerticesFromSections)
|
||||
v = srcLod.Sections[chunkIndex].SoftVertices[chunkVertexIndex++];
|
||||
else if (!vertBuffer.bUseFullPrecisionUVs)
|
||||
v = vertBuffer.VertsHalf[j];
|
||||
else
|
||||
v = vertBuffer.VertsFloat[j];
|
||||
|
||||
builder.Positions.Add(new Vector3(v.Pos.X, v.Pos.Y, v.Pos.Z));
|
||||
builder.Normals.Add(new Vector3(v.Normal[2].X, v.Normal[2].Y, v.Normal[2].Z));
|
||||
}
|
||||
|
||||
for (var j = 0; j < srcLod.Indices.Indices16.Length; j++)
|
||||
{
|
||||
builder.TriangleIndices.Add(srcLod.Indices.Indices16[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
builder.Scale(0.05, 0.05, 0.05);
|
||||
CubeMesh = builder.ToMesh();
|
||||
Red = PhongMaterials.Red;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
FModel/Views/ModelViewer.xaml
Normal file
59
FModel/Views/ModelViewer.xaml
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<adonisControls:AdonisWindow x:Class="FModel.Views.ModelViewer"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:FModel"
|
||||
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.75'}"
|
||||
Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.65'}">
|
||||
<adonisControls:AdonisWindow.Style>
|
||||
<Style TargetType="adonisControls:AdonisWindow" BasedOn="{StaticResource {x:Type adonisControls:AdonisWindow}}" >
|
||||
<Setter Property="Title" Value="Model Viewer" />
|
||||
</Style>
|
||||
</adonisControls:AdonisWindow.Style>
|
||||
<adonisControls:AdonisWindow.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Resources/Resources.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</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 Cam}"
|
||||
IsShadowMappingEnabled="True"
|
||||
EnableSSAO="True"
|
||||
MSAA="Maximum"
|
||||
FXAALevel="Ultra"
|
||||
SSAOQuality="High"
|
||||
UseDefaultGestures="False"
|
||||
EffectsManager="{Binding EffectManager}"
|
||||
BackgroundColor="#262630">
|
||||
<helix:Viewport3DX.InputBindings>
|
||||
<MouseBinding Command="helix:ViewportCommands.Rotate" Gesture="MiddleClick" />
|
||||
<MouseBinding Command="helix:ViewportCommands.Pan" Gesture="Shift+MiddleClick"></MouseBinding>
|
||||
</helix:Viewport3DX.InputBindings>
|
||||
|
||||
<helix:GroupModel3D>
|
||||
<helix:DirectionalLight3D Direction="0, 0, -1" Color="White" />
|
||||
<helix:DirectionalLight3D Direction="0, -1, 0" Color="White"/>
|
||||
</helix:GroupModel3D>
|
||||
<helix:GroupModel3D>
|
||||
<helix:SpotLight3D Direction="0, 1, 0" Color="Red" Position="0, -2, 0"/>
|
||||
<helix:PointLight3D Position="3, 0, 0" Color="Green"/>
|
||||
</helix:GroupModel3D>
|
||||
|
||||
<helix:MeshGeometryModel3D Geometry="{Binding CubeMesh}" Material="{Binding Red}" />
|
||||
</helix:Viewport3DX>
|
||||
</Grid>
|
||||
</adonisControls:AdonisWindow>
|
||||
23
FModel/Views/ModelViewer.xaml.cs
Normal file
23
FModel/Views/ModelViewer.xaml.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||
using FModel.ViewModels;
|
||||
|
||||
namespace FModel.Views
|
||||
{
|
||||
public partial class ModelViewer
|
||||
{
|
||||
public ModelViewer(UObject export)
|
||||
{
|
||||
DataContext = export switch
|
||||
{
|
||||
UStaticMesh st => new ModelViewerViewModel(st),
|
||||
USkeletalMesh sk => new ModelViewerViewModel(sk),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user