1
0
Эх сурвалжийг харах

feat: add manual camera prop to canvas

alvarosabu 2 жил өмнө
parent
commit
588a3fcddd

+ 1 - 0
playground/components.d.ts

@@ -11,6 +11,7 @@ declare module '@vue/runtime-core' {
   export interface GlobalComponents {
     AkuAku: typeof import('./src/components/gltf/AkuAku.vue')['default']
     AnimatedModel: typeof import('./src/components/AnimatedModel.vue')['default']
+    Cameras: typeof import('./src/components/Cameras.vue')['default']
     FBXModels: typeof import('./src/components/FBXModels.vue')['default']
     Gltf: typeof import('./src/components/gltf/index.vue')['default']
     MeshWobbleMaterial: typeof import('./src/components/meshWobbleMaterial/index.vue')['default']

+ 113 - 0
playground/src/components/Cameras.vue

@@ -0,0 +1,113 @@
+<script setup lang="ts">
+import { TresCanvas } from '/@'
+import { BasicShadowMap, sRGBEncoding, NoToneMapping, PerspectiveCamera, OrthographicCamera } from 'three'
+
+import { Box, useTweakPane } from '@tresjs/cientos'
+
+const gl = {
+  clearColor: '#82DBC5',
+  shadows: true,
+  alpha: false,
+  shadowMapType: BasicShadowMap,
+  outputEncoding: sRGBEncoding,
+  toneMapping: NoToneMapping,
+}
+
+const state = reactive({
+  cameraType: 'perspective',
+  camera: new PerspectiveCamera(75, 1, 0.1, 1000),
+})
+
+state.camera.position.set(5, 5, 5)
+state.camera.lookAt(0, 0, 0)
+const { pane } = useTweakPane()
+
+pane
+  .addBlade({
+    view: 'list',
+    label: 'Camera',
+    options: [
+      { text: 'perspective', value: 'perspective' },
+      { text: 'orthographic', value: 'orthographic' },
+    ],
+    value: 'perspective',
+  })
+  .on('change', e => {
+    state.cameraType = e.value
+    const newCamera =
+      e.value === 'perspective'
+        ? new PerspectiveCamera(75, 1, 0.1, 1000)
+        : new OrthographicCamera(-10, 10, 10, -10, 0.1, 1000)
+
+    newCamera.position.set(5, 5, 5)
+    newCamera.lookAt(0, 0, 0)
+    state.camera = newCamera
+    perspectiveFolder.hidden = e.value === 'orthographic'
+    orthographicFolder.hidden = e.value === 'perspective'
+    /* context.value.state.accio += 1 */
+  })
+
+const perspectiveFolder = pane.addFolder({
+  title: 'Perspective Camera',
+})
+
+const orthographicFolder = pane.addFolder({
+  title: 'Ortographic Camera',
+})
+
+orthographicFolder.hidden = true
+
+watch(
+  () => state.cameraType,
+  () => {
+    if (state.cameraType === 'orthographic') {
+      perspectiveFolder.children.forEach(child => {
+        child.dispose()
+      })
+      orthographicFolder.addInput(state.camera, 'left', { min: -50, max: 50 })
+      orthographicFolder.addInput(state.camera, 'right', { min: -50, max: 50 })
+      orthographicFolder.addInput(state.camera, 'top', { min: -50, max: 50 })
+      orthographicFolder.addInput(state.camera, 'bottom', { min: -50, max: 50 })
+      orthographicFolder.addInput(state.camera, 'near', { min: 0, max: 50 })
+      orthographicFolder.addInput(state.camera, 'far', { min: 0, max: 50 })
+    } else {
+      orthographicFolder.children.forEach(child => {
+        child.dispose()
+      })
+      perspectiveFolder.addInput(state.camera, 'fov', { min: 0, max: 180 })
+      perspectiveFolder.addInput(state.camera, 'near', { min: 0, max: 10 })
+      perspectiveFolder.addInput(state.camera, 'far', { min: 0, max: 10 })
+    }
+  },
+  {
+    immediate: true,
+  },
+)
+
+const context = ref(null)
+
+watchEffect(() => {
+  if (context.value) {
+    console.log(context.value)
+  }
+})
+
+const asyncTorus = ref(false)
+
+setTimeout(() => {
+  asyncTorus.value = true
+}, 1000)
+</script>
+
+<template>
+  <TresCanvas v-bind="gl" ref="context" :camera="state.camera">
+    <!--     <TresPerspectiveCamera v-if="state.cameraType === 'perspective'" :position="[11, 11, 11]" />
+    <TresOrthographicCamera v-if="state.cameraType === 'orthographic'" :position="[11, 11, 11]" /> -->
+    <Box :position="[0, 1, 0]" :scale="[2, 2, 2]">
+      <TresMeshNormalMaterial :color="'teal'" />
+    </Box>
+    <TresGridHelper />
+    <TresAmbientLight :intensity="1" />
+    <TresDirectionalLight :position="[3, 3, 3]" :intensity="1" />
+  </TresCanvas>
+</template>

+ 1 - 1
playground/src/pages/index.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts"></script>
 <template>
   <Suspense>
-    <TheExperience />
+    <Cameras />
   </Suspense>
 </template>

+ 3 - 1
src/components/TresCanvas.ts

@@ -1,7 +1,7 @@
 import { TresScene } from './TresScene'
 import { defineComponent, h } from 'vue'
 import { ShadowMapType, TextureEncoding, ToneMapping } from 'three'
-import { useTresProvider } from '/@/composables'
+import { CameraType, useTresProvider } from '/@/composables'
 import { RendererPresetsType } from '/@/composables/useRenderer/const'
 
 export interface TresCanvasProps {
@@ -19,6 +19,7 @@ export interface TresCanvasProps {
   windowSize?: boolean
   preset?: RendererPresetsType
   disableRender?: boolean
+  camera?: CameraType
 }
 /**
  * Vue component for rendering a Tres component.
@@ -41,6 +42,7 @@ export const TresCanvas = defineComponent<TresCanvasProps>({
     'windowSize',
     'preset',
     'disableRender',
+    'camera',
   ] as unknown as undefined,
   setup(props, { slots, expose }) {
     const tres = useTresProvider()

+ 21 - 4
src/components/TresScene.ts

@@ -1,8 +1,8 @@
-import { App, defineComponent, h, onMounted, onUnmounted, provide, ref, watchEffect } from 'vue'
+import { App, defineComponent, h, onMounted, onUnmounted, ref, watch, watchEffect } from 'vue'
 import * as THREE from 'three'
 import { ShadowMapType, TextureEncoding, ToneMapping } from 'three'
 import { createTres } from '/@/core/renderer'
-import { TRES_CONTEXT_KEY, useLogger } from '/@/composables'
+import { CameraType, TRES_CONTEXT_KEY, useLogger } from '/@/composables'
 import { useCamera, useRenderer, useRenderLoop, useRaycaster, useTres } from '/@/composables'
 import { extend } from '/@/core/catalogue'
 import { RendererPresetsType } from '/@/composables/useRenderer/const'
@@ -25,6 +25,7 @@ export interface TresSceneProps {
   windowSize?: boolean
   preset?: RendererPresetsType
   disableRender?: boolean
+  camera?: CameraType
 }
 /**
  * Vue component for rendering a Tres component.
@@ -49,6 +50,7 @@ export const TresScene = defineComponent<TresSceneProps>({
     'windowSize',
     'preset',
     'disableRender',
+    'camera',
   ] as unknown as undefined,
   setup(props, { slots, expose }) {
     if (props.physicallyCorrectLights === true) {
@@ -69,7 +71,8 @@ export const TresScene = defineComponent<TresSceneProps>({
     const internal = slots && slots.default && slots.default()
 
     if (internal?.length > 0) {
-      isCameraAvailable.value = internal.some((node: TresObject) => isString(node.type) && node.type.includes('Camera'))
+      isCameraAvailable.value =
+        internal.some((node: TresObject) => isString(node.type) && node.type.includes('Camera')) || props.camera
       if (!isCameraAvailable.value) {
         logWarning('No camera found in the scene, please add one!')
       }
@@ -83,10 +86,14 @@ export const TresScene = defineComponent<TresSceneProps>({
       setState('renderer', null)
     })
 
+    const { activeCamera, pushCamera, clearCameras } = useCamera()
+
     function initRenderer() {
       const { renderer } = useRenderer(props)
 
-      const { activeCamera } = useCamera()
+      if (props.camera) {
+        pushCamera(props.camera as any)
+      }
 
       const { onLoop } = useRenderLoop()
 
@@ -153,6 +160,16 @@ export const TresScene = defineComponent<TresSceneProps>({
       import.meta.hot.on('vite:afterUpdate', dispose)
     }
 
+    watch(
+      () => props.camera,
+      camera => {
+        if (camera) {
+          clearCameras()
+          pushCamera(camera as any)
+        }
+      },
+    )
+
     return () => {
       return h(
         h(