javascriptreactjsthree.jsreact-three-fiberreact-three-drei

Three.js concave shape from point cloud


I am currently struggling to create shapes in three.js dynamically from the point cloud. Hence I am using ConvexGeometry, it works perfectly fine for convex shapes and it is getting difficult when I need a concave shape.

I am drawing a line on the 2D plane (red line from screenshot) then I take all points from the line or curve, clone them, and rotate around the x axis. And now when I have a point cloud, I wish I could simply make a shape. Here are the results: rendering shapes As you can see 2nd and 3rd segments look good but for the first one mesh isn't covering points as I need. rendering concave shape I need any suggestions or ideas on how to achieve the desired results.

Here is my component rendering a shape:

import { Vector3 } from "three";
import { ConvexGeometry } from "three/examples/jsm/Addons.js";

type PointsToGeometryProps = {
  pointsData: number[][];
};

export function PointsToGeometry({ pointsData }: PointsToGeometryProps) {
  const axis = new Vector3(1, 0, 0);
  const basePoints = pointsData.map((p) => new Vector3(p[0], p[1], p[2]));
  const rotations = 100;
  const points = [...basePoints];

  for (let i = 1; i <= rotations; i++) {
    const angle = (i * 2 * Math.PI) / rotations;
    const rotatedPoints = basePoints
      .map((p) => {
        if (!p.y) return;
        return p.clone().applyAxisAngle(axis, angle);
      })
      .filter((p) => p);

    points.push(...(rotatedPoints as Vector3[]));
  }

  const geometry = new ConvexGeometry(points);

  return (
      <mesh geometry={geometry}>
        <meshStandardMaterial />
      </mesh>
  );
}

Thanks in advance


Solution

  • I wanted to share the solution I found for my problem. It turns out that the LatheGeometry class from the Three.js library is exactly what I needed. I can't believe I overlooked it for so long. If anyone else encounters a similar issue, I highly recommend using LatheGeometry. Here’s the updated code snippet that worked for me:

    import { LatheGeometry, Vector2 } from "three";
    
    type PointsToGeometryProps = {
      pointsData: Vector2[];
    };
    
    export function PointsToGeometry({ pointsData }: PointsToGeometryProps) {
      const rotations = 100;
      const rotatedPoints = pointsData.map((p) =>
        p.rotateAround(new Vector2(0, 0), Math.PI / 2)
      );
    
      const geometry = new LatheGeometry(rotatedPoints, rotations).rotateZ(
        -Math.PI / 2
      );
    
      return (
        <mesh geometry={geometry}>
          <meshStandardMaterial />
        </mesh>
      );
    }
    

    I hope this helps someone else!