0.00
60.0 fps

Custom PBR Lighting

Trying to make the cheapest PBR model

Log in to post a comment.

#version 300 es
precision highp float;

// Forked from "Phong Lighting" by Matyanson
// https://oneshader.net/shader/d579b9b3f8


uniform float iTime;
uniform vec2  iResolution;

uniform vec3 baseColor; // value=.75,0,0
uniform vec3 specularColor; // value=.1,.1,.09
uniform vec3 ambientColor; // value=0,0,.1
uniform vec3 lightColor; // value=1,1,1
uniform float lightAzimuth; // value=0.69, min=0, max=6.28318530718, step=0.03141592653
uniform float lightZenith; // value=1.10, min=0, max=3.14159265359, step=0.03141592653
uniform float roughness; // value=0.1, min=0, max=1, step=0.01

in vec2 vScreen; // screen coords
out vec4 fragColor;

vec3 fresnelSchlick(float cosTheta, vec3 F0) {
    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}

vec4 customPBR(vec3 normal, vec3 lightDir, vec3 viewDir) {
    vec3 N = normalize(normal);
    vec3 L = normalize(lightDir);
    vec3 V = normalize(viewDir);
    vec3 H = normalize(L + V);
    
    float NdotL = max(dot(N, L), 0.0);
    float NdotH = max(dot(N, H), 0.0001);
    float VdotH = max(dot(V, H), 0.0);
    
    // Adjust Fresnel with roughness
    vec3 fresnel = fresnelSchlick(NdotL, specularColor);
    
    // GGX-like specular highlight distribution
    float alpha = roughness * roughness; // Convert roughness to perceptual alpha
    float specularFactor = pow(NdotH, (2.0 / (alpha * alpha)) - 2.0);
    
    // Split incoming light into specular and diffuse components
    vec3 specularLight = lightColor * fresnel * specularFactor;
    vec3 transmittedLight = lightColor * (1.0 - fresnel);
    
    // Split transmitted light into scattered and absorbed
    vec3 diffuseLight = transmittedLight * baseColor * NdotL;
    
    vec3 color = ambientColor + specularLight + diffuseLight;
    return vec4(color, 1.0);
}

vec4 sphereShaders(float radius) {
    // sphere geometry
    float z = sqrt(pow(radius, 2.0) - pow(vScreen.x, 2.0) - pow(vScreen.y, 2.0));
    vec3 fragPos = vec3(vScreen, z);
    vec3 normal = fragPos / radius;
    // prepare other properties
    vec3 cameraPos = vec3(0.0, 0.0, 1.0);
    vec3 viewDir = cameraPos - fragPos;
    vec3 lightDir = vec3(
        sin(lightZenith) * cos(lightAzimuth),
        cos(lightZenith),
        sin(lightZenith) * sin(lightAzimuth)
    );
    return customPBR(normal, lightDir, viewDir);
}

vec4 backgroundShaders() {
    return vec4(vec3(0.1), 1.0);
}

void main() {
    float radius = 0.5;
    
    if(length(vScreen) <= radius) {
        fragColor = sphereShaders(radius);
    } else {
        fragColor = backgroundShaders();
    }
}