From ca95df2dd425e28ec787627f4e50004a627ca410 Mon Sep 17 00:00:00 2001 From: Asval Date: Sat, 4 May 2024 23:25:01 +0200 Subject: [PATCH] convex collision preview --- CUE4Parse | 2 +- FModel/App.xaml.cs | 13 ---- FModel/FModel.csproj | 2 + FModel/MainWindow.xaml.cs | 6 +- FModel/Resources/collision.vert | 20 +++++++ FModel/Settings/EndpointSettings.cs | 1 - FModel/ViewModels/CUE4ParseViewModel.cs | 1 + FModel/Views/Snooper/Models/Collision.cs | 62 ++++++++++++++++++++ FModel/Views/Snooper/Models/SkeletalModel.cs | 13 ++++ FModel/Views/Snooper/Models/StaticModel.cs | 9 +++ FModel/Views/Snooper/Models/UModel.cs | 25 ++++++++ FModel/Views/Snooper/Renderer.cs | 8 +++ FModel/Views/Snooper/Shading/Shader.cs | 6 +- FModel/Views/Snooper/SnimGui.cs | 1 + 14 files changed, 148 insertions(+), 21 deletions(-) create mode 100644 FModel/Resources/collision.vert create mode 100644 FModel/Views/Snooper/Models/Collision.cs diff --git a/CUE4Parse b/CUE4Parse index 38be1267..fb9413d0 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 38be126747f52c4a72f98d09de2d8073c4af750e +Subproject commit fb9413d0362457867e0c46c339ab3756c2b0a399 diff --git a/FModel/App.xaml.cs b/FModel/App.xaml.cs index 8491c467..f5de48d8 100644 --- a/FModel/App.xaml.cs +++ b/FModel/App.xaml.cs @@ -41,8 +41,6 @@ public partial class App { UserSettings.Default = JsonConvert.DeserializeObject( File.ReadAllText(UserSettings.FilePath), JsonNetSerializer.SerializerSettings); - - /*if (UserSettings.Default.ShowChangelog) */MigrateV1Games(); } catch { @@ -143,17 +141,6 @@ public partial class App e.Handled = true; } - private void MigrateV1Games() - { - foreach ((var gameDir, var setting) in UserSettings.Default.ManualGames) - { - if (!Directory.Exists(gameDir)) continue; - UserSettings.Default.PerDirectory[gameDir] = - DirectorySettings.Default(setting.GameName, setting.GameDirectory, true, setting.OverridedGame, setting.AesKeys?.MainKey); - } - UserSettings.Default.ManualGames.Clear(); - } - private string GetOperatingSystemProductName() { var productName = string.Empty; diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index 9e1e1f6f..9163c262 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -116,6 +116,7 @@ + @@ -141,6 +142,7 @@ + diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index 3c69be80..fe365445 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -83,9 +83,9 @@ public partial class MainWindow ).ConfigureAwait(false); #if DEBUG - await _threadWorkerView.Begin(cancellationToken => - _applicationView.CUE4Parse.Extract(cancellationToken, - "ShooterGame/Content/Characters/Smonk/S0/3P/Models/TP_Smonk_S0_Skelmesh.uasset")); + // await _threadWorkerView.Begin(cancellationToken => + // _applicationView.CUE4Parse.Extract(cancellationToken, + // "FortniteGame/Content/Environments/Asteria/Props/Coastal/Coastal_Boat_B/Meshes/SM_Coastal_Boat_B.uasset")); #endif } diff --git a/FModel/Resources/collision.vert b/FModel/Resources/collision.vert new file mode 100644 index 00000000..b2036c3c --- /dev/null +++ b/FModel/Resources/collision.vert @@ -0,0 +1,20 @@ +#version 460 core + +layout (location = 0) in vec3 vPos; + +uniform mat4 uView; +uniform mat4 uProjection; +uniform mat4 uInstanceMatrix; +uniform mat4 uCollisionMatrix; +uniform float uScaleDown; + +out vec3 fPos; +out vec3 fColor; + +void main() +{ + gl_PointSize = 7.5f; + gl_Position = uProjection * uView * uInstanceMatrix * uCollisionMatrix * vec4(vPos.xzy * uScaleDown, 1.0); + fPos = vec3(uInstanceMatrix * uCollisionMatrix * vec4(vPos.xzy * uScaleDown, 1.0)); + fColor = vec3(1.0); +} diff --git a/FModel/Settings/EndpointSettings.cs b/FModel/Settings/EndpointSettings.cs index 03390abb..98a33c3e 100644 --- a/FModel/Settings/EndpointSettings.cs +++ b/FModel/Settings/EndpointSettings.cs @@ -17,7 +17,6 @@ public class EndpointSettings : ViewModel return new EndpointSettings[] { new("https://fortnitecentral.genxgames.gg/api/v1/aes", "$.['mainKey','dynamicKeys']"), - // new("https://fortnitecentral.genxgames.gg/api/v1/mappings", "$.[?(@.meta.compressionMethod=='Oodle')].['url','fileName']") new("https://fortnitecentral.genxgames.gg/api/v1/mappings", "$.[0].['url','fileName']") // just get the first available, not just oodle! (Unfortunately not default except when resetting settings) }; default: diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 3a043223..b9298cda 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -399,6 +399,7 @@ public class CUE4ParseViewModel : ViewModel else if (endpoint.IsValid) { var mappingsFolder = Path.Combine(UserSettings.Default.OutputDirectory, ".data"); + if (endpoint.Path == "$.[?(@.meta.compressionMethod=='Oodle')].['url','fileName']") endpoint.Path = "$.[0].['url','fileName']"; var mappings = _apiEndpointView.DynamicApi.GetMappings(default, endpoint.Url, endpoint.Path); if (mappings is { Length: > 0 }) { diff --git a/FModel/Views/Snooper/Models/Collision.cs b/FModel/Views/Snooper/Models/Collision.cs new file mode 100644 index 00000000..6ac7c4d4 --- /dev/null +++ b/FModel/Views/Snooper/Models/Collision.cs @@ -0,0 +1,62 @@ +using System; +using CUE4Parse.UE4.Objects.Core.Math; +using CUE4Parse.UE4.Objects.PhysicsEngine; +using FModel.Views.Snooper.Buffers; +using FModel.Views.Snooper.Shading; +using OpenTK.Graphics.OpenGL4; + +namespace FModel.Views.Snooper.Models; + +public class Collision : IDisposable +{ + private readonly int[] _indexData; + private readonly FVector[] _vertexData; + private readonly Transform _transform; + + private int _handle; + private BufferObject _ebo { get; set; } + private BufferObject _vbo { get; set; } + private VertexArrayObject _vao { get; set; } + + public Collision(FKConvexElem convexElems) + { + _indexData = convexElems.IndexData; + _vertexData = convexElems.VertexData; + _transform = new Transform + { + Position = convexElems.Transform.Translation * Constants.SCALE_DOWN_RATIO, + Rotation = convexElems.Transform.Rotation, + Scale = convexElems.Transform.Scale3D + }; + } + + public void Setup() + { + _handle = GL.CreateProgram(); + _ebo = new BufferObject(_indexData, BufferTarget.ElementArrayBuffer); + _vbo = new BufferObject(_vertexData, BufferTarget.ArrayBuffer); + _vao = new VertexArrayObject(_vbo, _ebo); + + _vao.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 1, 0); + _vao.Unbind(); + } + + public void Render(Shader shader) + { + shader.SetUniform("uCollisionMatrix", _transform.Matrix); + + _vao.Bind(); + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); + GL.DrawElements(PrimitiveType.Triangles, _ebo.Size, DrawElementsType.UnsignedInt, 0); + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); + _vao.Unbind(); + } + + public void Dispose() + { + _ebo?.Dispose(); + _vbo?.Dispose(); + _vao?.Dispose(); + GL.DeleteProgram(_handle); + } +} diff --git a/FModel/Views/Snooper/Models/SkeletalModel.cs b/FModel/Views/Snooper/Models/SkeletalModel.cs index 92ea0b80..00846f7f 100644 --- a/FModel/Views/Snooper/Models/SkeletalModel.cs +++ b/FModel/Views/Snooper/Models/SkeletalModel.cs @@ -4,6 +4,7 @@ using CUE4Parse_Conversion.Meshes.PSK; using CUE4Parse.UE4.Assets.Exports.Animation; using CUE4Parse.UE4.Assets.Exports.SkeletalMesh; using CUE4Parse.UE4.Objects.Core.Math; +using CUE4Parse.UE4.Objects.PhysicsEngine; using CUE4Parse.UE4.Objects.UObject; using FModel.Views.Snooper.Animations; using FModel.Views.Snooper.Buffers; @@ -44,6 +45,18 @@ public class SkeletalModel : UModel Sockets.Add(new Socket(socket)); } + if (export.PhysicsAsset.TryLoad(out UPhysicsAsset physicsAsset)) + { + foreach (var skeletalBodySetup in physicsAsset.SkeletalBodySetups) + { + if (!skeletalBodySetup.TryLoad(out USkeletalBodySetup bodySetup)) continue; + foreach (var convexElem in bodySetup.AggGeom.ConvexElems) + { + Collisions.Add(new Collision(convexElem)); + } + } + } + Morphs = new List(); for (var i = 0; i < export.MorphTargets.Length; i++) { diff --git a/FModel/Views/Snooper/Models/StaticModel.cs b/FModel/Views/Snooper/Models/StaticModel.cs index be0dc9b1..2c0e073b 100644 --- a/FModel/Views/Snooper/Models/StaticModel.cs +++ b/FModel/Views/Snooper/Models/StaticModel.cs @@ -1,6 +1,7 @@ using CUE4Parse_Conversion.Meshes.PSK; using CUE4Parse.UE4.Assets.Exports.Material; using CUE4Parse.UE4.Assets.Exports.StaticMesh; +using CUE4Parse.UE4.Objects.PhysicsEngine; using FModel.Views.Snooper.Shading; namespace FModel.Views.Snooper.Models; @@ -52,6 +53,14 @@ public class StaticModel : UModel public StaticModel(UStaticMesh export, CStaticMesh staticMesh, Transform transform = null) : base(export, staticMesh.LODs[LodLevel], export.Materials, staticMesh.LODs[LodLevel].Verts, staticMesh.LODs.Count, transform) { + if (export.BodySetup.TryLoad(out UBodySetup bodySetup)) + { + foreach (var convexElem in bodySetup.AggGeom.ConvexElems) + { + Collisions.Add(new Collision(convexElem)); + } + } + Box = staticMesh.BoundingBox * Constants.SCALE_DOWN_RATIO; for (int i = 0; i < export.Sockets.Length; i++) { diff --git a/FModel/Views/Snooper/Models/UModel.cs b/FModel/Views/Snooper/Models/UModel.cs index 8e6fa3d1..9cdb0b99 100644 --- a/FModel/Views/Snooper/Models/UModel.cs +++ b/FModel/Views/Snooper/Models/UModel.cs @@ -60,6 +60,7 @@ public abstract class UModel : IRenderableModel public FBox Box; public readonly List Sockets; + public readonly List Collisions; public Material[] Materials; public bool IsTwoSided; public bool IsProp; @@ -67,12 +68,14 @@ public abstract class UModel : IRenderableModel public int VertexSize => _vertexAttributes.Where(x => x.Enabled).Sum(x => x.Size); public bool HasVertexColors => _vertexAttributes[(int) EAttribute.Colors].Enabled; public bool HasSockets => Sockets.Count > 0; + public bool HasCollisions => Collisions.Count > 0; public int TransformsCount => Transforms.Count; public bool IsSetup { get; set; } public bool IsVisible { get; set; } public bool IsSelected { get; set; } public bool ShowWireframe { get; set; } + public bool ShowCollisions { get; set; } public int SelectedInstance; protected UModel() @@ -82,6 +85,7 @@ public abstract class UModel : IRenderableModel Box = new FBox(new FVector(-2f), new FVector(2f)); Sockets = new List(); + Collisions = new List(); Transforms = new List(); } @@ -95,6 +99,7 @@ public abstract class UModel : IRenderableModel Box = new FBox(new FVector(-2f), new FVector(2f)); Sockets = new List(); + Collisions = new List(); Transforms = new List(); Attachments = new Attachment(Name); @@ -209,6 +214,11 @@ public abstract class UModel : IRenderableModel Materials[i].Setup(options, broken ? 1 : UvCount); } + foreach (var collision in Collisions) + { + collision.Setup(); + } + if (options.Models.Count == 1 && Sections.All(x => !x.Show)) { IsVisible = true; @@ -294,6 +304,16 @@ public abstract class UModel : IRenderableModel if (IsTwoSided) GL.Enable(EnableCap.CullFace); } + public void RenderCollision(Shader shader) + { + shader.SetUniform("uInstanceMatrix", GetTransform().Matrix); + shader.SetUniform("uScaleDown", Constants.SCALE_DOWN_RATIO); + foreach (var collision in Collisions) + { + collision.Render(shader); + } + } + public void Update(Options options) { MatrixVbo.Bind(); @@ -381,6 +401,11 @@ public abstract class UModel : IRenderableModel socket?.Dispose(); } Sockets.Clear(); + foreach (var collision in Collisions) + { + collision?.Dispose(); + } + Collisions.Clear(); GL.DeleteProgram(Handle); } diff --git a/FModel/Views/Snooper/Renderer.cs b/FModel/Views/Snooper/Renderer.cs index 568cf9f2..f429ce55 100644 --- a/FModel/Views/Snooper/Renderer.cs +++ b/FModel/Views/Snooper/Renderer.cs @@ -46,6 +46,7 @@ public class Renderer : IDisposable private Shader _outline; private Shader _light; private Shader _bone; + private Shader _collision; private bool _saveCameraMode; public bool ShowSkybox; @@ -227,6 +228,7 @@ public class Renderer : IDisposable _outline = new Shader("outline"); _light = new Shader("light"); _bone = new Shader("bone"); + _collision = new Shader("collision", "bone"); Picking.Setup(); Options.SetupModelsAndLights(); @@ -272,6 +274,11 @@ public class Renderer : IDisposable _bone.Render(viewMatrix, projMatrix); skeletalModel.RenderBones(_bone); } + else if (selected.ShowCollisions) + { + _collision.Render(viewMatrix, projMatrix); + selected.RenderCollision(_collision); + } _outline.Render(viewMatrix, CameraOp.Position, projMatrix); selected.Render(_outline, Color == VertexColor.TextureCoordinates ? Options.Icons["checker"] : null, true); @@ -642,6 +649,7 @@ public class Renderer : IDisposable _outline?.Dispose(); _light?.Dispose(); _bone?.Dispose(); + _collision?.Dispose(); Picking?.Dispose(); Options?.Dispose(); } diff --git a/FModel/Views/Snooper/Shading/Shader.cs b/FModel/Views/Snooper/Shading/Shader.cs index 4cbc9b13..538f05af 100644 --- a/FModel/Views/Snooper/Shading/Shader.cs +++ b/FModel/Views/Snooper/Shading/Shader.cs @@ -14,12 +14,12 @@ public class Shader : IDisposable public Shader() : this("default") {} - public Shader(string name) + public Shader(string name1, string name2 = null) { _handle = GL.CreateProgram(); - var v = LoadShader(ShaderType.VertexShader, $"{name}.vert"); - var f = LoadShader(ShaderType.FragmentShader, $"{name}.frag"); + var v = LoadShader(ShaderType.VertexShader, $"{name1}.vert"); + var f = LoadShader(ShaderType.FragmentShader, $"{name2 ?? name1}.frag"); GL.AttachShader(_handle, v); GL.AttachShader(_handle, f); GL.LinkProgram(_handle); diff --git a/FModel/Views/Snooper/SnimGui.cs b/FModel/Views/Snooper/SnimGui.cs index ff28a65a..f39c38f2 100644 --- a/FModel/Views/Snooper/SnimGui.cs +++ b/FModel/Views/Snooper/SnimGui.cs @@ -421,6 +421,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio s.Renderer.Options.SelectModel(guid); if (ImGui.MenuItem("Show", null, model.IsVisible)) model.IsVisible = !model.IsVisible; if (ImGui.MenuItem("Wireframe", null, model.ShowWireframe)) model.ShowWireframe = !model.ShowWireframe; + if (ImGui.MenuItem("Collisions", null, model.ShowCollisions, model.HasCollisions)) model.ShowCollisions = !model.ShowCollisions; ImGui.Separator(); if (ImGui.MenuItem("Save")) {