diff --git a/src/composables/useLoad3d.ts b/src/composables/useLoad3d.ts index 8b589fc2be8..08a63b30e96 100644 --- a/src/composables/useLoad3d.ts +++ b/src/composables/useLoad3d.ts @@ -214,12 +214,20 @@ export const useLoad3d = (nodeOrRef: MaybeRef) => { return modelPath } - const [subfolder, filename] = Load3dUtils.splitFilePath(modelPath) + let cleanPath = modelPath.trim() + let forcedType: 'output' | 'input' | undefined + + if (cleanPath.endsWith('[output]')) { + cleanPath = cleanPath.replace(/\s*\[output\]$/, '').trim() + forcedType = 'output' + } + + const [subfolder, filename] = Load3dUtils.splitFilePath(cleanPath) return api.apiURL( Load3dUtils.getResourceURL( subfolder, filename, - isPreview.value ? 'output' : 'input' + forcedType ?? (isPreview.value ? 'output' : 'input') ) ) } catch (error) { diff --git a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelect.vue b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelect.vue index e4cc4878294..51250cd81a6 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelect.vue +++ b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelect.vue @@ -59,8 +59,11 @@ const specDescriptor = computed<{ allowUpload: boolean folder: ResultItemType | undefined }>(() => { + const isLoad3DMesh = + props.nodeType === 'Load3D' && props.widget.name === 'model_file' + const spec = comboSpec.value - if (!spec) { + if (!spec && !isLoad3DMesh) { return { kind: 'unknown', allowUpload: false, @@ -74,7 +77,7 @@ const specDescriptor = computed<{ video_upload, image_folder, audio_upload - } = spec + } = spec || {} let kind: AssetKind = 'unknown' if (video_upload) { @@ -83,18 +86,27 @@ const specDescriptor = computed<{ kind = 'image' } else if (audio_upload) { kind = 'audio' + } else if (isLoad3DMesh) { + kind = 'mesh' } + // TODO: add support for models (checkpoints, VAE, LoRAs, etc.) -- get widgetType from spec const allowUpload = image_upload === true || animated_image_upload === true || video_upload === true || - audio_upload === true + audio_upload === true || + isLoad3DMesh + + const subfolder = isLoad3DMesh ? '3d' : undefined + const folder = isLoad3DMesh ? 'input' : image_folder + return { kind, allowUpload, - folder: image_folder + folder, + subfolder } }) diff --git a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue index f460390a234..c5d45e3d201 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue +++ b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue @@ -114,7 +114,7 @@ const inputItems = computed(() => { })) }) const outputItems = computed(() => { - if (!['image', 'video'].includes(props.assetKind ?? '')) return [] + if (!['image', 'video', 'mesh'].includes(props.assetKind ?? '')) return [] const outputs = new Set() @@ -123,7 +123,8 @@ const outputItems = computed(() => { task.flatOutputs.forEach((output) => { const isTargetType = (props.assetKind === 'image' && output.mediaType === 'images') || - (props.assetKind === 'video' && output.mediaType === 'video') + (props.assetKind === 'video' && output.mediaType === 'video') || + (props.assetKind === 'mesh' && output.is3D) if (output.type === 'output' && isTargetType) { const path = output.subfolder @@ -182,7 +183,7 @@ const mediaPlaceholder = computed(() => { return t('widgets.uploadSelect.placeholderVideo') case 'audio': return t('widgets.uploadSelect.placeholderAudio') - case 'model': + case 'mesh': return t('widgets.uploadSelect.placeholderModel') case 'unknown': return t('widgets.uploadSelect.placeholderUnknown') @@ -206,6 +207,8 @@ const acceptTypes = computed(() => { return 'video/*' case 'audio': return 'audio/*' + case 'mesh': + return '.obj,.stl,.ply,.spz' default: return undefined // model or unknown } diff --git a/src/types/widgetTypes.ts b/src/types/widgetTypes.ts index ed6cb20c9a6..453f283db99 100644 --- a/src/types/widgetTypes.ts +++ b/src/types/widgetTypes.ts @@ -1,5 +1,11 @@ import type { InjectionKey } from 'vue' -export type AssetKind = 'image' | 'video' | 'audio' | 'model' | 'unknown' +export type AssetKind = + | 'image' + | 'video' + | 'audio' + | 'model' + | 'mesh' + | 'unknown' export const OnCloseKey: InjectionKey<() => void> = Symbol()