本节摘要:Python 在 Houdini 里不做逐点计算,做"元工作":批量创建/连接节点、读写参数、接入外部数据、构建工具界面。入口是 HOM(Houdini Object Model)API 与 hou 模块。本节实验:用一段脚本批量生成 12 座不同种子的山体变体——正是第 6 章 PDG 要解决的需求的手工版雏形。
打开 Houdini 底部的 Python Shell(Windows 菜单里),先做一个最小动作:
import hou geo = hou.node('/obj').createNode('geo', 'mountain_v2') grid = geo.createNode('grid') grid.parm('rows').set(100) grid.parm('cols').set(100) mnt = geo.createNode('mountain') mnt.setInput(0, grid) mnt.moveToGoodPosition()
回视口,一座山出现了——但这次它不是你手连的,是脚本建的。把这件事乘以 12:批量复制山体容器、给每座不同 seed:
obj = hou.node('/obj') base = hou.node('/obj/mountain_v2') # 上一步的母版 for i in range(12): dup = base.copyTo(obj) dup.setName(f'variant_{i:02d}') # 深入网络找 mountain 与 scatter 节点改种子 for n in dup.children(): if n.type().name() == 'mountain': n.parm('offset').set((i * 3.7, 0, i * 1.3)) elif n.type().name() == 'scatter': n.parm('seed').set(1000 + i)
跑完 obj 层排开 12 座山。这就是 Python 的角色:当操作对象是"节点网络"而不是"点"时,用它。同样的需求用 VEX 无法表达——VEX 看不见节点。
hou 模块的一切围绕三层东西转:

| 对象 | 代表什么 | 典型操作 |
|---|---|---|
| hou.Node | 网络里的一个节点 | 创建/连接/删、读写 parm |
| hou.Parm | 节点上一个参数 | set/eval、设 keyframe |
| hou.Geometry | 节点产出的几何 | 点循环(慢,少用) |
⚠️ 常见坑:用 Python 的 Geometry API 逐点循环改属性——比 VEX 慢几个数量级(解释执行、无 SIMD)。规则很硬:逐点归 VEX,管网络归 Python,越界必挨性能板子。
程序化资产的常见需求:策划给一张表,按表生成。示例——按表配置生成一排障碍物:
import csv geo = hou.node('/obj').createNode('geo', 'from_csv') for i, row in enumerate(csv.DictReader(open('props.csv'))): box = geo.createNode('box', row['name']) box.parm('sizex').set(float(row['width'])) box.parm('tz').set(float(row['depth'])) geo.layoutChildren()
同样的结构可以换成 JSON、Excel 或数据库查询——Houdini 之外的世界由 Python 负责接进来。第 6 章的 TOPs 做调度时,这类"配置即数据"的思路会升级为正式的产线设计。
Python 还有一项 VEX 完全没有的能力:做 UI。第 7 章会把山体封装成 HDA,届时参数面板上的按钮、下拉联动逻辑都要用 Python Script 写回调(Callback Script)。此刻只需要记住入口:任何参数的回调栏里写的都是 hou.parm(...) 风格的 Python 片段。
💡 关键直觉:把 Python 当车间的调度电话——它不亲自加工零件,但能开机器、传图纸、拉闸门。
下一节看最小的语言:参数栏里的 HScript 表达式。
Python 的主战场在网络之上:驱动节点、批量命名、接入外部数据源。一个真实管线的骨架是"扫描参数→建节点→连线→设参数"四段式:
import hou obj = hou.node("/obj") geo = obj.createNode("geo", "auto_rig_proxy") grid = geo.createNode("grid", "base") mount = geo.createNode("mountain", "disp") wrangle = geo.createNode("attribwrangle", "style") mount.setInput(0, grid); wrangle.setInput(0, mount) mount.parm("height").set(0.6) wrangle.parm("snippet").set('v@Cd = {0.2, 0.5, 0.3};') geo.layoutChildren() # 自动整理布局
把这段存为 shelf 工具,一键生成标准化起步网络——团队规范从文档变成按钮,是 Python 在 Houdini 里最高杠杆的用法。
# Python 造数据(外部世界: json/excel/数据库) -> VEX 消费(几何世界) import json cfg = json.load(open("levels.json")) node = hou.pwd() node.setUserData("levels", json.dumps(cfg["levels"])) # 下游 Wrangle 中: import json; levels = json.loads(op:'../style'.userData)