mirror of
https://github.com/4sval/FModel.git
synced 2026-03-27 12:15:09 -05:00
I have no idea how I made multiple materials work
This commit is contained in:
parent
0014b6f4ed
commit
2cf40a022c
|
|
@ -130,7 +130,6 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CUE4Parse\CUE4Parse-Conversion\CUE4Parse-Conversion.csproj" />
|
||||
<ProjectReference Include="..\CUE4Parse\CUE4Parse-Fortnite\CUE4Parse-Fortnite.csproj" />
|
||||
<ProjectReference Include="..\CUE4Parse\CUE4Parse\CUE4Parse.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ public partial class MainWindow
|
|||
#if DEBUG
|
||||
await _threadWorkerView.Begin(_ =>
|
||||
_applicationView.CUE4Parse.Extract(
|
||||
"/Game/Gadgets/Assets/VinderTech_GliderChute/Glider_Mark_II/Meshes/Glider_Mark_II.uasset"));
|
||||
"FortniteGame/Content/Environments/Props/Winter/Meshes/SM_ChristmasTree_Llama.uasset"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Serilog;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
|
|
@ -9,16 +10,15 @@ public class Camera
|
|||
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;
|
||||
public float Pitch { get; set; } = 0f;
|
||||
public float Zoom { get; set; } = 45f;
|
||||
public float AspectRatio => 16f / 9f;
|
||||
|
||||
public Camera(Vector3 position, Vector3 direction, float aspectRatio = 16f / 9f)
|
||||
public Camera(Vector3 position, Vector3 direction)
|
||||
{
|
||||
Position = position;
|
||||
Direction = direction;
|
||||
AspectRatio = aspectRatio;
|
||||
|
||||
// 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));
|
||||
|
|
@ -40,7 +40,7 @@ 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);
|
||||
|
||||
Direction = Vector3.Normalize(CalculateDirection());
|
||||
CalculateDirection();
|
||||
}
|
||||
|
||||
public Matrix4x4 GetViewMatrix()
|
||||
|
|
@ -53,12 +53,22 @@ public class Camera
|
|||
return Matrix4x4.CreatePerspectiveFieldOfView(Helper.DegreesToRadians(Zoom), AspectRatio, 0.1f, 100.0f);
|
||||
}
|
||||
|
||||
private Vector3 CalculateDirection()
|
||||
public void 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;
|
||||
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);
|
||||
}
|
||||
|
||||
private void Loge()
|
||||
{
|
||||
Log.Logger.Information("Position {Position}", Position);
|
||||
Log.Logger.Information("Direction {Direction}", Direction);
|
||||
Log.Logger.Information("Yaw {Yaw}", Yaw);
|
||||
Log.Logger.Information("Pitch {Pitch}", Pitch);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
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
|
||||
public class Model : IDisposable
|
||||
{
|
||||
private uint _handle;
|
||||
private GL _gl;
|
||||
|
|
@ -18,28 +15,27 @@ public class Mesh : IDisposable
|
|||
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 };
|
||||
|
||||
private Shader _shader;
|
||||
|
||||
public uint[] Indices;
|
||||
public float[] Vertices;
|
||||
public CMaterialParams[] Params;
|
||||
public Section[] Sections;
|
||||
|
||||
public Mesh(CBaseMeshLod lod, CMeshVertex[] vertices)
|
||||
public Model(CBaseMeshLod lod, CMeshVertex[] vertices)
|
||||
{
|
||||
var sections = lod.Sections.Value;
|
||||
Params = new CMaterialParams[sections.Length];
|
||||
Sections = new Section[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];
|
||||
Sections[s] = new Section((uint) section.NumFaces * _faceSize, section.FirstIndex, section);
|
||||
for (uint face = 0; face < section.NumFaces; face++)
|
||||
{
|
||||
foreach (var f in _facesIndex)
|
||||
|
|
@ -58,15 +54,9 @@ public class Mesh : IDisposable
|
|||
Vertices[index * _vertexSize + 6] = vert.UV.U;
|
||||
Vertices[index * _vertexSize + 7] = vert.UV.V;
|
||||
|
||||
Indices[index] = (uint) index;
|
||||
Indices[index] = i;
|
||||
}
|
||||
}
|
||||
|
||||
Params[s] = new CMaterialParams();
|
||||
if (section.Material != null && section.Material.TryLoad(out var material) && material is UMaterialInterface unrealMaterial)
|
||||
{
|
||||
unrealMaterial.GetParams(Params[s]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +66,8 @@ public class Mesh : IDisposable
|
|||
|
||||
_handle = _gl.CreateProgram();
|
||||
|
||||
_shader = new Shader(_gl);
|
||||
|
||||
_ebo = new BufferObject<uint>(_gl, Indices, BufferTargetARB.ElementArrayBuffer);
|
||||
_vbo = new BufferObject<float>(_gl, Vertices, BufferTargetARB.ArrayBuffer);
|
||||
_vao = new VertexArrayObject<float, uint>(_gl, _vbo, _ebo);
|
||||
|
|
@ -84,20 +76,13 @@ public class Mesh : IDisposable
|
|||
_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++)
|
||||
for (int section = 0; section < Sections.Length; section++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
Sections[section].Setup(_gl);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void Bind(Camera camera)
|
||||
public void Bind(Camera camera)
|
||||
{
|
||||
_vao.Bind();
|
||||
|
||||
|
|
@ -106,15 +91,14 @@ public class Mesh : IDisposable
|
|||
_shader.SetUniform("uModel", Matrix4x4.Identity);
|
||||
_shader.SetUniform("uView", camera.GetViewMatrix());
|
||||
_shader.SetUniform("uProjection", camera.GetProjectionMatrix());
|
||||
// _shader.SetUniform("viewPos", _camera.Position);
|
||||
// _shader.SetUniform("viewPos", camera.Position);
|
||||
|
||||
for (int i = 0; i < _albedoMap.Length; i++)
|
||||
for (int section = 0; section < Sections.Length; section++)
|
||||
{
|
||||
_shader.SetUniform("material.albedo", i);
|
||||
_albedoMap[i].Bind(TextureUnit.Texture0 + i);
|
||||
}
|
||||
Sections[section].Bind(_shader);
|
||||
|
||||
_gl.DrawElements(PrimitiveType.Triangles, (uint) Indices.Length, DrawElementsType.UnsignedInt, null);
|
||||
_gl.DrawArrays(PrimitiveType.Triangles, Sections[section].FirstFaceIndex, Sections[section].FacesCount);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -123,6 +107,10 @@ public class Mesh : IDisposable
|
|||
_vbo.Dispose();
|
||||
_vao.Dispose();
|
||||
_shader.Dispose();
|
||||
for (int section = 0; section < Sections.Length; section++)
|
||||
{
|
||||
Sections[section].Dispose();
|
||||
}
|
||||
_gl.DeleteProgram(_handle);
|
||||
}
|
||||
}
|
||||
57
FModel/Views/Snooper/Section.cs
Normal file
57
FModel/Views/Snooper/Section.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
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 Section : IDisposable
|
||||
{
|
||||
private uint _handle;
|
||||
private GL _gl;
|
||||
|
||||
private Texture _albedoMap;
|
||||
// private Texture _normalMap;
|
||||
|
||||
public uint FacesCount;
|
||||
public int FirstFaceIndex;
|
||||
public CMaterialParams Params;
|
||||
|
||||
public Section(uint facesCount, int firstFaceIndex, CMeshSection section)
|
||||
{
|
||||
FacesCount = facesCount;
|
||||
FirstFaceIndex = firstFaceIndex;
|
||||
Params = new CMaterialParams();
|
||||
if (section.Material != null && section.Material.TryLoad(out var material) && material is UMaterialInterface unrealMaterial)
|
||||
{
|
||||
unrealMaterial.GetParams(Params);
|
||||
}
|
||||
}
|
||||
|
||||
public void Setup(GL gl)
|
||||
{
|
||||
_gl = gl;
|
||||
|
||||
_handle = _gl.CreateProgram();
|
||||
|
||||
if (Params.Diffuse is UTexture2D { IsVirtual: false } diffuse && diffuse.GetFirstMip() is { } mip)
|
||||
{
|
||||
TextureDecoder.DecodeTexture(mip, diffuse.Format, diffuse.isNormalMap, out var data, out _);
|
||||
_albedoMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind(Shader shader)
|
||||
{
|
||||
shader.SetUniform("material.albedo", 0);
|
||||
_albedoMap.Bind(TextureUnit.Texture0);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_albedoMap.Dispose();
|
||||
_gl.DeleteProgram(_handle);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ public class Snooper
|
|||
private IKeyboard _keyboard;
|
||||
private Vector2 _previousMousePosition;
|
||||
|
||||
private Mesh[] _meshes;
|
||||
private Model[] _models;
|
||||
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
|
|
@ -35,7 +35,6 @@ public class Snooper
|
|||
|
||||
var options = WindowOptions.Default;
|
||||
options.Size = new Vector2D<int>(Width, Height);
|
||||
options.Position = new Vector2D<int>(Width, Height);
|
||||
options.Title = "Snooper";
|
||||
_window = Window.Create(options);
|
||||
|
||||
|
|
@ -44,18 +43,18 @@ public class Snooper
|
|||
_window.Render += OnRender;
|
||||
_window.Closing += OnClose;
|
||||
|
||||
_meshes = new Mesh[1];
|
||||
_models = new Model[1];
|
||||
switch (export)
|
||||
{
|
||||
case UStaticMesh st when st.TryConvert(out var mesh):
|
||||
{
|
||||
_meshes[0] = new Mesh(mesh.LODs[0], mesh.LODs[0].Verts);
|
||||
_models[0] = new Model(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);
|
||||
_models[0] = new Model(mesh.LODs[0], mesh.LODs[0].Verts);
|
||||
SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
|
||||
break;
|
||||
}
|
||||
|
|
@ -71,10 +70,6 @@ public class Snooper
|
|||
|
||||
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);
|
||||
|
|
@ -95,9 +90,9 @@ public class Snooper
|
|||
_gl = GL.GetApi(_window);
|
||||
_gl.Enable(EnableCap.DepthTest);
|
||||
|
||||
foreach (var mesh in _meshes)
|
||||
foreach (var model in _models)
|
||||
{
|
||||
mesh.Setup(_gl);
|
||||
model.Setup(_gl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,9 +101,9 @@ public class Snooper
|
|||
_gl.ClearColor(0.149f, 0.149f, 0.188f, 1.0f);
|
||||
_gl.Clear((uint) ClearBufferMask.ColorBufferBit | (uint) ClearBufferMask.DepthBufferBit);
|
||||
|
||||
foreach (var mesh in _meshes)
|
||||
foreach (var model in _models)
|
||||
{
|
||||
mesh.Bind(_camera);
|
||||
model.Bind(_camera);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,9 +158,9 @@ public class Snooper
|
|||
|
||||
private void OnClose()
|
||||
{
|
||||
foreach (var mesh in _meshes)
|
||||
foreach (var model in _models)
|
||||
{
|
||||
mesh.Dispose();
|
||||
model.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ public class Texture : IDisposable
|
|||
|
||||
private void SetParameters()
|
||||
{
|
||||
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) GLEnum.ClampToEdge);
|
||||
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge);
|
||||
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) GLEnum.LinearMipmapLinear);
|
||||
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) GLEnum.Linear);
|
||||
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user