diff --git a/FModel/Views/Snooper/Camera.cs b/FModel/Views/Snooper/Camera.cs index 520c24a6..a0af4c15 100644 --- a/FModel/Views/Snooper/Camera.cs +++ b/FModel/Views/Snooper/Camera.cs @@ -17,12 +17,11 @@ public class Camera public Vector3 Position; public Vector3 Direction; - public Vector3 Focus => Position - Direction; - public Vector3 Up = Vector3.UnitY; - public WorldMode Mode = UserSettings.Default.CameraMode; + public WorldMode Mode; + public Vector3 PositionArc => Position - Direction; + public Vector3 DirectionArc => Direction - Position; + public Vector3 Up => Vector3.UnitY; - public float Yaw = -90f; - public float Pitch = 0f; public float Zoom = 60f; public float Speed = 1f; public float Far = 100f; @@ -33,27 +32,11 @@ public class Camera { Position = new Vector3(0, 1, 1); Direction = Vector3.Zero; - - InitDirection(); + Mode = UserSettings.Default.CameraMode; } - public Camera(FBox box, float far) - { - Far = far; - Teleport(FVector.ZeroVector, box, true); - } - - public Camera(Vector3 position, Vector3 direction, float far, float speed) - { - Position = position; - Direction = direction; - Far = far; - Speed = speed; - - InitDirection(); - } - - public void Teleport(FVector instancePos, FBox box, bool updateSpeed = false) + public void Setup(FBox box) => Teleport(FVector.ZeroVector, box, true); + public void Teleport(FVector instancePos, FBox box, bool updateAll = false) { box.GetCenterAndExtents(out var center, out var extents); center = center.ToMapVector(); @@ -62,58 +45,42 @@ public class Camera Position = new Vector3(instancePos.X, center.Y, instancePos.Z + distance * 2); Direction = new Vector3(center.X, center.Y, center.Z); - if (updateSpeed) Speed = distance; - - InitDirection(); - } - - private void InitDirection() - { - // trigonometric math to calculate the cam's yaw/pitch based on position and direction to look - var yaw = MathF.Atan((-Position.X - Direction.X) / (Position.Z - Direction.Z)); - var pitch = MathF.Atan((Position.Y - Direction.Y) / (Position.Z - Direction.Z)); - Modify(Helper.RadiansToDegrees(yaw), Helper.RadiansToDegrees(pitch)); + if (updateAll) + { + Far = Math.Max(Far, box.Max.AbsMax() * 50f); + Speed = Math.Max(Speed, distance); + } } public void Modify(Vector2 mouseDelta) { var lookSensitivity = Mode switch { - WorldMode.FlyCam => 0.1f, - WorldMode.Arcball => 0.01f, + WorldMode.FlyCam => 0.002f, + WorldMode.Arcball => 0.003f, _ => throw new ArgumentOutOfRangeException() }; mouseDelta *= lookSensitivity; - Modify(mouseDelta.X, mouseDelta.Y); - } - private void Modify(float xOffset, float yOffset) - { + + var rotationX = Matrix4x4.CreateFromAxisAngle(-Up, mouseDelta.X); switch (Mode) { case WorldMode.FlyCam: { - Yaw += xOffset; - Pitch -= yOffset; - Pitch = Math.Clamp(Pitch, -89f, 89f); + Direction = Vector3.Transform(DirectionArc, rotationX) + Position; - var direction = Vector3.Zero; - var yaw = Helper.DegreesToRadians(Yaw); - var pitch = Helper.DegreesToRadians(Pitch); - direction.X = MathF.Cos(yaw) * MathF.Cos(pitch); - direction.Y = MathF.Sin(pitch); - direction.Z = MathF.Sin(yaw) * MathF.Cos(pitch); - Direction = Vector3.Normalize(direction); + var right = Vector3.Normalize(Vector3.Cross(Up, DirectionArc)); + var rotationY = Matrix4x4.CreateFromAxisAngle(right, mouseDelta.Y); + Direction = Vector3.Transform(DirectionArc, rotationY) + Position; break; } case WorldMode.Arcball: { - var up = -Up; - var rotationX = Matrix4x4.CreateFromAxisAngle(up, xOffset); - Position = Vector3.Transform(Focus, rotationX) + Direction; + Position = Vector3.Transform(PositionArc, rotationX) + Direction; - var right = Vector3.Normalize(Vector3.Cross(up, Focus)); - var rotationY = Matrix4x4.CreateFromAxisAngle(right, yOffset); - Position = Vector3.Transform(Focus, rotationY) + Direction; + var right = Vector3.Normalize(Vector3.Cross(-Up, PositionArc)); + var rotationY = Matrix4x4.CreateFromAxisAngle(right, mouseDelta.Y); + Position = Vector3.Transform(PositionArc, rotationY) + Direction; break; } default: @@ -123,71 +90,71 @@ public class Camera public void Modify(KeyboardState keyboard, float time) { + if (!keyboard.IsAnyKeyDown) return; var multiplier = keyboard.IsKeyDown(Keys.LeftShift) ? 2f : 1f; var moveSpeed = Speed * multiplier * time; - - var focus = Mode switch - { - WorldMode.FlyCam => Direction, - WorldMode.Arcball => -Focus, - _ => throw new ArgumentOutOfRangeException() - }; - - if (keyboard.IsKeyDown(Keys.W)) - Position += moveSpeed * focus; - if (keyboard.IsKeyDown(Keys.S)) - Position -= moveSpeed * focus; + var moveAxis = Vector3.Normalize(-PositionArc); + var panAxis = Vector3.Normalize(Vector3.Cross(moveAxis, Up)); switch (Mode) { case WorldMode.FlyCam: { - if (keyboard.IsKeyDown(Keys.A)) - Position -= Vector3.Normalize(Vector3.Cross(focus, Up)) * moveSpeed; - if (keyboard.IsKeyDown(Keys.D)) - Position += Vector3.Normalize(Vector3.Cross(focus, Up)) * moveSpeed; - if (keyboard.IsKeyDown(Keys.E)) - Position += moveSpeed * Up; - if (keyboard.IsKeyDown(Keys.Q)) - Position -= moveSpeed * Up; + if (keyboard.IsKeyDown(Keys.W)) // forward + { + var d = moveSpeed * moveAxis; + Position += d; + Direction += d; + } + if (keyboard.IsKeyDown(Keys.S)) // backward + { + var d = moveSpeed * moveAxis; + Position -= d; + Direction -= d; + } break; } case WorldMode.Arcball: { - if (keyboard.IsKeyDown(Keys.A)) - { - var d = Vector3.Normalize(Vector3.Cross(focus, Up)) * moveSpeed; - Position -= d; - Direction -= d; - } - if (keyboard.IsKeyDown(Keys.D)) - { - var d = Vector3.Normalize(Vector3.Cross(focus, Up)) * moveSpeed; - Position += d; - Direction += d; - } - if (keyboard.IsKeyDown(Keys.E)) - { - var d = moveSpeed * Up; - Position += d; - Direction += d; - } - if (keyboard.IsKeyDown(Keys.Q)) - { - var d = moveSpeed * Up; - Position -= d; - Direction -= d; - } + if (keyboard.IsKeyDown(Keys.W)) // forward + Position += moveSpeed * moveAxis; + if (keyboard.IsKeyDown(Keys.S)) // backward + Position -= moveSpeed * moveAxis; break; } default: throw new ArgumentOutOfRangeException(); } - if (keyboard.IsKeyDown(Keys.X)) - ModifyZoom(-.5f); - if (keyboard.IsKeyDown(Keys.C)) + if (keyboard.IsKeyDown(Keys.A)) // left + { + var d = panAxis * moveSpeed; + Position -= d; + Direction -= d; + } + if (keyboard.IsKeyDown(Keys.D)) // right + { + var d = panAxis * moveSpeed; + Position += d; + Direction += d; + } + if (keyboard.IsKeyDown(Keys.E)) // up + { + var d = moveSpeed * Up; + Position += d; + Direction += d; + } + if (keyboard.IsKeyDown(Keys.Q)) // down + { + var d = moveSpeed * Up; + Position -= d; + Direction -= d; + } + + if (keyboard.IsKeyDown(Keys.C)) // zoom in ModifyZoom(+.5f); + if (keyboard.IsKeyDown(Keys.X)) // zoom out + ModifyZoom(-.5f); } private void ModifyZoom(float zoomAmount) @@ -196,20 +163,9 @@ public class Camera Zoom = Math.Clamp(Zoom - zoomAmount, 1.0f, 89f); } - public Matrix4x4 GetViewMatrix() - { - return Mode switch - { - WorldMode.FlyCam => Matrix4x4.CreateLookAt(Position, Position + Direction, Up), - WorldMode.Arcball => Matrix4x4.CreateLookAt(Position, Direction, Up), - _ => throw new ArgumentOutOfRangeException() - }; - } - + public Matrix4x4 GetViewMatrix() => Matrix4x4.CreateLookAt(Position, Direction, Up); public Matrix4x4 GetProjectionMatrix() - { - return Matrix4x4.CreatePerspectiveFieldOfView(Helper.DegreesToRadians(Zoom), AspectRatio, Near, Far); - } + => Matrix4x4.CreatePerspectiveFieldOfView(Helper.DegreesToRadians(Zoom), AspectRatio, Near, Far); private const float _step = 0.01f; private const float _zero = 0.000001f; // doesn't actually work if _infinite is used as max value /shrug diff --git a/FModel/Views/Snooper/Models/Cube.cs b/FModel/Views/Snooper/Models/Cube.cs index b984720e..3681cf08 100644 --- a/FModel/Views/Snooper/Models/Cube.cs +++ b/FModel/Views/Snooper/Models/Cube.cs @@ -1,66 +1,41 @@ -using CUE4Parse.UE4.Assets.Exports.Material; +using CUE4Parse_Conversion.Meshes.PSK; +using CUE4Parse.UE4.Assets.Exports.Material; using FModel.Views.Snooper.Shading; namespace FModel.Views.Snooper.Models; public class Cube : Model { - public Cube(UMaterialInterface unrealMaterial) : base(unrealMaterial) + public Cube(CStaticMesh mesh, UMaterialInterface unrealMaterial) : base(unrealMaterial) { - Indices = new uint[] + var lod = mesh.LODs[0]; + + Indices = new uint[lod.Indices.Value.Length]; + for (int i = 0; i < Indices.Length; i++) { - 0, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, - 32, 33, 34, 35 - }; - Vertices = new float[] { - // I X Y Z Normals Tangent U V Layer - -1, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, .5f, - -1, 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, .5f, - -1, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, .5f, - -1, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, .5f, - -1, -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, .5f, - -1, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, .5f, + Indices[i] = (uint) lod.Indices.Value[i]; + } - -1, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, .5f, - -1, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, .5f, - -1, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, .5f, - -1, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, .5f, - -1, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, .5f, - -1, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, .5f, - - -1, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, .5f, - -1, -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, .5f, - -1, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, .5f, - -1, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, .5f, - -1, -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, .5f, - -1, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, .5f, - - -1, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, .5f, - -1, 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, .5f, - -1, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, .5f, - -1, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, .5f, - -1, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, .5f, - -1, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, .5f, - - -1, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, .5f, - -1, 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, .5f, - -1, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, .5f, - -1, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, .5f, - -1, -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, .5f, - -1, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, .5f, - - -1, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, .5f, - -1, 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, .5f, - -1, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, .5f, - -1, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, .5f, - -1, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, .5f, - -1, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, .5f - }; + Vertices = new float[lod.NumVerts * VertexSize]; + for (int i = 0; i < lod.Verts.Length; i++) + { + var count = 0; + var baseIndex = i * VertexSize; + var vert = lod.Verts[i]; + Vertices[baseIndex + count++] = i; + Vertices[baseIndex + count++] = vert.Position.X * Constants.SCALE_DOWN_RATIO; + Vertices[baseIndex + count++] = vert.Position.Z * Constants.SCALE_DOWN_RATIO; + Vertices[baseIndex + count++] = vert.Position.Y * Constants.SCALE_DOWN_RATIO; + Vertices[baseIndex + count++] = vert.Normal.X; + Vertices[baseIndex + count++] = vert.Normal.Z; + Vertices[baseIndex + count++] = vert.Normal.Y; + Vertices[baseIndex + count++] = vert.Tangent.X; + Vertices[baseIndex + count++] = vert.Tangent.Z; + Vertices[baseIndex + count++] = vert.Tangent.Y; + Vertices[baseIndex + count++] = vert.UV.U; + Vertices[baseIndex + count++] = vert.UV.V; + Vertices[baseIndex + count++] = .5f; + } Materials = new Material[1]; Materials[0] = new Material(unrealMaterial) { IsUsed = true }; diff --git a/FModel/Views/Snooper/Models/Model.cs b/FModel/Views/Snooper/Models/Model.cs index f4e57576..a8450660 100644 --- a/FModel/Views/Snooper/Models/Model.cs +++ b/FModel/Views/Snooper/Models/Model.cs @@ -33,7 +33,7 @@ public class Model : IDisposable private VertexArrayObject _vao; private readonly UObject _export; - private readonly int _vertexSize = 13; // VertexIndex + Position + Normal + Tangent + UV + TextureLayer + protected readonly int VertexSize = 13; // VertexIndex + Position + Normal + Tangent + UV + TextureLayer private const int _faceSize = 3; public readonly string Path; @@ -70,7 +70,7 @@ public class Model : IDisposable Name = Path.SubstringAfterLast('/').SubstringBefore('.'); Type = export.ExportType; UvCount = 1; - Box = new FBox(new FVector(-.65f), new FVector(.65f)); + Box = new FBox(new FVector(-2f), new FVector(2f)); Transforms = new List(); } @@ -96,7 +96,7 @@ public class Model : IDisposable Morphs = new Morph[length]; for (var i = 0; i < Morphs.Length; i++) { - Morphs[i] = new Morph(Vertices, _vertexSize, morphTargets[i].Load()); + Morphs[i] = new Morph(Vertices, VertexSize, morphTargets[i].Load()); ApplicationService.ApplicationView.Status.UpdateStatusLabel($"{Morphs[i].Name} ... {i}/{length}"); } ApplicationService.ApplicationView.Status.UpdateStatusLabel(""); @@ -117,13 +117,13 @@ public class Model : IDisposable if (lod.VertexColors is { Length: > 0}) { HasVertexColors = true; - _vertexSize += 4; // + Color + VertexSize += 4; // + Color } if (skeleton != null) { Skeleton = new Skeleton(skeleton); - _vertexSize += 8; // + BoneIds + BoneWeights + VertexSize += 8; // + BoneIds + BoneWeights } Indices = new uint[lod.Indices.Value.Length]; @@ -132,11 +132,11 @@ public class Model : IDisposable Indices[i] = (uint) lod.Indices.Value[i]; } - Vertices = new float[lod.NumVerts * _vertexSize]; + Vertices = new float[lod.NumVerts * VertexSize]; for (int i = 0; i < vertices.Length; i++) { var count = 0; - var baseIndex = i * _vertexSize; + var baseIndex = i * VertexSize; var vert = vertices[i]; Vertices[baseIndex + count++] = i; Vertices[baseIndex + count++] = vert.Position.X * Constants.SCALE_DOWN_RATIO; @@ -224,15 +224,15 @@ public class Model : IDisposable _vbo = new BufferObject(Vertices, BufferTarget.ArrayBuffer); _vao = new VertexArrayObject(_vbo, _ebo); - _vao.VertexAttributePointer(0, 1, VertexAttribPointerType.Int, _vertexSize, 0); // vertex index - _vao.VertexAttributePointer(1, 3, VertexAttribPointerType.Float, _vertexSize, 1); // position - _vao.VertexAttributePointer(2, 3, VertexAttribPointerType.Float, _vertexSize, 4); // normal - _vao.VertexAttributePointer(3, 3, VertexAttribPointerType.Float, _vertexSize, 7); // tangent - _vao.VertexAttributePointer(4, 2, VertexAttribPointerType.Float, _vertexSize, 10); // uv - if (!broken) _vao.VertexAttributePointer(5, 1, VertexAttribPointerType.Float, _vertexSize, 12); // texture index - _vao.VertexAttributePointer(6, 4, VertexAttribPointerType.Float, _vertexSize, 13); // color - _vao.VertexAttributePointer(7, 4, VertexAttribPointerType.Float, _vertexSize, 17); // boneids - _vao.VertexAttributePointer(8, 4, VertexAttribPointerType.Float, _vertexSize, 21); // boneweights + _vao.VertexAttributePointer(0, 1, VertexAttribPointerType.Int, VertexSize, 0); // vertex index + _vao.VertexAttributePointer(1, 3, VertexAttribPointerType.Float, VertexSize, 1); // position + _vao.VertexAttributePointer(2, 3, VertexAttribPointerType.Float, VertexSize, 4); // normal + _vao.VertexAttributePointer(3, 3, VertexAttribPointerType.Float, VertexSize, 7); // tangent + _vao.VertexAttributePointer(4, 2, VertexAttribPointerType.Float, VertexSize, 10); // uv + if (!broken) _vao.VertexAttributePointer(5, 1, VertexAttribPointerType.Float, VertexSize, 12); // texture index + _vao.VertexAttributePointer(6, 4, VertexAttribPointerType.Float, VertexSize, 13); // color + _vao.VertexAttributePointer(7, 4, VertexAttribPointerType.Float, VertexSize, 17); // boneids + _vao.VertexAttributePointer(8, 4, VertexAttribPointerType.Float, VertexSize, 21); // boneweights SetupInstances(); // instanced models transform diff --git a/FModel/Views/Snooper/Renderer.cs b/FModel/Views/Snooper/Renderer.cs index 044bce80..dcd84a64 100644 --- a/FModel/Views/Snooper/Renderer.cs +++ b/FModel/Views/Snooper/Renderer.cs @@ -14,6 +14,8 @@ using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Objects.Core.Math; using CUE4Parse.UE4.Objects.Engine; using CUE4Parse.UE4.Objects.UObject; +using FModel.Creator; +using FModel.Extensions; using FModel.Settings; using FModel.Views.Snooper.Buffers; using FModel.Views.Snooper.Lights; @@ -36,6 +38,7 @@ public class Renderer : IDisposable public bool ShowLights; public int VertexColor; + public Camera CameraOp { get; } public PickingTexture Picking { get; } public Options Options { get; } @@ -44,6 +47,7 @@ public class Renderer : IDisposable _skybox = new Skybox(); _grid = new Grid(); + CameraOp = new Camera(); Picking = new PickingTexture(width, height); Options = new Options(); @@ -52,17 +56,25 @@ public class Renderer : IDisposable VertexColor = 0; // default } - public Camera Load(CancellationToken cancellationToken, UObject export) + public void Load(CancellationToken cancellationToken, UObject export) { ShowLights = false; - return export switch + switch (export) { - UStaticMesh st => LoadStaticMesh(st), - USkeletalMesh sk => LoadSkeletalMesh(sk), - UMaterialInstance mi => LoadMaterialInstance(mi), - UWorld wd => LoadWorld(cancellationToken, wd, Transform.Identity), - _ => throw new ArgumentOutOfRangeException(nameof(export)) - }; + case UStaticMesh st: + LoadStaticMesh(st); + break; + case USkeletalMesh sk: + LoadSkeletalMesh(sk); + break; + case UMaterialInstance mi: + LoadMaterialInstance(mi); + break; + case UWorld wd: + LoadWorld(cancellationToken, wd, Transform.Identity); + CameraOp.Mode = Camera.WorldMode.FlyCam; + break; + } } public void Swap(UMaterialInstance unrealMaterial) @@ -97,15 +109,15 @@ public class Renderer : IDisposable Options.SetupModelsAndLights(); } - public void Render(Camera cam) + public void Render() { - var viewMatrix = cam.GetViewMatrix(); - var projMatrix = cam.GetProjectionMatrix(); + var viewMatrix = CameraOp.GetViewMatrix(); + var projMatrix = CameraOp.GetProjectionMatrix(); if (ShowSkybox) _skybox.Render(viewMatrix, projMatrix); - if (ShowGrid) _grid.Render(viewMatrix, projMatrix, cam.Near, cam.Far); + if (ShowGrid) _grid.Render(viewMatrix, projMatrix, CameraOp.Near, CameraOp.Far); - _shader.Render(viewMatrix, cam.Position, projMatrix); + _shader.Render(viewMatrix, CameraOp.Position, projMatrix); for (int i = 0; i < 5; i++) _shader.SetUniform($"bVertexColors[{i}]", i == VertexColor); @@ -132,7 +144,7 @@ public class Renderer : IDisposable // outline pass if (Options.TryGetModel(out var selected) && selected.Show) { - _outline.Render(viewMatrix, cam.Position, projMatrix); + _outline.Render(viewMatrix, CameraOp.Position, projMatrix); selected.Outline(_outline); } @@ -140,55 +152,73 @@ public class Renderer : IDisposable Picking.Render(viewMatrix, projMatrix, Options.Models); } - private Camera SetupCamera(FBox box) - { - var far = box.Max.AbsMax(); - return new Camera(box, far * 50f); - } - - private Camera LoadStaticMesh(UStaticMesh original) + private void LoadStaticMesh(UStaticMesh original) { var guid = original.LightingGuid; if (Options.TryGetModel(guid, out var model)) { model.AddInstance(Transform.Identity); Application.Current.Dispatcher.Invoke(() => model.SetupInstances()); - return null; + return; } if (!original.TryConvert(out var mesh)) - return null; + return; Options.Models[guid] = new Model(original, mesh); Options.SelectModel(guid); - return SetupCamera(Options.Models[guid].Box); + SetupCamera(Options.Models[guid].Box); } - private Camera LoadSkeletalMesh(USkeletalMesh original) + private void LoadSkeletalMesh(USkeletalMesh original) { var guid = Guid.NewGuid(); - if (Options.Models.ContainsKey(guid) || !original.TryConvert(out var mesh)) return null; + if (Options.Models.ContainsKey(guid) || !original.TryConvert(out var mesh)) return; Options.Models[guid] = new Model(original, mesh); Options.SelectModel(guid); - return SetupCamera(Options.Models[guid].Box); + SetupCamera(Options.Models[guid].Box); } - private Camera LoadMaterialInstance(UMaterialInstance original) + private void LoadMaterialInstance(UMaterialInstance original) { - var guid = Guid.NewGuid(); - if (Options.Models.ContainsKey(guid)) return null; + if (!Utils.TryLoadObject("Engine/Content/EditorMeshes/EditorCube.EditorCube", out UStaticMesh editorCube)) + return; - Options.Models[guid] = new Cube(original); + var guid = editorCube.LightingGuid; + if (Options.TryGetModel(guid, out var model)) + { + model.Materials[0].SwapMaterial(original); + Application.Current.Dispatcher.Invoke(() => model.Materials[0].Setup(Options, model.UvCount)); + return; + } + + if (!editorCube.TryConvert(out var mesh)) + return; + + Options.Models[guid] = new Cube(mesh, original); Options.SelectModel(guid); - return SetupCamera(Options.Models[guid].Box); + SetupCamera(Options.Models[guid].Box); } - private Camera LoadWorld(CancellationToken cancellationToken, UWorld original, Transform transform) + private void SetupCamera(FBox box) => CameraOp.Setup(box); + + private void LoadWorld(CancellationToken cancellationToken, UWorld original, Transform transform) { - var cam = new Camera(new Vector3(0f, 5f, 5f), Vector3.Zero, 1000f, 5f); + CameraOp.Setup(new FBox(FVector.ZeroVector, new FVector(0, 10, 10))); if (original.PersistentLevel.Load() is not { } persistentLevel) - return cam; + return; + + if (persistentLevel.TryGetValue(out FSoftObjectPath runtimeCell, "WorldPartitionRuntimeCell") && + Utils.TryLoadObject(runtimeCell.AssetPathName.Text.SubstringBeforeWithLast(".") + runtimeCell.SubPathString.SubstringAfterLast("."), out UObject worldPartition)) + { + var ratio = MathF.Pow(Constants.SCALE_DOWN_RATIO, 2); + var position = worldPartition.GetOrDefault("Position", FVector.ZeroVector).ToMapVector() * Constants.SCALE_DOWN_RATIO; + var box = worldPartition.GetOrDefault("ContentBounds", new FBox(FVector.ZeroVector, FVector.OneVector)); + box.Min *= ratio;box.Max *= ratio; + + CameraOp.Teleport(position, box, true); + } var length = persistentLevel.Actors.Length; for (var i = 0; i < length; i++) @@ -200,27 +230,22 @@ public class Renderer : IDisposable continue; Services.ApplicationService.ApplicationView.Status.UpdateStatusLabel($"{original.Name} ... {i}/{length}"); - WorldCamera(actor, ref cam); + WorldCamera(actor); // WorldLight(actor); WorldMesh(actor, transform); AdditionalWorlds(actor, transform.Matrix, cancellationToken); } Services.ApplicationService.ApplicationView.Status.UpdateStatusLabel($"{original.Name} ... {length}/{length}"); - return cam; } - private void WorldCamera(UObject actor, ref Camera cam) + private void WorldCamera(UObject actor) { if (actor.ExportType != "LevelBounds" || !actor.TryGetValue(out FPackageIndex boxComponent, "BoxComponent") || boxComponent.Load() is not { } boxObject) return; var direction = boxObject.GetOrDefault("RelativeLocation", FVector.ZeroVector).ToMapVector() * Constants.SCALE_DOWN_RATIO; var position = boxObject.GetOrDefault("RelativeScale3D", FVector.OneVector).ToMapVector() / 2f * Constants.SCALE_DOWN_RATIO; - var far = position.AbsMax(); - cam = new Camera( - new Vector3(position.X, position.Y, position.Z), - new Vector3(direction.X, direction.Y, direction.Z), - far * 25f, Math.Max(5f, far / 10f)); + CameraOp.Setup(new FBox(direction, position)); } private void WorldLight(UObject actor) @@ -344,12 +369,19 @@ public class Renderer : IDisposable }; for (int j = 0; j < additionalWorlds.Length; j++) - if (Creator.Utils.TryLoadObject(additionalWorlds[j].AssetPathName.Text, out UWorld w)) + if (Utils.TryLoadObject(additionalWorlds[j].AssetPathName.Text, out UWorld w)) LoadWorld(cancellationToken, w, transform); } + public void WindowResized(int width, int height) + { + CameraOp.AspectRatio = width / (float) height; + Picking.WindowResized(width, height); + } + public void Save() { + UserSettings.Default.CameraMode = CameraOp.Mode; UserSettings.Default.ShowSkybox = ShowSkybox; UserSettings.Default.ShowGrid = ShowGrid; } diff --git a/FModel/Views/Snooper/SnimGui.cs b/FModel/Views/Snooper/SnimGui.cs index b8df4f06..0974e14e 100644 --- a/FModel/Views/Snooper/SnimGui.cs +++ b/FModel/Views/Snooper/SnimGui.cs @@ -149,7 +149,7 @@ public class SnimGui ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); if (ImGui.CollapsingHeader("Camera")) { - s.Camera.ImGuiCamera(); + s.Renderer.CameraOp.ImGuiCamera(); } ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); @@ -351,7 +351,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio if (ImGui.Selectable("Teleport To")) { var instancePos = model.Transforms[model.SelectedInstance].Position; - s.Camera.Teleport(instancePos, model.Box); + s.Renderer.CameraOp.Teleport(instancePos, model.Box); } if (ImGui.Selectable("Delete")) s.Renderer.Options.Models.Remove(guid); @@ -524,7 +524,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio ImGui.SliderInt("", ref model.SelectedInstance, 0, model.TransformsCount - 1, "Instance %i", ImGuiSliderFlags.AlwaysClamp); ImGui.EndDisabled(); ImGui.PopID(); - model.Transforms[model.SelectedInstance].ImGuiTransform(s.Camera.Speed / 100f); + model.Transforms[model.SelectedInstance].ImGuiTransform(s.Renderer.CameraOp.Speed / 100f); model.UpdateMatrix(model.SelectedInstance); ImGui.EndTabItem(); } @@ -653,7 +653,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio largest.Y -= ImGui.GetScrollY(); var size = new Vector2(largest.X, largest.Y); - s.Camera.AspectRatio = size.X / size.Y; + s.Renderer.CameraOp.AspectRatio = size.X / size.Y; ImGui.ImageButton(s.Framebuffer.GetPointer(), size, new Vector2(0, 1), new Vector2(1, 0), 0); if (ImGui.IsItemHovered()) @@ -674,7 +674,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio if (ImGui.IsMouseDragging(ImGuiMouseButton.Left) && _viewportFocus) { - s.Camera.Modify(ImGui.GetIO().MouseDelta); + s.Renderer.CameraOp.Modify(ImGui.GetIO().MouseDelta); } // if left button up and mouse was in viewport diff --git a/FModel/Views/Snooper/Snooper.cs b/FModel/Views/Snooper/Snooper.cs index a59860ab..a63826c8 100644 --- a/FModel/Views/Snooper/Snooper.cs +++ b/FModel/Views/Snooper/Snooper.cs @@ -4,7 +4,6 @@ using System.Runtime.InteropServices; using System.Threading; using System.Windows; using CUE4Parse.UE4.Assets.Exports; -using FModel.Settings; using FModel.Views.Snooper.Buffers; using ImGuiNET; using OpenTK.Graphics.OpenGL4; @@ -19,19 +18,15 @@ namespace FModel.Views.Snooper; public class Snooper : GameWindow { - public Camera Camera; public readonly FramebufferObject Framebuffer; public readonly Renderer Renderer; private readonly SnimGui _gui; - private float _previousSpeed; - private bool _init; public Snooper(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings) { - Camera = new Camera(); Framebuffer = new FramebufferObject(ClientSize); Renderer = new Renderer(ClientSize.X, ClientSize.Y); @@ -41,13 +36,7 @@ public class Snooper : GameWindow public bool TryLoadExport(CancellationToken cancellationToken, UObject export) { - var newCamera = Renderer.Load(cancellationToken, export) ?? new Camera(); - if (newCamera.Speed > _previousSpeed) - { - newCamera.Zoom = Camera.Zoom; - Camera = newCamera; - _previousSpeed = Camera.Speed; - } + Renderer.Load(cancellationToken, export); return Renderer.Options.Models.Count > 0; } @@ -55,13 +44,12 @@ public class Snooper : GameWindow { if (clear) { - _previousSpeed = 0f; + Renderer.CameraOp.Speed = 0; Renderer.Options.ResetModelsAndLights(); Renderer.Options.SelectModel(Guid.Empty); Renderer.Save(); } - UserSettings.Default.CameraMode = Camera.Mode; GLFW.SetWindowShouldClose(WindowPtr, value); // start / stop game loop IsVisible = !value; } @@ -134,7 +122,7 @@ public class Snooper : GameWindow Framebuffer.Bind(); // switch to viewport background ClearWhatHasBeenDrawn(); // clear viewport background - Renderer.Render(Camera); + Renderer.Render(); Framebuffer.BindMsaa(); Framebuffer.Bind(0); // switch to window background @@ -163,7 +151,7 @@ public class Snooper : GameWindow if (!IsVisible || ImGui.GetIO().WantTextInput) return; - Camera.Modify(KeyboardState, (float) e.Time); + Renderer.CameraOp.Modify(KeyboardState, (float) e.Time); if (KeyboardState.IsKeyPressed(Keys.H)) WindowShouldClose(true, false); @@ -177,9 +165,8 @@ public class Snooper : GameWindow GL.Viewport(0, 0, e.Width, e.Height); - Camera.AspectRatio = e.Width / (float) e.Height; Framebuffer.WindowResized(e.Width, e.Height); - Renderer.Picking.WindowResized(e.Width, e.Height); + Renderer.WindowResized(e.Width, e.Height); _gui.Controller.WindowResized(e.Width, e.Height); }