Blinn-Phong Lighting
Log in to post a comment.
#version 300 es
precision highp float;
uniform float iTime;
uniform vec2 iResolution;
uniform vec3 baseColor; // value=.75,0,0
uniform vec3 specularColor; // value=1,1,0.9
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;
// GLOBAL VARIABLES
vec3 cameraPos = vec3(0.0, 0.0, 3.0);
vec4 sphere = vec4(0.0, 0.0, 0.0, 0.5); // x, y, z, radius
vec3 fragPos;
vec3 viewDir;
vec3 lightDir;
vec4 phong(vec3 normal, vec3 lightDir, vec3 viewDir, float shininess) {
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);
vec3 diffuse = baseColor * NdotL;
float NdotH = max(dot(N, H), 0.0);
float spec = pow(NdotH, shininess);
vec3 specular = specularColor * spec;
vec3 color = ambientColor + lightColor * (diffuse + specular);
return vec4(color, 1.0);
}
// https://www.shadertoy.com/view/4d2XWV by Inigo Quilez
float sphereIntersect(vec3 ro, vec3 rd, vec4 sph) {
vec3 oc = ro - sph.xyz; // Vector from sphere center to ray origin
float b = dot(oc, rd); // Projection of oc onto rd
float c = dot(oc, oc) - sph.w * sph.w; // Squared distance from ro to sphere surface minus radius²
float h = b * b - c; // Discriminant of the quadratic equation
if (h < 0.0) return -1.0; // No intersection if the discriminant is negative
return -b - sqrt(h); // Return the smallest positive intersection distance
}
vec4 sphereShaders(vec4 color) {
// RAY CALCULATIONS
vec3 rd = -viewDir;
float d = sphereIntersect(cameraPos, rd, sphere);
if(d < 0.0) return color;
vec3 normal = cameraPos + d * rd;
// Compute shininess from roughness
float shininess = max(0.0, (2.0 / (roughness * roughness)) - 2.0);
return phong(normal, lightDir, viewDir, shininess);
}
vec4 backgroundShaders(vec4 color) {
if(dot(-viewDir, lightDir) > 0.999)
return vec4(vec3(lightColor), 1.0);
return vec4(vec3(0.1), 1.0);
}
void main() {
// SETUP
fragPos = vec3(vScreen, 0.0);
viewDir = normalize(cameraPos - fragPos);
lightDir = vec3(
sin(lightZenith) * cos(lightAzimuth),
cos(lightZenith),
sin(lightZenith) * sin(lightAzimuth)
);
// SHADER PASSES
vec4 color = vec4(0.0, 0.0, 0.0, 0.0);
color = mix(sphereShaders(color), color, color.a);
color = mix(backgroundShaders(color), color, color.a);
fragColor = color;
}