Files
lo-th-Comfyui_three_js/js/three_view.js
T
AlekPet aca6376fe6 updated styles, betters view wrappers, index.html and add Canny Edge
Corrected visible wrappers and clear code
Added Canny Edge  (experiment)
Fixed incorrect work "Fix camers", not set in the "Lines" canvas, once set
composer and not set if changed.
Fixed layout index.html and incorrect path to Javascript and css files.
Other small fixes.
2024-12-02 21:57:39 +03:00

281 lines
9.4 KiB
JavaScript

import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
import { addStylesheet } from "../../scripts/utils.js";
//import * as THREE from "./lib/three.module.js";
//import { OrbitControls } from "./lib/OrbitControls.js";
import { $el } from "../../scripts/ui.js";
import { ThreeCanvas } from "./ThreeCanvas.js";
const DEBUG = true;
// Function create widget
async function widgetThreeJS(node, nodeData, inputData, app, params = {}) {
const d = new Date();
const canvasNames = [
{name:"image", color: "black"},
{name:"lines", color: "red"},
{name:"depth", color: "yellow"},
{name:"normal", color: "#8080ff"}
];
const base_filenames = canvasNames.map((data)=>`${nodeData.name}${node.id}-${d.getUTCFullYear()}_${d.getUTCMonth() + 1}_${d.getUTCDate()}_${data.name}.png`)
// Find widget stored image filename for threejs, and hide him.
const widgeImageThree = node.widgets.find((w) => w.name === "imageThreejs");
widgeImageThree.value = base_filenames.join()
widgeImageThree.type = "converted-widget";
widgeImageThree.computeSize = () => [0, -4];
if (widgeImageThree.linkedWidgets) {
for (const link of widgeImageThree.linkedWidgets) {
link.type = "converted-widget";
link.computeSize = () => [0, -4];
}
}
let widget = {};
const threeCanvas = new ThreeCanvas(node, widgeImageThree, params);
threeCanvas.setApi(api);
threeCanvas.init(canvasNames);
const panelWidget = node.addDOMWidget(
nodeData.name,
"threeCanvasPanel",
threeCanvas.panelWrapper,
{
getValue() {
return "panelWidgetValue";
},
}
);
panelWidget.computeSize = () => {
return [node.size[0], 45];
};
// end - Panel
// Add widget threeCanvas
widget = node.addDOMWidget("threeCanvas", "custom_widget", threeCanvas.threeWrapper, {
getValue() {
return threeCanvas.getSavedOptions();
},
});
const origDraw = widget.draw;
widget.draw = function () {
origDraw?.apply(this, arguments);
const [ctx, nodeThree, widgetWidth, posY] = arguments;
const w = widgetWidth - 25;
const aspect_ratio = threeCanvas.size.h / threeCanvas.size.w;
Object.assign(threeCanvas.threeWrapper.style, {
width: w + "px",
height: w * aspect_ratio + "px",
});
// Update renderer
// threeCanvas.update(node.size[0]);
//app.graph.setDirtyCanvas(true, false);
};
widget.threeCanvas = threeCanvas;
widget.threeWrapper = threeCanvas.threeWrapper;
widget.callback = () => {};
// Note: If the node is collapsed, the draw method does not work and the canvas will not update.
// const animator = () => {
// threeCanvas.update(node.size[0]);
// app.graph.setDirtyCanvas(true, false);
// requestAnimationFrame(animator);
// };
// requestAnimationFrame(animator);
node.onResize = function () {
let [w, h] = this.size;
let aspect_ratio = 1;
aspect_ratio = threeCanvas.size.h / threeCanvas.size.w;
const buffer = 140;
if (w > 1024) w = w - (w - 1024);
if (w < 200) w = 200;
h = w * aspect_ratio + buffer;
if (h < 200) h = 200 + h / 2;
this.size = [w, h];
};
// Serialize node data, you can save the image here too
node.onSerialize = (n) => {
//console.log('YOOOOO')
};
node.onDragOver = function (e) {
return false;
};
node.onDragDrop = function (e) {
return false;
};
// https://docs.comfy.org/essentials/comms_messages
// api.addEventListener("execution_start", async () => {
// console.log("execution_start...");
// await threeCanvas.sendFileToServer(widgeImageThree.value);
// });
// Custom event save image
api.addEventListener("lth_save_image", async ({ detail }) => {
const { unique_id } = detail;
if (+unique_id !== node.id) return;
function reflect(promise){
return promise.then(function(v){ return {v:v, status: "fulfilled" }},
function(e){ return {e:e, status: "rejected" }});
}
const promises = base_filenames.map((v, idx)=>threeCanvas.sendFileToServer(v, idx))
Promise.all(promises.map(reflect)).then(async function (results) {
const success = results.filter(x => x.status === "fulfilled");
if (success.length === base_filenames.length) {
console.log("All images saved successfully. Notifying server...");
await api.fetchApi("/lth/save_complete", {
method: "POST",
body: JSON.stringify({
unique_id: node.id.toString(),
}),
});
} else {
console.error("Some images failed to save. Skipping server notification.");
}
});
});
return widget;
}
app.registerExtension({
name: "Three View",
async init(){
// Add css styles
addStylesheet("css/styles.css", import.meta.url);
},
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeType.comfyClass === "ThreeView") {
nodeType.prototype.onExecuted = async function (message) {
console.log("yooooo is running !!!!");
};
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = async function () {
const r = onNodeCreated
? onNodeCreated.apply(this, arguments)
: undefined;
const titleNode = await this.getTitle(); // need to load properties node
let parameters = {}
try {
parameters = {savedData: this?.widgets_values[2]}
} catch (error) {
}
// Create widget
const widget = await widgetThreeJS(
this,
nodeData,
nodeData,
app,
parameters
);
this.title = `${this.type} [${widget.threeCanvas.size.w}x${widget.threeCanvas.size.h}]`;
this?.onResize()
console.log("onCreate")
return r;
};
// onConfigure, load serialized values
const onConfigure = nodeType.prototype.onConfigure;
nodeType.prototype.onConfigure = async function (w) {
onConfigure?.apply(this, arguments);
await this.getTitle(); // wait loaded node
if (w?.widgets_values?.length) {
const threeCanvasId = this.widgets.findIndex(
(wi) => wi.name === "threeCanvas"
);
if (threeCanvasId !== -1 && w?.widgets_values[threeCanvasId]) {
// Get widget threeCanvas by Index
const threeCnavasWidget = this.widgets[threeCanvasId].threeCanvas
// Get value size and options
const {size: sizeData, camera: cameraData, currentModel} = w.widgets_values[threeCanvasId];
// Set size
if(sizeData){
const { w: width, h: height } = sizeData;
if(width && height){
threeCnavasWidget.setCanvasSize(width, height);
this.title = `${this.type} [${width}x${height}]`;
}
}
// Loading last model added
if(currentModel){
const [subfolder, name] = currentModel.split("/")
const urlData = await api.apiURL(
`/view?filename=${encodeURIComponent(
name
)}&type=input&subfolder=${subfolder}${app.getPreviewFormatParam()}${app.getRandParam()}`
);
await threeCnavasWidget.loaderGltf.load(urlData, ( glb ) => {
threeCnavasWidget.addModel( glb );
// Load camera data
if( cameraData ) threeCnavasWidget.loadCameraState( cameraData )
},
( data ) => {/* console.log( `Loaded data: ${data.loaded}/${data.total}` */},
( err ) => {
console.log( err );
threeCnavasWidget.addHeadTest();
})
}
console.log("onConfigure")
}
}
};
// When the node is executed we will be sent the input text, display this in the widget
/*const onExecuted = nodeType.prototype.onExecuted;
nodeType.prototype.onExecuted = function (message) {
console.log("yooooo");
//onExecuted?.apply(this, arguments);
//populate.call(this, message.text);
};*/
}
},
});