improved shader

This commit is contained in:
4sval
2022-08-30 17:14:32 +02:00
parent 7b9e53c931
commit b947ac3e96
7 changed files with 232 additions and 76 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -134,7 +134,7 @@ public class Snooper
_controller = new ImGuiController(_gl, _window, input);
ImGuiExtensions.Theme();
// ImGuiExtensions.Theme();
_skybox.Setup(_gl);
_grid.Setup(_gl);

View File

@@ -90,6 +90,8 @@ public class Texture : IDisposable
_gl.BindTexture(target, _handle);
}
public IntPtr GetPointer() => (IntPtr) _handle;
public void Dispose()
{
_gl.DeleteTexture(_handle);