Skip to content

Commit

Permalink
added invalidation on pass changes for native three effects
Browse files Browse the repository at this point in the history
  • Loading branch information
Tinoooo committed Sep 12, 2024
1 parent d484912 commit 8e9c534
Show file tree
Hide file tree
Showing 8 changed files with 27 additions and 18 deletions.
2 changes: 1 addition & 1 deletion playground/src/components/BasicScene.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defineProps<{
</script>

<template>
<TresCanvas>
<TresCanvas render-mode="on-demand">
<TresPerspectiveCamera
:position="[5, 5, 5]"
:look-at="[0, 0, 0]"
Expand Down
8 changes: 3 additions & 5 deletions src/core/pmndrs/composables/useEffect.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useTresContext } from '@tresjs/core'
import { EffectPass } from 'postprocessing'
import { inject, onUnmounted, shallowRef, watchEffect } from 'vue'
import { inject, nextTick, onUnmounted, shallowRef, watchEffect } from 'vue'
import type { Effect } from 'postprocessing'
import type { ShallowRef } from 'vue'
import { effectComposerInjectionKey } from '../EffectComposer.vue'
Expand All @@ -21,12 +21,10 @@ export const useEffect = <T extends Effect>(newEffectFunction: () => T): {
effect.value.mainCamera = camera.value
})

let unwatch = () => {} // seperate declaration prevents error in HMR

unwatch = watchEffect(() => {
const unwatch = watchEffect(() => {
if (!camera.value || !composer?.value || !scene.value) { return }

unwatch()
nextTick(() => unwatch())
if (effect.value) { return }

effect.value = newEffectFunction()
Expand Down
2 changes: 1 addition & 1 deletion src/core/three/Glitch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface GlitchProps {
<script lang="ts" setup>
const props = defineProps<GlitchProps>()
const { pass } = useEffect(() => new GlitchPass(props.dtSize))
const { pass } = useEffect(() => new GlitchPass(props.dtSize), props)
defineExpose({ pass })
Expand Down
3 changes: 2 additions & 1 deletion src/core/three/Halftone.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ const { pass } = useEffect(() => new HalftonePass(
sizes.width.value,
sizes.height.value,
shakedProps.value,
))
), props)
defineExpose({ pass })
watchEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/core/three/Pixelation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const props = defineProps<PixelationProps>()
const { scene, camera } = useTresContext()
const { pass } = useEffect(() => new RenderPixelatedPass(props.pixelSize, scene.value, camera.value!))
const { pass } = useEffect(() => new RenderPixelatedPass(props.pixelSize, scene.value, camera.value!), props)
defineExpose({ pass })
Expand Down
2 changes: 1 addition & 1 deletion src/core/three/SMAA.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const { pixelRatio } = useDevicePixelRatio() // the renderers pixel ratio is not
const width = computed(() => props.width ?? sizes.width.value * pixelRatio.value)
const height = computed(() => props.height ?? sizes.height.value * pixelRatio.value)
const { pass } = useEffect(() => new SMAAPass(width.value, height.value))
const { pass } = useEffect(() => new SMAAPass(width.value, height.value), props)
defineExpose({ pass })
Expand Down
2 changes: 1 addition & 1 deletion src/core/three/UnrealBloom.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const { pass } = useEffect(() => new UnrealBloomPass(
props.radius,
props.strength,
props.threshold,
))
), props)
defineExpose({ pass })
Expand Down
24 changes: 17 additions & 7 deletions src/core/three/composables/useEffect.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
import { useTresContext } from '@tresjs/core'
import { inject, onUnmounted, shallowRef, watchEffect } from 'vue'
import { inject, nextTick, onUnmounted, shallowRef, watch, watchEffect } from 'vue'
import type { Pass } from 'three/examples/jsm/postprocessing/Pass.js'
import type { ShallowRef } from 'vue'
import type { Reactive, ShallowRef } from 'vue'
import { effectComposerInjectionKey } from '../EffectComposer.vue'

export const useEffect = <T extends Pass>(newPassFunction: () => T): { pass: ShallowRef<T> } => {
/**
* @param newPassFunction - A function that returns a new pass instance.
* @param passDependencies - A reactive object that the pass depends on (usually props). Changes to this object will trigger re-rendering.
*/
export const useEffect = <T extends Pass>(
newPassFunction: () => T,
passDependencies?: Reactive<object>,
): { pass: ShallowRef<T> } => {
const composer = inject(effectComposerInjectionKey)

const pass = shallowRef<T>(newPassFunction()) as ShallowRef<T>
const { sizes } = useTresContext()
const { sizes, invalidate } = useTresContext()

let unwatch = () => {} // seperate declaration prevents error in HMR
unwatch = watchEffect(() => {
if (passDependencies) {
watch(passDependencies, () => invalidate())
}

const unwatch = watchEffect(() => {
if (!composer?.value || !sizes.height.value || !sizes.width.value) { return }

composer.value.addPass(pass.value)
unwatch()
nextTick(() => unwatch())
})

onUnmounted(() => {
Expand Down

0 comments on commit 8e9c534

Please sign in to comment.