我们分析下这个需求大概可能有哪些步骤。

        首先需要安装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.pyhttps://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的制作_哔哩哔哩_bilibilihttps://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文件。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐