mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-15 01:48:06 +00:00
Compare commits
3 Commits
pr5-list-v
...
v1.20.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d9d5e5061 | ||
|
|
be1d6d776a | ||
|
|
ada7dde51c |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@comfyorg/comfyui-frontend",
|
||||
"private": true,
|
||||
"version": "1.20.4",
|
||||
"version": "1.20.5",
|
||||
"type": "module",
|
||||
"repository": "https://github.com/Comfy-Org/ComfyUI_frontend",
|
||||
"homepage": "https://comfy.org",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { LGraphNode } from '@comfyorg/litegraph'
|
||||
import { onMounted, onUnmounted, ref, toRaw, watch, watchEffect } from 'vue'
|
||||
import { onMounted, onUnmounted, ref, toRaw, watch } from 'vue'
|
||||
|
||||
import LoadingOverlay from '@/components/load3d/LoadingOverlay.vue'
|
||||
import Load3d from '@/extensions/core/load3d/Load3d'
|
||||
@@ -76,18 +76,71 @@ const eventConfig = {
|
||||
emit('recordingStatusChange', value)
|
||||
} as const
|
||||
|
||||
watchEffect(() => {
|
||||
if (load3d.value) {
|
||||
const rawLoad3d = toRaw(load3d.value) as Load3d
|
||||
watch(
|
||||
() => props.showPreview,
|
||||
(newValue) => {
|
||||
if (load3d.value) {
|
||||
const rawLoad3d = toRaw(load3d.value) as Load3d
|
||||
|
||||
rawLoad3d.setBackgroundColor(props.backgroundColor)
|
||||
rawLoad3d.toggleGrid(props.showGrid)
|
||||
rawLoad3d.setLightIntensity(props.lightIntensity)
|
||||
rawLoad3d.setFOV(props.fov)
|
||||
rawLoad3d.toggleCamera(props.cameraType)
|
||||
rawLoad3d.togglePreview(props.showPreview)
|
||||
rawLoad3d.togglePreview(newValue)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.cameraType,
|
||||
(newValue) => {
|
||||
if (load3d.value) {
|
||||
const rawLoad3d = toRaw(load3d.value) as Load3d
|
||||
|
||||
rawLoad3d.toggleCamera(newValue)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.fov,
|
||||
(newValue) => {
|
||||
if (load3d.value) {
|
||||
const rawLoad3d = toRaw(load3d.value) as Load3d
|
||||
|
||||
rawLoad3d.setFOV(newValue)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.lightIntensity,
|
||||
(newValue) => {
|
||||
if (load3d.value) {
|
||||
const rawLoad3d = toRaw(load3d.value) as Load3d
|
||||
|
||||
rawLoad3d.setLightIntensity(newValue)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.showGrid,
|
||||
(newValue) => {
|
||||
if (load3d.value) {
|
||||
const rawLoad3d = toRaw(load3d.value) as Load3d
|
||||
|
||||
rawLoad3d.toggleGrid(newValue)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.backgroundColor,
|
||||
(newValue) => {
|
||||
if (load3d.value) {
|
||||
const rawLoad3d = toRaw(load3d.value) as Load3d
|
||||
|
||||
rawLoad3d.setBackgroundColor(newValue)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.backgroundImage,
|
||||
@@ -164,12 +217,13 @@ const handleEvents = (action: 'add' | 'remove') => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
load3d.value = useLoad3dService().registerLoad3d(
|
||||
node.value as LGraphNode,
|
||||
// @ts-expect-error fixme ts strict error
|
||||
container.value,
|
||||
props.inputSpec
|
||||
)
|
||||
if (container.value) {
|
||||
load3d.value = useLoad3dService().registerLoad3d(
|
||||
node.value as LGraphNode,
|
||||
container.value,
|
||||
props.inputSpec
|
||||
)
|
||||
}
|
||||
handleEvents('add')
|
||||
})
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ useExtensionService().registerExtension({
|
||||
LOAD_3D(node) {
|
||||
const fileInput = document.createElement('input')
|
||||
fileInput.type = 'file'
|
||||
fileInput.accept = '.gltf,.glb,.obj,.mtl,.fbx,.stl'
|
||||
fileInput.accept = '.gltf,.glb,.obj,.fbx,.stl'
|
||||
fileInput.style.display = 'none'
|
||||
|
||||
fileInput.onchange = async () => {
|
||||
@@ -195,9 +195,7 @@ useExtensionService().registerExtension({
|
||||
|
||||
await nextTick()
|
||||
|
||||
const load3d = useLoad3dService().getLoad3d(node)
|
||||
|
||||
if (load3d) {
|
||||
useLoad3dService().waitForLoad3d(node, (load3d) => {
|
||||
let cameraState = node.properties['Camera Info']
|
||||
|
||||
const config = new Load3DConfiguration(load3d)
|
||||
@@ -256,7 +254,7 @@ useExtensionService().registerExtension({
|
||||
return returnVal
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -346,67 +344,65 @@ useExtensionService().registerExtension({
|
||||
|
||||
await nextTick()
|
||||
|
||||
const sceneWidget = node.widgets?.find((w) => w.name === 'image')
|
||||
useLoad3dService().waitForLoad3d(node, (load3d) => {
|
||||
const sceneWidget = node.widgets?.find((w) => w.name === 'image')
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
let cameraState = node.properties['Camera Info']
|
||||
const width = node.widgets?.find((w) => w.name === 'width')
|
||||
const height = node.widgets?.find((w) => w.name === 'height')
|
||||
|
||||
const load3d = useLoad3dService().getLoad3d(node) as Load3dAnimation
|
||||
if (modelWidget && width && height && sceneWidget && load3d) {
|
||||
const config = new Load3DConfiguration(load3d)
|
||||
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
config.configure('input', modelWidget, cameraState, width, height)
|
||||
|
||||
let cameraState = node.properties['Camera Info']
|
||||
sceneWidget.serializeValue = async () => {
|
||||
node.properties['Camera Info'] = load3d.getCameraState()
|
||||
|
||||
const width = node.widgets?.find((w) => w.name === 'width')
|
||||
const height = node.widgets?.find((w) => w.name === 'height')
|
||||
const load3dAnimation = load3d as Load3dAnimation
|
||||
load3dAnimation.toggleAnimation(false)
|
||||
|
||||
if (modelWidget && width && height && sceneWidget && load3d) {
|
||||
const config = new Load3DConfiguration(load3d)
|
||||
if (load3dAnimation.isRecording()) {
|
||||
load3dAnimation.stopRecording()
|
||||
}
|
||||
|
||||
config.configure('input', modelWidget, cameraState, width, height)
|
||||
const {
|
||||
scene: imageData,
|
||||
mask: maskData,
|
||||
normal: normalData
|
||||
} = await load3dAnimation.captureScene(
|
||||
width.value as number,
|
||||
height.value as number
|
||||
)
|
||||
|
||||
sceneWidget.serializeValue = async () => {
|
||||
node.properties['Camera Info'] = load3d.getCameraState()
|
||||
|
||||
load3d.toggleAnimation(false)
|
||||
|
||||
if (load3d.isRecording()) {
|
||||
load3d.stopRecording()
|
||||
}
|
||||
|
||||
const {
|
||||
scene: imageData,
|
||||
mask: maskData,
|
||||
normal: normalData
|
||||
} = await load3d.captureScene(
|
||||
width.value as number,
|
||||
height.value as number
|
||||
)
|
||||
|
||||
const [data, dataMask, dataNormal] = await Promise.all([
|
||||
Load3dUtils.uploadTempImage(imageData, 'scene'),
|
||||
Load3dUtils.uploadTempImage(maskData, 'scene_mask'),
|
||||
Load3dUtils.uploadTempImage(normalData, 'scene_normal')
|
||||
])
|
||||
|
||||
load3d.handleResize()
|
||||
|
||||
const returnVal = {
|
||||
image: `threed/${data.name} [temp]`,
|
||||
mask: `threed/${dataMask.name} [temp]`,
|
||||
normal: `threed/${dataNormal.name} [temp]`,
|
||||
camera_info: node.properties['Camera Info'],
|
||||
recording: ''
|
||||
}
|
||||
|
||||
const recordingData = load3d.getRecordingData()
|
||||
if (recordingData) {
|
||||
const [recording] = await Promise.all([
|
||||
Load3dUtils.uploadTempImage(recordingData, 'recording', 'mp4')
|
||||
const [data, dataMask, dataNormal] = await Promise.all([
|
||||
Load3dUtils.uploadTempImage(imageData, 'scene'),
|
||||
Load3dUtils.uploadTempImage(maskData, 'scene_mask'),
|
||||
Load3dUtils.uploadTempImage(normalData, 'scene_normal')
|
||||
])
|
||||
returnVal['recording'] = `threed/${recording.name} [temp]`
|
||||
}
|
||||
|
||||
return returnVal
|
||||
load3dAnimation.handleResize()
|
||||
|
||||
const returnVal = {
|
||||
image: `threed/${data.name} [temp]`,
|
||||
mask: `threed/${dataMask.name} [temp]`,
|
||||
normal: `threed/${dataNormal.name} [temp]`,
|
||||
camera_info: node.properties['Camera Info'],
|
||||
recording: ''
|
||||
}
|
||||
|
||||
const recordingData = load3dAnimation.getRecordingData()
|
||||
if (recordingData) {
|
||||
const [recording] = await Promise.all([
|
||||
Load3dUtils.uploadTempImage(recordingData, 'recording', 'mp4')
|
||||
])
|
||||
returnVal['recording'] = `threed/${recording.name} [temp]`
|
||||
}
|
||||
|
||||
return returnVal
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -467,19 +463,19 @@ useExtensionService().registerExtension({
|
||||
useToastStore().addAlert(msg)
|
||||
}
|
||||
|
||||
const load3d = useLoad3dService().getLoad3d(node)
|
||||
|
||||
let cameraState = message.result[1]
|
||||
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
useLoad3dService().waitForLoad3d(node, (load3d) => {
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
|
||||
if (load3d && modelWidget) {
|
||||
modelWidget.value = filePath.replaceAll('\\', '/')
|
||||
if (modelWidget) {
|
||||
modelWidget.value = filePath.replaceAll('\\', '/')
|
||||
|
||||
const config = new Load3DConfiguration(load3d)
|
||||
const config = new Load3DConfiguration(load3d)
|
||||
|
||||
config.configure('output', modelWidget, cameraState)
|
||||
}
|
||||
config.configure('output', modelWidget, cameraState)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -543,16 +539,16 @@ useExtensionService().registerExtension({
|
||||
|
||||
let cameraState = message.result[1]
|
||||
|
||||
const load3d = useLoad3dService().getLoad3d(node)
|
||||
useLoad3dService().waitForLoad3d(node, (load3d) => {
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
if (modelWidget) {
|
||||
modelWidget.value = filePath.replaceAll('\\', '/')
|
||||
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
if (load3d && modelWidget) {
|
||||
modelWidget.value = filePath.replaceAll('\\', '/')
|
||||
const config = new Load3DConfiguration(load3d)
|
||||
|
||||
const config = new Load3DConfiguration(load3d)
|
||||
|
||||
config.configure('output', modelWidget, cameraState)
|
||||
}
|
||||
config.configure('output', modelWidget, cameraState)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -486,6 +486,14 @@ class Load3d {
|
||||
}
|
||||
|
||||
public remove(): void {
|
||||
this.renderer.forceContextLoss()
|
||||
const canvas = this.renderer.domElement
|
||||
const event = new Event('webglcontextlost', {
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
})
|
||||
canvas.dispatchEvent(event)
|
||||
|
||||
if (this.animationFrameId !== null) {
|
||||
cancelAnimationFrame(this.animationFrameId)
|
||||
}
|
||||
|
||||
@@ -62,6 +62,14 @@ export class PreviewManager implements PreviewManagerInterface {
|
||||
|
||||
dispose(): void {
|
||||
if (this.previewRenderer) {
|
||||
this.previewRenderer.forceContextLoss()
|
||||
const canvas = this.previewRenderer.domElement
|
||||
const event = new Event('webglcontextlost', {
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
})
|
||||
canvas.dispatchEvent(event)
|
||||
|
||||
this.previewRenderer.dispose()
|
||||
}
|
||||
|
||||
|
||||
@@ -3403,7 +3403,7 @@
|
||||
"clear": {
|
||||
},
|
||||
"height": {
|
||||
"name": "altura"
|
||||
"name": "alto"
|
||||
},
|
||||
"image": {
|
||||
"name": "imagen"
|
||||
@@ -3417,20 +3417,26 @@
|
||||
"name": "ancho"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "imagen"
|
||||
},
|
||||
"1": {
|
||||
"name": "mask"
|
||||
},
|
||||
"2": {
|
||||
"name": "ruta_malla"
|
||||
},
|
||||
"3": {
|
||||
"name": "normal"
|
||||
},
|
||||
{
|
||||
"4": {
|
||||
"name": "lineart"
|
||||
},
|
||||
{
|
||||
"name": "camera_info"
|
||||
"5": {
|
||||
"name": "info_cámara"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Load3DAnimation": {
|
||||
"display_name": "Cargar 3D - Animación",
|
||||
@@ -3438,7 +3444,7 @@
|
||||
"clear": {
|
||||
},
|
||||
"height": {
|
||||
"name": "altura"
|
||||
"name": "alto"
|
||||
},
|
||||
"image": {
|
||||
"name": "imagen"
|
||||
@@ -3452,17 +3458,23 @@
|
||||
"name": "ancho"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "imagen"
|
||||
},
|
||||
"1": {
|
||||
"name": "mask"
|
||||
},
|
||||
"2": {
|
||||
"name": "ruta_malla"
|
||||
},
|
||||
"3": {
|
||||
"name": "normal"
|
||||
},
|
||||
{
|
||||
"name": "camera_info"
|
||||
"4": {
|
||||
"name": "info_cámara"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"LoadAudio": {
|
||||
"display_name": "CargarAudio",
|
||||
|
||||
@@ -3417,20 +3417,26 @@
|
||||
"name": "largeur"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "image"
|
||||
},
|
||||
"1": {
|
||||
"name": "masque"
|
||||
},
|
||||
"2": {
|
||||
"name": "chemin_maillage"
|
||||
},
|
||||
"3": {
|
||||
"name": "normale"
|
||||
},
|
||||
{
|
||||
"name": "ligne artistique"
|
||||
"4": {
|
||||
"name": "lineart"
|
||||
},
|
||||
{
|
||||
"name": "informations caméra"
|
||||
"5": {
|
||||
"name": "info_caméra"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Load3DAnimation": {
|
||||
"display_name": "Charger 3D - Animation",
|
||||
@@ -3452,17 +3458,23 @@
|
||||
"name": "largeur"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"name": "normal"
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "image"
|
||||
},
|
||||
{
|
||||
"name": "camera_info"
|
||||
"1": {
|
||||
"name": "masque"
|
||||
},
|
||||
"2": {
|
||||
"name": "chemin_maillage"
|
||||
},
|
||||
"3": {
|
||||
"name": "normale"
|
||||
},
|
||||
"4": {
|
||||
"name": "info_caméra"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"LoadAudio": {
|
||||
"display_name": "ChargerAudio",
|
||||
|
||||
@@ -3417,23 +3417,29 @@
|
||||
"name": "幅"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "画像"
|
||||
},
|
||||
"1": {
|
||||
"name": "マスク"
|
||||
},
|
||||
"2": {
|
||||
"name": "メッシュパス"
|
||||
},
|
||||
"3": {
|
||||
"name": "法線"
|
||||
},
|
||||
{
|
||||
"4": {
|
||||
"name": "線画"
|
||||
},
|
||||
{
|
||||
"5": {
|
||||
"name": "カメラ情報"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Load3DAnimation": {
|
||||
"display_name": "3Dを読み込む - アニメーション",
|
||||
"display_name": "3D読み込み - アニメーション",
|
||||
"inputs": {
|
||||
"clear": {
|
||||
},
|
||||
@@ -3452,17 +3458,23 @@
|
||||
"name": "幅"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "画像"
|
||||
},
|
||||
"1": {
|
||||
"name": "マスク"
|
||||
},
|
||||
"2": {
|
||||
"name": "メッシュパス"
|
||||
},
|
||||
"3": {
|
||||
"name": "法線"
|
||||
},
|
||||
{
|
||||
"4": {
|
||||
"name": "カメラ情報"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"LoadAudio": {
|
||||
"display_name": "音声を読み込む",
|
||||
|
||||
@@ -3398,7 +3398,7 @@
|
||||
}
|
||||
},
|
||||
"Load3D": {
|
||||
"display_name": "3D 로드",
|
||||
"display_name": "3D 불러오기",
|
||||
"inputs": {
|
||||
"clear": {
|
||||
},
|
||||
@@ -3417,23 +3417,29 @@
|
||||
"name": "너비"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "이미지"
|
||||
},
|
||||
"1": {
|
||||
"name": "마스크"
|
||||
},
|
||||
"2": {
|
||||
"name": "메시 경로"
|
||||
},
|
||||
"3": {
|
||||
"name": "노멀"
|
||||
},
|
||||
{
|
||||
"4": {
|
||||
"name": "라인아트"
|
||||
},
|
||||
{
|
||||
"5": {
|
||||
"name": "카메라 정보"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Load3DAnimation": {
|
||||
"display_name": "3D 로드 - 애니메이션",
|
||||
"display_name": "3D 불러오기 - 애니메이션",
|
||||
"inputs": {
|
||||
"clear": {
|
||||
},
|
||||
@@ -3452,17 +3458,23 @@
|
||||
"name": "너비"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "이미지"
|
||||
},
|
||||
"1": {
|
||||
"name": "마스크"
|
||||
},
|
||||
"2": {
|
||||
"name": "메시 경로"
|
||||
},
|
||||
"3": {
|
||||
"name": "노멀"
|
||||
},
|
||||
{
|
||||
"4": {
|
||||
"name": "카메라 정보"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"LoadAudio": {
|
||||
"display_name": "오디오 로드",
|
||||
|
||||
@@ -3409,7 +3409,7 @@
|
||||
"name": "изображение"
|
||||
},
|
||||
"model_file": {
|
||||
"name": "файл_модели"
|
||||
"name": "файл модели"
|
||||
},
|
||||
"upload 3d model": {
|
||||
},
|
||||
@@ -3417,23 +3417,29 @@
|
||||
"name": "ширина"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "изображение"
|
||||
},
|
||||
"1": {
|
||||
"name": "mask"
|
||||
},
|
||||
"2": {
|
||||
"name": "путь к mesh"
|
||||
},
|
||||
"3": {
|
||||
"name": "нормаль"
|
||||
},
|
||||
{
|
||||
"name": "линеарт"
|
||||
"4": {
|
||||
"name": "линейный рисунок"
|
||||
},
|
||||
{
|
||||
"name": "информация_камеры"
|
||||
"5": {
|
||||
"name": "информация о камере"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Load3DAnimation": {
|
||||
"display_name": "Загрузить 3D — Анимация",
|
||||
"display_name": "Загрузить 3D - Анимация",
|
||||
"inputs": {
|
||||
"clear": {
|
||||
},
|
||||
@@ -3452,17 +3458,23 @@
|
||||
"name": "ширина"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "изображение"
|
||||
},
|
||||
"1": {
|
||||
"name": "mask"
|
||||
},
|
||||
"2": {
|
||||
"name": "путь_к_модели"
|
||||
},
|
||||
"3": {
|
||||
"name": "нормаль"
|
||||
},
|
||||
{
|
||||
"name": "информация_камеры"
|
||||
"4": {
|
||||
"name": "информация_о_камере"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"LoadAudio": {
|
||||
"display_name": "Загрузить аудио",
|
||||
|
||||
@@ -3417,20 +3417,26 @@
|
||||
"name": "宽度"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"name": "法线"
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "image"
|
||||
},
|
||||
{
|
||||
"name": "线稿"
|
||||
"1": {
|
||||
"name": "mask"
|
||||
},
|
||||
{
|
||||
"name": "相机信息"
|
||||
"2": {
|
||||
"name": "mesh_path"
|
||||
},
|
||||
"3": {
|
||||
"name": "normal"
|
||||
},
|
||||
"4": {
|
||||
"name": "lineart"
|
||||
},
|
||||
"5": {
|
||||
"name": "camera_info"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Load3DAnimation": {
|
||||
"display_name": "加载3D动画",
|
||||
@@ -3452,17 +3458,23 @@
|
||||
"name": "宽度"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"outputs": {
|
||||
"0": {
|
||||
"name": "图像"
|
||||
},
|
||||
"1": {
|
||||
"name": "遮罩"
|
||||
},
|
||||
"2": {
|
||||
"name": "mesh_path"
|
||||
},
|
||||
"3": {
|
||||
"name": "法线"
|
||||
},
|
||||
{
|
||||
"4": {
|
||||
"name": "相机信息"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"LoadAudio": {
|
||||
"display_name": "加载音频",
|
||||
|
||||
@@ -5,9 +5,12 @@ import Load3d from '@/extensions/core/load3d/Load3d'
|
||||
import Load3dAnimation from '@/extensions/core/load3d/Load3dAnimation'
|
||||
import type { CustomInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
|
||||
type Load3dReadyCallback = (load3d: Load3d | Load3dAnimation) => void
|
||||
|
||||
export class Load3dService {
|
||||
private static instance: Load3dService
|
||||
private nodeToLoad3dMap = new Map<LGraphNode, Load3d | Load3dAnimation>()
|
||||
private pendingCallbacks = new Map<LGraphNode, Load3dReadyCallback[]>()
|
||||
|
||||
private constructor() {}
|
||||
|
||||
@@ -60,6 +63,13 @@ export class Load3dService {
|
||||
|
||||
this.nodeToLoad3dMap.set(rawNode, instance)
|
||||
|
||||
const callbacks = this.pendingCallbacks.get(rawNode)
|
||||
|
||||
if (callbacks) {
|
||||
callbacks.forEach((callback) => callback(instance))
|
||||
this.pendingCallbacks.delete(rawNode)
|
||||
}
|
||||
|
||||
return instance
|
||||
}
|
||||
|
||||
@@ -69,6 +79,24 @@ export class Load3dService {
|
||||
return this.nodeToLoad3dMap.get(rawNode) || null
|
||||
}
|
||||
|
||||
waitForLoad3d(node: LGraphNode, callback: Load3dReadyCallback): void {
|
||||
const rawNode = toRaw(node)
|
||||
|
||||
const existingInstance = this.nodeToLoad3dMap.get(rawNode)
|
||||
|
||||
if (existingInstance) {
|
||||
callback(existingInstance)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.pendingCallbacks.has(rawNode)) {
|
||||
this.pendingCallbacks.set(rawNode, [])
|
||||
}
|
||||
|
||||
this.pendingCallbacks.get(rawNode)!.push(callback)
|
||||
}
|
||||
|
||||
getNodeByLoad3d(load3d: Load3d | Load3dAnimation): LGraphNode | null {
|
||||
for (const [node, instance] of this.nodeToLoad3dMap) {
|
||||
if (instance === load3d) {
|
||||
@@ -88,12 +116,15 @@ export class Load3dService {
|
||||
|
||||
this.nodeToLoad3dMap.delete(rawNode)
|
||||
}
|
||||
|
||||
this.pendingCallbacks.delete(rawNode)
|
||||
}
|
||||
|
||||
clear() {
|
||||
for (const [node] of this.nodeToLoad3dMap) {
|
||||
this.removeLoad3d(node)
|
||||
}
|
||||
this.pendingCallbacks.clear()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user