UNPKG

marching

Version:

Marching.js is a JavaScript library that compiles GLSL ray marchers.

153 lines (129 loc) 3.57 kB
module.exports = ` /* __--__--__--__--__--__--__--____ Audio-Reactive Visuals marching.js will perform an FFT analysis of any sound/music fed to the browser. When you first start the FFT, you'll be asked to choose an audio device to listen to. You can later change this in Chrome by clicking on the camera icon in the browser window's location bar. By using software like SoundFlower or JACK you can virtually route audio from your favorite music software into marching.js... or you can simply use a microphone / standard audio input. __--__--__--__--__--__--__--____ */ // create a scene to play with march( si = StairsIntersection( Sphere(2).material( 'white' ), repeat = Repeat( sphere = Sphere(.125), Vec3(.5) ), .125 ) ).render( 4, true ) // start our FFT FFT.start() // animate onframe = time => { si.rotate( time * 15 ) // our FFT object has low,mid, and high // properties that we can assign to elements // of our ray marching scene repeat.distance.x = FFT.low repeat.distance.y = FFT.mid repeat.distance.z = FFT.high sphere.radius = FFT.mid * FFT.high } si.d = 4 si.c = .5 /* __--__--__--__--__--__--__--____ increasing the window size (how many samples of audio the FFT looks at) will result in less hectic animations. The window size must be a power of 2; doubling and halving it is an easy way to experiment with different sizes. __--__--__--__--__--__--__--____ */ // run multiple times for greater effect FFT.windowSize *= 2 /* __--__--__--__--__--__--__--____ One fun combinator use with the FFT is Switch, which enables you to alternate between two geometries depending on whether or not an input exceeds a certain threshold. __--__--__--__--__--__--__--____ */ // super-simple Switch example march( s = Switch( Sphere(), Box() ) ).render( 3, true ) // the threshold property is unhelpfully // named 'c' for now... onframe = t => s.c = t/2 % 1 // extending our first example with Switch... march( si = StairsIntersection( swt = Switch( s = Sphere(2).material('red'), b = Box(1.75).material('white') ), repeat = Repeat( sphere = Sphere(.125), Vec3(.25) ), .125/2 ), Plane( Vec3(0,1,0), 1.35 ) ) .fog(.25, Vec3(0) ) .render( 4, true ) onframe = t => { si.rotate( t * 15 ) // try scaling the FFT results // by different values to control // the switch effect swt.c = FFT.low * 1 repeat.distance.x = FFT.mid * FFT.low fft = (FFT.low + FFT.mid + FFT.high) // scale both our sphere and our box on every // frame, since we don't know which will be active s.radius = fft b.size = fft * .75 sphere.radius = FFT.high / 2 } /* __--__--__--__--__--__--__--____ By default, the FFT assigns frequences < 150 Hz o FFT.low, 150-1400Hz to FFT.mid, and all remaining frequencies to FFT.high. However, you can also define your own definitions by passing an array to FFT.start(); if you do this the averages will then be in FFT[0], FFT[1], FFT[2] etc. Below is the first example from this tutorial, modified to use more bins. __--__--__--__--__--__--__--____ */ march( si = StairsIntersection( Sphere(2).material( 'white' ), repeat = Repeat( sphere = Sphere(.125), Vec3(.5) ), .125 ) ).render( 4, true ) // start our FFT FFT.start([100,200,400,800,1600,3200,6400,12800,22050]) onframe = time => { si.rotate( time * 15 ) repeat.distance.x = FFT[0] repeat.distance.y = FFT[1] + FFT[2] repeat.distance.z = FFT[3] sphere.radius = FFT[4] * FFT[5] } `