mirror of
https://github.com/4sval/FModel.git
synced 2026-04-24 06:48:38 -05:00
pbr lights + gamma correction
This commit is contained in:
parent
65d20fbde8
commit
25de50818d
|
|
@ -1 +1 @@
|
|||
Subproject commit 68fa4d6fcaca164d13919ab5bc64e5ed0b32ab7f
|
||||
Subproject commit cc744cfb54e219d7f5d9440d30c4cd55b56afb3c
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
#version 330 core
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define MAX_UV_COUNT 8
|
||||
|
||||
in vec3 fPos;
|
||||
|
|
@ -39,8 +41,6 @@ struct Parameters
|
|||
Mask M;
|
||||
bool HasM;
|
||||
|
||||
float Roughness;
|
||||
float SpecularMult;
|
||||
float EmissiveMult;
|
||||
|
||||
float UVScale;
|
||||
|
|
@ -49,6 +49,8 @@ struct Parameters
|
|||
uniform Parameters uParameters;
|
||||
uniform int uNumTexCoords;
|
||||
uniform vec3 uViewPos;
|
||||
uniform vec3 uViewDir;
|
||||
uniform bool bDiffuseOnly;
|
||||
uniform bool bVertexColors;
|
||||
uniform bool bVertexNormals;
|
||||
uniform bool bVertexTangent;
|
||||
|
|
@ -78,6 +80,59 @@ vec3 ComputeNormals(int layer)
|
|||
return normalize(tbn * normal);
|
||||
}
|
||||
|
||||
vec3 schlickFresnel(int layer, float vDotH)
|
||||
{
|
||||
vec3 f0 = vec3(0.04f);
|
||||
return f0 + (1.0f - f0) * pow(clamp(1.0f - vDotH, 0.0f, 1.0f), 5);
|
||||
}
|
||||
|
||||
float ggxDistribution(float roughness, float nDoth)
|
||||
{
|
||||
float alpha2 = roughness * roughness * roughness * roughness;
|
||||
float d = nDoth * nDoth * (alpha2- 1.0f) + 1.0f;
|
||||
return alpha2 / (PI * d * d);
|
||||
}
|
||||
|
||||
float geomSmith(float roughness, float dp)
|
||||
{
|
||||
float k = (roughness + 1.0f) * (roughness + 1.0f) / 8.0f;
|
||||
float denom = dp * (1.0f - k) + k;
|
||||
return dp / denom;
|
||||
}
|
||||
|
||||
vec3 CalcPBRLight(int layer, vec3 normals)
|
||||
{
|
||||
vec3 specular_masks = SamplerToVector(uParameters.SpecularMasks[layer].Sampler).rgb;
|
||||
float roughness = max(0.0f, specular_masks.b);
|
||||
|
||||
vec3 intensity = vec3(1.0f) * 1.0f;
|
||||
vec3 l = -uViewDir;
|
||||
|
||||
vec3 n = normals;
|
||||
vec3 v = normalize(uViewPos - fPos);
|
||||
vec3 h = normalize(v + l);
|
||||
|
||||
float nDotH = max(dot(n, h), 0.0f);
|
||||
float vDotH = max(dot(v, h), 0.0f);
|
||||
float nDotL = max(dot(n, l), 0.0f);
|
||||
float nDotV = max(dot(n, v), 0.0f);
|
||||
|
||||
vec3 f = schlickFresnel(layer, vDotH);
|
||||
|
||||
vec3 kS = f;
|
||||
vec3 kD = 1.0 - kS;
|
||||
kD *= 1.0 - max(0.0f, dot(v, reflect(-v, normals)) * specular_masks.g);
|
||||
|
||||
vec3 specBrdfNom = ggxDistribution(roughness, nDotH) * f * geomSmith(roughness, nDotL) * geomSmith(roughness, nDotV);
|
||||
float specBrdfDenom = 4.0f * nDotV * nDotL + 0.0001f;
|
||||
vec3 specBrdf = specBrdfNom / specBrdfDenom;
|
||||
|
||||
vec3 fLambert = SamplerToVector(uParameters.Diffuse[layer].Sampler).rgb * uParameters.Diffuse[layer].Color.rgb;
|
||||
|
||||
vec3 diffuseBrdf = kD * fLambert / PI;
|
||||
return (diffuseBrdf + specBrdf) * intensity * nDotL;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
if (bVertexColors)
|
||||
|
|
@ -99,13 +154,10 @@ void main()
|
|||
else
|
||||
{
|
||||
int layer = LayerToIndex();
|
||||
vec3 normals = ComputeNormals(layer);
|
||||
vec4 diffuse = SamplerToVector(uParameters.Diffuse[layer].Sampler);
|
||||
vec3 result = uParameters.Diffuse[layer].Color.rgb * diffuse.rgb;
|
||||
|
||||
vec3 normals = ComputeNormals(layer);
|
||||
vec3 light_direction = normalize(uViewPos - fPos);
|
||||
result += max(dot(normals, light_direction), 0.0f) * result;
|
||||
|
||||
if (uParameters.HasM)
|
||||
{
|
||||
vec3 m = SamplerToVector(uParameters.M.Sampler).rgb;
|
||||
|
|
@ -117,20 +169,19 @@ void main()
|
|||
result *= clamp(color * m.b, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
result *= m.r * uParameters.M.AmbientOcclusion;
|
||||
result += m.g * uParameters.M.Cavity;
|
||||
if (m.r > 0.0f) result *= m.r * uParameters.M.AmbientOcclusion;
|
||||
if (m.g > 0.0f) result += m.g * uParameters.M.Cavity;
|
||||
}
|
||||
|
||||
vec3 reflect_direction = reflect(-light_direction, normals);
|
||||
vec3 specular_masks = SamplerToVector(uParameters.SpecularMasks[layer].Sampler).rgb;
|
||||
float specular = uParameters.SpecularMult * max(0.0f, specular_masks.r);
|
||||
float metallic = max(0.0f, dot(light_direction, reflect_direction) * specular_masks.g);
|
||||
float roughness = max(0.0f, uParameters.Roughness * specular_masks.b);
|
||||
result += metallic * roughness * specular;
|
||||
|
||||
vec4 emissive = SamplerToVector(uParameters.Emissive[layer].Sampler);
|
||||
result += uParameters.Emissive[layer].Color.rgb * emissive.rgb * uParameters.EmissiveMult;
|
||||
|
||||
FragColor = vec4(result, 1.0f);
|
||||
if (!bDiffuseOnly)
|
||||
{
|
||||
result += CalcPBRLight(layer, normals);
|
||||
}
|
||||
|
||||
result = result / (result + vec3(1.0f));
|
||||
FragColor = vec4(pow(result, vec3(1.0f / 2.2f)), 1.0f);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@ out vec4 fColor;
|
|||
|
||||
void main()
|
||||
{
|
||||
vec3 pos = mix(vPos, vMorphTarget, uMorphTime);
|
||||
gl_Position = uProjection * uView * vInstanceMatrix * vec4(pos, 1.0);
|
||||
vec4 pos = vec4(mix(vPos, vMorphTarget, uMorphTime), 1.0);
|
||||
gl_Position = uProjection * uView * vInstanceMatrix * pos;
|
||||
|
||||
fPos = vec3(vInstanceMatrix * vec4(pos, 1.0));
|
||||
fPos = vec3(vInstanceMatrix * pos);
|
||||
fNormal = mat3(transpose(inverse(vInstanceMatrix))) * vNormal;
|
||||
fTangent = mat3(transpose(inverse(vInstanceMatrix))) * vTangent;
|
||||
fTexCoords = vTexCoords;
|
||||
|
|
|
|||
|
|
@ -15,12 +15,14 @@ public class Cache : IDisposable
|
|||
public readonly Dictionary<FGuid, Texture> Textures;
|
||||
|
||||
private ETexturePlatform _platform;
|
||||
private readonly FGame _game;
|
||||
|
||||
public Cache()
|
||||
{
|
||||
Models = new Dictionary<FGuid, Model>();
|
||||
Textures = new Dictionary<FGuid, Texture>();
|
||||
_platform = UserSettings.Default.OverridedPlatform;
|
||||
_game = Services.ApplicationService.ApplicationView.CUE4Parse.Game;
|
||||
}
|
||||
|
||||
public bool TryGetCachedModel(UStaticMesh o, out Model model)
|
||||
|
|
@ -34,12 +36,13 @@ public class Cache : IDisposable
|
|||
return model != null;
|
||||
}
|
||||
|
||||
public bool TryGetCachedTexture(UTexture2D o, out Texture texture)
|
||||
public bool TryGetCachedTexture(UTexture2D o, bool fix, out Texture texture)
|
||||
{
|
||||
var guid = o.LightingGuid;
|
||||
if (!Textures.TryGetValue(guid, out texture) && o.GetFirstMip() is { } mip)
|
||||
{
|
||||
TextureDecoder.DecodeTexture(mip, o.Format, o.isNormalMap, _platform, out var data, out _);
|
||||
// if (fix) FixChannels(o, mip, ref data);
|
||||
|
||||
texture = new Texture(data, mip.SizeX, mip.SizeY, o);
|
||||
Textures[guid] = texture;
|
||||
|
|
@ -47,6 +50,16 @@ public class Cache : IDisposable
|
|||
return texture != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Red : Specular
|
||||
/// Blue : Roughness
|
||||
/// Green : Metallic
|
||||
/// </summary>
|
||||
private void FixChannels(UTexture2D o, FTexture2DMipMap mip, ref byte[] data)
|
||||
{
|
||||
// only if it makes a big difference pls
|
||||
}
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
foreach (var model in Models.Values)
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ public class Material : IDisposable
|
|||
public Mask M;
|
||||
public bool HasM;
|
||||
|
||||
public float Roughness;
|
||||
public float SpecularMult = 1f;
|
||||
public float EmissiveMult = 1f;
|
||||
|
||||
public float UVScale = 1f;
|
||||
|
|
@ -89,7 +87,7 @@ public class Material : IDisposable
|
|||
}
|
||||
|
||||
{ // scalars
|
||||
if (Parameters.TryGetTexture2d(out var original, "M") && cache.TryGetCachedTexture(original, out var transformed))
|
||||
if (Parameters.TryGetTexture2d(out var original, "M", "AEM") && cache.TryGetCachedTexture(original, false, out var transformed))
|
||||
{
|
||||
M = new Mask { Texture = transformed, AmbientOcclusion = 0.7f };
|
||||
HasM = true;
|
||||
|
|
@ -97,14 +95,6 @@ public class Material : IDisposable
|
|||
M.SkinBoost = new Boost { Color = new Vector3(l.R, l.G, l.B), Exponent = l.A };
|
||||
}
|
||||
|
||||
if (Parameters.TryGetScalar(out var roughnessMin, "RoughnessMin", "SpecRoughnessMin") &&
|
||||
Parameters.TryGetScalar(out var roughnessMax, "RoughnessMax", "SpecRoughnessMax"))
|
||||
Roughness = (roughnessMin + roughnessMax) / 2f;
|
||||
if (Parameters.TryGetScalar(out var roughness, "Rough", "Roughness"))
|
||||
Roughness = roughness;
|
||||
|
||||
if (Parameters.TryGetScalar(out var specularMult, "SpecularMult"))
|
||||
SpecularMult = specularMult;
|
||||
if (Parameters.TryGetScalar(out var emissiveMult, "emissive mult", "Emissive_Mult"))
|
||||
EmissiveMult = emissiveMult;
|
||||
|
||||
|
|
@ -124,24 +114,25 @@ public class Material : IDisposable
|
|||
{
|
||||
UTexture2D original;
|
||||
Texture transformed;
|
||||
var fix = fallback == CMaterialParams2.FallbackSpecularMasks;
|
||||
var textures = new Texture[numTexCoords];
|
||||
|
||||
if (top)
|
||||
{
|
||||
for (int i = 0; i < textures.Length; i++)
|
||||
{
|
||||
if (Parameters.TryGetTexture2d(out original, triggers[i]) && cache.TryGetCachedTexture(original, out transformed))
|
||||
if (Parameters.TryGetTexture2d(out original, triggers[i]) && cache.TryGetCachedTexture(original, fix, out transformed))
|
||||
textures[i] = transformed;
|
||||
else if (i > 0 && textures[i - 1] != null)
|
||||
textures[i] = textures[i - 1];
|
||||
}
|
||||
}
|
||||
else if (Parameters.TryGetTexture2d(out original, fallback) && cache.TryGetCachedTexture(original, out transformed))
|
||||
else if (Parameters.TryGetTexture2d(out original, fallback) && cache.TryGetCachedTexture(original, fix, out transformed))
|
||||
{
|
||||
for (int i = 0; i < textures.Length; i++)
|
||||
textures[i] = transformed;
|
||||
}
|
||||
else if (first && Parameters.TryGetFirstTexture2d(out original) && cache.TryGetCachedTexture(original, out transformed))
|
||||
else if (first && Parameters.TryGetFirstTexture2d(out original) && cache.TryGetCachedTexture(original, fix, out transformed))
|
||||
{
|
||||
for (int i = 0; i < textures.Length; i++)
|
||||
textures[i] = transformed;
|
||||
|
|
@ -206,8 +197,6 @@ public class Material : IDisposable
|
|||
shader.SetUniform("uParameters.M.Cavity", M.Cavity);
|
||||
shader.SetUniform("uParameters.HasM", HasM);
|
||||
|
||||
shader.SetUniform("uParameters.Roughness", Roughness);
|
||||
shader.SetUniform("uParameters.SpecularMult", SpecularMult);
|
||||
shader.SetUniform("uParameters.EmissiveMult", EmissiveMult);
|
||||
|
||||
shader.SetUniform("uParameters.UVScale", UVScale);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ public class Renderer : IDisposable
|
|||
private Shader _shader;
|
||||
private Shader _outline;
|
||||
|
||||
public bool bDiffuseOnly;
|
||||
|
||||
public PickingTexture Picking { get; }
|
||||
public Cache Cache { get; }
|
||||
public Options Settings { get; }
|
||||
|
|
@ -68,7 +70,8 @@ public class Renderer : IDisposable
|
|||
var projMatrix = cam.GetProjectionMatrix();
|
||||
|
||||
// render pass
|
||||
_shader.Render(viewMatrix, cam.Position, projMatrix);
|
||||
_shader.Render(viewMatrix, cam.Position, cam.Direction, projMatrix);
|
||||
_shader.SetUniform("bDiffuseOnly", bDiffuseOnly);
|
||||
foreach (var model in Cache.Models.Values)
|
||||
{
|
||||
if (!model.Show) continue;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
|
|
@ -10,8 +9,6 @@ namespace FModel.Views.Snooper;
|
|||
public class Shader : IDisposable
|
||||
{
|
||||
private readonly int _handle;
|
||||
private readonly Dictionary<string, int> _uniformToLocation = new ();
|
||||
private readonly Dictionary<string, int> _attribLocation = new ();
|
||||
|
||||
public Shader() : this("default") {}
|
||||
|
||||
|
|
@ -57,6 +54,11 @@ public class Shader : IDisposable
|
|||
GL.UseProgram(_handle);
|
||||
}
|
||||
|
||||
public void Render(Matrix4 viewMatrix, Vector3 viewPos, Vector3 viewDir, Matrix4 projMatrix)
|
||||
{
|
||||
Render(viewMatrix, viewPos, projMatrix);
|
||||
SetUniform("uViewDir", viewDir);
|
||||
}
|
||||
public void Render(Matrix4 viewMatrix, Vector3 viewPos, Matrix4 projMatrix)
|
||||
{
|
||||
Render(viewMatrix, projMatrix);
|
||||
|
|
@ -72,10 +74,7 @@ public class Shader : IDisposable
|
|||
public void SetUniform(string name, int value)
|
||||
{
|
||||
int location = GL.GetUniformLocation(_handle, name);
|
||||
if (location == -1)
|
||||
{
|
||||
throw new Exception($"{name} uniform not found on shader.");
|
||||
}
|
||||
ThrowIfNotFound(location, name);
|
||||
GL.Uniform1(location, value);
|
||||
}
|
||||
|
||||
|
|
@ -83,10 +82,7 @@ public class Shader : IDisposable
|
|||
{
|
||||
//A new overload has been created for setting a uniform so we can use the transform in our shader.
|
||||
int location = GL.GetUniformLocation(_handle, name);
|
||||
if (location == -1)
|
||||
{
|
||||
throw new Exception($"{name} uniform not found on shader.");
|
||||
}
|
||||
ThrowIfNotFound(location, name);
|
||||
GL.UniformMatrix4(location, 1, false, (float*) &value);
|
||||
}
|
||||
|
||||
|
|
@ -95,20 +91,14 @@ public class Shader : IDisposable
|
|||
public void SetUniform(string name, uint value)
|
||||
{
|
||||
int location = GL.GetUniformLocation(_handle, name);
|
||||
if (location == -1)
|
||||
{
|
||||
throw new Exception($"{name} uniform not found on shader.");
|
||||
}
|
||||
ThrowIfNotFound(location, name);
|
||||
GL.Uniform1(location, value);
|
||||
}
|
||||
|
||||
public void SetUniform(string name, float value)
|
||||
{
|
||||
int location = GL.GetUniformLocation(_handle, name);
|
||||
if (location == -1)
|
||||
{
|
||||
throw new Exception($"{name} uniform not found on shader.");
|
||||
}
|
||||
ThrowIfNotFound(location, name);
|
||||
GL.Uniform1(location, value);
|
||||
}
|
||||
|
||||
|
|
@ -117,10 +107,7 @@ public class Shader : IDisposable
|
|||
public void SetUniform3(string name, float x, float y, float z)
|
||||
{
|
||||
int location = GL.GetUniformLocation(_handle, name);
|
||||
if (location == -1)
|
||||
{
|
||||
throw new Exception($"{name} uniform not found on shader.");
|
||||
}
|
||||
ThrowIfNotFound(location, name);
|
||||
GL.Uniform3(location, x, y, z);
|
||||
}
|
||||
|
||||
|
|
@ -129,39 +116,16 @@ public class Shader : IDisposable
|
|||
public void SetUniform4(string name, float x, float y, float z, float w)
|
||||
{
|
||||
int location = GL.GetUniformLocation(_handle, name);
|
||||
if (location == -1)
|
||||
{
|
||||
throw new Exception($"{name} uniform not found on shader.");
|
||||
}
|
||||
ThrowIfNotFound(location, name);
|
||||
GL.Uniform4(location, x, y, z, w);
|
||||
}
|
||||
|
||||
public int GetUniformLocation(string uniform)
|
||||
private void ThrowIfNotFound(int location, string name)
|
||||
{
|
||||
if (!_uniformToLocation.TryGetValue(uniform, out int location))
|
||||
if (location == -1)
|
||||
{
|
||||
location = GL.GetUniformLocation(_handle, uniform);
|
||||
_uniformToLocation.Add(uniform, location);
|
||||
if (location == -1)
|
||||
{
|
||||
Serilog.Log.Debug($"The uniform '{uniform}' does not exist in the shader!");
|
||||
}
|
||||
// throw new Exception($"{name} uniform not found on shader.");
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
public int GetAttribLocation(string attrib)
|
||||
{
|
||||
if (!_attribLocation.TryGetValue(attrib, out int location))
|
||||
{
|
||||
location = GL.GetAttribLocation(_handle, attrib);
|
||||
_attribLocation.Add(attrib, location);
|
||||
if (location == -1)
|
||||
{
|
||||
Serilog.Log.Debug($"The attrib '{attrib}' does not exist in the shader!");
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ public class SnimGui
|
|||
ImGui.DragFloat("Far Plane", ref s.Camera.Far, 0.1f, 5f, s.Camera.Far * 2f, "%.2f m", ImGuiSliderFlags.AlwaysClamp);
|
||||
ImGui.End();
|
||||
ImGui.Begin("World");
|
||||
ImGui.Checkbox("Diffuse Only", ref s.Renderer.bDiffuseOnly);
|
||||
ImGui.End();
|
||||
ImGui.Begin("Timeline");
|
||||
ImGui.End();
|
||||
|
|
@ -95,8 +96,6 @@ public class SnimGui
|
|||
const int width = 50;
|
||||
var material = model.Materials[section.MaterialIndex];
|
||||
ImGui.Checkbox("Show Section", ref section.Show);
|
||||
ImGui.SetNextItemWidth(width); ImGui.DragFloat("Roughness", ref material.Roughness, .01f, 0f, 1f);
|
||||
ImGui.SetNextItemWidth(width); ImGui.DragFloat("Specular Multiplier", ref material.SpecularMult, .01f, 0f);
|
||||
ImGui.SetNextItemWidth(width); ImGui.DragFloat("Emissive Multiplier", ref material.EmissiveMult, .01f, 0f);
|
||||
ImGui.SetNextItemWidth(width); ImGui.DragFloat("UV Scale", ref material.UVScale, .01f, 0f);
|
||||
if (material.HasM)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public class Texture : IDisposable
|
|||
Height = height;
|
||||
Bind(TextureUnit.Texture0);
|
||||
|
||||
GL.TexImage2D(_target, 0, PixelInternalFormat.Rgb, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, data);
|
||||
GL.TexImage2D(_target, 0, texture2D.SRGB ? PixelInternalFormat.Srgb : PixelInternalFormat.Rgb, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, data);
|
||||
GL.TexParameter(_target, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.LinearMipmapLinear);
|
||||
GL.TexParameter(_target, TextureParameterName.TextureMagFilter, (int) TextureMinFilter.Linear);
|
||||
GL.TexParameter(_target, TextureParameterName.TextureBaseLevel, 0);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user