Skip to content

Commit 08717ef

Browse files
authored
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
1 parent c4547f9 commit 08717ef

File tree

9 files changed

+143
-117
lines changed

9 files changed

+143
-117
lines changed

playground/src/components/TheExperience.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ watchEffect(() => {
6464
:rotation="[-Math.PI / 2, 0, Math.PI / 2]"
6565
name="floor"
6666
receive-shadow
67+
@click="wireframe = !wireframe"
6768
>
6869
<TresPlaneGeometry :args="[20, 20, 20]" />
6970
<TresMeshToonMaterial

src/components/TresCanvas.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ onMounted(() => {
136136
emit,
137137
})
138138
139-
usePointerEventHandler({ scene: scene.value, contextParts: context.value })
139+
usePointerEventHandler(context.value)
140140
141141
const { registerCamera, camera, cameras, deregisterCamera } = context.value
142142

src/composables/useCamera/index.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ export const useCamera = ({ sizes, scene }: Pick<TresContext, 'sizes'> & { scene
5050
}
5151
})
5252

53-
scene.userData.tres__registerCamera = registerCamera
54-
scene.userData.tres__deregisterCamera = deregisterCamera
55-
5653
onUnmounted(() => {
5754
cameras.value = []
5855
})

src/composables/usePointerEventHandler/index.ts

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { Intersection, Object3D, Object3DEventMap } from 'three'
2-
import type { TresScene } from 'src/types'
32
import { computed, reactive, ref } from 'vue'
43
import { uniqueBy } from '../../utils'
54
import { useRaycaster } from '../useRaycaster'
@@ -17,11 +16,7 @@ export interface EventProps {
1716
}
1817

1918
export const usePointerEventHandler = (
20-
{ scene, contextParts }:
21-
{
22-
scene: TresScene
23-
contextParts: Pick<TresContext, 'renderer' | 'camera' | 'raycaster'>
24-
},
19+
ctx: TresContext,
2520
) => {
2621
const objectsWithEventListeners = reactive({
2722
click: new Map<Object3D<Object3DEventMap>, CallbackFn>(),
@@ -54,13 +49,6 @@ export const usePointerEventHandler = (
5449
if (onPointerLeave) objectsWithEventListeners.pointerLeave.set(object, onPointerLeave)
5550
}
5651

57-
// to make the registerObject available in the custom renderer (nodeOps), it is attached to the scene
58-
scene.userData.tres__registerAtPointerEventHandler = registerObject
59-
scene.userData.tres__deregisterAtPointerEventHandler = deregisterObject
60-
61-
scene.userData.tres__registerBlockingObjectAtPointerEventHandler = registerBlockingObject
62-
scene.userData.tres__deregisterBlockingObjectAtPointerEventHandler = deregisterBlockingObject
63-
6452
const objectsToWatch = computed(() =>
6553
uniqueBy(
6654
[
@@ -73,7 +61,13 @@ export const usePointerEventHandler = (
7361
),
7462
)
7563

76-
const { onClick, onPointerMove } = useRaycaster(objectsToWatch, contextParts)
64+
// Temporaly add the methods to the context, this should be handled later by the EventManager state on the context https://github.com/Tresjs/tres/issues/515
65+
ctx.registerObjectAtPointerEventHandler = registerObject
66+
ctx.deregisterObjectAtPointerEventHandler = deregisterObject
67+
ctx.registerBlockingObjectAtPointerEventHandler = registerBlockingObject
68+
ctx.deregisterBlockingObjectAtPointerEventHandler = deregisterBlockingObject
69+
70+
const { onClick, onPointerMove } = useRaycaster(objectsToWatch, ctx)
7771

7872
onClick(({ intersects, event }) => {
7973
if (intersects.length) objectsWithEventListeners.click.get(intersects[0].object)?.(intersects[0], event)
@@ -101,5 +95,7 @@ export const usePointerEventHandler = (
10195
return {
10296
registerObject,
10397
deregisterObject,
98+
registerBlockingObject,
99+
deregisterBlockingObject,
104100
}
105101
}

src/composables/useRaycaster/index.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ interface PointerClickEventPayload {
2020

2121
export const useRaycaster = (
2222
objects: Ref<THREE.Object3D[]>,
23-
{ renderer, camera, raycaster }: Pick<TresContext, 'renderer' | 'camera' | 'raycaster'>,
23+
ctx: TresContext,
2424
) => {
2525
// having a separate computed makes useElementBounding work
26-
const canvas = computed(() => renderer.value.domElement as HTMLCanvasElement)
26+
const canvas = computed(() => ctx.renderer.value.domElement as HTMLCanvasElement)
2727

2828
const { x, y } = usePointer({ target: canvas })
2929

@@ -39,11 +39,11 @@ export const useRaycaster = (
3939
}
4040

4141
const getIntersectsByRelativePointerPosition = ({ x, y }: { x: number; y: number }) => {
42-
if (!camera.value) return
42+
if (!ctx.camera.value) return
4343

44-
raycaster.value.setFromCamera(new Vector2(x, y), camera.value)
44+
ctx.raycaster.value.setFromCamera(new Vector2(x, y), ctx.camera.value)
4545

46-
return raycaster.value.intersectObjects(objects.value, false)
46+
return ctx.raycaster.value.intersectObjects(objects.value, false)
4747
}
4848

4949
const getIntersects = (event?: PointerEvent | MouseEvent) => {

src/composables/useTresContextProvider/index.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { toValue, useElementSize, useFps, useMemory, useRafFn, useWindowSize, refDebounced } from '@vueuse/core'
22
import { inject, provide, readonly, shallowRef, computed, ref, onUnmounted, watchEffect } from 'vue'
3-
import type { Camera, EventDispatcher, Scene, WebGLRenderer } from 'three'
3+
import type { Camera, EventDispatcher, Object3D, WebGLRenderer } from 'three'
44
import { Raycaster } from 'three'
55
import type { ComputedRef, DeepReadonly, MaybeRef, MaybeRefOrGetter, Ref, ShallowRef } from 'vue'
66
import { calculateMemoryUsage } from '../../utils/perf'
@@ -9,6 +9,8 @@ import type { UseRendererOptions } from '../useRenderer'
99
import { useRenderer } from '../useRenderer'
1010
import { extend } from '../../core/catalogue'
1111
import { useLogger } from '../useLogger'
12+
import type { TresScene } from '../../types'
13+
import type { EventProps } from '../usePointerEventHandler'
1214

1315
export interface InternalState {
1416
priority: Ref<number>
@@ -43,7 +45,7 @@ export interface PerformanceState {
4345
}
4446

4547
export interface TresContext {
46-
scene: ShallowRef<Scene>
48+
scene: ShallowRef<TresScene>
4749
sizes: { height: Ref<number>; width: Ref<number>; aspectRatio: ComputedRef<number> }
4850
extend: (objects: any) => void
4951
camera: ComputedRef<Camera | undefined>
@@ -61,9 +63,17 @@ export interface TresContext {
6163
* Advance one frame when renderMode === 'manual'
6264
*/
6365
advance: () => void
66+
// Camera
6467
registerCamera: (camera: Camera) => void
6568
setCameraActive: (cameraOrUuid: Camera | string) => void
6669
deregisterCamera: (camera: Camera) => void
70+
// Events
71+
// Temporaly add the methods to the context, this should be handled later by the EventManager state on the context https://github.com/Tresjs/tres/issues/515
72+
// When thats done maybe we can short the names of the methods since the parent will give the context.
73+
registerObjectAtPointerEventHandler: (object: Object3D & EventProps) => void
74+
deregisterObjectAtPointerEventHandler: (object: Object3D) => void
75+
registerBlockingObjectAtPointerEventHandler: (object: Object3D) => void
76+
deregisterBlockingObjectAtPointerEventHandler: (object: Object3D) => void
6777
}
6878

6979
export function useTresContextProvider({
@@ -74,7 +84,7 @@ export function useTresContextProvider({
7484
rendererOptions,
7585
emit,
7686
}: {
77-
scene: Scene
87+
scene: TresScene
7888
canvas: MaybeRef<HTMLCanvasElement>
7989
windowSize: MaybeRefOrGetter<boolean>
8090
disableRender: MaybeRefOrGetter<boolean>
@@ -109,7 +119,7 @@ export function useTresContextProvider({
109119
width: computed(() => debouncedReactiveSize.value.width),
110120
aspectRatio,
111121
}
112-
const localScene = shallowRef<Scene>(scene)
122+
const localScene = shallowRef<TresScene>(scene)
113123
const {
114124
camera,
115125
cameras,
@@ -121,7 +131,7 @@ export function useTresContextProvider({
121131
// Render state
122132

123133
const render: RenderState = {
124-
mode: ref<'always' | 'on-demand' | 'manual'>(rendererOptions.renderMode || 'always'),
134+
mode: ref(rendererOptions.renderMode || 'always') as Ref<'always' | 'on-demand' | 'manual'>,
125135
priority: ref(0),
126136
frames: ref(0),
127137
maxFrames: 60,
@@ -189,8 +199,10 @@ export function useTresContextProvider({
189199

190200
provide('useTres', ctx)
191201

192-
// Add context to scene.userData
193-
ctx.scene.value.userData.tres__context = ctx
202+
// Add context to scene local state
203+
ctx.scene.value.__tres = {
204+
root: ctx,
205+
}
194206

195207
// Performance
196208
const updateInterval = 100 // Update interval in milliseconds

0 commit comments

Comments
 (0)