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:
Terry Jia
2025-11-11 04:02:12 -05:00
committed by GitHub
parent c94cedf8ee
commit 879cb8f1a8
15 changed files with 310 additions and 84 deletions

View File

@@ -3,6 +3,7 @@ import { ref, toRaw, watch } from 'vue'
import Load3d from '@/extensions/core/load3d/Load3d'
import Load3dUtils from '@/extensions/core/load3d/Load3dUtils'
import type {
BackgroundRenderModeType,
CameraType,
MaterialMode,
UpDirection
@@ -21,6 +22,7 @@ interface Load3dViewerState {
lightIntensity: number
cameraState: any
backgroundImage: string
backgroundRenderMode: BackgroundRenderModeType
upDirection: UpDirection
materialMode: MaterialMode
}
@@ -33,6 +35,7 @@ export const useLoad3dViewer = (node: LGraphNode) => {
const lightIntensity = ref(1)
const backgroundImage = ref('')
const hasBackgroundImage = ref(false)
const backgroundRenderMode = ref<BackgroundRenderModeType>('tiled')
const upDirection = ref<UpDirection>('original')
const materialMode = ref<MaterialMode>('original')
const needApplyChanges = ref(true)
@@ -49,6 +52,7 @@ export const useLoad3dViewer = (node: LGraphNode) => {
lightIntensity: 1,
cameraState: null,
backgroundImage: '',
backgroundRenderMode: 'tiled',
upDirection: 'original',
materialMode: 'original'
})
@@ -124,6 +128,20 @@ export const useLoad3dViewer = (node: LGraphNode) => {
}
})
watch(backgroundRenderMode, (newValue) => {
if (!load3d) return
try {
load3d.setBackgroundRenderMode(newValue)
} catch (error) {
console.error('Error updating background render mode:', error)
useToastStore().addAlert(
t('toastMessages.failedToUpdateBackgroundRenderMode', {
mode: newValue
})
)
}
})
watch(upDirection, (newValue) => {
if (!load3d) return
try {
@@ -180,6 +198,10 @@ export const useLoad3dViewer = (node: LGraphNode) => {
source.sceneManager.currentBackgroundColor
showGrid.value =
sceneConfig.showGrid ?? source.sceneManager.gridHelper.visible
backgroundRenderMode.value =
sceneConfig.backgroundRenderMode ||
source.sceneManager.backgroundRenderMode ||
'tiled'
const backgroundInfo = source.sceneManager.getCurrentBackgroundInfo()
if (backgroundInfo.type === 'image' && sceneConfig.backgroundImage) {
@@ -219,6 +241,7 @@ export const useLoad3dViewer = (node: LGraphNode) => {
lightIntensity: lightIntensity.value,
cameraState: sourceCameraState,
backgroundImage: backgroundImage.value,
backgroundRenderMode: backgroundRenderMode.value,
upDirection: upDirection.value,
materialMode: materialMode.value
}
@@ -274,7 +297,8 @@ export const useLoad3dViewer = (node: LGraphNode) => {
nodeValue.properties['Scene Config'] = {
showGrid: initialState.value.showGrid,
backgroundColor: initialState.value.backgroundColor,
backgroundImage: initialState.value.backgroundImage
backgroundImage: initialState.value.backgroundImage,
backgroundRenderMode: initialState.value.backgroundRenderMode
}
nodeValue.properties['Camera Config'] = {
@@ -309,7 +333,8 @@ export const useLoad3dViewer = (node: LGraphNode) => {
nodeValue.properties['Scene Config'] = {
showGrid: showGrid.value,
backgroundColor: backgroundColor.value,
backgroundImage: backgroundImage.value
backgroundImage: backgroundImage.value,
backgroundRenderMode: backgroundRenderMode.value
}
nodeValue.properties['Camera Config'] = {
@@ -331,6 +356,7 @@ export const useLoad3dViewer = (node: LGraphNode) => {
await useLoad3dService().copyLoad3dState(load3d, sourceLoad3d)
await sourceLoad3d.setBackgroundImage(backgroundImage.value)
sourceLoad3d.setBackgroundRenderMode(backgroundRenderMode.value)
sourceLoad3d.forceRender()
@@ -429,6 +455,7 @@ export const useLoad3dViewer = (node: LGraphNode) => {
lightIntensity,
backgroundImage,
hasBackgroundImage,
backgroundRenderMode,
upDirection,
materialMode,
needApplyChanges,