email me!
< back

Evan Harwin

Mathematician, Data Scientist, Programmer.

Looking at Curl through Particle Simulation

In this demonstration (below) you can see the curl of the given function shown as the colour of the particles.

The source code is below:

raw file

            
var scene, camera, renderer, clock, tick // define world attributes as globals
var vel_funct, curl_funct, geometry, material, body, options // some throwaway variables ( for short term use )

// THE FUNCTION(s)
// ........ Edit Here to Change the Function 
// ........ to avoid writing a parser / something that differentiates functions 
// ........ the curl_funct should be equal to curl( vel_funct ), to change that you'll have to 
// ........ calculate the function using 2dCurl( r ) = ( r.y )dx - ( r.x )dy 

vel_funct = ( r ) => new THREE.Vector3( Math.sin( r.y ), Math.pow( r.x, 3 ), 0 ).multiplyScalar( 0.1 )
curl_funct = ( r ) => 3 * Math.pow( r.x, 2 ) - Math.cos( r.y )

// vel_funct = ( r ) => new THREE.Vector3( Math.sin( r.y * 5  ), 0, 0 )
// curl_funct = ( r ) => - 5 * Math.cos( r.y * 5 )

// vel_funct = ( r ) => new THREE.Vector3( -r.x, -r.y, 0 )
// curl_funct = ( r ) => 0

function build() {

    // SCENE
    scene = new THREE.Scene()

    //CLOCK
    clock = new THREE.Clock()
    tick = 0

    // CAMERA
    camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 )
    camera.position.z = 2

    // RENDERER
    renderer = new THREE.WebGLRenderer()
    renderer.setSize( window.innerWidth, window.innerHeight )
    document.body.appendChild( renderer.domElement )

    // PARTICLES
    particleSystem = new THREE.GPUParticleSystem( { maxParticles: 500000 } );
    scene.add( particleSystem )
    particleHandler = new ParticleHandler( vel_funct, curl_funct, 20, 0.1, 500000 )


}

function animate() {
    requestAnimationFrame( animate )
    particleHandler.tick()
    renderer.render( scene, camera )
}

class ParticleHandler {
    constructor( vel_funct, curl_funct, range, timeScale, spawnRate ) {
        options = {
                position: new THREE.Vector3(),
                positionRandomness: 0.1,
                velocity: new THREE.Vector3(),
                velocityRandomness: 0,
                color: 0xaa0000,
                colorRandomness: 0.5,
                turbulence: 0,
                lifetime: 1.5,
                size: 6,
                sizeRandomness: 10
        }
        this.timeScale = timeScale
        this.spawnRate = spawnRate
        this.range = range
        this.vel_funct = vel_funct
        this.curl_funct = curl_funct
    }
    tick() {
        var delta = clock.getDelta() * this.timeScale;
            tick += delta;
            if ( tick < 0 ) { tick = 0 };
            if ( delta > 0 ) {
                for ( var x = 0; x < this.spawnRate * delta; x++ ) {
                    options.position.x = ( Math.random( ) * this.range ) - this.range / 2
                    options.position.y = ( Math.random( ) * this.range ) - this.range / 2
                    options.velocity = this.vel_funct( options.position )
                    options.color = new THREE.Color( 0xaaaaaa ).add( new THREE.Color( 0xff0000 ).multiplyScalar( this.curl_funct( options.position ) ) )
                    particleSystem.spawnParticle( options )
                }
            }
            particleSystem.update( tick )
    }
}

build()
animate()