From 299c72987d42efeedfabb85430f3064111dce150 Mon Sep 17 00:00:00 2001 From: Steven Cobb Date: Sun, 28 Jul 2019 13:37:39 -0400 Subject: [PATCH] revert to debug mode (cameraLookUp false), init FireShader class - change old Fire.js to Flame.js --- TODO.md | 20 +++++ css/bounce.scss | 63 ------------- index.html | 5 +- src/js/Fire.js | 91 ++++++++++--------- src/js/FireShader.js | 199 +++++++++++++++++++++++++++++++++++++++++ src/js/Flame.js | 36 ++++++++ src/js/app.js | 36 +++++--- src/js/globals.js | 3 +- vendor/Fire.js | 51 +++++++++++ vendor/FireShader.js | 208 +++++++++++++++++++++++++++++++++++++++++++ webpack.config.js | 4 +- 11 files changed, 589 insertions(+), 127 deletions(-) create mode 100644 TODO.md delete mode 100644 css/bounce.scss create mode 100644 src/js/FireShader.js create mode 100644 src/js/Flame.js create mode 100644 vendor/Fire.js create mode 100644 vendor/FireShader.js diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..af23cd2 --- /dev/null +++ b/TODO.md @@ -0,0 +1,20 @@ +## TODO + +- [ ] Fix Fire class and shader import +- [ ] Fix audio quality in recordings +- [ ] Other shapes besides spheres - each shape has different sound / wave type +- [ ] Contact surfaces light up based on note color +- [ ] Keep camera in line with ballX position +- [ ] Dynamically set zPos based on note position in staff (position.z in instrumentMapping getter) +- [ ] Clean up instrumentMapping template and getters +- [ ] Drum machine wheel or metronome for repeating snare and kick synths +- [ ] Different contact surfaces with different restitution +- [ ] UI for editable 'instrument - shape - note - keyboard' mapping object +- [ ] Web MIDI API support to connect to keyboard +- [x] Arrow key controls +- [x] support PolySynth in getInstrumentMappingTemplate to allow chords +- [x] variation added for striped balls +- [x] configurable static row positioning of ball array using globalShowStaticRows +- [x] dynamic associatation of keyName with keyMapped options for dropped balls +- [x] set fill styles from instrumentMapping obj instead of THREEx.createPoolBall +- [x] How to drop balls without stacking? \ No newline at end of file diff --git a/css/bounce.scss b/css/bounce.scss deleted file mode 100644 index 5aa4d22..0000000 --- a/css/bounce.scss +++ /dev/null @@ -1,63 +0,0 @@ -$yellow: #0201BD; -$blue: #003366; - -body { - margin: 0; - text-align: center -} -canvas { - width: 100%; - height: 100%; - min-height: 500px; - //margin: 200px 0 10px; - margin: 0; -} -#controls-container { - position: absolute; - top: 30px; - left: 5px; - right: 0; - margin: 0 auto; - z-index: 1; - text-align: left; -} - -.play-wrapper { - text-align: left; - z-index: 2; -} -.play { - display: inline-block; - margin: auto 3px 30px auto; - padding: 12px 18px; - background: none; - font: 22px/1 Verdana, Geneva, sans-serif; - letter-spacing: 1.5px; - color: $blue; - border: 1px solid $blue; - text-transform: uppercase; - cursor: pointer; - -webkit-transition: all 0.3s; - transition: all 0.3s; - span.fa { - padding: 0 5px 0 3px; - } -} -.play:hover { - background: $blue; - color: #fff; -} - -button { - cursor: pointer; -} - -/*** AUDIO ANALYSER ***/ -.visuals { - position: absolute; - z-index: 0; -} - -.playlist { - display: none; -} \ No newline at end of file diff --git a/index.html b/index.html index e833f3e..c922676 100644 --- a/index.html +++ b/index.html @@ -17,8 +17,9 @@ - - + + + diff --git a/src/js/Fire.js b/src/js/Fire.js index f22de52..f605e6d 100644 --- a/src/js/Fire.js +++ b/src/js/Fire.js @@ -1,55 +1,54 @@ -import globals from './globals.js'; +import FireShader from './FireShader.js'; -/* - *** FIRE *** +/** + * see: mattatz / http://github.com/mattatz + * Ray tracing based real-time procedural volumetric fire object for three.js */ +// THREE.Fire = function ( fireTex, color ) { export default class Fire { - - constructor(fireParam) { - // https://googlechrome.github.io/samples/classes-es6/ - // this.name = 'Polygon'; - // this.height = height; - // this.width = width; - // this.volumetricFire = fireParam; - this.triggerTime = fireParam; - } - - initFire() { - globals.loader.crossOrigin = ''; - var fireTex = globals.loader.load("./assets/flame/FireOrig.png"); - var wireframeMat = new THREE.MeshBasicMaterial({ - color : new THREE.Color(0xffffff), - wireframe : true - }); - - const volumetricFire = new THREE.Fire(fireTex); - volumetricFire.position.set(globals.posBehindX + 22, 0, globals.posBehindZ); - - // volumetricFire.scale.set(3, 3.4, 3.0); //width, height, z - volumetricFire.scale.set(6, 6.8, 6.0); //width, height, z - - // console.log(volumetricFire.material.uniforms); - // volumetricFire.material.uniforms.magnitude.value = 0.5; //higher = spaciness - // volumetricFire.material.uniforms.lacunarity.value = 0.1; //lower = more cartoony - // volumetricFire.material.uniforms.lacunarity.gain = 0.1; //more = less height - var wireframe = new THREE.Mesh(volumetricFire.geometry, wireframeMat.clone()); - volumetricFire.add(wireframe); - wireframe.visible = false; - - // console.log({volumetricFire}); - // scene.add(volumetricFire); - globals.scene.add(volumetricFire); + constructor() { + // super(); } - addFire(posX = globals.posBehindX + 22, currentTime) { - // console.log(this); - // if (currentTime === this.triggerTime) { - // console.log('addFire active......'); - volumetricFire.position.set(posX, 0, globals.posBehindZ); - scene.add(volumetricFire); - // } + init() { + var fireMaterial = new THREE.ShaderMaterial( { + defines : FireShader.defines, + uniforms : THREE.UniformsUtils.clone( FireShader.uniforms ), + vertexShader : FireShader.vertexShader, + fragmentShader : FireShader.fragmentShader, + transparent : true, + depthWrite : false, + depthTest : false + } ); + + // initialize uniforms + + fireTex.magFilter = fireTex.minFilter = THREE.LinearFilter; + fireTex.wrapS = fireTex.wrapT = THREE.ClampToEdgeWrapping; + + fireMaterial.uniforms.fireTex.value = fireTex; + fireMaterial.uniforms.color.value = color || new THREE.Color( 0xeeeeee ); + fireMaterial.uniforms.invModelMatrix.value = new THREE.Matrix4(); + fireMaterial.uniforms.scale.value = new THREE.Vector3( 1, 1, 1 ); + fireMaterial.uniforms.seed.value = Math.random() * 19.19; + + THREE.Mesh.call( this, new THREE.BoxGeometry( 1.0, 1.0, 1.0 ), fireMaterial ); + + // THREE.Fire.prototype = Object.create( THREE.Mesh.prototype ); + // THREE.Fire.prototype.constructor = THREE.Fire; } -} \ No newline at end of file + // update = function ( time ) { + // var invModelMatrix = this.material.uniforms.invModelMatrix.value; + // this.updateMatrixWorld(); + // invModelMatrix.getInverse( this.matrixWorld ); + // if( time !== undefined ) { + // this.material.uniforms.time.value = time; + // } + // this.material.uniforms.invModelMatrix.value = invModelMatrix; + // this.material.uniforms.scale.value = this.scale; + // }; + +}; \ No newline at end of file diff --git a/src/js/FireShader.js b/src/js/FireShader.js new file mode 100644 index 0000000..33b7ce2 --- /dev/null +++ b/src/js/FireShader.js @@ -0,0 +1,199 @@ +/* see: http://mattatz.github.io */ + +// THREE.FireShader = { +// export default class FireShader { +export default { + + defines: { + "ITERATIONS" : "20", + "OCTIVES" : "3" + }, + + uniforms: { + "fireTex" : { type : "t", value : null }, + "color" : { type : "c", value : null }, + "time" : { type : "f", value : 0.0 }, + "seed" : { type : "f", value : 0.0 }, + "invModelMatrix": { type : "m4", value : null }, + "scale" : { type : "v3", value : null }, + + "noiseScale" : { type : "v4", value : new THREE.Vector4(1, 2, 1, 0.3) }, + "magnitude" : { type : "f", value : 1.3 }, + "lacunarity" : { type : "f", value : 2.0 }, + "gain" : { type : "f", value : 0.5 } + }, + + vertexShader: [ + "varying vec3 vWorldPos;", + "void main() {", + "gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);", + "vWorldPos = (modelMatrix * vec4(position, 1.0)).xyz;", + "}" + ].join("\n"), + + fragmentShader: [ + "uniform vec3 color;", + "uniform float time;", + "uniform float seed;", + "uniform mat4 invModelMatrix;", + "uniform vec3 scale;", + + "uniform vec4 noiseScale;", + "uniform float magnitude;", + "uniform float lacunarity;", + "uniform float gain;", + + "uniform sampler2D fireTex;", + + "varying vec3 vWorldPos;", + + // GLSL simplex noise function by ashima / https://github.com/ashima/webgl-noise/blob/master/src/noise3D.glsl + // -------- simplex noise + "vec3 mod289(vec3 x) {", + "return x - floor(x * (1.0 / 289.0)) * 289.0;", + "}", + + "vec4 mod289(vec4 x) {", + "return x - floor(x * (1.0 / 289.0)) * 289.0;", + "}", + + "vec4 permute(vec4 x) {", + "return mod289(((x * 34.0) + 1.0) * x);", + "}", + + "vec4 taylorInvSqrt(vec4 r) {", + "return 1.79284291400159 - 0.85373472095314 * r;", + "}", + + "float snoise(vec3 v) {", + "const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);", + "const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);", + + // First corner + "vec3 i = floor(v + dot(v, C.yyy));", + "vec3 x0 = v - i + dot(i, C.xxx);", + + // Other corners + "vec3 g = step(x0.yzx, x0.xyz);", + "vec3 l = 1.0 - g;", + "vec3 i1 = min(g.xyz, l.zxy);", + "vec3 i2 = max(g.xyz, l.zxy);", + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + "vec3 x1 = x0 - i1 + C.xxx;", + "vec3 x2 = x0 - i2 + C.yyy;", // 2.0*C.x = 1/3 = C.y + "vec3 x3 = x0 - D.yyy;", // -1.0+3.0*C.x = -0.5 = -D.y + + // Permutations + "i = mod289(i); ", + "vec4 p = permute(permute(permute( ", + "i.z + vec4(0.0, i1.z, i2.z, 1.0))", + "+ i.y + vec4(0.0, i1.y, i2.y, 1.0)) ", + "+ i.x + vec4(0.0, i1.x, i2.x, 1.0));", + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + "float n_ = 0.142857142857;", // 1.0/7.0 + "vec3 ns = n_ * D.wyz - D.xzx;", + + "vec4 j = p - 49.0 * floor(p * ns.z * ns.z);", // mod(p,7*7) + + "vec4 x_ = floor(j * ns.z);", + "vec4 y_ = floor(j - 7.0 * x_);", // mod(j,N) + + "vec4 x = x_ * ns.x + ns.yyyy;", + "vec4 y = y_ * ns.x + ns.yyyy;", + "vec4 h = 1.0 - abs(x) - abs(y);", + + "vec4 b0 = vec4(x.xy, y.xy);", + "vec4 b1 = vec4(x.zw, y.zw);", + + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + "vec4 s0 = floor(b0) * 2.0 + 1.0;", + "vec4 s1 = floor(b1) * 2.0 + 1.0;", + "vec4 sh = -step(h, vec4(0.0));", + + "vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;", + "vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;", + + "vec3 p0 = vec3(a0.xy, h.x);", + "vec3 p1 = vec3(a0.zw, h.y);", + "vec3 p2 = vec3(a1.xy, h.z);", + "vec3 p3 = vec3(a1.zw, h.w);", + + //Normalise gradients + "vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));", + "p0 *= norm.x;", + "p1 *= norm.y;", + "p2 *= norm.z;", + "p3 *= norm.w;", + + // Mix final noise value + "vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);", + "m = m * m;", + "return 42.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));", + "}", + // simplex noise -------- + + "float turbulence(vec3 p) {", + "float sum = 0.0;", + "float freq = 1.0;", + "float amp = 1.0;", + + "for(int i = 0; i < OCTIVES; i++) {", + "sum += abs(snoise(p * freq)) * amp;", + "freq *= lacunarity;", + "amp *= gain;", + "}", + + "return sum;", + "}", + + "vec4 samplerFire (vec3 p, vec4 scale) {", + "vec2 st = vec2(sqrt(dot(p.xz, p.xz)), p.y);", + + "if(st.x <= 0.0 || st.x >= 1.0 || st.y <= 0.0 || st.y >= 1.0) return vec4(0.0);", + + "p.y -= (seed + time) * scale.w;", + "p *= scale.xyz;", + + "st.y += sqrt(st.y) * magnitude * turbulence(p);", + + "if(st.y <= 0.0 || st.y >= 1.0) return vec4(0.0);", + + "return texture2D(fireTex, st);", + "}", + + "vec3 localize(vec3 p) {", + "return (invModelMatrix * vec4(p, 1.0)).xyz;", + "}", + + "void main() {", + "vec3 rayPos = vWorldPos;", + "vec3 rayDir = normalize(rayPos - cameraPosition);", + "float rayLen = 0.0288 * length(scale.xyz);", + + "vec4 col = vec4(0.0);", + + "for(int i = 0; i < ITERATIONS; i++) {", + "rayPos += rayDir * rayLen;", + + "vec3 lp = localize(rayPos);", + + "lp.y += 0.5;", + "lp.xz *= 2.0;", + "col += samplerFire(lp, noiseScale);", + "}", + + "col.a = col.r;", + + "gl_FragColor = col;", + "}", + + ].join("\n") + +}; \ No newline at end of file diff --git a/src/js/Flame.js b/src/js/Flame.js new file mode 100644 index 0000000..1498489 --- /dev/null +++ b/src/js/Flame.js @@ -0,0 +1,36 @@ +import globals from './globals.js'; +// import THREE.Fire from '../vendor/Fire.js'; +// import Fire from './Fire.js'; + +// import FireShader from '../vendor/FireShader.js'; + +// import Fire from 'Fire'; + +/* + *** Flame *** + */ + +export default class Flame { + + constructor(fireParam) { + this.triggerTime = fireParam; + } + + initFire() { + globals.loader.crossOrigin = ''; + var fireTex = globals.loader.load("./assets/flame/FireOrig.png"); + + // const volumetricFire = new THREE.Fire(fireTex); + const volumetricFire = new Fire(fireTex); + volumetricFire.position.set(globals.posBehindX + 22, 0, globals.posBehindZ); + volumetricFire.scale.set(6, 6.8, 6.0); //width, height, z + volumetricFire.add(wireframe); + globals.scene.add(volumetricFire); + } + + addFire(posX = globals.posBehindX + 22, currentTime) { + volumetricFire.position.set(posX, 0, globals.posBehindZ); + scene.add(volumetricFire); + } + +} \ No newline at end of file diff --git a/src/js/app.js b/src/js/app.js index 20a6192..8ed9cf0 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -3,7 +3,7 @@ import globals from './globals.js'; import InstrumentMappings from './InstrumentMappings.js'; import { FlyControls } from 'three/examples/jsm/controls/FlyControls.js'; import Light from './Light.js'; -import Fire from './Fire.js'; +// import Flame from './Flame.js'; import Physics from './Physics.js'; import Helpers from './THREEx.js'; import Pool from './Pool.js'; @@ -131,14 +131,6 @@ function onTextureLoaded(texture) { const light = new Light(); light.addLights(globals.renderer); -let flameActive = false; -// let flameActive = ''; -// const triggerAnimationTime = "4:0:0"; -let volumetricFire; //TODO: remove after Fire class methods working -let flameFirst = new Fire(globals.triggerAnimationTime); -flameFirst.initFire(); -// initFire(); - const physics = new Physics(); physics.initPhysics(); @@ -294,6 +286,22 @@ function addThickStaffLines() { } // addThickStaffLines(); + +//-----Static Fire Example------// +let flameActive = false; +let volumetricFire; //TODO: remove after Flame class methods working +// let flameFirst = new Flame(globals.triggerAnimationTime); +// flameFirst.initFire(); + +globals.loader.crossOrigin = ''; +const fireTex = globals.loader.load("./assets/flame/FireOrig.png"); +volumetricFire = new THREE.Fire(fireTex); +volumetricFire.position.set(globals.posBehindX + 22, 0, globals.posBehindZ); +volumetricFire.scale.set(6, 6.8, 6.0); //width, height, z +volumetricFire.position.set(globals.posBehindX + 20, 0, globals.posBehindZ); +console.log(volumetricFire); +globals.scene.add(volumetricFire); + //-----POOL BALLS (STATIC ROW)------// const poolBalls = {}; if (globals.showStaticRows === true) { @@ -434,11 +442,11 @@ let animate = () => { // if (triggerAnimationTime === Tone.Transport.position & flameActive === false) { // if (Tone.Transport.position === "5:8:0" & flameActive === false) { // if (Tone.Transport.position === "6:5:0" & flameActive === false) { - if (Tone.Transport.seconds > 23 & flameActive === false) { - console.log('addFire active -> position: ', Tone.Transport.position); - // flameFirst.addFire(); - flameFirst.addFire(globals.ticks); - flameActive = true; + // if (Tone.Transport.seconds > 23 & flameActive === false) { + if (flameActive === false) { + // console.log('addFire active -> position: ', Tone.Transport.position); + // flameFirst.addFire(globals.ticks); + // flameActive = true; } if (Tone.Transport.seconds > 41 && Tone.Transport.seconds < 42) { diff --git a/src/js/globals.js b/src/js/globals.js index 447e0a7..dbc8717 100644 --- a/src/js/globals.js +++ b/src/js/globals.js @@ -8,7 +8,8 @@ export default { autoStart: false, camera: new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.1, 1000), cameraPositionBehind: true, - cameraLookUp: true, + // cameraLookUp: true, + cameraLookUp: false, clock: new THREE.Clock(), configColorAnimate: true, controls: '', diff --git a/vendor/Fire.js b/vendor/Fire.js new file mode 100644 index 0000000..8a42d8a --- /dev/null +++ b/vendor/Fire.js @@ -0,0 +1,51 @@ +/** + * @author mattatz / http://github.com/mattatz + * + * Ray tracing based real-time procedural volumetric fire object for three.js + */ + +THREE.Fire = function ( fireTex, color ) { + + var fireMaterial = new THREE.ShaderMaterial( { + defines : THREE.FireShader.defines, + uniforms : THREE.UniformsUtils.clone( THREE.FireShader.uniforms ), + vertexShader : THREE.FireShader.vertexShader, + fragmentShader : THREE.FireShader.fragmentShader, + transparent : true, + depthWrite : false, + depthTest : false + } ); + + // initialize uniforms + + fireTex.magFilter = fireTex.minFilter = THREE.LinearFilter; + fireTex.wrapS = fireTex.wrapT = THREE.ClampToEdgeWrapping; + + fireMaterial.uniforms.fireTex.value = fireTex; + fireMaterial.uniforms.color.value = color || new THREE.Color( 0xeeeeee ); + fireMaterial.uniforms.invModelMatrix.value = new THREE.Matrix4(); + fireMaterial.uniforms.scale.value = new THREE.Vector3( 1, 1, 1 ); + fireMaterial.uniforms.seed.value = Math.random() * 19.19; + + THREE.Mesh.call( this, new THREE.BoxGeometry( 1.0, 1.0, 1.0 ), fireMaterial ); +}; + +THREE.Fire.prototype = Object.create( THREE.Mesh.prototype ); +THREE.Fire.prototype.constructor = THREE.Fire; + +THREE.Fire.prototype.update = function ( time ) { + + var invModelMatrix = this.material.uniforms.invModelMatrix.value; + + this.updateMatrixWorld(); + invModelMatrix.getInverse( this.matrixWorld ); + + if( time !== undefined ) { + this.material.uniforms.time.value = time; + } + + this.material.uniforms.invModelMatrix.value = invModelMatrix; + + this.material.uniforms.scale.value = this.scale; + +}; \ No newline at end of file diff --git a/vendor/FireShader.js b/vendor/FireShader.js new file mode 100644 index 0000000..087c583 --- /dev/null +++ b/vendor/FireShader.js @@ -0,0 +1,208 @@ +/** + * @author mattatz / http://mattatz.github.io + * + * Ray tracing based real-time procedural volumetric fire shader. + * + * Based on + * Alfred et al. Real-Time procedural volumetric fire / http://dl.acm.org/citation.cfm?id=1230131 + * and + * webgl-noise / https://github.com/ashima/webgl-noise/blob/master/src/noise3D.glsl + * and + * primitive: blog | object space raymarching / https://github.com/ashima/webgl-noise/blob/master/src/noise3D.glsl + */ + +THREE.FireShader = { + + defines: { + "ITERATIONS" : "20", + "OCTIVES" : "3" + }, + + uniforms: { + "fireTex" : { type : "t", value : null }, + "color" : { type : "c", value : null }, + "time" : { type : "f", value : 0.0 }, + "seed" : { type : "f", value : 0.0 }, + "invModelMatrix": { type : "m4", value : null }, + "scale" : { type : "v3", value : null }, + + "noiseScale" : { type : "v4", value : new THREE.Vector4(1, 2, 1, 0.3) }, + "magnitude" : { type : "f", value : 1.3 }, + "lacunarity" : { type : "f", value : 2.0 }, + "gain" : { type : "f", value : 0.5 } + }, + + vertexShader: [ + "varying vec3 vWorldPos;", + "void main() {", + "gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);", + "vWorldPos = (modelMatrix * vec4(position, 1.0)).xyz;", + "}" + ].join("\n"), + + fragmentShader: [ + "uniform vec3 color;", + "uniform float time;", + "uniform float seed;", + "uniform mat4 invModelMatrix;", + "uniform vec3 scale;", + + "uniform vec4 noiseScale;", + "uniform float magnitude;", + "uniform float lacunarity;", + "uniform float gain;", + + "uniform sampler2D fireTex;", + + "varying vec3 vWorldPos;", + + // GLSL simplex noise function by ashima / https://github.com/ashima/webgl-noise/blob/master/src/noise3D.glsl + // -------- simplex noise + "vec3 mod289(vec3 x) {", + "return x - floor(x * (1.0 / 289.0)) * 289.0;", + "}", + + "vec4 mod289(vec4 x) {", + "return x - floor(x * (1.0 / 289.0)) * 289.0;", + "}", + + "vec4 permute(vec4 x) {", + "return mod289(((x * 34.0) + 1.0) * x);", + "}", + + "vec4 taylorInvSqrt(vec4 r) {", + "return 1.79284291400159 - 0.85373472095314 * r;", + "}", + + "float snoise(vec3 v) {", + "const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);", + "const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);", + + // First corner + "vec3 i = floor(v + dot(v, C.yyy));", + "vec3 x0 = v - i + dot(i, C.xxx);", + + // Other corners + "vec3 g = step(x0.yzx, x0.xyz);", + "vec3 l = 1.0 - g;", + "vec3 i1 = min(g.xyz, l.zxy);", + "vec3 i2 = max(g.xyz, l.zxy);", + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + "vec3 x1 = x0 - i1 + C.xxx;", + "vec3 x2 = x0 - i2 + C.yyy;", // 2.0*C.x = 1/3 = C.y + "vec3 x3 = x0 - D.yyy;", // -1.0+3.0*C.x = -0.5 = -D.y + + // Permutations + "i = mod289(i); ", + "vec4 p = permute(permute(permute( ", + "i.z + vec4(0.0, i1.z, i2.z, 1.0))", + "+ i.y + vec4(0.0, i1.y, i2.y, 1.0)) ", + "+ i.x + vec4(0.0, i1.x, i2.x, 1.0));", + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + "float n_ = 0.142857142857;", // 1.0/7.0 + "vec3 ns = n_ * D.wyz - D.xzx;", + + "vec4 j = p - 49.0 * floor(p * ns.z * ns.z);", // mod(p,7*7) + + "vec4 x_ = floor(j * ns.z);", + "vec4 y_ = floor(j - 7.0 * x_);", // mod(j,N) + + "vec4 x = x_ * ns.x + ns.yyyy;", + "vec4 y = y_ * ns.x + ns.yyyy;", + "vec4 h = 1.0 - abs(x) - abs(y);", + + "vec4 b0 = vec4(x.xy, y.xy);", + "vec4 b1 = vec4(x.zw, y.zw);", + + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + "vec4 s0 = floor(b0) * 2.0 + 1.0;", + "vec4 s1 = floor(b1) * 2.0 + 1.0;", + "vec4 sh = -step(h, vec4(0.0));", + + "vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;", + "vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;", + + "vec3 p0 = vec3(a0.xy, h.x);", + "vec3 p1 = vec3(a0.zw, h.y);", + "vec3 p2 = vec3(a1.xy, h.z);", + "vec3 p3 = vec3(a1.zw, h.w);", + + //Normalise gradients + "vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));", + "p0 *= norm.x;", + "p1 *= norm.y;", + "p2 *= norm.z;", + "p3 *= norm.w;", + + // Mix final noise value + "vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);", + "m = m * m;", + "return 42.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));", + "}", + // simplex noise -------- + + "float turbulence(vec3 p) {", + "float sum = 0.0;", + "float freq = 1.0;", + "float amp = 1.0;", + + "for(int i = 0; i < OCTIVES; i++) {", + "sum += abs(snoise(p * freq)) * amp;", + "freq *= lacunarity;", + "amp *= gain;", + "}", + + "return sum;", + "}", + + "vec4 samplerFire (vec3 p, vec4 scale) {", + "vec2 st = vec2(sqrt(dot(p.xz, p.xz)), p.y);", + + "if(st.x <= 0.0 || st.x >= 1.0 || st.y <= 0.0 || st.y >= 1.0) return vec4(0.0);", + + "p.y -= (seed + time) * scale.w;", + "p *= scale.xyz;", + + "st.y += sqrt(st.y) * magnitude * turbulence(p);", + + "if(st.y <= 0.0 || st.y >= 1.0) return vec4(0.0);", + + "return texture2D(fireTex, st);", + "}", + + "vec3 localize(vec3 p) {", + "return (invModelMatrix * vec4(p, 1.0)).xyz;", + "}", + + "void main() {", + "vec3 rayPos = vWorldPos;", + "vec3 rayDir = normalize(rayPos - cameraPosition);", + "float rayLen = 0.0288 * length(scale.xyz);", + + "vec4 col = vec4(0.0);", + + "for(int i = 0; i < ITERATIONS; i++) {", + "rayPos += rayDir * rayLen;", + + "vec3 lp = localize(rayPos);", + + "lp.y += 0.5;", + "lp.xz *= 2.0;", + "col += samplerFire(lp, noiseScale);", + "}", + + "col.a = col.r;", + + "gl_FragColor = col;", + "}", + + ].join("\n") + +}; \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index d312f1e..152df45 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -7,6 +7,8 @@ const path = require('path'); const config = { entry: { 'bundle.js': [ + path.resolve(__dirname, 'src/js/Fire.js'), + path.resolve(__dirname, 'src/js/FireShader.js'), path.resolve(__dirname, 'node_modules/tone/build/Tone.js'), path.resolve(__dirname, 'src/js/globals.js'), path.resolve(__dirname, 'src/js/Trigger.js'), @@ -15,7 +17,7 @@ const config = { path.resolve(__dirname, 'src/js/Physics.js'), path.resolve(__dirname, 'src/js/drums.js'), path.resolve(__dirname, 'src/js/InstrumentMappings.js'), - path.resolve(__dirname, 'src/js/Fire.js'), + path.resolve(__dirname, 'src/js/Flame.js'), path.resolve(__dirname, 'src/js/Light.js'), path.resolve(__dirname, 'src/js/app.js'), path.resolve(__dirname, 'src/js/Audio.js'),