GeoCalib → fSpy JSON
GeoCalib → fSpy JSON, explained
- fspy_json
Here's the odd one out. GeoCalibToFSpy has nothing to do with booleans or integers. It's the node that takes a photograph - or an AI-generated image - and turns it into a camera calibration your 3D software can read. It's a bridge from image generation into Blender, and it's the only node in SimpleLogics that needs a second, unrelated pack to do anything.
The workflow it serves: people who generate or shoot an image, then want to reconstruct it as a 3D scene - putting objects, walls, and lights into Blender so they line up with the photo. The standard tool for that is fSpy, the open-source app where you click vanishing points on a photo and it computes where the camera must have been. It's a genuinely popular trick in the community for turning 2D images into 3D scenes. The catch is that clicking vanishing points by hand is fiddly. This node automates it: instead of you eyeballing the geometry in fSpy's GUI, a vision model estimates the camera, and this node formats that estimate as an fSpy file.
Specifically, it expects the outputs of the GeoCalib Estimator node (from the separate ComfyUI-GeoCalib pack, based on the GeoCalib single-image camera calibration model) - roll, pitch, and vfov - plus the image dimensions. GeoCalib looks at one frame and guesses how the camera was tilted and how wide its field of view was, which is exactly the information fSpy needs.
How it works under the hood
Reading the source, it builds an fSpy JSON structure:
principalPointat the image center (normalized{x: 0, y: 0})relativeFocalLength=0.5 / tan(vfov/2), the fSpy convention normalized to half the image height- horizontal FoV derived from vfov and the aspect ratio
- camera/view transform matrices built from roll and pitch rotation (yaw is left at 0 - GeoCalib doesn't estimate heading, so the scene has no compass direction)
vanishingPointsset to null placeholders, with a note that GeoCalib doesn't estimate them
The output is a single STRING - a JSON document you save to a .fspy file and open in Blender with the fSpy addon enabled. Import it, and Blender places a camera that matches the photo's perspective.
Inputs:
image_width,image_height(INT) - from your Load Image node or primitives. Defaults 1920×1080.roll,pitch,vfov(FLOAT) - wire these straight from the GeoCalib Estimator node.
Installing it
The node itself is in ComfyUI-SimpleLogics (Manager → search "SimpleLogics", or manual clone below), and the pack itself has zero dependencies:
cd ComfyUI/custom_nodes
git clone https://github.com/danipisca07/ComfyUI-SimpleLogics
But to actually use it you also need ComfyUI-GeoCalib installed (that's the pack that provides the Estimator node and its model weights), plus Blender and the free fSpy addon. No pip install needed for SimpleLogics itself - it's pure Python - but GeoCalib is a separate install with its own model download.
Where people get tripped up
- You still need to build the geometry. fSpy gives you the camera, not the scene. Once the camera is placed, the modeling, texturing, and lighting are on you. This node only automates the calibration step.
- No yaw, no vanishing points. Because GeoCalib only estimates roll, pitch, and vfov, the transform has no heading and the vanishing points are null placeholders. For straight-on or slightly tilted shots that's usually fine; for dramatic angled shots you may need to nudge the camera in Blender afterward.
- It's a JSON string, not a file. Nothing writes a
.fspyfor you. You save the output to disk (paste into a text file namedsomething.fspy) and import that in Blender.
Niche, yes. But if your thing is feeding generated images into a real 3D pipeline, this node collapses a tedious manual step into one wire.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| image_width | INT | 19201–65536 | — |
| image_height | INT | 10801–65536 | — |
| roll | FLOAT | 0.00-180–180 | — |
| pitch | FLOAT | 0.00-90–90 | — |
| vfov | FLOAT | 60.001–179 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| fspy_json | STRING | — |