Kaynağa Gözat

fix: camera aspect

* Update orthographic camera aspect when screen size updates
* Give user a "manual" flag to keep Tres from updating camera
Peter 1 yıl önce
ebeveyn
işleme
52dad5c982

+ 13 - 8
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)
 })

+ 24 - 6
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<TresContext, 'sizes'> & { 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<TresContext, 'sizes'> & { scene
     deregisterCamera,
     setCameraActive,
   }
+}
+
+function isOrthographicCamera(o: any): o is OrthographicCamera {
+  return o.hasOwnProperty('isOrthographicCamera') && o.isOrthographicCamera
 }