jcode/skills/threejs-csg/csg.md

1.9 KiB

Boolean operations with three-bvh-csg

import { Brush, Evaluator, ADDITION, SUBTRACTION, INTERSECTION, DIFFERENCE } from 'three-bvh-csg';

(already mapped in the import map of template.html)

Rules

  • CSG operands are Brush objects (a Mesh subclass): new Brush(geometry, material).
  • Place the brush (position, rotation, scale), then call brush.updateMatrixWorld(); the evaluator works on world matrices.
  • const ev = new Evaluator(); ev.useGroups = false; - then the result is one mesh that takes the material you assign (result.material = mat).
  • ev.evaluate(a, b, OP) returns a NEW Brush. Add the result to the scene, not the operands.
  • Chain operations by reusing the result: part = ev.evaluate(part, nextTool, SUBTRACTION).
  • Curved cuts need enough segments: new THREE.CylinderGeometry(r, r, h, 48).
  • Make the cutting tool slightly longer than the solid (cube size 2 -> cylinder height 2.2). Exactly coplanar faces produce artifacts.
  • Results have no smooth normals across the cut; call result.geometry.computeVertexNormals() only if the shading looks wrong (flat shading is usually fine for CAD-like parts).

Operations

Constant Result
ADDITION union of a and b
SUBTRACTION a minus b (holes, pockets)
INTERSECTION volume shared by a and b
DIFFERENCE symmetric difference (a xor b)

Example: cube with a through-hole

const mat  = new THREE.MeshStandardMaterial({ color: 0x4488ff, metalness: 0.2, roughness: 0.5 });
const cube = new Brush(new THREE.BoxGeometry(2, 2, 2), mat);
const hole = new Brush(new THREE.CylinderGeometry(0.5, 0.5, 2.2, 48), mat);
hole.rotation.x = Math.PI / 2;          // cylinder axis along z
cube.updateMatrixWorld(); hole.updateMatrixWorld();

const ev = new Evaluator(); ev.useGroups = false;
const part = ev.evaluate(cube, hole, SUBTRACTION);
part.material = mat;
scene.add(part);