0.00
60.0 fps

Psycial Based Lighting

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);
}