<script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>
body {margin:0px; padding:0px; overflow: hidden}
let program;
function setup() {
pixelDensity(1);
const canvas = createCanvas(windowWidth, windowHeight,WEBGL);
rectMode(CENTER);
noStroke();
fill(1);
program = createShader(vert,frag);
}
function draw() {
shader(program);
background(0);
program.setUniform('res',[width,height]);
program.setUniform('roughness', mouseX / width);
program.setUniform('metallic', 1.0 - mouseY / height);
rect(0,0,width,height);
}
const vert=`
#ifdef GL_ES
precision highp float;
precision highp int;
#endif
#extension GL_OES_standard_derivatives : enable
attribute vec3 aPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
uniform mat3 uNormalMatrix;
void main() {
gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0);
}`;
const frag=`
#ifdef GL_ES
precision highp float;
#endif
// https://learnopengl.com/PBR/Theory
//https://learnopengl.com/PBR/Lighting
#define PI 3.14159265358979323846
uniform vec2 res;
uniform float roughness;
uniform float metallic;
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
float DistributionGGX(vec3 N, vec3 H, float roughness)
{
float a = roughness*roughness;
float a2 = a*a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH*NdotH;
float num = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return num / denom;
}
float GeometrySchlickGGX(float NdotV, float roughness)
{
float r = (roughness + 1.0);
float k = (r*r) / 8.0;
float num = NdotV;
float denom = NdotV * (1.0 - k) + k;
return num / denom;
}
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
{
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
mat2 rotate2d(float _angle){
return mat2(cos(_angle),-sin(_angle),
sin(_angle),cos(_angle));
}
vec3 shade(vec3 V, vec3 P, vec3 N) {
vec3 F0 = vec3(0.04);
vec3 albedo = vec3(1.0);
F0 = mix(F0, albedo, metallic);
vec3 lightPosition = vec3(1.0, 1.0, -1.0);
vec3 L = normalize(lightPosition - P);
vec3 H = normalize(V + L);
float NDF = DistributionGGX(N, H, roughness);
return vec3(NDF);
}
float SDF(vec3 p) {
float radius = 0.25;
return length(p)-radius;
}
vec3 normal(vec3 P) {
vec2 h = vec2(0.001, 0.0);
return normalize(vec3(SDF(P + h.xyy) - SDF(P - h.xyy),
SDF(P + h.yxy) - SDF(P - h.yxy),
SDF(P + h.yyx) - SDF(P - h.yyx)));
}
float rayHitDist(vec3 eye, vec3 rayDir) {
float dist = 0.0;
float threshold = 0.005;
for(int i = 0 ; i < 16 ; ++i) {
float d = SDF(eye + rayDir * dist);
if(d < threshold) { return dist; }
dist += d;
}
return -1.0;
}
void main(void)
{
vec2 crd = (gl_FragCoord.xy - res * 0.5) / min(res.x, res.y);
vec3 eye = vec3(0.0, 0.0, -2.5);
vec3 V = normalize(eye - vec3(crd, 0.0));
float dist = rayHitDist(eye, -V);
vec3 color = vec3(0.05);
if (dist >= 0.0) {
vec3 P = eye - V * dist;
vec3 N = normal(P);
color = mix(color, shade(V, P, N), smoothstep(0.0, 0.1, dot(V, N)));
}
color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0/2.2));
gl_FragColor = vec4(color, 1.0);
}`;
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.