cv2.ppf_match_3d.loadPLYSimple
The pack's one node that asks you to type a file path
- nparray
Almost everything in ComfyUI reaches files through a dropdown: Load Image, Load Video, Load 3D. This node doesn't. It takes a string path to a PLY file on your disk and returns the point cloud inside it. That single difference is why people get stuck on it - there's no browsing, no upload, and a typo is an OpenCV exception rather than an empty dropdown.
What it's for
PLY is the lingua franca of scanned and reconstructed point clouds, and 3D scanning is exactly where PPF matching gets used: you have a stored scan or a synthetic cloud exported from a mesh, and you want it as an array so the pack's geometry nodes can chew on it. 3d-generation.md is blunt that the geometry coming out of image-to-3D tools is triangle soup - a PLY round-trip is how you take that result out of the mesh world and into a data pipeline where you can normalise it, register it, or compare it against a reference.
If you already have a mesh (.glb, .obj) rather than a cloud, you don't want this node - use CV Mesh From 3D Model, which goes through core's Load 3D and gives you vertices and triangle indices.
How it works
cv2.ppf_match_3d.loadPLYSimple(fileName, withNormals) is one of only two free functions in that module, which is why it's exposed as a raw wrapper. The word Simple is doing real work: this is the loader for PLY files that store points, not the general-purpose importer. It returns an OpenCV Mat of XYZ (or XYZ + normals) values, and the wrapper hands it out as an NPARRAY.
withNormals is the interesting knob. Turn it on and the loader reads the normal channels the PLY carries and returns an Nx6 cloud, which is what PPF and ICP want. Leave it off and you get Nx3 and you'll have to compute normals yourself with CV Point Cloud Normals - and if the cloud came from a mesh, prefer CV Mesh Vertex Normals instead, because normals derived from a plane fit can't be oriented consistently on a closed model and will flip the PPF pose roughly 180 degrees.
Inputs and outputs
fileName is a plain string widget. Type an absolute path (/home/you/models/bunny.ply, or C:/models/bunny.ply with forward slashes on Windows). A relative path resolves against ComfyUI's working directory, which is not the folder you think it is - absolute is the way. Note that this one parameter is unguarded by design: the pack blacklists path-taking functions like imread from the raw registry, but loadPLYSimple is a legitimate file reader and lives here on purpose.
withNormals is an optional literal widget that starts blank. Blank means "use the OpenCV default", which is off - an Nx3 cloud. Put 1 (or true) in it to read normals.
The output is a single nparray. Sensible next steps: CV Point Cloud Normals to add normals, CV Transform Points 3D to rotate/scale it, CV Filter Points 3D By Mask to trim it, CV ICP Register (Point Clouds) to align it to another cloud, or CV Write PLY (Point Cloud) to write a cleaned copy back out.
Install
ComfyUI CV (bmad4ever). Manager, search comfyui_cv. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Restart afterwards. Python ≥ 3.12, recent ComfyUI on the V3 node API. No model files needed - the PLY is yours.
Common issues
"The node isn't there." ppf_match_3d only exists in a contrib build. If you've installed opencv-python over opencv-contrib-python, the module silently disappears and the pack skips it. python tools/repair_opencv_contrib.py --check will tell you; --apply fixes it.
cv2 throws on the file. Check the path character by character - a path that doesn't exist is an exception here, not a warning. Windows users: forward slashes, and quote nothing (the widget is a raw string, not a shell argument).
Your PLY loads but everything downstream looks wrong. Two usual causes: the file is in different units than the rest of your pipeline (millimetres vs metres), or it has no normals and you skipped the normals step. The pack's raw nodes never apply normals on your behalf; the curated PPF node does.
Faces and colours ignored? Expected. This is the simple loader - points in, points out. Convert your mesh to a cloud first if that's what you actually have.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| fileName | STRING | - - - | |
| withNormalsopt | STRING | - - - Optional - leave blank to use the OpenCV default. Accepts a Python literal, e.g. 3, 1.5, true, or (3, 3). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | — |