mirror of
https://github.com/4sval/FModel.git
synced 2026-09-13 03:56:43 -05:00
good cam position + fixed depth mip mapping + trying to understand shit
This commit is contained in:
Submodule CUE4Parse updated: 5f323ef90c...aa5c9a485e
@@ -89,9 +89,13 @@ public partial class App
|
||||
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Logs"));
|
||||
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, ".data"));
|
||||
|
||||
#if DEBUG
|
||||
Log.Logger = new LoggerConfiguration().WriteTo.Console(theme: AnsiConsoleTheme.Literate).CreateLogger();
|
||||
#else
|
||||
Log.Logger = new LoggerConfiguration().WriteTo.Console(theme: AnsiConsoleTheme.Literate).WriteTo.File(
|
||||
Path.Combine(UserSettings.Default.OutputDirectory, "Logs", $"FModel-Log-{DateTime.Now:yyyy-MM-dd}.txt"),
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [FModel] [{Level:u3}] {Message:lj}{NewLine}{Exception}").CreateLogger();
|
||||
#endif
|
||||
|
||||
Log.Information("Version {Version}", Constants.APP_VERSION);
|
||||
Log.Information("{OS}", GetOperatingSystemProductName());
|
||||
|
||||
@@ -9,6 +9,8 @@ public static class Constants
|
||||
public const string ZERO_64_CHAR = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
public static readonly FGuid ZERO_GUID = new(0U);
|
||||
|
||||
public const float SCALE_DOWN_RATIO = 0.01F;
|
||||
|
||||
public const string WHITE = "#DAE5F2";
|
||||
public const string GRAY = "#BBBBBB";
|
||||
public const string RED = "#E06C75";
|
||||
|
||||
@@ -105,4 +105,9 @@ public static class Helper
|
||||
{
|
||||
return MathF.PI / 180f * degrees;
|
||||
}
|
||||
|
||||
public static float RadiansToDegrees(float radians)
|
||||
{
|
||||
return radians* 180f / MathF.PI;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public partial class MainWindow
|
||||
#if DEBUG
|
||||
await _threadWorkerView.Begin(_ =>
|
||||
_applicationView.CUE4Parse.Extract(
|
||||
"FortniteGame/Content/Environments/Props/Winter/Meshes/S_Sled.uasset"));
|
||||
"/Game/Gadgets/Assets/VinderTech_GliderChute/Glider_Mark_II/Meshes/Glider_Mark_II.uasset"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -6,22 +6,24 @@ namespace FModel.Views.Snooper;
|
||||
public class Camera
|
||||
{
|
||||
public Vector3 Position { get; set; }
|
||||
public Vector3 Front { get; set; }
|
||||
|
||||
public Vector3 Up { get; private set; }
|
||||
public float AspectRatio { get; set; }
|
||||
public Vector3 Direction { get; private set; }
|
||||
public Vector3 Up = Vector3.UnitY;
|
||||
|
||||
public float AspectRatio { get; }
|
||||
public float Yaw { get; set; } = -90f;
|
||||
public float Pitch { get; set; }
|
||||
public float Zoom = 45f;
|
||||
|
||||
private float Zoom = 45f;
|
||||
|
||||
public Camera(Vector3 position, Vector3 front, Vector3 up, float aspectRatio)
|
||||
public Camera(Vector3 position, Vector3 direction, float aspectRatio = 16f / 9f)
|
||||
{
|
||||
Position = position;
|
||||
Direction = direction;
|
||||
AspectRatio = aspectRatio;
|
||||
Front = front;
|
||||
Up = up;
|
||||
|
||||
// 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));
|
||||
ModifyDirection(Helper.RadiansToDegrees(yaw), Helper.RadiansToDegrees(pitch));
|
||||
}
|
||||
|
||||
public void ModifyZoom(float zoomAmount)
|
||||
@@ -38,21 +40,25 @@ public class Camera
|
||||
//We don't want to be able to look behind us by going over our head or under our feet so make sure it stays within these bounds
|
||||
Pitch = Math.Clamp(Pitch, -89f, 89f);
|
||||
|
||||
var cameraDirection = Vector3.Zero;
|
||||
cameraDirection.X = MathF.Cos(Helper.DegreesToRadians(Yaw)) * MathF.Cos(Helper.DegreesToRadians(Pitch));
|
||||
cameraDirection.Y = MathF.Sin(Helper.DegreesToRadians(Pitch));
|
||||
cameraDirection.Z = MathF.Sin(Helper.DegreesToRadians(Yaw)) * MathF.Cos(Helper.DegreesToRadians(Pitch));
|
||||
|
||||
Front = Vector3.Normalize(cameraDirection);
|
||||
Direction = Vector3.Normalize(CalculateDirection());
|
||||
}
|
||||
|
||||
public Matrix4x4 GetViewMatrix()
|
||||
{
|
||||
return Matrix4x4.CreateLookAt(Position, Position + Front, Up);
|
||||
return Matrix4x4.CreateLookAt(Position, Position + Direction, Up);
|
||||
}
|
||||
|
||||
public Matrix4x4 GetProjectionMatrix()
|
||||
{
|
||||
return Matrix4x4.CreatePerspectiveFieldOfView(Helper.DegreesToRadians(Zoom), AspectRatio, 0.1f, 100.0f);
|
||||
}
|
||||
|
||||
private Vector3 CalculateDirection()
|
||||
{
|
||||
var direction = Vector3.Zero;
|
||||
direction.X = MathF.Cos(Helper.DegreesToRadians(Yaw)) * MathF.Cos(Helper.DegreesToRadians(Pitch));
|
||||
direction.Y = MathF.Sin(Helper.DegreesToRadians(Pitch));
|
||||
direction.Z = MathF.Sin(Helper.DegreesToRadians(Yaw)) * MathF.Cos(Helper.DegreesToRadians(Pitch));
|
||||
return direction;
|
||||
}
|
||||
}
|
||||
|
||||
128
FModel/Views/Snooper/Mesh.cs
Normal file
128
FModel/Views/Snooper/Mesh.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using CUE4Parse_Conversion.Meshes.PSK;
|
||||
using CUE4Parse_Conversion.Textures;
|
||||
using Silk.NET.OpenGL;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
public class Mesh : IDisposable
|
||||
{
|
||||
private uint _handle;
|
||||
private GL _gl;
|
||||
|
||||
private BufferObject<uint> _ebo;
|
||||
private BufferObject<float> _vbo;
|
||||
private VertexArrayObject<float, uint> _vao;
|
||||
|
||||
private Shader _shader;
|
||||
private Texture[] _albedoMap;
|
||||
// private Texture _normalMap;
|
||||
|
||||
private const int _vertexSize = 8; // Position + Normals + UV
|
||||
private const uint _faceSize = 3; // just so we don't have to do .Length
|
||||
private readonly uint[] _facesIndex = { 1, 0, 2 };
|
||||
|
||||
public uint[] Indices;
|
||||
public float[] Vertices;
|
||||
public CMaterialParams[] Params;
|
||||
|
||||
public Mesh(CBaseMeshLod lod, CMeshVertex[] vertices)
|
||||
{
|
||||
var sections = lod.Sections.Value;
|
||||
Params = new CMaterialParams[sections.Length];
|
||||
Indices = new uint[sections.Sum(section => section.NumFaces * _faceSize)];
|
||||
Vertices = new float[Indices.Length * _vertexSize];
|
||||
|
||||
for (var s = 0; s < sections.Length; s++)
|
||||
{
|
||||
var section = sections[s];
|
||||
for (uint face = 0; face < section.NumFaces; face++)
|
||||
{
|
||||
foreach (var f in _facesIndex)
|
||||
{
|
||||
var i = face * _faceSize + f;
|
||||
var index = section.FirstIndex + i;
|
||||
var indice = lod.Indices.Value[index];
|
||||
|
||||
var vert = vertices[indice];
|
||||
Vertices[index * _vertexSize] = vert.Position.X * Constants.SCALE_DOWN_RATIO;
|
||||
Vertices[index * _vertexSize + 1] = vert.Position.Z * Constants.SCALE_DOWN_RATIO;
|
||||
Vertices[index * _vertexSize + 2] = vert.Position.Y * Constants.SCALE_DOWN_RATIO;
|
||||
Vertices[index * _vertexSize + 3] = vert.Normal.X;
|
||||
Vertices[index * _vertexSize + 4] = vert.Normal.Z;
|
||||
Vertices[index * _vertexSize + 5] = vert.Normal.Y;
|
||||
Vertices[index * _vertexSize + 6] = vert.UV.U;
|
||||
Vertices[index * _vertexSize + 7] = vert.UV.V;
|
||||
|
||||
Indices[index] = (uint) index;
|
||||
}
|
||||
}
|
||||
|
||||
Params[s] = new CMaterialParams();
|
||||
if (section.Material != null && section.Material.TryLoad(out var material) && material is UMaterialInterface unrealMaterial)
|
||||
{
|
||||
unrealMaterial.GetParams(Params[s]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Setup(GL gl)
|
||||
{
|
||||
_gl = gl;
|
||||
|
||||
_handle = _gl.CreateProgram();
|
||||
|
||||
_ebo = new BufferObject<uint>(_gl, Indices, BufferTargetARB.ElementArrayBuffer);
|
||||
_vbo = new BufferObject<float>(_gl, Vertices, BufferTargetARB.ArrayBuffer);
|
||||
_vao = new VertexArrayObject<float, uint>(_gl, _vbo, _ebo);
|
||||
|
||||
_vao.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, _vertexSize, 0); // position
|
||||
_vao.VertexAttributePointer(1, 3, VertexAttribPointerType.Float, _vertexSize, 3); // normals
|
||||
_vao.VertexAttributePointer(2, 2, VertexAttribPointerType.Float, _vertexSize, 6); // uv
|
||||
|
||||
_shader = new Shader(_gl);
|
||||
|
||||
_albedoMap = new Texture[Params.Length];
|
||||
for (int i = 0; i < _albedoMap.Length; i++)
|
||||
{
|
||||
if (Params[i].Diffuse is UTexture2D { IsVirtual: false } diffuse && diffuse.GetFirstMip() is { } mip)
|
||||
{
|
||||
TextureDecoder.DecodeTexture(mip, diffuse.Format, diffuse.isNormalMap, out var data, out _);
|
||||
_albedoMap[i] = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void Bind(Camera camera)
|
||||
{
|
||||
_vao.Bind();
|
||||
|
||||
_shader.Use();
|
||||
|
||||
_shader.SetUniform("uModel", Matrix4x4.Identity);
|
||||
_shader.SetUniform("uView", camera.GetViewMatrix());
|
||||
_shader.SetUniform("uProjection", camera.GetProjectionMatrix());
|
||||
// _shader.SetUniform("viewPos", _camera.Position);
|
||||
|
||||
for (int i = 0; i < _albedoMap.Length; i++)
|
||||
{
|
||||
_shader.SetUniform("material.albedo", i);
|
||||
_albedoMap[i].Bind(TextureUnit.Texture0 + i);
|
||||
}
|
||||
|
||||
_gl.DrawElements(PrimitiveType.Triangles, (uint) Indices.Length, DrawElementsType.UnsignedInt, null);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_ebo.Dispose();
|
||||
_vbo.Dispose();
|
||||
_vao.Dispose();
|
||||
_shader.Dispose();
|
||||
_gl.DeleteProgram(_handle);
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,6 @@ struct Material {
|
||||
};
|
||||
|
||||
uniform Material material;
|
||||
uniform vec3 viewPos;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using CUE4Parse_Conversion.Meshes;
|
||||
using CUE4Parse_Conversion.Textures;
|
||||
using Silk.NET.Input;
|
||||
using Silk.NET.Maths;
|
||||
using Silk.NET.OpenGL;
|
||||
@@ -22,25 +20,11 @@ public class Snooper
|
||||
private IKeyboard _keyboard;
|
||||
private Vector2 _previousMousePosition;
|
||||
|
||||
private BufferObject<uint> _ebo;
|
||||
private BufferObject<float> _vbo;
|
||||
private VertexArrayObject<float, uint> _vao;
|
||||
private Shader _shader;
|
||||
private CMaterialParams _params;
|
||||
|
||||
private Texture _albedoMap;
|
||||
private Texture _normalMap;
|
||||
|
||||
private uint[] _indices;
|
||||
private float[] _vertices;
|
||||
private Mesh[] _meshes;
|
||||
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
|
||||
private const int _vertexSize = 8; // Position + Normals + UV
|
||||
private const uint _faceSize = 3; // just so we don't have to do .Length
|
||||
private readonly uint[] _facesIndex = { 1, 0, 2 };
|
||||
|
||||
public Snooper(UObject export)
|
||||
{
|
||||
const double ratio = .6;
|
||||
@@ -60,42 +44,19 @@ public class Snooper
|
||||
_window.Render += OnRender;
|
||||
_window.Closing += OnClose;
|
||||
|
||||
_meshes = new Mesh[1];
|
||||
switch (export)
|
||||
{
|
||||
case UStaticMesh st when st.TryConvert(out var mesh):
|
||||
{
|
||||
_indices = new uint[mesh.LODs[0].Sections.Value.Sum(section => section.NumFaces * _faceSize)];
|
||||
_vertices = new float[_indices.Length * _vertexSize];
|
||||
foreach (var section in mesh.LODs[0].Sections.Value)
|
||||
{
|
||||
for (uint face = 0; face < section.NumFaces; face++)
|
||||
{
|
||||
foreach (var f in _facesIndex)
|
||||
{
|
||||
var i = face * _faceSize + f;
|
||||
var index = section.FirstIndex + i;
|
||||
var indice = mesh.LODs[0].Indices.Value[index];
|
||||
|
||||
var vert = mesh.LODs[0].Verts[indice];
|
||||
_vertices[index * _vertexSize] = vert.Position.X * 0.01f;
|
||||
_vertices[index * _vertexSize + 1] = vert.Position.Z * 0.01f;
|
||||
_vertices[index * _vertexSize + 2] = vert.Position.Y * 0.01f;
|
||||
_vertices[index * _vertexSize + 3] = vert.Normal.X;
|
||||
_vertices[index * _vertexSize + 4] = vert.Normal.Z;
|
||||
_vertices[index * _vertexSize + 5] = vert.Normal.Y;
|
||||
_vertices[index * _vertexSize + 6] = vert.UV.U;
|
||||
_vertices[index * _vertexSize + 7] = vert.UV.V;
|
||||
|
||||
_indices[index] = i;
|
||||
}
|
||||
}
|
||||
|
||||
_params = new CMaterialParams();
|
||||
if (section.Material != null && section.Material.TryLoad(out var material) && material is UMaterialInterface unrealMaterial)
|
||||
{
|
||||
unrealMaterial.GetParams(_params);
|
||||
}
|
||||
}
|
||||
_meshes[0] = new Mesh(mesh.LODs[0], mesh.LODs[0].Verts);
|
||||
SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
|
||||
break;
|
||||
}
|
||||
case USkeletalMesh sk when sk.TryConvert(out var mesh):
|
||||
{
|
||||
_meshes[0] = new Mesh(mesh.LODs[0], mesh.LODs[0].Verts);
|
||||
SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -108,6 +69,17 @@ public class Snooper
|
||||
_window.Run();
|
||||
}
|
||||
|
||||
private void SetupCamera(FBox box)
|
||||
{
|
||||
// X Yaw Gauche Droite
|
||||
// Y Pitch Haut Bas
|
||||
// Z Avant Arrière
|
||||
|
||||
var center = box.GetCenter();
|
||||
var position = new Vector3(0f, center.Z, box.Max.Y * 3);
|
||||
_camera = new Camera(position, center);
|
||||
}
|
||||
|
||||
private void OnLoad()
|
||||
{
|
||||
var input = _window.CreateInput();
|
||||
@@ -121,65 +93,44 @@ public class Snooper
|
||||
}
|
||||
|
||||
_gl = GL.GetApi(_window);
|
||||
_gl.Enable(EnableCap.DepthTest);
|
||||
|
||||
_ebo = new BufferObject<uint>(_gl, _indices, BufferTargetARB.ElementArrayBuffer);
|
||||
_vbo = new BufferObject<float>(_gl, _vertices, BufferTargetARB.ArrayBuffer);
|
||||
_vao = new VertexArrayObject<float, uint>(_gl, _vbo, _ebo);
|
||||
|
||||
_vao.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, _vertexSize, 0); // position
|
||||
_vao.VertexAttributePointer(1, 3, VertexAttribPointerType.Float, _vertexSize, 3); // normals
|
||||
_vao.VertexAttributePointer(2, 2, VertexAttribPointerType.Float, _vertexSize, 6); // uv
|
||||
|
||||
_shader = new Shader(_gl);
|
||||
|
||||
_camera = new Camera(Vector3.UnitZ * 6, Vector3.UnitZ * -1, Vector3.UnitY, Width / Height);
|
||||
|
||||
if (_params.Diffuse is UTexture2D { IsVirtual: false } diffuse && diffuse.GetFirstMip() is { } mip)
|
||||
foreach (var mesh in _meshes)
|
||||
{
|
||||
TextureDecoder.DecodeTexture(mip, diffuse.Format, diffuse.isNormalMap, out var data, out _);
|
||||
_albedoMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
|
||||
mesh.Setup(_gl);
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void OnRender(double deltaTime)
|
||||
private void OnRender(double deltaTime)
|
||||
{
|
||||
_gl.Clear((uint) ClearBufferMask.ColorBufferBit);
|
||||
_gl.ClearColor(0.149f, 0.149f, 0.188f, 1.0f);
|
||||
_gl.Clear((uint) ClearBufferMask.ColorBufferBit | (uint) ClearBufferMask.DepthBufferBit);
|
||||
|
||||
_vao.Bind();
|
||||
_shader.Use();
|
||||
|
||||
_albedoMap.Bind(TextureUnit.Texture0);
|
||||
|
||||
_shader.SetUniform("uModel", Matrix4x4.Identity);
|
||||
_shader.SetUniform("uView", _camera.GetViewMatrix());
|
||||
_shader.SetUniform("uProjection", _camera.GetProjectionMatrix());
|
||||
// _shader.SetUniform("viewPos", _camera.Position);
|
||||
|
||||
//Configure the materials variables.
|
||||
_shader.SetUniform("material.albedo", 0);
|
||||
|
||||
_gl.DrawElements(PrimitiveType.Triangles, (uint) _indices.Length, DrawElementsType.UnsignedInt, null);
|
||||
foreach (var mesh in _meshes)
|
||||
{
|
||||
mesh.Bind(_camera);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUpdate(double deltaTime)
|
||||
{
|
||||
var speed = _keyboard.IsKeyPressed(Key.ShiftLeft) ? 5f : 2.5f;
|
||||
var speed = _keyboard.IsKeyPressed(Key.ShiftLeft) ? 2.5f : 1f;
|
||||
var moveSpeed = speed * (float) deltaTime;
|
||||
if (_keyboard.IsKeyPressed(Key.W))
|
||||
{
|
||||
_camera.Position += moveSpeed * _camera.Front;
|
||||
_camera.Position += moveSpeed * _camera.Direction;
|
||||
}
|
||||
if (_keyboard.IsKeyPressed(Key.S))
|
||||
{
|
||||
_camera.Position -= moveSpeed * _camera.Front;
|
||||
_camera.Position -= moveSpeed * _camera.Direction;
|
||||
}
|
||||
if (_keyboard.IsKeyPressed(Key.A))
|
||||
{
|
||||
_camera.Position -= Vector3.Normalize(Vector3.Cross(_camera.Front, _camera.Up)) * moveSpeed;
|
||||
_camera.Position -= Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
|
||||
}
|
||||
if (_keyboard.IsKeyPressed(Key.D))
|
||||
{
|
||||
_camera.Position += Vector3.Normalize(Vector3.Cross(_camera.Front, _camera.Up)) * moveSpeed;
|
||||
_camera.Position += Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
|
||||
}
|
||||
if (_keyboard.IsKeyPressed(Key.E))
|
||||
{
|
||||
@@ -212,10 +163,10 @@ public class Snooper
|
||||
|
||||
private void OnClose()
|
||||
{
|
||||
_ebo.Dispose();
|
||||
_vbo.Dispose();
|
||||
_vao.Dispose();
|
||||
_shader.Dispose();
|
||||
foreach (var mesh in _meshes)
|
||||
{
|
||||
mesh.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void KeyDown(IKeyboard keyboard, Key key, int arg3)
|
||||
|
||||
Reference in New Issue
Block a user