205 lines
5.8 KiB
GLSL
205 lines
5.8 KiB
GLSL
#version 420
|
|
|
|
layout(binding = 0) uniform sampler2D diffuseTex;
|
|
|
|
out vec4 out_Color;
|
|
|
|
in vec4 ex_Pos;
|
|
in vec2 ex_Tex;
|
|
in vec3 ex_Normal;
|
|
|
|
layout (binding = 0) uniform ScreenVariables {
|
|
mat4 CameraView;
|
|
mat4 Projection;
|
|
vec4 CameraEye;
|
|
|
|
vec4 FogColor;
|
|
float FogNear;
|
|
float FogFar;
|
|
};
|
|
|
|
layout (binding = 1) uniform ObjectVariables {
|
|
mat4 Transform;
|
|
vec2 TexOffset;
|
|
vec2 TexScale;
|
|
vec4 Scale;
|
|
|
|
vec4 BaseColor;
|
|
vec4 Emission;
|
|
float SpecularMix;
|
|
float DiffuseMix;
|
|
float Metallic;
|
|
float DiffuseRoughness;
|
|
float SpecularPower;
|
|
float IncidentSpecular;
|
|
|
|
int ColorReplace;
|
|
int Lit;
|
|
};
|
|
|
|
struct Light {
|
|
vec4 Position;
|
|
vec4 Color;
|
|
vec4 Direction;
|
|
float Attenuation0;
|
|
float Attenuation1;
|
|
int FalloffEnabled;
|
|
int Active;
|
|
};
|
|
|
|
layout (binding = 3) uniform Lighting {
|
|
Light Lights[32];
|
|
vec4 AmbientLighting;
|
|
};
|
|
|
|
float pow5(float v) {
|
|
return (v * v) * (v * v) * v;
|
|
}
|
|
|
|
float f_diffuse(vec3 i, vec3 o, vec3 h, vec3 normal, float power, float roughness) {
|
|
float h_dot_i = dot(h, i);
|
|
float h_dot_i_2 = h_dot_i * h_dot_i;
|
|
float f_d90 = 0.5 + 2 * h_dot_i_2 * roughness;
|
|
|
|
float cos_theta_i = dot(i, normal);
|
|
float cos_theta_o = dot(o, normal);
|
|
|
|
float f_d = (1 + (f_d90 - 1) * pow5(1 - cos_theta_i)) * (1 + (f_d90 - 1) * pow5(1 - cos_theta_o));
|
|
return clamp(f_d * power * cos_theta_i, 0.0, 1.0);
|
|
}
|
|
|
|
float f_specular(vec3 i, vec3 o, vec3 h, vec3 normal, float F0, float power, float specularPower) {
|
|
vec3 reflected = -reflect(i, normal);
|
|
float intensity = dot(reflected, o);
|
|
|
|
if (intensity < 0) return 0;
|
|
|
|
// Fresnel approximation
|
|
float F0_scaled = 0.08 * F0;
|
|
float o_dot_h = dot(o, h);
|
|
float s = pow5(1 - o_dot_h);
|
|
float F = F0_scaled + s * (1 - F0_scaled);
|
|
|
|
return clamp(pow(intensity, specularPower) * F * power, 0.0, 1.0);
|
|
}
|
|
|
|
float f_specular_ambient(vec3 o, vec3 normal, float F0, float power) {
|
|
// Fresnel approximation
|
|
float F0_scaled = 0.08 * F0;
|
|
float o_dot_n = dot(o, normal);
|
|
float s = pow5(1 - o_dot_n);
|
|
float F = F0_scaled + s * (1 - F0_scaled);
|
|
|
|
return clamp(F * power, 0.0, 1.0);
|
|
}
|
|
|
|
float linearToSrgb(float u) {
|
|
const float MinSrgbPower = 0.0031308;
|
|
|
|
if (u < MinSrgbPower) {
|
|
return 12.92 * u;
|
|
}
|
|
else {
|
|
return 1.055 * pow(u, 1 / 2.4) - 0.055;
|
|
}
|
|
}
|
|
|
|
float srgbToLinear(float u) {
|
|
const float MinSrgbPower = 0.04045;
|
|
|
|
if (u < MinSrgbPower) {
|
|
return u / 12.92;
|
|
}
|
|
else {
|
|
return pow((u + 0.055) / 1.055, 2.4);
|
|
}
|
|
}
|
|
|
|
vec3 linearToSrgb(vec3 v) {
|
|
return vec3(linearToSrgb(v.r), linearToSrgb(v.g), linearToSrgb(v.b));
|
|
}
|
|
|
|
vec3 srgbToLinear(vec3 v) {
|
|
return vec3(srgbToLinear(v.r), srgbToLinear(v.g), srgbToLinear(v.b));
|
|
}
|
|
|
|
void main(void) {
|
|
const float FullSpecular = 1 / 0.08;
|
|
|
|
vec3 totalLighting = vec3(1.0, 1.0, 1.0);
|
|
vec3 normal = normalize(ex_Normal.xyz);
|
|
|
|
vec4 baseColor;
|
|
float roughness = 0.5;
|
|
float power = 1.0;
|
|
|
|
if (ColorReplace == 0) {
|
|
vec4 diffuse = texture(diffuseTex, ex_Tex).rgba;
|
|
baseColor = vec4(srgbToLinear(diffuse.rgb), diffuse.a) * BaseColor;
|
|
}
|
|
else {
|
|
baseColor = BaseColor;
|
|
}
|
|
|
|
totalLighting = baseColor.rgb;
|
|
|
|
if (Lit == 1) {
|
|
vec3 o = normalize(CameraEye.xyz - ex_Pos.xyz);
|
|
float cos_theta_o = dot(o, normal);
|
|
|
|
vec3 ambientSpecular = f_specular_ambient(o, normal, IncidentSpecular, SpecularMix) * AmbientLighting.rgb;
|
|
vec3 ambientDiffuse = f_diffuse(o, o, o, normal, DiffuseMix, DiffuseRoughness) * AmbientLighting.rgb * baseColor.rgb;
|
|
vec3 ambientMetallic = f_specular_ambient(o, normal, FullSpecular, 1.0) * AmbientLighting.rgb * baseColor.rgb;
|
|
|
|
totalLighting = mix(ambientSpecular + ambientDiffuse, ambientMetallic, Metallic);
|
|
totalLighting += Emission.rgb;
|
|
|
|
for (int li = 0; li < 32; ++li) {
|
|
if (Lights[li].Active == 0) continue;
|
|
|
|
vec3 i = Lights[li].Position.xyz - ex_Pos.xyz;
|
|
float inv_dist = 1.0 / length(i);
|
|
i *= inv_dist;
|
|
|
|
float cos_theta_i = dot(i, normal);
|
|
|
|
if (cos_theta_i < 0) continue;
|
|
if (cos_theta_o < 0) continue;
|
|
|
|
vec3 h = normalize(i + o);
|
|
vec3 diffuse = f_diffuse(i, o, h, normal, DiffuseMix, DiffuseRoughness) * baseColor.rgb * Lights[li].Color.rgb;
|
|
vec3 specular = f_specular(i, o, h, normal, IncidentSpecular, SpecularMix, SpecularPower) * Lights[li].Color.rgb;
|
|
vec3 metallic = vec3(0.0, 0.0, 0.0);
|
|
|
|
if (Metallic > 0) {
|
|
metallic = f_specular(i, o, h, normal, FullSpecular, 1, SpecularPower) * Lights[li].Color.rgb * baseColor.rgb;
|
|
}
|
|
|
|
// Spotlight calculation
|
|
float spotCoherence = -dot(i, Lights[li].Direction.xyz);
|
|
float spotAttenuation = 1.0;
|
|
if (spotCoherence > Lights[li].Attenuation0) spotAttenuation = 1.0;
|
|
else if (spotCoherence < Lights[li].Attenuation1) spotAttenuation = 0.0;
|
|
else {
|
|
float t = Lights[li].Attenuation0 - Lights[li].Attenuation1;
|
|
if (t == 0) spotAttenuation = 1.0;
|
|
else spotAttenuation = (spotCoherence - Lights[li].Attenuation1) / t;
|
|
}
|
|
|
|
float falloff = 1.0;
|
|
if (Lights[li].FalloffEnabled == 1) {
|
|
falloff = (inv_dist * inv_dist);
|
|
}
|
|
|
|
vec3 bsdf = mix(diffuse + specular, metallic, Metallic);
|
|
|
|
totalLighting += falloff * bsdf * spotAttenuation * spotAttenuation * spotAttenuation;
|
|
}
|
|
}
|
|
|
|
const float distanceToCamera = length(CameraEye.xyz - ex_Pos.xyz);
|
|
const float fogAttenuation = (clamp(distanceToCamera, FogNear, FogFar) - FogNear) / (FogFar - FogNear);
|
|
|
|
out_Color = vec4(linearToSrgb(mix(totalLighting.rgb, FogColor.rgb, fogAttenuation)), baseColor.a);
|
|
}
|