ComfyUI Node

Three View

A real 3D scene inside a ComfyUI node — that hands you ready-made ControlNet maps

By lo-th·Created 2 years ago·Updated about a year ago· 21
Three View
    • image
    • lines
    • depth
    • normal
    imageThreejstheejs_image.png,theejs_image_lines.png,theejs_image_depth.png,theejs_image_normal.png

    The Three View node from lo-th's Comfyui_three_js pack puts an actual three.js renderer inside a ComfyUI node, and it's the only one that does what you'd actually want: it renders a 3D model from the exact camera angle you pick, then hands you four image tensors - the color render, an edge map, a depth map, and a normal map - ready to feed straight into a ControlNet.

    Why that's useful: normally you get a depth or normal map by running a preprocessor (Depth Anything, MiDaS, Normal BAE) on a 2D image and hoping it guesses the geometry right. Three View skips the guessing. You load a GLB, orbit the camera to the framing you want, and the depth and normals come straight from the actual mesh. That's pixel-accurate geometry with zero estimation error, and it's yours before you've generated a single diffusion image. If you've ever wanted to compose a scene, render it, then regenerate it "in style" while keeping the structure - this is the missing link.

    How it works - the browser does the rendering

    Here's the part that surprises people: nothing here is Python-side rendering. The node works because your browser renders the scene. When the node is created, the frontend swaps the plain text widget for a live WebGL canvas with orbit controls, four renderers running four passes - color, lines (a toon/outline shader), depth (MeshDepthMaterial), and normal (MeshNormalMaterial). When you hit Queue, the JS serializes each canvas to a PNG, uploads it to ComfyUI via the /upload/image endpoint, pings the server when done, and only then does the Python side read the four files back and convert them to IMAGE tensors. So it's a round trip: browser → server → tensor. The mechanism matters, because it explains the single biggest constraint - see troubleshooting below.

    The inputs and outputs that matter

    The only required input, imageThreejs, is a comma-separated list of PNG filenames - and you will never type it. The frontend rewrites it automatically with per-node, timestamped filenames and then hides the widget. Treat it as plumbing and ignore it.

    The four outputs are where it pays off, and they wire into exactly what you think:

    • image - the color render, camera-lit and tone-mapped (ACES). Feed it to VAE Encode and prompt around it, or use it as a ControlNet reference.
    • depth - a real depth pass from the mesh. Perfectly aligned by definition, so it makes a crisp depth ControlNet condition.
    • normal - surface orientation from MeshNormalMaterial. Great for lighting/material-aware generation, and pairs with IC-Light-style relighting if that's your thing.
    • lines - a toon/outline edge map. This is effectively a free Canny/sketch ControlNet condition with zero preprocessing.

    In practice you'll usually wire image into the sampler (via VAE Encode) and depth or normal into a ControlNet, using the camera to nail the composition before generation.

    Installing it

    Both standard routes work. Easiest is ComfyUI Manager → search Comfyui_three_js → Install. Or, from your ComfyUI/custom_nodes directory:

    git clone https://github.com/lo-th/Comfyui_three_js
    

    Then restart ComfyUI. There's no model download step and no Python dependencies - pyproject.toml lists an empty dependency array, and all the three.js library code ships bundled in the node's js/ folder. That's genuinely rare in this ecosystem and worth appreciating.

    Where people get burned

    • It needs a real browser session. Since the browser renders the images, running this node headless or via the API-only mode produces nothing - there's no canvas to render or upload. If you're on a server you access through a browser (ComfyUI runs locally or on a box you can open in a tab), you're fine.
    • GLB only. The model scanner in three_view.py filters to .glb files, period. Drop your model in ComfyUI/input/ThreeViewModels/ (picked up as "loaded") or use the bundled defaults in js/assets, and load via the node's panel. Anything else is silently ignored.
    • The save can time out. The Python side waits up to about 10 seconds for the browser to upload all four renders. On a slow machine with a heavy model, the queue can stall and log a timeout in the console - keep the browser tab on the ComfyUI page while it runs.
    • It's a browser widget, not a "real" node - collapses and graph reloads can reset camera state, so grab your camera position before you close the workflow.

    Three View is niche - it's for people who actually have a 3D asset and want to drive diffusion from it. But for that job, nothing else in the graph does it this cleanly.

    Categorylth

    Inputs (1)

    NameTypeDefaultDescription
    imageThreejsSTRINGtheejs_image.png,theejs_image_lines.png,theejs_image_depth.png,theejs_image_normal.png

    Outputs (4)

    NameTypeDescription
    imageIMAGE
    linesIMAGE
    depthIMAGE
    normalIMAGE