Three.JS - 粒子以随机方向围绕一个点形成一个球体

Three.JS - Particles orbiting a point in random directions forming a sphere

我有一个粒子系统,其中所有粒子都位于同一坐标,一个接一个,随机方向,它们(应该)开始围绕场景的中心形成一个球体。

到目前为止,我设法实现的是一组 Vector3 对象(粒子),它们一个接一个地开始沿 Z 轴绕中心运行,只需根据当前角度计算它们的正弦和余弦。

我的数学不太好,我什至不知道该找什么。

这是我写的:

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();

如果你想现场观看,这里是 JSFiddle: https://jsfiddle.net/kekkorider/qs6s0wv2/

编辑Working example

有人可以帮帮我吗?

提前致谢!

您希望每个粒子围绕特定的随机轴旋转。您可以让它们在 3D space 中跟随 parametric equation of a circle,或者您可以使用 THREE.js 旋转矩阵。

现在所有的粒子都在围绕向量 (0, 0, 1) 旋转。由于您的粒子从 x 轴开始,您希望它们全部围绕 y-z 平面 (0, y, z) 中的随机向量旋转。这可以在创建顶点时定义:

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

现在您可以使用每次更新创建的随机旋转轴对每个粒子调用 THREE.Vector3.applyAxisAngle(axis, angle) 方法:

particle.applyAxisAngle(particle.rotationAxis, 0.01); 

总而言之,它应该是这样的:

绘图():

...
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);
}
...

更新():

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

    let particle = sphereGeometry.vertices[i];

    if ( Date.now() > particle.delay ) {
        particle.applyAxisAngle(particle.rotationAxis, 0.01); 
    }
}
...