mirror of
https://github.com/4sval/FModel.git
synced 2026-04-17 06:56:46 -05:00
uv map poc
This commit is contained in:
parent
023b68ffae
commit
29f556dc2a
|
|
@ -1 +1 @@
|
|||
Subproject commit a048e1373b71c504b01de4cd89bebe4e01cb3d11
|
||||
Subproject commit 842f6d4b37b4ecf54d51dd93dcc19f154e33e438
|
||||
|
|
@ -79,7 +79,7 @@ public partial class MainWindow
|
|||
#if DEBUG
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken,
|
||||
"fortnitegame/Content/Accessories/FORT_Backpacks/Backpack_F_MED_FNCS_S20/Meshes/F_MED_FNCS_S20_Pack.uasset"));
|
||||
"FortniteGame/Content/Environments/Artemis/Sets/Seven/Village/Meshes/S_Seven_Village_Wall_01A_Window02.uasset"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ in vec4 fColor;
|
|||
struct Material {
|
||||
sampler2D diffuseMap;
|
||||
sampler2D normalMap;
|
||||
sampler2D specularMap;
|
||||
sampler2D emissionMap;
|
||||
|
||||
bool useSpecularMap;
|
||||
sampler2D specularMap;
|
||||
|
||||
bool hasDiffuseColor;
|
||||
vec4 diffuseColor;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
|
|
@ -62,8 +61,11 @@ public class Cube : Model
|
|||
-1, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
Materials = new Material[1];
|
||||
Materials[0] = new Material(1, unrealMaterial);
|
||||
|
||||
Sections = new Section[1];
|
||||
Sections[0] = new Section(0, Indices.Length, 0, unrealMaterial);
|
||||
Sections[0] = new Section(0, Indices.Length, 0, Materials[0]);
|
||||
|
||||
AddInstance(Transform.Identity);
|
||||
}
|
||||
|
|
|
|||
147
FModel/Views/Snooper/Material.cs
Normal file
147
FModel/Views/Snooper/Material.cs
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
using CUE4Parse_Conversion.Textures;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using FModel.Settings;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Mathematics;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
public class Material : IDisposable
|
||||
{
|
||||
private int _handle;
|
||||
|
||||
private Vector3 _ambientLight;
|
||||
|
||||
public readonly CMaterialParams2 Parameters;
|
||||
public readonly int UvNumber;
|
||||
|
||||
public Texture[] Diffuse;
|
||||
public Texture[] Normals;
|
||||
public Texture[] SpecularMasks;
|
||||
public Texture Emissive;
|
||||
|
||||
public Vector4 DiffuseColor;
|
||||
public Vector4 EmissionColor;
|
||||
public bool HasSpecularMap;
|
||||
public bool HasDiffuseColor;
|
||||
|
||||
public Material()
|
||||
{
|
||||
DiffuseColor = Vector4.Zero;
|
||||
EmissionColor = Vector4.Zero;
|
||||
}
|
||||
|
||||
public Material(int numUvs, UMaterialInterface unrealMaterial) : this()
|
||||
{
|
||||
UvNumber = numUvs;
|
||||
Parameters = new CMaterialParams2();
|
||||
SwapMaterial(unrealMaterial);
|
||||
}
|
||||
|
||||
public void SwapMaterial(UMaterialInterface unrealMaterial)
|
||||
{
|
||||
unrealMaterial.GetParams(Parameters);
|
||||
}
|
||||
|
||||
public void Setup(Cache cache)
|
||||
{
|
||||
_handle = GL.CreateProgram();
|
||||
|
||||
int index;
|
||||
var platform = UserSettings.Default.OverridedPlatform;
|
||||
void Add(Texture[] array, UTexture2D original)
|
||||
{
|
||||
var guid = original.LightingGuid;
|
||||
if (cache.TryGetTexture(guid, out var texture))
|
||||
{
|
||||
array[index++] = texture;
|
||||
}
|
||||
else if (original.GetFirstMip() is { } mip)
|
||||
{
|
||||
TextureDecoder.DecodeTexture(mip, original.Format, original.isNormalMap, platform, out var data, out _);
|
||||
|
||||
var t = new Texture(data, mip.SizeX, mip.SizeY, original);
|
||||
cache.AddTexture(guid, t);
|
||||
array[index++] = t;
|
||||
}
|
||||
}
|
||||
|
||||
index = 0;
|
||||
Diffuse = new Texture[UvNumber];
|
||||
foreach (var d in Parameters.GetDiffuseTextures())
|
||||
if (index < UvNumber && d is UTexture2D original)
|
||||
Add(Diffuse, original);
|
||||
|
||||
index = 0;
|
||||
Normals = new Texture[UvNumber];
|
||||
foreach (var n in Parameters.GetNormalsTextures())
|
||||
if (index < UvNumber && n is UTexture2D original)
|
||||
Add(Normals, original);
|
||||
|
||||
index = 0;
|
||||
SpecularMasks = new Texture[UvNumber];
|
||||
foreach (var s in Parameters.GetSpecularMasksTextures())
|
||||
if (index < UvNumber && s is UTexture2D original)
|
||||
Add(SpecularMasks, original);
|
||||
|
||||
// diffuse light is based on normal map, so increase ambient if no normal map
|
||||
_ambientLight = new Vector3(Normals[0] == null ? 1.0f : 0.2f);
|
||||
HasSpecularMap = SpecularMasks[0] != null;
|
||||
HasDiffuseColor = DiffuseColor != Vector4.Zero;
|
||||
}
|
||||
|
||||
public void Render(Shader shader)
|
||||
{
|
||||
var unit = 0;
|
||||
|
||||
for (var i = 0; i < Diffuse.Length; i++)
|
||||
{
|
||||
shader.SetUniform("material.diffuseMap", unit);
|
||||
Diffuse[i]?.Bind(TextureUnit.Texture0 + unit++);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Normals.Length; i++)
|
||||
{
|
||||
shader.SetUniform("material.normalMap", unit);
|
||||
Normals[i]?.Bind(TextureUnit.Texture0 + unit++);
|
||||
}
|
||||
|
||||
for (var i = 0; i < SpecularMasks.Length; i++)
|
||||
{
|
||||
shader.SetUniform("material.specularMap", unit);
|
||||
SpecularMasks[i]?.Bind(TextureUnit.Texture0 + unit++);
|
||||
}
|
||||
|
||||
shader.SetUniform("material.useSpecularMap", HasSpecularMap);
|
||||
|
||||
shader.SetUniform("material.hasDiffuseColor", HasDiffuseColor);
|
||||
shader.SetUniform("material.diffuseColor", DiffuseColor);
|
||||
|
||||
shader.SetUniform("material.emissionColor", EmissionColor);
|
||||
|
||||
shader.SetUniform("material.metallic_value", 1f);
|
||||
shader.SetUniform("material.roughness_value", 0f);
|
||||
|
||||
shader.SetUniform("light.ambient", _ambientLight);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
for (int i = 0; i < Diffuse.Length; i++)
|
||||
{
|
||||
Diffuse[i]?.Dispose();
|
||||
}
|
||||
for (int i = 0; i < Normals.Length; i++)
|
||||
{
|
||||
Normals[i]?.Dispose();
|
||||
}
|
||||
for (int i = 0; i < SpecularMasks.Length; i++)
|
||||
{
|
||||
SpecularMasks[i]?.Dispose();
|
||||
}
|
||||
Emissive?.Dispose();
|
||||
GL.DeleteProgram(_handle);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,8 @@ using System.Numerics;
|
|||
using CUE4Parse.UE4.Assets.Exports.Animation;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using CUE4Parse_Conversion.Meshes.PSK;
|
||||
using CUE4Parse.UE4.Assets;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
|
@ -31,12 +33,14 @@ public class Model : IDisposable
|
|||
public uint[] Indices;
|
||||
public float[] Vertices;
|
||||
public Section[] Sections;
|
||||
public readonly Morph[] Morphs;
|
||||
public Material[] Materials;
|
||||
public readonly List<CSkelMeshBone> Skeleton;
|
||||
|
||||
public int TransformsCount;
|
||||
public readonly List<Transform> Transforms;
|
||||
|
||||
public readonly Morph[] Morphs;
|
||||
|
||||
public bool Show;
|
||||
public bool IsSetup;
|
||||
public bool IsSelected;
|
||||
|
|
@ -52,10 +56,11 @@ public class Model : IDisposable
|
|||
Show = true;
|
||||
}
|
||||
|
||||
public Model(string name, string type, CStaticMesh staticMesh) : this(name, type, staticMesh.LODs[0], staticMesh.LODs[0].Verts) {}
|
||||
public Model(string name, string type, CStaticMesh staticMesh, Transform transform) : this(name, type, staticMesh.LODs[0], staticMesh.LODs[0].Verts, null, transform) {}
|
||||
public Model(string name, string type, CSkeletalMesh skeletalMesh) : this(name, type, skeletalMesh.LODs[0], skeletalMesh.LODs[0].Verts, skeletalMesh.RefSkeleton) {}
|
||||
public Model(string name, string type, FPackageIndex[] morphTargets, CSkeletalMesh skeletalMesh) : this(name, type, skeletalMesh)
|
||||
public Model(string name, string type, ResolvedObject[] materials, CStaticMesh staticMesh) : this(name, type, materials, staticMesh, Transform.Identity) {}
|
||||
public Model(string name, string type, ResolvedObject[] materials, CStaticMesh staticMesh, Transform transform) : this(name, type, materials, staticMesh.LODs[0], staticMesh.LODs[0].Verts, transform) {}
|
||||
public Model(string name, string type, ResolvedObject[] materials, CSkeletalMesh skeletalMesh) : this(name, type, materials, skeletalMesh, Transform.Identity) {}
|
||||
public Model(string name, string type, ResolvedObject[] materials, CSkeletalMesh skeletalMesh, Transform transform) : this(name, type, materials, skeletalMesh.LODs[0], skeletalMesh.LODs[0].Verts, transform, skeletalMesh.RefSkeleton) {}
|
||||
public Model(string name, string type, ResolvedObject[] materials, FPackageIndex[] morphTargets, CSkeletalMesh skeletalMesh) : this(name, type, materials, skeletalMesh)
|
||||
{
|
||||
if (morphTargets is not { Length: > 0 })
|
||||
return;
|
||||
|
|
@ -68,8 +73,15 @@ public class Model : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public Model(string name, string type, CBaseMeshLod lod, CMeshVertex[] vertices, List<CSkelMeshBone> skeleton = null, Transform transform = null) : this(name, type)
|
||||
private Model(string name, string type, ResolvedObject[] materials, CBaseMeshLod lod, CMeshVertex[] vertices, Transform transform, List<CSkelMeshBone> skeleton = null) : this(name, type)
|
||||
{
|
||||
Materials = new Material[materials.Length];
|
||||
for (int m = 0; m < Materials.Length; m++)
|
||||
{
|
||||
if (materials[m].TryLoad(out var material) && material is UMaterialInterface unrealMaterial)
|
||||
Materials[m] = new Material(1, unrealMaterial); // lod.NumTexCoords
|
||||
}
|
||||
|
||||
if (lod.VertexColors is { Length: > 0})
|
||||
{
|
||||
HasVertexColors = true;
|
||||
|
|
@ -91,7 +103,7 @@ public class Model : IDisposable
|
|||
for (var s = 0; s < sections.Length; s++)
|
||||
{
|
||||
var section = sections[s];
|
||||
Sections[s] = new Section(section.MaterialName, section.MaterialIndex, section.NumFaces * _faceSize, section.FirstIndex, section);
|
||||
Sections[s] = new Section(section.MaterialIndex, section.NumFaces * _faceSize, section.FirstIndex, Materials[section.MaterialIndex]);
|
||||
for (uint face = 0; face < section.NumFaces; face++)
|
||||
{
|
||||
foreach (var f in _facesIndex)
|
||||
|
|
@ -141,7 +153,7 @@ public class Model : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
AddInstance(transform ?? Transform.Identity);
|
||||
AddInstance(transform);
|
||||
}
|
||||
|
||||
public void AddInstance(Transform transform) => Transforms.Add(transform);
|
||||
|
|
@ -185,6 +197,13 @@ public class Model : IDisposable
|
|||
_vao.BindInstancing(); // VertexAttributePointer 7, 8, 9, 10
|
||||
}
|
||||
|
||||
{ // setup all materials for use in different UV channels
|
||||
for (var i = 0; i < Materials.Length; i++)
|
||||
{
|
||||
Materials[i].Setup(cache);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasMorphTargets)
|
||||
{
|
||||
for (uint morph = 0; morph < Morphs.Length; morph++)
|
||||
|
|
@ -265,10 +284,16 @@ public class Model : IDisposable
|
|||
Morphs[morph].Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
for (int material = 0; material < Materials.Length; material++)
|
||||
{
|
||||
Materials[material]?.Dispose();
|
||||
}
|
||||
for (int section = 0; section < Sections.Length; section++)
|
||||
{
|
||||
Sections[section].Dispose();
|
||||
}
|
||||
|
||||
GL.DeleteProgram(_handle);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ public class Renderer : IDisposable
|
|||
if (!Cache.TryGetModel(Settings.SelectedModel, out var model) ||
|
||||
!Settings.TryGetSection(model, out var section)) return;
|
||||
|
||||
section.SwapMaterial(unrealMaterial);
|
||||
section.Material.SwapMaterial(unrealMaterial);
|
||||
Settings.SwapMaterial(false);
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +111,7 @@ public class Renderer : IDisposable
|
|||
if (!original.TryConvert(out var mesh))
|
||||
return null;
|
||||
|
||||
Cache.AddModel(guid, new Model(original.Name, original.ExportType, mesh));
|
||||
Cache.AddModel(guid, new Model(original.Name, original.ExportType, original.Materials, mesh));
|
||||
Settings.SelectModel(guid);
|
||||
return SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
|
||||
}
|
||||
|
|
@ -121,7 +121,7 @@ public class Renderer : IDisposable
|
|||
var guid = Guid.NewGuid();
|
||||
if (Cache.HasModel(guid) || !original.TryConvert(out var mesh)) return null;
|
||||
|
||||
Cache.AddModel(guid, new Model(original.Name, original.ExportType, original.MorphTargets, mesh));
|
||||
Cache.AddModel(guid, new Model(original.Name, original.ExportType, original.Materials, original.MorphTargets, mesh));
|
||||
Settings.SelectModel(guid);
|
||||
return SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
|
||||
}
|
||||
|
|
@ -175,7 +175,7 @@ public class Renderer : IDisposable
|
|||
}
|
||||
else if (m.TryConvert(out var mesh))
|
||||
{
|
||||
model = new Model(m.Name, m.ExportType, mesh, transform);
|
||||
model = new Model(m.Name, m.ExportType, m.Materials, mesh, transform);
|
||||
|
||||
if (actor.TryGetAllValues(out FPackageIndex[] textureData, "TextureData"))
|
||||
{
|
||||
|
|
@ -186,13 +186,13 @@ public class Renderer : IDisposable
|
|||
|
||||
if (textureDataIdx.TryGetValue(out FPackageIndex diffuse, "Diffuse") &&
|
||||
diffuse.Load() is UTexture2D diffuseTexture)
|
||||
model.Sections[j].Parameters.Diffuse = diffuseTexture;
|
||||
model.Sections[j].Material.Parameters.Textures["Diffuse"] = diffuseTexture;
|
||||
if (textureDataIdx.TryGetValue(out FPackageIndex normal, "Normal") &&
|
||||
normal.Load() is UTexture2D normalTexture)
|
||||
model.Sections[j].Parameters.Normal = normalTexture;
|
||||
model.Sections[j].Material.Parameters.Textures["Normals"] = normalTexture;
|
||||
if (textureDataIdx.TryGetValue(out FPackageIndex specular, "Specular") &&
|
||||
specular.Load() is UTexture2D specularTexture)
|
||||
model.Sections[j].Parameters.Specular = specularTexture;
|
||||
model.Sections[j].Material.Parameters.Textures["SpecularMasks"] = specularTexture;
|
||||
}
|
||||
}
|
||||
if (staticMeshComp.TryGetValue(out FPackageIndex[] overrideMaterials, "OverrideMaterials"))
|
||||
|
|
@ -202,7 +202,7 @@ public class Renderer : IDisposable
|
|||
{
|
||||
if (j > max) break;
|
||||
if (overrideMaterials[j].Load() is not UMaterialInterface unrealMaterial) continue;
|
||||
model.Sections[j].SwapMaterial(unrealMaterial);
|
||||
model.Sections[j].Material.SwapMaterial(unrealMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,5 @@
|
|||
using System;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using CUE4Parse_Conversion.Meshes.PSK;
|
||||
using CUE4Parse_Conversion.Textures;
|
||||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
using System;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Mathematics;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
|
|
@ -14,239 +7,37 @@ public class Section : IDisposable
|
|||
{
|
||||
private int _handle;
|
||||
|
||||
private Vector3 _ambientLight;
|
||||
|
||||
private readonly FGame _game;
|
||||
|
||||
public string Name;
|
||||
public readonly int Index;
|
||||
public readonly int FacesCount;
|
||||
public readonly int FirstFaceIndex;
|
||||
public readonly CMaterialParams Parameters;
|
||||
public readonly Material Material;
|
||||
|
||||
public bool Show;
|
||||
public bool Wireframe;
|
||||
public readonly Texture[] Textures;
|
||||
public readonly string[] TexturesLabels;
|
||||
public Vector4 DiffuseColor;
|
||||
public Vector4 EmissionColor;
|
||||
public bool HasSpecularMap;
|
||||
public bool HasDiffuseColor;
|
||||
|
||||
private Section(string name, int index, int facesCount, int firstFaceIndex)
|
||||
private Section(int index, int facesCount, int firstFaceIndex)
|
||||
{
|
||||
Name = name;
|
||||
Index = index;
|
||||
FacesCount = facesCount;
|
||||
FirstFaceIndex = firstFaceIndex;
|
||||
Parameters = new CMaterialParams();
|
||||
|
||||
Show = true;
|
||||
Textures = new Texture[4];
|
||||
TexturesLabels = new[] { "Diffuse", "Normal", "Specular", "Emissive" };
|
||||
DiffuseColor = Vector4.Zero;
|
||||
EmissionColor = Vector4.Zero;
|
||||
|
||||
_game = ApplicationService.ApplicationView.CUE4Parse.Game;
|
||||
}
|
||||
|
||||
public Section(string name, int index, int facesCount, int firstFaceIndex, CMeshSection section) : this(name, index, facesCount, firstFaceIndex)
|
||||
public Section(int index, int facesCount, int firstFaceIndex, Material material) : this(index, facesCount, firstFaceIndex)
|
||||
{
|
||||
if (section.Material != null && section.Material.TryLoad(out var material) && material is UMaterialInterface unrealMaterial)
|
||||
{
|
||||
SwapMaterial(unrealMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
public Section(int index, int facesCount, int firstFaceIndex, UMaterialInterface unrealMaterial) : this(string.Empty, index, facesCount, firstFaceIndex)
|
||||
{
|
||||
SwapMaterial(unrealMaterial);
|
||||
}
|
||||
|
||||
public void SwapMaterial(UMaterialInterface unrealMaterial)
|
||||
{
|
||||
Name = unrealMaterial.Name;
|
||||
unrealMaterial.GetParams(Parameters);
|
||||
Material = material;
|
||||
}
|
||||
|
||||
public void Setup(Cache cache)
|
||||
{
|
||||
_handle = GL.CreateProgram();
|
||||
|
||||
if (Parameters.IsNull)
|
||||
{
|
||||
DiffuseColor = new Vector4(1, 0, 0, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
var platform = UserSettings.Default.OverridedPlatform;
|
||||
void Add(int index, UTexture2D original)
|
||||
{
|
||||
var guid = original.LightingGuid;
|
||||
if (cache.TryGetTexture(guid, out var texture))
|
||||
{
|
||||
// Anything in Parameters that is supposed to be modified will not be modified
|
||||
// eg. Metallic Roughness
|
||||
Textures[index] = texture;
|
||||
}
|
||||
else if (original.GetFirstMip() is { } mip)
|
||||
{
|
||||
byte[] data;
|
||||
if (index != 2) TextureDecoder.DecodeTexture(mip, original.Format, original.isNormalMap, platform, out data, out _);
|
||||
else SwapSpecular(original, mip, platform, out data);
|
||||
|
||||
var t = new Texture(data, mip.SizeX, mip.SizeY, original);
|
||||
cache.AddTexture(guid, t);
|
||||
Textures[index] = t;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Parameters.HasTopDiffuseTexture && Parameters.DiffuseColor is { A: > 0 } diffuseColor)
|
||||
DiffuseColor = new Vector4(diffuseColor.R, diffuseColor.G, diffuseColor.B, diffuseColor.A);
|
||||
else if (Parameters.Diffuse is UTexture2D { IsVirtual: false } diffuse)
|
||||
Add(0, diffuse);
|
||||
|
||||
if (Parameters.Normal is UTexture2D { IsVirtual: false } normal)
|
||||
Add(1, normal);
|
||||
|
||||
if (Parameters.Specular is UTexture2D { IsVirtual: false } specular)
|
||||
Add(2, specular);
|
||||
|
||||
if (Parameters.HasTopEmissiveTexture &&
|
||||
Parameters.Emissive is UTexture2D { IsVirtual: false } emissive)
|
||||
{
|
||||
Add(3, emissive);
|
||||
if (Parameters.EmissiveColor is { A: > 0 } emissiveColor)
|
||||
EmissionColor = new Vector4(emissiveColor.R, emissiveColor.G, emissiveColor.B, emissiveColor.A);
|
||||
else
|
||||
EmissionColor = Vector4.One;
|
||||
}
|
||||
}
|
||||
|
||||
// diffuse light is based on normal map, so increase ambient if no normal map
|
||||
_ambientLight = new Vector3(Textures[1] == null ? 1.0f : 0.2f);
|
||||
HasSpecularMap = Textures[2] != null;
|
||||
HasDiffuseColor = DiffuseColor != Vector4.Zero;
|
||||
Show = !Parameters.IsNull && !Parameters.IsTransparent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// goal is to put
|
||||
/// Metallic on Blue
|
||||
/// Roughness on Green
|
||||
/// Ambient Occlusion on Red
|
||||
/// </summary>
|
||||
private void SwapSpecular(UTexture2D specular, FTexture2DMipMap mip, ETexturePlatform platform, out byte[] data)
|
||||
{
|
||||
TextureDecoder.DecodeTexture(mip, specular.Format, specular.isNormalMap, platform, out data, out _);
|
||||
|
||||
switch (_game)
|
||||
{
|
||||
case FGame.FortniteGame:
|
||||
{
|
||||
// Fortnite's Specular Texture Channels
|
||||
// R Specular
|
||||
// G Metallic
|
||||
// B Roughness
|
||||
unsafe
|
||||
{
|
||||
var offset = 0;
|
||||
fixed (byte* d = data)
|
||||
{
|
||||
for (var i = 0; i < mip.SizeX * mip.SizeY; i++)
|
||||
{
|
||||
(d[offset + 1], d[offset + 2]) = (d[offset + 2], d[offset + 1]); // swap G and B
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FGame.ShooterGame:
|
||||
{
|
||||
var packedPBRType = specular.Name[(specular.Name.LastIndexOf('_') + 1)..];
|
||||
switch (packedPBRType)
|
||||
{
|
||||
case "MRAE": // R: Metallic, G: AO (0-127) & Emissive (128-255), B: Roughness (Character PBR)
|
||||
unsafe
|
||||
{
|
||||
var offset = 0;
|
||||
fixed (byte* d = data)
|
||||
{
|
||||
for (var i = 0; i < mip.SizeX * mip.SizeY; i++)
|
||||
{
|
||||
(d[offset], d[offset + 2]) = (d[offset + 2], d[offset]); // swap R and B
|
||||
(d[offset], d[offset + 1]) = (d[offset + 1], d[offset]); // swap R and G
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case "MRAS": // R: Metallic, B: Roughness, B: AO, A: Specular (Legacy PBR)
|
||||
case "MRA": // R: Metallic, B: Roughness, B: AO (Environment PBR)
|
||||
case "MRS": // R: Metallic, G: Roughness, B: Specular (Weapon PBR)
|
||||
unsafe
|
||||
{
|
||||
var offset = 0;
|
||||
fixed (byte* d = data)
|
||||
{
|
||||
for (var i = 0; i < mip.SizeX * mip.SizeY; i++)
|
||||
{
|
||||
(d[offset], d[offset + 2]) = (d[offset + 2], d[offset]); // swap R and B
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FGame.Gameface:
|
||||
{
|
||||
// GTA's Specular Texture Channels
|
||||
// R Metallic
|
||||
// G Roughness
|
||||
// B Specular
|
||||
unsafe
|
||||
{
|
||||
var offset = 0;
|
||||
fixed (byte* d = data)
|
||||
{
|
||||
for (var i = 0; i < mip.SizeX * mip.SizeY; i++)
|
||||
{
|
||||
(d[offset], d[offset + 2]) = (d[offset + 2], d[offset]); // swap R and B
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Parameters.MetallicValue = 1;
|
||||
Parameters.RoughnessValue = 0;
|
||||
Material.Setup(cache);
|
||||
}
|
||||
|
||||
public void Render(Shader shader, int instanceCount)
|
||||
{
|
||||
for (var i = 0; i < Textures.Length; i++)
|
||||
{
|
||||
Textures[i]?.Bind(TextureUnit.Texture0 + i);
|
||||
}
|
||||
|
||||
shader.SetUniform("material.useSpecularMap", HasSpecularMap);
|
||||
|
||||
shader.SetUniform("material.hasDiffuseColor", HasDiffuseColor);
|
||||
shader.SetUniform("material.diffuseColor", DiffuseColor);
|
||||
|
||||
shader.SetUniform("material.emissionColor", EmissionColor);
|
||||
|
||||
shader.SetUniform("material.metallic_value", 1f);
|
||||
shader.SetUniform("material.roughness_value", 0f);
|
||||
|
||||
shader.SetUniform("light.ambient", _ambientLight);
|
||||
Material.Render(shader);
|
||||
|
||||
GL.PolygonMode(MaterialFace.FrontAndBack, Wireframe ? PolygonMode.Line : PolygonMode.Fill);
|
||||
if (Show) GL.DrawArraysInstanced(PrimitiveType.Triangles, FirstFaceIndex, FacesCount, instanceCount);
|
||||
|
|
@ -254,10 +45,6 @@ public class Section : IDisposable
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
for (var i = 0; i < Textures.Length; i++)
|
||||
{
|
||||
Textures[i]?.Dispose();
|
||||
}
|
||||
GL.DeleteProgram(_handle);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user