mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-11 16:10:05 +00:00
support panoramic image in 3d node (#6638)
## Summary Adds panoramic image support to the 3D node viewer, allowing users to display equirectangular panoramic images as immersive backgrounds alongside the existing tiled image mode. ## Changes - Toggle between tiled and panorama rendering modes for background images - Field of view (FOV) control for panorama mode - Refactored FOV slider into reusable PopupSlider component ## Screenshots https://github.com/user-attachments/assets/8955d74b-b0e6-4b26-83ca-ccf902b43aa6 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6638-support-panoramic-image-in-3d-node-2a56d73d365081b98647f988130e312e) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -162,7 +162,11 @@ class Load3DConfiguration {
|
||||
return
|
||||
}
|
||||
|
||||
this.load3d.setBackgroundImage(config.backgroundImage)
|
||||
void this.load3d.setBackgroundImage(config.backgroundImage)
|
||||
|
||||
if (config.backgroundRenderMode) {
|
||||
this.load3d.setBackgroundRenderMode(config.backgroundRenderMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -510,6 +510,11 @@ class Load3d {
|
||||
this.forceRender()
|
||||
}
|
||||
|
||||
setBackgroundRenderMode(mode: 'tiled' | 'panorama'): void {
|
||||
this.sceneManager.setBackgroundRenderMode(mode)
|
||||
this.forceRender()
|
||||
}
|
||||
|
||||
toggleCamera(cameraType?: 'perspective' | 'orthographic'): void {
|
||||
this.cameraManager.toggleCamera(cameraType)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
|
||||
|
||||
import Load3dUtils from './Load3dUtils'
|
||||
import {
|
||||
type BackgroundRenderModeType,
|
||||
type EventManagerInterface,
|
||||
type SceneManagerInterface
|
||||
} from './interfaces'
|
||||
@@ -16,6 +17,8 @@ export class SceneManager implements SceneManagerInterface {
|
||||
backgroundMesh: THREE.Mesh | null = null
|
||||
backgroundTexture: THREE.Texture | null = null
|
||||
|
||||
backgroundRenderMode: 'tiled' | 'panorama' = 'tiled'
|
||||
|
||||
backgroundColorMaterial: THREE.MeshBasicMaterial | null = null
|
||||
currentBackgroundType: 'color' | 'image' = 'color'
|
||||
currentBackgroundColor: string = '#282828'
|
||||
@@ -89,6 +92,10 @@ export class SceneManager implements SceneManagerInterface {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.scene.background) {
|
||||
this.scene.background = null
|
||||
}
|
||||
|
||||
this.scene.clear()
|
||||
}
|
||||
|
||||
@@ -104,6 +111,15 @@ export class SceneManager implements SceneManagerInterface {
|
||||
this.currentBackgroundColor = color
|
||||
this.currentBackgroundType = 'color'
|
||||
|
||||
if (this.scene.background instanceof THREE.Texture) {
|
||||
this.scene.background = null
|
||||
}
|
||||
|
||||
if (this.backgroundRenderMode === 'panorama') {
|
||||
this.backgroundRenderMode = 'tiled'
|
||||
this.eventManager.emitEvent('backgroundRenderModeChange', 'tiled')
|
||||
}
|
||||
|
||||
if (!this.backgroundMesh || !this.backgroundColorMaterial) {
|
||||
this.initBackgroundScene()
|
||||
}
|
||||
@@ -168,36 +184,41 @@ export class SceneManager implements SceneManagerInterface {
|
||||
this.backgroundTexture = texture
|
||||
this.currentBackgroundType = 'image'
|
||||
|
||||
if (!this.backgroundMesh) {
|
||||
this.initBackgroundScene()
|
||||
}
|
||||
|
||||
const imageMaterial = new THREE.MeshBasicMaterial({
|
||||
map: texture,
|
||||
transparent: true,
|
||||
depthWrite: false,
|
||||
depthTest: false,
|
||||
side: THREE.DoubleSide
|
||||
})
|
||||
|
||||
if (this.backgroundMesh) {
|
||||
if (
|
||||
this.backgroundMesh.material !== this.backgroundColorMaterial &&
|
||||
this.backgroundMesh.material instanceof THREE.Material
|
||||
) {
|
||||
this.backgroundMesh.material.dispose()
|
||||
if (this.backgroundRenderMode === 'panorama') {
|
||||
texture.mapping = THREE.EquirectangularReflectionMapping
|
||||
this.scene.background = texture
|
||||
} else {
|
||||
if (!this.backgroundMesh) {
|
||||
this.initBackgroundScene()
|
||||
}
|
||||
|
||||
this.backgroundMesh.material = imageMaterial
|
||||
this.backgroundMesh.position.set(0, 0, 0)
|
||||
}
|
||||
const imageMaterial = new THREE.MeshBasicMaterial({
|
||||
map: texture,
|
||||
transparent: true,
|
||||
depthWrite: false,
|
||||
depthTest: false,
|
||||
side: THREE.DoubleSide
|
||||
})
|
||||
|
||||
this.updateBackgroundSize(
|
||||
this.backgroundTexture,
|
||||
this.backgroundMesh,
|
||||
this.renderer.domElement.clientWidth,
|
||||
this.renderer.domElement.clientHeight
|
||||
)
|
||||
if (this.backgroundMesh) {
|
||||
if (
|
||||
this.backgroundMesh.material !== this.backgroundColorMaterial &&
|
||||
this.backgroundMesh.material instanceof THREE.Material
|
||||
) {
|
||||
this.backgroundMesh.material.dispose()
|
||||
}
|
||||
|
||||
this.backgroundMesh.material = imageMaterial
|
||||
this.backgroundMesh.position.set(0, 0, 0)
|
||||
}
|
||||
|
||||
this.updateBackgroundSize(
|
||||
this.backgroundTexture,
|
||||
this.backgroundMesh,
|
||||
this.renderer.domElement.clientWidth,
|
||||
this.renderer.domElement.clientHeight
|
||||
)
|
||||
}
|
||||
|
||||
this.eventManager.emitEvent('backgroundImageChange', uploadPath)
|
||||
this.eventManager.emitEvent('backgroundImageLoadingEnd', null)
|
||||
@@ -213,6 +234,35 @@ export class SceneManager implements SceneManagerInterface {
|
||||
this.eventManager.emitEvent('backgroundImageLoadingEnd', null)
|
||||
}
|
||||
|
||||
setBackgroundRenderMode(mode: BackgroundRenderModeType): void {
|
||||
if (this.backgroundRenderMode === mode) return
|
||||
|
||||
this.backgroundRenderMode = mode
|
||||
|
||||
if (this.currentBackgroundType === 'image' && this.backgroundTexture) {
|
||||
try {
|
||||
if (mode === 'panorama') {
|
||||
this.backgroundTexture.mapping =
|
||||
THREE.EquirectangularReflectionMapping
|
||||
this.scene.background = this.backgroundTexture
|
||||
} else {
|
||||
this.scene.background = null
|
||||
if (
|
||||
this.backgroundMesh &&
|
||||
this.backgroundMesh.material instanceof THREE.MeshBasicMaterial
|
||||
) {
|
||||
this.backgroundMesh.material.map = this.backgroundTexture
|
||||
this.backgroundMesh.material.needsUpdate = true
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error set background render mode:', error)
|
||||
}
|
||||
}
|
||||
|
||||
this.eventManager.emitEvent('backgroundRenderModeChange', mode)
|
||||
}
|
||||
|
||||
updateBackgroundSize(
|
||||
backgroundTexture: THREE.Texture | null,
|
||||
backgroundMesh: THREE.Mesh | null,
|
||||
@@ -254,7 +304,11 @@ export class SceneManager implements SceneManagerInterface {
|
||||
}
|
||||
|
||||
renderBackground(): void {
|
||||
if (this.backgroundMesh) {
|
||||
if (
|
||||
(this.backgroundRenderMode === 'tiled' ||
|
||||
this.currentBackgroundType === 'color') &&
|
||||
this.backgroundMesh
|
||||
) {
|
||||
const currentToneMapping = this.renderer.toneMapping
|
||||
const currentExposure = this.renderer.toneMappingExposure
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import { type CustomInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
export type MaterialMode = 'original' | 'normal' | 'wireframe' | 'depth'
|
||||
export type UpDirection = 'original' | '-x' | '+x' | '-y' | '+y' | '-z' | '+z'
|
||||
export type CameraType = 'perspective' | 'orthographic'
|
||||
export type BackgroundRenderModeType = 'tiled' | 'panorama'
|
||||
|
||||
export interface CameraState {
|
||||
position: THREE.Vector3
|
||||
@@ -25,6 +26,7 @@ export interface SceneConfig {
|
||||
showGrid: boolean
|
||||
backgroundColor: string
|
||||
backgroundImage?: string
|
||||
backgroundRenderMode?: BackgroundRenderModeType
|
||||
}
|
||||
|
||||
export interface ModelConfig {
|
||||
@@ -77,6 +79,7 @@ export interface SceneManagerInterface extends BaseManager {
|
||||
setBackgroundColor(color: string): void
|
||||
setBackgroundImage(uploadPath: string): Promise<void>
|
||||
removeBackgroundImage(): void
|
||||
setBackgroundRenderMode(mode: BackgroundRenderModeType): void
|
||||
handleResize(width: number, height: number): void
|
||||
captureScene(width: number, height: number): Promise<CaptureResult>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user