Spaces:
Runtime error
Runtime error
#version 330 core | |
/////////////////////////////////////////////////////////////////////////////// | |
// Structs | |
/////////////////////////////////////////////////////////////////////////////// | |
struct SpotLight { | |
vec3 color; | |
float intensity; | |
float range; | |
vec3 position; | |
vec3 direction; | |
float light_angle_scale; | |
float light_angle_offset; | |
#ifdef SPOT_LIGHT_SHADOWS | |
sampler2D shadow_map; | |
mat4 light_matrix; | |
#endif | |
}; | |
struct DirectionalLight { | |
vec3 color; | |
float intensity; | |
vec3 direction; | |
#ifdef DIRECTIONAL_LIGHT_SHADOWS | |
sampler2D shadow_map; | |
mat4 light_matrix; | |
#endif | |
}; | |
struct PointLight { | |
vec3 color; | |
float intensity; | |
float range; | |
vec3 position; | |
#ifdef POINT_LIGHT_SHADOWS | |
samplerCube shadow_map; | |
#endif | |
}; | |
struct Material { | |
vec3 emissive_factor; | |
#ifdef USE_METALLIC_MATERIAL | |
vec4 base_color_factor; | |
float metallic_factor; | |
float roughness_factor; | |
#endif | |
#ifdef USE_GLOSSY_MATERIAL | |
vec4 diffuse_factor; | |
vec3 specular_factor; | |
float glossiness_factor; | |
#endif | |
#ifdef HAS_NORMAL_TEX | |
sampler2D normal_texture; | |
#endif | |
#ifdef HAS_OCCLUSION_TEX | |
sampler2D occlusion_texture; | |
#endif | |
#ifdef HAS_EMISSIVE_TEX | |
sampler2D emissive_texture; | |
#endif | |
#ifdef HAS_BASE_COLOR_TEX | |
sampler2D base_color_texture; | |
#endif | |
#ifdef HAS_METALLIC_ROUGHNESS_TEX | |
sampler2D metallic_roughness_texture; | |
#endif | |
#ifdef HAS_DIFFUSE_TEX | |
sampler2D diffuse_texture; | |
#endif | |
#ifdef HAS_SPECULAR_GLOSSINESS_TEX | |
sampler2D specular_glossiness; | |
#endif | |
}; | |
struct PBRInfo { | |
float nl; | |
float nv; | |
float nh; | |
float lh; | |
float vh; | |
float roughness; | |
float metallic; | |
vec3 f0; | |
vec3 c_diff; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// Uniforms | |
/////////////////////////////////////////////////////////////////////////////// | |
uniform Material material; | |
uniform PointLight point_lights[MAX_POINT_LIGHTS]; | |
uniform int n_point_lights; | |
uniform DirectionalLight directional_lights[MAX_DIRECTIONAL_LIGHTS]; | |
uniform int n_directional_lights; | |
uniform SpotLight spot_lights[MAX_SPOT_LIGHTS]; | |
uniform int n_spot_lights; | |
uniform vec3 cam_pos; | |
uniform vec3 ambient_light; | |
#ifdef USE_IBL | |
uniform samplerCube diffuse_env; | |
uniform samplerCube specular_env; | |
#endif | |
/////////////////////////////////////////////////////////////////////////////// | |
// Inputs | |
/////////////////////////////////////////////////////////////////////////////// | |
in vec3 frag_position; | |
#ifdef NORMAL_LOC | |
in vec3 frag_normal; | |
#endif | |
#ifdef HAS_NORMAL_TEX | |
#ifdef TANGENT_LOC | |
#ifdef NORMAL_LOC | |
in mat3 tbn; | |
#endif | |
#endif | |
#endif | |
#ifdef TEXCOORD_0_LOC | |
in vec2 uv_0; | |
#endif | |
#ifdef TEXCOORD_1_LOC | |
in vec2 uv_1; | |
#endif | |
#ifdef COLOR_0_LOC | |
in vec4 color_multiplier; | |
#endif | |
/////////////////////////////////////////////////////////////////////////////// | |
// OUTPUTS | |
/////////////////////////////////////////////////////////////////////////////// | |
out vec4 frag_color; | |
/////////////////////////////////////////////////////////////////////////////// | |
// Constants | |
/////////////////////////////////////////////////////////////////////////////// | |
const float PI = 3.141592653589793; | |
const float min_roughness = 0.04; | |
/////////////////////////////////////////////////////////////////////////////// | |
// Utility Functions | |
/////////////////////////////////////////////////////////////////////////////// | |
vec4 srgb_to_linear(vec4 srgb) | |
{ | |
#ifndef SRGB_CORRECTED | |
// Fast Approximation | |
//vec3 linOut = pow(srgbIn.xyz,vec3(2.2)); | |
// | |
vec3 b_less = step(vec3(0.04045),srgb.xyz); | |
vec3 lin_out = mix( srgb.xyz/vec3(12.92), pow((srgb.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), b_less ); | |
return vec4(lin_out, srgb.w); | |
#else | |
return srgb; | |
#endif | |
} | |
// Normal computation | |
vec3 get_normal() | |
{ | |
#ifdef HAS_NORMAL_TEX | |
#ifndef HAS_TANGENTS | |
vec3 pos_dx = dFdx(frag_position); | |
vec3 pos_dy = dFdy(frag_position); | |
vec3 tex_dx = dFdx(vec3(uv_0, 0.0)); | |
vec3 tex_dy = dFdy(vec3(uv_0, 0.0)); | |
vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t); | |
#ifdef NORMAL_LOC | |
vec3 ng = normalize(frag_normal); | |
#else | |
vec3 = cross(pos_dx, pos_dy); | |
#endif | |
t = normalize(t - ng * dot(ng, t)); | |
vec3 b = normalize(cross(ng, t)); | |
mat3 tbn_n = mat3(t, b, ng); | |
#else | |
mat3 tbn_n = tbn; | |
#endif | |
vec3 n = texture(material.normal_texture, uv_0).rgb; | |
n = normalize(tbn_n * ((2.0 * n - 1.0) * vec3(1.0, 1.0, 1.0))); | |
return n; // TODO NORMAL MAPPING | |
#else | |
#ifdef NORMAL_LOC | |
return frag_normal; | |
#else | |
return normalize(cam_pos - frag_position); | |
#endif | |
#endif | |
} | |
// Fresnel | |
vec3 specular_reflection(PBRInfo info) | |
{ | |
vec3 res = info.f0 + (1.0 - info.f0) * pow(clamp(1.0 - info.vh, 0.0, 1.0), 5.0); | |
return res; | |
} | |
// Smith | |
float geometric_occlusion(PBRInfo info) | |
{ | |
float r = info.roughness + 1.0; | |
float k = r * r / 8.0; | |
float g1 = info.nv / (info.nv * (1.0 - k) + k); | |
float g2 = info.nl / (info.nl * (1.0 - k) + k); | |
//float k = info.roughness * sqrt(2.0 / PI); | |
//float g1 = info.lh / (info.lh * (1.0 - k) + k); | |
//float g2 = info.nh / (info.nh * (1.0 - k) + k); | |
return g1 * g2; | |
} | |
float microfacet_distribution(PBRInfo info) | |
{ | |
float a = info.roughness * info.roughness; | |
float a2 = a * a; | |
float nh2 = info.nh * info.nh; | |
float denom = (nh2 * (a2 - 1.0) + 1.0); | |
return a2 / (PI * denom * denom); | |
} | |
vec3 compute_brdf(vec3 n, vec3 v, vec3 l, | |
float roughness, float metalness, | |
vec3 f0, vec3 c_diff, vec3 albedo, | |
vec3 radiance) | |
{ | |
vec3 h = normalize(l+v); | |
float nl = clamp(dot(n, l), 0.001, 1.0); | |
float nv = clamp(abs(dot(n, v)), 0.001, 1.0); | |
float nh = clamp(dot(n, h), 0.0, 1.0); | |
float lh = clamp(dot(l, h), 0.0, 1.0); | |
float vh = clamp(dot(v, h), 0.0, 1.0); | |
PBRInfo info = PBRInfo(nl, nv, nh, lh, vh, roughness, metalness, f0, c_diff); | |
// Compute PBR terms | |
vec3 F = specular_reflection(info); | |
float G = geometric_occlusion(info); | |
float D = microfacet_distribution(info); | |
// Compute BRDF | |
vec3 diffuse_contrib = (1.0 - F) * c_diff / PI; | |
vec3 spec_contrib = F * G * D / (4.0 * nl * nv + 0.001); | |
vec3 color = nl * radiance * (diffuse_contrib + spec_contrib); | |
return color; | |
} | |
float texture2DCompare(sampler2D depths, vec2 uv, float compare) { | |
return compare > texture(depths, uv.xy).r ? 1.0 : 0.0; | |
} | |
float texture2DShadowLerp(sampler2D depths, vec2 size, vec2 uv, float compare) { | |
vec2 texelSize = vec2(1.0)/size; | |
vec2 f = fract(uv*size+0.5); | |
vec2 centroidUV = floor(uv*size+0.5)/size; | |
float lb = texture2DCompare(depths, centroidUV+texelSize*vec2(0.0, 0.0), compare); | |
float lt = texture2DCompare(depths, centroidUV+texelSize*vec2(0.0, 1.0), compare); | |
float rb = texture2DCompare(depths, centroidUV+texelSize*vec2(1.0, 0.0), compare); | |
float rt = texture2DCompare(depths, centroidUV+texelSize*vec2(1.0, 1.0), compare); | |
float a = mix(lb, lt, f.y); | |
float b = mix(rb, rt, f.y); | |
float c = mix(a, b, f.x); | |
return c; | |
} | |
float PCF(sampler2D depths, vec2 size, vec2 uv, float compare){ | |
float result = 0.0; | |
for(int x=-1; x<=1; x++){ | |
for(int y=-1; y<=1; y++){ | |
vec2 off = vec2(x,y)/size; | |
result += texture2DShadowLerp(depths, size, uv+off, compare); | |
} | |
} | |
return result/9.0; | |
} | |
float shadow_calc(mat4 light_matrix, sampler2D shadow_map, float nl) | |
{ | |
// Compute light texture UV coords | |
vec4 proj_coords = vec4(light_matrix * vec4(frag_position.xyz, 1.0)); | |
vec3 light_coords = proj_coords.xyz / proj_coords.w; | |
light_coords = light_coords * 0.5 + 0.5; | |
float current_depth = light_coords.z; | |
float bias = max(0.001 * (1.0 - nl), 0.0001) / proj_coords.w; | |
float compare = (current_depth - bias); | |
float shadow = PCF(shadow_map, textureSize(shadow_map, 0), light_coords.xy, compare); | |
if (light_coords.z > 1.0) { | |
shadow = 0.0; | |
} | |
return shadow; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// MAIN | |
/////////////////////////////////////////////////////////////////////////////// | |
void main() | |
{ | |
vec4 color = vec4(vec3(0.0), 1.0); | |
/////////////////////////////////////////////////////////////////////////////// | |
// Handle Metallic Materials | |
/////////////////////////////////////////////////////////////////////////////// | |
#ifdef USE_METALLIC_MATERIAL | |
// Compute metallic/roughness factors | |
float roughness = material.roughness_factor; | |
float metallic = material.metallic_factor; | |
#ifdef HAS_METALLIC_ROUGHNESS_TEX | |
vec2 mr = texture(material.metallic_roughness_texture, uv_0).rg; | |
roughness = roughness * mr.r; | |
metallic = metallic * mr.g; | |
#endif | |
roughness = clamp(roughness, min_roughness, 1.0); | |
metallic = clamp(metallic, 0.0, 1.0); | |
// In convention, material roughness is perceputal roughness ^ 2 | |
float alpha_roughness = roughness * roughness; | |
// Compute albedo | |
vec4 base_color = material.base_color_factor; | |
#ifdef HAS_BASE_COLOR_TEX | |
base_color = base_color * srgb_to_linear(texture(material.base_color_texture, uv_0)); | |
#endif | |
// Compute specular and diffuse colors | |
vec3 dialectric_spec = vec3(min_roughness); | |
vec3 c_diff = mix(vec3(0.0), base_color.rgb * (1 - min_roughness), 1.0 - metallic); | |
vec3 f0 = mix(dialectric_spec, base_color.rgb, metallic); | |
// Compute normal | |
vec3 n = normalize(get_normal()); | |
// Loop over lights | |
for (int i = 0; i < n_directional_lights; i++) { | |
vec3 direction = directional_lights[i].direction; | |
vec3 v = normalize(cam_pos - frag_position); // Vector towards camera | |
vec3 l = normalize(-1.0 * direction); // Vector towards light | |
// Compute attenuation and radiance | |
float attenuation = directional_lights[i].intensity; | |
vec3 radiance = attenuation * directional_lights[i].color; | |
// Compute outbound color | |
vec3 res = compute_brdf(n, v, l, roughness, metallic, | |
f0, c_diff, base_color.rgb, radiance); | |
// Compute shadow | |
#ifdef DIRECTIONAL_LIGHT_SHADOWS | |
float nl = clamp(dot(n,l), 0.0, 1.0); | |
float shadow = shadow_calc( | |
directional_lights[i].light_matrix, | |
directional_lights[i].shadow_map, | |
nl | |
); | |
res = res * (1.0 - shadow); | |
#endif | |
color.xyz += res; | |
} | |
for (int i = 0; i < n_point_lights; i++) { | |
vec3 position = point_lights[i].position; | |
vec3 v = normalize(cam_pos - frag_position); // Vector towards camera | |
vec3 l = normalize(position - frag_position); // Vector towards light | |
// Compute attenuation and radiance | |
float dist = length(position - frag_position); | |
float attenuation = point_lights[i].intensity / (dist * dist); | |
vec3 radiance = attenuation * point_lights[i].color; | |
// Compute outbound color | |
vec3 res = compute_brdf(n, v, l, roughness, metallic, | |
f0, c_diff, base_color.rgb, radiance); | |
color.xyz += res; | |
} | |
for (int i = 0; i < n_spot_lights; i++) { | |
vec3 position = spot_lights[i].position; | |
vec3 v = normalize(cam_pos - frag_position); // Vector towards camera | |
vec3 l = normalize(position - frag_position); // Vector towards light | |
// Compute attenuation and radiance | |
vec3 direction = spot_lights[i].direction; | |
float las = spot_lights[i].light_angle_scale; | |
float lao = spot_lights[i].light_angle_offset; | |
float dist = length(position - frag_position); | |
float cd = clamp(dot(direction, -l), 0.0, 1.0); | |
float attenuation = clamp(cd * las + lao, 0.0, 1.0); | |
attenuation = attenuation * attenuation * spot_lights[i].intensity; | |
attenuation = attenuation / (dist * dist); | |
vec3 radiance = attenuation * spot_lights[i].color; | |
// Compute outbound color | |
vec3 res = compute_brdf(n, v, l, roughness, metallic, | |
f0, c_diff, base_color.rgb, radiance); | |
#ifdef SPOT_LIGHT_SHADOWS | |
float nl = clamp(dot(n,l), 0.0, 1.0); | |
float shadow = shadow_calc( | |
spot_lights[i].light_matrix, | |
spot_lights[i].shadow_map, | |
nl | |
); | |
res = res * (1.0 - shadow); | |
#endif | |
color.xyz += res; | |
} | |
color.xyz += base_color.xyz * ambient_light; | |
// Calculate lighting from environment | |
#ifdef USE_IBL | |
// TODO | |
#endif | |
// Apply occlusion | |
#ifdef HAS_OCCLUSION_TEX | |
float ao = texture(material.occlusion_texture, uv_0).r; | |
color.xyz *= ao; | |
#endif | |
// Apply emissive map | |
vec3 emissive = material.emissive_factor; | |
#ifdef HAS_EMISSIVE_TEX | |
emissive *= srgb_to_linear(texture(material.emissive_texture, uv_0)).rgb; | |
#endif | |
color.xyz += emissive * material.emissive_factor; | |
#ifdef COLOR_0_LOC | |
color *= color_multiplier; | |
#endif | |
frag_color = clamp(vec4(pow(color.xyz, vec3(1.0/2.2)), color.a * base_color.a), 0.0, 1.0); | |
#else | |
// TODO GLOSSY MATERIAL BRDF | |
#endif | |
/////////////////////////////////////////////////////////////////////////////// | |
// Handle Glossy Materials | |
/////////////////////////////////////////////////////////////////////////////// | |
} | |