Three.JS-沿随机方向围绕点旋转的粒子,形成球体

Three.JS-沿随机方向围绕点旋转的粒子,形成球体,three.js,particle-system,Three.js,Particle System,我有一个粒子系统,所有的粒子都被放置在相同的坐标上,一个接一个,在随机的方向上,它们(应该)开始围绕场景的中心旋转,形成一个球体 到目前为止,我一直努力实现的是一组矢量3对象(粒子),它们一个接一个地开始沿着Z轴围绕中心旋转,只是根据当前角度计算它们的正弦和余弦 我的数学不是很好,我甚至不知道该找什么 以下是我写的: var scene = new THREE.Scene(); let container = document.getElementById('container'),

我有一个粒子系统,所有的粒子都被放置在相同的坐标上,一个接一个,在随机的方向上,它们(应该)开始围绕场景的中心旋转,形成一个球体

到目前为止,我一直努力实现的是一组矢量3对象(粒子),它们一个接一个地开始沿着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();
var scene=new THREE.scene();
让container=document.getElementById('container'),
loader=新的三个.TextureLoader(),
渲染器,
摄像机,
最大粒子数=5000,
particlesDelay=50,
半径=50,
旋光法,
球体;
loader.crossOrigin=true;
函数init(){
设vw=window.innerWidth,
vh=窗内高度;
renderer=new THREE.WebGLRenderer();
渲染器。设置大小(vw、vh);
renderer.setPixelRatio(window.devicePixelRatio);
摄像机=新的三视角摄像机(45,vw/vh,11000);
摄像机位置z=200;
摄像机位置x=30;
摄像机位置y=30;
摄像机。注视(场景。位置);
场景。添加(摄影机);
let controls=新的三个.OrbitControls(摄影机、渲染器.doElement);
设axisHelper=new-THREE.axisHelper(50);
添加(axisHelper);
container.appendChild(renderer.domeElement);
addEventListener('resize',onResize,false);
}
函数onResize(){
camera.aspect=window.innerWidth/window.innerHeight;
camera.updateProjectMatrix();
renderer.setSize(window.innerWidth、window.innerHeight);
}
函数绘图(){
球面测量法=新的三点几何();
sphereGeometry.dynamic=真;
让particlexture=loader.load('https://threejs.org/examples/textures/particle2.png'), 
材料=新的三点材料({
颜色:0xffffff,
尺寸:3,
透明:是的,
混合:3.可加性贷款,
地图:particlexture,
depthWrite:false
});
for(设i=0;iparticle.delay){
让角度=粒子。角度+=0.01;
粒子x=半径*数学cos(角度);
如果(i%2==0){
粒子y=半径*数学sin(角度);
}否则{
particle.y=-半径*Math.sin(角度);
}
}
}
sphere.geometry.verticesNeedUpdate=true;
}
函数render(){
更新();
渲染器。渲染(场景、摄影机);
请求动画帧(渲染);
}
init();
draw();
render();
如果您想看现场直播,这里是JSFIDLE:

编辑

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

    let particle = sphereGeometry.vertices[i];

    if ( Date.now() > particle.delay ) {
        particle.applyAxisAngle(particle.rotationAxis, 0.01); 
    }
}
...
谁能帮我一下吗


提前谢谢

希望每个粒子围绕特定的随机轴旋转。可以让它们在3D空间中跟随a,也可以使用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(设i=0;i
更新()

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

    let particle = sphereGeometry.vertices[i];

    if ( Date.now() > particle.delay ) {
        particle.applyAxisAngle(particle.rotationAxis, 0.01); 
    }
}
...
。。。
for(设i=0;iparticle.delay){
粒子应用轴角(粒子旋转轴,0.01);
}
}
...

Hi@micnil,你的解决方案很有魅力,非常感谢你的帮助:)我添加了一个指向工作示例的链接,以备其他人需要。@micnil你能帮我澄清一下吗?我一直在研究这个例子,因为它产生了一个非常酷的效果,我计划构建一个“黑洞”场景。具有随机y和z值的向量3的
顶点旋转轴如何导致粒子沿随机方向旋转?我已经戳了JSFIDLE好几天了,我仍然不明白是什么造成了粒子形成球体的这种效果。我知道
applyAxisAngle
是产生这种效果的魔法,但是,我不明白为什么为每个粒子的
rotationAxis
调整y和z可以做到这一点。@AlexFallenstedt基本上我创建了一个粒子可以旋转的向量。在没有图片和数字的评论中用文字解释有点困难。但是想想你小提琴的这个版本:尝试按“运行”几次,您将看到粒子在其旋转轴发生变化时的行为。@AlexFallenstedt可能更清楚:,查看粒子如何始终与旋转轴成直角。这将消除许多混淆。谢谢@micnil.)