Add upload mesh node

This commit is contained in:
kijai 2025-02-02 13:57:03 +02:00
parent 205be20e08
commit 7bba1dd89a
2 changed files with 132 additions and 2 deletions

View File

@ -958,6 +958,41 @@ class Hy3DLoadMesh:
return (mesh,)
class Hy3DUploadMesh:
@classmethod
def INPUT_TYPES(s):
mesh_extensions = ['glb', 'gltf']
input_dir = folder_paths.get_input_directory()
files = []
for f in os.listdir(input_dir):
if os.path.isfile(os.path.join(input_dir, f)):
file_parts = f.split('.')
if len(file_parts) > 1 and (file_parts[-1] in mesh_extensions):
files.append(f)
return {
"required": {
"mesh": (sorted(files),),
}
}
RETURN_TYPES = ("HY3DMESH",)
RETURN_NAMES = ("mesh",)
OUTPUT_TOOLTIPS = ("The glb model with mesh to texturize.",)
FUNCTION = "load"
CATEGORY = "Hunyuan3DWrapper"
DESCRIPTION = "Loads a glb model from the given path."
def load(self, mesh):
path = mesh.strip()
if path.startswith("\""):
path = path[1:]
if path.endswith("\""):
path = path[:-1]
mesh_file = folder_paths.get_annotated_filepath(path)
loaded_mesh = trimesh.load(mesh_file, force="mesh")
return (loaded_mesh,)
class Hy3DGenerateMesh:
@classmethod
@ -1504,6 +1539,7 @@ NODE_CLASS_MAPPINGS = {
"Hy3DTorchCompileSettings": Hy3DTorchCompileSettings,
"Hy3DPostprocessMesh": Hy3DPostprocessMesh,
"Hy3DLoadMesh": Hy3DLoadMesh,
"Hy3DUploadMesh": Hy3DUploadMesh,
"Hy3DCameraConfig": Hy3DCameraConfig,
"Hy3DMeshUVWrap": Hy3DMeshUVWrap,
"Hy3DSampleMultiView": Hy3DSampleMultiView,
@ -1534,6 +1570,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"Hy3DTorchCompileSettings": "Hy3D Torch Compile Settings",
"Hy3DPostprocessMesh": "Hy3D Postprocess Mesh",
"Hy3DLoadMesh": "Hy3D Load Mesh",
"Hy3DUploadMesh": "Hy3D Upload Mesh",
"Hy3DCameraConfig": "Hy3D Camera Config",
"Hy3DMeshUVWrap": "Hy3D Mesh UV Wrap",
"Hy3DSampleMultiView": "Hy3D Sample MultiView",

View File

@ -1,4 +1,5 @@
import { app } from "../../../scripts/app.js";
import { api } from "../../../scripts/api.js";
app.registerExtension({
name: "HY3D.jsnodes",
@ -25,8 +26,100 @@ app.registerExtension({
this.outputs[2]["name"] = values[1] + " faces"
return r
}
break;
break;
case "Hy3DUploadMesh":
addUploadWidget(nodeType, nodeData, "mesh");
break;
}
},
});
});
//file upload code from VHS nodes: https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite
async function uploadFile(file) {
//TODO: Add uploaded file to cache with Cache.put()?
try {
// Wrap file in formdata so it includes filename
const body = new FormData();
const i = file.webkitRelativePath.lastIndexOf('/');
const subfolder = file.webkitRelativePath.slice(0,i+1)
const new_file = new File([file], file.name, {
type: file.type,
lastModified: file.lastModified,
});
body.append("image", new_file);
if (i > 0) {
body.append("subfolder", subfolder);
}
const resp = await api.fetchApi("/upload/image", {
method: "POST",
body,
});
if (resp.status === 200) {
return resp
} else {
alert(resp.status + " - " + resp.statusText);
}
} catch (error) {
alert(error);
}
}
function addUploadWidget(nodeType, nodeData, widgetName) {
chainCallback(nodeType.prototype, "onNodeCreated", function() {
const pathWidget = this.widgets.find((w) => w.name === widgetName);
const fileInput = document.createElement("input");
chainCallback(this, "onRemoved", () => {
fileInput?.remove();
});
Object.assign(fileInput, {
type: "file",
accept: ".glb,.gltf,model/gltf-binary,model/gltf+json",
style: "display: none",
onchange: async () => {
if (fileInput.files.length) {
let resp = await uploadFile(fileInput.files[0])
if (resp.status != 200) {
//upload failed and file can not be added to options
return;
}
const filename = (await resp.json()).name;
pathWidget.options.values.push(filename);
pathWidget.value = filename;
if (pathWidget.callback) {
pathWidget.callback(filename)
}
}
},
});
console.log(this)
document.body.append(fileInput);
let uploadWidget = this.addWidget("button", "choose glb file to upload", "image", () => {
//clear the active click event
app.canvas.node_widget = null
fileInput.click();
});
uploadWidget.options.serialize = false;
});
}
function chainCallback(object, property, callback) {
if (object == undefined) {
//This should not happen.
console.error("Tried to add callback to non-existant object")
return;
}
if (property in object && object[property]) {
const callback_orig = object[property]
object[property] = function () {
const r = callback_orig.apply(this, arguments);
callback.apply(this, arguments);
return r
};
} else {
object[property] = callback;
}
}