three-bvh-csg
Version:
A fast, flexible, dynamic CSG implementation on top of three-mesh-bvh
309 lines (190 loc) • 9.37 kB
Markdown
# three-bvh-csg
[](https://www.npmjs.com/package/three-bvh-csg)
[](https://github.com/gkjohnson/three-bvh-csg/actions)
[](https://github.com/gkjohnson/three-bvh-csg/)
[](https://twitter.com/garrettkjohnson)
[](https://github.com/sponsors/gkjohnson/)

An _experimental, in progress_, flexible, memory compact, fast and dynamic CSG implementation on top of [three-mesh-bvh](https://github.com/gkjohnson/three-mesh-bvh). More than 100 times faster than other BSP-based three.js CSG libraries in complex cases. Contributions welcome!
> **Note**
> All brush geometry must be [two-manifold](https://knowledge.autodesk.com/support/maya-lt/learn-explore/caas/CloudHelp/cloudhelp/2015/ENU/MayaLT/files/Polygons-overview-Twomanifold-vs--nonmanifold-polygonal-geometry-htm.html) - or water tight with no triangle interpenetration.
> **Warning**
> Due to numerical precision and corner cases resulting geometry may not be correctly completely two-manifold.
# Roadmap / Help Wanted
- Fix triangle splitting / missing triangle issues [#73](https://github.com/gkjohnson/three-bvh-csg/issues/73) [#68](https://github.com/gkjohnson/three-bvh-csg/issues/68)
- Polygon splitting & triangulation [#51](https://github.com/gkjohnson/three-bvh-csg/issues/51)
- Worker Support [#14](https://github.com/gkjohnson/three-bvh-csg/issues/14)
[And more!](https://github.com/gkjohnson/three-bvh-csg/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
# Examples
[Simple CSG](https://gkjohnson.github.io/three-bvh-csg/examples/bundle/simple.html)
[Complex Model CSG](https://gkjohnson.github.io/three-bvh-csg/examples/bundle/geometry.html)
[Multimaterial CSG](https://gkjohnson.github.io/three-bvh-csg/examples/bundle/multimaterial.html)
[Hierarchical Operations](https://gkjohnson.github.io/three-bvh-csg/examples/bundle/hierarchy.html)
# Use
```js
import { SUBTRACTION, Brush, Evaluator } from 'three-bvh-csg';
import { MeshStandardMaterial, Mesh, SphereGeometry, BoxGeometry } from 'three';
const csgEvaluator = new Evaluator();
const brush1 = new Brush( new SphereGeometry() );
const brush2 = new Brush( new BoxGeometry() );
const result = csgEvaluator.evaluate( brush1, brush2, SUBTRACTION );
// render the result!
```
# API
## Constants
### CSGOperations
CSG operations enums for use with `Evaluator`.
```
ADDITION
SUBTRACTION
DIFFERENCE
INTERSECTION
```
## Brush
_extends THREE.Mesh_
An object with the same interface as `THREE.Mesh` but used to evaluate CSG operations. Once a brush is created the geometry should not be modified.
> **Note**
>
> It is recommended to remove groups from a geometry before creating a brush if multi-material support is not required.
## Operation
_extends Brush_
This is an extension of the `Brush` class. With this class is possible to create a mesh and pass the CSG Operation constant to define which operation computes on the mesh. The result is a Mesh whose effect is defined from the operation selected. You can see how it works in the _hierarchy_ example.
### .operation
```js
operation = ADDITION : CSGOperation
```
The operation to perform on the next brush in processing chain when running `Evaluater.evaluateHierarchy`.
### .insertBefore
```js
insertBefore( brush : Brush )
```
Inserts the brush before the operation element that calls the method, in the list of the children of the operation's parent.
### .insertAfter
```js
insertAfter( brush : Brush )
```
Inserts the brush after the operation element that calls the method, in the list of the children of the operation's parent.
## OperationGroup
_extends THREE.Group_
A class with the same interface as `THREE.Group` but used to group a list of Operation mesh through the `.add` method inherited from the THREE.Group class. You can create a group starting from single Operation meshes as in the _hierarchy_ example.
## Evaluator
### .useGroups
```js
useGroups = true : Boolean
```
Whether to use geometry groups when processing the geometry. If geometry groups are used then a material array and groups will be assigned to the target `Brush` after processing. If groups are disabled then a single coherent piece of geometry with no groups will be produced.
### .evaluate
```js
evaluate(
brushA : Brush,
brushB : Brush,
operation : CSGOperation,
target = null : Brush | Mesh
) : Brush | Mesh
```
Performs the given `operation` on `brushA` with `brushB`. If no target is provided then a new `Brush` will be created with the new geometry. Otherwise the provided Brush will be _modified in place_ and geometry disposed or marked for update as needed.
### .evaluateHierarchy
```js
evaluateHierarchy(
root: Opertation,
target = new Brush : Brush | Mesh
) : Brush | Mesh
```
The method gets as parameters a root, an Operation mesh and a target if it is provided, otherwise, a new `Brush` will be created.
First sets the `updateMatrixWolrd` of the root to true then calls the traverse function with the root parameter to `evaluate` the mesh and its children.
```js
evaluate( brush, child, child.operation );
```
In this case, the arguments passed to `evaluate` is the `root` as `brushA`, the child as `brushB` and the `child.operation` as the operation to apply to the mesh.
## OperationDebugData
This class is used in the constructor of the Evaluator class. When the Evaluator is defined the constructor creates a debug property of type OperationDebugData and it is used to set the debug context, that is `addEdge` and `addIntersectionTriangles` to, for example, an EdgesHelper or a TriangleHelper.
### .enabled
```js
enabled = false : Boolean
```
Whether to collect the debug data during CSG operations which has a performance a memory cost.
### .intersectionEdges
```js
intersectionEdges = [] : Line3
```
A list of edges formed by intersecting triangles during the CSG process.
<!--
## EvaluatorWorker
_extends Evaluator_
### .evaluate
TODO
### .evaluateHierarchy
TODO
-->
## GridMaterial
_extends THREE.MeshPhongMaterial_
A material with the same interface as `THREE.MeshPhongMaterial`. It adds a stylized grid on the mesh for more easily visualizing mesh topology and measurements.
### .enableGrid
```js
enableGrid = true : Boolean
```
Sets the visibility of the grid on the mesh.
## HalfEdgeMap
TODO
### constructor
```js
constructor( geometry : BufferGeometry = null )
```
### .getSiblingTriangleIndex
```js
getSiblingTriangleIndex( triIndex : Number, edgeIndex : 0 | 1 | 2 ) : Number
```
### .getSiblingEdgeIndex
```js
getSiblingEdgeIndex( triIndex : Number, edgeIndex : 0 | 1 | 2 ) : Number
```
### .updateFrom
```js
updateFrom( geometry : BufferGeometry ) : void
```
## PointsHelper
_extends THREE.InstancedMesh_
Helper class for generating spheres to display.
### .setPoints
```js
setPoints( points : Vector3[] ) : void;
```
Sets the points, passed as Vector3, and visualizes them as spheres.
## EdgesHelper
_extends THREE.LineSegments_
Helper class for generating a line to display the provided edges.
### .setEdges
```js
setEdges( edges : Line3[] ) : void
```
Sets the list of lines to be visualized.
## HalfEdgeMapHelper
_extends EdgesHelper_
This is a helper class that takes the `HalfEdgeMap` object and visualizes the connectivity between triangles.
### .setHalfEdges
```js
setHalfEdges( geometry : Geometry, halfEdges : HalfEdgeMap ) : void
```
Sets the half edge map to visualize along with the associated geometry.
## TriangleSetHelper
_extends THREE.Group_
Helper class for displaying a set of triangles. In the _Simple CSG_ example is possible to enable/disable the visibility of the triangles helper via `displayTriangleIntersections` checkbox.
The helper is composed of two meshes, one is a mesh with a MeshPhongMaterial and the other is a mesh with a LineBasicMaterial.
### .setTriangles
```js
setTriangles( triangles: Triangle[] ) : void
```
Sets the geometry of the mesh and the line with the position of the triangles passed as a parameter of the method.
## Functions
### computeMeshVolume
```js
computeMeshVolume( mesh : Mesh | BufferGeometry ) : Number
```
Computes the volume of the given mesh in world space. The world matrix is expected to be updated before calling this function.
# Gotchas
- All geometry are expected to have all attributes being used and of the same type.
- Geometry on a Brush should be unique and not be modified after being set.
- All geometry must be [two-manifold](https://knowledge.autodesk.com/support/maya-lt/learn-explore/caas/CloudHelp/cloudhelp/2015/ENU/MayaLT/files/Polygons-overview-Twomanifold-vs--nonmanifold-polygonal-geometry-htm.html) - or water tight with no triangle interpenetration.
# References
- [Godot CSG](https://github.com/godotengine/godot/blob/master/modules/csg/csg.cpp)
- RealtimeCSG ([Overview](https://www.youtube.com/watch?v=uqaiUMuGlRc), [GDC Presentation](https://www.youtube.com/watch?v=Iqmg4gblreo))