Browse Source

refactor: 1043 render function triggers too often (#1044)

* refactor!: moved function to replace render function to renderer manager

* removed test

* fixed test type stuff

* fix: take over render

* refactor: update attach demo to use useTresContext

* refactor: added render callback back to useLoop for less breaking changes

* removed deprecation message
Tino Koch 1 week ago
parent
commit
c4c3f0bb4b

+ 2 - 2
playground/vue/src/pages/advanced/attachPostProcessing/Effects.vue

@@ -3,14 +3,14 @@ import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer
 import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
 import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass'
 import { UnrealBloomPass } from 'three-stdlib'
-import { extend, useLoop, useTres } from '@tresjs/core'
+import { extend, useTres, useTresContext } from '@tresjs/core'
 import { shallowRef } from 'vue'
 
 extend({ EffectComposer, OutputPass, UnrealBloomPass, RenderPass })
 const { renderer, scene, camera, sizes } = useTres()
 const composer = shallowRef<EffectComposer>()
 
-useLoop().render(() => {
+useTresContext().renderer.replaceRenderFunction(() => {
   if (composer.value) {
     composer.value!.render()
   }

+ 6 - 6
playground/vue/src/pages/advanced/takeOverRender/TakeOverRenderExperience.vue

@@ -1,20 +1,20 @@
 <script setup lang="ts">
 import { OrbitControls } from '@tresjs/cientos'
 
-import { useLoop, useTres } from '@tresjs/core'
+import { useLoop, useTresContext } from '@tresjs/core'
 import { useControls } from '@tresjs/leches'
 import type { Mesh } from 'three'
 
-const { render, onRender } = useLoop()
-const { renderer, scene, camera } = useTres()
+const { onRender } = useLoop()
+const { renderer, scene, camera } = useTresContext()
 
 const { shouldRender } = useControls({
   shouldRender: true,
 })
 
-render((notifySuccess) => {
-  if (shouldRender.value && camera.value) {
-    renderer.render(scene.value, camera.value)
+renderer.replaceRenderFunction((notifySuccess) => {
+  if (shouldRender.value && camera.activeCamera.value) {
+    renderer.instance.render(scene.value, camera.activeCamera.value)
     notifySuccess()
   }
 })

+ 3 - 16
src/composables/useCreateRafLoop/index.ts

@@ -3,20 +3,12 @@ import { Clock } from 'three'
 
 export interface RafLoopContext { delta: number, elapsed: number }
 
-type LoopFunction = (notifySuccess: () => void) => void
-
 /**
- * @param defaultFunction the default function that is called before after the after event hook is triggered and after the before is triggered.
- * @param notifySuccess a callback that should be called to indicate a successfull cycle.
+ * @param cycleFn the function that is called before the after event hook is triggered and after the before event hook is triggered.
  */
-export const useCreateRafLoop = (
-  defaultFunction: LoopFunction,
-  notifySuccess: () => void,
-) => {
+export const useCreateRafLoop = (cycleFn: () => void) => {
   const clock = new Clock()
 
-  let cycleFn: LoopFunction = defaultFunction
-
   const eventHooks = {
     before: createEventHook<RafLoopContext>(),
     after: createEventHook<RafLoopContext>(),
@@ -29,7 +21,7 @@ export const useCreateRafLoop = (
     })
 
     eventHooks.before.trigger(getContextWithClock())
-    cycleFn(notifySuccess)
+    cycleFn()
     eventHooks.after.trigger(getContextWithClock())
   }, {
     immediate: false,
@@ -45,16 +37,11 @@ export const useCreateRafLoop = (
     pause()
   }
 
-  const replaceLoopFunction = (fn: LoopFunction) => {
-    cycleFn = fn
-  }
-
   return {
     start,
     stop,
     isActive,
     onBeforeLoop: eventHooks.before.on,
     onLoop: eventHooks.after.on,
-    replaceLoopFunction,
   }
 }

+ 1 - 1
src/composables/useLoop/index.ts

@@ -24,7 +24,7 @@ export const useLoop = () => {
     eventHookAfterRender.trigger({ ...tresContext, ...loopContext })
   })
 
-  const render = rendererManager.loop.replaceLoopFunction
+  const render = rendererManager.replaceRenderFunction
 
   return {
     stop: rendererManager.loop.stop,

+ 1 - 13
src/composables/useLoop/useLoop.test.ts

@@ -13,7 +13,7 @@ describe(useLoop.name, () => {
         camera: {},
         scene: {},
         renderer: {
-          loop: useCreateRafLoop(() => {}, () => {}),
+          loop: useCreateRafLoop(() => {}),
         },
         controls: {},
         events: {},
@@ -65,16 +65,4 @@ describe(useLoop.name, () => {
     expect(toTest).toBe('01234567')
     vi.useRealTimers()
   })
-
-  it('should be possible to replace the loop function', () => {
-    let toTest = 0
-    loop.start()
-    loop.render(() => {
-      toTest++
-    })
-    vi.advanceTimersToNextFrame()
-    vi.advanceTimersToNextFrame()
-    vi.advanceTimersToNextFrame()
-    expect(toTest).toBe(3)
-  })
 })

+ 15 - 3
src/composables/useRenderer/useRendererManager.ts

@@ -28,6 +28,7 @@ import { useCreateRafLoop } from '../useCreateRafLoop'
  * If set to 'always', the scene will be rendered every frame
  */
 export type RenderMode = 'always' | 'on-demand' | 'manual'
+export type RenderFunction = (notifySuccess: () => void) => void
 
 export type TresRenderer = WebGLRenderer | Renderer
 
@@ -288,12 +289,22 @@ export function useRendererManager(
     renderEventHook.trigger(renderer)
   }
 
-  const loop = useCreateRafLoop((_notifyFrameRendered) => {
-    if (camera.activeCamera.value && frames.value) {
+  let renderFunction: RenderFunction = (_notifyFrameRendered) => {
+    if (camera.activeCamera.value) {
       renderer.render(scene.value, camera.activeCamera.value)
       _notifyFrameRendered()
     }
-  }, notifyFrameRendered)
+  }
+
+  const replaceRenderFunction = (fn: RenderFunction) => {
+    renderFunction = fn
+  }
+
+  const loop = useCreateRafLoop(() => {
+    if (frames.value) {
+      renderFunction(notifyFrameRendered)
+    }
+  })
 
   readyEventHook.on(loop.start)
 
@@ -410,6 +421,7 @@ export function useRendererManager(
     invalidate,
     canBeInvalidated,
     mode: toValue(options.renderMode),
+    replaceRenderFunction,
   }
 }