Reconstruct Ball Pivoting (backend)
Ball pivoting reconstruction — the detail keeper that leaves holes
- points
- reconstructed_mesh
- info
Ball pivoting is what you pick when Poisson's smooth, blobby result makes you sad. It's the surface reconstruction method that actually touches your points, so it holds onto the fine detail - sharp-ish corners, surface texture, the things that make a scan look like the object instead of a melted version of it. The trade is right in the pack's tooltip: it preserves detail but may leave holes in undersampled areas. If your cloud is dense and even, ball pivoting looks great. If it's sparse or gappy, you'll spend the afternoon chasing holes.
This is the ball_pivoting backend that Reconstruct Surface spawns when you pick it in the dropdown. It's marked dev-only in the schema, so you'll normally drive it through the frontend node - but the mechanism and parameters are identical, and if a workflow drops the backend node in directly, it runs the same way.
How it works
The algorithm is dead simple to picture: imagine a ball of fixed radius rolling over the surface of your point cloud. Where the ball rests against three points, it stamps out a triangle. Roll it on, keep stamping, and the triangles knit into a mesh. Points that are too close together or too far apart for the ball to seat on will be skipped - which is exactly why gaps in the cloud become holes in the result. The pack runs this through PyMeshLab's ball-pivoting implementation.
Inputs and outputs
- points (TRIMESH) - the cloud.
- ball_radius (default 0) - the size of the rolling ball, in the same units as your coordinates. This is the parameter. Too small: holes everywhere. Too big: smooths away the detail you came for. Default 0 = auto, where PyMeshLab estimates a radius from point spacing - genuinely a good starting point, because a good ball radius is the whole game here.
- estimate_normals (default true) - ball pivoting needs normals too. Keep it on unless the input has trustworthy ones.
- normal_radius (default 0.1) - the k-nearest-neighbor search radius for normal estimation, 2–3× the point spacing. Only read when
estimate_normalsis true.
Outputs: reconstructed_mesh (TRIMESH) and info (STRING) with the engine, radius used, and before/after counts. The info line tells you whether auto-radius was chosen, which is handy when you're dialing in a value.
Installing
Same as every node in the pack - ComfyUI Manager → GeometryPack, or:
cd ComfyUI/custom_nodes
git clone https://github.com/PozzettiAndrea/ComfyUI-GeometryPack.git
cd ComfyUI-GeometryPack
pip install -r requirements.txt --upgrade
python install.py
Restart, and don't skip install.py - that's the comfy-env/pixi step that builds the isolated environments, and PyMeshLab lives there.
Troubleshooting
- Holey mesh with default radius - nudge
ball_radiusup in small steps. Auto isn't magic; it guesses from average spacing, and outliers wreck that guess. - Missing features entirely - the ball is bigger than the gaps between features. Drop the radius, and make sure the cloud is actually dense where you care about detail.
- "Ball pivoting requires PyMeshLab" - the isolated env didn't build; re-run
python install.pyand check the repo's Discussions. - If a saved workflow with the frontend node errors on validation, it's the pack's known stale-workflow issue: delete the node, re-add, re-pick
ball_pivoting.
Worth knowing: this is the opposite of Poisson in a meaningful way - Poisson always gives you watertight but slightly smoothed, ball pivoting gives you detail but not guaranteed closed. For a print, many people run ball pivoting and then use the pack's fill-holes step. For a render, ball pivoting often wins outright.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| points | TRIMESH | — | |
| ball_radius | FLOAT | 0.000–100 | Ball radius in absolute units (same as mesh coordinates). Smaller = finer detail but more holes, larger = smoother but loses detail. 0 = auto (PyMeshLab estimates from point spacing). |
| estimate_normals | COMBO | true | Re-estimate point normals using k-nearest neighbors. Enable if the input has no normals or unreliable normals. |
| normal_radius | FLOAT | 0.100.001–10 | Search radius for normal estimation via k-nearest neighbors. Should be 2-3x the average point spacing. Only used when estimate_normals is true. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| reconstructed_mesh | TRIMESH | — |
| info | STRING | — |