@react-three/postprocessing 3.0.4 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +80 -81
- package/dist/EffectComposer.d.ts +14 -6
- package/dist/EffectGroup.d.ts +9 -0
- package/dist/Selection.d.ts +8 -8
- package/dist/createEffectComponent.d.ts +30 -0
- package/dist/effects/ASCII.d.ts +29 -7
- package/dist/effects/Autofocus.d.ts +8 -7
- package/dist/effects/Bloom.d.ts +10 -5
- package/dist/effects/BrightnessContrast.d.ts +15 -5
- package/dist/effects/ChromaticAberration.d.ts +30 -7
- package/dist/effects/ColorAverage.d.ts +7 -8
- package/dist/effects/ColorDepth.d.ts +8 -5
- package/dist/effects/Depth.d.ts +13 -5
- package/dist/effects/DepthOfField.d.ts +7 -18
- package/dist/effects/DotScreen.d.ts +15 -5
- package/dist/effects/FXAA.d.ts +11 -5
- package/dist/effects/Glitch.d.ts +17 -29
- package/dist/effects/GodRays.d.ts +7 -19
- package/dist/effects/Grid.d.ts +8 -8
- package/dist/effects/HueSaturation.d.ts +15 -5
- package/dist/effects/LUT.d.ts +4 -3
- package/dist/effects/LensFlare.d.ts +52 -11
- package/dist/effects/Noise.d.ts +8 -5
- package/dist/effects/Outline.d.ts +9 -25
- package/dist/effects/Pixelation.d.ts +3 -2
- package/dist/effects/Ramp.d.ts +58 -10
- package/dist/effects/SMAA.d.ts +10 -5
- package/dist/effects/SSAO.d.ts +7 -30
- package/dist/effects/ScanlineEffect.d.ts +13 -5
- package/dist/effects/SelectiveBloom.d.ts +5 -10
- package/dist/effects/Sepia.d.ts +13 -5
- package/dist/effects/ShockWave.d.ts +12 -5
- package/dist/effects/Texture.d.ts +7 -8
- package/dist/effects/TiltShift.d.ts +10 -5
- package/dist/effects/TiltShift2.d.ts +44 -8
- package/dist/effects/ToneMapping.d.ts +9 -7
- package/dist/effects/Vignette.d.ts +19 -5
- package/dist/effects/Water.d.ts +17 -5
- package/dist/index.d.ts +15 -11
- package/dist/index.js +1841 -45
- package/dist/index.js.map +1 -1
- package/dist/passes/DepthPicking.d.ts +11 -0
- package/dist/{effects → passes}/N8AO.d.ts +5 -2
- package/dist/util.d.ts +19 -17
- package/dist/wrapEffect.d.ts +12 -0
- package/package.json +74 -67
- package/src/EffectComposer.tsx +379 -200
- package/src/EffectGroup.tsx +74 -0
- package/src/Selection.tsx +86 -46
- package/src/createEffectComponent.tsx +71 -0
- package/src/effects/ASCII.tsx +183 -135
- package/src/effects/Autofocus.tsx +122 -153
- package/src/effects/Bloom.tsx +34 -6
- package/src/effects/BrightnessContrast.tsx +7 -4
- package/src/effects/ChromaticAberration.tsx +22 -5
- package/src/effects/ColorAverage.tsx +4 -15
- package/src/effects/ColorDepth.tsx +25 -4
- package/src/effects/Depth.tsx +6 -4
- package/src/effects/DepthOfField.tsx +109 -89
- package/src/effects/DotScreen.tsx +7 -4
- package/src/effects/FXAA.tsx +6 -4
- package/src/effects/Glitch.tsx +32 -40
- package/src/effects/GodRays.tsx +104 -16
- package/src/effects/Grid.tsx +27 -21
- package/src/effects/HueSaturation.tsx +7 -4
- package/src/effects/LUT.tsx +25 -26
- package/src/effects/LensFlare.tsx +765 -611
- package/src/effects/Noise.tsx +16 -4
- package/src/effects/Outline.tsx +84 -117
- package/src/effects/Pixelation.tsx +20 -15
- package/src/effects/Ramp.tsx +239 -150
- package/src/effects/SMAA.tsx +20 -4
- package/src/effects/SSAO.tsx +152 -41
- package/src/effects/ScanlineEffect.tsx +7 -7
- package/src/effects/SelectiveBloom.tsx +98 -126
- package/src/effects/Sepia.tsx +6 -4
- package/src/effects/ShockWave.tsx +32 -4
- package/src/effects/Texture.tsx +28 -23
- package/src/effects/TiltShift.tsx +32 -4
- package/src/effects/TiltShift2.tsx +156 -90
- package/src/effects/ToneMapping.tsx +19 -6
- package/src/effects/Vignette.tsx +7 -4
- package/src/effects/Water.tsx +50 -35
- package/src/index.ts +43 -40
- package/src/passes/DepthPicking.tsx +63 -0
- package/src/passes/N8AO.tsx +105 -0
- package/src/tests/Autofocus.test.tsx +38 -0
- package/src/tests/Bloom.test.tsx +76 -0
- package/src/tests/ChromaticAberration.test.tsx +81 -0
- package/src/tests/ColorDepth.test.tsx +71 -0
- package/src/tests/DepthOfField.test.tsx +130 -0
- package/src/tests/DepthPicking.test.tsx +250 -0
- package/src/tests/EffectComposer.test.tsx +1404 -0
- package/src/tests/EffectGroup.test.tsx +337 -0
- package/src/tests/Glitch.test.tsx +56 -0
- package/src/tests/GodRays.test.tsx +101 -0
- package/src/tests/Grid.test.tsx +34 -0
- package/src/tests/LUT.test.tsx +64 -0
- package/src/tests/N8AO.test.tsx +92 -0
- package/src/tests/Outline.test.tsx +211 -0
- package/src/tests/SSAO.test.tsx +140 -0
- package/src/tests/Selection.test.tsx +324 -0
- package/src/tests/SelectiveBloom.test.tsx +166 -0
- package/src/tests/ShockWave.test.tsx +95 -0
- package/src/tests/TiltShift.test.tsx +76 -0
- package/src/tests/createEffectComponent.test.tsx +286 -0
- package/src/tests/effects.smoke.test.tsx +238 -0
- package/src/tests/test-utils.tsx +96 -0
- package/src/tests/wrapEffect.test.tsx +209 -0
- package/src/util.tsx +221 -55
- package/src/wrapEffect.tsx +123 -0
- package/src/EffectComposer.test.tsx +0 -126
- package/src/effects/N8AO.tsx +0 -81
package/src/effects/SMAA.tsx
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
|
-
import { SMAAEffect } from 'postprocessing'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { SMAAEffect } from 'postprocessing'
|
|
2
|
+
import type { Ref } from 'react'
|
|
3
|
+
import { useMemo } from 'react'
|
|
4
|
+
import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
|
|
5
|
+
|
|
6
|
+
type SMAAOptions = EffectOptions<typeof SMAAEffect>
|
|
7
|
+
|
|
8
|
+
const SMAAImpl = /* @__PURE__ */ createEffectComponent<typeof SMAAEffect, SMAAOptions>(SMAAEffect)
|
|
9
|
+
|
|
10
|
+
export type SMAAProps = SMAAOptions & { opacity?: number; ref?: Ref<SMAAEffect> }
|
|
11
|
+
|
|
12
|
+
// preset/edgeDetectionMode/predicationMode have no live setter in
|
|
13
|
+
// postprocessing - routed through args so they still work as plain props.
|
|
14
|
+
export function SMAA({ preset, edgeDetectionMode, predicationMode, ...liveProps }: SMAAProps) {
|
|
15
|
+
const args = useMemo<[SMAAOptions]>(
|
|
16
|
+
() => [{ preset, edgeDetectionMode, predicationMode }],
|
|
17
|
+
[preset, edgeDetectionMode, predicationMode]
|
|
18
|
+
)
|
|
19
|
+
return <SMAAImpl args={args} {...liveProps} />
|
|
20
|
+
}
|
package/src/effects/SSAO.tsx
CHANGED
|
@@ -1,41 +1,152 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { EffectComposerContext } from '../EffectComposer'
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
1
|
+
import { BlendFunction, SSAOEffect } from 'postprocessing'
|
|
2
|
+
import { Ref, use, useMemo } from 'react'
|
|
3
|
+
import { EffectComposerContext } from '../EffectComposer'
|
|
4
|
+
import { applyPierced, readPierced, useDispose, useLiveDefaults } from '../util'
|
|
5
|
+
|
|
6
|
+
// first two args are camera and texture
|
|
7
|
+
type SSAOProps = ConstructorParameters<typeof SSAOEffect>[2] & { ref?: Ref<SSAOEffect> }
|
|
8
|
+
|
|
9
|
+
// Only resolutionScale/resolutionX/resolutionY/width/height and
|
|
10
|
+
// normalDepthBuffer have no live setter in postprocessing - everything else
|
|
11
|
+
// either has a real accessor directly on SSAOEffect, or on the nested
|
|
12
|
+
// ssaoMaterial (rangeThreshold/rangeFalloff are the constructor's names for
|
|
13
|
+
// what ssaoMaterial exposes as proximityThreshold/proximityFalloff).
|
|
14
|
+
// camera+normalBuffer being required constructor args also rule out
|
|
15
|
+
// createEffectComponent (needs `new Effect()` to work with zero args).
|
|
16
|
+
const LIVE_KEYS = [
|
|
17
|
+
'blendMode-blendFunction',
|
|
18
|
+
'normalBuffer',
|
|
19
|
+
'samples',
|
|
20
|
+
'rings',
|
|
21
|
+
'radius',
|
|
22
|
+
'depthAwareUpsampling',
|
|
23
|
+
'color',
|
|
24
|
+
'luminanceInfluence',
|
|
25
|
+
'intensity',
|
|
26
|
+
'ssaoMaterial-bias',
|
|
27
|
+
'ssaoMaterial-fade',
|
|
28
|
+
'ssaoMaterial-minRadiusScale',
|
|
29
|
+
'ssaoMaterial-distanceThreshold',
|
|
30
|
+
'ssaoMaterial-distanceFalloff',
|
|
31
|
+
'ssaoMaterial-worldDistanceThreshold',
|
|
32
|
+
'ssaoMaterial-worldDistanceFalloff',
|
|
33
|
+
'rangeThreshold',
|
|
34
|
+
'rangeFalloff',
|
|
35
|
+
'ssaoMaterial-worldProximityThreshold',
|
|
36
|
+
'ssaoMaterial-worldProximityFalloff',
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
function get(effect: SSAOEffect, key: string): unknown {
|
|
40
|
+
if (key === 'rangeThreshold') return effect.ssaoMaterial.proximityThreshold
|
|
41
|
+
if (key === 'rangeFalloff') return effect.ssaoMaterial.proximityFalloff
|
|
42
|
+
return readPierced(effect, key)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function set(effect: SSAOEffect, key: string, value: unknown): void {
|
|
46
|
+
if (key === 'rangeThreshold') effect.ssaoMaterial.proximityThreshold = value as number
|
|
47
|
+
else if (key === 'rangeFalloff') effect.ssaoMaterial.proximityFalloff = value as number
|
|
48
|
+
else applyPierced(effect, key, value)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function SSAO({
|
|
52
|
+
blendFunction = BlendFunction.MULTIPLY,
|
|
53
|
+
samples = 30,
|
|
54
|
+
rings = 4,
|
|
55
|
+
distanceThreshold = 1.0,
|
|
56
|
+
distanceFalloff = 0.0,
|
|
57
|
+
rangeThreshold = 0.5,
|
|
58
|
+
rangeFalloff = 0.1,
|
|
59
|
+
luminanceInfluence = 0.9,
|
|
60
|
+
radius = 20,
|
|
61
|
+
bias = 0.5,
|
|
62
|
+
intensity = 1.0,
|
|
63
|
+
color,
|
|
64
|
+
worldDistanceThreshold,
|
|
65
|
+
worldDistanceFalloff,
|
|
66
|
+
worldProximityThreshold,
|
|
67
|
+
worldProximityFalloff,
|
|
68
|
+
minRadiusScale,
|
|
69
|
+
fade,
|
|
70
|
+
depthAwareUpsampling = true,
|
|
71
|
+
resolutionScale,
|
|
72
|
+
resolutionX,
|
|
73
|
+
resolutionY,
|
|
74
|
+
width,
|
|
75
|
+
height,
|
|
76
|
+
ref,
|
|
77
|
+
}: SSAOProps) {
|
|
78
|
+
const { camera, normalPass, downSamplingPass, resolutionScale: composerResolutionScale } = use(EffectComposerContext)
|
|
79
|
+
|
|
80
|
+
const effect = useMemo<SSAOEffect | {}>(() => {
|
|
81
|
+
if (normalPass === null && downSamplingPass === null) {
|
|
82
|
+
console.error('Please enable the NormalPass in the EffectComposer in order to use SSAO.')
|
|
83
|
+
return {}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return new SSAOEffect(camera, normalPass && !downSamplingPass ? (normalPass as any).texture : null, {
|
|
87
|
+
blendFunction,
|
|
88
|
+
samples,
|
|
89
|
+
rings,
|
|
90
|
+
distanceThreshold,
|
|
91
|
+
distanceFalloff,
|
|
92
|
+
rangeThreshold,
|
|
93
|
+
rangeFalloff,
|
|
94
|
+
luminanceInfluence,
|
|
95
|
+
radius,
|
|
96
|
+
bias,
|
|
97
|
+
intensity,
|
|
98
|
+
// @ts-ignore
|
|
99
|
+
normalDepthBuffer: downSamplingPass ? downSamplingPass.texture : null,
|
|
100
|
+
resolutionScale: resolutionScale ?? composerResolutionScale ?? 1,
|
|
101
|
+
resolutionX,
|
|
102
|
+
resolutionY,
|
|
103
|
+
width,
|
|
104
|
+
height,
|
|
105
|
+
depthAwareUpsampling,
|
|
106
|
+
})
|
|
107
|
+
// color/worldDistanceThreshold/worldDistanceFalloff/worldProximityThreshold/
|
|
108
|
+
// worldProximityFalloff/minRadiusScale/fade are deliberately left out here
|
|
109
|
+
// even though they're valid constructor options: they have no JS-level
|
|
110
|
+
// default in this component's own signature, so useLiveDefaults' first
|
|
111
|
+
// snapshot must see SSAOEffect's own real default for them, not whatever
|
|
112
|
+
// value happened to be passed on the mounting render - otherwise removing
|
|
113
|
+
// the prop later "resets" to that first-render value instead of the
|
|
114
|
+
// effect's true default. They're still applied immediately below, live.
|
|
115
|
+
//
|
|
116
|
+
// Only the genuinely construction-only options belong here - everything
|
|
117
|
+
// else is applied live below via useLiveDefaults instead.
|
|
118
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
119
|
+
}, [camera, downSamplingPass, normalPass, resolutionScale, composerResolutionScale, resolutionX, resolutionY, width, height])
|
|
120
|
+
|
|
121
|
+
useLiveDefaults(
|
|
122
|
+
effect instanceof SSAOEffect ? effect : null,
|
|
123
|
+
{
|
|
124
|
+
'blendMode-blendFunction': blendFunction,
|
|
125
|
+
samples,
|
|
126
|
+
rings,
|
|
127
|
+
radius,
|
|
128
|
+
depthAwareUpsampling,
|
|
129
|
+
color,
|
|
130
|
+
luminanceInfluence,
|
|
131
|
+
intensity,
|
|
132
|
+
'ssaoMaterial-bias': bias,
|
|
133
|
+
'ssaoMaterial-fade': fade,
|
|
134
|
+
'ssaoMaterial-minRadiusScale': minRadiusScale,
|
|
135
|
+
'ssaoMaterial-distanceThreshold': distanceThreshold,
|
|
136
|
+
'ssaoMaterial-distanceFalloff': distanceFalloff,
|
|
137
|
+
'ssaoMaterial-worldDistanceThreshold': worldDistanceThreshold,
|
|
138
|
+
'ssaoMaterial-worldDistanceFalloff': worldDistanceFalloff,
|
|
139
|
+
rangeThreshold,
|
|
140
|
+
rangeFalloff,
|
|
141
|
+
'ssaoMaterial-worldProximityThreshold': worldProximityThreshold,
|
|
142
|
+
'ssaoMaterial-worldProximityFalloff': worldProximityFalloff,
|
|
143
|
+
},
|
|
144
|
+
LIVE_KEYS,
|
|
145
|
+
get,
|
|
146
|
+
set
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
useDispose(effect as SSAOEffect)
|
|
150
|
+
|
|
151
|
+
return <primitive ref={ref} object={effect} />
|
|
152
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ScanlineEffect
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export const Scanline = /* @__PURE__ */
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { ScanlineEffect } from 'postprocessing'
|
|
2
|
+
import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
|
|
3
|
+
|
|
4
|
+
export const Scanline = /* @__PURE__ */ createEffectComponent<
|
|
5
|
+
typeof ScanlineEffect,
|
|
6
|
+
EffectOptions<typeof ScanlineEffect>
|
|
7
|
+
>(ScanlineEffect)
|
|
@@ -1,126 +1,98 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { BloomEffectOptions } from 'postprocessing'
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { EffectComposerContext } from '../EffectComposer'
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}>
|
|
20
|
-
|
|
21
|
-
const addLight = (light: Object3D, effect: SelectiveBloomEffect) => light.layers.enable(effect.selection.layer)
|
|
22
|
-
const removeLight = (light: Object3D, effect: SelectiveBloomEffect) => light.layers.disable(effect.selection.layer)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}, [effect, invalidate, selectionLayer])
|
|
100
|
-
|
|
101
|
-
useEffect(() => {
|
|
102
|
-
if (lights && lights.length > 0) {
|
|
103
|
-
lights.forEach((light) => addLight(resolveRef(light), effect))
|
|
104
|
-
invalidate()
|
|
105
|
-
return () => {
|
|
106
|
-
lights.forEach((light) => removeLight(resolveRef(light), effect))
|
|
107
|
-
invalidate()
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}, [effect, invalidate, lights, selectionLayer])
|
|
111
|
-
|
|
112
|
-
useEffect(() => {
|
|
113
|
-
if (api && api.enabled) {
|
|
114
|
-
if (api.selected?.length) {
|
|
115
|
-
effect.selection.set(api.selected)
|
|
116
|
-
invalidate()
|
|
117
|
-
return () => {
|
|
118
|
-
effect.selection.clear()
|
|
119
|
-
invalidate()
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}, [api, effect.selection, invalidate])
|
|
124
|
-
|
|
125
|
-
return <primitive ref={forwardRef} object={effect} dispose={null} />
|
|
126
|
-
})
|
|
1
|
+
import { useThree } from '@react-three/fiber'
|
|
2
|
+
import type { BloomEffectOptions } from 'postprocessing'
|
|
3
|
+
import { BlendFunction, SelectiveBloomEffect } from 'postprocessing'
|
|
4
|
+
import { Ref, RefObject, use, useEffect, useMemo } from 'react'
|
|
5
|
+
import { Object3D } from 'three'
|
|
6
|
+
import { EffectComposerContext } from '../EffectComposer'
|
|
7
|
+
import { EMPTY_ARRAY, resolveRef, useDispose, useLiveDefaults, useSelectionSync } from '../util'
|
|
8
|
+
|
|
9
|
+
type ObjectRef = RefObject<Object3D | null>
|
|
10
|
+
|
|
11
|
+
export type SelectiveBloomProps = BloomEffectOptions &
|
|
12
|
+
Partial<{
|
|
13
|
+
lights: Object3D[] | ObjectRef[]
|
|
14
|
+
selection: Object3D | Object3D[] | ObjectRef | ObjectRef[]
|
|
15
|
+
selectionLayer: number
|
|
16
|
+
inverted: boolean
|
|
17
|
+
ignoreBackground: boolean
|
|
18
|
+
ref?: Ref<SelectiveBloomEffect>
|
|
19
|
+
}>
|
|
20
|
+
|
|
21
|
+
const addLight = (light: Object3D, effect: SelectiveBloomEffect) => light.layers.enable(effect.selection.layer)
|
|
22
|
+
const removeLight = (light: Object3D, effect: SelectiveBloomEffect) => light.layers.disable(effect.selection.layer)
|
|
23
|
+
|
|
24
|
+
// BloomEffect (which SelectiveBloomEffect extends) only exposes real
|
|
25
|
+
// setters for these - luminanceThreshold/luminanceSmoothing/mipmapBlur/
|
|
26
|
+
// radius/levels/resolution* are construction-only in postprocessing itself.
|
|
27
|
+
// scene/camera being required constructor args also rules out
|
|
28
|
+
// createEffectComponent (needs `new Effect()` to work with zero args).
|
|
29
|
+
const LIVE_KEYS = ['width', 'height', 'kernelSize', 'intensity', 'inverted', 'ignoreBackground']
|
|
30
|
+
|
|
31
|
+
export function SelectiveBloom({
|
|
32
|
+
selection = EMPTY_ARRAY,
|
|
33
|
+
selectionLayer = 10,
|
|
34
|
+
lights = EMPTY_ARRAY,
|
|
35
|
+
luminanceThreshold,
|
|
36
|
+
luminanceSmoothing,
|
|
37
|
+
mipmapBlur,
|
|
38
|
+
radius,
|
|
39
|
+
levels,
|
|
40
|
+
resolutionScale,
|
|
41
|
+
resolutionX,
|
|
42
|
+
resolutionY,
|
|
43
|
+
ref,
|
|
44
|
+
...liveProps
|
|
45
|
+
}: SelectiveBloomProps) {
|
|
46
|
+
const { scene, camera } = use(EffectComposerContext)
|
|
47
|
+
|
|
48
|
+
const invalidate = useThree((state) => state.invalidate)
|
|
49
|
+
|
|
50
|
+
const effect = useMemo(
|
|
51
|
+
() =>
|
|
52
|
+
new SelectiveBloomEffect(scene, camera, {
|
|
53
|
+
blendFunction: BlendFunction.ADD,
|
|
54
|
+
luminanceThreshold,
|
|
55
|
+
luminanceSmoothing,
|
|
56
|
+
mipmapBlur,
|
|
57
|
+
radius,
|
|
58
|
+
levels,
|
|
59
|
+
resolutionScale,
|
|
60
|
+
resolutionX,
|
|
61
|
+
resolutionY,
|
|
62
|
+
}),
|
|
63
|
+
[scene, camera, luminanceThreshold, luminanceSmoothing, mipmapBlur, radius, levels, resolutionScale, resolutionX, resolutionY]
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
useLiveDefaults(effect, liveProps as Record<string, unknown>, LIVE_KEYS)
|
|
67
|
+
|
|
68
|
+
// Must run before the lights effect below: addLight/removeLight read
|
|
69
|
+
// effect.selection.layer live, so it needs to already reflect the
|
|
70
|
+
// latest selectionLayer by the time lights get (re-)assigned to it.
|
|
71
|
+
useSelectionSync(effect, selection, selectionLayer)
|
|
72
|
+
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (lights.length === 0) {
|
|
75
|
+
console.warn('SelectiveBloom requires lights to work.')
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Refs may not have attached yet - resolve and drop nullish entries
|
|
80
|
+
// rather than crashing addLight/removeLight on a null object.
|
|
81
|
+
const resolvedLights = lights.map((light) => resolveRef(light)).filter((light): light is Object3D => light != null)
|
|
82
|
+
if (resolvedLights.length === 0) return
|
|
83
|
+
|
|
84
|
+
resolvedLights.forEach((light) => addLight(light, effect))
|
|
85
|
+
|
|
86
|
+
invalidate()
|
|
87
|
+
|
|
88
|
+
return () => {
|
|
89
|
+
resolvedLights.forEach((light) => removeLight(light, effect))
|
|
90
|
+
|
|
91
|
+
invalidate()
|
|
92
|
+
}
|
|
93
|
+
}, [effect, invalidate, lights, selectionLayer])
|
|
94
|
+
|
|
95
|
+
useDispose(effect)
|
|
96
|
+
|
|
97
|
+
return <primitive ref={ref} object={effect} />
|
|
98
|
+
}
|
package/src/effects/Sepia.tsx
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { SepiaEffect } from 'postprocessing'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export const Sepia = /* @__PURE__ */
|
|
1
|
+
import { SepiaEffect } from 'postprocessing'
|
|
2
|
+
import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
|
|
3
|
+
|
|
4
|
+
export const Sepia = /* @__PURE__ */ createEffectComponent<typeof SepiaEffect, EffectOptions<typeof SepiaEffect>>(
|
|
5
|
+
SepiaEffect
|
|
6
|
+
)
|
|
@@ -1,4 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type { ReactThreeFiber } from '@react-three/fiber'
|
|
2
|
+
import { ShockWaveEffect } from 'postprocessing'
|
|
3
|
+
import { Ref, use, useMemo } from 'react'
|
|
4
|
+
import { EffectComposerContext } from '../EffectComposer'
|
|
5
|
+
import { useDispose, useLiveDefaults, useVector3 } from '../util'
|
|
6
|
+
|
|
7
|
+
export type ShockWaveProps = {
|
|
8
|
+
position?: ReactThreeFiber.Vector3
|
|
9
|
+
speed?: number
|
|
10
|
+
maxRadius?: number
|
|
11
|
+
waveSize?: number
|
|
12
|
+
amplitude?: number
|
|
13
|
+
ref?: Ref<ShockWaveEffect>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const LIVE_KEYS = ['position', 'speed', 'maxRadius', 'waveSize', 'amplitude']
|
|
17
|
+
|
|
18
|
+
// ShockWaveEffect's constructor is (camera, position, options) - camera is
|
|
19
|
+
// a required arg, so it can't use createEffectComponent (needs
|
|
20
|
+
// `new Effect()` to work with zero args). Built by hand instead, like
|
|
21
|
+
// Outline/GodRays.
|
|
22
|
+
export function ShockWave(props: ShockWaveProps) {
|
|
23
|
+
const { speed, maxRadius, waveSize, amplitude, ref } = props
|
|
24
|
+
const { camera } = use(EffectComposerContext)
|
|
25
|
+
const effect = useMemo(() => new ShockWaveEffect(camera), [camera])
|
|
26
|
+
const position = useVector3(props, 'position')
|
|
27
|
+
|
|
28
|
+
useLiveDefaults(effect, { position, speed, maxRadius, waveSize, amplitude }, LIVE_KEYS)
|
|
29
|
+
useDispose(effect)
|
|
30
|
+
|
|
31
|
+
return <primitive ref={ref} object={effect} />
|
|
32
|
+
}
|
package/src/effects/Texture.tsx
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
import { useLoader } from '@react-three/fiber'
|
|
2
|
+
import { TextureEffect } from 'postprocessing'
|
|
3
|
+
import type { Ref } from 'react'
|
|
4
|
+
import { useLayoutEffect } from 'react'
|
|
5
|
+
import { RepeatWrapping, SRGBColorSpace, TextureLoader } from 'three'
|
|
6
|
+
import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
|
|
7
|
+
|
|
8
|
+
const TextureImpl = /* @__PURE__ */ createEffectComponent<typeof TextureEffect, EffectOptions<typeof TextureEffect>>(
|
|
9
|
+
TextureEffect
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
export type TextureProps = EffectOptions<typeof TextureEffect> & {
|
|
13
|
+
textureSrc: string
|
|
14
|
+
/** opacity of provided texture */
|
|
15
|
+
opacity?: number
|
|
16
|
+
ref?: Ref<TextureEffect>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function Texture({ textureSrc, texture, opacity = 1, ...props }: TextureProps) {
|
|
20
|
+
const t = useLoader(TextureLoader, textureSrc)
|
|
21
|
+
|
|
22
|
+
useLayoutEffect(() => {
|
|
23
|
+
t.colorSpace = SRGBColorSpace
|
|
24
|
+
t.wrapS = t.wrapT = RepeatWrapping
|
|
25
|
+
}, [t])
|
|
26
|
+
|
|
27
|
+
return <TextureImpl {...props} texture={texture ?? t} opacity={opacity} />
|
|
28
|
+
}
|
|
@@ -1,4 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { BlendFunction, TiltShiftEffect } from 'postprocessing'
|
|
2
|
+
import type { Ref } from 'react'
|
|
3
|
+
import { useMemo } from 'react'
|
|
4
|
+
import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
|
|
5
|
+
|
|
6
|
+
type TiltShiftOptions = EffectOptions<typeof TiltShiftEffect>
|
|
7
|
+
|
|
8
|
+
const TiltShiftImpl = /* @__PURE__ */ createEffectComponent<typeof TiltShiftEffect, TiltShiftOptions>(TiltShiftEffect)
|
|
9
|
+
|
|
10
|
+
export type TiltShiftProps = TiltShiftOptions & {
|
|
11
|
+
opacity?: number
|
|
12
|
+
ref?: Ref<TiltShiftEffect>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// kernelSize/resolutionScale/resolutionX/resolutionY have no live setter in
|
|
16
|
+
// postprocessing - routed through args so they still work as plain props
|
|
17
|
+
// (previously they were passed as plain props and silently never reached
|
|
18
|
+
// the effect at all, since there was no setter for diffProps to hit).
|
|
19
|
+
export function TiltShift({
|
|
20
|
+
blendFunction = BlendFunction.ADD,
|
|
21
|
+
kernelSize,
|
|
22
|
+
resolutionScale,
|
|
23
|
+
resolutionX,
|
|
24
|
+
resolutionY,
|
|
25
|
+
...liveProps
|
|
26
|
+
}: TiltShiftProps) {
|
|
27
|
+
const args = useMemo<[TiltShiftOptions]>(
|
|
28
|
+
() => [{ kernelSize, resolutionScale, resolutionX, resolutionY }],
|
|
29
|
+
[kernelSize, resolutionScale, resolutionX, resolutionY]
|
|
30
|
+
)
|
|
31
|
+
return <TiltShiftImpl blendFunction={blendFunction} args={args} {...liveProps} />
|
|
32
|
+
}
|