Skip to content

Commit

Permalink
Merge pull request #236 from Tresjs/feature/camera-prop-tres-canvas
Browse files Browse the repository at this point in the history
feat: camera prop tres canvas
  • Loading branch information
alvarosabu authored Apr 27, 2023
2 parents 7fec938 + 9247132 commit b2ab708
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 6 deletions.
1 change: 1 addition & 0 deletions docs/api/renderer.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions playground/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand Down
113 changes: 113 additions & 0 deletions playground/src/components/Cameras.vue
Original file line number Diff line number Diff line change
@@ -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>
2 changes: 1 addition & 1 deletion playground/src/pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts"></script>
<template>
<Suspense>
<TheExperience />
<Cameras />
</Suspense>
</template>
4 changes: 3 additions & 1 deletion src/components/TresCanvas.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -19,6 +19,7 @@ export interface TresCanvasProps {
windowSize?: boolean
preset?: RendererPresetsType
disableRender?: boolean
camera?: CameraType
}
/**
* Vue component for rendering a Tres component.
Expand All @@ -41,6 +42,7 @@ export const TresCanvas = defineComponent<TresCanvasProps>({
'windowSize',
'preset',
'disableRender',
'camera',
] as unknown as undefined,
setup(props, { slots, expose }) {
const tres = useTresProvider()
Expand Down
25 changes: 21 additions & 4 deletions src/components/TresScene.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -25,6 +25,7 @@ export interface TresSceneProps {
windowSize?: boolean
preset?: RendererPresetsType
disableRender?: boolean
camera?: CameraType
}
/**
* Vue component for rendering a Tres component.
Expand All @@ -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) {
Expand All @@ -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!')
}
Expand All @@ -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()

Expand Down Expand Up @@ -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(
Expand Down

0 comments on commit b2ab708

Please sign in to comment.