mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 03:01:54 +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:
@@ -39,6 +39,8 @@
|
|||||||
v-model:show-grid="sceneConfig!.showGrid"
|
v-model:show-grid="sceneConfig!.showGrid"
|
||||||
v-model:background-color="sceneConfig!.backgroundColor"
|
v-model:background-color="sceneConfig!.backgroundColor"
|
||||||
v-model:background-image="sceneConfig!.backgroundImage"
|
v-model:background-image="sceneConfig!.backgroundImage"
|
||||||
|
v-model:background-render-mode="sceneConfig!.backgroundRenderMode"
|
||||||
|
v-model:fov="cameraConfig!.fov"
|
||||||
@update-background-image="handleBackgroundImageUpdate"
|
@update-background-image="handleBackgroundImageUpdate"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
<SceneControls
|
<SceneControls
|
||||||
v-model:background-color="viewer.backgroundColor.value"
|
v-model:background-color="viewer.backgroundColor.value"
|
||||||
v-model:show-grid="viewer.showGrid.value"
|
v-model:show-grid="viewer.showGrid.value"
|
||||||
|
v-model:background-render-mode="viewer.backgroundRenderMode.value"
|
||||||
|
v-model:fov="viewer.fov.value"
|
||||||
:has-background-image="viewer.hasBackgroundImage.value"
|
:has-background-image="viewer.hasBackgroundImage.value"
|
||||||
@update-background-image="viewer.handleBackgroundImageUpdate"
|
@update-background-image="viewer.handleBackgroundImageUpdate"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -6,65 +6,30 @@
|
|||||||
value: $t('load3d.switchCamera'),
|
value: $t('load3d.switchCamera'),
|
||||||
showDelay: 300
|
showDelay: 300
|
||||||
}"
|
}"
|
||||||
:class="['pi', getCameraIcon, 'text-lg text-white']"
|
:class="['pi', 'pi-camera', 'text-lg text-white']"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
<div v-if="showFOVButton" class="show-fov relative">
|
<PopupSlider
|
||||||
<Button class="p-button-rounded p-button-text" @click="toggleFOV">
|
v-if="showFOVButton"
|
||||||
<i
|
v-model="fov"
|
||||||
v-tooltip.right="{ value: $t('load3d.fov'), showDelay: 300 }"
|
:tooltip-text="$t('load3d.fov')"
|
||||||
class="pi pi-expand text-lg text-white"
|
/>
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
<div
|
|
||||||
v-show="showFOV"
|
|
||||||
class="absolute top-0 left-12 rounded-lg bg-black/50 p-4 shadow-lg"
|
|
||||||
style="width: 150px"
|
|
||||||
>
|
|
||||||
<Slider v-model="fov" class="w-full" :min="10" :max="150" :step="1" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Button from 'primevue/button'
|
import Button from 'primevue/button'
|
||||||
import Slider from 'primevue/slider'
|
import { computed } from 'vue'
|
||||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
||||||
|
|
||||||
|
import PopupSlider from '@/components/load3d/controls/PopupSlider.vue'
|
||||||
import type { CameraType } from '@/extensions/core/load3d/interfaces'
|
import type { CameraType } from '@/extensions/core/load3d/interfaces'
|
||||||
|
|
||||||
const showFOV = ref(false)
|
|
||||||
|
|
||||||
const cameraType = defineModel<CameraType>('cameraType')
|
const cameraType = defineModel<CameraType>('cameraType')
|
||||||
const fov = defineModel<number>('fov')
|
const fov = defineModel<number>('fov')
|
||||||
const showFOVButton = computed(() => cameraType.value === 'perspective')
|
const showFOVButton = computed(() => cameraType.value === 'perspective')
|
||||||
const getCameraIcon = computed(() => {
|
|
||||||
return cameraType.value === 'perspective' ? 'pi-camera' : 'pi-camera'
|
|
||||||
})
|
|
||||||
|
|
||||||
const toggleFOV = () => {
|
|
||||||
showFOV.value = !showFOV.value
|
|
||||||
}
|
|
||||||
|
|
||||||
const switchCamera = () => {
|
const switchCamera = () => {
|
||||||
cameraType.value =
|
cameraType.value =
|
||||||
cameraType.value === 'perspective' ? 'orthographic' : 'perspective'
|
cameraType.value === 'perspective' ? 'orthographic' : 'perspective'
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeCameraSlider = (e: MouseEvent) => {
|
|
||||||
const target = e.target as HTMLElement
|
|
||||||
|
|
||||||
if (!target.closest('.show-fov')) {
|
|
||||||
showFOV.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
document.addEventListener('click', closeCameraSlider)
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
document.removeEventListener('click', closeCameraSlider)
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
64
src/components/load3d/controls/PopupSlider.vue
Normal file
64
src/components/load3d/controls/PopupSlider.vue
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div class="relative show-slider">
|
||||||
|
<Button class="p-button-rounded p-button-text" @click="toggleSlider">
|
||||||
|
<i
|
||||||
|
v-tooltip.right="{ value: tooltipText, showDelay: 300 }"
|
||||||
|
:class="['pi', icon, 'text-lg text-white']"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
<div
|
||||||
|
v-show="showSlider"
|
||||||
|
class="absolute top-0 left-12 rounded-lg bg-black/50 p-4 shadow-lg w-[150px]"
|
||||||
|
>
|
||||||
|
<Slider
|
||||||
|
v-model="value"
|
||||||
|
class="w-full"
|
||||||
|
:min="min"
|
||||||
|
:max="max"
|
||||||
|
:step="step"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Button from 'primevue/button'
|
||||||
|
import Slider from 'primevue/slider'
|
||||||
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
|
||||||
|
const {
|
||||||
|
icon = 'pi-expand',
|
||||||
|
min = 10,
|
||||||
|
max = 150,
|
||||||
|
step = 1
|
||||||
|
} = defineProps<{
|
||||||
|
icon?: string
|
||||||
|
tooltipText: string
|
||||||
|
min?: number
|
||||||
|
max?: number
|
||||||
|
step?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const value = defineModel<number>()
|
||||||
|
const showSlider = ref(false)
|
||||||
|
|
||||||
|
const toggleSlider = () => {
|
||||||
|
showSlider.value = !showSlider.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeSlider = (e: MouseEvent) => {
|
||||||
|
const target = e.target as HTMLElement
|
||||||
|
|
||||||
|
if (!target.closest('.show-slider')) {
|
||||||
|
showSlider.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener('click', closeSlider)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.removeEventListener('click', closeSlider)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -51,6 +51,28 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="hasBackgroundImage">
|
||||||
|
<Button
|
||||||
|
class="p-button-rounded p-button-text"
|
||||||
|
:class="{ 'p-button-outlined': backgroundRenderMode === 'panorama' }"
|
||||||
|
@click="toggleBackgroundRenderMode"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
v-tooltip.right="{
|
||||||
|
value: $t('load3d.panoramaMode'),
|
||||||
|
showDelay: 300
|
||||||
|
}"
|
||||||
|
class="pi pi-globe text-lg text-white"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<PopupSlider
|
||||||
|
v-if="hasBackgroundImage && backgroundRenderMode === 'panorama'"
|
||||||
|
v-model="fov"
|
||||||
|
:tooltip-text="$t('load3d.fov')"
|
||||||
|
/>
|
||||||
|
|
||||||
<div v-if="hasBackgroundImage">
|
<div v-if="hasBackgroundImage">
|
||||||
<Button
|
<Button
|
||||||
class="p-button-rounded p-button-text"
|
class="p-button-rounded p-button-text"
|
||||||
@@ -72,6 +94,9 @@
|
|||||||
import Button from 'primevue/button'
|
import Button from 'primevue/button'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
import PopupSlider from '@/components/load3d/controls/PopupSlider.vue'
|
||||||
|
import type { BackgroundRenderModeType } from '@/extensions/core/load3d/interfaces'
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'updateBackgroundImage', file: File | null): void
|
(e: 'updateBackgroundImage', file: File | null): void
|
||||||
}>()
|
}>()
|
||||||
@@ -79,6 +104,11 @@ const emit = defineEmits<{
|
|||||||
const showGrid = defineModel<boolean>('showGrid')
|
const showGrid = defineModel<boolean>('showGrid')
|
||||||
const backgroundColor = defineModel<string>('backgroundColor')
|
const backgroundColor = defineModel<string>('backgroundColor')
|
||||||
const backgroundImage = defineModel<string>('backgroundImage')
|
const backgroundImage = defineModel<string>('backgroundImage')
|
||||||
|
const backgroundRenderMode = defineModel<BackgroundRenderModeType>(
|
||||||
|
'backgroundRenderMode',
|
||||||
|
{ default: 'tiled' }
|
||||||
|
)
|
||||||
|
const fov = defineModel<number>('fov')
|
||||||
const hasBackgroundImage = computed(
|
const hasBackgroundImage = computed(
|
||||||
() => backgroundImage.value && backgroundImage.value !== ''
|
() => backgroundImage.value && backgroundImage.value !== ''
|
||||||
)
|
)
|
||||||
@@ -113,4 +143,9 @@ const uploadBackgroundImage = (event: Event) => {
|
|||||||
const removeBackgroundImage = () => {
|
const removeBackgroundImage = () => {
|
||||||
emit('updateBackgroundImage', null)
|
emit('updateBackgroundImage', null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleBackgroundRenderMode = () => {
|
||||||
|
backgroundRenderMode.value =
|
||||||
|
backgroundRenderMode.value === 'panorama' ? 'tiled' : 'panorama'
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -32,6 +32,24 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="hasBackgroundImage" class="space-y-2">
|
<div v-if="hasBackgroundImage" class="space-y-2">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<Button
|
||||||
|
:severity="backgroundRenderMode === 'tiled' ? 'primary' : 'secondary'"
|
||||||
|
:label="$t('load3d.tiledMode')"
|
||||||
|
icon="pi pi-th-large"
|
||||||
|
class="flex-1"
|
||||||
|
@click="setBackgroundRenderMode('tiled')"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
:severity="
|
||||||
|
backgroundRenderMode === 'panorama' ? 'primary' : 'secondary'
|
||||||
|
"
|
||||||
|
:label="$t('load3d.panoramaMode')"
|
||||||
|
icon="pi pi-globe"
|
||||||
|
class="flex-1"
|
||||||
|
@click="setBackgroundRenderMode('panorama')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Button
|
<Button
|
||||||
severity="secondary"
|
severity="secondary"
|
||||||
:label="$t('load3d.removeBackgroundImage')"
|
:label="$t('load3d.removeBackgroundImage')"
|
||||||
@@ -50,6 +68,9 @@ import { ref } from 'vue'
|
|||||||
|
|
||||||
const backgroundColor = defineModel<string>('backgroundColor')
|
const backgroundColor = defineModel<string>('backgroundColor')
|
||||||
const showGrid = defineModel<boolean>('showGrid')
|
const showGrid = defineModel<boolean>('showGrid')
|
||||||
|
const backgroundRenderMode = defineModel<'tiled' | 'panorama'>(
|
||||||
|
'backgroundRenderMode'
|
||||||
|
)
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
hasBackgroundImage?: boolean
|
hasBackgroundImage?: boolean
|
||||||
@@ -77,4 +98,8 @@ const handleImageUpload = (event: Event) => {
|
|||||||
const removeBackgroundImage = () => {
|
const removeBackgroundImage = () => {
|
||||||
emit('updateBackgroundImage', null)
|
emit('updateBackgroundImage', null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setBackgroundRenderMode = (mode: 'tiled' | 'panorama') => {
|
||||||
|
backgroundRenderMode.value = mode
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ export const useLoad3d = (nodeOrRef: MaybeRef<LGraphNode | null>) => {
|
|||||||
const sceneConfig = ref<SceneConfig>({
|
const sceneConfig = ref<SceneConfig>({
|
||||||
showGrid: true,
|
showGrid: true,
|
||||||
backgroundColor: '#000000',
|
backgroundColor: '#000000',
|
||||||
backgroundImage: ''
|
backgroundImage: '',
|
||||||
|
backgroundRenderMode: 'tiled'
|
||||||
})
|
})
|
||||||
|
|
||||||
const modelConfig = ref<ModelConfig>({
|
const modelConfig = ref<ModelConfig>({
|
||||||
@@ -131,7 +132,11 @@ export const useLoad3d = (nodeOrRef: MaybeRef<LGraphNode | null>) => {
|
|||||||
// Restore configs - watchers will handle applying them to the Three.js scene
|
// Restore configs - watchers will handle applying them to the Three.js scene
|
||||||
const savedSceneConfig = node.properties['Scene Config'] as SceneConfig
|
const savedSceneConfig = node.properties['Scene Config'] as SceneConfig
|
||||||
if (savedSceneConfig) {
|
if (savedSceneConfig) {
|
||||||
sceneConfig.value = savedSceneConfig
|
sceneConfig.value = {
|
||||||
|
...sceneConfig.value,
|
||||||
|
...savedSceneConfig,
|
||||||
|
backgroundRenderMode: savedSceneConfig.backgroundRenderMode || 'tiled'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const savedModelConfig = node.properties['Model Config'] as ModelConfig
|
const savedModelConfig = node.properties['Model Config'] as ModelConfig
|
||||||
@@ -221,12 +226,17 @@ export const useLoad3d = (nodeOrRef: MaybeRef<LGraphNode | null>) => {
|
|||||||
|
|
||||||
watch(
|
watch(
|
||||||
sceneConfig,
|
sceneConfig,
|
||||||
(newValue) => {
|
async (newValue) => {
|
||||||
if (load3d && nodeRef.value) {
|
if (load3d && nodeRef.value) {
|
||||||
nodeRef.value.properties['Scene Config'] = newValue
|
nodeRef.value.properties['Scene Config'] = newValue
|
||||||
load3d.toggleGrid(newValue.showGrid)
|
load3d.toggleGrid(newValue.showGrid)
|
||||||
load3d.setBackgroundColor(newValue.backgroundColor)
|
load3d.setBackgroundColor(newValue.backgroundColor)
|
||||||
void load3d.setBackgroundImage(newValue.backgroundImage || '')
|
|
||||||
|
await load3d.setBackgroundImage(newValue.backgroundImage || '')
|
||||||
|
|
||||||
|
if (newValue.backgroundRenderMode) {
|
||||||
|
load3d.setBackgroundRenderMode(newValue.backgroundRenderMode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
@@ -424,6 +434,9 @@ export const useLoad3d = (nodeOrRef: MaybeRef<LGraphNode | null>) => {
|
|||||||
backgroundColorChange: (value: string) => {
|
backgroundColorChange: (value: string) => {
|
||||||
sceneConfig.value.backgroundColor = value
|
sceneConfig.value.backgroundColor = value
|
||||||
},
|
},
|
||||||
|
backgroundRenderModeChange: (value: string) => {
|
||||||
|
sceneConfig.value.backgroundRenderMode = value as 'tiled' | 'panorama'
|
||||||
|
},
|
||||||
lightIntensityChange: (value: number) => {
|
lightIntensityChange: (value: number) => {
|
||||||
lightConfig.value.intensity = value
|
lightConfig.value.intensity = value
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { ref, toRaw, watch } from 'vue'
|
|||||||
import Load3d from '@/extensions/core/load3d/Load3d'
|
import Load3d from '@/extensions/core/load3d/Load3d'
|
||||||
import Load3dUtils from '@/extensions/core/load3d/Load3dUtils'
|
import Load3dUtils from '@/extensions/core/load3d/Load3dUtils'
|
||||||
import type {
|
import type {
|
||||||
|
BackgroundRenderModeType,
|
||||||
CameraType,
|
CameraType,
|
||||||
MaterialMode,
|
MaterialMode,
|
||||||
UpDirection
|
UpDirection
|
||||||
@@ -21,6 +22,7 @@ interface Load3dViewerState {
|
|||||||
lightIntensity: number
|
lightIntensity: number
|
||||||
cameraState: any
|
cameraState: any
|
||||||
backgroundImage: string
|
backgroundImage: string
|
||||||
|
backgroundRenderMode: BackgroundRenderModeType
|
||||||
upDirection: UpDirection
|
upDirection: UpDirection
|
||||||
materialMode: MaterialMode
|
materialMode: MaterialMode
|
||||||
}
|
}
|
||||||
@@ -33,6 +35,7 @@ export const useLoad3dViewer = (node: LGraphNode) => {
|
|||||||
const lightIntensity = ref(1)
|
const lightIntensity = ref(1)
|
||||||
const backgroundImage = ref('')
|
const backgroundImage = ref('')
|
||||||
const hasBackgroundImage = ref(false)
|
const hasBackgroundImage = ref(false)
|
||||||
|
const backgroundRenderMode = ref<BackgroundRenderModeType>('tiled')
|
||||||
const upDirection = ref<UpDirection>('original')
|
const upDirection = ref<UpDirection>('original')
|
||||||
const materialMode = ref<MaterialMode>('original')
|
const materialMode = ref<MaterialMode>('original')
|
||||||
const needApplyChanges = ref(true)
|
const needApplyChanges = ref(true)
|
||||||
@@ -49,6 +52,7 @@ export const useLoad3dViewer = (node: LGraphNode) => {
|
|||||||
lightIntensity: 1,
|
lightIntensity: 1,
|
||||||
cameraState: null,
|
cameraState: null,
|
||||||
backgroundImage: '',
|
backgroundImage: '',
|
||||||
|
backgroundRenderMode: 'tiled',
|
||||||
upDirection: 'original',
|
upDirection: 'original',
|
||||||
materialMode: '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) => {
|
watch(upDirection, (newValue) => {
|
||||||
if (!load3d) return
|
if (!load3d) return
|
||||||
try {
|
try {
|
||||||
@@ -180,6 +198,10 @@ export const useLoad3dViewer = (node: LGraphNode) => {
|
|||||||
source.sceneManager.currentBackgroundColor
|
source.sceneManager.currentBackgroundColor
|
||||||
showGrid.value =
|
showGrid.value =
|
||||||
sceneConfig.showGrid ?? source.sceneManager.gridHelper.visible
|
sceneConfig.showGrid ?? source.sceneManager.gridHelper.visible
|
||||||
|
backgroundRenderMode.value =
|
||||||
|
sceneConfig.backgroundRenderMode ||
|
||||||
|
source.sceneManager.backgroundRenderMode ||
|
||||||
|
'tiled'
|
||||||
|
|
||||||
const backgroundInfo = source.sceneManager.getCurrentBackgroundInfo()
|
const backgroundInfo = source.sceneManager.getCurrentBackgroundInfo()
|
||||||
if (backgroundInfo.type === 'image' && sceneConfig.backgroundImage) {
|
if (backgroundInfo.type === 'image' && sceneConfig.backgroundImage) {
|
||||||
@@ -219,6 +241,7 @@ export const useLoad3dViewer = (node: LGraphNode) => {
|
|||||||
lightIntensity: lightIntensity.value,
|
lightIntensity: lightIntensity.value,
|
||||||
cameraState: sourceCameraState,
|
cameraState: sourceCameraState,
|
||||||
backgroundImage: backgroundImage.value,
|
backgroundImage: backgroundImage.value,
|
||||||
|
backgroundRenderMode: backgroundRenderMode.value,
|
||||||
upDirection: upDirection.value,
|
upDirection: upDirection.value,
|
||||||
materialMode: materialMode.value
|
materialMode: materialMode.value
|
||||||
}
|
}
|
||||||
@@ -274,7 +297,8 @@ export const useLoad3dViewer = (node: LGraphNode) => {
|
|||||||
nodeValue.properties['Scene Config'] = {
|
nodeValue.properties['Scene Config'] = {
|
||||||
showGrid: initialState.value.showGrid,
|
showGrid: initialState.value.showGrid,
|
||||||
backgroundColor: initialState.value.backgroundColor,
|
backgroundColor: initialState.value.backgroundColor,
|
||||||
backgroundImage: initialState.value.backgroundImage
|
backgroundImage: initialState.value.backgroundImage,
|
||||||
|
backgroundRenderMode: initialState.value.backgroundRenderMode
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeValue.properties['Camera Config'] = {
|
nodeValue.properties['Camera Config'] = {
|
||||||
@@ -309,7 +333,8 @@ export const useLoad3dViewer = (node: LGraphNode) => {
|
|||||||
nodeValue.properties['Scene Config'] = {
|
nodeValue.properties['Scene Config'] = {
|
||||||
showGrid: showGrid.value,
|
showGrid: showGrid.value,
|
||||||
backgroundColor: backgroundColor.value,
|
backgroundColor: backgroundColor.value,
|
||||||
backgroundImage: backgroundImage.value
|
backgroundImage: backgroundImage.value,
|
||||||
|
backgroundRenderMode: backgroundRenderMode.value
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeValue.properties['Camera Config'] = {
|
nodeValue.properties['Camera Config'] = {
|
||||||
@@ -331,6 +356,7 @@ export const useLoad3dViewer = (node: LGraphNode) => {
|
|||||||
await useLoad3dService().copyLoad3dState(load3d, sourceLoad3d)
|
await useLoad3dService().copyLoad3dState(load3d, sourceLoad3d)
|
||||||
|
|
||||||
await sourceLoad3d.setBackgroundImage(backgroundImage.value)
|
await sourceLoad3d.setBackgroundImage(backgroundImage.value)
|
||||||
|
sourceLoad3d.setBackgroundRenderMode(backgroundRenderMode.value)
|
||||||
|
|
||||||
sourceLoad3d.forceRender()
|
sourceLoad3d.forceRender()
|
||||||
|
|
||||||
@@ -429,6 +455,7 @@ export const useLoad3dViewer = (node: LGraphNode) => {
|
|||||||
lightIntensity,
|
lightIntensity,
|
||||||
backgroundImage,
|
backgroundImage,
|
||||||
hasBackgroundImage,
|
hasBackgroundImage,
|
||||||
|
backgroundRenderMode,
|
||||||
upDirection,
|
upDirection,
|
||||||
materialMode,
|
materialMode,
|
||||||
needApplyChanges,
|
needApplyChanges,
|
||||||
|
|||||||
@@ -162,7 +162,11 @@ class Load3DConfiguration {
|
|||||||
return
|
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()
|
this.forceRender()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setBackgroundRenderMode(mode: 'tiled' | 'panorama'): void {
|
||||||
|
this.sceneManager.setBackgroundRenderMode(mode)
|
||||||
|
this.forceRender()
|
||||||
|
}
|
||||||
|
|
||||||
toggleCamera(cameraType?: 'perspective' | 'orthographic'): void {
|
toggleCamera(cameraType?: 'perspective' | 'orthographic'): void {
|
||||||
this.cameraManager.toggleCamera(cameraType)
|
this.cameraManager.toggleCamera(cameraType)
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
|
|||||||
|
|
||||||
import Load3dUtils from './Load3dUtils'
|
import Load3dUtils from './Load3dUtils'
|
||||||
import {
|
import {
|
||||||
|
type BackgroundRenderModeType,
|
||||||
type EventManagerInterface,
|
type EventManagerInterface,
|
||||||
type SceneManagerInterface
|
type SceneManagerInterface
|
||||||
} from './interfaces'
|
} from './interfaces'
|
||||||
@@ -16,6 +17,8 @@ export class SceneManager implements SceneManagerInterface {
|
|||||||
backgroundMesh: THREE.Mesh | null = null
|
backgroundMesh: THREE.Mesh | null = null
|
||||||
backgroundTexture: THREE.Texture | null = null
|
backgroundTexture: THREE.Texture | null = null
|
||||||
|
|
||||||
|
backgroundRenderMode: 'tiled' | 'panorama' = 'tiled'
|
||||||
|
|
||||||
backgroundColorMaterial: THREE.MeshBasicMaterial | null = null
|
backgroundColorMaterial: THREE.MeshBasicMaterial | null = null
|
||||||
currentBackgroundType: 'color' | 'image' = 'color'
|
currentBackgroundType: 'color' | 'image' = 'color'
|
||||||
currentBackgroundColor: string = '#282828'
|
currentBackgroundColor: string = '#282828'
|
||||||
@@ -89,6 +92,10 @@ export class SceneManager implements SceneManagerInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.scene.background) {
|
||||||
|
this.scene.background = null
|
||||||
|
}
|
||||||
|
|
||||||
this.scene.clear()
|
this.scene.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +111,15 @@ export class SceneManager implements SceneManagerInterface {
|
|||||||
this.currentBackgroundColor = color
|
this.currentBackgroundColor = color
|
||||||
this.currentBackgroundType = '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) {
|
if (!this.backgroundMesh || !this.backgroundColorMaterial) {
|
||||||
this.initBackgroundScene()
|
this.initBackgroundScene()
|
||||||
}
|
}
|
||||||
@@ -168,36 +184,41 @@ export class SceneManager implements SceneManagerInterface {
|
|||||||
this.backgroundTexture = texture
|
this.backgroundTexture = texture
|
||||||
this.currentBackgroundType = 'image'
|
this.currentBackgroundType = 'image'
|
||||||
|
|
||||||
if (!this.backgroundMesh) {
|
if (this.backgroundRenderMode === 'panorama') {
|
||||||
this.initBackgroundScene()
|
texture.mapping = THREE.EquirectangularReflectionMapping
|
||||||
}
|
this.scene.background = texture
|
||||||
|
} else {
|
||||||
const imageMaterial = new THREE.MeshBasicMaterial({
|
if (!this.backgroundMesh) {
|
||||||
map: texture,
|
this.initBackgroundScene()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.backgroundMesh.material = imageMaterial
|
const imageMaterial = new THREE.MeshBasicMaterial({
|
||||||
this.backgroundMesh.position.set(0, 0, 0)
|
map: texture,
|
||||||
}
|
transparent: true,
|
||||||
|
depthWrite: false,
|
||||||
|
depthTest: false,
|
||||||
|
side: THREE.DoubleSide
|
||||||
|
})
|
||||||
|
|
||||||
this.updateBackgroundSize(
|
if (this.backgroundMesh) {
|
||||||
this.backgroundTexture,
|
if (
|
||||||
this.backgroundMesh,
|
this.backgroundMesh.material !== this.backgroundColorMaterial &&
|
||||||
this.renderer.domElement.clientWidth,
|
this.backgroundMesh.material instanceof THREE.Material
|
||||||
this.renderer.domElement.clientHeight
|
) {
|
||||||
)
|
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('backgroundImageChange', uploadPath)
|
||||||
this.eventManager.emitEvent('backgroundImageLoadingEnd', null)
|
this.eventManager.emitEvent('backgroundImageLoadingEnd', null)
|
||||||
@@ -213,6 +234,35 @@ export class SceneManager implements SceneManagerInterface {
|
|||||||
this.eventManager.emitEvent('backgroundImageLoadingEnd', null)
|
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(
|
updateBackgroundSize(
|
||||||
backgroundTexture: THREE.Texture | null,
|
backgroundTexture: THREE.Texture | null,
|
||||||
backgroundMesh: THREE.Mesh | null,
|
backgroundMesh: THREE.Mesh | null,
|
||||||
@@ -254,7 +304,11 @@ export class SceneManager implements SceneManagerInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderBackground(): void {
|
renderBackground(): void {
|
||||||
if (this.backgroundMesh) {
|
if (
|
||||||
|
(this.backgroundRenderMode === 'tiled' ||
|
||||||
|
this.currentBackgroundType === 'color') &&
|
||||||
|
this.backgroundMesh
|
||||||
|
) {
|
||||||
const currentToneMapping = this.renderer.toneMapping
|
const currentToneMapping = this.renderer.toneMapping
|
||||||
const currentExposure = this.renderer.toneMappingExposure
|
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 MaterialMode = 'original' | 'normal' | 'wireframe' | 'depth'
|
||||||
export type UpDirection = 'original' | '-x' | '+x' | '-y' | '+y' | '-z' | '+z'
|
export type UpDirection = 'original' | '-x' | '+x' | '-y' | '+y' | '-z' | '+z'
|
||||||
export type CameraType = 'perspective' | 'orthographic'
|
export type CameraType = 'perspective' | 'orthographic'
|
||||||
|
export type BackgroundRenderModeType = 'tiled' | 'panorama'
|
||||||
|
|
||||||
export interface CameraState {
|
export interface CameraState {
|
||||||
position: THREE.Vector3
|
position: THREE.Vector3
|
||||||
@@ -25,6 +26,7 @@ export interface SceneConfig {
|
|||||||
showGrid: boolean
|
showGrid: boolean
|
||||||
backgroundColor: string
|
backgroundColor: string
|
||||||
backgroundImage?: string
|
backgroundImage?: string
|
||||||
|
backgroundRenderMode?: BackgroundRenderModeType
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModelConfig {
|
export interface ModelConfig {
|
||||||
@@ -77,6 +79,7 @@ export interface SceneManagerInterface extends BaseManager {
|
|||||||
setBackgroundColor(color: string): void
|
setBackgroundColor(color: string): void
|
||||||
setBackgroundImage(uploadPath: string): Promise<void>
|
setBackgroundImage(uploadPath: string): Promise<void>
|
||||||
removeBackgroundImage(): void
|
removeBackgroundImage(): void
|
||||||
|
setBackgroundRenderMode(mode: BackgroundRenderModeType): void
|
||||||
handleResize(width: number, height: number): void
|
handleResize(width: number, height: number): void
|
||||||
captureScene(width: number, height: number): Promise<CaptureResult>
|
captureScene(width: number, height: number): Promise<CaptureResult>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1737,6 +1737,8 @@
|
|||||||
"previewOutput": "Preview Output",
|
"previewOutput": "Preview Output",
|
||||||
"uploadBackgroundImage": "Upload Background Image",
|
"uploadBackgroundImage": "Upload Background Image",
|
||||||
"removeBackgroundImage": "Remove Background Image",
|
"removeBackgroundImage": "Remove Background Image",
|
||||||
|
"tiledMode": "Tiled",
|
||||||
|
"panoramaMode": "Panorama",
|
||||||
"loadingModel": "Loading 3D Model...",
|
"loadingModel": "Loading 3D Model...",
|
||||||
"upDirection": "Up Direction",
|
"upDirection": "Up Direction",
|
||||||
"materialMode": "Material Mode",
|
"materialMode": "Material Mode",
|
||||||
@@ -1833,7 +1835,8 @@
|
|||||||
"failedToInitializeLoad3dViewer": "Failed to initialize 3D Viewer",
|
"failedToInitializeLoad3dViewer": "Failed to initialize 3D Viewer",
|
||||||
"failedToLoadBackgroundImage": "Failed to load background image",
|
"failedToLoadBackgroundImage": "Failed to load background image",
|
||||||
"failedToLoadModel": "Failed to load 3D model",
|
"failedToLoadModel": "Failed to load 3D model",
|
||||||
"modelLoadedSuccessfully": "3D model loaded successfully"
|
"modelLoadedSuccessfully": "3D model loaded successfully",
|
||||||
|
"failedToUpdateBackgroundRenderMode": "Failed to update background render mode to {mode}"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"apiKey": {
|
"apiKey": {
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ describe('useLoad3d', () => {
|
|||||||
'Scene Config': {
|
'Scene Config': {
|
||||||
showGrid: true,
|
showGrid: true,
|
||||||
backgroundColor: '#000000',
|
backgroundColor: '#000000',
|
||||||
backgroundImage: ''
|
backgroundImage: '',
|
||||||
|
backgroundRenderMode: 'tiled'
|
||||||
},
|
},
|
||||||
'Model Config': {
|
'Model Config': {
|
||||||
upDirection: 'original',
|
upDirection: 'original',
|
||||||
@@ -81,6 +82,7 @@ describe('useLoad3d', () => {
|
|||||||
toggleGrid: vi.fn(),
|
toggleGrid: vi.fn(),
|
||||||
setBackgroundColor: vi.fn(),
|
setBackgroundColor: vi.fn(),
|
||||||
setBackgroundImage: vi.fn().mockResolvedValue(undefined),
|
setBackgroundImage: vi.fn().mockResolvedValue(undefined),
|
||||||
|
setBackgroundRenderMode: vi.fn(),
|
||||||
setUpDirection: vi.fn(),
|
setUpDirection: vi.fn(),
|
||||||
setMaterialMode: vi.fn(),
|
setMaterialMode: vi.fn(),
|
||||||
toggleCamera: vi.fn(),
|
toggleCamera: vi.fn(),
|
||||||
@@ -130,7 +132,8 @@ describe('useLoad3d', () => {
|
|||||||
expect(composable.sceneConfig.value).toEqual({
|
expect(composable.sceneConfig.value).toEqual({
|
||||||
showGrid: true,
|
showGrid: true,
|
||||||
backgroundColor: '#000000',
|
backgroundColor: '#000000',
|
||||||
backgroundImage: ''
|
backgroundImage: '',
|
||||||
|
backgroundRenderMode: 'tiled'
|
||||||
})
|
})
|
||||||
expect(composable.modelConfig.value).toEqual({
|
expect(composable.modelConfig.value).toEqual({
|
||||||
upDirection: 'original',
|
upDirection: 'original',
|
||||||
@@ -165,9 +168,11 @@ describe('useLoad3d', () => {
|
|||||||
const containerRef = document.createElement('div')
|
const containerRef = document.createElement('div')
|
||||||
|
|
||||||
await composable.initializeLoad3d(containerRef)
|
await composable.initializeLoad3d(containerRef)
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
expect(mockLoad3d.toggleGrid).toHaveBeenCalledWith(true)
|
expect(mockLoad3d.toggleGrid).toHaveBeenCalledWith(true)
|
||||||
expect(mockLoad3d.setBackgroundColor).toHaveBeenCalledWith('#000000')
|
expect(mockLoad3d.setBackgroundColor).toHaveBeenCalledWith('#000000')
|
||||||
|
expect(mockLoad3d.setBackgroundRenderMode).toHaveBeenCalledWith('tiled')
|
||||||
expect(mockLoad3d.setUpDirection).toHaveBeenCalledWith('original')
|
expect(mockLoad3d.setUpDirection).toHaveBeenCalledWith('original')
|
||||||
expect(mockLoad3d.setMaterialMode).toHaveBeenCalledWith('original')
|
expect(mockLoad3d.setMaterialMode).toHaveBeenCalledWith('original')
|
||||||
expect(mockLoad3d.toggleCamera).toHaveBeenCalledWith('perspective')
|
expect(mockLoad3d.toggleCamera).toHaveBeenCalledWith('perspective')
|
||||||
@@ -356,17 +361,22 @@ describe('useLoad3d', () => {
|
|||||||
composable.sceneConfig.value = {
|
composable.sceneConfig.value = {
|
||||||
showGrid: false,
|
showGrid: false,
|
||||||
backgroundColor: '#ffffff',
|
backgroundColor: '#ffffff',
|
||||||
backgroundImage: 'test.jpg'
|
backgroundImage: 'test.jpg',
|
||||||
|
backgroundRenderMode: 'panorama'
|
||||||
}
|
}
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
|
||||||
expect(mockLoad3d.toggleGrid).toHaveBeenCalledWith(false)
|
expect(mockLoad3d.toggleGrid).toHaveBeenCalledWith(false)
|
||||||
expect(mockLoad3d.setBackgroundColor).toHaveBeenCalledWith('#ffffff')
|
expect(mockLoad3d.setBackgroundColor).toHaveBeenCalledWith('#ffffff')
|
||||||
expect(mockLoad3d.setBackgroundImage).toHaveBeenCalledWith('test.jpg')
|
expect(mockLoad3d.setBackgroundImage).toHaveBeenCalledWith('test.jpg')
|
||||||
|
expect(mockLoad3d.setBackgroundRenderMode).toHaveBeenCalledWith(
|
||||||
|
'panorama'
|
||||||
|
)
|
||||||
expect(mockNode.properties['Scene Config']).toEqual({
|
expect(mockNode.properties['Scene Config']).toEqual({
|
||||||
showGrid: false,
|
showGrid: false,
|
||||||
backgroundColor: '#ffffff',
|
backgroundColor: '#ffffff',
|
||||||
backgroundImage: 'test.jpg'
|
backgroundImage: 'test.jpg',
|
||||||
|
backgroundRenderMode: 'panorama'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -375,6 +385,10 @@ describe('useLoad3d', () => {
|
|||||||
const containerRef = document.createElement('div')
|
const containerRef = document.createElement('div')
|
||||||
|
|
||||||
await composable.initializeLoad3d(containerRef)
|
await composable.initializeLoad3d(containerRef)
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
mockLoad3d.setUpDirection.mockClear()
|
||||||
|
mockLoad3d.setMaterialMode.mockClear()
|
||||||
|
|
||||||
composable.modelConfig.value.upDirection = '+y'
|
composable.modelConfig.value.upDirection = '+y'
|
||||||
composable.modelConfig.value.materialMode = 'wireframe'
|
composable.modelConfig.value.materialMode = 'wireframe'
|
||||||
@@ -393,6 +407,10 @@ describe('useLoad3d', () => {
|
|||||||
const containerRef = document.createElement('div')
|
const containerRef = document.createElement('div')
|
||||||
|
|
||||||
await composable.initializeLoad3d(containerRef)
|
await composable.initializeLoad3d(containerRef)
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
mockLoad3d.toggleCamera.mockClear()
|
||||||
|
mockLoad3d.setFOV.mockClear()
|
||||||
|
|
||||||
composable.cameraConfig.value.cameraType = 'orthographic'
|
composable.cameraConfig.value.cameraType = 'orthographic'
|
||||||
composable.cameraConfig.value.fov = 90
|
composable.cameraConfig.value.fov = 90
|
||||||
@@ -412,6 +430,9 @@ describe('useLoad3d', () => {
|
|||||||
const containerRef = document.createElement('div')
|
const containerRef = document.createElement('div')
|
||||||
|
|
||||||
await composable.initializeLoad3d(containerRef)
|
await composable.initializeLoad3d(containerRef)
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
mockLoad3d.setLightIntensity.mockClear()
|
||||||
|
|
||||||
composable.lightConfig.value.intensity = 10
|
composable.lightConfig.value.intensity = 10
|
||||||
await nextTick()
|
await nextTick()
|
||||||
@@ -652,6 +673,7 @@ describe('useLoad3d', () => {
|
|||||||
const expectedEvents = [
|
const expectedEvents = [
|
||||||
'materialModeChange',
|
'materialModeChange',
|
||||||
'backgroundColorChange',
|
'backgroundColorChange',
|
||||||
|
'backgroundRenderModeChange',
|
||||||
'lightIntensityChange',
|
'lightIntensityChange',
|
||||||
'fovChange',
|
'fovChange',
|
||||||
'cameraTypeChange',
|
'cameraTypeChange',
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ describe('useLoad3dViewer', () => {
|
|||||||
'Scene Config': {
|
'Scene Config': {
|
||||||
backgroundColor: '#282828',
|
backgroundColor: '#282828',
|
||||||
showGrid: true,
|
showGrid: true,
|
||||||
backgroundImage: ''
|
backgroundImage: '',
|
||||||
|
backgroundRenderMode: 'tiled'
|
||||||
},
|
},
|
||||||
'Camera Config': {
|
'Camera Config': {
|
||||||
cameraType: 'perspective',
|
cameraType: 'perspective',
|
||||||
@@ -115,6 +116,7 @@ describe('useLoad3dViewer', () => {
|
|||||||
materialMode: 'original'
|
materialMode: 'original'
|
||||||
},
|
},
|
||||||
setBackgroundImage: vi.fn().mockResolvedValue(undefined),
|
setBackgroundImage: vi.fn().mockResolvedValue(undefined),
|
||||||
|
setBackgroundRenderMode: vi.fn(),
|
||||||
forceRender: vi.fn()
|
forceRender: vi.fn()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user