Skip to content

Commit

Permalink
feat: 516 localstate for custom renderer node instances instead of us…
Browse files Browse the repository at this point in the history
…erdata (#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
  • Loading branch information
alvarosabu authored Feb 1, 2024
1 parent c4547f9 commit 08717ef
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 117 deletions.
1 change: 1 addition & 0 deletions playground/src/components/TheExperience.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ watchEffect(() => {
:rotation="[-Math.PI / 2, 0, Math.PI / 2]"
name="floor"
receive-shadow
@click="wireframe = !wireframe"
>
<TresPlaneGeometry :args="[20, 20, 20]" />
<TresMeshToonMaterial
Expand Down
2 changes: 1 addition & 1 deletion src/components/TresCanvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ onMounted(() => {
emit,
})
usePointerEventHandler({ scene: scene.value, contextParts: context.value })
usePointerEventHandler(context.value)
const { registerCamera, camera, cameras, deregisterCamera } = context.value
Expand Down
3 changes: 0 additions & 3 deletions src/composables/useCamera/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ export const useCamera = ({ sizes, scene }: Pick<TresContext, 'sizes'> & { scene
}
})

scene.userData.tres__registerCamera = registerCamera
scene.userData.tres__deregisterCamera = deregisterCamera

onUnmounted(() => {
cameras.value = []
})
Expand Down
24 changes: 10 additions & 14 deletions src/composables/usePointerEventHandler/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Intersection, Object3D, Object3DEventMap } from 'three'
import type { TresScene } from 'src/types'
import { computed, reactive, ref } from 'vue'
import { uniqueBy } from '../../utils'
import { useRaycaster } from '../useRaycaster'
Expand All @@ -17,11 +16,7 @@ export interface EventProps {
}

export const usePointerEventHandler = (
{ scene, contextParts }:
{
scene: TresScene
contextParts: Pick<TresContext, 'renderer' | 'camera' | 'raycaster'>
},
ctx: TresContext,
) => {
const objectsWithEventListeners = reactive({
click: new Map<Object3D<Object3DEventMap>, CallbackFn>(),
Expand Down Expand Up @@ -54,13 +49,6 @@ export const usePointerEventHandler = (
if (onPointerLeave) objectsWithEventListeners.pointerLeave.set(object, onPointerLeave)
}

// to make the registerObject available in the custom renderer (nodeOps), it is attached to the scene
scene.userData.tres__registerAtPointerEventHandler = registerObject
scene.userData.tres__deregisterAtPointerEventHandler = deregisterObject

scene.userData.tres__registerBlockingObjectAtPointerEventHandler = registerBlockingObject
scene.userData.tres__deregisterBlockingObjectAtPointerEventHandler = deregisterBlockingObject

const objectsToWatch = computed(() =>
uniqueBy(
[
Expand All @@ -73,7 +61,13 @@ export const usePointerEventHandler = (
),
)

const { onClick, onPointerMove } = useRaycaster(objectsToWatch, contextParts)
// 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
ctx.registerObjectAtPointerEventHandler = registerObject
ctx.deregisterObjectAtPointerEventHandler = deregisterObject
ctx.registerBlockingObjectAtPointerEventHandler = registerBlockingObject
ctx.deregisterBlockingObjectAtPointerEventHandler = deregisterBlockingObject

const { onClick, onPointerMove } = useRaycaster(objectsToWatch, ctx)

onClick(({ intersects, event }) => {
if (intersects.length) objectsWithEventListeners.click.get(intersects[0].object)?.(intersects[0], event)
Expand Down Expand Up @@ -101,5 +95,7 @@ export const usePointerEventHandler = (
return {
registerObject,
deregisterObject,
registerBlockingObject,
deregisterBlockingObject,
}
}
10 changes: 5 additions & 5 deletions src/composables/useRaycaster/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ interface PointerClickEventPayload {

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

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

Expand All @@ -39,11 +39,11 @@ export const useRaycaster = (
}

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

raycaster.value.setFromCamera(new Vector2(x, y), camera.value)
ctx.raycaster.value.setFromCamera(new Vector2(x, y), ctx.camera.value)

return raycaster.value.intersectObjects(objects.value, false)
return ctx.raycaster.value.intersectObjects(objects.value, false)
}

const getIntersects = (event?: PointerEvent | MouseEvent) => {
Expand Down
26 changes: 19 additions & 7 deletions src/composables/useTresContextProvider/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { toValue, useElementSize, useFps, useMemory, useRafFn, useWindowSize, refDebounced } from '@vueuse/core'
import { inject, provide, readonly, shallowRef, computed, ref, onUnmounted, watchEffect } from 'vue'
import type { Camera, EventDispatcher, Scene, WebGLRenderer } from 'three'
import type { Camera, EventDispatcher, Object3D, WebGLRenderer } from 'three'
import { Raycaster } from 'three'
import type { ComputedRef, DeepReadonly, MaybeRef, MaybeRefOrGetter, Ref, ShallowRef } from 'vue'
import { calculateMemoryUsage } from '../../utils/perf'
Expand All @@ -9,6 +9,8 @@ import type { UseRendererOptions } from '../useRenderer'
import { useRenderer } from '../useRenderer'
import { extend } from '../../core/catalogue'
import { useLogger } from '../useLogger'
import type { TresScene } from '../../types'
import type { EventProps } from '../usePointerEventHandler'

export interface InternalState {
priority: Ref<number>
Expand Down Expand Up @@ -43,7 +45,7 @@ export interface PerformanceState {
}

export interface TresContext {
scene: ShallowRef<Scene>
scene: ShallowRef<TresScene>
sizes: { height: Ref<number>; width: Ref<number>; aspectRatio: ComputedRef<number> }
extend: (objects: any) => void
camera: ComputedRef<Camera | undefined>
Expand All @@ -61,9 +63,17 @@ export interface TresContext {
* Advance one frame when renderMode === 'manual'
*/
advance: () => void
// Camera
registerCamera: (camera: Camera) => void
setCameraActive: (cameraOrUuid: Camera | string) => void
deregisterCamera: (camera: Camera) => void
// Events
// 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
// When thats done maybe we can short the names of the methods since the parent will give the context.
registerObjectAtPointerEventHandler: (object: Object3D & EventProps) => void
deregisterObjectAtPointerEventHandler: (object: Object3D) => void
registerBlockingObjectAtPointerEventHandler: (object: Object3D) => void
deregisterBlockingObjectAtPointerEventHandler: (object: Object3D) => void
}

export function useTresContextProvider({
Expand All @@ -74,7 +84,7 @@ export function useTresContextProvider({
rendererOptions,
emit,
}: {
scene: Scene
scene: TresScene
canvas: MaybeRef<HTMLCanvasElement>
windowSize: MaybeRefOrGetter<boolean>
disableRender: MaybeRefOrGetter<boolean>
Expand Down Expand Up @@ -109,7 +119,7 @@ export function useTresContextProvider({
width: computed(() => debouncedReactiveSize.value.width),
aspectRatio,
}
const localScene = shallowRef<Scene>(scene)
const localScene = shallowRef<TresScene>(scene)
const {
camera,
cameras,
Expand All @@ -121,7 +131,7 @@ export function useTresContextProvider({
// Render state

const render: RenderState = {
mode: ref<'always' | 'on-demand' | 'manual'>(rendererOptions.renderMode || 'always'),
mode: ref(rendererOptions.renderMode || 'always') as Ref<'always' | 'on-demand' | 'manual'>,
priority: ref(0),
frames: ref(0),
maxFrames: 60,
Expand Down Expand Up @@ -189,8 +199,10 @@ export function useTresContextProvider({

provide('useTres', ctx)

// Add context to scene.userData
ctx.scene.value.userData.tres__context = ctx
// Add context to scene local state
ctx.scene.value.__tres = {
root: ctx,
}

// Performance
const updateInterval = 100 // Update interval in milliseconds
Expand Down
Loading

0 comments on commit 08717ef

Please sign in to comment.