diff --git a/docs/api/renderer.md b/docs/api/renderer.md
index cf148bf18..e0f266731 100644
--- a/docs/api/renderer.md
+++ b/docs/api/renderer.md
@@ -83,6 +83,7 @@ renderer.shadowMap.type: PCFSoftShadowMap
| **clearColor** | The color the renderer will use to clear the canvas. | `#000000` |
| **windowSize** | Whether to use the window size as the canvas size or the parent element. | `false` |
| **disableRender** | Disable render on requestAnimationFrame, usefull for PostProcessing | `false` |
+| **camera** | A manual camera to be used by the renderer. | |
## Defaults
diff --git a/playground/components.d.ts b/playground/components.d.ts
index 228cc37c4..111081ceb 100644
--- a/playground/components.d.ts
+++ b/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']
diff --git a/playground/src/components/Cameras.vue b/playground/src/components/Cameras.vue
new file mode 100644
index 000000000..44aa7217c
--- /dev/null
+++ b/playground/src/components/Cameras.vue
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playground/src/pages/index.vue b/playground/src/pages/index.vue
index 44b22ffbc..4ca74bf35 100644
--- a/playground/src/pages/index.vue
+++ b/playground/src/pages/index.vue
@@ -1,6 +1,6 @@
-
+
diff --git a/src/components/TresCanvas.ts b/src/components/TresCanvas.ts
index 165e9fbd3..8bbd24294 100644
--- a/src/components/TresCanvas.ts
+++ b/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({
'windowSize',
'preset',
'disableRender',
+ 'camera',
] as unknown as undefined,
setup(props, { slots, expose }) {
const tres = useTresProvider()
diff --git a/src/components/TresScene.ts b/src/components/TresScene.ts
index d2228dda8..e2bb7bdce 100644
--- a/src/components/TresScene.ts
+++ b/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({
'windowSize',
'preset',
'disableRender',
+ 'camera',
] as unknown as undefined,
setup(props, { slots, expose }) {
if (props.physicallyCorrectLights === true) {
@@ -69,7 +71,8 @@ export const TresScene = defineComponent({
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({
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({
import.meta.hot.on('vite:afterUpdate', dispose)
}
+ watch(
+ () => props.camera,
+ camera => {
+ if (camera) {
+ clearCameras()
+ pushCamera(camera as any)
+ }
+ },
+ )
+
return () => {
return h(
h(