mirror of
https://github.com/4sval/FModel.git
synced 2026-03-27 04:05:18 -05:00
fixed the fucked up camera and meshes wrongly axed on Y
This commit is contained in:
parent
983d9da845
commit
db7fb35bd2
|
|
@ -1 +1 @@
|
|||
Subproject commit e5861dac2390041a9b70c6623a99646c1503d4e5
|
||||
Subproject commit 85c993e2a1cab603654905ce58e5f38455edeb52
|
||||
|
|
@ -69,6 +69,7 @@ namespace FModel.ViewModels
|
|||
public AesManagerViewModel AesManager { get; }
|
||||
public AudioPlayerViewModel AudioPlayer { get; }
|
||||
public MapViewerViewModel MapViewer { get; }
|
||||
public ModelViewerViewModel ModelViewer { get; }
|
||||
|
||||
public ApplicationViewModel()
|
||||
{
|
||||
|
|
@ -89,6 +90,7 @@ namespace FModel.ViewModels
|
|||
AesManager = new AesManagerViewModel(CUE4Parse);
|
||||
MapViewer = new MapViewerViewModel(CUE4Parse);
|
||||
AudioPlayer = new AudioPlayerViewModel();
|
||||
ModelViewer = new ModelViewerViewModel();
|
||||
Status = EStatusKind.Ready;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -592,7 +592,8 @@ namespace FModel.ViewModels
|
|||
{
|
||||
Application.Current.Dispatcher.Invoke(delegate
|
||||
{
|
||||
Helper.OpenWindow<AdonisWindow>("Model Viewer", () => new ModelViewer(export).Show());
|
||||
var modelViewer = Helper.GetWindow<ModelViewer>("Model Viewer", () => new ModelViewer().Show());
|
||||
modelViewer.Load(export);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
||||
using System;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||
using CUE4Parse_Conversion.Meshes;
|
||||
using FModel.Framework;
|
||||
using HelixToolkit.SharpDX.Core;
|
||||
using HelixToolkit.Wpf.SharpDX;
|
||||
|
|
@ -23,124 +26,110 @@ namespace FModel.ViewModels
|
|||
set => SetProperty(ref _cam, value);
|
||||
}
|
||||
|
||||
private Geometry3D _cubeMesh;
|
||||
public Geometry3D CubeMesh
|
||||
private Geometry3D _mesh;
|
||||
public Geometry3D Mesh
|
||||
{
|
||||
get => _cubeMesh;
|
||||
set => SetProperty(ref _cubeMesh, value);
|
||||
get => _mesh;
|
||||
set => SetProperty(ref _mesh, value);
|
||||
}
|
||||
|
||||
private Material _red;
|
||||
public Material Red
|
||||
private Material _meshMat;
|
||||
public Material MeshMat
|
||||
{
|
||||
get => _red;
|
||||
set => SetProperty(ref _red, value);
|
||||
get => _meshMat;
|
||||
set => SetProperty(ref _meshMat, value);
|
||||
}
|
||||
|
||||
public ModelViewerViewModel(UStaticMesh? mesh)
|
||||
public ModelViewerViewModel()
|
||||
{
|
||||
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++)
|
||||
Cam = new PerspectiveCamera
|
||||
{
|
||||
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;
|
||||
NearPlaneDistance = 0.1,
|
||||
FarPlaneDistance = 10000000,
|
||||
FieldOfView = 80
|
||||
};
|
||||
}
|
||||
|
||||
public void LoadExport(UObject export)
|
||||
{
|
||||
switch (export)
|
||||
{
|
||||
case UStaticMesh st:
|
||||
LoadStaticMesh(st);
|
||||
break;
|
||||
case USkeletalMesh sk:
|
||||
LoadSkeletalMesh(sk);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
builder.Scale(0.05, 0.05, 0.05);
|
||||
CubeMesh = builder.ToMesh();
|
||||
Red = PhongMaterials.Red;
|
||||
}
|
||||
|
||||
public ModelViewerViewModel(USkeletalMesh? mesh)
|
||||
private void LoadStaticMesh(UStaticMesh mesh)
|
||||
{
|
||||
EffectManager = new DefaultEffectsManager();
|
||||
Cam = new PerspectiveCamera();
|
||||
if (mesh == null || mesh.LODModels?.Length < 1) return;
|
||||
if (!mesh.TryConvert(out var convertedMesh) || convertedMesh.LODs.Length <= 0)
|
||||
{
|
||||
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 < mesh.LODModels.Length; i++)
|
||||
for (var i = 0; i < convertedMesh.LODs.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)
|
||||
for (var j = 0; j < convertedMesh.LODs[i].NumVerts; j++)
|
||||
{
|
||||
bUseVerticesFromSections = true;
|
||||
for (var j = 0; j < srcLod.Sections.Length; j++)
|
||||
{
|
||||
vertexCount += srcLod.Sections[i].SoftVertices.Length;
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
var chunkIndex = -1;
|
||||
var chunkVertexIndex = 0;
|
||||
long lastChunkVertex = -1;
|
||||
var vertBuffer = srcLod.VertexBufferGPUSkin;
|
||||
|
||||
for (var j = 0; j < vertexCount; j++)
|
||||
|
||||
var numIndices = convertedMesh.LODs[i].Indices.Value.Length;
|
||||
for (var j = 0; j < numIndices; 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]);
|
||||
builder.TriangleIndices.Add(convertedMesh.LODs[i].Indices.Value[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
builder.Scale(0.05, 0.05, 0.05);
|
||||
CubeMesh = builder.ToMesh();
|
||||
Red = PhongMaterials.Red;
|
||||
Mesh = builder.ToMesh();
|
||||
MeshMat = DiffuseMaterials.White;
|
||||
}
|
||||
|
||||
private void LoadSkeletalMesh(USkeletalMesh mesh)
|
||||
{
|
||||
if (!mesh.TryConvert(out var convertedMesh) || convertedMesh.LODs.Length <= 0)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
var numIndices = convertedMesh.LODs[i].Indices.Value.Length;
|
||||
for (var j = 0; j < numIndices; j++)
|
||||
{
|
||||
builder.TriangleIndices.Add(convertedMesh.LODs[i].Indices.Value[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
Mesh = builder.ToMesh();
|
||||
MeshMat = DiffuseMaterials.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
<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'}">
|
||||
Height="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.50'}"
|
||||
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}}" >
|
||||
<Setter Property="Title" Value="Model Viewer" />
|
||||
|
|
@ -30,14 +29,14 @@
|
|||
IsChangeFieldOfViewEnabled="False"
|
||||
ShowViewCube="False"
|
||||
ShowCameraTarget="False"
|
||||
Camera="{Binding Cam}"
|
||||
Camera="{Binding ModelViewer.Cam}"
|
||||
IsShadowMappingEnabled="True"
|
||||
EnableSSAO="True"
|
||||
MSAA="Maximum"
|
||||
FXAALevel="Ultra"
|
||||
SSAOQuality="High"
|
||||
UseDefaultGestures="False"
|
||||
EffectsManager="{Binding EffectManager}"
|
||||
EffectsManager="{Binding ModelViewer.EffectManager}"
|
||||
BackgroundColor="#262630">
|
||||
<helix:Viewport3DX.InputBindings>
|
||||
<MouseBinding Command="helix:ViewportCommands.Rotate" Gesture="MiddleClick" />
|
||||
|
|
@ -48,12 +47,18 @@
|
|||
<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: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:Viewport3DX>
|
||||
</Grid>
|
||||
</adonisControls:AdonisWindow>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,19 @@
|
|||
using System;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using FModel.Services;
|
||||
using FModel.ViewModels;
|
||||
|
||||
namespace FModel.Views
|
||||
{
|
||||
public partial class ModelViewer
|
||||
{
|
||||
public ModelViewer(UObject export)
|
||||
private ApplicationViewModel _applicationView => ApplicationService.ApplicationView;
|
||||
|
||||
public ModelViewer()
|
||||
{
|
||||
DataContext = export switch
|
||||
{
|
||||
UStaticMesh st => new ModelViewerViewModel(st),
|
||||
USkeletalMesh sk => new ModelViewerViewModel(sk),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
||||
DataContext = _applicationView;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void Load(UObject export) => _applicationView.ModelViewer.LoadExport(export);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user