hyporo-cpp/source/hpr/gpu/shaders/base.frag.glsl

205 lines
5.8 KiB
Plaintext
Raw Normal View History

2022-11-18 21:50:49 +05:00
#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);
}