A personal research and development project that brings GNM Head — Google's high-fidelity statistical 3D model of the human head — into SideFX Houdini as a digital asset (HDA), generating parametric head meshes directly inside a SOP network.
Scope: This project is built and tested for personal use. It is shared openly in case others find it useful, but it comes with no guarantees of stability or completeness. Contributions and issues are welcome.
GNM (Generative aNthropometric Model, pronounced like genome) is a family of parametric statistical human models developed by Google. Its first open-source release, GNM Head, is a 3D morphable model of the human head offering fine-grained, disentangled control over identity, expression, and head pose, including internal anatomy such as eyeballs, teeth, and tongue. It ships with NumPy, JAX, PyTorch, and TensorFlow backends; this project uses the NumPy backend only.
gnm::gnm_head::1.0HDA — a SOP node that generates a head mesh (17,821 points / 35,324 triangles) from the GNM Head model, with full parameter control over identity, expression, and pose (see Usage), and seam-correct per-corner UVs (auvvertex attribute) ready for texturing.houdini/python/gnm_hda.py— core logic: cached model load, seed-to-identity mapping, mesh generation, geometry write. Uses Houdini's bundled numpy; no TensorFlow on the generation path. A single cook takes on the order of tens of milliseconds.houdini/packages/GNM.json— a Houdini package that setsPYTHONPATHand auto-discovers the HDA.scripts/build_hda.py— reproducible HDA build script.tests/test_gnm_hda.py— unit tests runnable under hython.semantic_server/— a separate, uv-managed FastAPI server (plain Python, not hython) wrapping GNM's TensorFlow-based semantic sampler. Lets the HDA generate an identity from gender/ethnicity, or an expression from a named label, via HTTP; seesemantic_server/README.md.
GNM itself is an external, read-only dependency: this repository contains no model code or data, and imports GNM from a separate clone via PYTHONPATH.
- Procedural head generation — scatter seeds to produce varied background or crowd heads
- Base mesh supply — generate a clean, consistent-topology head as a starting point for sculpting or lookdev
- Research and pipeline testing — evaluate GNM Head output inside a real DCC environment
- Numbered sliders only — identity/expression components are statistical basis coefficients with no semantic labels (this is inherent to the model data); sliders are numbered per group, with low numbers making the biggest changes.
- No textures or materials — the mesh carries UVs, but no material or texture is wired in (GNM ships one modeling reference image, not a skin texture)
- Semantic sampling needs a separate running server — GNM's semantic sampler requires TensorFlow, which is not bundled into Houdini's Python;
semantic_server/runs it separately and the HDA calls it over HTTP only when you click a "Sample" button (never during a normal cook). Single-label only — no weighted blending of multiple labels yet. - External GNM clone required — model data is not bundled; you need your own GNM checkout and two environment variables (see below)
- Houdini — tested with 22.0.368 (bundled Python 3.13, numpy 2.3); also verified with 21.0.729 (Python 3.11, numpy 1.26)
- A clone of GNM: https://github.com/google/GNM
- Optional, for semantic sampling only — uv (Python 3.13, fetched automatically by uv); see
semantic_server/README.md
The commands below call hython, Houdini's bundled Python interpreter. It lives
in Houdini's bin/ directory — either add that directory to your PATH or
replace hython with its full path.
-
Clone this repository and make sure you have a GNM clone.
-
Use Houdini's hython to install the pure-Python dependencies into a local
deps/directory (run from the repository root):hython -m pip install --target=./deps etils absl-py immutabledict typing_extensions(numpy is provided by Houdini, so it is not installed. The core generation path does not require TensorFlow.)
-
Set two environment variables (pointing at your actual paths):
GNM_HOUDINI= the root of this repositoryGNM_REPO= your GNM clone
-
Let Houdini load this repository's package by making
houdini/packages/GNM.jsondiscoverable. The simplest way is to setHOUDINI_PACKAGE_DIRto$GNM_HOUDINI/houdini/packages, or copy that JSON into thepackages/folder of your Houdini user preferences directory (e.g.$HOME/houdiniX.Y/packages/).
Launch Houdini and create a GNM Head node in a SOP context. Parameters are
grouped in three tabs:
- Identity —
Seed/Strengthpick a random base face (0 = the average face). The Head and Teeth component lists plus three Eyeball sliders add per-component offsets on top of the base: set a list's count to expose that many components (entry N always controls component N; low-numbered components make the biggest changes). Each entry's toggle mutes that component without losing its value or animation keys.Gender/EthnicityplusSample Identityfetch a semantic identity fromsemantic_server/(see below);Semantic Strengthblends it in on top of the seed base, same asStrengthdoes for the random base — both sources and the slider offsets sum together. - Expression — same pattern:
Exp Seed/Exp Strength(default 0 = neutral) plus per-region component lists (Left/Right Eye, Lower Face, Tongue) and an Iris slider.Expression LabelplusSample Expressionfetch a named expression (e.g. Happy, Surprise) the same way, blended in viaSemantic Strength. - Pose — axis-angle rotations in degrees for the neck, head, and each eyeball, plus a global translation.
- Start the server (see
semantic_server/README.mdfor setup): fromsemantic_server/,uv run uvicorn server:app --host 0.0.0.0 --port 8000(or your own port viaGNM_SEMANTIC_PORT). - On the HDA, set
Server URL(shared by both tabs) to match, e.g.http://localhost:8000. - Pick a
Gender/Ethnicity(Identity tab) orExpression Label(Expression tab), then press theSample Identity/Sample Expressionbutton. This is the only point that talks to the server — it fetches once and bakes the result into the node, so the server doesn't need to stay running afterward for the node to keep cooking. - Raise
Semantic Strengthfrom 0 to blend the sampled result in; it sums with the random Seed/Strength base and the slider offsets, it doesn't replace them.
If you update houdini/otls/gnm.gnm_head.1.0.hda (e.g. after pulling a
newer version of this repo), existing GNM Head nodes already placed in a
scene keep using the old parameter definition until you right-click the
node → Match Current Definition (or delete and recreate it) — the new
tabs/parms won't appear otherwise.
Rebuild the HDA (run from the repository root; needs the same environment as Installation, since the build reads group sizes from the model):
hython scripts/build_hda.py houdini/otls/gnm.gnm_head.1.0.hdaVerify the built HDA end-to-end (needs the package env from Installation):
hython scripts/verify_hda.pyRun the tests:
hython -m unittest discover -s tests -v
For semantic_server/'s own dev/test commands (managed separately with uv), see semantic_server/README.md.
This project (HDA, Python module, scripts) is released for personal and research use with no restrictions.
GNM is subject to its own license — Apache License 2.0, permissive for both non-commercial and commercial use; see the GNM repository for details. This repository does not redistribute any GNM code, model data, or weights.