3

I am trying to create a random point within a sphere, and I am not sure how to do this. I came up with this but I think it is returning a point within a cube I think I have to do something with Math.PI but not sure how.

  #createParticlePosition() {
    const shape = this.options.shape;
    // shape.radius = 2;
    if (shape.type === 'sphere') {
      return new Three.Vector3(
        (Math.random() * shape.radius - (shape.radius / 2)) * 1.0,
        (Math.random() * shape.radius - (shape.radius / 2)) * 1.0,
        (Math.random() * shape.radius - (shape.radius / 2)) * 1.0
      );
    }
  }
M -
  • 26,908
  • 11
  • 49
  • 81
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338
  • 1
    Does this answer your question? [Random Point on a given Sphere](https://stackoverflow.com/questions/5531827/random-point-on-a-given-sphere) – kelsny Oct 27 '22 at 22:48

2 Answers2

4

You are indeed just creating boxes. You're only calculating the x,y,z values linearly, not spherically. Three.js has a Vector3.randomDirection method that could do these calculations for you:

const maxRadius = 2;

// Randomize to range [0, 2]
const randomRadius = Math.random() * maxRadius;

// Create vec3
const randomVec = new THREE.Vector3();

// Make vector point in a random direction with a radius of 1
randomVec.randomDirection();

// Scale vector to match random radius
randomVec.multiplyScalar(randomRadius);

This method utilizes this approach internally to avoid density accumulation in the poles.

enter image description here

M -
  • 26,908
  • 11
  • 49
  • 81
1

To distribute points inside a sphere evenly, having direction and radius, the radius computes with Math.sqrt( r * r * Math.random());

In the snippet, the red point cloud utilizes simple r * Math.random(), the aqua one utilizes that I wrote above:

body{
  overflow: hidden;
  margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three@0.136.0";
import {OrbitControls} from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/controls/OrbitControls";

let scene = new THREE.Scene();
scene.background = new THREE.Color(0x160016);
let camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 8);
let renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", event => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
})

let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.enablePan = false;

let pts = new Array(1000).fill().map(p => {
  let rMax = 2 * Math.random();
  return new THREE.Vector3().randomDirection().multiplyScalar(rMax);
})

let g = new THREE.BufferGeometry().setFromPoints(pts);
let m = new THREE.PointsMaterial({size: 0.1, color: "red"})
let p = new THREE.Points(g, m);
p.position.x = -2;
scene.add(p)

let pts2 = new Array(1000).fill().map(p => {
  let rMax = 2;
  let r = Math.sqrt(rMax * rMax * Math.random());
  return new THREE.Vector3().randomDirection().multiplyScalar(r);
})

let g2 = new THREE.BufferGeometry().setFromPoints(pts2);
let m2 = new THREE.PointsMaterial({size: 0.1, color: "aqua"})
let p2 = new THREE.Points(g2, m2);
p2.position.x = 2;
scene.add(p2)

renderer.setAnimationLoop(() => {
  controls.update();
  renderer.render(scene, camera);
});
</script>

For reference: https://discourse.threejs.org/t/random-points-on-surfaces/34153

prisoner849
  • 16,894
  • 4
  • 34
  • 68