initial commit

This commit is contained in:
paulh4x
2025-07-07 23:18:31 +02:00
parent d7bb02da2b
commit 9b23fbd625
21 changed files with 11593 additions and 15 deletions
+59 -15
View File
@@ -1,4 +1,4 @@
# ComfyUI-PHRenderFormerWrapper
# ✨ ComfyUI-PHRenderFormerWrapper ✨
**Author:** paulh4x
@@ -11,15 +11,54 @@
This repository contains a set of custom nodes for ComfyUI that provide a wrapper for Microsoft's **RenderFormer** model. It allows you to render complex 3D scenes with physically-based materials and global illumination directly within the ComfyUI interface.
## Features
---
- **End-to-End Rendering:** Load 3D models, define materials, set up cameras, and render—all within ComfyUI.
- **Modular Node-Based Workflow:** Each step of the rendering pipeline is a separate node, allowing for flexible and complex setups.
- **Advanced Mesh Processing:** Includes nodes for loading, combining, remeshing, and applying simple color randomization to your 3D assets.
- **Lighting and Material Control:** Easily add default light sources and control PBR material properties like diffuse, specular, roughness, and emission.
- **Full Transformation Control:** Apply translation, rotation, and scaling to objects within the scene.
### 🌱 My Journey
## Installation
This project represents my very first baby steps into the world of coding and my first-ever contribution to the open-source community. ❤️ It was born out of a desire to learn and create, fueled by late-night sessions of what can only be described as "vibecoding."
What started as a simple experiment quickly grew into a passion project. It has been a journey of discovery, filled with challenges, learning, and the immense satisfaction of seeing an idea come to life. I hope this wrapper brings as much utility and fun to your projects as it has brought me in building it. Thank you for being a part of my story!
---
### Version 0.1 - Initial Development
This initial version of the PHRenderFormerWrapper lays the foundation for rendering 3D scenes within ComfyUI. The focus was on establishing the core architecture, implementing a comprehensive set of nodes for scene construction, and creating a flexible, user-friendly workflow.
**Key Features & Accomplishments:**
* **Core Rendering Pipeline:**
* `RenderFormerModelLoader`: Loads the RenderFormer model from Hugging Face.
* `RenderFormerGenerator`: The main sampler node that renders the final image from a scene.
* **In-Memory Scene Processing:** The entire scene-to-HDF5 conversion process is handled in memory, patching `trimesh` and `h5py` to avoid slow disk operations and temporary files. This is a key performance and efficiency feature.
* **Modular Scene Construction:**
* `LoadMesh`: Loads `.obj`, `.glb`, and other 3D files. Also acts as the central point for defining PBR materials.
* `RenderFormerCamera`: Defines camera position, target, and FOV.
* `RenderFormerLighting`: Creates an emissive light source with configurable properties.
* `RenderFormerSceneBuilder`: Assembles all components (meshes, materials, camera, lights) into a final scene ready for rendering.
* **Advanced Node Functionality:**
* `RenderFormerMeshCombine`: Allows for combining multiple `PH_MESH` objects into a single scene.
* `RenderFormerLightingCombine`: Allows for combining multiple light sources.
* `RemeshMesh`: Simplifies mesh geometry to a target face count using `pymeshlab`.
* `RandomizeColors`: A utility node to apply a deterministic, gradient-based color pattern to a mesh's faces, useful for debugging and creative effects.
* `RenderFormerFromJSON` & `LoadRenderFormerExampleScene`: Provides advanced methods for loading scenes directly from JSON definitions or the original RenderFormer example files.
* **UI/UX Enhancements:**
* **File Uploader:** The `LoadMesh` node includes a convenient "choose mesh to upload" button.
* **Advanced Color Picker:** The `diffuse_rgb` string input was replaced with a custom, canvas-based interactive color picker for a much better user experience.
* **High-Precision Transforms:** All transform inputs (translation, rotation, scale) were given high precision for fine-grained control.
### 🚀 Features
- **🎨 End-to-End Rendering:** Load 3D models, define materials, set up cameras, and render—all within ComfyUI.
- **⚙️ Modular Node-Based Workflow:** Each step of the rendering pipeline is a separate node, allowing for flexible and complex setups.
- **🔧 Advanced Mesh Processing:** Includes nodes for loading, combining, remeshing, and applying simple color randomization to your 3D assets.
- **💡 Lighting and Material Control:** Easily add default light sources and control PBR material properties like diffuse, specular, roughness, and emission.
- **↔️ Full Transformation Control:** Apply translation, rotation, and scaling to objects within the scene.
### 🛠️ Installation
1. Navigate to your ComfyUI `custom_nodes` directory:
```bash
@@ -27,30 +66,30 @@ This repository contains a set of custom nodes for ComfyUI that provide a wrappe
```
2. Clone this repository:
```bash
git clone <repository_url> ComfyUI-PHRenderFormerWrapper
git clone <repository_url> ComfyUI_PHRenderFormerWrapper
```
3. Install the required dependencies:
```bash
cd ComfyUI-PHRenderFormerWrapper
cd ComfyUI_PHRenderFormerWrapper
pip install -r requirements.txt
```
4. Restart ComfyUI.
## Nodes
### 📦 Nodes
- **PHRenderFormer Model Loader**: Loads a specified RenderFormer model from Hugging Face or a local path.
- **PHRenderFormer Mesh Loader**: Loads a 3D mesh file (e.g., `.obj`, `.glb`) from your `ComfyUI/input/3d` directory.
- **PHRenderFormer Mesh Loader**: Loads a 3D mesh file (e.g., `.obj`, `.glb`). Includes a file upload button to add models directly to your `ComfyUI/input/3d` directory.
- **PHRenderFormer Mesh Combine**: Combines multiple meshes into a single scene object.
- **PHRenderFormer Remesh**: Simplifies the geometry of a mesh to a target face count using `pymeshlab`.
- **PHRenderFormer Random Colors**: Applies random vertex colors to a mesh for creative effects.
- **PHRenderFormer Camera**: Defines the camera's position, look-at target, and field of view (FOV).
- **PHRenderFormer Material**: Defines the PBR material properties for a mesh.
- **PHRenderFormer Material**: Defines the PBR material properties for a mesh. The diffuse color can be set using an interactive, canvas-based color picker within the `PHRenderFormer Mesh Loader` node.
- **PHRenderFormer Lighting**: Controls the scene's lighting, allowing you to add and configure a default emissive light source.
- **PHRenderFormer Scene Builder**: Assembles the final scene by combining meshes, a camera, materials, lighting, and transformations.
- **PHRenderFormer Sampler**: Executes the RenderFormer pipeline on the assembled scene to produce the final rendered image.
- **PHRenderFormer From JSON**: Loads a scene from a JSON definition, allowing for more complex and customized setups.
## Acknowledgements
### 🙏 Acknowledgements
This project would not be possible without the foundational work of others.
@@ -60,4 +99,9 @@ This project would not be possible without the foundational work of others.
- [Official RenderFormer GitHub](https://github.com/microsoft/renderformer)
- **comfyui-hunyuan3dwrapper**
Special thanks to **kijai** for their work on the `comfyui-hunyan3dwrapper`, which served as an invaluable reference and starting point for this project during its development in `vibecoding`.
Special thanks to **kijai** for their work on the `comfyui-hunyan3dwrapper`, which served as an invaluable reference and starting point for this project during its development in `vibecoding`.
- [ComfyUI-Hunyuan3DWrapper GitHub](https://github.com/kijai/ComfyUI-Hunyuan3DWrapper)
- **ComfyUI_Fill-Example-Nodes**
A huge thank you to **filliptm** for creating the `ComfyUI_Fill-Example-Nodes` repository. The advanced color picker in this project was implemented by adapting the excellent example code provided in that repo. It was an essential learning resource for understanding how to build custom UI elements in ComfyUI.
- [ComfyUI_Fill-Example-Nodes GitHub](https://github.com/filliptm/ComfyUI_Fill-Example-Nodes)
+13
View File
@@ -0,0 +1,13 @@
import os
import folder_paths
from .nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
# Register the 3D models directory
input_3d_dir = os.path.join(folder_paths.get_input_directory(), "3d")
if not os.path.exists(input_3d_dir):
os.makedirs(input_3d_dir)
folder_paths.add_model_folder_path("3d", input_3d_dir)
WEB_DIRECTORY = "./web"
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
Binary file not shown.
Binary file not shown.
+12
View File
@@ -0,0 +1,12 @@
# 3ds Max Wavefront OBJ Exporter v0.99 - (c)2007 guruware
# File Created: 06.07.2025 04:13:21
newmtl wire_177027088
Ns 32
d 1
Tr 0
Tf 1 1 1
illum 2
Ka 0.6941 0.1059 0.3451
Kd 0.6941 0.1059 0.3451
Ks 0.3500 0.3500 0.3500
+52
View File
@@ -0,0 +1,52 @@
# 3ds Max Wavefront OBJ Exporter v0.99 - (c)2007 guruware
# File Created: 06.07.2025 04:13:21
mtllib phrenderformer_cube_00.mtl
#
# object Box001
#
v -0.5000 -0.5000 0.5000
v -0.5000 -0.5000 -0.5000
v 0.5000 -0.5000 -0.5000
v 0.5000 -0.5000 0.5000
v -0.5000 0.5000 0.5000
v 0.5000 0.5000 0.5000
v 0.5000 0.5000 -0.5000
v -0.5000 0.5000 -0.5000
# 8 vertices
vn -0.5774 -0.5774 0.5774
vn -0.5774 -0.5774 -0.5774
vn 0.5774 -0.5774 -0.5774
vn 0.5774 -0.5774 0.5774
vn -0.5774 0.5774 0.5774
vn 0.5774 0.5774 0.5774
vn 0.5774 0.5774 -0.5774
vn -0.5774 0.5774 -0.5774
# 8 vertex normals
vt 1.0000 0.0000 0.0000
vt 1.0000 1.0000 0.0000
vt 0.0000 1.0000 0.0000
vt 0.0000 0.0000 0.0000
# 4 texture coords
o Box001
g Box001
usemtl wire_177027088
s 2
f 1/1/1 2/2/2 3/3/3 4/4/4
s 4
f 5/4/5 6/1/6 7/2/7 8/3/8
s 8
f 1/4/1 4/1/4 6/2/6 5/3/5
s 16
f 4/4/4 3/1/3 7/2/7 6/3/6
s 32
f 3/4/3 2/1/2 8/2/8 7/3/7
s 64
f 2/4/2 1/1/1 5/2/5 8/3/8
# 6 polygons
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
# 3ds Max Wavefront OBJ Exporter v0.99 - (c)2007 guruware
# File Created: 06.07.2025 04:12:20
newmtl wire_177088027
Ns 32
d 1
Tr 0
Tf 1 1 1
illum 2
Ka 0.6941 0.3451 0.1059
Kd 0.6941 0.3451 0.1059
Ks 0.3500 0.3500 0.3500
+52
View File
@@ -0,0 +1,52 @@
# 3ds Max Wavefront OBJ Exporter v0.99 - (c)2007 guruware
# File Created: 06.07.2025 04:12:20
mtllib phrenderformerbox_00.mtl
#
# object Box002
#
v -0.3265 -0.1491 0.9984
v -0.3265 -0.1491 -0.9984
v 0.3265 -0.1491 -0.9984
v 0.3265 -0.1491 0.9984
v -0.3265 0.1491 0.9984
v 0.3265 0.1491 0.9984
v 0.3265 0.1491 -0.9984
v -0.3265 0.1491 -0.9984
# 8 vertices
vn -0.5774 -0.5774 0.5774
vn -0.5774 -0.5774 -0.5774
vn 0.5774 -0.5774 -0.5774
vn 0.5774 -0.5774 0.5774
vn -0.5774 0.5774 0.5774
vn 0.5774 0.5774 0.5774
vn 0.5774 0.5774 -0.5774
vn -0.5774 0.5774 -0.5774
# 8 vertex normals
vt 1.0000 0.0000 0.0000
vt 1.0000 1.0000 0.0000
vt 0.0000 1.0000 0.0000
vt 0.0000 0.0000 0.0000
# 4 texture coords
o Box002
g Box002
usemtl wire_177088027
s 2
f 1/1/1 2/2/2 3/3/3 4/4/4
s 4
f 5/4/5 6/1/6 7/2/7 8/3/8
s 8
f 1/4/1 4/1/4 6/2/6 5/3/5
s 16
f 4/4/4 3/1/3 7/2/7 6/3/6
s 32
f 3/4/3 2/1/2 8/2/8 7/3/7
s 64
f 2/4/2 1/1/1 5/2/5 8/3/8
# 6 polygons
Binary file not shown.
+12
View File
@@ -0,0 +1,12 @@
# 3ds Max Wavefront OBJ Exporter v0.99 - (c)2007 guruware
# File Created: 06.07.2025 00:28:45
newmtl wire_238166000
Ns 32
d 1
Tr 0
Tf 1 1 1
illum 2
Ka 0.9333 0.6510 0.0000
Kd 0.9333 0.6510 0.0000
Ks 0.3500 0.3500 0.3500
+508
View File
@@ -0,0 +1,508 @@
# 3ds Max Wavefront OBJ Exporter v0.99 - (c)2007 guruware
# File Created: 06.07.2025 00:28:45
mtllib phrenderformertest_00.mtl
#
# object Text001
#
v -0.0242 -0.1862 -0.0907
v -0.0211 -0.1862 -0.0681
v -0.0211 0.0138 -0.0681
v -0.0242 0.0138 -0.0907
v -0.0158 -0.1862 -0.0474
v -0.0158 0.0138 -0.0474
v -0.0084 -0.1862 -0.0287
v -0.0084 0.0138 -0.0287
v 0.0010 -0.1862 -0.0118
v 0.0010 0.0138 -0.0118
v 0.0126 -0.1862 0.0031
v 0.0126 0.0138 0.0031
v 0.0263 -0.1862 0.0161
v 0.0263 0.0138 0.0161
v 0.0422 -0.1862 0.0273
v 0.0422 0.0138 0.0273
v 0.0606 -0.1862 0.0368
v 0.0606 0.0138 0.0368
v 0.0814 -0.1862 0.0445
v 0.0814 0.0138 0.0445
v 0.1046 -0.1862 0.0506
v 0.1046 0.0138 0.0506
v 0.1303 -0.1862 0.0549
v 0.1303 0.0138 0.0549
v 0.1584 -0.1862 0.0574
v 0.1584 0.0138 0.0574
v 0.1890 -0.1862 0.0583
v 0.1890 0.0138 0.0583
v 0.4047 -0.1862 0.0583
v 0.4047 0.0138 0.0583
v 0.4047 -0.1862 -0.4687
v 0.4047 0.0138 -0.4687
v 0.2457 -0.1862 -0.4687
v 0.2457 0.0138 -0.4687
v 0.2457 -0.1862 -0.2987
v 0.2457 0.0138 -0.2987
v 0.1974 -0.1862 -0.2987
v 0.1974 0.0138 -0.2987
v 0.1786 -0.1862 -0.2982
v 0.1786 0.0138 -0.2982
v 0.1604 -0.1862 -0.2968
v 0.1604 0.0138 -0.2968
v 0.1430 -0.1862 -0.2945
v 0.1430 0.0138 -0.2945
v 0.1262 -0.1862 -0.2912
v 0.1262 0.0138 -0.2912
v 0.1100 -0.1862 -0.2870
v 0.1100 0.0138 -0.2870
v 0.0946 -0.1862 -0.2818
v 0.0946 0.0138 -0.2818
v 0.0798 -0.1862 -0.2758
v 0.0798 0.0138 -0.2758
v 0.0659 -0.1862 -0.2688
v 0.0659 0.0138 -0.2688
v 0.0528 -0.1862 -0.2611
v 0.0528 0.0138 -0.2611
v 0.0408 -0.1862 -0.2526
v 0.0408 0.0138 -0.2526
v 0.0297 -0.1862 -0.2434
v 0.0297 0.0138 -0.2434
v 0.0195 -0.1862 -0.2334
v 0.0195 0.0138 -0.2334
v 0.0103 -0.1862 -0.2226
v 0.0103 0.0138 -0.2226
v 0.0020 -0.1862 -0.2110
v 0.0020 0.0138 -0.2110
v -0.0052 -0.1862 -0.1988
v -0.0052 0.0138 -0.1988
v -0.0114 -0.1862 -0.1861
v -0.0114 0.0138 -0.1861
v -0.0164 -0.1862 -0.1729
v -0.0164 0.0138 -0.1729
v -0.0203 -0.1862 -0.1592
v -0.0203 0.0138 -0.1592
v -0.0231 -0.1862 -0.1451
v -0.0231 0.0138 -0.1451
v -0.0247 -0.1862 -0.1304
v -0.0247 0.0138 -0.1304
v -0.0253 -0.1862 -0.1152
v -0.0253 0.0138 -0.1152
v 0.1441 -0.1862 -0.1382
v 0.1482 -0.1862 -0.1527
v 0.1482 0.0138 -0.1527
v 0.1441 0.0138 -0.1382
v 0.1552 -0.1862 -0.1646
v 0.1552 0.0138 -0.1646
v 0.1648 -0.1862 -0.1738
v 0.1648 0.0138 -0.1738
v 0.1773 -0.1862 -0.1804
v 0.1773 0.0138 -0.1804
v 0.1925 -0.1862 -0.1844
v 0.1925 0.0138 -0.1844
v 0.2104 -0.1862 -0.1857
v 0.2104 0.0138 -0.1857
v 0.2457 -0.1862 -0.1857
v 0.2457 0.0138 -0.1857
v 0.2457 -0.1862 -0.0557
v 0.2457 0.0138 -0.0557
v 0.2159 -0.1862 -0.0557
v 0.2159 0.0138 -0.0557
v 0.2059 -0.1862 -0.0560
v 0.2059 0.0138 -0.0560
v 0.1967 -0.1862 -0.0570
v 0.1967 0.0138 -0.0570
v 0.1882 -0.1862 -0.0587
v 0.1882 0.0138 -0.0587
v 0.1804 -0.1862 -0.0611
v 0.1804 0.0138 -0.0611
v 0.1733 -0.1862 -0.0641
v 0.1733 0.0138 -0.0641
v 0.1669 -0.1862 -0.0678
v 0.1669 0.0138 -0.0678
v 0.1613 -0.1862 -0.0722
v 0.1613 0.0138 -0.0722
v 0.1564 -0.1862 -0.0773
v 0.1564 0.0138 -0.0773
v 0.1522 -0.1862 -0.0830
v 0.1522 0.0138 -0.0830
v 0.1488 -0.1862 -0.0893
v 0.1488 0.0138 -0.0893
v 0.1461 -0.1862 -0.0963
v 0.1461 0.0138 -0.0963
v 0.1442 -0.1862 -0.1039
v 0.1442 0.0138 -0.1039
v 0.1431 -0.1862 -0.1122
v 0.1431 0.0138 -0.1122
v 0.1427 -0.1862 -0.1211
v 0.1427 0.0138 -0.1211
# 128 vertices
vn -0.7146 -0.6965 0.0651
vn -0.7056 -0.6949 0.1386
vn -0.7056 0.6949 0.1386
vn -0.7146 0.6965 0.0651
vn -0.6859 -0.6933 0.2209
vn -0.6859 0.6933 0.2209
vn -0.6523 -0.6919 0.3095
vn -0.6523 0.6919 0.3095
vn -0.6025 -0.6909 0.3996
vn -0.6025 0.6909 0.3996
vn -0.5367 -0.6905 0.4849
vn -0.5367 0.6905 0.4849
vn -0.4582 -0.6908 0.5593
vn -0.4582 0.6908 0.5593
vn -0.3736 -0.6921 0.6176
vn -0.3736 0.6921 0.6176
vn -0.2911 -0.6939 0.6586
vn -0.2911 0.6939 0.6586
vn -0.2158 -0.6958 0.6851
vn -0.2158 0.6958 0.6851
vn -0.1493 -0.6974 0.7009
vn -0.1493 0.6974 0.7009
vn -0.0919 -0.6988 0.7094
vn -0.0919 0.6988 0.7094
vn -0.0428 -0.7000 0.7128
vn -0.0428 0.7000 0.7128
vn -0.0100 -0.7039 0.7102
vn -0.0100 0.7039 0.7102
vn 0.5774 -0.5774 0.5774
vn 0.5774 0.5774 0.5774
vn 0.5774 -0.5774 -0.5774
vn 0.5774 0.5774 -0.5774
vn -0.5774 -0.5774 -0.5774
vn -0.5774 0.5774 -0.5774
vn -0.3015 -0.9045 -0.3015
vn -0.3015 0.9045 -0.3015
vn -0.0088 -0.7044 -0.7098
vn -0.0088 0.7044 -0.7098
vn -0.0364 -0.7013 -0.7119
vn -0.0364 0.7013 -0.7119
vn -0.0749 -0.7009 -0.7093
vn -0.0749 0.7009 -0.7093
vn -0.1157 -0.7005 -0.7042
vn -0.1157 0.7005 -0.7042
vn -0.1587 -0.7002 -0.6961
vn -0.1587 0.7002 -0.6961
vn -0.2033 -0.6998 -0.6848
vn -0.2033 0.6998 -0.6848
vn -0.2492 -0.6994 -0.6699
vn -0.2492 0.6994 -0.6699
vn -0.2953 -0.6993 -0.6510
vn -0.2953 0.6993 -0.6510
vn -0.3415 -0.6989 -0.6284
vn -0.3415 0.6989 -0.6284
vn -0.3884 -0.6984 -0.6011
vn -0.3884 0.6984 -0.6011
vn -0.4352 -0.6981 -0.5686
vn -0.4352 0.6981 -0.5686
vn -0.4809 -0.6978 -0.5308
vn -0.4809 0.6978 -0.5308
vn -0.5244 -0.6976 -0.4883
vn -0.5244 0.6976 -0.4883
vn -0.5644 -0.6975 -0.4415
vn -0.5644 0.6975 -0.4415
vn -0.6000 -0.6976 -0.3915
vn -0.6000 0.6976 -0.3915
vn -0.6314 -0.6976 -0.3388
vn -0.6314 0.6976 -0.3388
vn -0.6582 -0.6976 -0.2832
vn -0.6582 0.6976 -0.2832
vn -0.6800 -0.6976 -0.2256
vn -0.6800 0.6976 -0.2256
vn -0.6964 -0.6979 -0.1673
vn -0.6964 0.6979 -0.1673
vn -0.7074 -0.6982 -0.1096
vn -0.7074 0.6982 -0.1096
vn -0.7135 -0.6986 -0.0536
vn -0.7135 0.6986 -0.0536
vn -0.7158 -0.6983 0.0022
vn -0.7158 0.6983 0.0022
vn 0.6724 -0.7301 0.1219
vn 0.6227 -0.7362 0.2652
vn 0.6227 0.7362 0.2652
vn 0.6724 0.7301 0.1219
vn 0.5280 -0.7401 0.4165
vn 0.5280 0.7401 0.4165
vn 0.3939 -0.7393 0.5461
vn 0.3939 0.7393 0.5461
vn 0.2462 -0.7343 0.6327
vn 0.2462 0.7343 0.6327
vn 0.1119 -0.7281 0.6763
vn 0.1119 0.7281 0.6763
vn 0.0256 -0.7154 0.6982
vn 0.0256 0.7154 0.6982
vn -0.3015 -0.9045 0.3015
vn -0.3015 0.9045 0.3015
vn 0.0121 0.7033 -0.7108
vn 0.0119 0.7109 -0.7031
vn 0.0499 -0.7157 -0.6966
vn 0.0512 -0.6987 -0.7136
vn 0.1088 0.6975 -0.7083
vn 0.1058 0.7169 -0.6890
vn 0.1685 -0.7184 -0.6749
vn 0.1739 -0.6962 -0.6964
vn 0.2461 0.6949 -0.6757
vn 0.2376 0.7198 -0.6522
vn 0.3112 -0.7211 -0.6190
vn 0.3236 -0.6936 -0.6436
vn 0.4032 0.6926 -0.5982
vn 0.3866 0.7222 -0.5735
vn 0.4598 -0.7230 -0.5157
vn 0.4805 -0.6919 -0.5389
vn 0.5511 0.6916 -0.4669
vn 0.5268 0.7233 -0.4463
vn 0.5842 -0.7230 -0.3687
vn 0.5842 0.7230 -0.3687
vn 0.6292 -0.7221 -0.2874
vn 0.6292 0.7221 -0.2874
vn 0.6615 -0.7208 -0.2070
vn 0.6615 0.7208 -0.2070
vn 0.6821 -0.7194 -0.1312
vn 0.6821 0.7194 -0.1312
vn 0.6934 -0.7178 -0.0622
vn 0.6934 0.7178 -0.0622
vn 0.6926 -0.7212 0.0131
vn 0.6926 0.7212 0.0131
# 126 vertex normals
o Text001
g Text001
usemtl wire_238166000
s 1
f 1//1 2//2 3//3 4//4
s 3
f 2//2 5//5 6//6 3//3
s 2
f 5//5 7//7 8//8 6//6
f 7//7 9//9 10//10 8//8
f 9//9 11//11 12//12 10//10
f 11//11 13//13 14//14 12//12
f 13//13 15//15 16//16 14//14
f 15//15 17//17 18//18 16//16
f 17//17 19//19 20//20 18//18
f 19//19 21//21 22//22 20//20
f 21//21 23//23 24//24 22//22
f 23//23 25//25 26//26 24//24
f 25//25 27//27 28//28 26//26
s 4
f 27//27 29//29 30//30 28//28
s 2
f 29//29 31//31 32//32 30//30
s 4
f 31//31 33//33 34//34 32//32
s 2
f 33//33 35//35 36//36 34//34
s 4
f 35//35 37//37 38//38 36//36
s 2
f 37//37 39//39 40//40 38//38
f 39//39 41//41 42//42 40//40
f 41//41 43//43 44//44 42//42
f 43//43 45//45 46//46 44//44
f 45//45 47//47 48//48 46//46
f 47//47 49//49 50//50 48//48
f 49//49 51//51 52//52 50//50
f 51//51 53//53 54//54 52//52
f 53//53 55//55 56//56 54//54
f 55//55 57//57 58//58 56//56
f 57//57 59//59 60//60 58//58
f 59//59 61//61 62//62 60//60
f 61//61 63//63 64//64 62//62
f 63//63 65//65 66//66 64//64
f 65//65 67//67 68//68 66//66
f 67//67 69//69 70//70 68//68
f 69//69 71//71 72//72 70//70
f 71//71 73//73 74//74 72//72
f 73//73 75//75 76//76 74//74
f 75//75 77//77 78//78 76//76
f 77//77 79//79 80//80 78//78
s 3
f 79//79 1//1 4//4 80//80
s 1
f 81//81 82//82 83//83 84//84
s 3
f 82//82 85//85 86//86 83//83
s 2
f 85//85 87//87 88//88 86//86
f 87//87 89//89 90//90 88//88
f 89//89 91//91 92//92 90//90
f 91//91 93//93 94//94 92//92
s 4
f 93//93 95//95 96//96 94//94
s 2
f 95//95 97//35 98//33 96//96
s 4
f 97//35 99//97 100//98 98//33
s 2
f 99//97 101//99 102//100 100//98
f 101//99 103//101 104//102 102//100
f 103//101 105//103 106//104 104//102
f 105//103 107//105 108//106 106//104
f 107//105 109//107 110//108 108//106
f 109//107 111//109 112//110 110//108
f 111//109 113//111 114//112 112//110
f 113//111 115//113 116//114 114//112
f 115//113 117//115 118//116 116//114
f 117//115 119//117 120//118 118//116
f 119//117 121//119 122//120 120//118
f 121//119 123//121 124//122 122//120
f 123//121 125//123 126//124 124//122
f 125//123 127//125 128//126 126//124
s 3
f 127//125 81//81 84//84 128//126
s 16
f 13//13 101//99 99//97 97//35
f 13//13 105//103 103//101 101//99
f 13//13 109//107 107//105 105//103
f 97//35 17//17 15//15 13//13
f 97//35 21//21 19//19 17//17
f 97//35 25//25 23//23 21//21
f 97//35 29//29 27//27 25//25
f 13//13 113//111 111//109 109//107
f 97//35 95//95 31//31 29//29
f 13//13 117//115 115//113 113//111
f 31//31 95//95 35//35 33//33
f 93//93 37//37 35//35 95//95
f 91//91 39//39 37//37 93//93
f 91//91 89//89 41//41 39//39
f 89//89 45//45 43//43 41//41
f 87//87 47//47 45//45 89//89
f 87//87 85//85 49//49 47//47
f 11//11 119//117 117//115 13//13
f 9//9 7//7 119//117 11//11
f 7//7 5//5 121//119 119//117
f 2//2 123//121 121//119 5//5
f 1//1 125//123 123//121 2//2
f 79//79 127//125 125//123 1//1
f 77//77 75//75 127//125 79//79
f 75//75 73//73 81//81 127//125
f 71//71 69//69 81//81 73//73
f 67//67 65//65 81//81 69//69
f 65//65 63//63 82//82 81//81
f 61//61 59//59 82//82 63//63
f 57//57 85//85 82//82 59//59
f 55//55 53//53 85//85 57//57
f 51//51 49//49 85//85 53//53
f 14//14 16//16 98//33 100//98
f 14//14 100//98 102//100 104//102
f 14//14 104//102 106//104 108//106
f 14//14 108//106 110//108 112//110
f 98//33 16//16 18//18 20//20
f 98//33 20//20 22//22 24//24
f 98//33 24//24 26//26 28//28
f 98//33 28//28 30//30 32//32
f 96//96 98//33 32//32 36//36
f 14//14 112//110 114//112 116//114
f 14//14 116//114 118//116 12//12
f 32//32 34//34 36//36
f 94//94 96//96 36//36 38//38
f 92//92 94//94 38//38 40//40
f 92//92 40//40 42//42 90//90
f 90//90 42//42 44//44 46//46
f 88//88 90//90 46//46 48//48
f 88//88 48//48 50//50 86//86
f 12//12 118//116 120//118 10//10
f 8//8 10//10 120//118 122//120
f 6//6 8//8 122//120 3//3
f 3//3 122//120 124//122 4//4
f 4//4 124//122 126//124 80//80
f 80//80 126//124 128//126 78//78
f 76//76 78//78 128//126 84//84
f 74//74 76//76 84//84 72//72
f 70//70 72//72 84//84 68//68
f 66//66 68//68 84//84 83//83
f 64//64 66//66 83//83 62//62
f 60//60 62//62 83//83 58//58
f 58//58 83//83 86//86 56//56
f 54//54 56//56 86//86 52//52
f 50//50 52//52 86//86
# 127 polygons - 2 triangles
#
# object Text002
#
v -0.5594 -0.1862 -0.4687
v -0.5594 -0.1862 0.0583
v -0.5594 0.0138 0.0583
v -0.5594 0.0138 -0.4687
v -0.4004 -0.1862 0.0583
v -0.4004 0.0138 0.0583
v -0.4004 -0.1862 -0.1367
v -0.4004 0.0138 -0.1367
v -0.2184 -0.1862 -0.1367
v -0.2184 0.0138 -0.1367
v -0.2184 -0.1862 0.0583
v -0.2184 0.0138 0.0583
v -0.0594 -0.1862 0.0583
v -0.0594 0.0138 0.0583
v -0.0594 -0.1862 -0.4687
v -0.0594 0.0138 -0.4687
v -0.2184 -0.1862 -0.4687
v -0.2184 0.0138 -0.4687
v -0.2184 -0.1862 -0.2717
v -0.2184 0.0138 -0.2717
v -0.4004 -0.1862 -0.2717
v -0.4004 0.0138 -0.2717
v -0.4004 -0.1862 -0.4687
v -0.4004 0.0138 -0.4687
# 24 vertices
vn -0.5774 -0.5774 -0.5774
vn -0.5774 -0.5774 0.5774
vn -0.5774 0.5774 0.5774
vn -0.5774 0.5774 -0.5774
vn 0.5774 -0.5774 0.5774
vn 0.5774 0.5774 0.5774
vn 0.3015 -0.9045 0.3015
vn 0.3015 0.9045 0.3015
vn -0.3015 -0.9045 0.3015
vn -0.3015 0.9045 0.3015
vn 0.5774 -0.5774 -0.5774
vn 0.5774 0.5774 -0.5774
vn -0.3015 -0.9045 -0.3015
vn -0.3015 0.9045 -0.3015
vn 0.3015 -0.9045 -0.3015
vn 0.3015 0.9045 -0.3015
# 16 vertex normals
o Text002
g Text002
usemtl wire_238166000
s 1
f 129//127 130//128 131//129 132//130
s 4
f 130//128 133//131 134//132 131//129
s 2
f 133//131 135//133 136//134 134//132
s 4
f 135//133 137//135 138//136 136//134
s 2
f 137//135 139//128 140//129 138//136
s 4
f 139//128 141//131 142//132 140//129
s 2
f 141//131 143//137 144//138 142//132
s 4
f 143//137 145//127 146//130 144//138
s 2
f 145//127 147//139 148//140 146//130
s 4
f 147//139 149//141 150//142 148//140
s 2
f 149//141 151//137 152//138 150//142
s 4
f 151//137 129//127 132//130 152//138
s 16
f 149//141 130//128 129//127 151//137
f 143//137 141//131 147//139 145//127
f 137//135 147//139 141//131 139//128
f 135//133 149//141 147//139 137//135
f 135//133 133//131 130//128 149//141
f 150//142 152//138 132//130 131//129
f 144//138 146//130 148//140 142//132
f 138//136 140//129 142//132 148//140
f 136//134 138//136 148//140 150//142
f 136//134 150//142 131//129 134//132
# 22 polygons
+30
View File
@@ -0,0 +1,30 @@
# 3ds Max Wavefront OBJ Exporter v0.99 - (c)2007 guruware
# File Created: 25.06.2025 23:25:19
newmtl Material__25
Kd 0.5000 0.5000 0.5000
Ks 1.0000 1.0000 1.0000
Tr 0.0000
d 1.0000
Tf 1.0000 1.0000 1.0000
Pr 0.0000
Pm 0.0000
Pc 0.0000
Pcr 0.0000
Ni 1.5200
Ke 0.0000 0.0000 0.0000
illum 2
newmtl Material__27
Kd 0.7667 0.4762 0.0265
Ks 0.0855 0.0855 0.0855
Tr 0.0000
d 1.0000
Tf 1.0000 1.0000 1.0000
Pr 0.0000
Pm 0.0000
Pc 0.0000
Pcr 0.0000
Ni 1.5200
Ke 0.0000 0.0000 0.0000
illum 2
File diff suppressed because it is too large Load Diff
+72
View File
@@ -0,0 +1,72 @@
# 3ds Max Wavefront OBJ Exporter v0.99 - (c)2007 guruware
# File Created: 27.06.2025 21:22:56
newmtl Material__25
Kd 0.5000 0.5000 0.5000
Ks 1.0000 1.0000 1.0000
Tr 0.0000
d 1.0000
Tf 1.0000 1.0000 1.0000
Pr 0.0000
Pm 0.0000
Pc 0.0000
Pcr 0.0000
Ni 1.5200
Ke 0.0000 0.0000 0.0000
illum 2
newmtl Material__27
Kd 0.7667 0.4762 0.0265
Ks 0.0855 0.0855 0.0855
Tr 0.0000
d 1.0000
Tf 1.0000 1.0000 1.0000
Pr 0.0000
Pm 0.0000
Pc 0.0000
Pcr 0.0000
Ni 1.5200
Ke 0.0000 0.0000 0.0000
illum 2
newmtl Material__28
Kd 0.9936 0.0265 0.7228
Ks 0.0855 0.0855 0.0855
Tr 0.0000
d 1.0000
Tf 1.0000 1.0000 1.0000
Pr 0.0000
Pm 0.0000
Pc 0.0000
Pcr 0.0000
Ni 1.5200
Ke 0.0000 0.0000 0.0000
illum 2
newmtl Material__26
Kd 0.0356 0.0356 0.0356
Ks 0.4934 0.4934 0.4934
Tr 0.0000
d 1.0000
Tf 1.0000 1.0000 1.0000
Pr 0.0000
Pm 0.0000
Pc 0.0000
Pcr 0.0000
Ni 1.5200
Ke 0.0000 0.0000 0.0000
illum 2
newmtl default
Kd 0.5000 0.5000 0.5000
Ks 1.0000 1.0000 1.0000
Tr 0.0000
d 1.0000
Tf 1.0000 1.0000 1.0000
Pr 0.0000
Pm 0.0000
Pc 0.0000
Pcr 0.0000
Ni 1.5200
Ke 0.0000 0.0000 0.0000
illum 2
File diff suppressed because it is too large Load Diff
Binary file not shown.
Submodule example_repos/renderformer added at e6e38527e1
+1384
View File
File diff suppressed because it is too large Load Diff
+16
View File
@@ -0,0 +1,16 @@
torch==2.7.1+cu126
torchvision
numpy
dacite
einops
roma
huggingface_hub
safetensors
trimesh
scipy
pymeshlab
h5py
natsort
imageio[ffmpeg]
simple-ocio
git+https://github.com/iamNCJ/renderformer-liger-kernel.git
+278
View File
@@ -0,0 +1,278 @@
import { app } from "/scripts/app.js";
import { api } from "/scripts/api.js";
// --- Helper Functions ---
async function uploadFile(file) {
try {
const body = new FormData();
body.append("image", file);
body.append("subfolder", "3d");
const resp = await api.fetchApi("/upload/image", {
method: "POST",
body,
});
return resp.status === 200 ? resp : alert(resp.status + " - " + resp.statusText);
} catch (error) {
alert(error);
}
}
function hexToRgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null;
}
function rgbToHsv(r, g, b) {
r /= 255, g /= 255, b /= 255;
let max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, v = max;
let d = max - min;
s = max == 0 ? 0 : d / max;
if (max == min) {
h = 0;
} else {
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return { h, s, v };
}
function rgb_to_hex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
}
function rgbStringToRgb(rgbStr) {
if (!rgbStr || typeof rgbStr !== 'string') return { r: 204, g: 204, b: 204 };
const parts = rgbStr.split(',').map(s => parseInt(s.trim(), 10));
if (parts.length !== 3 || parts.some(isNaN)) return { r: 204, g: 204, b: 204 };
return { r: parts[0], g: parts[1], b: parts[2] };
}
app.registerExtension({
name: "Comfy.RenderFormer.Nodes",
async nodeCreated(node) {
// -- PHRenderFormer Mesh Loader Node --
if (node.comfyClass === "LoadMesh") {
// 1. Add File Upload Widget
const pathWidget = node.widgets.find((w) => w.name === "mesh");
const fileInput = document.createElement("input");
node.onRemoved = () => {
fileInput?.remove();
};
Object.assign(fileInput, {
type: "file",
accept: ".obj,.glb,.gltf,.stl,.3mf,.ply",
style: "display: none",
onchange: async () => {
if (fileInput.files.length) {
let resp = await uploadFile(fileInput.files[0]);
if (resp?.status !== 200) return;
const filename = (await resp.json()).name;
if (!pathWidget.options.values.includes(filename)) {
pathWidget.options.values.push(filename);
}
pathWidget.value = filename;
if (pathWidget.callback) {
pathWidget.callback(filename);
}
}
},
});
document.body.append(fileInput);
let uploadWidget = node.addWidget("button", "choose mesh to upload", "image", () => {
fileInput.click();
});
uploadWidget.options.serialize = false;
// 2. Add Advanced Color Picker
const PADDING = 10;
const WIDGET_HEIGHT = 20;
const WIDGET_MARGIN = 5;
const PICKER_AREA_HEIGHT = 150;
let gradientWidth, gradientHeight = PICKER_AREA_HEIGHT;
let pickerPos = { x: 0, y: 0 };
let isPickerActive = false;
const colorWidget = node.widgets.find(w => w.name === "diffuse_rgb");
if (!colorWidget) {
console.error("PHRenderFormer Mesh Loader: Could not find 'diffuse_rgb' widget!");
return;
}
let selectedColor = "#CCCCCC";
function calculatePickerPosFromHex(hex) {
const rgb = hexToRgb(hex);
if (!rgb) return { x: 0, y: 0 };
const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
const x = hsv.h * (gradientWidth || 200);
const y = (1 - hsv.v) * gradientHeight;
return {
x: Math.max(0, Math.min(x, gradientWidth || 200)),
y: Math.max(0, Math.min(y, gradientHeight))
};
}
function updateColorOutput() {
const rgb = hexToRgb(selectedColor);
if (rgb) {
colorWidget.value = `${rgb.r}, ${rgb.g}, ${rgb.b}`;
}
node.setDirtyCanvas(true, true);
}
function updateSelectedColor(x, y) {
x = Math.max(0, Math.min(x, gradientWidth || 0));
y = Math.max(0, Math.min(y, gradientHeight || 0));
pickerPos = { x, y };
if (gradientWidth > 0 && gradientHeight > 0) {
const offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = gradientWidth;
offscreenCanvas.height = gradientHeight;
const offscreenCtx = offscreenCanvas.getContext('2d', { willReadFrequently: true });
const gradient = offscreenCtx.createLinearGradient(0, 0, gradientWidth, 0);
gradient.addColorStop(0, "rgb(255, 0, 0)");
gradient.addColorStop(0.17, "rgb(255, 255, 0)");
gradient.addColorStop(0.33, "rgb(0, 255, 0)");
gradient.addColorStop(0.5, "rgb(0, 255, 255)");
gradient.addColorStop(0.67, "rgb(0, 0, 255)");
gradient.addColorStop(0.83, "rgb(255, 0, 255)");
gradient.addColorStop(1, "rgb(255, 0, 0)");
offscreenCtx.fillStyle = gradient;
offscreenCtx.fillRect(0, 0, gradientWidth, gradientHeight);
const blackGradient = offscreenCtx.createLinearGradient(0, 0, 0, gradientHeight);
blackGradient.addColorStop(0, "rgba(0, 0, 0, 0)");
blackGradient.addColorStop(1, "rgba(0, 0, 0, 1)");
offscreenCtx.fillStyle = blackGradient;
offscreenCtx.fillRect(0, 0, gradientWidth, gradientHeight);
const pixelData = offscreenCtx.getImageData(Math.round(x), Math.round(y), 1, 1).data;
selectedColor = rgb_to_hex(pixelData[0], pixelData[1], pixelData[2]);
}
updateColorOutput();
}
const pickerWidget = node.addCustomWidget({
name: "COLOR_PICKER_DISPLAY",
type: "CANVAS_WIDGET",
y: colorWidget.y,
draw: function (ctx, node, widgetWidth, widgetY, height) {
gradientWidth = widgetWidth - PADDING * 2;
const drawY = widgetY + PADDING;
ctx.save();
ctx.translate(PADDING, drawY);
if (gradientWidth > 0 && gradientHeight > 0) {
const gradient = ctx.createLinearGradient(0, 0, gradientWidth, 0);
gradient.addColorStop(0, "rgb(255, 0, 0)");
gradient.addColorStop(0.17, "rgb(255, 255, 0)");
gradient.addColorStop(0.33, "rgb(0, 255, 0)");
gradient.addColorStop(0.5, "rgb(0, 255, 255)");
gradient.addColorStop(0.67, "rgb(0, 0, 255)");
gradient.addColorStop(0.83, "rgb(255, 0, 255)");
gradient.addColorStop(1, "rgb(255, 0, 0)");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, gradientWidth, gradientHeight);
const blackGradient = ctx.createLinearGradient(0, 0, 0, gradientHeight);
blackGradient.addColorStop(0, "rgba(0, 0, 0, 0)");
blackGradient.addColorStop(1, "rgba(0, 0, 0, 1)");
ctx.fillStyle = blackGradient;
ctx.fillRect(0, 0, gradientWidth, gradientHeight);
const pickerDrawX = Math.max(0, Math.min(pickerPos.x, gradientWidth));
const pickerDrawY = Math.max(0, Math.min(pickerPos.y, gradientHeight));
ctx.beginPath();
ctx.arc(pickerDrawX, pickerDrawY, 5, 0, Math.PI * 2);
ctx.strokeStyle = isPickerActive ? "yellow" : "white";
ctx.lineWidth = 2;
ctx.stroke();
}
ctx.fillStyle = selectedColor;
ctx.fillRect(0, gradientHeight + WIDGET_MARGIN, gradientWidth, WIDGET_HEIGHT);
ctx.fillStyle = "white";
ctx.font = "12px Arial";
ctx.textAlign = "left";
ctx.fillText(selectedColor, 5, gradientHeight + WIDGET_MARGIN + WIDGET_HEIGHT - 5);
ctx.restore();
},
mouse: function (event, pos, node) {
const widgetRect = this.computeArea();
const gradientAreaX = PADDING;
const gradientAreaY = widgetRect.y + PADDING;
const clickX = pos[0] - gradientAreaX;
const clickY = pos[1] - gradientAreaY;
if (event.type === "pointerdown") {
if (clickX >= 0 && clickX <= gradientWidth && clickY >= 0 && clickY <= gradientHeight) {
isPickerActive = true;
updateSelectedColor(clickX, clickY);
event.stopPropagation();
return true;
}
} else if (event.type === "pointermove" && isPickerActive) {
updateSelectedColor(clickX, clickY);
return true;
} else if (event.type === "pointerup" && isPickerActive) {
isPickerActive = false;
return true;
}
return false;
},
computeSize: function (width) {
const totalHeight = PADDING * 2 + gradientHeight + WIDGET_MARGIN + WIDGET_HEIGHT;
return [width, totalHeight];
},
computeArea: function() {
let y = this.y || 0;
let totalHeight = this.computeSize(node.size[0])[1];
return { x: 0, y: y, w: node.size[0], h: totalHeight };
}
});
colorWidget.type = "HIDDEN";
function initializePicker() {
const initialRgb = rgbStringToRgb(colorWidget.value);
selectedColor = rgb_to_hex(initialRgb.r, initialRgb.g, initialRgb.b);
node.setSize(node.computeSize());
gradientWidth = node.size[0] - PADDING * 2;
pickerPos = calculatePickerPosFromHex(selectedColor);
updateColorOutput();
}
setTimeout(() => initializePicker(), 0);
const originalSetValue = colorWidget.setValue;
colorWidget.setValue = function(value) {
if (originalSetValue) {
originalSetValue.call(this, value);
}
initializePicker();
};
}
// -- PHRenderFormer Mesh Combine Node --
// No custom JS is needed. The default ComfyUI behavior for optional
// inputs handles this node correctly, just like the lighting combine node.
},
});