BGPSeg Segmentation
BGPSeg Segmentation
- point_cloud
- models
- segmented_cloud
- boundary_points
- summary
This is the node that answers "what is this scan made of?" Feed it a point cloud or a mesh and it carves the thing up into the shapes CAD models are actually built from - planes, cylinders, spheres, cones, tori. That's primitive segmentation, and it's the step between "I have a messy 3D scan" and "I have a solid model I can edit or fit surfaces to."
It's a ComfyUI port of the BGPSeg paper (Boundary-Guided Primitive Segmentation for Point Clouds, IEEE TIP 2025), and the README says it right in the first line: work in progress. Don't expect polish. But the pipeline is real, and it's one of the few ways to get instance-level primitive segmentation on a node graph instead of in a Python script.
Where it fits This is the 3D corner of the ecosystem, not image generation. The included workflow pulls a mesh in with Geometry Pack's GeomPackLoadMesh and previews the results with GeomPackPreviewMesh(VTK). The outputs were also designed to drop straight into PozzettiAndrea's other pack, ComfyUI-CADabra - specifically Point2CADSurfaceFitting / PrimitiveFitting for actual CAD surface reconstruction. If you're not already running a geometry pack and CADabra, this node alone won't get you to a solid model; it's one stage of a pipeline.
How it works Two-stage. First a BoundaryNet marks which points sit on the seams between primitives. Then the main model (BGFE) computes a 32-dim embedding for every point, with attention biased by those boundary predictions - that's the "boundary-guided" part, and it's why instances don't bleed into each other at their edges. Mean-shift clustering groups the embeddings into instances, and a classifier tags each one with a primitive type from ten classes: plane, sphere, cylinder, cone, torus, BSpline, revolution, extrusion, background, and a catch-all "other". The heavy lifting runs through JIT-compiled CUDA ops (pointops + boundaryops) that build on first use.
The inputs that matter Two are non-negotiable: point_cloud (TRIMESH) and models (the wire from LoadBGPSegModels). The point cloud must have vertex normals - the node refuses otherwise - and if you hand it a mesh with faces, it samples 8,192 points off the surface before segmenting, so don't expect to segment a dense scan at full resolution. Three dials you'll actually touch:
bandwidth(default 1.31, straight from the paper) - mean-shift cluster size. Raise it to merge small fragments into fewer, larger primitives; lower it to split.boundary_threshold(default 0.5) - how confident BoundaryNet has to be before a point counts as a boundary.cluster_batch_size(default 700) - a memory knob. Drop it if the clustering runs out of VRAM.
The outputs segmented_cloud (TRIMESH) carries the per-point labels in its metadata - that's what you preview, or pipe into CADabra's fitting nodes. boundary_points is the same cloud filtered to just the boundary points, colored red, which is handy for judging whether your threshold is sane. summary is a STRING with cluster counts and the primitive-type distribution; wire it into any text preview node.
Install In ComfyUI Manager, search "BGPSeg", or do it by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/PozzettiAndrea/ComfyUI-BGPSeg
pip install -r ComfyUI-BGPSeg/requirements.txt
That pulls torch, numpy, trimesh and gdown. Restart ComfyUI. The models auto-download from Google Drive into ComfyUI/models/cadrecon/bgpseg/ the first time the loader runs.
Where people get burned The WIP status is the honest headline - expect rough edges. CUDA is effectively mandatory: the custom ops JIT-compile on first run (a few minutes, needs a CUDA toolkit with nvcc), and CPU mode is so slow the node itself warns you. Google Drive downloads via gdown can stall; if one does, grab the two .pth files from the Drive folder the loader prints and drop them into models/cadrecon/bgpseg/ yourself. And if you hit "point cloud must have vertex normals," you haven't converted your mesh properly - the tooltip's advice to use a mesh-to-pointcloud node is the fix, not a suggestion.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| point_cloud | TRIMESH | Input point cloud or mesh. Must have vertex normals. Use a mesh-to-pointcloud node if needed. | |
| models | BGPSEG_MODELS | Loaded BGPSeg models from LoadBGPSegModels node. | |
| bandwidthopt | FLOAT | 1.310.1–5 | Mean-shift clustering bandwidth. Higher values = fewer, larger clusters. Default 1.31 from BGPSeg paper. |
| boundary_thresholdopt | FLOAT | 0.500–1 | Threshold for boundary point classification. Points with boundary probability above this are marked as boundaries. |
| cluster_batch_sizeopt | INT | 700100–2000 | Batch size for GPU mean-shift clustering. Reduce if running out of memory. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| segmented_cloud | TRIMESH | — |
| boundary_points | TRIMESH | — |
| summary | STRING | — |