Detect collision of instanced mesh and planes

Following up this topic of detecting rain drop collision with a Plane, i have this function bellow, using ray cast to find collision point and reset the rain drop (instanced mesh) whenever it get pass the collision point on the plane:

const intersectionPoints = []; // Array to store intersection points for visualization

function updateRainPositions() {
    intersectionPoints.length = 0; // Clear intersection points array

    raindrops.forEach((raindrop, index) => {
        // Update position
        raindrop.y -= raindrop.velocity; // Move the raindrop upward

        // Check if raindrop is out of screen
        if (raindrop.y < -3.5) {
            raindrop.y = 10; // Reset position above the screen
            raindrop.velocity = THREE.MathUtils.randFloat(0.1, 0.5); // Reset velocity
                // Raycast to check for collision with the plane and the roof
        const raycaster = new THREE.Raycaster(
              new THREE.Vector3(raindrop.x, raindrop.y, raindrop.z),
              new THREE.Vector3(0, -1, 0)
        let intersects = raycaster.intersectObjects([planeMesh, roofMesh]);

        let collided = false; // Flag to track collision
        let intersectionPoint = null; // Store intersection point

        // Check for intersection with the plane
        if (intersects.length > 0) {
            intersectionPoint = intersects[0].point; // Get the intersection point
            let check1 = intersectionPoint.y - raindrop.y;
            // collided = intersectionPoint.y <= raindrop.y; // Check if collision happened at or below the raindrop
            collided = check1 <= 0.001;
            // console.log(intersectionPoint.y);
        // Reset raindrop if collision detected
        if (collided) {
          // Store the intersection point for visualization

          // Check if raindrop passed the collision point
          if (raindrop.y < intersectionPoint.y) {
              console.log("passed collision point, resetting");

              // Reset raindrop position and velocity
              raindrop.y = 10; // Reset position above the screen
              raindrop.velocity = THREE.MathUtils.randFloat(0.1, 0.5); // Reset velocity

    // Update rainMesh positions
    for (let i = 0; i < gCount; i++) {
        const raindrop = raindrops[i];
        const matrix = new THREE.Matrix4().makeTranslation(raindrop.x, raindrop.y, raindrop.z);
        rainMesh.setMatrixAt(i, matrix);

    rainMesh.instanceMatrix.needsUpdate = true; // Update instance matrix

    // Visualize intersection points

However, no rain drop were reset when they pass through the collision point at all. I used a sphere to visualize the collision point. And it does show the sphere at each point till the rain drop fall through that point, which mean it did detect collision of the points. I also make a console log to print out whenever a rain drop get pass a collision point, but no message was printed out. What could be the problem here?

Such types of problems are easier to resolve by debugging. And as you are the only one that can debug the code, it is up to you. Here are a few suggestions:

  • simplify the code by removing all unnecessary things (e.g., for all intersections you can use just one raycaster, instead of creating a new raycaster for each raindrop in each frame)
  • make just one drop and debug how its coordinates change
  • use normal (non-instance) object and test your algorithm – if it is working, the issue might be with how you manage instancing, if it is not working, then the bug is not in the instancing
  • double check all values, for example, is gCount the same as raindrops.length?
  • check your axes, e.g. I am confused by this comment β€œMove the raindrop upward”. Is your scene upside-down?
  • try to make an online debuggable minimal program with ground, roof, and a few drops, if you still have problems with this simple program, then ask again for help (and provide a link).

Just out of curiousity: is it really need to be that physically correct, when a raindrop hits a surface, then it stars an effect at the exact spot of the hitting?
Maybe it’s enough to show ripples on surfaces, generated with noise in shaders?

1 Like