Skip to content

Commit a2afd3f

Browse files
TinooooTino Koch
andauthored
feat(post-processing): refactor of existing effects (#64)
* chore: refactored depth of field * feat: made effects react to main camera changes * chore: refactored glitch effect * chore: added comments for util functions * chore: refactored bloom effect component * chore: removed prop that is not reactive from bloom demo * chore: refactored outline effect component * chore: removed obsolete todo comment --------- Co-authored-by: Tino Koch <tino.koch@xpoli.eu>
1 parent 9264231 commit a2afd3f

File tree

10 files changed

+226
-228
lines changed

10 files changed

+226
-228
lines changed

docs/guide/effects/bloom.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { EffectComposer, Bloom } from '@tresjs/post-processing'
3535
| `kernelSize` | The kernel size. | `KernelSize.LARGE` |
3636
| `luminanceThreshold` | The luminance threshold. Raise this value to mask out darker elements in the scene. Range is [0, 1]. | `0.9` |
3737
| `luminanceSmoothing` | Controls the smoothness of the luminance threshold. Range is [0, 1]. | `0.025` |
38-
| `mipMapBlur` | Enables mip map blur. (UnrealBloom) | `false` |
38+
| `mipMapBlur` | Enables mip map blur (UnrealBloom). This prop is not reactive. | `false` |
3939

4040
## Further Reading
4141
see [postprocessing docs](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/BloomEffect.js~BloomEffect.html)

playground/src/components/UnrealBloom.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ const gl = {
1717
const bloomParams = reactive({
1818
luminanceThreshold: 0.2,
1919
luminanceSmoothing: 0.3,
20-
mipmapBlur: true,
2120
intensity: 4.0,
2221
blendFunction: BlendFunction.ADD,
2322
})
@@ -26,7 +25,6 @@ const { pane } = useTweakPane()
2625
2726
pane.addInput(bloomParams, 'luminanceThreshold', { min: 0, max: 1 })
2827
pane.addInput(bloomParams, 'luminanceSmoothing', { min: 0, max: 1 })
29-
pane.addInput(bloomParams, 'mipmapBlur')
3028
pane.addInput(bloomParams, 'intensity', { min: 0, max: 10 })
3129
3230
const materialRef = ref(null)
@@ -77,7 +75,10 @@ onMounted(() => {
7775
/>
7876
<Suspense>
7977
<EffectComposer :depth-buffer="true">
80-
<Bloom v-bind="bloomParams" />
78+
<Bloom
79+
v-bind="bloomParams"
80+
mipmap-blur
81+
/>
8182
</EffectComposer>
8283
</Suspense>
8384
</TresCanvas>

src/core/composables/effect.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import type { Effect } from 'postprocessing'
2+
import { EffectPass } from 'postprocessing'
3+
import { inject, onUnmounted, shallowRef, watchEffect, defineExpose } from 'vue'
4+
import { useTresContext } from '@tresjs/core'
5+
import { effectComposerInjectionKey } from '../injectionKeys'
6+
7+
export const useEffect = <T extends Effect>( newEffectFunction: () => T) => {
8+
const composer = inject(effectComposerInjectionKey)
9+
const pass = shallowRef<EffectPass | null>(null)
10+
const effect = shallowRef<T | null>(null)
11+
12+
const { scene, camera } = useTresContext()
13+
14+
watchEffect(() => {
15+
if (!camera.value || !effect?.value) return
16+
17+
effect.value.mainCamera = camera.value
18+
})
19+
20+
let unwatch = () => {} // seperate declaration prevents error in HMR
21+
22+
unwatch = watchEffect(() => {
23+
if (!camera.value || !composer?.value || !scene.value) return
24+
25+
unwatch()
26+
if (effect.value) return
27+
28+
effect.value = newEffectFunction()
29+
pass.value = new EffectPass(camera.value, effect.value)
30+
31+
composer.value.addPass(pass.value)
32+
})
33+
34+
onUnmounted(() => {
35+
if (pass.value) composer?.value?.removePass(pass.value)
36+
effect.value?.dispose()
37+
pass.value?.dispose()
38+
})
39+
40+
return {
41+
pass,
42+
effect,
43+
}
44+
}

src/core/effects/Bloom.vue

Lines changed: 21 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
<script setup lang="ts">
2-
import { useTresContext } from '@tresjs/core'
3-
import { h, inject, onUnmounted, shallowRef, watchEffect } from 'vue'
2+
import { BloomEffect } from 'postprocessing'
43
import type { KernelSize, BlendFunction } from 'postprocessing'
5-
import { EffectPass, BloomEffect } from 'postprocessing'
6-
import { effectComposerInjectionKey } from '../injectionKeys'
4+
import { useEffect } from '../composables/effect'
5+
import { makePropWatchers } from '../../util/prop'
76
87
export interface BloomProps {
98
/**
@@ -59,49 +58,28 @@ export interface BloomProps {
5958
mipmapBlur?: boolean
6059
}
6160
62-
const props = defineProps<BloomProps>()
61+
const props = withDefaults(
62+
defineProps<BloomProps>(),
63+
{
64+
mipmapBlur: undefined,
65+
},
66+
)
6367
64-
const composer = inject(effectComposerInjectionKey)
65-
const pass = shallowRef<EffectPass | null>(null)
66-
const effect = shallowRef<BloomEffect | null>(null)
68+
const { pass, effect } = useEffect(() => new BloomEffect(props))
6769
6870
defineExpose({ pass, effect }) // to allow users to modify pass and effect via template ref
6971
70-
const { camera } = useTresContext()
71-
72-
const unwatch = watchEffect(() => {
73-
if (!camera.value || !composer?.value) return
74-
75-
unwatch?.()
76-
if (effect.value) return
77-
78-
effect.value = new BloomEffect(props)
79-
pass.value = new EffectPass(camera.value, effect.value)
80-
81-
composer.value.addPass(pass.value)
82-
})
83-
84-
watchEffect(() => {
85-
if (!effect.value) return
86-
const plainEffectPass = new BloomEffect()
87-
88-
// blendFunction is not updated, because it has no setter in BloomEffect
89-
90-
effect.value.intensity = props.intensity !== undefined ? props.intensity : plainEffectPass.intensity
91-
effect.value.kernelSize = props.kernelSize !== undefined ? props.kernelSize : plainEffectPass.kernelSize
92-
effect.value.luminanceMaterial.smoothing
93-
= props.luminanceSmoothing !== undefined ? props.luminanceSmoothing : plainEffectPass.luminanceMaterial.smoothing
94-
effect.value.luminanceMaterial.threshold
95-
= props.luminanceThreshold !== undefined ? props.luminanceThreshold : plainEffectPass.luminanceMaterial.threshold
96-
97-
plainEffectPass.dispose()
98-
})
99-
100-
onUnmounted(() => {
101-
if (pass.value) composer?.value?.removePass(pass.value)
102-
effect.value?.dispose()
103-
pass.value?.dispose()
104-
})
72+
makePropWatchers(
73+
[
74+
// blendFunction is not updated, because it has no setter in BloomEffect
75+
[() => props.intensity, 'intensity'],
76+
[() => props.kernelSize, 'kernelSize'],
77+
[() => props.luminanceSmoothing, 'luminanceMaterial.smoothing'],
78+
[() => props.luminanceThreshold, 'luminanceMaterial.threshold'],
79+
],
80+
effect,
81+
() => new BloomEffect(),
82+
)
10583
</script>
10684

10785
<template></template>

src/core/effects/DepthOfField.vue

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
<script lang="ts" setup>
22
import type { BlendFunction } from 'postprocessing'
33
import { useTresContext } from '@tresjs/core'
4-
import { EffectPass, DepthOfFieldEffect } from 'postprocessing'
5-
import { inject, onUnmounted, shallowRef, watchEffect } from 'vue'
4+
import { DepthOfFieldEffect } from 'postprocessing'
65
import { makePropWatchers } from '../../util/prop'
7-
import { effectComposerInjectionKey } from '../injectionKeys'
6+
import { useEffect } from '../composables/effect'
87
98
export interface DepthOfFieldProps {
109
/**
@@ -43,27 +42,10 @@ export interface DepthOfFieldProps {
4342
}
4443
4544
const props = defineProps<DepthOfFieldProps>()
46-
47-
const composer = inject(effectComposerInjectionKey)
48-
const pass = shallowRef<EffectPass | null>(null)
49-
const effect = shallowRef<DepthOfFieldEffect | null>(null)
50-
51-
defineExpose({ pass, effect }) // to allow users to modify pass and effect via template ref
52-
5345
const { camera } = useTresContext()
54-
55-
const unwatch = watchEffect(() => {
56-
if (!camera.value || !composer?.value) return
57-
58-
unwatch?.()
59-
60-
if (effect.value) return
61-
62-
effect.value = new DepthOfFieldEffect(camera.value, props)
63-
pass.value = new EffectPass(camera.value, effect.value)
64-
65-
composer?.value?.addPass(pass.value)
66-
})
46+
47+
const { pass, effect } = useEffect(() => new DepthOfFieldEffect(camera.value, props))
48+
defineExpose({ pass, effect }) // to allow users to modify pass and effect via template ref
6749
6850
makePropWatchers(
6951
[
@@ -80,12 +62,6 @@ makePropWatchers(
8062
effect,
8163
() => new DepthOfFieldEffect(),
8264
)
83-
84-
onUnmounted(() => {
85-
if (pass.value) composer?.value?.removePass(pass.value)
86-
effect.value?.dispose()
87-
pass.value?.dispose()
88-
})
8965
</script>
9066

9167
<template></template>

src/core/effects/Glitch.vue

Lines changed: 18 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
<script setup lang="ts">
2+
import { GlitchMode, GlitchEffect } from 'postprocessing'
3+
import { watchEffect } from 'vue'
24
import type { BlendFunction } from 'postprocessing'
3-
import { GlitchMode, EffectPass, GlitchEffect } from 'postprocessing'
4-
import { inject, onUnmounted, shallowRef, watchEffect } from 'vue'
5-
65
import type { Vector2, Texture } from 'three'
7-
8-
import { useTresContext } from '@tresjs/core'
9-
import { effectComposerInjectionKey } from '../injectionKeys'
6+
import { omit } from '../../util/object'
7+
import { useEffect } from '../composables/effect'
8+
import { makePropWatchersUsingAllProps } from '../../util/prop'
109
1110
export interface GlitchProps {
1211
blendFunction?: BlendFunction
@@ -99,57 +98,29 @@ export interface GlitchProps {
9998
10099
const props = defineProps<GlitchProps>()
101100
102-
const composer = inject(effectComposerInjectionKey)
103-
const pass = shallowRef<EffectPass | null>(null)
104-
const effect = shallowRef<GlitchEffect | null>(null)
105-
101+
const { pass, effect } = useEffect(() => new GlitchEffect(props))
106102
defineExpose({ pass, effect }) // to allow users to modify pass and effect via template ref
107103
108-
const { camera } = useTresContext()
109-
110-
const unwatch = watchEffect(() => {
111-
if (!camera.value || !composer?.value) return
112-
113-
unwatch?.()
114-
if (effect.value) return
115-
116-
effect.value = new GlitchEffect(props)
117-
pass.value = new EffectPass(camera.value, effect.value)
118-
119-
composer.value.addPass(pass.value)
120-
})
121-
122104
watchEffect(() => {
123-
if (!effect.value) return
124-
const plainEffectPass = new GlitchEffect()
125-
126-
// blendFunction and dtSize are not updated, because it has no setter in BloomEffect
127-
128105
const getMode = () => {
129106
if (props.mode !== undefined) return props.active === false ? GlitchMode.DISABLED : props.mode
107+
const plainEffectPass = new GlitchEffect()
108+
109+
const defaultMode = plainEffectPass.mode
110+
plainEffectPass.dispose()
130111
131-
return plainEffectPass.mode
112+
return defaultMode
132113
}
133114
134-
effect.value.mode = getMode()
135-
effect.value.ratio = props.ratio !== undefined ? props.ratio : plainEffectPass.ratio
136-
effect.value.delay = props.delay !== undefined ? props.delay : plainEffectPass.delay
137-
effect.value.columns = props.columns !== undefined ? props.columns : plainEffectPass.columns
138-
effect.value.duration = props.duration !== undefined ? props.duration : plainEffectPass.duration
139-
effect.value.strength = props.strength !== undefined ? props.strength : plainEffectPass.strength
140-
effect.value.perturbationMap
141-
= props.perturbationMap !== undefined ? props.perturbationMap : plainEffectPass.perturbationMap
142-
effect.value.chromaticAberrationOffset
143-
= props.chromaticAberrationOffset !== undefined
144-
? props.chromaticAberrationOffset
145-
: plainEffectPass.chromaticAberrationOffset
115+
if (effect.value)
116+
effect.value.mode = getMode()
146117
})
147118
148-
onUnmounted(() => {
149-
if (pass.value) composer?.value?.removePass(pass.value)
150-
effect.value?.dispose()
151-
pass.value?.dispose()
152-
})
119+
makePropWatchersUsingAllProps(
120+
omit(props, ['active', 'mode', 'blendFunction']),
121+
effect,
122+
() => new GlitchEffect(),
123+
)
153124
</script>
154125

155126
<template></template>

0 commit comments

Comments
 (0)