Home > Software design >  only one particle showing in the scene with three.js
only one particle showing in the scene with three.js

Time:04-07

I am trying to create a sphere with particles randomly floating on its surface. It will move depends on the position on mousemove. something like this enter image description here

Strangely, it is only displaying one particle on canvas. I am debugging with console.log(vertices), but it clearly shows all the vertices in the array.

My code in CodeSandBox

CodePudding user response:

The problem is with your loop. You're assigning a value to theta and phi only once outside your loop, then you give the same value to all 1600 vertices:

const theta = Math.acos(THREE.Math.randFloatSpread(2));
const phi = THREE.Math.randFloatSpread(360);

for (let i = 0; i < 1600; i  ) {
  const vertex = new THREE.Vector3();

  vertex.x = distance * Math.sin(theta) * Math.cos(phi);
  vertex.y = distance * Math.sin(theta) * Math.sin(phi);
  vertex.z = distance * Math.cos(theta);

  vertices.push(vertex.x, vertex.y, vertex.z);
}

When you use console.log(vertices), look at the x, y, z values and you'll see they all repeat.

What you should do is re-assign a new theta and a new phi inside the loop, so each vertex gets a unique position:

let theta, phi;
let x, y, z;

for (let i = 0; i < 1600; i  ) {
  theta = Math.acos(THREE.Math.randFloatSpread(2));
  phi = THREE.Math.randFloatSpread(360);

  x = distance * Math.sin(theta) * Math.cos(phi);
  y = distance * Math.sin(theta) * Math.sin(phi);
  z = distance * Math.cos(theta);

  vertices.push(x, y, z);
}

You also don't need to create a THREE.Vector3() on each iteration, it's pretty inefficient to create 1600 Vector3s just to be discarded immediately. Instead you can re-use the same x, y, z variables to avoid all those object construction costs.

See here for a working demo of your example. I also scaled down the point size to 1.

CodePudding user response:

Just a small remark, not the answer (all kudos to @Marquizzo)

Since r133, there is a method .randomDirection() of THREE.Vector3(), which helps us to set points on a sphere in a more convenient way.

Thus, all the code for instantiating of particles is:

    const distance = Math.min(200, window.innerWidth / 16);
    let vertices = new Array(1600).fill().map((v) => {
      return new THREE.Vector3().randomDirection().setLength(distance);
    });
    const geometry = new THREE.BufferGeometry().setFromPoints(vertices);
    const material = new THREE.PointsMaterial({ color: 0xffffff, size: 1 });
    const particles = new THREE.Points(geometry, material);

Demo

  • Related