2

I have a particle system where all the particles are positioned at the same coordinates and one after another, in random directions, they (should) start orbiting the center of the scene forming a sphere.

What I managed to achieve until now is a group of Vector3 objects (the particles) that one after another start orbiting the center along the Z axis simply calculating their sine and cosine based on the current angle.

I'm not that good at math and I don't even know what to look for precisely.

Here's what I wrote:

var scene = new THREE.Scene();

let container = document.getElementById('container'), 
    loader = new THREE.TextureLoader(), 
    renderer, 
    camera, 
    maxParticles = 5000, 
    particlesDelay = 50, 
    radius = 50, 
    sphereGeometry, 
    sphere;

loader.crossOrigin = true;

function init() {

    let vw = window.innerWidth, 
        vh = window.innerHeight;

    renderer = new THREE.WebGLRenderer();
    renderer.setSize(vw, vh);
    renderer.setPixelRatio(window.devicePixelRatio);

    camera = new THREE.PerspectiveCamera(45, vw / vh, 1, 1000);
    camera.position.z = 200;
    camera.position.x = 30;
    camera.position.y = 30;
    camera.lookAt(scene.position);
    scene.add(camera);

    let controls = new THREE.OrbitControls(camera, renderer.domElement);

    let axisHelper = new THREE.AxisHelper(50);
    scene.add(axisHelper);

    container.appendChild(renderer.domElement);

    window.addEventListener('resize', onResize, false);

}

function onResize() {

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);    

}

function draw() {

    sphereGeometry = new THREE.Geometry();
    sphereGeometry.dynamic = true;

    let particleTexture = loader.load('https://threejs.org/examples/textures/particle2.png'), 
        material = new THREE.PointsMaterial({
            color: 0xffffff, 
            size: 3, 
            transparent: true, 
            blending: THREE.AdditiveBlending, 
            map: particleTexture, 
            depthWrite: false
        });

        for ( let i = 0; i < maxParticles; i++ ) {

            let vertex = new THREE.Vector3(radius, 0, 0);
            vertex.delay = Date.now() + (particlesDelay * i);
            vertex.angle = 0;
            sphereGeometry.vertices.push(vertex);

        }

        sphere = new THREE.Points(sphereGeometry, material);
        scene.add(sphere);

}

function update() {

    for ( let i = 0; i < maxParticles; i++ ) {

        let particle = sphereGeometry.vertices[i];

        if ( Date.now() > particle.delay ) {

            let angle = particle.angle += 0.01;

            particle.x = radius * Math.cos(angle);

            if ( i % 2 === 0 ) {
                particle.y = radius * Math.sin(angle);
            } else {
                particle.y = -radius * Math.sin(angle);
            }

        }


    }

    sphere.geometry.verticesNeedUpdate = true;

}

function render() {

    update();
    renderer.render(scene, camera);
    requestAnimationFrame(render);

}

init();
draw();
render();

And here's the JSFiddle if you want to see it live: https://jsfiddle.net/kekkorider/qs6s0wv2/

EDIT: Working example

Can someone please give me a hand?

Thanks in advance!

1 Answers1

3

You want each particle to rotate around a specific random axis. You can either let them follow a parametric equation of a circle in 3D space, or you can make use of THREE.js rotation matrices.

Right now all your particles are rotating round the vector (0, 0, 1). Since your particles start off on the x-axis, you want them all to rotate around a random vector in the y-z plane (0, y, z). This can be defined during the creation of the vertices:

vertex.rotationAxis = new THREE.Vector3(0, Math.random() * 2 - 1, Math.random() * 2 - 1);
vertex.rotationAxis.normalize();

now you can just call the THREE.Vector3.applyAxisAngle(axis, angle) method on each of your particles with the random rotation axis you created each update:

particle.applyAxisAngle(particle.rotationAxis, 0.01); 

To sum up, this is how it should look like:

draw():

...
for ( let i = 0; i < maxParticles; i++ ) {

    let vertex = new THREE.Vector3(radius, 0, 0);
    vertex.delay = Date.now() + (particlesDelay * i);
    vertex.rotationAxis = new THREE.Vector3(0, Math.random() * 2 - 1, Math.random() * 2 - 1);
    vertex.rotationAxis.normalize();
    sphereGeometry.vertices.push(vertex);
}
...

update():

...
for ( let i = 0; i < maxParticles; i++ ) {

    let particle = sphereGeometry.vertices[i];

    if ( Date.now() > particle.delay ) {
        particle.applyAxisAngle(particle.rotationAxis, 0.01); 
    }
}
...
micnil
  • 4,705
  • 2
  • 28
  • 39
  • 1
    Hi @micnil, your solution worked as a charm, thanks a lot for your help :) I added a link to a working example in case someone else needs it. – Francesco Michelini Apr 18 '17 at 21:19
  • @micnil Could you clarify something for me? I've been studying this example because it produces a really cool effect, and I plan on building a "black hole" scene. How does a `vertex.rotationAxis`, which is a Vector3 with a random y and z value, cause the particles to rotate in random directions? I've been poking at jsfiddle for a couple of days now and I still cannot understand what is creating this effect of particles forming a sphere. I see that `applyAxisAngle` is the magic that creates this, however, I don't understand why adjusting y and z for each particle's `rotationAxis` does this. – Alex Fallenstedt Apr 20 '17 at 23:49
  • 1
    @AlexFallenstedt Basically I created a vector that the particles can rotate around. Its a bit hard to explain in text in a comment without images and figures. But consider this version of your fiddle: [https://jsfiddle.net/qs6s0wv2/5/](https://jsfiddle.net/qs6s0wv2/5/). Try pressing "run" a coupl of times and you'll see how the particle behaves when its rotation axis changes. – micnil Apr 21 '17 at 16:33
  • 1
    @AlexFallenstedt Maybe even clearer: [https://jsfiddle.net/qs6s0wv2/7/](https://jsfiddle.net/qs6s0wv2/7/), see how the particle is always at right angle to the rotation axis. – micnil Apr 21 '17 at 16:45
  • This is clearing up a lot of confusion. thank you @micnil. :) – Alex Fallenstedt Apr 21 '17 at 19:50