From a8a278c989e8d5d7e1e5094f10a81699ee225ac4 Mon Sep 17 00:00:00 2001 From: Asval Date: Sun, 12 May 2024 07:25:23 +0200 Subject: [PATCH] more collisions --- CUE4Parse | 2 +- FModel/MainWindow.xaml.cs | 5 +- FModel/Views/Snooper/Models/Collision.cs | 169 ++++++++++++++++++- FModel/Views/Snooper/Models/SkeletalModel.cs | 39 ++++- FModel/Views/Snooper/Models/StaticModel.cs | 34 +++- FModel/Views/Snooper/Models/UModel.cs | 11 +- 6 files changed, 242 insertions(+), 18 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index d6ef57b1..a840c298 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit d6ef57b1c46b22331589c1e0b2cfeaacfc909463 +Subproject commit a840c29822afa836d1e461360c9d5839315da46d diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index fe365445..7714cd4e 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -85,7 +85,10 @@ public partial class MainWindow #if DEBUG // await _threadWorkerView.Begin(cancellationToken => // _applicationView.CUE4Parse.Extract(cancellationToken, - // "FortniteGame/Content/Environments/Asteria/Props/Coastal/Coastal_Boat_B/Meshes/SM_Coastal_Boat_B.uasset")); + // "fortnitegame/Content/Characters/Player/Female/Large/Bodies/F_LRG_BunnyBR/Meshes/F_LRG_BunnyBR.uasset")); + // await _threadWorkerView.Begin(cancellationToken => + // _applicationView.CUE4Parse.Extract(cancellationToken, + // "FortniteGame/Content/Environments/Helios/Props/GlacierHotel/GlacierHotel_Globe_A/Meshes/SM_GlacierHotel_Globe_A.uasset")); #endif } diff --git a/FModel/Views/Snooper/Models/Collision.cs b/FModel/Views/Snooper/Models/Collision.cs index 953a573a..05e2ce44 100644 --- a/FModel/Views/Snooper/Models/Collision.cs +++ b/FModel/Views/Snooper/Models/Collision.cs @@ -1,6 +1,9 @@ -using System; +using System; +using System.Collections.Generic; +using System.Numerics; using CUE4Parse.UE4.Objects.Core.Math; using CUE4Parse.UE4.Objects.PhysicsEngine; +using CUE4Parse.UE4.Objects.UObject; using FModel.Views.Snooper.Buffers; using FModel.Views.Snooper.Shading; using OpenTK.Graphics.OpenGL4; @@ -9,16 +12,34 @@ namespace FModel.Views.Snooper.Models; public class Collision : IDisposable { + private const int Slices = 16; + private const int Stacks = 8; + private const float SectorStep = 2 * MathF.PI / Slices; + private const float StackStep = MathF.PI / Stacks; + private readonly int[] _indexData; private readonly FVector[] _vertexData; private readonly Transform _transform; + public readonly string LoweredBoneName; private int _handle; private BufferObject _ebo { get; set; } private BufferObject _vbo { get; set; } private VertexArrayObject _vao { get; set; } - public Collision(FKConvexElem convexElems) + private Collision() + { + _indexData = []; + _vertexData = []; + _transform = Transform.Identity; + } + + private Collision(FName boneName) : this() + { + LoweredBoneName = boneName.Text.ToLower(); + } + + public Collision(FKConvexElem convexElems, FName boneName = default) : this(boneName) { _indexData = convexElems.IndexData; _vertexData = convexElems.VertexData; @@ -30,6 +51,146 @@ public class Collision : IDisposable }; } + public Collision(FKSphereElem sphereElem, FName boneName = default) : this(boneName) + { + _vertexData = new FVector[(Slices + 1) * (Stacks + 1)]; + for (var i = 0; i <= Stacks; i++) + { + var stackAngle = MathF.PI / 2 - i * StackStep; + var xy = MathF.Cos(stackAngle); + var z = MathF.Sin(stackAngle); + + for (var j = 0; j <= Slices; j++) + { + var sectorAngle = j * SectorStep; + var x = xy * MathF.Cos(sectorAngle); + var y = xy * MathF.Sin(sectorAngle); + _vertexData[i * (Slices + 1) + j] = new FVector(x, y, z); + } + } + + _indexData = new int[Stacks * Slices * 6]; + for (var i = 0; i < Stacks; i++) + { + for (var j = 0; j < Slices; j++) + { + var a = i * (Slices + 1) + j; + var b = a + Slices + 1; + _indexData[(i * Slices + j) * 6 + 0] = a; + _indexData[(i * Slices + j) * 6 + 1] = b; + _indexData[(i * Slices + j) * 6 + 2] = a + 1; + _indexData[(i * Slices + j) * 6 + 3] = b; + _indexData[(i * Slices + j) * 6 + 4] = b + 1; + _indexData[(i * Slices + j) * 6 + 5] = a + 1; + } + } + + _transform = new Transform + { + Position = sphereElem.Center * Constants.SCALE_DOWN_RATIO, + Scale = new FVector(sphereElem.Radius) + }; + } + + public Collision(FKBoxElem boxElem, FName boneName = default) : this(boneName) + { + _vertexData = + [ + new FVector(-boxElem.X, -boxElem.Y, -boxElem.Z), + new FVector(boxElem.X, -boxElem.Y, -boxElem.Z), + new FVector(boxElem.X, boxElem.Y, -boxElem.Z), + new FVector(-boxElem.X, boxElem.Y, -boxElem.Z), + new FVector(-boxElem.X, -boxElem.Y, boxElem.Z), + new FVector(boxElem.X, -boxElem.Y, boxElem.Z), + new FVector(boxElem.X, boxElem.Y, boxElem.Z), + new FVector(-boxElem.X, boxElem.Y, boxElem.Z) + ]; + + _indexData = + [ + 0, 1, 2, 2, 3, 0, + 1, 5, 6, 6, 2, 1, + 5, 4, 7, 7, 6, 5, + 4, 0, 3, 3, 7, 4, + 3, 2, 6, 6, 7, 3, + 4, 5, 1, 1, 0, 4 + ]; + + _transform = new Transform + { + Position = boxElem.Center * Constants.SCALE_DOWN_RATIO, + Rotation = boxElem.Rotation.Quaternion(), + Scale = new FVector(.5f) + }; + } + + public Collision(FKSphylElem sphylElem, FName boneName = default) + : this(sphylElem.Length, [sphylElem.Radius, sphylElem.Radius], sphylElem.Center, sphylElem.Rotation, boneName) {} + public Collision(FKTaperedCapsuleElem taperedCapsuleElem, FName boneName = default) + : this(taperedCapsuleElem.Length, [taperedCapsuleElem.Radius1, taperedCapsuleElem.Radius0], taperedCapsuleElem.Center, taperedCapsuleElem.Rotation, boneName) {} + + private Collision(float length, float[] radius, FVector center = default, FRotator rotator = default, FName boneName = default) : this(boneName) + { + int vLength = 0; + int half = Slices / 2; + int k2 = (Slices + 1) * (Stacks + 1); + + _vertexData = new FVector[k2 + Slices + 1]; + for(int i = 0; i < 2; ++i) + { + float h = -length / 2.0f + i * length; + int start = i == 0 ? Stacks / 2 : 0; + int end = i == 0 ? Stacks : Stacks / 2; + + for(int j = start; j <= end; ++j) + { + var stackAngle = MathF.PI / 2 - j * StackStep; + var xy = radius[i] * MathF.Cos(stackAngle); + var z = radius[i] * MathF.Sin(stackAngle) + h; + + for(int k = 0; k <= Slices; ++k) + { + var sectorAngle = k * SectorStep; + var x = xy * MathF.Cos(sectorAngle); + var y = xy * MathF.Sin(sectorAngle); + _vertexData[vLength++] = new FVector(x, y, z); + } + } + } + + var indices = new List(); + AddIndicesForSlices(indices, ref k2); + indices.AddRange(new[] {0, k2, k2, k2 - half, half, half}); + AddIndicesForStacks(indices); + half /= 2; + indices.AddRange(new[] {half, k2 - half * 3, k2 - half * 3, half * 3, k2 - half, k2 - half}); + AddIndicesForStacks(indices, Stacks / 2); + _indexData = indices.ToArray(); + + _transform = new Transform + { + Position = center * Constants.SCALE_DOWN_RATIO, + Rotation = rotator.Quaternion() + }; + } + + private void AddIndicesForSlices(List indices, ref int k2) + { + for(int k1 = 0; k1 < Slices; ++k1, ++k2) + { + indices.AddRange(new[] {k1, k1 + 1, k1 + 1, k2, k2 + 1, k2 + 1}); + } + } + + private void AddIndicesForStacks(List indices, int start = 0) + { + for (int k1 = start; k1 < Stacks * Slices + Slices; k1 += Slices + 1) + { + if (k1 == Stacks / 2 * (Slices + 1) + start) continue; + indices.AddRange(new[] {k1, k1 + Slices + 1, k1 + Slices + 1, k1 + Slices / 2, k1 + Slices / 2 + Slices + 1, k1 + Slices / 2 + Slices + 1}); + } + } + public void Setup() { _handle = GL.CreateProgram(); @@ -41,9 +202,9 @@ public class Collision : IDisposable _vao.Unbind(); } - public void Render(Shader shader) + public void Render(Shader shader, Matrix4x4 boneMatrix) { - shader.SetUniform("uCollisionMatrix", _transform.Matrix); + shader.SetUniform("uCollisionMatrix", _transform.Matrix * boneMatrix); _vao.Bind(); if (_indexData.Length > 0) diff --git a/FModel/Views/Snooper/Models/SkeletalModel.cs b/FModel/Views/Snooper/Models/SkeletalModel.cs index 461d5d3f..92411f18 100644 --- a/FModel/Views/Snooper/Models/SkeletalModel.cs +++ b/FModel/Views/Snooper/Models/SkeletalModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Numerics; using CUE4Parse_Conversion.Meshes.PSK; using CUE4Parse.UE4.Assets.Exports.Animation; using CUE4Parse.UE4.Assets.Exports.SkeletalMesh; @@ -52,7 +53,23 @@ public class SkeletalModel : UModel if (!skeletalBodySetup.TryLoad(out USkeletalBodySetup bodySetup) || bodySetup.AggGeom == null) continue; foreach (var convexElem in bodySetup.AggGeom.ConvexElems) { - Collisions.Add(new Collision(convexElem)); + Collisions.Add(new Collision(convexElem, bodySetup.BoneName)); + } + foreach (var sphereElem in bodySetup.AggGeom.SphereElems) + { + Collisions.Add(new Collision(sphereElem, bodySetup.BoneName)); + } + foreach (var boxElem in bodySetup.AggGeom.BoxElems) + { + Collisions.Add(new Collision(boxElem, bodySetup.BoneName)); + } + foreach (var sphylElem in bodySetup.AggGeom.SphylElems) + { + Collisions.Add(new Collision(sphylElem, bodySetup.BoneName)); + } + foreach (var taperedCapsuleElem in bodySetup.AggGeom.TaperedCapsuleElems) + { + Collisions.Add(new Collision(taperedCapsuleElem, bodySetup.BoneName)); } } } @@ -108,6 +125,26 @@ public class SkeletalModel : UModel Vao.Unbind(); } + public override void RenderCollision(Shader shader) + { + base.RenderCollision(shader); + + GL.Disable(EnableCap.DepthTest); + GL.Disable(EnableCap.CullFace); + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); + foreach (var collision in Collisions) + { + var boneMatrix = Matrix4x4.Identity; + if (Skeleton.BonesByLoweredName.TryGetValue(collision.LoweredBoneName, out var bone)) + boneMatrix = Skeleton.GetBoneMatrix(bone); + + collision.Render(shader, boneMatrix); + } + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); + GL.Enable(EnableCap.CullFace); + GL.Enable(EnableCap.DepthTest); + } + public void Render(Shader shader) { shader.SetUniform("uMorphTime", MorphTime); diff --git a/FModel/Views/Snooper/Models/StaticModel.cs b/FModel/Views/Snooper/Models/StaticModel.cs index 59911859..369295e2 100644 --- a/FModel/Views/Snooper/Models/StaticModel.cs +++ b/FModel/Views/Snooper/Models/StaticModel.cs @@ -1,8 +1,10 @@ -using CUE4Parse_Conversion.Meshes.PSK; +using System.Numerics; +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; +using OpenTK.Graphics.OpenGL4; namespace FModel.Views.Snooper.Models; @@ -59,6 +61,22 @@ public class StaticModel : UModel { Collisions.Add(new Collision(convexElem)); } + foreach (var sphereElem in bodySetup.AggGeom.SphereElems) + { + Collisions.Add(new Collision(sphereElem)); + } + foreach (var boxElem in bodySetup.AggGeom.BoxElems) + { + Collisions.Add(new Collision(boxElem)); + } + foreach (var sphylElem in bodySetup.AggGeom.SphylElems) + { + Collisions.Add(new Collision(sphylElem)); + } + foreach (var taperedCapsuleElem in bodySetup.AggGeom.TaperedCapsuleElems) + { + Collisions.Add(new Collision(taperedCapsuleElem)); + } } Box = staticMesh.BoundingBox * Constants.SCALE_DOWN_RATIO; @@ -68,4 +86,18 @@ public class StaticModel : UModel Sockets.Add(new Socket(socket)); } } + + public override void RenderCollision(Shader shader) + { + base.RenderCollision(shader); + + GL.Disable(EnableCap.CullFace); + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); + foreach (var collision in Collisions) + { + collision.Render(shader, Matrix4x4.Identity); + } + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); + GL.Enable(EnableCap.CullFace); + } } diff --git a/FModel/Views/Snooper/Models/UModel.cs b/FModel/Views/Snooper/Models/UModel.cs index 918d48e9..4f398e19 100644 --- a/FModel/Views/Snooper/Models/UModel.cs +++ b/FModel/Views/Snooper/Models/UModel.cs @@ -305,19 +305,10 @@ public abstract class UModel : IRenderableModel if (IsTwoSided) GL.Enable(EnableCap.CullFace); } - public void RenderCollision(Shader shader) + public virtual void RenderCollision(Shader shader) { shader.SetUniform("uInstanceMatrix", GetTransform().Matrix); shader.SetUniform("uScaleDown", Constants.SCALE_DOWN_RATIO); - - GL.Disable(EnableCap.CullFace); - GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); - foreach (var collision in Collisions) - { - collision.Render(shader); - } - GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); - GL.Enable(EnableCap.CullFace); } public void Update(Options options)