Nodes/camera-comfyUI/ZDepthToRayDepthNode
ComfyUI Node

ZDepthToRayDepthNode

Convert Z-depth to ray depth

By Alexankharin·Created about a year ago·Updated about a month ago· 36
ZDepthToRayDepthNode
  • depth
  • ray depth
fov60.0

Most depth estimators - Depth Anything v2 and friends - output Z-depth: the distance from the camera plane to the surface, measured straight down the optical axis. But when you lift pixels into 3D, what you actually want is ray depth: the Euclidean distance along each pixel's own view ray. Near the center of the frame the two are nearly identical, so nobody notices. Push out toward a wide FOV and they diverge more and more, and suddenly your point cloud bows and curves like the scene is bulging at the edges. ZDepthToRayDepthNode is the one-node fix: it converts a Z-depth map into ray depth using the camera's horizontal FOV.

The math is straightforward pinhole geometry. From the FOV it computes a focal length in pixels (fx = W / (2·tan(fov/2))), builds a per-pixel ray-length factor sqrt(1 + x² + y²) where x and y are normalized offsets from the image center, and multiplies the Z-depth by that factor. Center pixels get a factor of ~1 (no change); edge pixels get more. One input depth map in, one corrected map out.

Inputs: depth (a TENSOR, [1,H,W,1]) and fov (horizontal FOV in degrees, default 60, range 1–179). Output: ray depth, same shape, ready for DepthToPointCloud, TracksToTrajectories, MotionMaskFromDepth, or VideoToFusedSplats.

Where it fits, and one honest caveat:

  • Use it after any Z-depth source. DepthEstimatorNode (Depth Anything v2), video depth models, anything that outputs planar Z-depth - route it through here before point-cloud lifting.
  • Don't use it after VideoPoseEstimator on current versions. The v1.1.0 code already converts VGGT's depth to radial ray depth internally (the README's "insert ZDepthToRayDepthNode" caveat is stale for that node). Running it through again double-corrects and bows the geometry the other way. Rule of thumb: if the depth came from VideoPoseEstimator, it's already radial; if it came from a plain depth model, it's Z-depth and needs this node.
  • The FOV must be right. This is a pinhole model with square pixels and the principal point assumed dead-center. If your FOV is wrong the correction is wrong - a 60° map fed with 90° will over-bow. Match the FOV to the actual source (the horizontal_fov output of VideoPoseEstimator is a good value to reuse when available).
  • It's also worth knowing this correction exists at all. If you've been fighting "why does my point cloud curve at the edges" for a while - this is the answer, and it's been the answer in every depth-lifting pipeline since pinhole cameras existed.

No heavy dependencies - pure tensor math. Install with the pack via ComfyUI Manager (search camera-comfyUI, Install, restart), or:

git clone https://github.com/Alexankharin/camera-comfyUI.git custom_nodes/camera-comfyUI
cd custom_nodes/camera-comfyUI && python install.py

It's a boring, essential fixer node - the kind you'll wire into a pipeline and forget it's there. But it's also the difference between a point cloud that looks like a room and one that looks like a funhouse mirror.

CategoryCamera/Depth

Inputs (2)

NameTypeDefaultDescription
depthTENSOR
fovFLOAT60.01–179Horizontal field of view in degrees

Outputs (1)

NameTypeDescription
ray depthTENSOR