mirror of
https://github.com/4sval/FModel.git
synced 2026-09-13 03:56:43 -05:00
improved shader
This commit is contained in:
Submodule CUE4Parse updated: 5725d3c30e...194224aff8
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -134,7 +134,7 @@ public class Snooper
|
||||
|
||||
_controller = new ImGuiController(_gl, _window, input);
|
||||
|
||||
ImGuiExtensions.Theme();
|
||||
// ImGuiExtensions.Theme();
|
||||
|
||||
_skybox.Setup(_gl);
|
||||
_grid.Setup(_gl);
|
||||
|
||||
@@ -90,6 +90,8 @@ public class Texture : IDisposable
|
||||
_gl.BindTexture(target, _handle);
|
||||
}
|
||||
|
||||
public IntPtr GetPointer() => (IntPtr) _handle;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_gl.DeleteTexture(_handle);
|
||||
|
||||
Reference in New Issue
Block a user