GNM Head Render
A real 3D head, plus ControlNet-ready depth and normal maps
- gnm_model
- identity
- expression
- image
- normal_map
- depth_map
- mask
If you've ever wanted the exact geometry of a face before the diffusion model invents one, GNMHeadRender is the node you came for. It's the workhorse of ComfyUI-GNM: feed it an identity vector and an expression vector, pose the head any way you like, and out the other side come four things - the color image, a normal map, a depth map, and a mask. The normal and depth maps are the point, because they're exactly what ControlNet-style conditioning eats for breakfast.
The context matters here. ControlNet conditions generation on spatial structure - edges, depth, pose - so the prompt decides what appears and the condition decides where it goes. Most people extract that structure from a photograph with a preprocessor. GNM is the weirder, more powerful path: generate the structure yourself, from a head you can pose and sculpt, so the condition is exactly the face you designed instead of the face a preprocessor happened to find. It's the same impulse as the "consistent characters via geometry" crowd - you're not hoping the prompt holds, you're handing the sampler a map.
How it works, mechanically: the model runs a forward pass - gnm(identity, expression, rotations) - to produce the mesh vertices, then the pack's own renderer (it drives pyrender directly, deliberately bypassing GNM's osmesa-forcing wrapper that breaks on Windows) draws the color, normal, and depth passes plus a mask. The heavy hitters among the inputs:
gnm_model- from the loader. Required.identityandexpression- optional. Leave them unwired and you get the average/template face, which is a feature, not a bug.head_yaw/pitch/roll- neck-joint rotation in degrees;eyes_yaw/pitch- eyeball rotation.camera_azimuth/elevation- orbit the camera (0/0 is dead-on front), withzoomandfovfor framing.surface-plain(flat material, cleanest normal/depth) oredgeflow_texture(GNM's default texture for the color pass).mesh_parts-face_default(eyelid skin excluded, the GNM default) orall.width/height- up to 4096;antialias1–4;backgroundgray level 0–1.
Outputs: image, normal_map, depth_map, mask. Wire the maps into a depth or normal ControlNet Apply and render away. One caveat the ecosystem keeps rediscovering: the post-Flux union ControlNets trimmed their condition menu and normal maps were among the casualties - so this shines brightest on SD/SDXL, or wherever a normal ControlNet still exists.
Install
ComfyUI Manager is the easy path: Custom Nodes → search "ComfyUI-GNM" → Install, then restart. Or clone by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/soylab-edu/ComfyUI-GNM
cd ComfyUI-GNM
pip install -r requirements.txt
The model data ships in vendor/ (a 51MB npz) - no separate download. The renderer needs pyrender, pyglet<2, and the pack's pinned PyOpenGL==3.1.10 (pyrender's default 3.1.0 breaks on Python 3.13 / numpy 2).
Common issues
The render node is where this pack's environment quirks live. Headless Linux servers need PYOPENGL_PLATFORM=egl set before launch - the README calls it out explicitly; Windows should just work via WGL. If you hit a pyrender import error, the requirements didn't land, and mind the pyglet<2 pin because newer pyglet breaks pyrender's GL context. Expect the first render to be slow while the model loads and caches; everything after that is fast.
Inputs (18)
| Name | Type | Default | Description |
|---|---|---|---|
| gnm_model | GNM_MODEL | — | |
| width | INT | 51264–4096 | — |
| height | INT | 51264–4096 | — |
| head_yaw | FLOAT | 0.0-90–90 | — |
| head_pitch | FLOAT | 0.0-90–90 | — |
| head_roll | FLOAT | 0.0-90–90 | — |
| eyes_yaw | FLOAT | 0.0-40–40 | — |
| eyes_pitch | FLOAT | 0.0-30–30 | — |
| camera_azimuth | FLOAT | 0.0-180–180 | — |
| camera_elevation | FLOAT | 0.0-89–89 | — |
| zoom | FLOAT | 1.000.2–5 | — |
| fov | FLOAT | 255–90 | — |
| background | FLOAT | 0.950–1 | — |
| surface | COMBO | 2 options: plain, edgeflow_texture | |
| mesh_parts | COMBO | 2 options: face_default, all | |
| antialias | INT | 21–4 | — |
| identityopt | GNM_IDENTITY | — | |
| expressionopt | GNM_EXPRESSION | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| normal_map | IMAGE | — |
| depth_map | IMAGE | — |
| mask | MASK | — |