mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 18:52:19 +00:00
[3d] improve mtl support logic (#3965)
This commit is contained in:
@@ -266,7 +266,7 @@ useExtensionService().registerExtension({
|
|||||||
LOAD_3D_ANIMATION(node) {
|
LOAD_3D_ANIMATION(node) {
|
||||||
const fileInput = document.createElement('input')
|
const fileInput = document.createElement('input')
|
||||||
fileInput.type = 'file'
|
fileInput.type = 'file'
|
||||||
fileInput.accept = '.fbx,glb,gltf'
|
fileInput.accept = '.gltf,.glb,.fbx'
|
||||||
fileInput.style.display = 'none'
|
fileInput.style.display = 'none'
|
||||||
fileInput.onchange = async () => {
|
fileInput.onchange = async () => {
|
||||||
if (fileInput.files?.length) {
|
if (fileInput.files?.length) {
|
||||||
@@ -452,31 +452,43 @@ useExtensionService().registerExtension({
|
|||||||
|
|
||||||
const onExecuted = node.onExecuted
|
const onExecuted = node.onExecuted
|
||||||
|
|
||||||
node.onExecuted = function (message: any) {
|
useLoad3dService().waitForLoad3d(node, (load3d) => {
|
||||||
onExecuted?.apply(this, arguments as any)
|
const config = new Load3DConfiguration(load3d)
|
||||||
|
|
||||||
let filePath = message.result[0]
|
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||||
|
|
||||||
if (!filePath) {
|
if (modelWidget) {
|
||||||
const msg = t('toastMessages.unableToGetModelFilePath')
|
const lastTimeModelFile = node.properties['Last Time Model File']
|
||||||
console.error(msg)
|
|
||||||
useToastStore().addAlert(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
let cameraState = message.result[1]
|
if (lastTimeModelFile) {
|
||||||
|
modelWidget.value = lastTimeModelFile
|
||||||
|
|
||||||
useLoad3dService().waitForLoad3d(node, (load3d) => {
|
const cameraState = node.properties['Camera Info']
|
||||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
|
||||||
|
|
||||||
if (modelWidget) {
|
|
||||||
modelWidget.value = filePath.replaceAll('\\', '/')
|
|
||||||
|
|
||||||
const config = new Load3DConfiguration(load3d)
|
|
||||||
|
|
||||||
config.configure('output', modelWidget, cameraState)
|
config.configure('output', modelWidget, cameraState)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
node.onExecuted = function (message: any) {
|
||||||
|
onExecuted?.apply(this, arguments as any)
|
||||||
|
|
||||||
|
let filePath = message.result[0]
|
||||||
|
|
||||||
|
if (!filePath) {
|
||||||
|
const msg = t('toastMessages.unableToGetModelFilePath')
|
||||||
|
console.error(msg)
|
||||||
|
useToastStore().addAlert(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
let cameraState = message.result[1]
|
||||||
|
|
||||||
|
modelWidget.value = filePath.replaceAll('\\', '/')
|
||||||
|
|
||||||
|
node.properties['Last Time Model File'] = modelWidget.value
|
||||||
|
|
||||||
|
config.configure('output', modelWidget, cameraState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -526,29 +538,42 @@ useExtensionService().registerExtension({
|
|||||||
|
|
||||||
const onExecuted = node.onExecuted
|
const onExecuted = node.onExecuted
|
||||||
|
|
||||||
node.onExecuted = function (message: any) {
|
useLoad3dService().waitForLoad3d(node, (load3d) => {
|
||||||
onExecuted?.apply(this, arguments as any)
|
const config = new Load3DConfiguration(load3d)
|
||||||
|
|
||||||
let filePath = message.result[0]
|
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||||
|
|
||||||
if (!filePath) {
|
if (modelWidget) {
|
||||||
const msg = t('toastMessages.unableToGetModelFilePath')
|
const lastTimeModelFile = node.properties['Last Time Model File']
|
||||||
console.error(msg)
|
|
||||||
useToastStore().addAlert(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
let cameraState = message.result[1]
|
if (lastTimeModelFile) {
|
||||||
|
modelWidget.value = lastTimeModelFile
|
||||||
|
|
||||||
useLoad3dService().waitForLoad3d(node, (load3d) => {
|
const cameraState = node.properties['Camera Info']
|
||||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
|
||||||
if (modelWidget) {
|
|
||||||
modelWidget.value = filePath.replaceAll('\\', '/')
|
|
||||||
|
|
||||||
const config = new Load3DConfiguration(load3d)
|
|
||||||
|
|
||||||
config.configure('output', modelWidget, cameraState)
|
config.configure('output', modelWidget, cameraState)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
node.onExecuted = function (message: any) {
|
||||||
|
onExecuted?.apply(this, arguments as any)
|
||||||
|
|
||||||
|
let filePath = message.result[0]
|
||||||
|
|
||||||
|
if (!filePath) {
|
||||||
|
const msg = t('toastMessages.unableToGetModelFilePath')
|
||||||
|
console.error(msg)
|
||||||
|
useToastStore().addAlert(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
let cameraState = message.result[1]
|
||||||
|
|
||||||
|
modelWidget.value = filePath.replaceAll('\\', '/')
|
||||||
|
|
||||||
|
node.properties['Last Time Model File'] = modelWidget.value
|
||||||
|
|
||||||
|
config.configure('output', modelWidget, cameraState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -132,6 +132,14 @@ export class LoaderManager implements LoaderManagerInterface {
|
|||||||
if (this.modelManager.materialMode === 'original') {
|
if (this.modelManager.materialMode === 'original') {
|
||||||
const mtlUrl = url.replace(/(filename=.*?)\.obj/, '$1.mtl')
|
const mtlUrl = url.replace(/(filename=.*?)\.obj/, '$1.mtl')
|
||||||
|
|
||||||
|
const subfolderMatch = url.match(/[?&]subfolder=([^&]*)/)
|
||||||
|
|
||||||
|
const subfolder = subfolderMatch
|
||||||
|
? decodeURIComponent(subfolderMatch[1])
|
||||||
|
: '3d'
|
||||||
|
|
||||||
|
this.mtlLoader.setSubfolder(subfolder)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const materials = await this.mtlLoader.loadAsync(mtlUrl)
|
const materials = await this.mtlLoader.loadAsync(mtlUrl)
|
||||||
materials.preload()
|
materials.preload()
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ class OverrideMTLLoader extends Loader {
|
|||||||
this.loadRootFolder = loadRootFolder
|
this.loadRootFolder = loadRootFolder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSubfolder(subfolder) {
|
||||||
|
this.subfolder = subfolder
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts loading from the given URL and passes the loaded MTL asset
|
* Starts loading from the given URL and passes the loaded MTL asset
|
||||||
* to the `onLoad()` callback.
|
* to the `onLoad()` callback.
|
||||||
@@ -135,7 +139,8 @@ class OverrideMTLLoader extends Loader {
|
|||||||
const materialCreator = new OverrideMaterialCreator(
|
const materialCreator = new OverrideMaterialCreator(
|
||||||
this.resourcePath || path,
|
this.resourcePath || path,
|
||||||
this.materialOptions,
|
this.materialOptions,
|
||||||
this.loadRootFolder
|
this.loadRootFolder,
|
||||||
|
this.subfolder
|
||||||
)
|
)
|
||||||
materialCreator.setCrossOrigin(this.crossOrigin)
|
materialCreator.setCrossOrigin(this.crossOrigin)
|
||||||
materialCreator.setManager(this.manager)
|
materialCreator.setManager(this.manager)
|
||||||
@@ -155,7 +160,7 @@ class OverrideMTLLoader extends Loader {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class OverrideMaterialCreator {
|
class OverrideMaterialCreator {
|
||||||
constructor(baseUrl = '', options = {}, loadRootFolder) {
|
constructor(baseUrl = '', options = {}, loadRootFolder, subfolder) {
|
||||||
this.baseUrl = baseUrl
|
this.baseUrl = baseUrl
|
||||||
this.options = options
|
this.options = options
|
||||||
this.materialsInfo = {}
|
this.materialsInfo = {}
|
||||||
@@ -164,6 +169,7 @@ class OverrideMaterialCreator {
|
|||||||
this.nameLookup = {}
|
this.nameLookup = {}
|
||||||
|
|
||||||
this.loadRootFolder = loadRootFolder
|
this.loadRootFolder = loadRootFolder
|
||||||
|
this.subfolder = subfolder
|
||||||
|
|
||||||
this.crossOrigin = 'anonymous'
|
this.crossOrigin = 'anonymous'
|
||||||
|
|
||||||
@@ -283,16 +289,25 @@ class OverrideMaterialCreator {
|
|||||||
/**
|
/**
|
||||||
* Override for ComfyUI api url
|
* Override for ComfyUI api url
|
||||||
*/
|
*/
|
||||||
function resolveURL(baseUrl, url, loadRootFolder) {
|
function resolveURL(baseUrl, url, loadRootFolder, subfolder) {
|
||||||
if (typeof url !== 'string' || url === '') return ''
|
if (typeof url !== 'string' || url === '') return ''
|
||||||
|
|
||||||
|
if (baseUrl.endsWith('/')) {
|
||||||
|
baseUrl = baseUrl.slice(0, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!baseUrl.endsWith('api')) {
|
||||||
|
baseUrl = '/api'
|
||||||
|
}
|
||||||
|
|
||||||
baseUrl =
|
baseUrl =
|
||||||
baseUrl +
|
baseUrl +
|
||||||
'/view?filename=' +
|
'/view?filename=' +
|
||||||
url +
|
url +
|
||||||
'&type=' +
|
'&type=' +
|
||||||
loadRootFolder +
|
loadRootFolder +
|
||||||
'&subfolder=3d'
|
'&subfolder=' +
|
||||||
|
subfolder
|
||||||
|
|
||||||
return baseUrl
|
return baseUrl
|
||||||
}
|
}
|
||||||
@@ -302,7 +317,12 @@ class OverrideMaterialCreator {
|
|||||||
|
|
||||||
const texParams = scope.getTextureParams(value, params)
|
const texParams = scope.getTextureParams(value, params)
|
||||||
const map = scope.loadTexture(
|
const map = scope.loadTexture(
|
||||||
resolveURL(scope.baseUrl, texParams.url, scope.loadRootFolder)
|
resolveURL(
|
||||||
|
scope.baseUrl,
|
||||||
|
texParams.url,
|
||||||
|
scope.loadRootFolder,
|
||||||
|
scope.subfolder
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
map.repeat.copy(texParams.scale)
|
map.repeat.copy(texParams.scale)
|
||||||
|
|||||||
Reference in New Issue
Block a user