Trying to make the cheapest PBR model
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,.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; // 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; 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 = dot(N, L); vec3 R = reflect(-L, N); float VdotR = dot(V, R); // power–law specular highlight distribution float cosTheta = VdotR * 0.5 + 0.5; // increase positive value range float alpha2 = pow(roughness, 4.0); float numerator = 1.0 / (alpha2 + 0.0000001) + 1.0; float specularFactor = numerator / 6.28318530718 * pow(cosTheta, numerator - 2.0); if(NdotL < 0.0) { specularFactor = 0.0; } NdotL = max(NdotL, 0.0); // Adjust Fresnel with roughness vec3 fresnel = fresnelSchlick(NdotL, specularColor); // scale light intensity based on the projected area size vec3 inLight = lightColor * NdotL; // Split incoming light into specular and diffuse components vec3 specularLight = inLight * fresnel * specularFactor + ambientColor * specularColor; vec3 transmittedLight = inLight * (1.0 - fresnel) + ambientColor * (1.0 - specularColor); // Split transmitted light into scattered and absorbed vec3 diffuseLight = transmittedLight * baseColor; vec3 color = diffuseLight + specularLight; 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; return customPBR(normal, lightDir, viewDir); } 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; }