fixed the fucked up camera and meshes wrongly axed on Y

This commit is contained in:
iAmAsval 2021-07-13 22:50:56 +02:00
parent 983d9da845
commit db7fb35bd2
6 changed files with 114 additions and 121 deletions

@ -1 +1 @@
Subproject commit e5861dac2390041a9b70c6623a99646c1503d4e5
Subproject commit 85c993e2a1cab603654905ce58e5f38455edeb52

View File

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

View File

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

View File

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

View File

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

View File

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