General clean up
This commit is contained in:
@@ -7,10 +7,10 @@ uniform samplerCube environmentMap;
|
||||
void main()
|
||||
{
|
||||
vec3 envColor = texture(environmentMap, WorldPos).rgb;
|
||||
|
||||
// HDR tonemap and gamma correct
|
||||
envColor = envColor / (envColor + vec3(1.0));
|
||||
envColor = pow(envColor, vec3(1.0/2.2));
|
||||
|
||||
FragColor = vec4(envColor, 1.0);
|
||||
|
||||
// HDR tonemap and gamma correct
|
||||
envColor = envColor / (envColor + vec3(1.0));
|
||||
envColor = pow(envColor, vec3(1.0/2.2));
|
||||
|
||||
FragColor = vec4(envColor, 1.0);
|
||||
}
|
||||
@@ -8,7 +8,7 @@ out vec3 WorldPos;
|
||||
|
||||
void main()
|
||||
{
|
||||
WorldPos = aPos;
|
||||
WorldPos = aPos;
|
||||
|
||||
mat4 rotView = mat4(mat3(view));
|
||||
vec4 clipPos = projection * rotView * vec4(WorldPos, 1.0);
|
||||
|
||||
@@ -3,24 +3,24 @@ out vec2 FragColor;
|
||||
in vec2 TexCoords;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
||||
// efficient VanDerCorpus calculation.
|
||||
float RadicalInverse_VdC(uint bits)
|
||||
{
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
vec2 Hammersley(uint i, uint N)
|
||||
{
|
||||
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
|
||||
{
|
||||
float a = roughness*roughness;
|
||||
@@ -36,78 +36,78 @@ vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
|
||||
H.z = cosTheta;
|
||||
|
||||
// from tangent-space H vector to world-space sample vector
|
||||
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
||||
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
||||
vec3 tangent = normalize(cross(up, N));
|
||||
vec3 bitangent = cross(N, tangent);
|
||||
|
||||
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
|
||||
return normalize(sampleVec);
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
// note that we use a different k for IBL
|
||||
float a = roughness;
|
||||
float k = (a * a) / 2.0;
|
||||
// note that we use a different k for IBL
|
||||
float a = roughness;
|
||||
float k = (a * a) / 2.0;
|
||||
|
||||
float nom = NdotV;
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
float nom = NdotV;
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
|
||||
return nom / denom;
|
||||
return nom / denom;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||
{
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
|
||||
return ggx1 * ggx2;
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
vec2 IntegrateBRDF(float NdotV, float roughness)
|
||||
{
|
||||
vec3 V;
|
||||
V.x = sqrt(1.0 - NdotV*NdotV);
|
||||
V.y = 0.0;
|
||||
V.z = NdotV;
|
||||
vec3 V;
|
||||
V.x = sqrt(1.0 - NdotV*NdotV);
|
||||
V.y = 0.0;
|
||||
V.z = NdotV;
|
||||
|
||||
float A = 0.0;
|
||||
float B = 0.0;
|
||||
float A = 0.0;
|
||||
float B = 0.0;
|
||||
|
||||
vec3 N = vec3(0.0, 0.0, 1.0);
|
||||
|
||||
const uint SAMPLE_COUNT = 1024u;
|
||||
for(uint i = 0u; i < SAMPLE_COUNT; ++i)
|
||||
{
|
||||
// generates a sample vector that's biased towards the
|
||||
// preferred alignment direction (importance sampling).
|
||||
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
|
||||
vec3 L = normalize(2.0 * dot(V, H) * H - V);
|
||||
vec3 N = vec3(0.0, 0.0, 1.0);
|
||||
|
||||
float NdotL = max(L.z, 0.0);
|
||||
float NdotH = max(H.z, 0.0);
|
||||
float VdotH = max(dot(V, H), 0.0);
|
||||
const uint SAMPLE_COUNT = 1024u;
|
||||
for(uint i = 0u; i < SAMPLE_COUNT; ++i) {
|
||||
|
||||
if(NdotL > 0.0)
|
||||
{
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
float G_Vis = (G * VdotH) / (NdotH * NdotV);
|
||||
float Fc = pow(1.0 - VdotH, 5.0);
|
||||
// generates a sample vector that's biased towards the
|
||||
// preferred alignment direction (importance sampling).
|
||||
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
|
||||
vec3 L = normalize(2.0 * dot(V, H) * H - V);
|
||||
|
||||
A += (1.0 - Fc) * G_Vis;
|
||||
B += Fc * G_Vis;
|
||||
}
|
||||
}
|
||||
A /= float(SAMPLE_COUNT);
|
||||
B /= float(SAMPLE_COUNT);
|
||||
return vec2(A, B);
|
||||
float NdotL = max(L.z, 0.0);
|
||||
float NdotH = max(H.z, 0.0);
|
||||
float VdotH = max(dot(V, H), 0.0);
|
||||
|
||||
if(NdotL > 0.0) {
|
||||
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
float G_Vis = (G * VdotH) / (NdotH * NdotV);
|
||||
float Fc = pow(1.0 - VdotH, 5.0);
|
||||
|
||||
A += (1.0 - Fc) * G_Vis;
|
||||
B += Fc * G_Vis;
|
||||
}
|
||||
}
|
||||
A /= float(SAMPLE_COUNT);
|
||||
B /= float(SAMPLE_COUNT);
|
||||
return vec2(A, B);
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y);
|
||||
FragColor = integratedBRDF;
|
||||
vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y);
|
||||
FragColor = integratedBRDF;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#version 330 core
|
||||
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec2 aTexCoords;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#version 330 core
|
||||
|
||||
layout (location = 0) in vec3 aPos;
|
||||
|
||||
out vec3 WorldPos;
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
#version 330 core
|
||||
|
||||
out vec4 FragColor;
|
||||
in vec3 WorldPos;
|
||||
in vec3 WorldPos;
|
||||
|
||||
uniform sampler2D equirectangularMap;
|
||||
|
||||
const vec2 invAtan = vec2(0.1591, 0.3183);
|
||||
|
||||
vec2 SampleSphericalMap(vec3 v)
|
||||
{
|
||||
vec2 uv = vec2(atan(v.z, v.x), asin(v.y));
|
||||
uv *= invAtan;
|
||||
uv += 0.5;
|
||||
return uv;
|
||||
vec2 uv = vec2(atan(v.z, v.x), asin(v.y));
|
||||
uv *= invAtan;
|
||||
uv += 0.5;
|
||||
return uv;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 uv = SampleSphericalMap(normalize(WorldPos));
|
||||
vec3 color = texture(equirectangularMap, uv).rgb;
|
||||
{
|
||||
vec2 uv = SampleSphericalMap(normalize(WorldPos));
|
||||
vec3 color = texture(equirectangularMap, uv).rgb;
|
||||
|
||||
// reinhard tone mapping
|
||||
vec3 mapped = color / (color + vec3(1.0));
|
||||
vec3 mapped = color / (color + vec3(1.0));
|
||||
|
||||
// gamma correction
|
||||
// gamma correction
|
||||
//float gamma = 2.2;
|
||||
//mapped = pow(mapped, vec3(1.0 / gamma));
|
||||
|
||||
//mapped = pow(mapped, vec3(1.0 / gamma));
|
||||
|
||||
color = mapped;
|
||||
|
||||
FragColor = vec4(color, 1.0);
|
||||
FragColor = vec4(color, 1.0);
|
||||
}
|
||||
@@ -29,66 +29,66 @@ uniform sampler2D brdfLUT;
|
||||
float shadow_factor(vec4 frag_pos_light_space);
|
||||
|
||||
float distribGGX(float NoH, float a) {
|
||||
float a2 = a * a;
|
||||
float f = (NoH * a2 - NoH) * NoH + 1.0;
|
||||
return a2 / (PI * f * f);
|
||||
float a2 = a * a;
|
||||
float f = (NoH * a2 - NoH) * NoH + 1.0;
|
||||
return a2 / (PI * f * f);
|
||||
}
|
||||
|
||||
vec3 fresnelSchlick(float u, vec3 f0) {
|
||||
return f0 + (vec3(1.0) - f0) * pow(1.0 - u, 5.0);
|
||||
return f0 + (vec3(1.0) - f0) * pow(1.0 - u, 5.0);
|
||||
}
|
||||
|
||||
vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
|
||||
{
|
||||
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
||||
}
|
||||
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
||||
}
|
||||
|
||||
float geometrySmith(float NoV, float NoL, float a) {
|
||||
float a2 = a * a;
|
||||
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
|
||||
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
|
||||
return 0.5 / (GGXV + GGXL);
|
||||
float a2 = a * a;
|
||||
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
|
||||
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
|
||||
return 0.5 / (GGXV + GGXL);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 l = normalize(lightDir);
|
||||
vec3 v = normalize(viewPos - fragPos);
|
||||
vec3 n = frag_normal;
|
||||
vec3 h = normalize(v + l);
|
||||
vec3 l = normalize(lightDir);
|
||||
vec3 v = normalize(viewPos - fragPos);
|
||||
vec3 n = frag_normal;
|
||||
vec3 h = normalize(v + l);
|
||||
|
||||
float light_intensity = 1;
|
||||
float light_intensity = 1;
|
||||
|
||||
float perceptualRoughness2 = max(perceptualRoughness, 0.089);
|
||||
float roughness = perceptualRoughness2 * perceptualRoughness2;
|
||||
float perceptualRoughness2 = max(perceptualRoughness, 0.089);
|
||||
float roughness = perceptualRoughness2 * perceptualRoughness2;
|
||||
|
||||
vec3 f0 = 0.16 * reflectance * reflectance * (1.0 - metallic) + baseColor * metallic;
|
||||
vec3 f0 = 0.16 * reflectance * reflectance * (1.0 - metallic) + baseColor * metallic;
|
||||
|
||||
float NoV = abs(dot(n, v)) + 1e-5;
|
||||
float NoL = clamp(dot(n, l), 0.0, 1.0);
|
||||
float NoH = clamp(dot(n, h), 0.0, 1.0);
|
||||
float LoH = clamp(dot(l, h), 0.0, 1.0);
|
||||
float NoV = abs(dot(n, v)) + 1e-5;
|
||||
float NoL = clamp(dot(n, l), 0.0, 1.0);
|
||||
float NoH = clamp(dot(n, h), 0.0, 1.0);
|
||||
float LoH = clamp(dot(l, h), 0.0, 1.0);
|
||||
|
||||
vec3 color = vec3(0);
|
||||
vec3 color = vec3(0);
|
||||
|
||||
float shadow = shadow_factor(frag_pos_light_space);
|
||||
|
||||
// Direct lighting
|
||||
{
|
||||
float D = distribGGX(NoH, roughness);
|
||||
vec3 F = fresnelSchlick(LoH, f0);
|
||||
float V = geometrySmith(NoV, NoL, roughness);
|
||||
// Direct lighting
|
||||
{
|
||||
float D = distribGGX(NoH, roughness);
|
||||
vec3 F = fresnelSchlick(LoH, f0);
|
||||
float V = geometrySmith(NoV, NoL, roughness);
|
||||
|
||||
vec3 specular = (F * D * V) / (4.0 * NoV * NoL + 0.0001);
|
||||
vec3 specular = (F * D * V) / (4.0 * NoV * NoL + 0.0001);
|
||||
|
||||
vec3 diffuse = (1 - F) * (1 - metallic) * baseColor / PI;
|
||||
vec3 diffuse = (1 - F) * (1 - metallic) * baseColor / PI;
|
||||
|
||||
color = (1 - shadow) * (diffuse + specular) * lightColor * light_intensity * NoL;
|
||||
}
|
||||
color = (1 - shadow) * (diffuse + specular) * lightColor * light_intensity * NoL;
|
||||
}
|
||||
|
||||
// Ambient lighting with IBL
|
||||
// Ambient lighting with IBL
|
||||
vec3 ambient;
|
||||
{
|
||||
{
|
||||
vec3 F = fresnelSchlickRoughness(NoV, f0, roughness);
|
||||
|
||||
vec3 irradiance = texture(irradianceMap, n).rgb;
|
||||
@@ -105,32 +105,33 @@ void main()
|
||||
|
||||
float ao = 1;
|
||||
ambient = ((1 - F) * (1 - metallic) * diffuse + specular) * ao;
|
||||
}
|
||||
}
|
||||
|
||||
color = color + ambient;
|
||||
|
||||
color = color / (color + vec3(1.0)); // HDR tonemapping
|
||||
color = pow(color, vec3(1.0/2.2)); // gamma correct
|
||||
color = color / (color + vec3(1.0)); // HDR tonemapping
|
||||
color = pow(color, vec3(1.0/2.2)); // gamma correct
|
||||
|
||||
FragColor = vec4(color, 1.0);
|
||||
FragColor = vec4(color, 1.0);
|
||||
}
|
||||
|
||||
float shadow_factor(vec4 frag_pos_light_space)
|
||||
{
|
||||
vec3 proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w;
|
||||
proj_coords = proj_coords * 0.5 + 0.5;
|
||||
vec3 proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w;
|
||||
proj_coords = proj_coords * 0.5 + 0.5;
|
||||
|
||||
float closest_depth = texture(shadow_map, proj_coords.xy).r;
|
||||
float current_depth = proj_coords.z;
|
||||
float closest_depth = texture(shadow_map, proj_coords.xy).r;
|
||||
float current_depth = proj_coords.z;
|
||||
|
||||
float bias = 0.005;
|
||||
float shadow = 0;
|
||||
vec2 delta = 1.0 / textureSize(shadow_map, 0);
|
||||
for (int i = -1; i < 2; i++)
|
||||
for (int j = -1; j < 2; j++) {
|
||||
float closest_depth = texture(shadow_map, proj_coords.xy + vec2(i, j) * delta).r;
|
||||
shadow += (current_depth - bias > closest_depth) ? 1.0 : 0.0;
|
||||
}
|
||||
shadow /= 9;
|
||||
return shadow;
|
||||
float bias = 0.005;
|
||||
float shadow = 0;
|
||||
vec2 delta = 1.0 / textureSize(shadow_map, 0);
|
||||
for (int i = -1; i < 2; i++)
|
||||
for (int j = -1; j < 2; j++) {
|
||||
float closest_depth = texture(shadow_map, proj_coords.xy + vec2(i, j) * delta).r;
|
||||
shadow += (current_depth - bias > closest_depth) ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
shadow /= 9;
|
||||
return shadow;
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
#version 330 core
|
||||
|
||||
struct Light {
|
||||
vec3 direction;
|
||||
vec3 ambient;
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
};
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
in vec3 frag_normal;
|
||||
in vec3 fragPos;
|
||||
in vec4 frag_pos_light_space;
|
||||
|
||||
uniform sampler2D shadow_map;
|
||||
uniform vec3 viewPos;
|
||||
|
||||
uniform float perceptualRoughness; // [0, 1]
|
||||
uniform float metallic; // [0, 1]
|
||||
uniform float reflectance; // [0, 1]
|
||||
uniform vec3 baseColor;
|
||||
|
||||
uniform Light light;
|
||||
|
||||
float shadow_factor(vec4 frag_pos_light_space)
|
||||
{
|
||||
vec3 proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w;
|
||||
proj_coords = proj_coords * 0.5 + 0.5;
|
||||
|
||||
float closest_depth = texture(shadow_map, proj_coords.xy).r;
|
||||
float current_depth = proj_coords.z;
|
||||
|
||||
float bias = 0.005;
|
||||
float shadow = 0;
|
||||
vec2 delta = 1.0 / textureSize(shadow_map, 0);
|
||||
for (int i = -1; i < 2; i++)
|
||||
for (int j = -1; j < 2; j++) {
|
||||
float closest_depth = texture(shadow_map, proj_coords.xy + vec2(i, j) * delta).r;
|
||||
shadow += (current_depth - bias > closest_depth) ? 1.0 : 0.0;
|
||||
}
|
||||
shadow /= 9;
|
||||
return shadow;
|
||||
}
|
||||
|
||||
float D_GGX(float NoH, float a) {
|
||||
float a2 = a * a;
|
||||
float f = (NoH * a2 - NoH) * NoH + 1.0;
|
||||
return a2 / (PI * f * f);
|
||||
}
|
||||
|
||||
vec3 F_Schlick(float u, vec3 f0) {
|
||||
return f0 + (vec3(1.0) - f0) * pow(1.0 - u, 5.0);
|
||||
}
|
||||
|
||||
float V_SmithGGXCorrelated(float NoV, float NoL, float a) {
|
||||
float a2 = a * a;
|
||||
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
|
||||
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
|
||||
return 0.5 / (GGXV + GGXL);
|
||||
}
|
||||
|
||||
float Fd_Lambert() {
|
||||
return 1.0 / PI;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// NOTE: frag_normal is normalized by the vertex shader
|
||||
/*
|
||||
vec3 l = normalize(light.direction);
|
||||
vec3 v = viewDir;
|
||||
vec3 n = frag_normal;
|
||||
vec3 h = normalize(v + l);
|
||||
vec3 diffuseColor = (1.0 - metallic) * baseColor.rgb;
|
||||
vec3 f0 = 0.16 * reflectance * reflectance * (1.0 - metallic) + baseColor * metallic;
|
||||
|
||||
float NoV = abs(dot(n, v)) + 1e-5;
|
||||
float NoL = clamp(dot(n, l), 0.0, 1.0);
|
||||
float NoH = clamp(dot(n, h), 0.0, 1.0);
|
||||
float LoH = clamp(dot(l, h), 0.0, 1.0);
|
||||
|
||||
float roughness = perceptualRoughness * perceptualRoughness;
|
||||
|
||||
float D = D_GGX(NoH, roughness);
|
||||
vec3 F = F_Schlick(LoH, f0);
|
||||
float V = V_SmithGGXCorrelated(NoV, NoL, roughness);
|
||||
|
||||
// specular BRDF
|
||||
vec3 Fr = (D * V) * F;
|
||||
|
||||
//vec3 energyCompensation = 1.0 + f0 * (1.0 / dfg.y - 1.0);
|
||||
//// Scale the specular lobe to account for multiscattering
|
||||
//Fr *= pixel.energyCompensation;
|
||||
|
||||
// diffuse BRDF
|
||||
vec3 Fd = diffuseColor * Fd_Lambert();
|
||||
|
||||
// apply lighting...
|
||||
|
||||
float shadow = shadow_factor(frag_pos_light_space);
|
||||
*/
|
||||
vec3 result = vec3(1, 0, 0); // Fd + Fr * (1 - shadow);
|
||||
FragColor = vec4(result, 1.0);
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
#version 330 core
|
||||
|
||||
// https://github.com/Nadrin/PBR/blob/master/data/shaders/glsl/pbr_fs.glsl
|
||||
|
||||
#define PI 3.1415926538
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
in vec3 frag_normal;
|
||||
in vec3 fragPos;
|
||||
in vec4 frag_pos_light_space;
|
||||
|
||||
uniform sampler2D shadow_map;
|
||||
uniform vec3 viewPos;
|
||||
|
||||
uniform float perceptualRoughness; // [0, 1]
|
||||
uniform float metallic; // [0, 1]
|
||||
uniform float reflectance; // [0, 1]
|
||||
uniform vec3 baseColor;
|
||||
|
||||
uniform vec3 lightDir;
|
||||
uniform vec3 lightColor;
|
||||
|
||||
float shadow_factor(vec4 frag_pos_light_space);
|
||||
|
||||
float D_GGX(float NoH, float a) {
|
||||
float a2 = a * a;
|
||||
float f = (NoH * a2 - NoH) * NoH + 1.0;
|
||||
return a2 / (PI * f * f);
|
||||
}
|
||||
|
||||
vec3 F_Schlick(float u, vec3 f0) {
|
||||
return f0 + (vec3(1.0) - f0) * pow(1.0 - u, 5.0);
|
||||
}
|
||||
|
||||
float V_SmithGGXCorrelated(float NoV, float NoL, float a) {
|
||||
float a2 = a * a;
|
||||
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
|
||||
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
|
||||
return 0.5 / (GGXV + GGXL);
|
||||
}
|
||||
|
||||
float Fd_Lambert()
|
||||
{
|
||||
return 1.0 / PI;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 l = normalize(lightDir);
|
||||
vec3 v = normalize(viewPos - fragPos);
|
||||
vec3 n = frag_normal;
|
||||
vec3 h = normalize(v + l);
|
||||
|
||||
float light_intensity = 1;
|
||||
|
||||
vec3 albedo = baseColor;
|
||||
vec3 diffuseColor = (1.0 - metallic) * baseColor;
|
||||
|
||||
vec3 f0 = 0.16 * reflectance * reflectance * (1.0 - metallic)
|
||||
+ baseColor * metallic;
|
||||
|
||||
float NoV = abs(dot(n, v)) + 1e-5;
|
||||
float NoL = clamp(dot(n, l), 0.0, 1.0);
|
||||
float NoH = clamp(dot(n, h), 0.0, 1.0);
|
||||
float LoH = clamp(dot(l, h), 0.0, 1.0);
|
||||
|
||||
float roughness = perceptualRoughness * perceptualRoughness;
|
||||
|
||||
float D = D_GGX(NoH, roughness);
|
||||
vec3 F = F_Schlick(LoH, f0);
|
||||
float V = V_SmithGGXCorrelated(NoV, NoL, roughness);
|
||||
|
||||
// specular BRDF
|
||||
float denominator = 4.0 * max(dot(n, v), 0.0) * max(dot(n, l), 0.0) + 0.0001; // + 0.0001 to prevent divide by zero
|
||||
vec3 Fr = (D * V) * F / denominator;
|
||||
|
||||
vec3 radiance = lightColor;
|
||||
vec3 light = ((vec3(1.0) - F) * (1.0 - metallic) * albedo / PI + Fr) * radiance * NoL;
|
||||
|
||||
float shadow = shadow_factor(frag_pos_light_space);
|
||||
|
||||
vec3 ambient = vec3(0.03) * albedo;
|
||||
vec3 color = (ambient + light) * (1 - shadow);
|
||||
|
||||
/*
|
||||
// HDR tonemapping
|
||||
color = color / (color + vec3(1.0));
|
||||
// gamma correct
|
||||
color = pow(color, vec3(1.0/2.2));
|
||||
*/
|
||||
FragColor = vec4(color, 1.0);
|
||||
}
|
||||
|
||||
float shadow_factor(vec4 frag_pos_light_space)
|
||||
{
|
||||
vec3 proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w;
|
||||
proj_coords = proj_coords * 0.5 + 0.5;
|
||||
|
||||
float closest_depth = texture(shadow_map, proj_coords.xy).r;
|
||||
float current_depth = proj_coords.z;
|
||||
|
||||
float bias = 0.005;
|
||||
float shadow = 0;
|
||||
vec2 delta = 1.0 / textureSize(shadow_map, 0);
|
||||
for (int i = -1; i < 2; i++)
|
||||
for (int j = -1; j < 2; j++) {
|
||||
float closest_depth = texture(shadow_map, proj_coords.xy + vec2(i, j) * delta).r;
|
||||
shadow += (current_depth - bias > closest_depth) ? 1.0 : 0.0;
|
||||
}
|
||||
shadow /= 9;
|
||||
return shadow;
|
||||
}
|
||||
@@ -7,37 +7,37 @@ uniform samplerCube environmentMap;
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
void main()
|
||||
{
|
||||
{
|
||||
// The world vector acts as the normal of a tangent surface
|
||||
// from the origin, aligned to WorldPos. Given this normal, calculate all
|
||||
// incoming radiance of the environment. The result of this radiance
|
||||
// is the radiance of light coming from -Normal direction, which is what
|
||||
// we use in the PBR shader to sample irradiance.
|
||||
vec3 N = normalize(WorldPos);
|
||||
// from the origin, aligned to WorldPos. Given this normal, calculate all
|
||||
// incoming radiance of the environment. The result of this radiance
|
||||
// is the radiance of light coming from -Normal direction, which is what
|
||||
// we use in the PBR shader to sample irradiance.
|
||||
vec3 N = normalize(WorldPos);
|
||||
|
||||
vec3 irradiance = vec3(0.0);
|
||||
|
||||
// tangent space calculation from origin point
|
||||
vec3 up = vec3(0.0, 1.0, 0.0);
|
||||
vec3 right = normalize(cross(up, N));
|
||||
up = normalize(cross(N, right));
|
||||
|
||||
float sampleDelta = 0.025;
|
||||
float nrSamples = 0.0;
|
||||
for(float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta)
|
||||
{
|
||||
for(float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta)
|
||||
{
|
||||
// spherical to cartesian (in tangent space)
|
||||
vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
|
||||
// tangent space to world
|
||||
vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N;
|
||||
vec3 irradiance = vec3(0.0);
|
||||
|
||||
irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta);
|
||||
nrSamples++;
|
||||
}
|
||||
}
|
||||
irradiance = PI * irradiance * (1.0 / float(nrSamples));
|
||||
|
||||
FragColor = vec4(irradiance, 1.0);
|
||||
// tangent space calculation from origin point
|
||||
vec3 up = vec3(0.0, 1.0, 0.0);
|
||||
vec3 right = normalize(cross(up, N));
|
||||
up = normalize(cross(N, right));
|
||||
|
||||
float sampleDelta = 0.025;
|
||||
float nrSamples = 0.0;
|
||||
for(float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta)
|
||||
{
|
||||
for(float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta)
|
||||
{
|
||||
// spherical to cartesian (in tangent space)
|
||||
vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
|
||||
// tangent space to world
|
||||
vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N;
|
||||
|
||||
irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta);
|
||||
nrSamples++;
|
||||
}
|
||||
}
|
||||
irradiance = PI * irradiance * (1.0 / float(nrSamples));
|
||||
|
||||
FragColor = vec4(irradiance, 1.0);
|
||||
}
|
||||
@@ -6,101 +6,101 @@ uniform samplerCube environmentMap;
|
||||
uniform float roughness;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
float a = roughness*roughness;
|
||||
float a2 = a*a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH*NdotH;
|
||||
float a = roughness*roughness;
|
||||
float a2 = a*a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH*NdotH;
|
||||
|
||||
float nom = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
float nom = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
|
||||
return nom / denom;
|
||||
return nom / denom;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
||||
// efficient VanDerCorpus calculation.
|
||||
float RadicalInverse_VdC(uint bits)
|
||||
{
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
vec2 Hammersley(uint i, uint N)
|
||||
{
|
||||
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
|
||||
{
|
||||
float a = roughness*roughness;
|
||||
|
||||
|
||||
float phi = 2.0 * PI * Xi.x;
|
||||
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
|
||||
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
|
||||
|
||||
|
||||
// from spherical coordinates to cartesian coordinates - halfway vector
|
||||
vec3 H;
|
||||
H.x = cos(phi) * sinTheta;
|
||||
H.y = sin(phi) * sinTheta;
|
||||
H.z = cosTheta;
|
||||
|
||||
|
||||
// from tangent-space H vector to world-space sample vector
|
||||
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
||||
vec3 tangent = normalize(cross(up, N));
|
||||
vec3 bitangent = cross(N, tangent);
|
||||
|
||||
|
||||
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
|
||||
return normalize(sampleVec);
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 N = normalize(WorldPos);
|
||||
|
||||
// make the simplifying assumption that V equals R equals the normal
|
||||
vec3 R = N;
|
||||
vec3 V = R;
|
||||
{
|
||||
vec3 N = normalize(WorldPos);
|
||||
|
||||
const uint SAMPLE_COUNT = 1024u;
|
||||
vec3 prefilteredColor = vec3(0.0);
|
||||
float totalWeight = 0.0;
|
||||
|
||||
for(uint i = 0u; i < SAMPLE_COUNT; ++i)
|
||||
{
|
||||
// generates a sample vector that's biased towards the preferred alignment direction (importance sampling).
|
||||
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
|
||||
vec3 L = normalize(2.0 * dot(V, H) * H - V);
|
||||
// make the simplifying assumption that V equals R equals the normal
|
||||
vec3 R = N;
|
||||
vec3 V = R;
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
if(NdotL > 0.0)
|
||||
{
|
||||
// sample from the environment's mip level based on roughness/pdf
|
||||
float D = DistributionGGX(N, H, roughness);
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float HdotV = max(dot(H, V), 0.0);
|
||||
float pdf = D * NdotH / (4.0 * HdotV) + 0.0001;
|
||||
const uint SAMPLE_COUNT = 1024u;
|
||||
vec3 prefilteredColor = vec3(0.0);
|
||||
float totalWeight = 0.0;
|
||||
|
||||
float resolution = 512.0; // resolution of source cubemap (per face)
|
||||
float saTexel = 4.0 * PI / (6.0 * resolution * resolution);
|
||||
float saSample = 1.0 / (float(SAMPLE_COUNT) * pdf + 0.0001);
|
||||
for(uint i = 0u; i < SAMPLE_COUNT; ++i)
|
||||
{
|
||||
// generates a sample vector that's biased towards the preferred alignment direction (importance sampling).
|
||||
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
|
||||
vec3 L = normalize(2.0 * dot(V, H) * H - V);
|
||||
|
||||
float mipLevel = roughness == 0.0 ? 0.0 : 0.5 * log2(saSample / saTexel);
|
||||
|
||||
prefilteredColor += textureLod(environmentMap, L, mipLevel).rgb * NdotL;
|
||||
totalWeight += NdotL;
|
||||
}
|
||||
}
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
if(NdotL > 0.0)
|
||||
{
|
||||
// sample from the environment's mip level based on roughness/pdf
|
||||
float D = DistributionGGX(N, H, roughness);
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float HdotV = max(dot(H, V), 0.0);
|
||||
float pdf = D * NdotH / (4.0 * HdotV) + 0.0001;
|
||||
|
||||
prefilteredColor = prefilteredColor / totalWeight;
|
||||
float resolution = 512.0; // resolution of source cubemap (per face)
|
||||
float saTexel = 4.0 * PI / (6.0 * resolution * resolution);
|
||||
float saSample = 1.0 / (float(SAMPLE_COUNT) * pdf + 0.0001);
|
||||
|
||||
FragColor = vec4(prefilteredColor, 1.0);
|
||||
float mipLevel = roughness == 0.0 ? 0.0 : 0.5 * log2(saSample / saTexel);
|
||||
|
||||
prefilteredColor += textureLod(environmentMap, L, mipLevel).rgb * NdotL;
|
||||
totalWeight += NdotL;
|
||||
}
|
||||
}
|
||||
|
||||
prefilteredColor = prefilteredColor / totalWeight;
|
||||
|
||||
FragColor = vec4(prefilteredColor, 1.0);
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
#version 330 core
|
||||
|
||||
out vec4 FragColor;
|
||||
in vec2 TexCoords;
|
||||
in vec2 TexCoords;
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 color = texture(tex, TexCoords).rgb;
|
||||
FragColor = vec4(color, 1.0);
|
||||
FragColor = vec4(color, 1.0);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
void main()
|
||||
{
|
||||
// This is implicit:
|
||||
// gl_FragDepth = gl_FragCoord.z;
|
||||
// This is implicit:
|
||||
// gl_FragDepth = gl_FragCoord.z;
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@ uniform mat4 model;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = light_space_matrix * model * vec4(aPos, 1.0);
|
||||
gl_Position = light_space_matrix * model * vec4(aPos, 1.0);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#version 330 core
|
||||
|
||||
layout (location=0) in vec3 aPos;
|
||||
layout (location=1) in vec3 aNormal;
|
||||
layout (location=2) in vec2 aTexCoords;
|
||||
@@ -17,8 +18,8 @@ out vec4 frag_pos_light_space;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
||||
fragPos = vec3(model * vec4(aPos, 1.0));
|
||||
frag_normal = normalize(mat3(norm) * aNormal);
|
||||
frag_pos_light_space = light_space_matrix * model * vec4(aPos, 1);
|
||||
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
||||
fragPos = vec3(model * vec4(aPos, 1.0));
|
||||
frag_normal = normalize(mat3(norm) * aNormal);
|
||||
frag_pos_light_space = light_space_matrix * model * vec4(aPos, 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user