How fill a loaded STL mesh ( NOT SIMPLE SHAPES LIKE CUBE ETC) with random particles and animate with this geometry bound in three.js

How I can fill a loaded STL mesh ( like Suzanne but NOT SIMPLE SHAPES LIKE CUBE etc) with random particles and animate it inside this geometry bounds with three.js ?

I see many examples but all of it for simple shapes with geometrical bounds like cube or sphere with limit by coordinates around center

was found this example: but it’s another solution when using vertexes of geometry of mesh like points material… I already do it , but how I can fill volume of this meshes?
I need algorithm to detect coordinates includes in the mesh volume ((
Also I think about raycasting from center of mesh, but this method also cant cover all volume of complex meshes (


You can “raycast” your mesh with infinite ray from the desired point with the direction, for example, [1, 0, 0] against all the triangles in the mesh and count how many triangles were intersected. If the number of interstected faces is odd, then the point is inside the mesh.

But if mesh have a not convex shape? for ex shape of letter G extruded and you trace ?

may be existed some example of this method in three.js code?

I’m working on its concept :slight_smile:


I think about another method about slice of object for the first with Z and then by Y and after that by X and we have lines with only one coordinates for testing, but I think performance in this case is not so good as raycasing… will wait your concept :star_struck:

Okay, here it is. Works like I said: counts the number of intersected faces, and if it’s odd, then a point is inside of a mesh (geometry):

  function fillWithPoints(geometry, count) {
    var ray = new THREE.Ray()
    var size = new THREE.Vector3();
    let bbox = geometry.boundingBox;
    let points = [];
    var dir = new THREE.Vector3(1, 1, 1).normalize();
    for (let i = 0; i < count; i++) {
      let p = setRandomVector(bbox.min, bbox.max);
    function setRandomVector(min, max){
      let v = new THREE.Vector3(
        THREE.Math.randFloat(min.x, max.x),
        THREE.Math.randFloat(min.y, max.y),
        THREE.Math.randFloat(min.z, max.z)
      if (!isInside(v)){return setRandomVector(min, max);}
      return v;
    function isInside(v){
      ray.set(v, dir);
      let counter = 0;
      let pos = geometry.attributes.position;
      let faces = pos.count / 3;
      let vA = new THREE.Vector3(), vB = new THREE.Vector3(), vC = new THREE.Vector3();

      for(let i = 0; i < faces; i++){
        vA.fromBufferAttribute(pos, i * 3 + 0);
        vB.fromBufferAttribute(pos, i * 3 + 1);
        vC.fromBufferAttribute(pos, i * 3 + 2);
        if (ray.intersectTriangle(vA, vB, vC)) counter++;
      return counter % 2 == 1;
    return new THREE.BufferGeometry().setFromPoints(points);