summaryrefslogtreecommitdiff
path: root/light-fluid-simulation
diff options
context:
space:
mode:
authors1n <[email protected]>2020-03-28 10:31:08 -0700
committers1n <[email protected]>2020-03-28 10:31:08 -0700
commit6b81836e6b9815a2996a55ad37dcaa4d89f99e42 (patch)
tree74bb9aa78ca31a6acfffd908e34dfb0df433c707 /light-fluid-simulation
parentCreate .gitignore (diff)
downloadcyne.cf-backup-6b81836e6b9815a2996a55ad37dcaa4d89f99e42.tar.xz
cyne.cf-backup-6b81836e6b9815a2996a55ad37dcaa4d89f99e42.zip
3/28/2020, 10:30HEADmaster
Diffstat (limited to 'light-fluid-simulation')
-rw-r--r--light-fluid-simulation/.htaccess1
-rw-r--r--light-fluid-simulation/css/main.css25
-rw-r--r--light-fluid-simulation/index.html59
-rw-r--r--light-fluid-simulation/js/main.js386
4 files changed, 471 insertions, 0 deletions
diff --git a/light-fluid-simulation/.htaccess b/light-fluid-simulation/.htaccess
new file mode 100644
index 0000000..45552cb
--- /dev/null
+++ b/light-fluid-simulation/.htaccess
@@ -0,0 +1 @@
+Options -Indexes \ No newline at end of file
diff --git a/light-fluid-simulation/css/main.css b/light-fluid-simulation/css/main.css
new file mode 100644
index 0000000..32eefc3
--- /dev/null
+++ b/light-fluid-simulation/css/main.css
@@ -0,0 +1,25 @@
+@import url('https://fonts.googleapis.com/css?family=Open+Sans:600&display=swap');
+
+* {
+ margin: 0;
+ border: 0;
+ box-sizing:
+ border-box;
+}
+
+body {
+
+ margin: 0;
+ position: fixed;
+ overflow: hidden;
+ background-color: #090d13;
+ user-select: none;
+
+}
+
+canvas {
+
+ width: 100%;
+ height: 100%;
+
+} \ No newline at end of file
diff --git a/light-fluid-simulation/index.html b/light-fluid-simulation/index.html
new file mode 100644
index 0000000..b6fbfa5
--- /dev/null
+++ b/light-fluid-simulation/index.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+ <title>s1nical - Light Fluid Simulation</title>
+ <!-- Site metadata -->
+ <meta name="description" content="Light Fluid Simulation">
+ <meta property="og:description" content="Light Fluid Simulation">
+ <meta property="og:title" content="s1nical - Light Fluid Simulation">
+ <meta property="twitter:card" content="summary">
+ <meta property="twitter:site" content="@9inny">
+ <meta property="og:image" content="">
+ <meta property="og:url" content="https://cyne.cf/light-fluid-simulation">
+ <link rel="apple-touch-icon" sizes="128x128" href="/favicon.jpg">
+ <link rel="icon" type="image/jpg" href="/favicon.jpg" sizes="128x128">
+ <link rel="canonical" href="https://cyne.cf/light-fluid-simulation">
+ <link rel="author" href="humans.txt" />
+ <!-- Schema.org Stuff -->
+ <script type="application/ld+json">
+ {
+ "name": "s1nical",
+ "alternateName": "s1n",
+ "description": "Light Fluid Simulation",
+ "headline": "Light Fluid Simulation",
+ "url": "https://cyne.cf/light-fluid-simulation",
+ "image": "",
+ "sameAs": [
+ "https://twitter.com/9inny",
+ "https://github.com/8cy",
+ "https://www.reddit.com/user/s1nical/"
+ ],
+ "publisher": {
+ "@type": "Organization",
+ "logo": {
+ "@type": "ImageObject",
+ "url": ""
+ }
+ },
+ "@type": "WebSite",
+ "@context": "http://schema.org"
+ }
+ </script>
+ <!-- CSS Links -->
+ <link rel="stylesheet" href="/light-fluid-simulation/css/main.css">
+ <!-- External Libraries -->
+ <script src="https://threejs.org/build/three.js"></script>
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
+ <!-- Invisible Scripts -->
+</head>
+
+ <body>
+ <!-- Visable Scripts -->
+ <script src="/light-fluid-simulation/js/main.js"></script>
+ </body>
+
+</html> \ No newline at end of file
diff --git a/light-fluid-simulation/js/main.js b/light-fluid-simulation/js/main.js
new file mode 100644
index 0000000..f6c81bd
--- /dev/null
+++ b/light-fluid-simulation/js/main.js
@@ -0,0 +1,386 @@
+//
+// shaders
+//
+const basic_vert = `
+precision highp float;
+
+void main() {
+ gl_Position = vec4( position, vec2(1.0) );
+}
+`;
+
+const prep_frag = `
+precision highp float;
+
+void main() {
+ gl_FragColor.z = 0.012;
+}
+`;
+
+const physics_frag = `
+precision highp float;
+
+uniform vec3 mouse;
+uniform vec3 pmouse;
+uniform vec2 resolution;
+uniform sampler2D texture;
+
+float distToSegment( vec2 x1, vec2 x2, vec2 p ) {
+
+ vec2 v = x2 - x1;
+ vec2 w = p - x1;
+
+ float c1 = dot(w,v);
+ float c2 = dot(v,v);
+
+ // if c2 <= c1 == c1
+ // if c2 > c1 == c2
+ float div = mix( c2, c1, step( c2, c1 ) );
+
+ // if c1 < 0 == 0.0
+ float mult = step( 0.0, c1 );
+
+ float b = c1 * mult / div;
+ vec2 pb = x1 + b*v;
+
+ return distance( p, pb );
+
+}
+
+vec3 computeNormal( vec4 n ) {
+
+ // pixel scale
+ vec2 un = 1. / resolution;
+ vec2 uv = gl_FragCoord.xy * un;
+
+ // tex sample neighbour-4;
+ vec3 n_r = texture2D( texture, uv + vec2( 1, 0 ) * un ).xyz;
+ vec3 n_l = texture2D( texture, uv - vec2( 1, 0 ) * un ).xyz;
+ vec3 n_u = texture2D( texture, uv + vec2( 0, 1 ) * un ).xyz;
+ vec3 n_d = texture2D( texture, uv - vec2( 0, 1 ) * un ).xyz;
+
+ // partial differences n-4;
+ vec4 dn = vec4( n.z );
+ dn -= vec4( n_r.z, n_l.z, n_u.z, n_d.z );
+
+ // right - left, up - down;
+ vec2 xy = vec2( dn.x - dn.y, dn.z - dn.w );
+ xy += n_r.xy + n_l.xy + n_u.xy + n_d.xy;
+ xy *= 0.972; // energy dissipation
+
+ float z;
+ z += dot( n_r.xy, - vec2( 1, 0 ) );
+ z += dot( n_l.xy, + vec2( 1, 0 ) );
+ z += dot( n_u.xy, - vec2( 0, 1 ) );
+ z += dot( n_d.xy, + vec2( 0, 1 ) );
+
+ return vec3( xy , z ) * 0.25;
+
+}
+
+
+void main() {
+
+ vec2 uv = gl_FragCoord.xy / resolution;
+ float asp = resolution.x / resolution.y; // aspect
+
+ // normal sampling
+ vec4 h = texture2D( texture, uv );
+
+ // previous velocity
+ float vel = h.a;
+ // apply elastic-viscous acceleration
+ // acc = - offset*elasticity - vel*viscosity
+ vel += - ( h.z - 0.012 ) * 0.016 - vel * 0.059;
+
+ // compute normal advection
+ vec3 f = computeNormal( h );
+ f.z += h.z + vel;
+
+ // mouse interaction - continuous distance from mouse
+ float dist = distToSegment(
+ vec2( pmouse.x * asp, pmouse.y), // previous mouse
+ vec2( mouse.x * asp, mouse.y), // current mouse
+ vec2( uv.x * asp, uv.y) // fragcoord
+ );
+
+ float mSize = 0.065; // mouse radius
+ float peak = 0.9; // max-height
+
+ float isDisp = step( 0.5, mouse.z ); // is displaced
+
+ if ( mouse.z > 0.5 && dist <= mSize ) {
+
+ float dst = ( mSize - dist ) / mSize;
+ f.z += pow( abs(dst), 1.9 ) * peak * 2.5;
+ f.xy -= f.xy * pow( abs(dst), 3.9 ) * 0.1;
+ f.z = min( peak, f.z );
+
+ }
+
+ gl_FragColor = clamp( vec4( f, vel ), -1.0, 1.0);
+
+}
+`;
+
+const light_frag = `
+precision highp float;
+
+#define RECIPROCAL_PI 0.31830988618
+
+uniform vec2 resolution;
+uniform sampler2D texture;
+
+float rand(vec2 co){
+ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
+}
+
+// based on https://www.shadertoy.com/view/MslGR8
+vec3 dithering( vec3 color ) {
+ //Calculate grid position
+ float grid_position = rand( gl_FragCoord.xy );
+ //Shift the individual colors differently, thus making it even harder to see the dithering pattern
+ vec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );
+ //modify shift acording to grid position.
+ dither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );
+ //shift the color by dither_shift
+ return color + dither_shift_RGB;
+}
+
+void main() {
+
+ vec2 uv = gl_FragCoord.xy / resolution.xy;
+
+ vec3 N = texture2D( texture, uv ).xyz;
+
+ vec3 viewPos = vec3( 0.0, 0.0, 1.2 );
+ vec3 lightPos = vec3( 0.0, 1.5, 0.98 );
+ vec3 fragPos = vec3( ( 2.0 * uv - 1.0 ), N.z );
+
+ vec3 L = normalize( lightPos - fragPos );
+ vec3 H = normalize( L + normalize( viewPos - fragPos ) );
+ vec3 dN = vec3( N.xy, N.z/2.0 + 0.28 );
+
+ float dif = max( dot( dN, L ), 0.0 );
+ float spec = clamp( dot( normalize(N), H ), 0.0, 1.0 );
+
+ float attenuation = 1.0 - length( lightPos - fragPos ) / 3.1;
+ vec3 dif_int = vec3( dif * 0.056 * attenuation );
+
+ float shininess = 4.8;
+ float ref = RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( spec, shininess );
+ vec3 spec_int = vec3( ref * 0.38 * pow( attenuation, 3.0 ) );
+
+ vec3 col = dif_int + spec_int;
+
+ col = pow( col, vec3( 1.0 / 2.2 ) );
+
+ col.r = mix( col.r * 1.28, col.r, length( dif_int ) * 1.2 / 3.0 );
+ // col += 0.045;
+
+ gl_FragColor = vec4( dithering(col), 1.0 );
+
+}
+`;
+
+
+//
+// three.js setup
+//
+const w = window.innerWidth;
+const h = window.innerHeight;
+const res = new THREE.Vector2(w, h);
+const mousecoord = new THREE.Vector3();
+const mouse = new THREE.Vector3();
+const pmouse = new THREE.Vector3();
+
+var renderer = new THREE.WebGLRenderer();
+renderer.setSize(w, h);
+document.body.appendChild(renderer.domElement);
+
+const scene = new THREE.Scene();
+const camera = new THREE.Camera();
+
+
+// render targets
+let rtt = new THREE.WebGLRenderTarget(w, h, {
+ minFilter: THREE.LinearFilter,
+ magFilter: THREE.LinearFilter,
+ format: THREE.RGBAFormat,
+ type: (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) ? THREE.HalfFloatType : THREE.FloatType,
+ depthTest: false,
+ depthBuffer: false,
+ stencilBuffer: false
+});
+
+let rtt2 = rtt.clone();
+
+
+//
+// materials
+//
+const copyMaterial = new THREE.ShaderMaterial({
+ vertexShader: basic_vert,
+ fragmentShader: prep_frag,
+ blending: THREE.NoBlending,
+ transparent: false,
+ fog: false,
+ lights: false,
+ depthWrite: false,
+ depthTest: false
+});
+
+const physicsMaterial = new THREE.ShaderMaterial({
+ uniforms: {
+ mouse: { type: 'v3', value: mouse },
+ pmouse: { type: 'v3', value: pmouse },
+ resolution: { type: 'v2', value: res },
+ texture: { type: 't' },
+ },
+ vertexShader: basic_vert,
+ fragmentShader: physics_frag,
+ blending: THREE.NoBlending,
+ transparent: false,
+ fog: false,
+ lights: false,
+ depthWrite: false,
+ depthTest: false
+});
+
+const lightsMaterial = new THREE.ShaderMaterial({
+ uniforms: {
+ resolution: { type: 'v2', value: res },
+ texture: { type: 't' },
+ },
+ vertexShader: basic_vert,
+ fragmentShader: light_frag,
+ blending: THREE.NoBlending,
+ transparent: false,
+ fog: false,
+ lights: false,
+ depthWrite: false,
+ depthTest: false
+});
+
+
+//
+// mesh setup
+//
+const geometry = new THREE.BufferGeometry();
+const vertices = new Float32Array([
+ -1.0, -1.0,
+ 3.0, -1.0,
+ -1.0, 3.0
+]);
+
+geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 2));
+
+mesh = new THREE.Mesh(geometry, copyMaterial);
+mesh.frustumCulled = false;
+scene.add(mesh);
+
+
+//
+// pre-render to rtt
+//
+
+renderer.setRenderTarget(rtt);
+renderer.render(scene, camera);
+
+renderer.setRenderTarget(rtt2);
+renderer.render(scene, camera);
+
+mesh.material = physicsMaterial;
+
+
+//
+// listeners
+//
+
+renderer.domElement.addEventListener('mousemove', mousemove);
+renderer.domElement.addEventListener('mouseout', mouseout);
+
+renderer.domElement.addEventListener('touchmove', touch);
+renderer.domElement.addEventListener('touchstart', touch);
+renderer.domElement.addEventListener('touchend', touchend);
+
+window.addEventListener('resize', resize);
+
+renderer.setAnimationLoop(function () {
+
+ render();
+
+});
+
+function render() {
+
+ const tmp = rtt;
+ rtt = rtt2;
+ rtt2 = tmp;
+
+ pmouse.copy(mouse);
+ mouse.copy(mousecoord);
+
+ if (pmouse.z == 0) pmouse.copy(mouse);
+
+ mesh.material = physicsMaterial;
+ mesh.material.uniforms.texture.value = rtt2.texture;
+
+ renderer.setRenderTarget(rtt);
+ renderer.render(scene, camera);
+
+ mesh.material = lightsMaterial;
+ mesh.material.uniforms.texture.value = rtt.texture;
+
+ renderer.setRenderTarget(null);
+ renderer.render(scene, camera);
+
+}
+
+function resize() {
+
+ const h = window.innerHeight;
+ const w = window.innerWidth;
+
+ res.set(w, h);
+
+ camera.aspect = w / h;
+
+ rtt.setSize(w, h);
+ rtt2.setSize(w, h);
+
+ renderer.setSize(w, h);
+
+}
+
+function mousemove(evt) {
+
+ mousecoord.x = evt.pageX / window.innerWidth;
+ mousecoord.y = 1 - (evt.pageY / window.innerHeight);
+ mousecoord.z = 1;
+
+}
+
+
+function mouseout(evt) {
+
+ mousecoord.z = 0;
+
+}
+
+function touch(evt) {
+
+ evt.preventDefault();
+
+ mousecoord.x = evt.touches[0].pageX / window.innerWidth;
+ mousecoord.y = 1 - evt.touches[0].pageY / window.innerHeight;
+ mousecoord.z = 1;
+
+}
+
+
+function touchend(evt) {
+
+ mousecoord.z = 0;
+
+} \ No newline at end of file