【随手练习】- houdini+comfyui+hunyuan3d 流程搭建
使用这个保存下来的json文件,就能来传给comfyui的前端了。这里我们遇到了又一个坑点,我们的工作流只能生成glb格式的模型文件,而houdini当前并不支持该格式的文件导入,需要转换为obj格式。之所以要在script中写的原因是,我们想要创建一个按钮,当点击按钮后,运行script中的函数,这样就避免了使用python sop时,每次bake都会走我们代码的尴尬处境。如此,在加载好json
我们分析下这个需求大概可能有哪些步骤。
首先需要安装comfyui,并在上面实现一个混元3d生成模型的工作流。之后我们需要到houdini里去制作一个python sop节点,用其和comfy ui的前端做http交互。然后再拉取结果到houdini内,并在工作流上显示出来当前生成的模型。
这里我默认读者都是已经安装了comfyui的,且已经有了混元3d生成模型的工作流,且有一定python基础。如果有同学还没安装comfyui的话可以评论区留言,我再出一期安装教程。如果没有py基础的话,建议阅读完后可以到菜鸟教程看看,不要问我咋知道这个网站,因为这是我来时的路!
另外混元3d的工作流在comfyui的最新版本中已经默认支持了,我们只需要从模板里选出来,并安装指定模型即可。
ComfyUI选择模型生成工作流
现在我们开始正常的流程搭建。
我们知道houdini是有py模块扩展的,他本身也能使用py脚本实现一些功能。但是由于他自带的编辑器过于难用。我更推荐我们用一个更温和的方式来实现这个流程。那就是我们先用comfyui的工程,做一个测试脚本来测试沟通前端,相当于模拟在houdini里。之后我们只需要做些简单的修改,放入houdini中即可。
通过了解我们知道,想要从外部触发comfyui的流程烘焙的话,需要将我们的工作流json文件传入到这个地址里。
http://localhost:8188/prompt
在这之前,我们还需要修改工作流json中的参数值,以用来生成不同的图片的模型。
这里我遇到了第一个坑点,我认为的json文件,就是咱们保存工作流时的那个,位置在 ComfyUI\user\default\workflows下,但实际上并不是。他是得开启api模式后保存的json文件。
寻找api json
使用这个保存下来的json文件,就能来传给comfyui的前端了。在传过去之前,我们需要修改下参数的值。分析了一下这个json文件,发现如果需要更换贴图的话,需要更换56号节点的image参数。

如此,在加载好json文件后,修改对应的值即可,大家如果有其他需要修改的参数(如模型面数,生成步数等),只需要找对应的节点即可。
source = "C:/Users/Administrator/Downloads/test1.jpg"
file_name = os.path.basename(source)
# 加载你之前保存的ComfyUI工作流模板JSON
with open("D:/AI/hunyuan_api.json", "r", encoding="utf-8") as f:
workflow_data = json.load(f)
# 设置json
workflow_data["56"]["inputs"]["image"] = file_name
当我们修改完json文件后,我们立刻意识到一个问题,这个文件名是传进去了,可是文件还在我们本地啊,comfyui是如何读取到的呢。通过了解后得知,我们需要将图片上传给他,具体就是将目标图片通过http沟通
http://localhost:8188/upload/image
而沟通方式是使用request库中的post方法,这样一来,comfyui就能准确的读取到我们想要生成的图片的信息了。
//postjson文件
response1 = requests.post(f"{self.base_url}/prompt", json=prompt_payload)
//使用这个来获取当前工作流队列的prompt_id,用于等待并获取工作流结果
response1.json()["prompt_id"]
//上传图片
response2 = requests.post(upload_url, files=files)
之后我们需要等待前端给我们返回结果,并分析结果内容,获取到模型,并下载
def get_history(self, prompt_id):
"""获取指定prompt的历史记录"""
response = requests.get(f"{self.base_url}/history/{prompt_id}")
return response.json()
def get_glb_output_url(self, prompt_id):
"""获取saveGLB节点输出的文件URL"""
# 等待工作流执行完成
while True:
history = self.get_history(prompt_id)
if prompt_id in history:
break
time.sleep(1)
# 从历史记录中获取输出信息
node_output = history[prompt_id].get("outputs", {}).get("82", {}).get("3d",{})
if not node_output:
print("错误:节点输出中没有3D文件信息")
return None
# 取第一个文件(通常只有一个)
glb_info = node_output[0]
filename = glb_info.get("filename")
subfolder = glb_info.get("subfolder")
file_url = f"{self.base_url}/view?filename={filename}&subfolder={subfolder}&type=output"
print(f"文件URL: {file_url}")
# 构造文件访问URL
# 默认情况下,ComfyUI会将输出文件放在output目录,并通过/files路径提供访问
return file_url
这段代码是等待并获取结果
history[prompt_id].get("outputs", {}).get("82", {}).get("3d",{})
至于这里为何要用这样去获取模型文件。需要大家打断点多去观察下history文件的结构。我这里直接贴出来了,如果大家的工作流跟我使用的同一个那没问题,如果是自己搭建的工作流,记得要更改参数哦。
同时我这里也给出了获取history的方式
requests.get(f"{self.base_url}/history/{prompt_id}")
以及文件的下载地址
file_url = f"{self.base_url}/view?filename={filename}&subfolder={subfolder}&type=output"
之后的流程就比较简单了,就是到对应地址下载文件即可。
def download_glb_from_url(self, url, timeout=30):
try:
# 发送GET请求,stream=True用于大文件分块下载
response = requests.get(url, stream=True, timeout=timeout)
response.raise_for_status() # 如果请求失败,抛出HTTPError异常
# 创建一个临时文件来保存下载的GLB内容
# 使用tempfile库可以避免手动处理临时文件的删除
with tempfile.NamedTemporaryFile(suffix='.glb', delete=False) as tmp_file:
# 分块写入文件,避免内存占用过高
for chunk in response.iter_content(chunk_size=8192):
if chunk:
tmp_file.write(chunk)
local_path = tmp_file.name
print(f"GLB文件已下载到: {local_path}")
return local_path
except requests.exceptions.RequestException as e:
print(f"下载GLB文件时出错: {e}")
return None
当我们在py环境下正常跑通,沟通comfyui前端的流程后(即正常下载了模型文件到本地),即可开始进入houdini中了。
进入houdini后我们遇到的第一个问题就是,houdini的py环境中没有request库。我们需要使用pip去安装,然而他可能还没有pip。
如此,我们需要先下载pip文件,安装pip,再安装request库。
https://bootstrap.pypa.io/get-pip.py
https://bootstrap.pypa.io/get-pip.py
先到这个地址,右键保存文件,然后放到houdini的py文件夹下。这里举例我的地址
D:\Program Files\Side Effects Software\Houdini 19.5.303\python39
到这里cmd直接进控制台

python.exe get-pip.py
当安装了pip后就简单了,我们直接使用pip安装request即可。
//先确认下是不是真的安装上了
python.exe -m pip --version
//安装request
python.exe -m pip install requests
接下来我们正式进入houdini
首先我们需要先制作一个hda资产文件。具体的制作流程有不会的同学,需要到b站学习一下,这个是我之前看的视频地址5.简单HDA的制作_哔哩哔哩_bilibili
https://www.bilibili.com/video/BV1Jv411i7uR/?spm_id_from=333.1391.0.0&p=5&vd_source=04a3496142588a0077dd16679623207b 然后我们需要在资产文件的script中编写代码。
创建HDA
之所以要在script中写的原因是,我们想要创建一个按钮,当点击按钮后,运行script中的函数,这样就避免了使用python sop时,每次bake都会走我们代码的尴尬处境。
最终我们had的参数面板希望是这样的

按钮中的callback script 使用

kwargs['node'].hdaModule().execute_comfyui_upload()
很明显execute_comfyui_upload方法就是我们的代码入口,大家可以按需替换。
接下来的流程基本就是把之前的代码拷贝到houdini中。这里需要再补充的流程就剩下,将下载好的模型文件显示在houdini中的流程了。
这里我们遇到了又一个坑点,我们的工作流只能生成glb格式的模型文件,而houdini当前并不支持该格式的文件导入,需要转换为obj格式。我们注意到工作流上是有下载obj到本地的选项的。

我本以为可以直接通过修改参数来下载这个obj文件,但是通过定位前端代码,发现这个obj选项内部实现是把glb文件用three.js转换了一个obj出来。既然如此,我们也就自己转换一下得了。
为了转换glb文件,我们需要对houdini的py安装trimesh库
python.exe -m pip install trimesh
# 使用这个来看下当前有没有安装上
python.exe -m pip list
然后使用这个库转换模型
def convert_glb_to_obj(glb_path, output_dir=None):
try:
if output_dir is None:
output_dir = os.path.dirname(glb_path)
obj_path = os.path.join(output_dir, "converted_model.obj")
if not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
# 加载GLB文件
mesh = trimesh.load(glb_path)
# 导出为OBJ
mesh.export(obj_path)
print(f"GLB文件已转换为OBJ: {obj_path}")
return obj_path
except Exception as e:
print(f"转换GLB文件时出错: {e}")
return None
最后,我们使用file sop节点来将转换后的模型文件显示出来,并连接到输出上。这里使用的是houdini的python api。
def creat_node(obj_path):
node = hou.pwd() # 获取当前HDA节点
file_node = node.node("my_file_node")
if file_node is None:
file_node = node.createNode("file", "my_file_node")
# 创建File SOP节点来加载OBJ
file_node.parm("file").set(obj_path)
output_node = node.node("output0")
if output_node is None:
output_node = node.createNode("output", "output0") # 如果不存在则创建输出节点
output_node.setInput(0, file_node)
output_node.setDisplayFlag(True)
node.layoutChildren()
def execute_comfyui_upload():
node = hou.pwd()
json_path = node.parm('json_path').eval()
image_path = node.parm('image_path').eval()
if not image_path or not os.path.exists(image_path):
raise FileNotFoundError(f"Image file not found at path: {image_path}")
comfyui_server = "http://127.0.0.1:8188"
with open(json_path, "r", encoding="utf-8") as f:
workflow_data = json.load(f)
client = ComfyUIClient(comfyui_server)
try:
print("开始上传图像到 ComfyUI...")
result = client.upload_image(image_path)
print("上传成功!服务器返回信息:")
print(json.dumps(result, indent=2))
print("修改工作流信息")
file_name = os.path.basename(image_path)
workflow_data["56"]["inputs"]["image"] = file_name
print("开始生成")
result = client.queue_prompt(workflow_data)
prompt_id = result["prompt_id"]
glb_url = client.get_glb_output_url(prompt_id)
print("生成结束")
print("下载模型")
local_path = client.download_glb_from_url(glb_url)
tar_path = "output/mesh"
obj_path = convert_glb_to_obj(local_path,tar_path)
os.remove(local_path)
creat_node(obj_path)
except Exception as e:
print(f"上传失败: {str(e)}")
raise # 可以选择再次抛出异常或直接处理
这里就是全部流程啦。注意使用按钮前先启动你的comfyui哦。
辛苦你认真看到这里。之后还是需要你自己动手跑一遍尝试一下,如果遇到什么问题,可以评论区我们一起讨论一下,期待大家评论区里提交动图分享喜悦。
最最最后,如果还是搭建不出来,或者想立刻尝鲜,可以直接私聊我获取hda文件。
更多推荐




所有评论(0)