A shader that implements the analytical PBR lighting as described in learnopengl.com/pbr/lighting
#pbr #lighting
Log in to post a comment.
#version 300 es
precision highp float;
uniform vec2 iResolution;
uniform vec3 albedo; // value=1,0,0
uniform float metallic; // value=0, min=0, max=1, step=0.001
uniform float roughness; // value=0.2, min=0, max=1, step=0.001
in vec2 vScreen;
out vec4 fragColor;
const float PI = 3.14159265359;
float distributionGGX (vec3 N, vec3 H, float roughness){
float a2 = roughness * roughness * roughness * roughness;
float NdotH = max (dot (N, H), 0.0);
float denom = (NdotH * NdotH * (a2 - 1.0) + 1.0);
return a2 / (PI * denom * denom);
}
float geometrySchlickGGX (float NdotV, float roughness){
float r = (roughness + 1.0);
float k = (r * r) / 8.0;
return NdotV / (NdotV * (1.0 - k) + k);
}
float geometrySmith (vec3 N, vec3 V, vec3 L, float roughness){
return geometrySchlickGGX (max (dot (N, L), 0.0), roughness) *
geometrySchlickGGX (max (dot (N, V), 0.0), roughness);
}
vec3 fresnelSchlick (float cosTheta, vec3 F0){
return F0 + (1.0 - F0) * pow (1.0 - cosTheta, 5.0);
}
// https://www.shadertoy.com/view/4d2XWV by Inigo Quilez
float sphereIntersect(vec3 ro, vec3 rd, vec4 sph) {
vec3 oc = ro - sph.xyz;
float b = dot( oc, rd );
float c = dot( oc, oc ) - sph.w*sph.w;
float h = b*b - c;
if( h<0.0 ) return -1.0;
return -b - sqrt( h );
}
void main (){
vec3 lightPos = vec3(1.25, 1.0, -2);
vec3 lightColor = vec3(1.0);
vec3 totColor = vec3(0.0);
vec3 ro = vec3(0.0, 0.0, -2.0);
for (float x = 0.0; x <= 1.0; x += 1.) {
for (float y = 0.0; y <= 1.0; y += 1.) {
vec3 rd = normalize(vec3(vScreen + vec2(x, y) / iResolution.y, 1.2));
float d = sphereIntersect(ro, rd, vec4(0,0,0,1));
if (d > 0.) {
vec3 worldPos = ro + d * rd;
vec3 N = normalize (worldPos);
vec3 V = -rd;
vec3 L = normalize (lightPos - worldPos);
vec3 H = normalize (V + L);
// Cook-Torrance BRDF
vec3 F0 = mix (vec3 (0.04), pow(albedo, vec3 (2.2)), metallic);
float NDF = distributionGGX(N, H, roughness);
float G = geometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
vec3 kD = vec3(1.0) - F;
kD *= 1.0 - metallic;
vec3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
vec3 specular = numerator / max(denominator, 0.001);
float NdotL = max(dot(N, L), 0.0);
vec3 color = lightColor * (kD * pow(albedo, vec3 (2.2)) / PI + specular) *
(NdotL / dot(lightPos - worldPos, lightPos - worldPos));
totColor += color;
}
}
}
// HDR tonemapping gamma correct
fragColor = vec4(pow(totColor/(totColor + 1.0), vec3 (1.0/2.2)), 1.0);
}