mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-27 17:52:16 +00:00
[3d] add support to upload texture (#3224)
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -32,6 +32,8 @@ useExtensionService().registerExtension({
|
||||
(w: IWidget) => w.name === 'model_file'
|
||||
) as IStringWidget
|
||||
|
||||
node.properties['Texture'] = undefined
|
||||
|
||||
const uploadPath = await Load3dUtils.uploadFile(
|
||||
fileInput.files[0]
|
||||
).catch((error) => {
|
||||
@@ -70,6 +72,8 @@ useExtensionService().registerExtension({
|
||||
)
|
||||
if (modelWidget) {
|
||||
modelWidget.value = ''
|
||||
|
||||
node.properties['Texture'] = undefined
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -61,7 +61,12 @@ class Load3DConfiguration {
|
||||
if (modelWidget.value) {
|
||||
onModelWidgetUpdate(modelWidget.value)
|
||||
}
|
||||
modelWidget.callback = onModelWidgetUpdate
|
||||
|
||||
modelWidget.callback = (value: string | number | boolean | object) => {
|
||||
this.load3d.node.properties['Texture'] = undefined
|
||||
|
||||
onModelWidgetUpdate(value)
|
||||
}
|
||||
}
|
||||
|
||||
private setupDefaultProperties() {
|
||||
@@ -136,6 +141,12 @@ class Load3DConfiguration {
|
||||
|
||||
this.load3d.setEdgeThreshold(edgeThreshold)
|
||||
|
||||
const texturePath = this.load3d.loadNodeProperty('Texture', null)
|
||||
|
||||
if (texturePath) {
|
||||
await this.load3d.applyTexture(texturePath)
|
||||
}
|
||||
|
||||
if (isFirstLoad && cameraState && typeof cameraState === 'object') {
|
||||
try {
|
||||
this.load3d.setCameraState(cameraState)
|
||||
|
||||
@@ -26,7 +26,7 @@ class Load3d {
|
||||
renderer: THREE.WebGLRenderer
|
||||
protected clock: THREE.Clock
|
||||
protected animationFrameId: number | null = null
|
||||
protected node: LGraphNode
|
||||
node: LGraphNode
|
||||
|
||||
protected eventManager: EventManager
|
||||
protected nodeStorage: NodeStorage
|
||||
@@ -267,6 +267,23 @@ class Load3d {
|
||||
}
|
||||
}
|
||||
|
||||
async applyTexture(texturePath: string): Promise<void> {
|
||||
if (!this.modelManager.currentModel) {
|
||||
throw new Error('No model to apply texture to')
|
||||
}
|
||||
|
||||
this.eventManager.emitEvent('textureLoadingStart', null)
|
||||
|
||||
try {
|
||||
await this.modelManager.applyTexture(texturePath)
|
||||
} catch (error) {
|
||||
console.error('Error applying texture:', error)
|
||||
throw error
|
||||
} finally {
|
||||
this.eventManager.emitEvent('textureLoadingEnd', null)
|
||||
}
|
||||
}
|
||||
|
||||
setBackgroundColor(color: string): void {
|
||||
this.sceneManager.setBackgroundColor(color)
|
||||
this.forceRender()
|
||||
|
||||
@@ -5,6 +5,7 @@ import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeome
|
||||
import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader'
|
||||
import { mergeVertices } from 'three/examples/jsm/utils/BufferGeometryUtils'
|
||||
|
||||
import Load3dUtils from './Load3dUtils'
|
||||
import { ColoredShadowMaterial } from './conditional-lines/ColoredShadowMaterial'
|
||||
import { ConditionalEdgesGeometry } from './conditional-lines/ConditionalEdgesGeometry'
|
||||
import { ConditionalEdgesShader } from './conditional-lines/ConditionalEdgesShader.js'
|
||||
@@ -37,6 +38,8 @@ export class ModelManager implements ModelManagerInterface {
|
||||
depthMaterial: THREE.MeshDepthMaterial
|
||||
originalFileName: string | null = null
|
||||
originalURL: string | null = null
|
||||
appliedTexture: THREE.Texture | null = null
|
||||
textureLoader: THREE.TextureLoader
|
||||
|
||||
private scene: THREE.Scene
|
||||
private renderer: THREE.WebGLRenderer
|
||||
@@ -68,6 +71,7 @@ export class ModelManager implements ModelManagerInterface {
|
||||
this.eventManager = eventManager
|
||||
this.activeCamera = getActiveCamera()
|
||||
this.setupCamera = setupCamera
|
||||
this.textureLoader = new THREE.TextureLoader()
|
||||
|
||||
if (
|
||||
options &&
|
||||
@@ -113,6 +117,11 @@ export class ModelManager implements ModelManagerInterface {
|
||||
this.wireframeMaterial.dispose()
|
||||
this.depthMaterial.dispose()
|
||||
|
||||
if (this.appliedTexture) {
|
||||
this.appliedTexture.dispose()
|
||||
this.appliedTexture = null
|
||||
}
|
||||
|
||||
this.disposeLineartModel()
|
||||
}
|
||||
|
||||
@@ -126,6 +135,66 @@ export class ModelManager implements ModelManagerInterface {
|
||||
})
|
||||
}
|
||||
|
||||
async applyTexture(texturePath: string): Promise<void> {
|
||||
if (!this.currentModel) {
|
||||
throw new Error('No model available to apply texture to')
|
||||
}
|
||||
|
||||
if (this.appliedTexture) {
|
||||
this.appliedTexture.dispose()
|
||||
}
|
||||
|
||||
try {
|
||||
let imageUrl = Load3dUtils.getResourceURL(
|
||||
...Load3dUtils.splitFilePath(texturePath)
|
||||
)
|
||||
|
||||
if (!imageUrl.startsWith('/api')) {
|
||||
imageUrl = '/api' + imageUrl
|
||||
}
|
||||
|
||||
this.appliedTexture = await new Promise<THREE.Texture>(
|
||||
(resolve, reject) => {
|
||||
this.textureLoader.load(
|
||||
imageUrl,
|
||||
(texture) => {
|
||||
texture.colorSpace = THREE.SRGBColorSpace
|
||||
texture.wrapS = THREE.RepeatWrapping
|
||||
texture.wrapT = THREE.RepeatWrapping
|
||||
resolve(texture)
|
||||
},
|
||||
undefined,
|
||||
(error) => reject(error)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (this.materialMode === 'original') {
|
||||
this.currentModel.traverse((child) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
const material = new THREE.MeshStandardMaterial({
|
||||
map: this.appliedTexture,
|
||||
metalness: 0.1,
|
||||
roughness: 0.8,
|
||||
side: THREE.DoubleSide
|
||||
})
|
||||
|
||||
if (!this.originalMaterials.has(child)) {
|
||||
this.originalMaterials.set(child, child.material)
|
||||
}
|
||||
|
||||
child.material = material
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
} catch (error) {
|
||||
console.error('Error applying texture:', error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
}
|
||||
|
||||
disposeLineartModel(): void {
|
||||
this.disposeEdgesModel()
|
||||
this.disposeShadowModel()
|
||||
@@ -576,7 +645,16 @@ export class ModelManager implements ModelManagerInterface {
|
||||
if (originalMaterial) {
|
||||
child.material = originalMaterial
|
||||
} else {
|
||||
child.material = this.standardMaterial
|
||||
if (this.appliedTexture) {
|
||||
child.material = new THREE.MeshStandardMaterial({
|
||||
map: this.appliedTexture,
|
||||
metalness: 0.1,
|
||||
roughness: 0.8,
|
||||
side: THREE.DoubleSide
|
||||
})
|
||||
} else {
|
||||
child.material = this.standardMaterial
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -638,6 +716,11 @@ export class ModelManager implements ModelManagerInterface {
|
||||
this.originalFileName = null
|
||||
this.originalURL = null
|
||||
|
||||
if (this.appliedTexture) {
|
||||
this.appliedTexture.dispose()
|
||||
this.appliedTexture = null
|
||||
}
|
||||
|
||||
this.originalMaterials = new WeakMap()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user