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

@@ -47,7 +47,8 @@ describe('useLoad3d', () => {
'Scene Config': {
showGrid: true,
backgroundColor: '#000000',
backgroundImage: ''
backgroundImage: '',
backgroundRenderMode: 'tiled'
},
'Model Config': {
upDirection: 'original',
@@ -81,6 +82,7 @@ describe('useLoad3d', () => {
toggleGrid: vi.fn(),
setBackgroundColor: vi.fn(),
setBackgroundImage: vi.fn().mockResolvedValue(undefined),
setBackgroundRenderMode: vi.fn(),
setUpDirection: vi.fn(),
setMaterialMode: vi.fn(),
toggleCamera: vi.fn(),
@@ -130,7 +132,8 @@ describe('useLoad3d', () => {
expect(composable.sceneConfig.value).toEqual({
showGrid: true,
backgroundColor: '#000000',
backgroundImage: ''
backgroundImage: '',
backgroundRenderMode: 'tiled'
})
expect(composable.modelConfig.value).toEqual({
upDirection: 'original',
@@ -165,9 +168,11 @@ describe('useLoad3d', () => {
const containerRef = document.createElement('div')
await composable.initializeLoad3d(containerRef)
await nextTick()
expect(mockLoad3d.toggleGrid).toHaveBeenCalledWith(true)
expect(mockLoad3d.setBackgroundColor).toHaveBeenCalledWith('#000000')
expect(mockLoad3d.setBackgroundRenderMode).toHaveBeenCalledWith('tiled')
expect(mockLoad3d.setUpDirection).toHaveBeenCalledWith('original')
expect(mockLoad3d.setMaterialMode).toHaveBeenCalledWith('original')
expect(mockLoad3d.toggleCamera).toHaveBeenCalledWith('perspective')
@@ -356,17 +361,22 @@ describe('useLoad3d', () => {
composable.sceneConfig.value = {
showGrid: false,
backgroundColor: '#ffffff',
backgroundImage: 'test.jpg'
backgroundImage: 'test.jpg',
backgroundRenderMode: 'panorama'
}
await nextTick()
expect(mockLoad3d.toggleGrid).toHaveBeenCalledWith(false)
expect(mockLoad3d.setBackgroundColor).toHaveBeenCalledWith('#ffffff')
expect(mockLoad3d.setBackgroundImage).toHaveBeenCalledWith('test.jpg')
expect(mockLoad3d.setBackgroundRenderMode).toHaveBeenCalledWith(
'panorama'
)
expect(mockNode.properties['Scene Config']).toEqual({
showGrid: false,
backgroundColor: '#ffffff',
backgroundImage: 'test.jpg'
backgroundImage: 'test.jpg',
backgroundRenderMode: 'panorama'
})
})
@@ -375,6 +385,10 @@ describe('useLoad3d', () => {
const containerRef = document.createElement('div')
await composable.initializeLoad3d(containerRef)
await nextTick()
mockLoad3d.setUpDirection.mockClear()
mockLoad3d.setMaterialMode.mockClear()
composable.modelConfig.value.upDirection = '+y'
composable.modelConfig.value.materialMode = 'wireframe'
@@ -393,6 +407,10 @@ describe('useLoad3d', () => {
const containerRef = document.createElement('div')
await composable.initializeLoad3d(containerRef)
await nextTick()
mockLoad3d.toggleCamera.mockClear()
mockLoad3d.setFOV.mockClear()
composable.cameraConfig.value.cameraType = 'orthographic'
composable.cameraConfig.value.fov = 90
@@ -412,6 +430,9 @@ describe('useLoad3d', () => {
const containerRef = document.createElement('div')
await composable.initializeLoad3d(containerRef)
await nextTick()
mockLoad3d.setLightIntensity.mockClear()
composable.lightConfig.value.intensity = 10
await nextTick()
@@ -652,6 +673,7 @@ describe('useLoad3d', () => {
const expectedEvents = [
'materialModeChange',
'backgroundColorChange',
'backgroundRenderModeChange',
'lightIntensityChange',
'fovChange',
'cameraTypeChange',

View File

@@ -44,7 +44,8 @@ describe('useLoad3dViewer', () => {
'Scene Config': {
backgroundColor: '#282828',
showGrid: true,
backgroundImage: ''
backgroundImage: '',
backgroundRenderMode: 'tiled'
},
'Camera Config': {
cameraType: 'perspective',
@@ -115,6 +116,7 @@ describe('useLoad3dViewer', () => {
materialMode: 'original'
},
setBackgroundImage: vi.fn().mockResolvedValue(undefined),
setBackgroundRenderMode: vi.fn(),
forceRender: vi.fn()
}