核心概念:在哪里写 Python 代码?
在 Houdini 中,你可以在几个主要的地方编写和执行 Python 代码,它们各自有不同的用途:

- Python 节点:这是最常用、最强大的方式,它是一个独立的节点,可以像其他 SOP、ROP 节点一样被创建和连接,你可以将逻辑封装在这个节点中,方便管理和重用。
- Python 脚本编辑器:位于菜单栏
Windows > General Editors > Python Shell,适合快速测试代码片段、调试和交互式操作。 - 事件驱动的 Python 脚本:在
houdini.py文件中编写的脚本,可以在 Houdini 启动、关闭或发生特定事件时自动执行,适合全局设置和自定义工具栏。 - 自定义工具和 UI:通过创建一个带有按钮的界面(比如使用
hou.ui模块),并将按钮的功能与 Python 函数绑定。
对于“按钮”这个主题,我们主要关注 Python 节点 和 自定义 UI 按钮。
Python 节点
这是最推荐的方法,因为它将功能与场景紧密结合。
创建一个简单的 Python 节点
- 在任何网络(如 SOP、POP、VEX 等)中,右键点击空白处。
- 选择
Python节点。 - 双击打开 Python 节点的编辑器窗口。
编写你的第一个脚本
在 Python 节点编辑器中,输入以下代码:
# 这是一个简单的 Python 节点示例
# 它会打印一条消息到 Houdini 的消息日志
import hou
# hou.node() 用于获取当前节点
# hou.pwd() 是一个快捷方式,表示 "print working directory",即当前节点
node = hou.pwd()
# 打印一条信息到 Houdini 的消息日志
hou.ui.displayMessage("Hello from Python Node!")
print(f"Python Node '{node.name()}' has been executed.")
# 你也可以创建一些输出,以便连接到其他节点
# 创建一个包含一个点的几何体
geo = node.createNode("geo") # 创建一个子网络
geo.setName("my_geo")
# 在子网络内创建一个点
add_node = geo.createNode("add")
add_node.parm("tx").set(2) # 将点移动到 X=2 的位置
- 点击编辑器窗口上的 "Apply Code" 按钮(或按
Ctrl + Enter)。 - 查看底部状态栏的 消息日志,你会看到 "Hello from Python Node!",你的网络中会创建一个新的子网络。
获取和修改节点参数
这是 Python 节点最强大的功能之一,你可以读取和修改其他节点的参数。
假设你的网络中有一个 Box 节点,你想通过 Python 节点来控制它的大小。
import hou
# 获取当前 Python 节点
python_node = hou.pwd()
# 假设我们想控制一个名为 'box1' 的节点
box_node = python_node.node("box1")
# 检查节点是否存在
if not box_node:
hou.ui.displayMessage("Error: 'box1' node not found!")
# 如果不存在,我们可以创建一个
box_node = python_node.createNode("box")
box_node.setName("box1")
# 获取 'size' 参数
# parm() 方法通过参数的路径获取参数对象
size_parm = box_node.parm("size")
# 读取参数的值
current_size = size_parm.eval()
print(f"Current box size is: {current_size}")
# 设置参数的值
new_size = 5.0
size_parm.set(new_size)
print(f"Box size has been set to: {new_size}")
# 你也可以一次性修改多个参数
# 修改 'tx', 'ty', 'tz' 来移动盒子
box_node.parm("tx").set(10)
box_node.parm("ty").set(2)
在 UI 中创建按钮
你希望有一个明显的按钮来触发操作,而不是每次都去修改 Python 节点,这时就需要创建自定义的 UI。
使用 Python 脚本编辑器创建一个简单按钮
这是最快速的方式,适合临时工具。
- 打开
Python Shell(Windows > General Editors > Python Shell)。 - 在编辑器中输入以下代码并按
Enter执行:
import hou
def my_button_callback():
"""当按钮被点击时,这个函数会被调用"""
print("Button was clicked!")
hou.ui.displayMessage("You clicked the button!")
# 创建一个带有按钮的对话框
# 第一个参数是按钮的标签,第二个参数是回调函数
# hou.ui.displayButton 会立即显示对话框并等待用户交互
hou.ui.displayButton("Click Me", my_button_callback)
一个对话框会弹出,上面有一个 "Click Me" 按钮,点击它,你会看到 Python Shell 和消息日志中打印出 "Button was clicked!"。
创建一个带有输入字段的工具
更实用的工具通常需要用户输入。
import hou
def create_sphere_with_name():
"""根据用户输入创建一个命名的球体"""
# 获取用户输入
# hou.ui.readInput 会弹出一个对话框,第一个参数是提示文本
result = hou.ui.readInput("Enter sphere name:", buttons=('OK', 'Cancel'), close_choice=1)
# result 是一个元组: (用户点击的按钮索引, 用户输入的文本)
# 'OK' 是 0, 'Cancel' 是 1
if result[0] == 0: # 如果用户点击了 'OK'
sphere_name = result[1]
# 获取当前选中的节点(通常是 OBJ 上下文)
selected_nodes = hou.selectedNodes()
parent_node = None
if selected_nodes:
parent_node = selected_nodes[0] # 使用第一个选中的节点作为父节点
else:
# 如果没有选中节点,在 /obj 下创建
parent_node = hou.node("/obj")
# 创建一个球体节点
sphere_node = parent_node.createNode("geo", sphere_name)
add_node = sphere_node.createNode("sphere")
hou.ui.displayMessage(f"Created '{sphere_name}' successfully!")
# 调用函数来显示对话框
create_sphere_with_name()
创建一个更复杂的工具窗口 (Tool Window)
对于更复杂的工具,你需要创建一个包含多个控件的窗口,这通常通过 hou.ui 模块实现。
import hou
def create_tool_window():
"""创建一个自定义的工具窗口"""
# 创建一个窗口
window = hou.ui.createWindow("My Awesome Tool")
# --- 添加控件 ---
# 1. 一个标签
window.addLabel("This is my custom tool.")
# 2. 一个文本输入框
name_parm = window.addStringParm("name_parm", "Object Name:", "my_object")
# 3. 一个浮点数滑块
size_parm = window.addFloatParm("size_parm", "Size:", 1.0, (0.1, 10.0))
# 4. 一个下拉菜单
type_menu = window.addEnumParm("type_parm", "Type:", 0, ("Cube", "Sphere", "Torus"))
# 5. 一个按钮
create_button = window.addButton("Create")
# --- 定义回调函数 ---
def on_create_clicked():
"""当 'Create' 按钮被点击时执行"""
obj_name = name_parm.getValue()
obj_size = size_parm.getValue()
obj_type = type_menu.getValue() # 0=Cube, 1=Sphere, 2=Torus
parent_node = hou.node("/obj")
geo_node = parent_node.createNode("geo", obj_name)
if obj_type == 0: # Cube
shape_node = geo_node.createNode("box")
elif obj_type == 1: # Sphere
shape_node = geo_node.createNode("sphere")
else: # Torus
shape_node = geo_node.createNode("torus")
shape_node.parm("tx").set(obj_size)
shape_node.parm("ty").set(obj_size)
hou.ui.displayMessage(f"Created {obj_type} named '{obj_name}' with size {obj_size}!")
# 关闭窗口
window.close()
# 将按钮的点击事件与回调函数连接起来
create_button.addEventCallback(hou.ui.EventCallbacks.ButtonClicked, on_create_clicked)
# 显示窗口
window.show()
# 调用函数来显示工具窗口
create_tool_window()
将按钮集成到 Houdini 界面
为了让你的工具更容易访问,你可以把它添加到 Houdini 的菜单或工具架上。
添加到菜单
- 在文本编辑器中创建一个文件,
~/Documents/houdiniXX.X/scripts/my_menu.py(XX.X 是你的 Houdini 版本)。 - 在文件中写入以下代码:
import hou
def add_my_menu():
"""在 'Python' 菜单下添加一个自定义项"""
# 获取 'Python' 菜单
python_menu = hou.ui.mainMenu().findMenu("Python")
# 'Python' 菜单不存在,创建它
if not python_menu:
python_menu = hou.ui.mainMenu().addMenu("Python")
# 添加一个菜单项
# 第一个参数是菜单项的标签
# 第二个参数是回调函数
# 第三个参数是快捷键 (可选)
action = python_menu.addAction("Show My Tool", show_my_tool)
action.setShortcut("Ctrl+Shift+M") # 设置快捷键
def show_my_tool():
"""显示我们之前创建的工具窗口"""
# 这里我们直接调用创建工具窗口的函数
# 注意:为了避免重复定义,最好把工具窗口的代码放在另一个函数里,然后在这里调用
from my_tool_module import create_tool_window # 假设你把工具代码放在了 my_tool_module.py
create_tool_window()
# 在 Houdini 启动时自动执行
add_my_menu()
- 重启 Houdini,你会在
Python菜单下看到 "Show My Tool" 选项。
总结与最佳实践
| 场景 | 推荐方法 | 优点 |
|---|---|---|
| 节点间的逻辑连接与自动化 | Python 节点 | 与场景数据流无缝集成,易于版本控制和共享。 |
| 快速测试、调试、一次性操作 | Python Shell | 即时反馈,无需保存文件。 |
| 创建可重用的、独立的工具 | 自定义 UI 窗口 | 用户友好,有清晰的交互界面。 |
| 全局快捷方式或常用功能 | 集成到菜单/工具架 | 快速访问,提高工作效率。 |
重要提示:
- 错误处理:在编写复杂的脚本时,使用
try...except块来捕获和处理错误,避免脚本意外中断。try: # 可能出错的代码 node = hou.node("/obj/my_missing_node") except hou.NodeNotFoundError: hou.ui.displayMessage("The required node was not found!") - 帮助文档:Houdini 的 Python 模块文档是你的好朋友,在 Python Shell 中输入
help(hou)或help(hou.ui)可以查看详细的文档和示例。 - 性能:对于处理大量数据的 SOP 节点,优先考虑使用 VEX 或
hou.Geometry中的底层方法,它们通常比纯 Python 循环快得多。
希望这个详细的指南能帮助你开始在 Houdini 中使用 Python 按钮和创建强大的工具!
