diff --git a/sounds/music.mp3 b/sounds/music.mp3 new file mode 100644 index 0000000..475be1b Binary files /dev/null and b/sounds/music.mp3 differ diff --git a/sounds/music2.mp3 b/sounds/music2.mp3 new file mode 100644 index 0000000..d993666 Binary files /dev/null and b/sounds/music2.mp3 differ diff --git a/src/main.js b/src/main.js index 5fa221d..f3bd585 100644 --- a/src/main.js +++ b/src/main.js @@ -2,48 +2,167 @@ const THREE = require('three'); // older modules are imported like this. You shouldn't have to worry about this much import Framework from './framework' +// Colors +var additionalControls = { + 'Color' : [255, 255, 255], + 'scale' : 1., + 'music' : true, + 'inv persistence' : 2., + 'radius' : 0.7, + 'detail' : 6. +}; + +// Local global to allow for modifying variables +var noiseCloud = { + mesh : {}, +}; + // called after the scene loads function onLoad(framework) { - var scene = framework.scene; - var camera = framework.camera; - var renderer = framework.renderer; - var gui = framework.gui; - var stats = framework.stats; - - // LOOK: the line below is synyatic sugar for the code above. Optional, but I sort of recommend it. - // var {scene, camera, renderer, gui, stats} = framework; - - // initialize a simple box and material - var box = new THREE.BoxGeometry(1, 1, 1); - - var adamMaterial = new THREE.ShaderMaterial({ - uniforms: { - image: { // Check the Three.JS documentation for the different allowed types and values - type: "t", - value: THREE.ImageUtils.loadTexture('./adam.jpg') - } - }, - vertexShader: require('./shaders/adam-vert.glsl'), - fragmentShader: require('./shaders/adam-frag.glsl') - }); - var adamCube = new THREE.Mesh(box, adamMaterial); - - // set camera position - camera.position.set(1, 1, 2); - camera.lookAt(new THREE.Vector3(0,0,0)); - - scene.add(adamCube); - - // edit params and listen to changes like this - // more information here: https://workshop.chromeexperiments.com/examples/gui/#1--Basic-Usage - gui.add(camera, 'fov', 0, 180).onChange(function(newVal) { - camera.updateProjectionMatrix(); - }); + var scene = framework.scene; + var camera = framework.camera; + var renderer = framework.renderer; + var gui = framework.gui; + var stats = framework.stats; + + // LOOK: the line below is synyatic sugar for the code above. Optional, but I sort of recommend it. + // var {scene, camera, renderer, gui, stats} = framework; + var adamMaterial = new THREE.ShaderMaterial({ + uniforms: { + image: { // Check the Three.JS documentation for the different allowed types and values + type: "t", + value: THREE.ImageUtils.loadTexture('./adam.jpg') + }, + inv_persistence: { + type: "f", + value: 2.0 + }, + time: { + type: "f", + value: 0. + }, + music: { + type: "f", + value: 1. + }, + music2: { + type: "f", + value: 1. + }, + colorMult: { + value: new THREE.Vector3(additionalControls['Color'][0]/255, additionalControls['Color'][1]/255, additionalControls['Color'][2]/255,) + } + }, + vertexShader: require('./shaders/adam-vert.glsl'), + fragmentShader: require('./shaders/adam-frag.glsl') + }); + + var iso = new THREE.IcosahedronBufferGeometry(0.7, 6); + noiseCloud.mesh = new THREE.Mesh(iso, adamMaterial); + noiseCloud.mesh.name = "adamCube"; + + // set camera position + camera.position.set(1, 1, 6); + camera.lookAt(new THREE.Vector3(0,0,0)); + + scene.add(noiseCloud.mesh); + + // edit params and listen to changes like this + // more information here: https://workshop.chromeexperiments.com/examples/gui/#1--Basic-Usage + gui.add(camera, 'fov', 0, 180).onChange(function(newVal) { + camera.updateProjectionMatrix(); + }); + + gui.add(additionalControls, 'inv persistence', 1., 10.).onChange(function(newVal) { + noiseCloud.mesh.material.uniforms.inv_persistence.value = newVal; + }); + + gui.add(additionalControls, 'music').onChange(function(newVal) { + additionalControls.music = newVal; + }); + + // Color menu + gui.addColor(additionalControls, 'Color').onChange(function(newVal) { + noiseCloud.mesh.material.uniforms.colorMult.value = new THREE.Vector3(newVal[0]/255, newVal[1]/255, newVal[2]/255,); + }); + + + // Audio stuff below + // http://raathigesh.com/Audio-Visualization-with-Web-Audio-and-ThreeJS/ + // http://stackoverflow.com/questions/27589179/basic-web-audio-api-not-playing-a-mp3-file + // http://stackoverflow.com/questions/3273552/html5-audio-looping + var context = new AudioContext(); + var jsNode = context.createScriptProcessor(2048,1,1); + jsNode.connect(context.destination); + + // Load file and set to repeat + var audio = new Audio(); + audio.src = "./sounds/music2.mp3"; //https://www.jamendo.com/track/1350213/jumper + audio.controls = true; + audio.autoplay = true; + audio.addEventListener('ended', function(){ + this.currentTime = 0; + this.play(); + }, false); + audio.loop = true; + + // Play file + var source = context.createMediaElementSource(audio); + source.connect(context.destination); + source.mediaElement.play(); + + // Analyze waveform data + var analyser = context.createAnalyser(); + analyser.fftSize = 128; + analyser.smoothingTimeConstat = 0.8; + source.connect(analyser); + + // Action to take with processed data + jsNode.onaudioprocess = function () { + + // If music sync box is checked + if (additionalControls.music) { + var array = new Uint8Array(analyser.frequencyBinCount); + analyser.getByteFrequencyData(array); + // console.log(analyser.maxDecibels) + + var Z = [array.slice(0, 9).reduce((a, b) => a + b, 0) / 10 /256, + array.slice(10, 19).reduce((a, b) => a + b, 0) / 10 /256, + array.slice(20, 29).reduce((a, b) => a + b, 0) / 10 /256, + array.slice(30, 39).reduce((a, b) => a + b, 0) / 10 /256, + array.slice(40, 49).reduce((a, b) => a + b, 0) / 10 /256, + array.slice(50, 59).reduce((a, b) => a + b, 0) / 10 /256]; + // console.log(Z); + + noiseCloud.mesh.material.uniforms.music.value = Z[4]; + noiseCloud.mesh.material.uniforms.music2.value = Z[1]; + } else { + noiseCloud.mesh.material.uniforms.music.value = 1.; + noiseCloud.mesh.material.uniforms.music2.value = 0.; + } + + + } + + } // called on frame updates function onUpdate(framework) { - console.log(`the time is ${new Date()}`); + + + framework.scene.traverse(function (object) + { + if (object instanceof THREE.Mesh) + { + if (object.name === 'adamCube') { + // var d = new Date(); + // console.log(`the time is ${(object.material.uniforms.time.value)}`); + object.material.uniforms.time.value += .01; + + } + } + }); } // when the scene is done initializing, it will call onLoad, then on frame updates, call onUpdate diff --git a/src/shaders/adam-frag.glsl b/src/shaders/adam-frag.glsl index 64ca0e0..dd579bf 100644 --- a/src/shaders/adam-frag.glsl +++ b/src/shaders/adam-frag.glsl @@ -1,12 +1,16 @@ varying vec2 vUv; +varying vec3 nor; varying float noise; +varying float mus; + uniform sampler2D image; +uniform vec3 colorMult; void main() { vec4 color = texture2D( image, vUv ); - gl_FragColor = vec4( color.rgb, 1.0 ); - + gl_FragColor = vec4( (1. - noise) * nor.rgb + noise * colorMult, 1.0 ); + // gl_FragColor = vec4( mus * color.rgb, 1.0 ); } \ No newline at end of file diff --git a/src/shaders/adam-vert.glsl b/src/shaders/adam-vert.glsl index e4b8cc0..b821a35 100644 --- a/src/shaders/adam-vert.glsl +++ b/src/shaders/adam-vert.glsl @@ -1,6 +1,82 @@ varying vec2 vUv; +varying vec3 nor; +varying float noise; +varying float mus; + +uniform float inv_persistence; +uniform float time; +uniform float music; +uniform float music2; + +#define M_PI 3.14159265 +const int N_OCTAVES = 5; + +float sampleNoise(vec3 pos) { + float x = fract(sin(dot(pos, vec3(134.9235, 63.5879, 218.9542))) * 27495.2467); + return x; +} + +float interpolate(float a, float b, float t) { + float cos_t = (1. - cos(t * M_PI)) * 0.5; + return a * (1. - cos_t) + b * cos_t; +} + +float interpNoise(vec3 pos, float f) { + + // Calculate the min/max positions of cube + vec3 p0 = floor(pos * f) / f; + vec3 p1 = p0 + 1. / f; + vec3 t = (pos - p0) * f; + + // Find noise values at corners of cube + float A = sampleNoise(vec3(p0.x, p0.y, p0.z)); + float E = sampleNoise(vec3(p1.x, p0.y, p0.z)); + + float B = sampleNoise(vec3(p0.x, p1.y, p0.z)); + float F = sampleNoise(vec3(p1.x, p1.y, p0.z)); + + float C = sampleNoise(vec3(p0.x, p0.y, p1.z)); + float G = sampleNoise(vec3(p1.x, p0.y, p1.z)); + + float D = sampleNoise(vec3(p0.x, p1.y, p1.z)); + float H = sampleNoise(vec3(p1.x, p1.y, p1.z)); + + // First pass of interpolation + float interpLi_AE = interpolate(A, E, t.x); + float interpLi_BF = interpolate(B, F, t.x); + float interpLi_CG = interpolate(C, G, t.x); + float interpLi_DH = interpolate(D, H, t.x); + + // Second pass of interpolation + float interpBi_12 = interpolate(interpLi_AE, interpLi_BF, t.y); + float interpBi_34 = interpolate(interpLi_CG, interpLi_DH, t.y); + + // Third pass + return interpolate(interpBi_12, interpBi_34, t.z); +} + +float multiOctaveNoise(float offset) { + + float total = 0.; + float persistence = 1. / inv_persistence; + + for (int i = 0; i < N_OCTAVES; i++) { + + float frequency = pow(2., float(i)); + float amplitude = pow(persistence, float(i)); + total += interpNoise(position + offset, frequency) * amplitude; + } + + return total; +} + void main() { vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); -} \ No newline at end of file + mus = music; + + noise = multiOctaveNoise(time); + nor = vec3(projectionMatrix * modelViewMatrix * vec4(normal, 0.)); + gl_Position = projectionMatrix * modelViewMatrix * vec4(position + noise * nor * music, 1.); +} +