diff --git a/playground/src/pages/cameras/Cameras.vue b/playground/src/pages/cameras/Cameras.vue index 402c772ef..d6c356382 100644 --- a/playground/src/pages/cameras/Cameras.vue +++ b/playground/src/pages/cameras/Cameras.vue @@ -13,16 +13,17 @@ const gl = { outputColorSpace: SRGBColorSpace, toneMapping: NoToneMapping, } +type Cam = (PerspectiveCamera | OrthographicCamera) & { manual?: boolean } const state = reactive({ cameraType: 'perspective', - camera: new PerspectiveCamera(75, 1, 0.1, 1000), + camera: new PerspectiveCamera(75, 1, 0.1, 1000) as Cam, }) state.camera.position.set(5, 5, 5) state.camera.lookAt(0, 0, 0) -const { value: cameraType } = useControls({ +const { cameraType, manual } = useControls({ cameraType: { label: 'CameraType', options: [{ @@ -31,19 +32,23 @@ const { value: cameraType } = useControls({ }, { text: 'Orthographic', value: 'orthographic', - }], + }, + ], value: state.cameraType, }, + manual: false, }) -watch(cameraType, ({ value }) => { - state.cameraType = value - if (value === 'perspective') { +watch(() => [cameraType.value.value, manual.value.value], () => { + state.cameraType = cameraType.value.value + if (cameraType.value.value === 'perspective') { state.camera = new PerspectiveCamera(75, 1, 0.1, 1000) } - else { - state.camera = new OrthographicCamera(-1, 1, 1, -1, 0.1, 1000) + else if (cameraType.value.value === 'orthographic') { + state.camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1000) + state.camera.zoom = 20 } + state.camera.manual = manual.value.value state.camera.position.set(5, 5, 5) state.camera.lookAt(0, 0, 0) }) diff --git a/src/composables/useCamera/index.ts b/src/composables/useCamera/index.ts index 10574fbc3..192c85d65 100644 --- a/src/composables/useCamera/index.ts +++ b/src/composables/useCamera/index.ts @@ -1,5 +1,6 @@ import { computed, watchEffect, onUnmounted, ref } from 'vue' -import { Camera, OrthographicCamera, PerspectiveCamera } from 'three' +import type { OrthographicCamera } from 'three' +import { Camera, PerspectiveCamera } from 'three' import type { TresScene } from '../../types' import type { TresContext } from '../useTresContextProvider' @@ -40,12 +41,25 @@ export const useCamera = ({ sizes, scene }: Pick & { scene watchEffect(() => { if (sizes.aspectRatio.value) { - cameras.value.forEach((camera: Camera) => { - if (camera instanceof PerspectiveCamera) - camera.aspect = sizes.aspectRatio.value - - if (camera instanceof PerspectiveCamera || camera instanceof OrthographicCamera) + cameras.value.forEach((camera: Camera & { manual?: boolean }) => { + // NOTE: Don't mess with the camera if it belongs to the user. + // https://github.com/pmndrs/react-three-fiber/blob/0ef66a1d23bf16ecd457dde92b0517ceec9861c5/packages/fiber/src/core/utils.ts#L457 + // + // To set camera as "manual": + // const myCamera = new PerspectiveCamera(); // or OrthographicCamera + // (myCamera as any).manual = true + if (!camera.manual && (camera instanceof PerspectiveCamera || isOrthographicCamera(camera))) { + if (camera instanceof PerspectiveCamera) { + camera.aspect = sizes.aspectRatio.value + } + else { + camera.left = sizes.width.value * -0.5 + camera.right = sizes.width.value * 0.5 + camera.top = sizes.height.value * 0.5 + camera.bottom = sizes.height.value * -0.5 + } camera.updateProjectionMatrix() + } }) } }) @@ -61,4 +75,8 @@ export const useCamera = ({ sizes, scene }: Pick & { scene deregisterCamera, setCameraActive, } +} + +function isOrthographicCamera(o: any): o is OrthographicCamera { + return o.hasOwnProperty('isOrthographicCamera') && o.isOrthographicCamera } \ No newline at end of file