-
-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 633 use loop #673
feat: 633 use loop #673
Conversation
Co-authored-by: Tino Koch <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see problems, thanks for this big work Alvaro
I agree with @Tinoooo . |
Awesome @andretchen0 , I already made the changes on the return and documented the |
src/composables/useLoop/index.ts
Outdated
const wrappedCallback = (params: LoopCallback) => { | ||
cb({ ...params, camera: unref(camera) as TresCamera, scene: unref(scene), renderer: unref(renderer), raycaster: unref(raycaster), controls: unref(controls), invalidate, advance }) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: I suggest creating a method that creates this method to avoid code duplication like mentioned here
@@ -185,6 +193,31 @@ export function useTresContextProvider({ | |||
root: ctx, | |||
} | |||
|
|||
// The loop | |||
|
|||
ctx.loop.register(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Can this be moved to useRenderer
? This would be beneficial for the seperation of concerns and the dependencies would be more obvious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I had commented the opposite.
Making this case for that:
If we move the question "should the scene be rendered?" to useRenderer
that means:
useRenderer
has to be passedrender
,invalidate
,advance
, andrenderMode
– 4 dependencies it otherwise doesn't require- it has to know and implement the update policies, which are orthogonal to what
WebGLRenderer
otherwise does.
If we want to keep the update in useRenderer
, I think it'd be better off encapulated in a single dependency like onRender()
– which it would simply call. But I'd personally prefer that it be removed from useRenderer
altogether. The render policy can be part of the loop:
if (renderPolicy.shouldRender()) {
renderer.render()
}
In this way, we eliminate the dependencies in useRenderer
altogether and put them behind an interface – nothing else needs to muck around with the implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already moved it.... can we please agree on one way @Tinoooo @andretchen0 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to reduce dependencies in useRenderer
, but I won't block the PR because of it. It's your call.
@@ -185,6 +193,31 @@ export function useTresContextProvider({ | |||
root: ctx, | |||
} | |||
|
|||
// The loop | |||
|
|||
ctx.loop.register(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Can/Should we make sure that this is resored once a user replaced the rendering with a custom callback and removed it afterwards via off
?
Co-authored-by: Tino Koch <[email protected]>
Co-authored-by: Tino Koch <[email protected]>
docs/directives/v-always-look-at.md
Outdated
@@ -2,6 +2,10 @@ | |||
|
|||
With the new directive v-always-look-at provided by **TresJS**, you can add easily command an [Object3D](https://threejs.org/docs/index.html?q=object#api/en/core/Object3D) to always look at a specific position, this could be passed as a Vector3 or an Array. | |||
|
|||
::: warning | |||
This directive can be only be used inside of a `TresCanvas` since this component acts as the provider for the context data and it uses `onLoop` under the hood. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this work? I'm getting
Error: useTresContext must be used together with useTresContextProvider
vAlwaysLookAt
only runs if updated – I think that's a bug – so you'll have to update it in order to get the error to throw.
<script setup lang="ts">
import { shallowRef } from 'vue'
import { vAlwaysLookAt, vLightHelper } from '@tresjs/core'
const other = shallowRef([1,1,1])
setTimeout(() => other.value = [2,1,1], 1000)
</script>
<template>
<TresDirectionalLight v-light-helper v-always-look-at="other" :position="[3, 3, 3]" :intensity="1" />
</template>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm gonna remove the directives with loop. They are not adding enough value for the troubles
src/composables/useLoop/index.ts
Outdated
|
||
function wrapCallback(cb: Fn) { | ||
return (params: LoopCallback) => { | ||
cb({ ...params, camera: unref(camera) as TresCamera, scene: unref(scene), renderer: unref(renderer), raycaster: unref(raycaster), controls: unref(controls), invalidate, advance }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If possible, it's probably be best to avoid wrapping the callback.
Currently, for every callback function in every frame, this code is recreating the argument object.
The argument object only needs to be created once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andretchen0 how do we get the latest context if we are returning the plain values? if we called once on the onLoop is only going to return the snapshot of the context at that specific moment.
src/composables/useRenderer/index.ts
Outdated
@@ -274,13 +250,33 @@ export function useRenderer( | |||
} | |||
}) | |||
|
|||
// Register loop |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For separation of concerns, I'd move this somewhere else.
Almost all core code has access to the renderer, so this could live just about anywhere.
On the other hand, useRenderer
has to be passed render
, loop
, invalidate
, advance
, in order to do loop.register
.
src/composables/useLoop/index.ts
Outdated
function render(cb: Fn) { | ||
const wrappedCallback = wrapCallback(cb) | ||
const { off } = loop.register(wrappedCallback, 'render') | ||
return { off } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can't be off
ed.
playground/src/components/TakeOverLoopExperience.vue
<script setup lang="ts">
import { useLoop } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'
import { useControls } from '@tresjs/leches'
const { render, pauseRender, resumeRender } = useLoop()
const off = render(({ renderer, scene, camera }) => {
console.log('on')
renderer.render(scene, camera)
}).off
setTimeout(() => {off(); console.log('offing')}, 1000)
const { isRenderPaused } = useControls({
isRenderPaused: {
value: false,
type: 'boolean',
label: 'Pause Render',
},
})
watchEffect(() => {
if (isRenderPaused.value) {
pauseRender()
}
else {
resumeRender()
}
})
</script>
<template>
<TresPerspectiveCamera :position="[3, 3, 3]" />
<OrbitControls />
<AnimatedObjectUseUpdate />
<TresAmbientLight :intensity="1" /> />
<TresGridHelper />
</template>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @andretchen0 please check the discord discussion
…to `useRender`" This reverts commit 24cec65.
…er with defaultFn fallback
BREAKING_CHANGE: Directives `vAlwaysLookAt` and `vRotate` due incompatibility with new `useLoop` and the refactor of the render loop logic.
* feat: 474 vue chrome devtools plugin (#479) * feat: vue chrome devtools * feat: editable scenes from devtools * chore(lint): fix lint errors * feat: highlight material * chore(lint): fix * chore: release v4.0.0-next.0 * feat: update to three `v160` and vue `v3.4` (#488) * fix(types): added `Object3DEventMap` to `Object3D` generics for point event handling (#491) * feat: 140 on demand rendering (#497) * feat: conditional rendering * chore: remove subscribe system * feat: on-demand automatic invalidation with prop changes * feat: invalidate once first when is `renderMode !== 'always'` * docs: performance page, on-demand rendering * chore: fix windowsize issue * chore(lint): fix maximum line length issues * feat: invalidate on-demand on window resize * feat: add advance method for manual mode * feat: fix manual first render with advance * docs: performance manual mode * docs: add badge with version * chore: correct typos and PR suggestions * chore: tell dont ask fix * feat: render state instead of internal * feat: remove default camera warning (#499) * feat: remove annoying defautl camera warning * chore: remove logWarning * feat: 492 set tone mapping default to acesfilmictonemapping (#498) * feat: set ACESFilmicToneMapping as default toneMapping * chore: usage of nullish coealescing operator instead of ternaries * feat: 516 localstate for custom renderer node instances instead of userdata (#522) * feat: conditional rendering * chore: remove subscribe system * feat: on-demand automatic invalidation with prop changes * feat: invalidate once first when is `renderMode !== 'always'` * docs: performance page, on-demand rendering * chore: fix windowsize issue * chore(lint): fix maximum line length issues * feat: invalidate on-demand on window resize * feat: add advance method for manual mode * feat: fix manual first render with advance * docs: performance manual mode * docs: add badge with version * chore: correct typos and PR suggestions * chore: tell dont ask fix * feat: render state instead of internal * feat: add __tres local state to nodeOps instances * feat: add context to root on instances localstate * feat: camera registration ops from node local state ctx * feat: event handling registration from localState of nodes * feature: disposable flag on node localstate * feat: remove userData from types * chore: remove unused import * fix(test): fake localstate `.__tres` on tests * fix(types): fix nodeOps instances localstate type * fix: camera aspect * Update orthographic camera aspect when screen size updates * Give user a "manual" flag to keep Tres from updating camera * feat: 503 conditional rendering of primitives (#514) * feat(nodeOps): switch instance logic for reactive `object` prop * chore: playground primitives with models * chore: fix linter * chore: fix tests and linters, primitive object is now reactive * chore: refactor instance swaping logic to overwrite set and copy properties * chore: tests * chore: remove console.log * chore: remove unused import watch * feat: add primitive conditional to patch object prop * fix: `nodeOps` is now a function (#579) * fix: `nodeOps` is now a function * chore(test): updated tests for `nodeOps` * chore: next package json version * chore: release v4.0.0-next.1 * fix: refactor nodeOps to return methods at the end of the function (#602) * fix: refactor nodeOps to return methods at the end of the function * chore: fix lint * chore: internal playground organisation (#601) * chore: new internal playground org and testing pages * chore: fix lint * chore: better styling of playground landing page * chore: lint * chore: deps update * chore: internal primitive model test playground * chore: fix lint * chore: release v4.0.0-next.2 * chore: misc routes * fix: do not change pierced props case (#608) * chore: lint fix * chore: problem with package version * chore: fix lint * chore: rebuild pnpm-lock * test(nodeOps): clean up tests * test(nodeOps): organize tests * test: add coverage plugin * test: add coverage to package.json script * test(nodeOps): improve test coverage * feat: devtools renderer improvements (#614) * feat: renderer programs when selecting scene on devtools * feat: renderer.info * chore: fix lint * docs: devtools update * chore: fix lint issues * feat(events)!: pointerevents manager and state (#529) * new file: playground/src/components/Box.vue new file: playground/src/pages/raycaster/Propogation.vue * Started work on interactive Event Propogation playground example modified: src/components/TresCanvas.vue * Import and use `useEventStore` * defineEmits for all expected pointer events so we may emit propogated events off of the canvasa modified: src/composables/index.ts new file: src/composables/useEventStore/index.ts * Started work on an event store. I'm not sure this counts as a store just yet * Wired up majority of pointer events * Added event propogation * Does not require using userData scene props or nodeOps for registering objects to scene modified: src/composables/useRaycaster/index.ts * Added new event listeners to power newly supported pointer events. We now check whole scene/children when calling intersectObjects. * Created new EventHooks for new events * Added `forceUpdate` function that allows for pointer-move events to work without mouth movement (good for when camera is moving but mouse is not) modified: src/core/nodeOps.ts * Added supported events to array so they don't get received as props * (temporarily) unhook current pointer event solution to iterate on useEventStore modified: src/utils/index.ts * Added Camel-to-kebab case util * Support multiple event listeners, add support for .stop event modifier * Set stopProgation variable to false by default, whoops * fix typo * fix: remove `createGlobalState` from `useEventStore`, allowing events to work while multiple TresCanvas' are being used * fix(perf): remove extraneous intersectObjects/getIntersects calls by moving intersects into a ref that is updated on pointer-move * chore(lint): fix lint issues * feat: enhance events manager to include duplicates checking, pointer-missed support, and forced updating Per file changelog: modified: playground/src/components/Box.vue * Added a pointer-missed handler for testing modified: playground/src/pages/TheBasic.vue * uses forceUpdate from EventManager to fire events even when the mouse hasn't moved modified: playground/src/pages/raycaster/Propagation.vue * Didn't mean to undo the lint changes, adds a pointer-missed event on the canvas for extra testing modified: src/components/TresCanvas.vue * Adds `pointer-missed` as possible event for canvas emits modified: src/composables/index.ts * Update export deleted: src/composables/useEventStore/index.ts * Rename `useEventStore` to `useTresEventManager` modified: src/composables/useRaycaster/index.ts * Check for empty intersects on hit test, wire up pointerMissed events eventHook * Fix forceUpdate to call onPointerMove instead of triggering an EventHook modified: src/composables/useTresContextProvider/index.ts * Add TresEventManager type new file: src/composables/useTresEventManager/index.ts * add onPointerMissed * create (de)registerPointerMissedObj methods so we can track objects in the scene listening to this event * Note: These are passed to nodeOps via TresContext * Implement duplicates checking for eventPropogation modified: src/core/nodeOps.ts * register/deregister pointerMissed objects * chore: lint * docs: new event docs * chore: fix lint * feat: enhance event object details and use in Box example to change material color. Add ability to force event system updates even when mouse hasn't moved. Enhance pointer-enter/leave events. Update types Box.vue * Added pointer-missed handler * set the materials flash color using the object coming off of the event instead of a ref UseRaycaster * Flesh out event details to include * all mouse event properties * intersections * tres camera * camera raycaster * source event * mouse position delta * stopPropagating stub * and unprojectedPoint (this needs work, cant get the math to work) UseTresContextProvider * Add TresEventManager type to TresContext useTresEventManager * Add forceUpdate method to allow apps to force an event system update even when the mouse hasnt moved * Add pointerMissed event * Properly implement pointer-enter/pointer-leave events * Before now, pointer-enter | leave were only called on first object in intersection, now we execute the events for all entered/left objects * Use stopPropagating property included on event object * chore: lint * chore: fix lint issues --------- Co-authored-by: alvarosabu <[email protected]> * feat: 499 better memory management (#606) * chore: memory management playground * feat: recursively free cpu and gpu memory allocation on remove * chore: clumsy attempt to dispose on unmount * chore: lint fix * feat: remove scene root on disposal * chore: fix lint * docs: added disposal guide on `performance` docs * chore: fix lint * chore: type issues (#663) * fix: fix some internal types * chore: fix linters * fix: typescript issues on event manager * chore: release v4.0.0-rc.0 * fix: make on* callbacks settable (#672) * fix: make on- callbacks settable * test: test setting not calling * feat: 633 use loop (#673) * feat: createRenderLoop unique to context * feat: onLoop returns current state * feat: ensuring callback excecution with index order * feat: take control of render loop logic * docs: updated composable docs * feat: change error to deprecation warning towards v5 * chore: add link to new composable docs on deprecation warning * chore: remove depcreation warning of existing useRenderLoop * feat: `useFrame` and `useRender` instead of `onLoop` * chore: fix lint * feat: applied useFrame to directives * chore: fix lint * feat: `useUpdate` instead of `useFrame` and useRender pausing. * chore: testing fbo * feat: reserve index 1 for late-updates * chore: fix lint * feat: useLoop composable for the win * chore: change onLoop name for register * chore: unit tests for loop * chore: change order for registration to make index optional * chore: fix lint * feat: pauseRender and resumeRender * docs: useLoop guide * docs: updated basic animations recipe to `useLoop` * docs: correct pause render methods on docs * Update docs/api/composables.md Co-authored-by: Tino Koch <[email protected]> * Update docs/api/composables.md Co-authored-by: Tino Koch <[email protected]> * Update docs/api/composables.md Co-authored-by: Tino Koch <[email protected]> * Update docs/api/composables.md Co-authored-by: Tino Koch <[email protected]> * Update docs/api/composables.md Co-authored-by: Tino Koch <[email protected]> * Update docs/api/composables.md Co-authored-by: Tino Koch <[email protected]> * Update docs/api/composables.md Co-authored-by: Tino Koch <[email protected]> * chore: refactor subscribers to `priorityEventHooks` * Update docs/api/composables.md Co-authored-by: Tino Koch <[email protected]> * feat: just return `off` on the loop registration methods * docs: update docs to add `off` unregister callback method * feat: remove `v-rotate` * docs: added context warning for `v-always-look-at` * Update docs/api/composables.md Co-authored-by: Tino Koch <[email protected]> * Update docs/api/composables.md Co-authored-by: Tino Koch <[email protected]> * chore: remove leftover of isntance.provide * chore: remove subscribers from context * chore: abstract `wrapCallback` and move render loop register to `useRender` * chore: fix lint * chore: testing off * Revert "chore: abstract `wrapCallback` and move render loop register to `useRender`" This reverts commit 24cec65. * chore: return bound `off` method and use createPriorityEvent for render with defaultFn fallback * feat: deprecate and remove `vAlwaysLookAt` and `vRotate` BREAKING_CHANGE: Directives `vAlwaysLookAt` and `vRotate` due incompatibility with new `useLoop` and the refactor of the render loop logic. * feat: set context to loop to avoid wrapping the callbacks * feat: dispose render hook before taking over --------- Co-authored-by: Tino Koch <[email protected]> * chore(playground): adding missing import and removing the directives that were deprecated * chore(playground): use new composable on animations * fix(utils): reorder object disposal to avoid issue with Helper `dispose` methods (#683) * chore: updated deps * chore: release v4.0.0-rc.1 * fix: manual rendering blank (#685) * fix: increate time to advance on manual mode * chore: correct playground * fix: 686 useloop callback state missing controls (#687) * fix(loop): take plain snapshots of ctx * fix: types for useloop * chore: lint * docs: add RectAreaLightHelper to vLightHelper docs * chore(deps): update deps 24-0-2024 * chore: release v4.0.0-rc.2 * fix: start loop if user calls useRenderLoop (#695) * docs: change motivation * chore(deps): last update before release --------- Co-authored-by: Peter <[email protected]> Co-authored-by: Garrett Walker <[email protected]> Co-authored-by: Tino Koch <[email protected]> Co-authored-by: Jaime Torrealba <[email protected]> Co-authored-by: Jaime A Torrealba C <[email protected]>
Hopefully Closes #633
Based on the team discussion. This PR introduces a new API
useLoop
This composable allows you to execute a callback on every frame, similar to
useRenderLoop
but unique to each TresCanvas instance and with access to the context.Warning
useLoop
can only be used inside of aTresCanvas
since this component acts as the provider for the context data.Usage
Register update callbacks
The user can register update callbacks (such as animations, fbo, etc) using the
onBeforeRender
Take over the render loop
The user can take over the render loop callback by using the
render
methodNote
To run this example please run the playground and go to http://localhost:5173/advanced/take-over-loop
Register after render callbacks (ex physics calculations)
The user can also register after rendering callbacks using the
onAfterRender
Priority mechanism
Both
useBeforeRender
anduseAfteRender
provide an optional priority index. This indexes could be any from[Number.NEGATIVE_INFINITY ... 0 ... Number.NEGATIVE_INFINITY]
For example, to use Frame Object Buffer (FBO) is convenient to use a very big number to ensure that all updates happen before the FBO callback and the last one just before the scene render.
Note
To run this example (FBO) please run the playground and go to http://localhost:5173/advanced/fbo`
Pausing and resuming the loop
The end user can use
pause
andresume
methods:Pausing and resuming the render
You can use
pauseRender
andresumeRender
methods:Pending