-
-
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: 140 on demand rendering #497
Conversation
TresCanvas now emits a <TresCanvas render-mode="on-demand" clear-color="#82DBC5" @render="onRender" > Maybe should we include an |
Hey! I'm having a look. Maybe I just need more context, but on a first read through, I'm wondering: For the (My mental representation of this functionality is "mark frame as dirty", so "invalidate" makes more intuitive sense to me than "advance".) Merging under
... can just chug right along. Whereas currently, I think we'd need to switch over the render mode, e.g.:
|
Hi @andretchen0 thanks for the feedback. Honestly I had the same dilemma as you, I added the I think is because when you are When The That being said, maybe makes more sense to change function advance() {
if (rendererOptions.renderMode === 'manual') {
renderer.value.render(scene.value,camera.value)
}
else {
logWarning('`advance` can only be used when `renderMode` is set to `manual`')
}
} Regarding switching between render mode on the fly, do you see it as a common use-case? |
Gotcha. No problem. If other libraries are using a separate method, then maybe there's a good reason.
I don't see it as a common use case, but people are surprising! ;) |
Hi @andretchen0 and @Tinoooo, I'm currently facing some performance issues on the devtools (creating the scene graph and reactivity) because I'm sending an event to the devtools every time it renders. Should we set "on-demand" rendering as default? wdyt? |
Maybe a fourth mode would make sense, where the render stops, when the current tab/window is not active anymore. This would prevent the scene rendering in the background, eating up performance and draining the users battery. The It's also worth mentioning, that |
I'd prefer "always" as the default, if possible. "always" matches my starting assumption for how rendering works: always throw away the last frame and render a new frame. Assuming my understanding of "on-demand" is correct, I think I'd be confused if I e.g., wrote a shader and then found it wasn't updating consistently because it wasn't hooked to a prop. |
You are right, also, we would need to refactor practically the ecosystem to be on-demand first, like OrbitControls and such. Let's keep |
@thomasaull That is a brilliant idea, I would probably add it to one of the current states instead of a new one. ☝️ |
@andretchen0 @thomasaull @Tinoooo what do you think? Should we create a new rendering mode like |
Hmm, I could imagine use cases for all modes that you want to pause rendering in the background. If it were up to me I'd probably add another prop like |
Is this not the way (Fwiw, I mostly work on Cientos and I'm not familiar with a lot of the Tres internals, so maybe I'm not looking/tinkering in the right spot.) |
@andretchen0 good point, you are right, I just check how many times it renders when I change tab and it stopped. |
@andretchen0 @alvarosabu In my tests with |
Sounds handy to me. Maybe getting to big for this PR, but ...:
|
That's why I want to consider it. But I agree with you, maybe we should create a different ticket for it. @thomasaull or @andretchen0 would you be so kind as to create a feature request? @andretchen0 can we merge this on v4? |
Will do.
I'll have a look at the code later today. |
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.
Nice job! Looks to me like everything's working. I wasn't able to break the functionality.
The comments are either typos or some code quality stuff that you can accept or ignore – I won't block the PR. It's been lingering long enough; I don't want to stand in the way.
@@ -8,6 +8,26 @@ import { useCamera } from '../useCamera' | |||
import type { UseRendererOptions } from '../useRenderer' | |||
import { useRenderer } from '../useRenderer' | |||
import { extend } from '../../core/catalogue' | |||
import { useLogger } from '../useLogger' | |||
|
|||
export interface InternalState { |
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 future readability/understandability, can we make this more descriptive? It's linked to renderMode
, so maybe renderModeState
?
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 if the name renderModeState
is meant to add clarity that the property isn't just a static setting but potentially a reactive state that could change over time, then we should rename most of the properties inside the TresContext
type to state, like controlsState
and rendererState
etc.
Imo being inside of the TresContext
which is already a state implies its nature without the need to add extra verbosity.
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 @alvarosabu
I'd be fine with dropping State
off the end, as most variables are some sort of state. (But then the name renderMode
will collide with the other renderMode
.)
The current name – internalState
– doesn't say anything about what the object is used for. Since it's about renderMode
-stuff, I thought that'd make it more obvious to future readers.
But no problem leaving it as is.
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 True, internal
doesn't give enough context. 🤔 Let's continue this exercise, then, what if we rename the InternalState
to RenderState
and add everything related to it inside?
export interface RenderState {
mode: Ref<'always' | 'on-demand' | 'manual'>
priority: Ref<number>
frames: Ref<number>
maxFrames: number
canBeInvalidated: ComputedRef<boolean>
invalidate: () => void
advance: () => void
}
I think it would be cleaner.
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.
Sounds good!
* If set to 'always', the scene will be rendered every frame | ||
*/ | ||
renderMode: Ref<'always' | 'on-demand' | 'manual'> | ||
internal: InternalState |
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.
Like the type, can we make this field name more descriptive? Maybe renderModeState
?
Hey, buddy @andretchen0 I refactored |
Hey! I think that's clearer than |
Way better |
* 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]>
This PR introduces the concept of conditional rendering. It closes #140
The
renderMode
prop has been added to theTresCanvas
component with 3 different options:always
the default one (current solution)on-demand
will automatically invalidate the frame on:manual
: theinvalidate
method needs to be called by the user to trigger a render.TresCanvas now emits a
render
event:I'm still finishing the docs, you can start taking a look to it.