@react-three/postprocessing 3.0.5 → 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/README.md +6 -7
- package/dist/EffectComposer.d.ts +9 -2
- package/dist/EffectGroup.d.ts +9 -0
- package/dist/createEffectComponent.d.ts +30 -0
- package/dist/effects/ASCII.d.ts +28 -7
- package/dist/effects/Autofocus.d.ts +1 -1
- package/dist/effects/Bloom.d.ts +9 -1
- package/dist/effects/BrightnessContrast.d.ts +14 -1
- package/dist/effects/ChromaticAberration.d.ts +26 -3
- package/dist/effects/ColorAverage.d.ts +7 -7
- package/dist/effects/ColorDepth.d.ts +7 -1
- package/dist/effects/Depth.d.ts +12 -1
- package/dist/effects/DotScreen.d.ts +14 -1
- package/dist/effects/FXAA.d.ts +10 -1
- package/dist/effects/Glitch.d.ts +16 -11
- package/dist/effects/GodRays.d.ts +1 -1
- package/dist/effects/Grid.d.ts +7 -6
- package/dist/effects/HueSaturation.d.ts +14 -1
- package/dist/effects/LUT.d.ts +1 -1
- package/dist/effects/LensFlare.d.ts +46 -5
- package/dist/effects/Noise.d.ts +7 -1
- package/dist/effects/Outline.d.ts +6 -3
- package/dist/effects/Pixelation.d.ts +1 -1
- package/dist/effects/Ramp.d.ts +58 -6
- package/dist/effects/SMAA.d.ts +9 -1
- package/dist/effects/SSAO.d.ts +1 -1
- package/dist/effects/ScanlineEffect.d.ts +12 -1
- package/dist/effects/SelectiveBloom.d.ts +1 -1
- package/dist/effects/Sepia.d.ts +12 -1
- package/dist/effects/ShockWave.d.ts +11 -1
- package/dist/effects/Texture.d.ts +4 -4
- package/dist/effects/TiltShift.d.ts +9 -1
- package/dist/effects/TiltShift2.d.ts +44 -4
- package/dist/effects/ToneMapping.d.ts +9 -3
- package/dist/effects/Vignette.d.ts +18 -1
- package/dist/effects/Water.d.ts +17 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2205 -713
- package/dist/index.js.map +1 -1
- package/dist/passes/DepthPicking.d.ts +11 -0
- package/dist/{effects → passes}/N8AO.d.ts +2 -1
- package/dist/util.d.ts +9 -15
- package/dist/wrapEffect.d.ts +3 -3
- package/package.json +4 -3
- package/src/EffectComposer.tsx +143 -42
- package/src/EffectGroup.tsx +74 -0
- package/src/createEffectComponent.tsx +71 -0
- package/src/effects/ASCII.tsx +75 -28
- package/src/effects/Autofocus.tsx +24 -77
- package/src/effects/Bloom.tsx +32 -4
- package/src/effects/BrightnessContrast.tsx +5 -2
- package/src/effects/ChromaticAberration.tsx +13 -21
- package/src/effects/ColorAverage.tsx +3 -16
- package/src/effects/ColorDepth.tsx +23 -2
- package/src/effects/Depth.tsx +4 -2
- package/src/effects/DepthOfField.tsx +48 -26
- package/src/effects/DotScreen.tsx +5 -2
- package/src/effects/FXAA.tsx +4 -2
- package/src/effects/Glitch.tsx +26 -31
- package/src/effects/GodRays.tsx +90 -6
- package/src/effects/Grid.tsx +17 -18
- package/src/effects/HueSaturation.tsx +5 -2
- package/src/effects/LUT.tsx +9 -11
- package/src/effects/LensFlare.tsx +209 -55
- package/src/effects/Noise.tsx +14 -2
- package/src/effects/Outline.tsx +55 -56
- package/src/effects/Pixelation.tsx +11 -8
- package/src/effects/Ramp.tsx +96 -7
- package/src/effects/SMAA.tsx +18 -2
- package/src/effects/SSAO.tsx +130 -22
- package/src/effects/ScanlineEffect.tsx +6 -6
- package/src/effects/SelectiveBloom.tsx +26 -44
- package/src/effects/Sepia.tsx +4 -2
- package/src/effects/ShockWave.tsx +30 -2
- package/src/effects/Texture.tsx +10 -9
- package/src/effects/TiltShift.tsx +30 -2
- package/src/effects/TiltShift2.tsx +72 -6
- package/src/effects/ToneMapping.tsx +16 -3
- package/src/effects/Vignette.tsx +5 -2
- package/src/effects/Water.tsx +21 -6
- package/src/index.ts +4 -2
- package/src/passes/DepthPicking.tsx +63 -0
- package/src/{effects → passes}/N8AO.tsx +28 -4
- package/src/tests/Autofocus.test.tsx +38 -0
- package/src/tests/Bloom.test.tsx +76 -0
- package/src/tests/ChromaticAberration.test.tsx +50 -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 +501 -8
- 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 +122 -0
- package/src/tests/SSAO.test.tsx +140 -0
- package/src/tests/SelectiveBloom.test.tsx +48 -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 +46 -42
- package/src/util.tsx +148 -23
- package/src/wrapEffect.tsx +3 -2
- package/dist/tests/test-utils.d.ts +0 -12
package/src/effects/Outline.tsx
CHANGED
|
@@ -1,83 +1,82 @@
|
|
|
1
1
|
import { OutlineEffect } from 'postprocessing'
|
|
2
|
-
import { Ref, RefObject, use, useMemo } from 'react'
|
|
3
|
-
import { Object3D } from 'three'
|
|
2
|
+
import { Ref, RefObject, use, useEffect, useMemo } from 'react'
|
|
3
|
+
import { Color, Object3D, type ColorRepresentation } from 'three'
|
|
4
4
|
import { EffectComposerContext } from '../EffectComposer'
|
|
5
|
-
import { EMPTY_ARRAY, useDispose, useSelectionSync } from '../util'
|
|
5
|
+
import { applyPierced, EMPTY_ARRAY, readPierced, useDispose, useLiveDefaults, useSelectionSync } from '../util'
|
|
6
6
|
|
|
7
7
|
type ObjectRef = RefObject<Object3D | null>
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
type OutlineEffectOptions = NonNullable<ConstructorParameters<typeof OutlineEffect>[2]>
|
|
10
|
+
|
|
11
|
+
export type OutlineProps = Omit<OutlineEffectOptions, 'visibleEdgeColor' | 'hiddenEdgeColor'> &
|
|
10
12
|
Partial<{
|
|
11
13
|
selection: Object3D | Object3D[] | ObjectRef | ObjectRef[]
|
|
12
14
|
selectionLayer: number
|
|
15
|
+
visibleEdgeColor: ColorRepresentation
|
|
16
|
+
hiddenEdgeColor: ColorRepresentation
|
|
13
17
|
ref?: Ref<OutlineEffect>
|
|
14
18
|
}>
|
|
15
19
|
|
|
20
|
+
// Every OutlineEffect option that has a real setter (verified against
|
|
21
|
+
// postprocessing's source) - resolutionScale/resolutionX/resolutionY are
|
|
22
|
+
// the only ones without one, since they only feed the internal blur pass
|
|
23
|
+
// at construction time. scene/camera are required constructor args, so
|
|
24
|
+
// OutlineEffect can't use createEffectComponent (needs `new Effect()` to
|
|
25
|
+
// work with zero args) - built by hand instead.
|
|
26
|
+
const LIVE_KEYS = [
|
|
27
|
+
'patternTexture',
|
|
28
|
+
'patternScale',
|
|
29
|
+
'edgeStrength',
|
|
30
|
+
'pulseSpeed',
|
|
31
|
+
'visibleEdgeColor',
|
|
32
|
+
'hiddenEdgeColor',
|
|
33
|
+
'multisampling',
|
|
34
|
+
'width',
|
|
35
|
+
'height',
|
|
36
|
+
'kernelSize',
|
|
37
|
+
'blur',
|
|
38
|
+
'xRay',
|
|
39
|
+
'dithering',
|
|
40
|
+
'blendMode-blendFunction',
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
// The setter stores whatever it's given as-is, unlike the constructor -
|
|
44
|
+
// wrap in a Color here too, or a raw hex/string breaks the shader uniform.
|
|
45
|
+
function set(effect: OutlineEffect, key: string, value: unknown): void {
|
|
46
|
+
if (key === 'visibleEdgeColor' || key === 'hiddenEdgeColor') applyPierced(effect, key, new Color(value as never))
|
|
47
|
+
else applyPierced(effect, key, value)
|
|
48
|
+
}
|
|
49
|
+
|
|
16
50
|
export function Outline({
|
|
17
51
|
selection = EMPTY_ARRAY,
|
|
18
52
|
selectionLayer = 10,
|
|
19
53
|
blendFunction,
|
|
20
|
-
patternTexture,
|
|
21
|
-
patternScale,
|
|
22
|
-
edgeStrength,
|
|
23
|
-
pulseSpeed,
|
|
24
|
-
visibleEdgeColor,
|
|
25
|
-
hiddenEdgeColor,
|
|
26
|
-
multisampling,
|
|
27
54
|
resolutionScale,
|
|
28
55
|
resolutionX,
|
|
29
56
|
resolutionY,
|
|
30
|
-
width,
|
|
31
|
-
height,
|
|
32
|
-
kernelSize,
|
|
33
|
-
blur,
|
|
34
|
-
xRay,
|
|
35
57
|
ref,
|
|
58
|
+
...liveProps
|
|
36
59
|
}: OutlineProps) {
|
|
37
|
-
const { scene, camera } = use(EffectComposerContext)
|
|
60
|
+
const { scene, camera, autoClear } = use(EffectComposerContext)
|
|
38
61
|
|
|
39
62
|
const effect = useMemo(
|
|
40
|
-
() =>
|
|
41
|
-
|
|
42
|
-
blendFunction,
|
|
43
|
-
patternTexture,
|
|
44
|
-
patternScale,
|
|
45
|
-
edgeStrength,
|
|
46
|
-
pulseSpeed,
|
|
47
|
-
visibleEdgeColor,
|
|
48
|
-
hiddenEdgeColor,
|
|
49
|
-
multisampling,
|
|
50
|
-
resolutionScale,
|
|
51
|
-
resolutionX,
|
|
52
|
-
resolutionY,
|
|
53
|
-
width,
|
|
54
|
-
height,
|
|
55
|
-
kernelSize,
|
|
56
|
-
blur,
|
|
57
|
-
xRay,
|
|
58
|
-
}),
|
|
59
|
-
[
|
|
60
|
-
blendFunction,
|
|
61
|
-
patternTexture,
|
|
62
|
-
patternScale,
|
|
63
|
-
edgeStrength,
|
|
64
|
-
pulseSpeed,
|
|
65
|
-
visibleEdgeColor,
|
|
66
|
-
hiddenEdgeColor,
|
|
67
|
-
multisampling,
|
|
68
|
-
resolutionScale,
|
|
69
|
-
resolutionX,
|
|
70
|
-
resolutionY,
|
|
71
|
-
width,
|
|
72
|
-
height,
|
|
73
|
-
kernelSize,
|
|
74
|
-
blur,
|
|
75
|
-
xRay,
|
|
76
|
-
camera,
|
|
77
|
-
scene,
|
|
78
|
-
]
|
|
63
|
+
() => new OutlineEffect(scene, camera, { resolutionScale, resolutionX, resolutionY }),
|
|
64
|
+
[scene, camera, resolutionScale, resolutionX, resolutionY]
|
|
79
65
|
)
|
|
80
66
|
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (autoClear !== false) {
|
|
69
|
+
console.warn('Outline requires <EffectComposer autoClear={false}> to render correctly.')
|
|
70
|
+
}
|
|
71
|
+
}, [autoClear])
|
|
72
|
+
|
|
73
|
+
useLiveDefaults(
|
|
74
|
+
effect,
|
|
75
|
+
{ ...liveProps, 'blendMode-blendFunction': blendFunction } as Record<string, unknown>,
|
|
76
|
+
LIVE_KEYS,
|
|
77
|
+
readPierced,
|
|
78
|
+
set
|
|
79
|
+
)
|
|
81
80
|
useSelectionSync(effect, selection, selectionLayer)
|
|
82
81
|
useDispose(effect)
|
|
83
82
|
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { PixelationEffect } from 'postprocessing'
|
|
2
|
-
import { Ref
|
|
3
|
-
import {
|
|
2
|
+
import type { Ref } from 'react'
|
|
3
|
+
import { createEffectComponent } from '../createEffectComponent'
|
|
4
|
+
|
|
5
|
+
// PixelationEffect's sole constructor arg is a bare number, not an options
|
|
6
|
+
// object - granularity is a real live setter though, so it's just a normal
|
|
7
|
+
// prop; only the curated default (5, vs the class's own default of 30)
|
|
8
|
+
// needs a thin wrapper.
|
|
9
|
+
const PixelationImpl = /* @__PURE__ */ createEffectComponent<typeof PixelationEffect, { granularity?: number }>(
|
|
10
|
+
PixelationEffect
|
|
11
|
+
)
|
|
4
12
|
|
|
5
13
|
export type PixelationProps = {
|
|
6
14
|
granularity?: number
|
|
@@ -8,10 +16,5 @@ export type PixelationProps = {
|
|
|
8
16
|
}
|
|
9
17
|
|
|
10
18
|
export function Pixelation({ granularity = 5, ref }: PixelationProps) {
|
|
11
|
-
|
|
12
|
-
const effect = useMemo(() => new PixelationEffect(granularity), [granularity])
|
|
13
|
-
|
|
14
|
-
useDispose(effect)
|
|
15
|
-
|
|
16
|
-
return <primitive ref={ref} object={effect} />
|
|
19
|
+
return <PixelationImpl granularity={granularity} ref={ref} />
|
|
17
20
|
}
|
package/src/effects/Ramp.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Effect } from 'postprocessing'
|
|
1
|
+
import { BlendFunction, Effect } from 'postprocessing'
|
|
2
|
+
import type { Ref } from 'react'
|
|
2
3
|
import { Uniform } from 'three'
|
|
3
|
-
import {
|
|
4
|
+
import { createEffectComponent } from '../createEffectComponent'
|
|
4
5
|
|
|
5
6
|
const RampShader = {
|
|
6
7
|
fragmentShader: /* glsl */ `
|
|
@@ -72,6 +73,9 @@ export enum RampType {
|
|
|
72
73
|
MirroredLinear,
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
type RampTuple2 = [number, number]
|
|
77
|
+
type RampTuple4 = [number, number, number, number]
|
|
78
|
+
|
|
75
79
|
export class RampEffect extends Effect {
|
|
76
80
|
constructor({
|
|
77
81
|
/**
|
|
@@ -83,25 +87,25 @@ export class RampEffect extends Effect {
|
|
|
83
87
|
*
|
|
84
88
|
* Ranges from `[0 - 1]` as `[x, y]`. Default is `[0.5, 0.5]`.
|
|
85
89
|
*/
|
|
86
|
-
rampStart = [0.5, 0.5],
|
|
90
|
+
rampStart = [0.5, 0.5] as RampTuple2,
|
|
87
91
|
/**
|
|
88
92
|
* Ending point of the ramp gradient in normalized coordinates.
|
|
89
93
|
*
|
|
90
94
|
* Ranges from `[0 - 1]` as `[x, y]`. Default is `[1, 1]`
|
|
91
95
|
*/
|
|
92
|
-
rampEnd = [1, 1],
|
|
96
|
+
rampEnd = [1, 1] as RampTuple2,
|
|
93
97
|
/**
|
|
94
98
|
* Color at the starting point of the gradient.
|
|
95
99
|
*
|
|
96
100
|
* Default is black: `[0, 0, 0, 1]`
|
|
97
101
|
*/
|
|
98
|
-
startColor = [0, 0, 0, 1],
|
|
102
|
+
startColor = [0, 0, 0, 1] as RampTuple4,
|
|
99
103
|
/**
|
|
100
104
|
* Color at the ending point of the gradient.
|
|
101
105
|
*
|
|
102
106
|
* Default is white: `[1, 1, 1, 1]`
|
|
103
107
|
*/
|
|
104
|
-
endColor = [1, 1, 1, 1],
|
|
108
|
+
endColor = [1, 1, 1, 1] as RampTuple4,
|
|
105
109
|
/**
|
|
106
110
|
* Bias for the interpolation curve when both bias and gain are 0.5.
|
|
107
111
|
*
|
|
@@ -145,6 +149,91 @@ export class RampEffect extends Effect {
|
|
|
145
149
|
]),
|
|
146
150
|
})
|
|
147
151
|
}
|
|
152
|
+
|
|
153
|
+
private u<T>(name: string): T {
|
|
154
|
+
return this.uniforms.get(name)!.value
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private setU(name: string, value: unknown): void {
|
|
158
|
+
this.uniforms.get(name)!.value = value
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
get rampType(): RampType {
|
|
162
|
+
return this.u('rampType')
|
|
163
|
+
}
|
|
164
|
+
set rampType(value: RampType) {
|
|
165
|
+
this.setU('rampType', value)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
get rampStart(): RampTuple2 {
|
|
169
|
+
return this.u('rampStart')
|
|
170
|
+
}
|
|
171
|
+
set rampStart(value: RampTuple2) {
|
|
172
|
+
this.setU('rampStart', value)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
get rampEnd(): RampTuple2 {
|
|
176
|
+
return this.u('rampEnd')
|
|
177
|
+
}
|
|
178
|
+
set rampEnd(value: RampTuple2) {
|
|
179
|
+
this.setU('rampEnd', value)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
get startColor(): RampTuple4 {
|
|
183
|
+
return this.u('startColor')
|
|
184
|
+
}
|
|
185
|
+
set startColor(value: RampTuple4) {
|
|
186
|
+
this.setU('startColor', value)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
get endColor(): RampTuple4 {
|
|
190
|
+
return this.u('endColor')
|
|
191
|
+
}
|
|
192
|
+
set endColor(value: RampTuple4) {
|
|
193
|
+
this.setU('endColor', value)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
get rampBias(): number {
|
|
197
|
+
return this.u('rampBias')
|
|
198
|
+
}
|
|
199
|
+
set rampBias(value: number) {
|
|
200
|
+
this.setU('rampBias', value)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
get rampGain(): number {
|
|
204
|
+
return this.u('rampGain')
|
|
205
|
+
}
|
|
206
|
+
set rampGain(value: number) {
|
|
207
|
+
this.setU('rampGain', value)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
get rampMask(): boolean {
|
|
211
|
+
return this.u('rampMask')
|
|
212
|
+
}
|
|
213
|
+
set rampMask(value: boolean) {
|
|
214
|
+
this.setU('rampMask', value)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
get rampInvert(): boolean {
|
|
218
|
+
return this.u('rampInvert')
|
|
219
|
+
}
|
|
220
|
+
set rampInvert(value: boolean) {
|
|
221
|
+
this.setU('rampInvert', value)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export type RampProps = {
|
|
226
|
+
blendFunction?: BlendFunction
|
|
227
|
+
rampType?: RampType
|
|
228
|
+
rampStart?: RampTuple2
|
|
229
|
+
rampEnd?: RampTuple2
|
|
230
|
+
startColor?: RampTuple4
|
|
231
|
+
endColor?: RampTuple4
|
|
232
|
+
rampBias?: number
|
|
233
|
+
rampGain?: number
|
|
234
|
+
rampMask?: boolean
|
|
235
|
+
rampInvert?: boolean
|
|
236
|
+
ref?: Ref<RampEffect>
|
|
148
237
|
}
|
|
149
238
|
|
|
150
|
-
export const Ramp = /* @__PURE__ */
|
|
239
|
+
export const Ramp = /* @__PURE__ */ createEffectComponent<typeof RampEffect, RampProps>(RampEffect)
|
package/src/effects/SMAA.tsx
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
import { SMAAEffect } from 'postprocessing'
|
|
2
|
-
import {
|
|
2
|
+
import type { Ref } from 'react'
|
|
3
|
+
import { useMemo } from 'react'
|
|
4
|
+
import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
|
|
3
5
|
|
|
4
|
-
|
|
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,13 +1,81 @@
|
|
|
1
1
|
import { BlendFunction, SSAOEffect } from 'postprocessing'
|
|
2
|
-
import { Ref,
|
|
2
|
+
import { Ref, use, useMemo } from 'react'
|
|
3
3
|
import { EffectComposerContext } from '../EffectComposer'
|
|
4
|
-
import { useDispose } from '../util'
|
|
4
|
+
import { applyPierced, readPierced, useDispose, useLiveDefaults } from '../util'
|
|
5
5
|
|
|
6
6
|
// first two args are camera and texture
|
|
7
7
|
type SSAOProps = ConstructorParameters<typeof SSAOEffect>[2] & { ref?: Ref<SSAOEffect> }
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
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)
|
|
11
79
|
|
|
12
80
|
const effect = useMemo<SSAOEffect | {}>(() => {
|
|
13
81
|
if (normalPass === null && downSamplingPass === null) {
|
|
@@ -16,29 +84,69 @@ export function SSAO({ ref, ...props }: SSAOProps) {
|
|
|
16
84
|
}
|
|
17
85
|
|
|
18
86
|
return new SSAOEffect(camera, normalPass && !downSamplingPass ? (normalPass as any).texture : null, {
|
|
19
|
-
blendFunction
|
|
20
|
-
samples
|
|
21
|
-
rings
|
|
22
|
-
distanceThreshold
|
|
23
|
-
distanceFalloff
|
|
24
|
-
rangeThreshold
|
|
25
|
-
rangeFalloff
|
|
26
|
-
luminanceInfluence
|
|
27
|
-
radius
|
|
28
|
-
bias
|
|
29
|
-
intensity
|
|
30
|
-
color: undefined,
|
|
87
|
+
blendFunction,
|
|
88
|
+
samples,
|
|
89
|
+
rings,
|
|
90
|
+
distanceThreshold,
|
|
91
|
+
distanceFalloff,
|
|
92
|
+
rangeThreshold,
|
|
93
|
+
rangeFalloff,
|
|
94
|
+
luminanceInfluence,
|
|
95
|
+
radius,
|
|
96
|
+
bias,
|
|
97
|
+
intensity,
|
|
31
98
|
// @ts-ignore
|
|
32
99
|
normalDepthBuffer: downSamplingPass ? downSamplingPass.texture : null,
|
|
33
|
-
resolutionScale: resolutionScale ?? 1,
|
|
34
|
-
|
|
35
|
-
|
|
100
|
+
resolutionScale: resolutionScale ?? composerResolutionScale ?? 1,
|
|
101
|
+
resolutionX,
|
|
102
|
+
resolutionY,
|
|
103
|
+
width,
|
|
104
|
+
height,
|
|
105
|
+
depthAwareUpsampling,
|
|
36
106
|
})
|
|
37
|
-
//
|
|
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.
|
|
38
118
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
39
|
-
}, [camera, downSamplingPass, normalPass, resolutionScale])
|
|
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
|
+
)
|
|
40
148
|
|
|
41
|
-
useDispose(effect)
|
|
149
|
+
useDispose(effect as SSAOEffect)
|
|
42
150
|
|
|
43
151
|
return <primitive ref={ref} object={effect} />
|
|
44
152
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ScanlineEffect } from 'postprocessing'
|
|
2
|
+
import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
|
|
3
3
|
|
|
4
|
-
export const Scanline = /* @__PURE__ */
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
export const Scanline = /* @__PURE__ */ createEffectComponent<
|
|
5
|
+
typeof ScanlineEffect,
|
|
6
|
+
EffectOptions<typeof ScanlineEffect>
|
|
7
|
+
>(ScanlineEffect)
|
|
@@ -4,7 +4,7 @@ import { BlendFunction, SelectiveBloomEffect } from 'postprocessing'
|
|
|
4
4
|
import { Ref, RefObject, use, useEffect, useMemo } from 'react'
|
|
5
5
|
import { Object3D } from 'three'
|
|
6
6
|
import { EffectComposerContext } from '../EffectComposer'
|
|
7
|
-
import { EMPTY_ARRAY, resolveRef, useDispose, useSelectionSync } from '../util'
|
|
7
|
+
import { EMPTY_ARRAY, resolveRef, useDispose, useLiveDefaults, useSelectionSync } from '../util'
|
|
8
8
|
|
|
9
9
|
type ObjectRef = RefObject<Object3D | null>
|
|
10
10
|
|
|
@@ -21,67 +21,49 @@ export type SelectiveBloomProps = BloomEffectOptions &
|
|
|
21
21
|
const addLight = (light: Object3D, effect: SelectiveBloomEffect) => light.layers.enable(effect.selection.layer)
|
|
22
22
|
const removeLight = (light: Object3D, effect: SelectiveBloomEffect) => light.layers.disable(effect.selection.layer)
|
|
23
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
|
+
|
|
24
31
|
export function SelectiveBloom({
|
|
25
32
|
selection = EMPTY_ARRAY,
|
|
26
33
|
selectionLayer = 10,
|
|
27
34
|
lights = EMPTY_ARRAY,
|
|
28
|
-
inverted = false,
|
|
29
|
-
ignoreBackground = false,
|
|
30
35
|
luminanceThreshold,
|
|
31
36
|
luminanceSmoothing,
|
|
32
37
|
mipmapBlur,
|
|
33
|
-
intensity,
|
|
34
38
|
radius,
|
|
35
39
|
levels,
|
|
36
|
-
kernelSize,
|
|
37
40
|
resolutionScale,
|
|
38
|
-
width,
|
|
39
|
-
height,
|
|
40
41
|
resolutionX,
|
|
41
42
|
resolutionY,
|
|
42
43
|
ref,
|
|
44
|
+
...liveProps
|
|
43
45
|
}: SelectiveBloomProps) {
|
|
44
46
|
const { scene, camera } = use(EffectComposerContext)
|
|
45
47
|
|
|
46
48
|
const invalidate = useThree((state) => state.invalidate)
|
|
47
49
|
|
|
48
|
-
const effect = useMemo(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
instance.ignoreBackground = ignoreBackground
|
|
66
|
-
return instance
|
|
67
|
-
}, [
|
|
68
|
-
scene,
|
|
69
|
-
camera,
|
|
70
|
-
luminanceThreshold,
|
|
71
|
-
luminanceSmoothing,
|
|
72
|
-
mipmapBlur,
|
|
73
|
-
intensity,
|
|
74
|
-
radius,
|
|
75
|
-
levels,
|
|
76
|
-
kernelSize,
|
|
77
|
-
resolutionScale,
|
|
78
|
-
width,
|
|
79
|
-
height,
|
|
80
|
-
resolutionX,
|
|
81
|
-
resolutionY,
|
|
82
|
-
inverted,
|
|
83
|
-
ignoreBackground,
|
|
84
|
-
])
|
|
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)
|
|
85
67
|
|
|
86
68
|
// Must run before the lights effect below: addLight/removeLight read
|
|
87
69
|
// effect.selection.layer live, so it needs to already reflect the
|
package/src/effects/Sepia.tsx
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { SepiaEffect } from 'postprocessing'
|
|
2
|
-
import {
|
|
2
|
+
import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
|
|
3
3
|
|
|
4
|
-
export const Sepia = /* @__PURE__ */
|
|
4
|
+
export const Sepia = /* @__PURE__ */ createEffectComponent<typeof SepiaEffect, EffectOptions<typeof SepiaEffect>>(
|
|
5
|
+
SepiaEffect
|
|
6
|
+
)
|
|
@@ -1,4 +1,32 @@
|
|
|
1
|
+
import type { ReactThreeFiber } from '@react-three/fiber'
|
|
1
2
|
import { ShockWaveEffect } from 'postprocessing'
|
|
2
|
-
import {
|
|
3
|
+
import { Ref, use, useMemo } from 'react'
|
|
4
|
+
import { EffectComposerContext } from '../EffectComposer'
|
|
5
|
+
import { useDispose, useLiveDefaults, useVector3 } from '../util'
|
|
3
6
|
|
|
4
|
-
export
|
|
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
|
+
}
|