From 10eac1ad551f337bcaf56224ff260c05638f5df6 Mon Sep 17 00:00:00 2001 From: Aleksei Ustinov Date: Tue, 17 Sep 2024 17:08:24 +0300 Subject: [PATCH] fix: camera controls supports multiple visage instances --- .../Scene/CameraControls.component.tsx | 99 ++++++++++--------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/src/components/Scene/CameraControls.component.tsx b/src/components/Scene/CameraControls.component.tsx index 959e70db..bc4ceca3 100644 --- a/src/components/Scene/CameraControls.component.tsx +++ b/src/components/Scene/CameraControls.component.tsx @@ -1,4 +1,5 @@ -import { useEffect, FC, useRef } from 'react'; +import React, { FC, useEffect, useRef } from 'react'; +import { OrbitControls as OrbitControlsComponent } from '@react-three/drei'; import { useFrame, useThree } from '@react-three/fiber'; import { Camera, Vector3 } from 'three'; import { OrbitControls } from 'three-stdlib'; @@ -22,18 +23,13 @@ type CameraControlsProps = { updateCameraTargetOnZoom?: boolean; }; -let controls: any; -let progress = Number.POSITIVE_INFINITY; - -const updateCameraFocus = (camera: Camera, delta: number, target?: Vector3) => { - if (target && progress <= 1) { - camera.position.setX(lerp(camera.position.x, target.x, progress)); - camera.position.setZ(lerp(camera.position.z, target.z, progress)); - progress += delta; - } -}; - -const updateCameraTarget = (camera: Camera, target: number, minDistance: number, maxDistance: number) => { +const updateCameraTarget = ( + controls: OrbitControls, + camera: Camera, + target: number, + minDistance: number, + maxDistance: number +) => { if (controls) { let distance = controls.target.distanceTo(camera.position); distance = clamp(distance, maxDistance, minDistance); @@ -54,9 +50,19 @@ export const CameraControls: FC = ({ }) => { const cameraZoomTargetRef = useRef(cameraZoomTarget); const { camera, gl } = useThree(); + const controlsRef = useRef(null); + const progressRef = useRef(Number.POSITIVE_INFINITY); const fallbackCameraTarget = cameraTarget || 1.475 + headScale / 10; const headScaleAdjustedMinDistance = controlsMinDistance + headScale / 10; + const updateCameraFocus = (delta: number, target?: Vector3) => { + if (target && progressRef.current <= 1) { + camera.position.setX(lerp(camera.position.x, target.x, progressRef.current)); + camera.position.setZ(lerp(camera.position.z, target.z, progressRef.current)); + progressRef.current += delta; + } + }; + useEffect(() => { if ( cameraZoomTargetRef.current?.x !== cameraZoomTarget?.x || @@ -64,50 +70,47 @@ export const CameraControls: FC = ({ cameraZoomTargetRef.current?.z !== cameraZoomTarget?.z ) { cameraZoomTargetRef.current = cameraZoomTarget; - progress = 0; + progressRef.current = 0; } - controls = new OrbitControls(camera, gl.domElement); - controls.enableRotate = false; - controls.enablePan = false; - - controls.minDistance = headScaleAdjustedMinDistance; - controls.maxDistance = controlsMaxDistance; - controls.minPolarAngle = 1.4; - controls.maxPolarAngle = 1.4; - - controls.target.set(0, fallbackCameraTarget, 0); - controls.update(); - - // TODO: Look for a better distance initialiser, without progress value check it conflicts with cameraZoomTarget which also can update camera position.z - if (cameraInitialDistance && progress === Number.POSITIVE_INFINITY) { - camera.position.z = cameraInitialDistance; - controls.update(); + const controls = controlsRef.current; + if (controls) { + // TODO: Look for a better distance initialiser, without progress value check it conflicts with cameraZoomTarget which also can update camera position.z + if (cameraInitialDistance && progressRef.current === Number.POSITIVE_INFINITY) { + camera.position.z = cameraInitialDistance; + controls.update(); + } } return () => { - controls.dispose(); + controls?.dispose(); }; - }, [ - cameraInitialDistance, - camera, - controlsMinDistance, - controlsMaxDistance, - fallbackCameraTarget, - gl.domElement, - headScaleAdjustedMinDistance, - cameraZoomTarget - ]); + }, [cameraInitialDistance, camera, gl.domElement, cameraZoomTarget]); useFrame((_, delta) => { - if (updateCameraTargetOnZoom) { - updateCameraTarget(camera, fallbackCameraTarget, headScaleAdjustedMinDistance, controlsMaxDistance); - } - updateCameraFocus(camera, delta, cameraZoomTarget); - if (controls) { - controls.update(); + if (updateCameraTargetOnZoom && controlsRef.current) { + updateCameraTarget( + controlsRef.current, + camera, + fallbackCameraTarget, + headScaleAdjustedMinDistance, + controlsMaxDistance + ); } + updateCameraFocus(delta, cameraZoomTarget); + controlsRef.current?.update(); }); - return null; + return ( + + ); };