<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() {
const lightPos = [-12, 12, -2];
shader(program);
background(0);
program.setUniform('res',[width,height]);
program.setUniform('time', frameCount / 60);
program.setUniform('lightPos', lightPos);
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
#define PI 3.14159265358979323846
uniform vec2 res;
uniform vec3 lightPos;
uniform float time;
float opUnion( float d1, float d2 ) { return min(d1,d2); }
float opSubtraction( float d1, float d2 ) { return max(-d1,d2); }
float opIntersection( float d1, float d2 ) { return max(d1,d2); }
vec3 rotate(vec3 p, float angle, vec3 axis) {
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;
vec3 n = normalize(axis);
return p * c + cross(n, p) * s + n * dot(n, p) * oc;
}
// Signed distance function for a box
float sdBox( vec3 p, vec3 b )
{
p = rotate(p, PI * 0.25, vec3(0.0, 1.0, 1.0)); // rotation
p.x -= sin(time * PI / 3.0)* 0.05 + 0.1;
vec3 q = abs(p) - b;
return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);
}
// Signed distance function for a sphere
float sdSphere(vec3 p, float s) {
p = rotate(p, PI * 0.25, vec3(0.0, 1.0, 1.0)); // rotation
p.x += sin(time * PI / 3.0)* 0.05 + 0.1;
return length(p) - s;
}
float SDF(vec3 p) {
return opUnion(sdSphere(p, 0.2), sdBox(p, vec3(0.1, 0.25, 0.3)));
}
vec3 getNormal(vec3 P) {
vec3 N;
vec2 h = vec2(0.001, 0.0);
N.x = SDF(P + h.xyy) - SDF(P - h.xyy);
N.y = SDF(P + h.yxy) - SDF(P - h.yxy);
N.z = SDF(P + h.yyx) - SDF(P - h.yyx);
return normalize(N);
}
float raymarch(vec3 eye, vec3 rayDir) {
float dist = 0.0;
float threshold = 0.001;
for(int i = 0 ; i < 64 ; ++i) {
float d = SDF(eye + rayDir * dist);
if(d < threshold) { return dist; }
dist += d;
}
return -1.0;
}
float diffuse(vec3 l, vec3 n) {
return max(0.0, dot(l, n));
}
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 rayDir = normalize(vec3(crd, 0.0) - eye);
float dist = raymarch(eye, rayDir);
vec4 color = vec4(vec3(0.01), 1.0);
if (dist >= 0.0) {
vec3 P = eye + rayDir * dist;
vec3 L = normalize(lightPos - P);
vec3 N = getNormal(P);
vec3 baseColor = vec3(1.0);
vec3 Cd = diffuse(L, N) * baseColor;
// Take into account shadows
float shadowDist = raymarch(P + 0.001 * N, L); // Start slightly above the surface to prevent self-shadowing
float shadow = shadowDist >= 0.0 ? 0.25 : 1.0;
Cd *= shadow;
Cd += vec3(0.1); // ambient light
color = vec4(Cd, 1.0);
}
color.rgb = pow(color.rgb, vec3(1.0 / 2.2));
gl_FragColor = color;
}`;
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.