From b947ac3e967084c2f3ba405c9e498bc407b3f912 Mon Sep 17 00:00:00 2001 From: 4sval Date: Tue, 30 Aug 2022 17:14:32 +0200 Subject: [PATCH] improved shader --- CUE4Parse | 2 +- FModel/Resources/shader.frag | 73 +++++++---- FModel/Views/Snooper/Model.cs | 3 +- FModel/Views/Snooper/Section.cs | 224 +++++++++++++++++++++++++------- FModel/Views/Snooper/Shader.cs | 2 + FModel/Views/Snooper/Snooper.cs | 2 +- FModel/Views/Snooper/Texture.cs | 2 + 7 files changed, 232 insertions(+), 76 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 5725d3c3..194224af 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 5725d3c30ec311870e5832e6869af73ea40aab79 +Subproject commit 194224aff89fa4512edac7557e7a1859b878f3a8 diff --git a/FModel/Resources/shader.frag b/FModel/Resources/shader.frag index 1fa18d57..129ac22b 100644 --- a/FModel/Resources/shader.frag +++ b/FModel/Resources/shader.frag @@ -7,14 +7,16 @@ in vec2 fTexCoords; struct Material { sampler2D diffuseMap; sampler2D normalMap; - sampler2D specularMap; - sampler2D metallicMap; sampler2D emissionMap; - bool swap; + bool useSpecularMap; + sampler2D specularMap; + bool hasDiffuseColor; vec4 diffuseColor; + vec4 emissionColor; + float shininess; }; @@ -31,36 +33,55 @@ uniform vec3 viewPos; out vec4 FragColor; +vec3 getNormalFromMap() +{ + vec3 tangentNormal = texture(material.normalMap, fTexCoords).xyz * 2.0 - 1.0; + + vec3 q1 = dFdx(fPos); + vec3 q2 = dFdy(fPos); + vec2 st1 = dFdx(fTexCoords); + vec2 st2 = dFdy(fTexCoords); + + vec3 n = normalize(fNormal); + vec3 t = normalize(q1*st2.t - q2*st1.t); + vec3 b = -normalize(cross(n, t)); + mat3 tbn = mat3(t, b, n); + + return normalize(tbn * tangentNormal); +} + void main() { - if (material.swap) + if (material.hasDiffuseColor) { FragColor = material.diffuseColor; - return; } + else + { + vec3 n_normal_map = getNormalFromMap(); + vec3 n_light_direction = normalize(light.position - fPos); + vec3 result = light.ambient * vec3(texture(material.diffuseMap, fTexCoords)); - // ambient - vec3 ambient = light.ambient * vec3(texture(material.diffuseMap, fTexCoords)); + // diffuse + float diff = max(dot(n_normal_map, n_light_direction), 0.0f); + vec4 diffuse_map = texture(material.diffuseMap, fTexCoords); + if(diffuse_map.a < 0.1f) discard; + result += light.diffuse * diff * diffuse_map.rgb; - // diffuse - vec3 norm = texture(material.normalMap, fTexCoords).rgb; - norm = normalize(norm * 2.0 - 1.0); - vec3 lightDir = normalize(light.position - fPos); - float diff = max(dot(norm, lightDir), 0.0f); - vec3 diffuseMap = vec3(texture(material.diffuseMap, fTexCoords)); - vec3 diffuse = light.diffuse * diff * diffuseMap; + // specular + if (material.useSpecularMap) + { + vec3 n_view_direction = normalize(viewPos - fPos); + vec3 reflect_direction = reflect(-n_light_direction, n_normal_map); + float spec = pow(max(dot(n_view_direction, reflect_direction), 0.0f), material.shininess); + vec3 specular_map = vec3(texture(material.specularMap, fTexCoords)); + result += light.specular * spec * specular_map.b; + } - // specular - vec3 viewDir = normalize(viewPos - fPos); - vec3 reflectDir = reflect(-lightDir, norm); - float spec = pow(max(dot(viewDir, reflectDir), 0.0f), material.shininess); - vec3 specularMap = vec3(texture(material.specularMap, fTexCoords)); - vec3 specular = light.specular * spec * specularMap; + // emission + vec3 emission_map = vec3(texture(material.emissionMap, fTexCoords)); + result += material.emissionColor.rgb * emission_map; - // emission - vec3 emissionMap = vec3(texture(material.emissionMap, fTexCoords)); - vec3 emission = material.emissionColor.rgb * emissionMap; - - vec3 result = ambient + diffuse + specular + emission; - FragColor = vec4(result, 1.0); + FragColor = vec4(result, 1.0); + } } diff --git a/FModel/Views/Snooper/Model.cs b/FModel/Views/Snooper/Model.cs index 8a032683..dee34493 100644 --- a/FModel/Views/Snooper/Model.cs +++ b/FModel/Views/Snooper/Model.cs @@ -90,11 +90,12 @@ public class Model : IDisposable ImGui.BeginTable("Sections", 2, ImGuiTableFlags.RowBg); ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.WidthFixed); - ImGui.TableSetupColumn("Material", ImGuiTableColumnFlags.WidthStretch); + ImGui.TableSetupColumn("Material", ImGuiTableColumnFlags.WidthFixed); ImGui.TableHeadersRow(); for (int section = 0; section < Sections.Length; section++) { Sections[section].Bind(camera, Indices.Length); + // if (!Sections[section].Show) continue; _gl.DrawArrays(PrimitiveType.Triangles, Sections[section].FirstFaceIndex, Sections[section].FacesCount); } ImGui.EndTable(); diff --git a/FModel/Views/Snooper/Section.cs b/FModel/Views/Snooper/Section.cs index a1097bf7..6bf40667 100644 --- a/FModel/Views/Snooper/Section.cs +++ b/FModel/Views/Snooper/Section.cs @@ -4,6 +4,7 @@ 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 ImGuiNET; using Silk.NET.OpenGL; @@ -14,15 +15,17 @@ public class Section : IDisposable { private uint _handle; private GL _gl; + private FGame _game; private Texture _diffuseMap; private Texture _normalMap; private Texture _specularMap; - // private Texture _metallicMap; private Texture _emissionMap; - private Vector4 _diffuseColor; - private Vector4 _emissionColor; + private bool _hasDiffuseColor; + private bool _hasSpecularMap; + private Vector4 _diffuseColor = Vector4.Zero; + private Vector4 _emissionColor = Vector4.Zero; private Shader _shader; @@ -32,6 +35,13 @@ public class Section : IDisposable public readonly int FirstFaceIndex; public readonly CMaterialParams Parameters; + private bool _show = true; + public bool Show + { + get => _show; + set => _show = value; + } + public Section(string name, int index, uint facesCount, int firstFaceIndex, CMeshSection section) { Name = name; @@ -44,6 +54,8 @@ public class Section : IDisposable Name = unrealMaterial.Name; unrealMaterial.GetParams(Parameters); } + + _game = ApplicationService.ApplicationView.CUE4Parse.Game; } public void Setup(GL gl) @@ -57,43 +69,152 @@ public class Section : IDisposable if (Parameters.IsNull) { _diffuseColor = new Vector4(1, 0, 0, 1); - return; + } + else + { + var platform = UserSettings.Default.OverridedPlatform; + 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) + { + var mip = diffuse.GetFirstMip(); + TextureDecoder.DecodeTexture(mip, diffuse.Format, diffuse.isNormalMap, platform, out var data, out _); + _diffuseMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY); + } + + if (Parameters.Normal is UTexture2D { IsVirtual: false } normal) + { + var mip = normal.GetFirstMip(); + TextureDecoder.DecodeTexture(mip, normal.Format, normal.isNormalMap, platform, out var data, out _); + _normalMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY); + } + + if (Parameters.Specular is UTexture2D { IsVirtual: false } specular) + { + var mip = specular.GetFirstMip(); + SwapSpecular(specular, mip, platform, out var data); + _specularMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY); + } + + if (Parameters.HasTopEmissiveTexture && + Parameters.EmissiveColor is { A: > 0 } emissiveColor && + Parameters.Emissive is UTexture2D { IsVirtual: false } emissive) + { + var mip = emissive.GetFirstMip(); + TextureDecoder.DecodeTexture(mip, emissive.Format, emissive.isNormalMap, platform, out var data, out _); + _emissionMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY); + _emissionColor = new Vector4(emissiveColor.R, emissiveColor.G, emissiveColor.B, emissiveColor.A); + } } - var platform = UserSettings.Default.OverridedPlatform; - 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) - { - var mip = diffuse.GetFirstMip(); - TextureDecoder.DecodeTexture(mip, diffuse.Format, diffuse.isNormalMap, platform, out var data, out _); - _diffuseMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY); - } + _hasSpecularMap = _specularMap != null; + _hasDiffuseColor = _diffuseColor != Vector4.Zero; + _show = !Parameters.IsNull && !Parameters.IsTransparent; + } - if (Parameters.Normal is UTexture2D { IsVirtual: false } normal) - { - var mip = normal.GetFirstMip(); - TextureDecoder.DecodeTexture(mip, normal.Format, normal.isNormalMap, platform, out var data, out _); - _normalMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY); - } + /// + /// goal is to put + /// Metallic on Blue + /// Roughness on Green + /// Ambient Occlusion on Red + /// + private void SwapSpecular(UTexture2D specular, FTexture2DMipMap mip, ETexturePlatform platform, out byte[] data) + { + TextureDecoder.DecodeTexture(mip, specular.Format, specular.isNormalMap, platform, out data, out _); - if (Parameters.Specular is UTexture2D { IsVirtual: false } specular) + switch (_game) { - var mip = specular.GetFirstMip(); - TextureDecoder.DecodeTexture(mip, specular.Format, specular.isNormalMap, platform, out var data, out _); - _specularMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY); - } + 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] = 0; + (d[offset + 1], d[offset + 2]) = (d[offset + 2], d[offset + 1]); // swap G and B + offset += 4; + } + } + } - if (Parameters.HasTopEmissiveTexture && - Parameters.EmissiveColor is { A: > 0 } emissiveColor && - Parameters.Emissive is UTexture2D { IsVirtual: false } emissive) - { - var mip = emissive.GetFirstMip(); - TextureDecoder.DecodeTexture(mip, emissive.Format, emissive.isNormalMap, platform, out var data, out _); - _emissionMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY); - _emissionColor = new Vector4(emissiveColor.R, emissiveColor.G, emissiveColor.B, emissiveColor.A); + Parameters.RoughnessValue = 1; + Parameters.MetallicValue = 1; + 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; + } + + Parameters.RoughnessValue = 1; + Parameters.MetallicValue = 1; + 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; + } } } @@ -111,8 +232,19 @@ public class Section : IDisposable ImGui.Text($"Faces: {FacesCount} ({Math.Round(FacesCount / indices * 100f, 2)}%%)"); ImGui.Text($"First Face: {FirstFaceIndex}"); ImGui.Separator(); - ImGui.Text($"Diffuse: ({Parameters.Diffuse?.ExportType}) {Parameters.Diffuse?.Name}"); - ImGui.Text($"Normal: ({Parameters.Normal?.ExportType}) {Parameters.Normal?.Name}"); + if (_hasDiffuseColor) + { + ImGui.ColorEdit4("Diffuse Color", ref _diffuseColor, ImGuiColorEditFlags.NoInputs); + } + else + { + ImGui.Text($"Diffuse: ({Parameters.Diffuse?.ExportType}) {Parameters.Diffuse?.Name}"); + ImGui.Text($"Normal: ({Parameters.Normal?.ExportType}) {Parameters.Normal?.Name}"); + ImGui.Text($"Specular: ({Parameters.Specular?.ExportType}) {Parameters.Specular?.Name}"); + if (Parameters.HasTopEmissiveTexture) + ImGui.Text($"Emissive: ({Parameters.Emissive?.ExportType}) {Parameters.Emissive?.Name}"); + ImGui.Separator(); + } ImGui.EndTooltip(); } @@ -126,26 +258,24 @@ public class Section : IDisposable _shader.SetUniform("material.diffuseMap", 0); _shader.SetUniform("material.normalMap", 1); _shader.SetUniform("material.specularMap", 2); - // _shader.SetUniform("material.metallicMap", 3); - _shader.SetUniform("material.emissionMap", 4); - _shader.SetUniform("material.shininess", 32f); + _shader.SetUniform("material.useSpecularMap", _hasSpecularMap); - _shader.SetUniform("material.swap", Convert.ToUInt32(_diffuseColor != Vector4.Zero)); + _shader.SetUniform("material.hasDiffuseColor", _hasDiffuseColor); _shader.SetUniform("material.diffuseColor", _diffuseColor); + + _shader.SetUniform("material.emissionMap", 4); _shader.SetUniform("material.emissionColor", _emissionColor); + _shader.SetUniform("material.shininess", Parameters.MetallicValue); + _diffuseMap?.Bind(TextureUnit.Texture0); _normalMap?.Bind(TextureUnit.Texture1); _specularMap?.Bind(TextureUnit.Texture2); _emissionMap?.Bind(TextureUnit.Texture4); - var lightColor = Vector3.One; - var diffuseColor = lightColor * new Vector3(0.5f); - var ambientColor = diffuseColor * new Vector3(0.2f); - - _shader.SetUniform("light.ambient", ambientColor); - _shader.SetUniform("light.diffuse", diffuseColor); // darkened - _shader.SetUniform("light.specular", Vector3.One); + _shader.SetUniform("light.ambient", new Vector3(0.2f)); + _shader.SetUniform("light.diffuse", new Vector3(0.75f)); + _shader.SetUniform("light.specular", new Vector3(0.5f)); _shader.SetUniform("light.position", camera.Position); } diff --git a/FModel/Views/Snooper/Shader.cs b/FModel/Views/Snooper/Shader.cs index 5ac485a2..cd540d43 100644 --- a/FModel/Views/Snooper/Shader.cs +++ b/FModel/Views/Snooper/Shader.cs @@ -61,6 +61,8 @@ public class Shader : IDisposable _gl.UniformMatrix4(location, 1, false, (float*) &value); } + public void SetUniform(string name, bool value) => SetUniform(name, Convert.ToUInt32(value)); + public void SetUniform(string name, uint value) { int location = _gl.GetUniformLocation(_handle, name); diff --git a/FModel/Views/Snooper/Snooper.cs b/FModel/Views/Snooper/Snooper.cs index f9646acb..05401e7c 100644 --- a/FModel/Views/Snooper/Snooper.cs +++ b/FModel/Views/Snooper/Snooper.cs @@ -134,7 +134,7 @@ public class Snooper _controller = new ImGuiController(_gl, _window, input); - ImGuiExtensions.Theme(); + // ImGuiExtensions.Theme(); _skybox.Setup(_gl); _grid.Setup(_gl); diff --git a/FModel/Views/Snooper/Texture.cs b/FModel/Views/Snooper/Texture.cs index 5478433c..8a1e60d4 100644 --- a/FModel/Views/Snooper/Texture.cs +++ b/FModel/Views/Snooper/Texture.cs @@ -90,6 +90,8 @@ public class Texture : IDisposable _gl.BindTexture(target, _handle); } + public IntPtr GetPointer() => (IntPtr) _handle; + public void Dispose() { _gl.DeleteTexture(_handle);