|
@@ -4,73 +4,213 @@ Vue 3 [Composition API](https://vuejs.org/guide/extras/composition-api-faq.html#
|
|
|
|
|
|
**TresJS** takes huge advantage of this API to create a set of composable functions that can be used to create animations, interact with the scene and more. It also allows you to create more complex scenes that might not be possible using just the Vue Components (Textures, Loaders, etc.).
|
|
|
|
|
|
-The core of **TresJS** uses these composables internally, so you would be using the same API that the core uses. For instance, components that need to updated on the internal render loop use the `useRenderLoop` composable to register a callback that will be called every time the renderer updates the scene.
|
|
|
+The core of **TresJS** uses these composables internally, so you would be using the same API that the core uses.
|
|
|
|
|
|
-## useRenderLoop
|
|
|
-
|
|
|
-The `useRenderLoop` composable is the core of **TresJS** animations. It allows you to register a callback that will be called on native refresh rate. This is the most important composable in **TresJS**.
|
|
|
+## useTresContext
|
|
|
+This composable aims to provide access to the state model which contains multiple useful properties.
|
|
|
|
|
|
```ts
|
|
|
-const { onLoop, resume } = useRenderLoop()
|
|
|
+const { camera, renderer, camera, cameras } = useTresContext()
|
|
|
+```
|
|
|
|
|
|
-onLoop(({ delta, elapsed, clock }) => {
|
|
|
- // I will run at every frame ~60FPS (depending of your monitor)
|
|
|
-})
|
|
|
+::: warning
|
|
|
+`useTresContext` can be only be used inside of a `TresCanvas` since this component acts as the provider for the context data.
|
|
|
+:::
|
|
|
+
|
|
|
+::: code-group
|
|
|
+
|
|
|
+```vue [App.vue]
|
|
|
+<script setup>
|
|
|
+import { TresCanvas } from '@tresjs/core'
|
|
|
+import SubComponent from './SubComponent.vue'
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <TresCanvas
|
|
|
+ render-mode="manual"
|
|
|
+ >
|
|
|
+ <SubComponent />
|
|
|
+ </TresCanvas>
|
|
|
+</template>
|
|
|
```
|
|
|
|
|
|
+```vue [SubComponent.vue]
|
|
|
+<script lang="ts" setup>
|
|
|
+import { useTresContext } from '@tresjs/core'
|
|
|
+
|
|
|
+const context = useTresContext()
|
|
|
+</script>
|
|
|
+```
|
|
|
+
|
|
|
+:::
|
|
|
+
|
|
|
+### Properties of context
|
|
|
+| Property | Description |
|
|
|
+| --- | --- |
|
|
|
+| **camera** | The currently active camera |
|
|
|
+| **cameras** | The cameras that exist in the scene |
|
|
|
+| **controls** | The controls of your scene |
|
|
|
+| **deregisterCamera** | A method to deregister a camera. This is only required if you manually create a camera. Cameras in the template are deregistered automatically. |
|
|
|
+| **extend** | Extends the component catalogue. See [extending](/advanced/extending) |
|
|
|
+| **raycaster** | the global raycaster used for pointer events |
|
|
|
+| **registerCamera** | a method to register a camera. This is only required if you manually create a camera. Cameras in the template are registered automatically. |
|
|
|
+| **renderer** | the [WebGLRenderer](https://threejs.org/docs/#api/en/renderers/WebGLRenderer) of your scene |
|
|
|
+| **scene** | the [scene](https://threejs.org/docs/?q=sce#api/en/scenes/Scene). |
|
|
|
+| **setCameraActive** | a method to set a camera active |
|
|
|
+| **sizes** | contains width, height and aspect ratio of your canvas |
|
|
|
+| **invalidate** | a method to invalidate the render loop. This is only required if you set the `render-mode` prop to `on-demand`. |
|
|
|
+| **advance** | a method to advance the render loop. This is only required if you set the `render-mode` prop to `manual`. |
|
|
|
+| **loop** | the renderer loop |
|
|
|
+
|
|
|
+### useLoop <Badge text="v4.1.0" />
|
|
|
+
|
|
|
+This composable allows you to execute a callback on every rendered frame, similar to `useRenderLoop` but unique to each `TresCanvas` instance and with access to the [context](#usetrescontext).
|
|
|
+
|
|
|
::: warning
|
|
|
-Be mindful of the performance implications of using this composable. It will run at every frame, so if you have a lot of logic in your callback, it might impact the performance of your app. Specially if you are updating reactive states or references.
|
|
|
+`useLoop` can be only be used inside of a `TresCanvas` since this component acts as the provider for the context data.
|
|
|
:::
|
|
|
|
|
|
-The `onLoop` callback receives an object with the following properties based on the [THREE clock](https://threejs.org/docs/?q=clock#api/en/core/Clock):
|
|
|
+#### Register update callbacks
|
|
|
|
|
|
-- `delta`: The delta time between the current and the last frame. This is the time in seconds since the last frame.
|
|
|
-- `elapsed`: The elapsed time since the start of the render loop.
|
|
|
+The user can register update callbacks (such as animations, fbo, etc) using the `onBeforeRender`
|
|
|
|
|
|
-This composable is based on `useRafFn` from [vueuse](https://vueuse.org/core/useRafFn/). Thanks to [@wheatjs](https://github.com/wheatjs) for the amazing contribution.
|
|
|
+::: code-group
|
|
|
|
|
|
-### Before and after render
|
|
|
+```vue [App.vue]
|
|
|
+<script setup>
|
|
|
+import { TresCanvas } from '@tresjs/core'
|
|
|
+import AnimatedBox from './AnimatedBox.vue'
|
|
|
+</script>
|
|
|
|
|
|
-You can also register a callback that will be called before and after the renderer updates the scene. This is useful if you add a profiler to measure the FPS for example.
|
|
|
+<template>
|
|
|
+ <TresCanvas>
|
|
|
+ <AnimatedBox />
|
|
|
+ </TresCanvas>
|
|
|
+</template>
|
|
|
+```
|
|
|
+
|
|
|
+```vue [AnimatedBox.vue]
|
|
|
+<script setup>
|
|
|
+import { useLoop } from '@tresjs/core'
|
|
|
+
|
|
|
+const boxRef = ref()
|
|
|
+
|
|
|
+const { onBeforeRender } = useLoop()
|
|
|
+
|
|
|
+onBeforeRender(({ delta }) => {
|
|
|
+ boxRef.value.rotation.y += delta
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <TresMesh ref="boxRef">
|
|
|
+ <TresBoxGeometry />
|
|
|
+ <TresMeshBasicMaterial color="teal" />
|
|
|
+ </TresMesh>
|
|
|
+</template>
|
|
|
+```
|
|
|
+
|
|
|
+:::
|
|
|
+
|
|
|
+Your callback function will be triggered just before a frame is rendered and it will be deregistered automatically when the component is destroyed.
|
|
|
+
|
|
|
+#### Take over the render loop
|
|
|
+
|
|
|
+You can take over the render call by using the `render` method.
|
|
|
|
|
|
```ts
|
|
|
-const { onBeforeLoop, onAfterLoop } = useRenderLoop()
|
|
|
+const { render } = useLoop()
|
|
|
|
|
|
-onBeforeLoop(({ delta, elapsed }) => {
|
|
|
- // I will run before the renderer updates the scene
|
|
|
- fps.begin()
|
|
|
+render(({ renderer, scene, camera }) => {
|
|
|
+ renderer.render(scene, camera)
|
|
|
})
|
|
|
+```
|
|
|
|
|
|
-onAfterLoop(({ delta, elapsed }) => {
|
|
|
- // I will run after the renderer updates the scene
|
|
|
- fps.end()
|
|
|
+::: warning
|
|
|
+Consider that if you take over the render loop, you will need to manually render the scene and take care of features like the conditional rendering yourself.
|
|
|
+:::
|
|
|
+
|
|
|
+#### Register after render callbacks (ex physics calculations)
|
|
|
+
|
|
|
+You can also register callbacks which are invoked after rendring by using the `onAfterRender` method.
|
|
|
+
|
|
|
+```ts
|
|
|
+const { onAfterRender } = useLoop()
|
|
|
+
|
|
|
+onAfterRender(({ renderer }) => {
|
|
|
+ // Calculations
|
|
|
})
|
|
|
```
|
|
|
|
|
|
-### Pause and resume
|
|
|
+#### Render priority
|
|
|
|
|
|
-You can pause and resume the render loop using the exposed `pause` and `resume` methods.
|
|
|
+Both useBeforeRender and useAfteRender provide an optional priority number. This number could be anything from `Number.NEGATIVE_INFINITY` to `Number.POSITIVE_INFINITY` being the 0 by default. The lower the number, the earlier the callback will be executed.
|
|
|
|
|
|
```ts
|
|
|
-const { pause, resume } = useRenderLoop()
|
|
|
+onBeforeRender(() => {
|
|
|
+ console.count('triggered first')
|
|
|
+}, -1)
|
|
|
|
|
|
-// Pause the render loop
|
|
|
-pause()
|
|
|
+onBeforeRender(() => {
|
|
|
+ console.count('triggered second')
|
|
|
+}, 1)
|
|
|
+```
|
|
|
|
|
|
-// Resume the render loop
|
|
|
-resume()
|
|
|
+#### Params of the callback
|
|
|
+
|
|
|
+All callbacks receive an object with the following properties:
|
|
|
+
|
|
|
+- `delta`: The delta time between the current and the last frame. This is the time in miliseconds since the last frame.
|
|
|
+- `elapsed`: The elapsed time since the start of the render loop.
|
|
|
+- `clock`: The [THREE clock](https://threejs.org/docs/?q=clock#api/en/core/Clock) instance.
|
|
|
+- `renderer`: The [WebGLRenderer](https://threejs.org/docs/#api/en/renderers/WebGLRenderer) of your scene.
|
|
|
+- `scene`: The [scene](https://threejs.org/docs/?q=sce#api/en/scenes/Scene) of your scene.
|
|
|
+- `camera`: The currently active camera.
|
|
|
+- `raycaster`: The global raycaster used for pointer events.
|
|
|
+- `controls`: The controls of your scene.
|
|
|
+- `invalidate`: A method to invalidate the render loop. This is only required if you set the `render-mode` prop to `on-demand`.
|
|
|
+- `advance`: A method to advance the render loop. This is only required if you set the `render-mode` prop to `manual`.
|
|
|
+
|
|
|
+#### Pausing and resuming the update loop
|
|
|
+
|
|
|
+You can use `pause` and `resume` methods:
|
|
|
+
|
|
|
+```ts
|
|
|
+const { onBeforeRender, pause, resume } = useLoop()
|
|
|
+
|
|
|
+onBeforeRender(({ elapsed }) => {
|
|
|
+ sphereRef.value.position.y += Math.sin(elapsed) * 0.01
|
|
|
+})
|
|
|
+
|
|
|
+pause() // This will pause the loop
|
|
|
+resume() // This will resume the loop
|
|
|
```
|
|
|
|
|
|
-Also you can get the active state of the render loop using the `isActive` property.
|
|
|
+#### Pausing and resuming the render
|
|
|
+
|
|
|
+You can use `pauseRender` and `resumeRender` methods:
|
|
|
|
|
|
```ts
|
|
|
-const { resume, isActive } = useRenderLoop()
|
|
|
+const { pauseRender, resumeRender } = useLoop()
|
|
|
|
|
|
-console.log(isActive) // false
|
|
|
+onBeforeRender(({ elapse }) => {
|
|
|
+ sphereRef.value.position.y += Math.sin(elapsed) * 0.01
|
|
|
+})
|
|
|
|
|
|
-resume()
|
|
|
+pauseRender() // This will pause the renderer
|
|
|
+resumeRender() // This will resume the renderer
|
|
|
+```
|
|
|
+
|
|
|
+#### Unregistering callbacks
|
|
|
+
|
|
|
+You can unregister a callback by calling the method `off` returned by the `onBeforeRender` or `onAfterRender` method.
|
|
|
+
|
|
|
+```ts
|
|
|
+const { onBeforeRender } = useLoop()
|
|
|
|
|
|
-console.log(isActive) // true
|
|
|
+const { off } = onBeforeRender(({ elapsed }) => {
|
|
|
+ sphereRef.value.position.y += Math.sin(elapsed) * 0.01
|
|
|
+})
|
|
|
```
|
|
|
|
|
|
## useLoader
|
|
@@ -197,46 +337,73 @@ watch(character, ({ model }) => {
|
|
|
})
|
|
|
```
|
|
|
|
|
|
-## useTresContext
|
|
|
-This composable aims to provide access to the state model which contains multiple useful properties.
|
|
|
+## useRenderLoop
|
|
|
+
|
|
|
+The `useRenderLoop` composable can be use for animations that don't require access to the [context](#usetrescontext). It allows you to register a callback that will be called on native refresh rate.
|
|
|
+
|
|
|
+::: warning
|
|
|
+ Since v4.1.0, `useRenderLoop` is no longer used internally to control the rendering, if you want to use conditional rendering, multiple canvases or need access to state please `useLoop` instead. [Read why](#useloop)
|
|
|
+:::
|
|
|
|
|
|
```ts
|
|
|
-const { camera, renderer, camera, cameras } = useTresContext()
|
|
|
+const { onLoop, resume } = useRenderLoop()
|
|
|
+
|
|
|
+onLoop(({ delta, elapsed, clock }) => {
|
|
|
+ // I will run at every frame ~60FPS (depending of your monitor)
|
|
|
+})
|
|
|
```
|
|
|
|
|
|
::: warning
|
|
|
-`useTresContext` can be only be used inside of a `TresCanvas` since `TresCanvas` acts as the provider for the context data. Use [the context exposed by TresCanvas](tres-canvas#exposed-public-properties) if you find yourself needing it in parent components of TresCanvas.
|
|
|
+Be mindful of the performance implications of using this composable. It will run at every frame, so if you have a lot of logic in your callback, it might impact the performance of your app. Specially if you are updating reactive states or references.
|
|
|
:::
|
|
|
|
|
|
-```vue
|
|
|
-<TresCanvas>
|
|
|
- <MyModel />
|
|
|
-</TresCanvas>
|
|
|
+The `onLoop` callback receives an object with the following properties based on the [THREE clock](https://threejs.org/docs/?q=clock#api/en/core/Clock):
|
|
|
+
|
|
|
+- `delta`: The delta time between the current and the last frame. This is the time in milliseconds since the last frame.
|
|
|
+- `elapsed`: The elapsed time since the start of the render loop.
|
|
|
+
|
|
|
+This composable is based on `useRafFn` from [vueuse](https://vueuse.org/core/useRafFn/). Thanks to [@wheatjs](https://github.com/wheatjs) for the amazing contribution.
|
|
|
+
|
|
|
+### Before and after render
|
|
|
+
|
|
|
+You can also register a callback that will be called before and after the renderer updates the scene. This is useful if you add a profiler to measure the FPS for example.
|
|
|
+
|
|
|
+```ts
|
|
|
+const { onBeforeLoop, onAfterLoop } = useRenderLoop()
|
|
|
+
|
|
|
+onBeforeLoop(({ delta, elapsed }) => {
|
|
|
+ // I will run before the renderer updates the scene
|
|
|
+ fps.begin()
|
|
|
+})
|
|
|
+
|
|
|
+onAfterLoop(({ delta, elapsed }) => {
|
|
|
+ // I will run after the renderer updates the scene
|
|
|
+ fps.end()
|
|
|
+})
|
|
|
```
|
|
|
|
|
|
-```vue
|
|
|
-// MyModel.vue
|
|
|
+### Pause and resume
|
|
|
|
|
|
-<script lang="ts" setup>
|
|
|
-import { useTresContext } from '@tresjs/core'
|
|
|
+You can pause and resume the render loop using the exposed `pause` and `resume` methods.
|
|
|
|
|
|
-const context = useTresContext()
|
|
|
-</script>
|
|
|
+```ts
|
|
|
+const { pause, resume } = useRenderLoop()
|
|
|
+
|
|
|
+// Pause the render loop
|
|
|
+pause()
|
|
|
+
|
|
|
+// Resume the render loop
|
|
|
+resume()
|
|
|
```
|
|
|
|
|
|
-### Properties of context
|
|
|
-| Property | Description |
|
|
|
-| --- | --- |
|
|
|
-| **camera** | The currently active camera |
|
|
|
-| **cameras** | The cameras that exist in the scene |
|
|
|
-| **controls** | The controls of your scene |
|
|
|
-| **deregisterCamera** | A method to deregister a camera. This is only required if you manually create a camera. Cameras in the template are deregistered automatically. |
|
|
|
-| **extend** | Extends the component catalogue. See [extending](/advanced/extending) |
|
|
|
-| **raycaster** | the global raycaster used for pointer events |
|
|
|
-| **registerCamera** | a method to register a camera. This is only required if you manually create a camera. Cameras in the template are registered automatically. |
|
|
|
-| **renderer** | the [WebGLRenderer](https://threejs.org/docs/#api/en/renderers/WebGLRenderer) of your scene |
|
|
|
-| **scene** | the [scene](https://threejs.org/docs/?q=sce#api/en/scenes/Scene). |
|
|
|
-| **setCameraActive** | a method to set a camera active |
|
|
|
-| **sizes** | contains width, height and aspect ratio of your canvas |
|
|
|
-| **invalidate** | a method to invalidate the render loop. This is only required if you set the `render-mode` prop to `on-demand`. |
|
|
|
-| **advance** | a method to advance the render loop. This is only required if you set the `render-mode` prop to `manual`. |
|
|
|
+Also you can get the active state of the render loop using the `isActive` property.
|
|
|
+
|
|
|
+```ts
|
|
|
+const { resume, isActive } = useRenderLoop()
|
|
|
+
|
|
|
+console.log(isActive.value) // false
|
|
|
+
|
|
|
+resume()
|
|
|
+
|
|
|
+console.log(isActive.value) // true
|
|
|
+```
|