cleaned camera + generated .umap position

This commit is contained in:
4sval 2023-01-01 20:09:46 +01:00
parent 26f9b5b9ce
commit 76a9f88eee
6 changed files with 204 additions and 254 deletions

View File

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

View File

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

View File

@ -33,7 +33,7 @@ public class Model : IDisposable
private VertexArrayObject<float, uint> _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<Transform>();
}
@ -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<UMorphTarget>());
Morphs[i] = new Morph(Vertices, VertexSize, morphTargets[i].Load<UMorphTarget>());
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<float>(Vertices, BufferTarget.ArrayBuffer);
_vao = new VertexArrayObject<float, uint>(_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

View File

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

View File

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

View File

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