diff --git a/react-components/src/components/SceneContainer/Queries.tsx b/react-components/src/components/SceneContainer/Queries.tsx index e94d2ea068..d935624a4c 100644 --- a/react-components/src/components/SceneContainer/Queries.tsx +++ b/react-components/src/components/SceneContainer/Queries.tsx @@ -112,15 +112,7 @@ export function createGetSceneQuery(sceneExternalId: string, sceneSpaceId: strin externalId: 'SceneConfiguration', version: 'v1' }, - properties: [ - 'name', - 'cameraTranslationX', - 'cameraTranslationY', - 'cameraTranslationZ', - 'cameraEulerRotationX', - 'cameraEulerRotationY', - 'cameraEulerRotationZ' - ] + properties: ['*'] } ] }, diff --git a/react-components/src/components/SceneContainer/SceneTypes.ts b/react-components/src/components/SceneContainer/SceneTypes.ts index fd0815a7b9..e223f80e12 100644 --- a/react-components/src/components/SceneContainer/SceneTypes.ts +++ b/react-components/src/components/SceneContainer/SceneTypes.ts @@ -20,6 +20,9 @@ export type SceneConfiguration = { cameraEulerRotationX: number; cameraEulerRotationY: number; cameraEulerRotationZ: number; + cameraTargetX?: number; + cameraTargetY?: number; + cameraTargetZ?: number; }; export type CadOrPointCloudModel = Transformation3d & { diff --git a/react-components/src/hooks/types.ts b/react-components/src/hooks/types.ts index d4fbbda857..8248422cae 100644 --- a/react-components/src/hooks/types.ts +++ b/react-components/src/hooks/types.ts @@ -69,6 +69,9 @@ export type SceneConfigurationProperties = { cameraEulerRotationX: number; cameraEulerRotationY: number; cameraEulerRotationZ: number; + cameraTargetX?: number; + cameraTargetY?: number; + cameraTargetZ?: number; }; export type SkyboxProperties = { diff --git a/react-components/src/hooks/useSceneConfig.ts b/react-components/src/hooks/useSceneConfig.ts index af692c9e17..f10f1c6df7 100644 --- a/react-components/src/hooks/useSceneConfig.ts +++ b/react-components/src/hooks/useSceneConfig.ts @@ -70,7 +70,10 @@ export const useSceneConfig = ( cameraTranslationZ: SceneConfigurationProperties.cameraTranslationZ, cameraEulerRotationX: SceneConfigurationProperties.cameraEulerRotationX, cameraEulerRotationY: SceneConfigurationProperties.cameraEulerRotationY, - cameraEulerRotationZ: SceneConfigurationProperties.cameraEulerRotationZ + cameraEulerRotationZ: SceneConfigurationProperties.cameraEulerRotationZ, + cameraTargetX: SceneConfigurationProperties.cameraTargetX, + cameraTargetY: SceneConfigurationProperties.cameraTargetY, + cameraTargetZ: SceneConfigurationProperties.cameraTargetZ }, skybox: getSkybox(sceneResponse), groundPlanes: getGroundPlanes(sceneResponse), diff --git a/react-components/src/hooks/useSceneDefaultCamera.tsx b/react-components/src/hooks/useSceneDefaultCamera.tsx index 9fa7a30f92..763288aeab 100644 --- a/react-components/src/hooks/useSceneDefaultCamera.tsx +++ b/react-components/src/hooks/useSceneDefaultCamera.tsx @@ -6,7 +6,8 @@ import { useMemo } from 'react'; import { useSceneConfig } from './useSceneConfig'; import { Vector3, Quaternion, Euler, MathUtils, Box3 } from 'three'; import { useReveal } from '..'; -import { CDF_TO_VIEWER_TRANSFORMATION } from '@cognite/reveal'; +import { CDF_TO_VIEWER_TRANSFORMATION, type Cognite3DViewer } from '@cognite/reveal'; +import { type SceneConfiguration } from '../components/SceneContainer/SceneTypes'; export const useSceneDefaultCamera = ( sceneExternalId: string, @@ -26,15 +27,36 @@ export const useSceneDefaultCamera = ( data.sceneConfiguration.cameraTranslationZ ); + const target = extractCameraTarget(data.sceneConfiguration, viewer); + position.applyMatrix4(CDF_TO_VIEWER_TRANSFORMATION); + target.applyMatrix4(CDF_TO_VIEWER_TRANSFORMATION); + + return { + fitCameraToSceneDefault: () => { + viewer.cameraManager.setCameraState({ position, target }); + } + }; + }, [viewer, data?.sceneConfiguration]); +}; + +function extractCameraTarget(scene: SceneConfiguration, viewer: Cognite3DViewer): Vector3 { + if (scene.cameraTargetX !== undefined) { + return new Vector3(scene.cameraTargetX, scene.cameraTargetY, scene.cameraTargetZ); + } else { const rotation = new Quaternion().setFromEuler( new Euler( - MathUtils.degToRad(data.sceneConfiguration.cameraEulerRotationX), - MathUtils.degToRad(data.sceneConfiguration.cameraEulerRotationY), - MathUtils.degToRad(data.sceneConfiguration.cameraEulerRotationZ), + MathUtils.degToRad(scene.cameraEulerRotationX), + MathUtils.degToRad(scene.cameraEulerRotationY), + MathUtils.degToRad(scene.cameraEulerRotationZ), 'XYZ' ) ); + const position = new Vector3( + scene.cameraTranslationX, + scene.cameraTranslationY, + scene.cameraTranslationZ + ); // As a heuristic, use distance to center of all models' bounding // boxes as target distance const positionToSceneCenterDistance = position.distanceTo( @@ -42,17 +64,8 @@ export const useSceneDefaultCamera = ( .reduce((acc, m) => acc.union(m.getModelBoundingBox()), new Box3()) .getCenter(new Vector3()) ); - const target = position + return position .clone() .add(new Vector3(0, 0, -positionToSceneCenterDistance).applyQuaternion(rotation)); - - position.applyMatrix4(CDF_TO_VIEWER_TRANSFORMATION); - target.applyMatrix4(CDF_TO_VIEWER_TRANSFORMATION); - - return { - fitCameraToSceneDefault: () => { - viewer.cameraManager.setCameraState({ position, target }); - } - }; - }, [data, viewer]); -}; + } +} diff --git a/react-components/stories/SceneContainer.stories.tsx b/react-components/stories/SceneContainer.stories.tsx index 3e7d66f763..3040a32aa8 100644 --- a/react-components/stories/SceneContainer.stories.tsx +++ b/react-components/stories/SceneContainer.stories.tsx @@ -46,13 +46,14 @@ export const Main: Story = { +