You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

287 lines
8.1 KiB
HTML

<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Control 2</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<canvas id="webgl" width="500" height="1758"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
attribute vec4 a_position;
uniform mat4 u_modelViewMatrix;
uniform mat4 u_projectionMatrix;
void main() {
gl_Position = a_position;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision highp float;
precision highp int;
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
uniform sampler2D u_noise;
// movement variables
vec3 movement = vec3(.0);
const int maxIterations = 256;
const float stopThreshold = 0.002;
const float stepScale = .5;
const float eps = 0.002;
const vec3 clipColour = vec3(1.);
const vec3 fogColour = vec3(1.);
const vec3 light1_position = vec3(0, 1., -1.);
const vec3 light1_colour = vec3(.8, .8, .85);
struct Surface {
int object_id;
float distance;
vec3 position;
vec3 onsurface_position;
vec3 colour;
float steps;
float ambient;
float spec;
float fog;
};
// Distance function copyright Inigo Quilez
float opExtrusion( in vec3 p, in float primitive, in float h ) {
float d = primitive;
vec2 w = vec2( d, abs(p.z) - h );
return min(max(w.x,w.y),0.0) + length(max(w,0.0));
}
float sdBox( in vec2 p, in vec2 b ) {
vec2 d = abs(p)-b;
return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
}
vec3 path(float z) {
// return vec3(0,0,0.);
return vec3(sin(z * .1) * 4., sin(z * .05) * 10., z);
}
float getBlock(vec3 position, inout int object_id, inout vec3 p) {
// position.z = fract(position.z) - .5;
// object_id = int(id);
float id = float(object_id);
float r = sin(id * .3 + u_time) * .5;
r = sin(texture2D(u_noise, vec2((id*2.)/255.)).x * 2. + u_time - id) * .25;
float rw = texture2D(u_noise, vec2((id*2.)/255.)).x - .5;
// // position.xy += r;
float s = sin(r);
float c = cos(r);
position.xy *= mat2(c, -s, s, c);
p = position;
float box = sdBox(position.xy, vec2(1.5 + rw, 1.)) * -1.;
float world = opExtrusion(position, box, .45) - .005;
// world += smoothstep(.04, 0., abs(sin(p.x * 4.))) * .01;
// world += smoothstep(.02, 0., abs(sin(p.y * 2.))) * .01;
return world;
}
// This function describes the world in distances from any given 3 dimensional point in space
float world(in vec3 position, inout int object_id, inout vec3 p) {
position.xy -= path(position.z).xy;
float id = floor(position.z);
position.z = fract(position.z) - .5;
int oid1 = int(id);
vec3 p1;
float block1 = getBlock(position, oid1, p1);
int oid2 = int(id+1.);
vec3 p2;
float block2 = getBlock(position + vec3(0,0,-1), oid2, p2);
object_id = oid1;
p = p1;
if(block2 < block1) {
block1 = block2;
object_id = oid2;
p = p2;
}
return block1;
}
float world(in vec3 position, inout int object_id) {
vec3 p;
return world(position, object_id, p);
}
float world(in vec3 position) {
int dummy = 0;
return world(position, dummy);
}
Surface getSurface(int object_id, float rayDepth, vec3 sp, float steps, vec3 onsurface_pos, float fog) {
return Surface(
object_id,
rayDepth,
sp,
onsurface_pos,
vec3(1.),
steps,
.5,
1000.,
fog);
}
// The raymarch loop
Surface rayMarch(vec3 ro, vec3 rd, float start, float end) {
float sceneDist = 1e4;
float rayDepth = start;
int object_id = 0;
float steps = 0.;
float fog = 0.;
vec3 p;
for(int i = 0; i < maxIterations; i++) {
sceneDist = world(ro + rd * rayDepth, object_id, p);
rd += (texture2D(u_noise, (p.xy)*255.).rgb-.5)*.0005;
steps++;
fog += max(sceneDist, 0.);
if(sceneDist < stopThreshold || rayDepth > end) {
break;
}
rayDepth += sceneDist * stepScale;
}
return getSurface(object_id, rayDepth, ro + rd * rayDepth, steps, p, fog);
}
// Calculated the normal of any given point in space. Intended to be cast from the point of a surface
vec3 calculate_normal(in vec3 position) {
vec3 grad = vec3(
world(vec3(position.x + eps, position.y, position.z)) - world(vec3(position.x - eps, position.y, position.z)),
world(vec3(position.x, position.y + eps, position.z)) - world(vec3(position.x, position.y - eps, position.z)),
world(vec3(position.x, position.y, position.z + eps)) - world(vec3(position.x, position.y, position.z - eps))
);
return normalize(grad);
}
vec3 lighting(Surface surface_object, vec3 cam) {
// start with black
vec3 sceneColour = vec3(0);
// Surface normal
vec3 normal = calculate_normal(surface_object.position);
normal += smoothstep(.02, 0., abs(sin(surface_object.onsurface_position.x * 4.))) * .5;
normal += smoothstep(.01, 0., abs(sin(surface_object.onsurface_position.y * 2.))) * .5;
// Light position
vec3 lp = path(u_time*3.+15.);
// Light direction
vec3 ld = lp - surface_object.position;
// light attenuation
// For brightly lit scenes or global illumination (like sunlit), this can be limited to just normalizing the ld
float len = length( ld );
ld = normalize(ld);
float lightAtten = min( 1.0 / ( 0.15*len ), 1.0 );
lightAtten = 1.;
// The surface's light reflection normal
vec3 reflection_normal = reflect(-ld, normal);
// Ambient Occlusion
float ao = (surface_object.steps*.01*(1./(surface_object.fog*.07)));
ao *= ao*2.;
ao = clamp(
((1.-ao)+.3)
, 0., 1.);
// ao -= surface_object.steps*.005;
// Object surface properties
float diffuse = max(0., dot(normal, ld));
float specular = max(0., dot( reflection_normal, normalize(cam - surface_object.position) ));
// Bringing all of the lighting components together
vec3 tp = surface_object.onsurface_position * 2.;
vec3 c = texture2D(u_noise, tp.xy + tp.zx).rrr + texture2D(u_noise, tp.zy + tp.yx).rrr;
tp = surface_object.onsurface_position * vec3(.8, .8, 1.);
c += texture2D(u_noise, tp.xy + tp.zx).rrr + texture2D(u_noise, tp.zy + tp.yx).rrr;
tp = surface_object.onsurface_position * vec3(1., .4, .4);
c += texture2D(u_noise, tp.xy + tp.zx).rrr + texture2D(u_noise, tp.zy + tp.yx).rrr;
c *= .125;
c *= .5 + .5;
c *= vec3(1,.98,.90);
sceneColour += ( c * (diffuse + specular )) * light1_colour * lightAtten * ao;
// adding fog
float fogl = surface_object.fog*.04;
fogl *= smoothstep(-.5, 1.8, fogl);
sceneColour = mix( sceneColour, fogColour, fogl );
return sceneColour;
}
void main() {
vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / min(u_resolution.y, u_resolution.x);
float t = u_time * 3.;
// movement
movement = path(t);
// Camera and look-at
vec3 cam = vec3(0,0,-2);
vec3 lookAt = vec3(0,-.5,-2.);
// add movement
lookAt = path(t+3.);
cam = movement;
// cam.y += abs(sin(u_time*20.)*.02);
// Unit vectors
vec3 forward = normalize(lookAt - cam);
vec3 right = normalize(vec3(forward.z, 0., -forward.x));
vec3 up = normalize(cross(forward, right));
// FOV
float FOV = 1.4;
// Ray origin and ray direction
vec3 ro = cam;
vec3 rd = normalize(forward + FOV * uv.x * right + FOV * uv.y * up);
rd.y -= (movement.y - lookAt.y) * .04;
// Ray marching
const float clipNear = 0.;
const float clipFar = 20.;
Surface objectSurface = rayMarch(ro, rd, clipNear, clipFar);
if(objectSurface.distance > clipFar) {
gl_FragColor = vec4(clipColour, 1.);
return;
}
vec3 sceneColour = lighting(objectSurface, cam);
gl_FragColor = vec4(sceneColour, 1.);
// gl_FragColor = vec4(vec3(objectSurface.fog*.03), 1.);
// gl_FragColor.rgb *= objectSurface.fog*.05;
}
</script>
<script src="./script.js"></script>
</body>
</html>