@react-three/csg

repository·main·Indexed 18 days ago

https://github.com/pmndrs/react-three-csg

A React abstraction for Constructive Solid Geometry (CSG) built on top of three-bvh-csg. It allows developers to perform boolean operations—such as Addition, Subtraction, ReverseSubtraction, Intersection, and Difference—on 3D geometries using a declarative component syntax. The library provides a <Geometry /> component to wrap operations, a <Base /> component for foundations, and a useCSG hook to manually trigger geometry updates at runtime.

Tokens
3.1K
Snippets
13
Records
14
Agent score
13%

What's inside @react-three/csg

  1. How Constructive Solid Geometry (CSG) works in React

    main

    The library provides a React abstraction for Constructive Solid Geometry using three-bvh-csg.

    To use it, you wrap your operations inside a <Geometry /> component. The <Geometry /> component produces a regular THREE.BufferGeometry which must be paired with a <mesh /> or another object that consumes geometry (like physics rigid bodies).

    Core Workflow:

    1. Define a Base: Every <Geometry /> must start with a <Base /> component. This serves as the foundation for all subsequent operations.
    2. Chain Operations: Add boolean operations as children of the <Geometry />. Order matters as each operation is performed on the result of the previous one.
    3. Transformations: All components (Base, Addition, Subtraction, etc.) behave like regular meshes; they can be nested, grouped, and transformed using props like position, scale, and rotation.
    import { Geometry, Base, Addition, Subtraction } from '@react-three/csg'
    
    function Cross() {
      return (
        <mesh>
          <meshStandardMaterial />
          <Geometry>
            <Base scale={[2, 0.5, 0.5]}>
              <boxGeometry />
            </Base>
            <Addition scale={[0.5, 2, 0.5]}>
              <boxGeometry />
            </Addition>
          </Geometry>
        </mesh>
      )
    }
  2. Visualize CSG operations with `showOperations`

    main

    You can debug or visualize your CSG setup by showing the meshes used in the operations:

    • Show all operations: Add showOperations to the <Geometry /> component.
    • Show a single operation: Add showOperation to a specific operation component (like <Addition />) inside the <Geometry />.
    // Show all operations
    <Geometry showOperations>
    
    // Show only one specific operation
    <Geometry>
      <Base geometry={bunnyGeometry} />
      <Addition geometry={carrotGeometry} showOperation />
    </Geometry>
  3. Update CSG geometry at runtime

    main

    Because CSG operations are computationally intensive, you should manually trigger updates when geometry changes (e.g., during a drag interaction) rather than relying on automatic re-renders.

    There are two ways to trigger an update:

    1. Using a Ref: Attach a ref to the <Geometry /> component and call .update() on it.
    2. Using the useCSG hook: Call the update function returned by the hook from within a child component.
    import { useRef } from 'react'
    import { Geometry, Base, Subtraction } from '@react-three/csg'
    import { PivotControls } from '@react-three/drei'
    
    function Shape() {
      const csg = useRef()
      return (
        <mesh>
          <Geometry ref={csg}>
            <Base geometry={bunnyGeometry} />
            <PivotControls onDrag={() => csg.current.update()}>
              <Subtraction geometry={sphereGeometry} />
            </PivotControls>
          </Geometry>
        </mesh>
      )
    }
  4. Use the Geometry component for CSG operations

    main

    The Geometry component is the root container for Constructive Solid Geometry (CSG) operations. It evaluates the children (brushes) provided to it and produces a single resulting bufferGeometry.

    To perform CSG, wrap your Addition, Subtraction, Difference, Intersection, or ReverseSubtraction components inside a Geometry component. The order of children determines the order of operations.

    <Geometry>
      <Addition>
        <mesh />
      </Addition>
      <Subtraction>
        <mesh />
      </Subtraction>
    </Geometry>
  5. Use `useCSG` to update geometry from children

    main

    The useCSG hook allows child components to trigger a re-computation of the parent <Geometry /> component. This is ideal for decoupled components like 'cutters' that need to tell the main shape to update after they move.

    import { useCSG, Geometry, Base, Subtraction } from '@react-three/csg'
    
    function Shape() {
      return (
        <mesh>
          <Geometry>
            <Base geometry={bunnyGeometry} />
            <Cutter />
          </Geometry>
        </mesh>
      )
    }
    
    function Cutter() {
      const { update } = useCSG()
      return (
        <PivotControls onDrag={update}>
          <Subtraction>
            <boxGeometry />
          </Subtraction>
        </PivotControls>
      )
    }
  6. Configure multi-material groups with `useGroups`

    main

    By default, CSG results in a single uniform material. If you set the useGroups prop on the <Geometry /> component, the library will generate material groups. This allows each operation to have its own unique material (defined via the material prop or as a child component). The resulting material groups are inserted into the final mesh.

    function Shape() {
      return (
        <mesh>
          <Geometry useGroups>
            <Base geometry={bunnyGeometry}>
              <meshStandardMaterial />
            </Base>
            <Subtraction position={[-1, 1, 1]} material={metal}>
              <meshStandardMaterial color="blue" />
            </Subtraction>
            <Addition position={[1, -1, -1]} geometry={sphereGeometry} material={stone} />
          </Geometry>
        </mesh>
      )
    }
  7. Configure the Geometry component

    main

    The Geometry component accepts several props to control how the resulting mesh is generated and rendered:

    • children: The CSG operations (brushes) to evaluate.
    • useGroups: (boolean, default: false) If true, each operation can have its own material.
    • consolidateGroups: (boolean, default: false) If true, groups in the final geometry sharing a common material will be merged to reduce draw calls.
    • showOperations: (boolean, default: false) If true, the individual operation meshes (brushes) will be visible in the scene.
    • computeVertexNormals: (boolean, default: false) If true, re-computes vertex normals for the resulting geometry.
    <Geometry 
      useGroups={true} 
      consolidateGroups={true} 
      showOperations={true} 
      computeVertexNormals={true}
    >
      {/* operations here */}
    </Geometry>
  8. Reference: CSGGeometryProps and CSGGeometryApi

    main

    The following types define the configuration and API available via refs or hooks for the <Geometry /> component.

    CSGGeometryProps

    • children?: React.ReactNode
    • useGroups?: boolean (Enables material groups for each operation. Default: false)
    • showOperations?: boolean (Makes all operation meshes visible. Default: false)
    • computeVertexNormals?: boolean (Re-computes vertex normals. Default: false)

    CSGGeometryApi

    • computeVertexNormals: boolean
    • showOperations: boolean
    • useGroups: boolean
    • update: () => void (Triggers geometry re-computation)
    export type CSGGeometryProps = {
      children?: React.ReactNode
      useGroups?: boolean
      showOperations?: boolean
      computeVertexNormals?: boolean
    }
    
    export type CSGGeometryApi = {
      computeVertexNormals: boolean
      showOperations: boolean
      useGroups: boolean
      update: () => void
    }
    
    export type CSGGeometryRef = CSGGeometryApi & {
      geometry: THREE.BufferGeometry
      operations: THREE.Group
    }
  9. Available CSG Boolean Operations

    main

    Within a <Geometry /> component, you can use the following operations to modify the base geometry:

    • Addition: Adds the geometry of the child to the previous result.
    • Subtraction: Subtracts the geometry of the child from the previous result.
    • ReverseSubtraction: Subtracts the previous geometry from the current child geometry.
    • Intersection: Keeps only the overlap between the previous result and the child geometry.
    • Difference: Keeps the negative overlap (the part of the previous result not covered by the child).
  10. Access Geometry API via ref

    main

    You can attach a ref to the Geometry component to access its internal state and trigger updates. The CSGGeometryRef provides:

    • geometry: The resulting THREE.BufferGeometry.
    • operations: A THREE.Group containing the operation meshes.
    • update: A function to manually trigger a re-computation of the CSG result.
    • computeVertexNormals: Boolean indicating if normals are computed.
    • showOperations: Boolean indicating if operations are visible.
    • useGroups: Boolean indicating if material groups are used.
    const geometryRef = useRef<CSGGeometryRef>(null!)
    
    // Later, to trigger a re-calculation:
    geometryRef.current.update()
  11. Perform CSG operations with Addition, Subtraction, Difference, Intersection, and ReverseSubtraction

    main

    These components are specialized wrappers around the brush element that set the specific CSG operator. They all accept the same props as a standard brush (excluding operator).

    • Addition: Performs an additive operation.
    • Subtraction: Performs a subtraction operation.
    • Difference: Performs a difference operation.
    • Intersection: Performs an intersection operation.
    • ReverseSubtraction: Performs a reverse subtraction operation.

    Each component can also take a showOperation prop to control its individual visibility independently of the Geometry component's showOperations setting.

    <Geometry>
      <Addition>
        <mesh />
      </Addition>
      <Subtraction showOperation={true}>
        <mesh />
      </Subtraction>
      <Intersection>
        <mesh />
      </Intersection>
    </Geometry>