@react-three/postprocessing 3.0.3 → 3.0.5
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 +81 -81
- package/dist/EffectComposer.d.ts +28 -0
- package/dist/Selection.d.ts +17 -0
- package/dist/effects/ASCII.d.ts +19 -0
- package/dist/effects/Autofocus.d.ts +23 -0
- package/dist/effects/Bloom.d.ts +2 -0
- package/dist/effects/BrightnessContrast.d.ts +2 -0
- package/dist/effects/ChromaticAberration.d.ts +8 -0
- package/dist/effects/ColorAverage.d.ts +7 -0
- package/dist/effects/ColorDepth.d.ts +2 -0
- package/dist/effects/Depth.d.ts +2 -0
- package/dist/effects/DepthOfField.d.ts +14 -0
- package/dist/effects/DotScreen.d.ts +2 -0
- package/dist/effects/FXAA.d.ts +2 -0
- package/dist/effects/Glitch.d.ts +13 -0
- package/dist/effects/GodRays.d.ts +9 -0
- package/dist/effects/Grid.d.ts +11 -0
- package/dist/effects/HueSaturation.d.ts +2 -0
- package/dist/effects/LUT.d.ts +10 -0
- package/dist/effects/LensFlare.d.ts +54 -0
- package/dist/effects/N8AO.d.ts +19 -0
- package/dist/effects/Noise.d.ts +2 -0
- package/dist/effects/Outline.d.ts +11 -0
- package/dist/effects/Pixelation.d.ts +7 -0
- package/dist/effects/Ramp.d.ts +74 -0
- package/dist/effects/SMAA.d.ts +2 -0
- package/dist/effects/SSAO.d.ts +7 -0
- package/dist/effects/ScanlineEffect.d.ts +2 -0
- package/dist/effects/SelectiveBloom.d.ts +15 -0
- package/dist/effects/Sepia.d.ts +2 -0
- package/dist/effects/ShockWave.d.ts +2 -0
- package/dist/effects/Texture.d.ts +10 -0
- package/dist/effects/TiltShift.d.ts +2 -0
- package/dist/effects/TiltShift2.d.ts +18 -0
- package/dist/effects/ToneMapping.d.ts +4 -0
- package/dist/effects/Vignette.d.ts +2 -0
- package/dist/effects/Water.d.ts +8 -0
- package/dist/index.d.ts +38 -1
- package/dist/index.js +855 -551
- package/dist/index.js.map +1 -1
- package/dist/tests/test-utils.d.ts +12 -0
- package/dist/util.d.ts +25 -0
- package/dist/wrapEffect.d.ts +12 -0
- package/package.json +73 -66
- package/src/EffectComposer.tsx +278 -200
- package/src/Selection.tsx +86 -46
- package/src/effects/ASCII.tsx +136 -135
- package/src/effects/Autofocus.tsx +175 -153
- package/src/effects/Bloom.tsx +6 -6
- package/src/effects/BrightnessContrast.tsx +4 -4
- package/src/effects/ChromaticAberration.tsx +30 -5
- package/src/effects/ColorAverage.tsx +17 -15
- package/src/effects/ColorDepth.tsx +4 -4
- package/src/effects/Depth.tsx +4 -4
- package/src/effects/DepthOfField.tsx +87 -89
- package/src/effects/DotScreen.tsx +4 -4
- package/src/effects/FXAA.tsx +4 -4
- package/src/effects/Glitch.tsx +37 -40
- package/src/effects/GodRays.tsx +20 -16
- package/src/effects/Grid.tsx +28 -21
- package/src/effects/HueSaturation.tsx +4 -4
- package/src/effects/LUT.tsx +27 -26
- package/src/effects/LensFlare.tsx +611 -611
- package/src/effects/N8AO.tsx +81 -81
- package/src/effects/Noise.tsx +4 -4
- package/src/effects/Outline.tsx +85 -117
- package/src/effects/Pixelation.tsx +17 -15
- package/src/effects/Ramp.tsx +150 -150
- package/src/effects/SMAA.tsx +4 -4
- package/src/effects/SSAO.tsx +44 -41
- package/src/effects/ScanlineEffect.tsx +7 -7
- package/src/effects/SelectiveBloom.tsx +116 -126
- package/src/effects/Sepia.tsx +4 -4
- package/src/effects/ShockWave.tsx +4 -4
- package/src/effects/Texture.tsx +27 -23
- package/src/effects/TiltShift.tsx +4 -4
- package/src/effects/TiltShift2.tsx +90 -90
- package/src/effects/ToneMapping.tsx +6 -6
- package/src/effects/Vignette.tsx +4 -4
- package/src/effects/Water.tsx +35 -35
- package/src/index.ts +41 -40
- package/src/tests/ChromaticAberration.test.tsx +31 -0
- package/src/tests/EffectComposer.test.tsx +911 -0
- package/src/tests/Outline.test.tsx +89 -0
- package/src/tests/Selection.test.tsx +324 -0
- package/src/tests/SelectiveBloom.test.tsx +118 -0
- package/src/tests/effects.smoke.test.tsx +234 -0
- package/src/tests/test-utils.tsx +96 -0
- package/src/tests/wrapEffect.test.tsx +209 -0
- package/src/util.tsx +96 -55
- package/src/wrapEffect.tsx +122 -0
- package/src/EffectComposer.test.tsx +0 -126
package/src/util.tsx
CHANGED
|
@@ -1,55 +1,96 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
export
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
1
|
+
import { useThree, type ReactThreeFiber } from '@react-three/fiber'
|
|
2
|
+
import type { Selection as PPSelection } from 'postprocessing'
|
|
3
|
+
import { use, useEffect, useMemo, useRef, type RefObject } from 'react'
|
|
4
|
+
import { Object3D, Vector2, type Vector2Tuple } from 'three'
|
|
5
|
+
import { selectionContext } from './Selection'
|
|
6
|
+
|
|
7
|
+
// Stable reference for array-typed props defaulting to "nothing" - `= []`
|
|
8
|
+
// as a default parameter allocates a new array on every call, which is
|
|
9
|
+
// enough to retrigger any effect that depends on it.
|
|
10
|
+
export const EMPTY_ARRAY: never[] = []
|
|
11
|
+
|
|
12
|
+
export const resolveRef = <T,>(ref: T | RefObject<T>) =>
|
|
13
|
+
typeof ref === 'object' && ref != null && 'current' in ref ? ref.current : ref
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Keeps a postprocessing effect's `selection` (and its render layer) in
|
|
17
|
+
* sync with either mode effects support: the manual
|
|
18
|
+
* `selection` prop (used only when there's no enclosing <Selection>), or
|
|
19
|
+
* the declarative Selection/Select API. The two are mutually exclusive -
|
|
20
|
+
* context wins when both are present.
|
|
21
|
+
*/
|
|
22
|
+
export function useSelectionSync(
|
|
23
|
+
effect: { selection: PPSelection },
|
|
24
|
+
selection: Object3D | Object3D[] | RefObject<Object3D | null> | RefObject<Object3D | null>[],
|
|
25
|
+
selectionLayer: number
|
|
26
|
+
): void {
|
|
27
|
+
const invalidate = useThree((state) => state.invalidate)
|
|
28
|
+
const api = use(selectionContext)
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
effect.selection.layer = selectionLayer
|
|
32
|
+
invalidate()
|
|
33
|
+
}, [effect, invalidate, selectionLayer])
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (api) return
|
|
37
|
+
const resolved = (Array.isArray(selection) ? selection.map((o) => resolveRef(o)) : [resolveRef(selection)]).filter(
|
|
38
|
+
(o): o is Object3D => o != null
|
|
39
|
+
)
|
|
40
|
+
if (!resolved.length) return
|
|
41
|
+
|
|
42
|
+
effect.selection.set(resolved)
|
|
43
|
+
invalidate()
|
|
44
|
+
return () => {
|
|
45
|
+
effect.selection.clear()
|
|
46
|
+
invalidate()
|
|
47
|
+
}
|
|
48
|
+
}, [effect, selection, api, invalidate])
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (api && api.enabled && api.selected?.length) {
|
|
52
|
+
effect.selection.set(api.selected)
|
|
53
|
+
invalidate()
|
|
54
|
+
return () => {
|
|
55
|
+
effect.selection.clear()
|
|
56
|
+
invalidate()
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}, [api, effect.selection, invalidate])
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* r3f never disposes <primitive> objects (their state may be owned outside
|
|
64
|
+
* React), so effects rendered that way must dispose themselves. Guards
|
|
65
|
+
* against double-dispose across StrictMode's dev-only mount/cleanup/mount
|
|
66
|
+
* cycle, where the cleanup closure re-runs against the same instance.
|
|
67
|
+
*/
|
|
68
|
+
export const useDispose = <T extends { dispose?: () => void }>(instance: T): void => {
|
|
69
|
+
const disposedRef = useRef<WeakSet<object>>(new WeakSet())
|
|
70
|
+
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
const disposed = disposedRef.current
|
|
73
|
+
return () => {
|
|
74
|
+
if (instance && typeof instance === 'object' && !disposed.has(instance)) {
|
|
75
|
+
disposed.add(instance)
|
|
76
|
+
instance.dispose?.()
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}, [instance])
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const useVector2 = (props: Record<string, unknown>, key: string): Vector2 => {
|
|
83
|
+
const value = props[key] as ReactThreeFiber.Vector2 | undefined
|
|
84
|
+
|
|
85
|
+
return useMemo(() => {
|
|
86
|
+
if (typeof value === 'number') {
|
|
87
|
+
return new Vector2(value, value)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (value) {
|
|
91
|
+
return new Vector2(...(value as Vector2Tuple))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return new Vector2()
|
|
95
|
+
}, [value])
|
|
96
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { extend, useThree } from '@react-three/fiber'
|
|
2
|
+
import type { BlendFunction, Effect, Pass } from 'postprocessing'
|
|
3
|
+
import { useMemo, type ExoticComponent, type JSX, type Ref } from 'react'
|
|
4
|
+
|
|
5
|
+
export type EffectConstructor = new (...args: any[]) => Effect | Pass
|
|
6
|
+
|
|
7
|
+
// Handles three ConstructorParameters<T> shapes: required first param
|
|
8
|
+
// (P), optional first param (Partial<P> — some effects in postprocessing
|
|
9
|
+
// type inner fields as required even though the whole object is
|
|
10
|
+
// omittable), and no params at all ({})
|
|
11
|
+
type FirstConstructorParam<T extends EffectConstructor> =
|
|
12
|
+
ConstructorParameters<T> extends [infer P, ...any[]]
|
|
13
|
+
? P
|
|
14
|
+
: ConstructorParameters<T> extends [(infer P)?, ...any[]]
|
|
15
|
+
? Partial<P>
|
|
16
|
+
: {}
|
|
17
|
+
|
|
18
|
+
export type EffectProps<T extends EffectConstructor> = FirstConstructorParam<T> & {
|
|
19
|
+
ref?: Ref<InstanceType<T>>
|
|
20
|
+
blendFunction?: BlendFunction
|
|
21
|
+
opacity?: number
|
|
22
|
+
args?: ConstructorParameters<T>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let i = 0
|
|
26
|
+
|
|
27
|
+
const components = new WeakMap<EffectConstructor, ExoticComponent<any> | string>()
|
|
28
|
+
|
|
29
|
+
const identityTokens = new WeakMap<object, number>()
|
|
30
|
+
let nextIdentityToken = 0
|
|
31
|
+
|
|
32
|
+
// Same object in, same token out — lets otherwise-opaque values (textures,
|
|
33
|
+
// refs, any class instance) still change the fingerprint when swapped for
|
|
34
|
+
// a different instance, without walking into them.
|
|
35
|
+
function identityOf(value: object): number {
|
|
36
|
+
let token = identityTokens.get(value)
|
|
37
|
+
if (token === undefined) {
|
|
38
|
+
token = nextIdentityToken++
|
|
39
|
+
identityTokens.set(value, token)
|
|
40
|
+
}
|
|
41
|
+
return token
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Walks props into a JSON-safe fingerprint for the args memo below. Two
|
|
45
|
+
// things JSON.stringify can't be trusted with here:
|
|
46
|
+
// - it throws on cycles (refs, or any three.js object with a back-
|
|
47
|
+
// reference), so cycles are cut off with a WeakSet guard instead.
|
|
48
|
+
// - it calls a value's own toJSON first if present, which for e.g.
|
|
49
|
+
// THREE.Texture re-encodes the whole image to a base64 data URL on
|
|
50
|
+
// every single render (measured ~39ms for a 512x512 texture) just to
|
|
51
|
+
// throw the result away. Reading properties directly sidesteps that.
|
|
52
|
+
// - reading properties directly instead means typed arrays need their
|
|
53
|
+
// own case: Object.keys() on one returns every numeric index, so
|
|
54
|
+
// walking a texture's backing buffer element-by-element is even
|
|
55
|
+
// slower (~340ms for the same texture) than the toJSON it replaces.
|
|
56
|
+
// Identity is enough — same buffer means unchanged.
|
|
57
|
+
function fingerprint(value: unknown, seen: WeakSet<object>): unknown {
|
|
58
|
+
if (value === null || typeof value !== 'object') return value
|
|
59
|
+
if (seen.has(value)) return '[Circular]'
|
|
60
|
+
|
|
61
|
+
if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
|
|
62
|
+
return identityOf(value)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
seen.add(value)
|
|
66
|
+
|
|
67
|
+
if (Array.isArray(value)) {
|
|
68
|
+
return value.map((item) => fingerprint(item, seen))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const out: Record<string, unknown> = {}
|
|
72
|
+
for (const key of Object.keys(value).sort()) {
|
|
73
|
+
out[key] = fingerprint((value as Record<string, unknown>)[key], seen)
|
|
74
|
+
}
|
|
75
|
+
return out
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function stableStringify(value: unknown): string {
|
|
79
|
+
return JSON.stringify(fingerprint(value, new WeakSet()))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function wrapEffect<T extends EffectConstructor>(
|
|
83
|
+
effect: T,
|
|
84
|
+
defaults?: EffectProps<T>
|
|
85
|
+
): (props: EffectProps<T>) => JSX.Element {
|
|
86
|
+
return function WrappedEffect({
|
|
87
|
+
ref,
|
|
88
|
+
blendFunction = defaults?.blendFunction,
|
|
89
|
+
opacity = defaults?.opacity,
|
|
90
|
+
...props
|
|
91
|
+
}) {
|
|
92
|
+
let Component = components.get(effect)
|
|
93
|
+
|
|
94
|
+
if (!Component) {
|
|
95
|
+
const key = `@react-three/postprocessing/${effect.name}-${i++}`
|
|
96
|
+
extend({ [key]: effect })
|
|
97
|
+
components.set(effect, (Component = key))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const camera = useThree((state) => state.camera)
|
|
101
|
+
|
|
102
|
+
const args = useMemo(
|
|
103
|
+
() => [
|
|
104
|
+
...((defaults?.args as unknown as any[]) ?? []),
|
|
105
|
+
...((props.args as unknown as any[]) ?? [{ ...defaults, ...props }]),
|
|
106
|
+
],
|
|
107
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
108
|
+
[stableStringify(props)]
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<Component
|
|
113
|
+
camera={camera}
|
|
114
|
+
blendMode-blendFunction={blendFunction}
|
|
115
|
+
blendMode-opacity-value={opacity}
|
|
116
|
+
{...props}
|
|
117
|
+
args={args}
|
|
118
|
+
ref={ref}
|
|
119
|
+
/>
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
2
|
-
import * as THREE from 'three'
|
|
3
|
-
import { vi, describe, it, expect } from 'vitest'
|
|
4
|
-
import { extend, createRoot, act } from '@react-three/fiber'
|
|
5
|
-
import { EffectComposer } from './EffectComposer'
|
|
6
|
-
import { EffectComposer as EffectComposerImpl, RenderPass, Pass, Effect, EffectPass } from 'postprocessing'
|
|
7
|
-
|
|
8
|
-
// Let React know that we'll be testing effectful components
|
|
9
|
-
declare global {
|
|
10
|
-
var IS_REACT_ACT_ENVIRONMENT: boolean
|
|
11
|
-
}
|
|
12
|
-
global.IS_REACT_ACT_ENVIRONMENT = true
|
|
13
|
-
|
|
14
|
-
// Create virtual R3F root for testing
|
|
15
|
-
extend(THREE as any)
|
|
16
|
-
const root = createRoot({
|
|
17
|
-
style: {} as CSSStyleDeclaration,
|
|
18
|
-
addEventListener: (() => {}) as any,
|
|
19
|
-
removeEventListener: (() => {}) as any,
|
|
20
|
-
width: 1280,
|
|
21
|
-
height: 800,
|
|
22
|
-
clientWidth: 1280,
|
|
23
|
-
clientHeight: 800,
|
|
24
|
-
getContext: (() =>
|
|
25
|
-
new Proxy(
|
|
26
|
-
{},
|
|
27
|
-
{
|
|
28
|
-
get(_target, prop) {
|
|
29
|
-
switch (prop) {
|
|
30
|
-
case 'getParameter':
|
|
31
|
-
return () => 'WebGL 2' // GL_VERSION
|
|
32
|
-
case 'getExtension':
|
|
33
|
-
return () => ({}) // EXT_blend_minmax
|
|
34
|
-
case 'getContextAttributes':
|
|
35
|
-
return () => ({ alpha: true })
|
|
36
|
-
case 'getShaderPrecisionFormat':
|
|
37
|
-
return () => ({ rangeMin: 1, rangeMax: 1, precision: 1 })
|
|
38
|
-
default:
|
|
39
|
-
return () => {}
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
}
|
|
43
|
-
)) as any,
|
|
44
|
-
} satisfies Partial<HTMLCanvasElement> as HTMLCanvasElement)
|
|
45
|
-
root.configure({ frameloop: 'never' })
|
|
46
|
-
|
|
47
|
-
const EFFECT_SHADER = 'mainImage() {}'
|
|
48
|
-
|
|
49
|
-
describe('EffectComposer', () => {
|
|
50
|
-
it('should merge effects together', async () => {
|
|
51
|
-
const composerRef = React.createRef<EffectComposerImpl>()
|
|
52
|
-
|
|
53
|
-
const effectA = new Effect('A', EFFECT_SHADER)
|
|
54
|
-
const effectB = new Effect('B', EFFECT_SHADER)
|
|
55
|
-
const effectC = new Effect('C', EFFECT_SHADER)
|
|
56
|
-
const passA = new Pass()
|
|
57
|
-
const passB = new Pass()
|
|
58
|
-
|
|
59
|
-
// Forward order
|
|
60
|
-
await act(async () =>
|
|
61
|
-
root.render(
|
|
62
|
-
<EffectComposer ref={composerRef}>
|
|
63
|
-
{/* EffectPass(effectA, effectB) */}
|
|
64
|
-
<primitive object={effectA} />
|
|
65
|
-
<primitive object={effectB} />
|
|
66
|
-
{/* PassA */}
|
|
67
|
-
<primitive object={passA} />
|
|
68
|
-
{/* EffectPass(effectC) */}
|
|
69
|
-
<primitive object={effectC} />
|
|
70
|
-
{/* PassB */}
|
|
71
|
-
<primitive object={passB} />
|
|
72
|
-
</EffectComposer>
|
|
73
|
-
)
|
|
74
|
-
)
|
|
75
|
-
expect(composerRef.current!.passes.map((p) => p.constructor)).toStrictEqual([
|
|
76
|
-
RenderPass,
|
|
77
|
-
EffectPass,
|
|
78
|
-
Pass,
|
|
79
|
-
EffectPass,
|
|
80
|
-
Pass,
|
|
81
|
-
])
|
|
82
|
-
// @ts-expect-error
|
|
83
|
-
expect((composerRef.current!.passes[1] as EffectPass).effects).toStrictEqual([effectA, effectB])
|
|
84
|
-
expect(composerRef.current!.passes[2]).toBe(passA)
|
|
85
|
-
// @ts-expect-error
|
|
86
|
-
expect((composerRef.current!.passes[3] as EffectPass).effects).toStrictEqual([effectC])
|
|
87
|
-
expect(composerRef.current!.passes[4]).toBe(passB)
|
|
88
|
-
|
|
89
|
-
// NOTE: instance children ordering is unstable until R3F v9, so we remount from scratch
|
|
90
|
-
await act(async () => root.render(null))
|
|
91
|
-
|
|
92
|
-
// Reverse order
|
|
93
|
-
await act(async () =>
|
|
94
|
-
root.render(
|
|
95
|
-
<EffectComposer ref={composerRef}>
|
|
96
|
-
{/* PassB */}
|
|
97
|
-
<primitive object={passB} />
|
|
98
|
-
{/* EffectPass(effectC) */}
|
|
99
|
-
<primitive object={effectC} />
|
|
100
|
-
{/* PassA */}
|
|
101
|
-
<primitive object={passA} />
|
|
102
|
-
{/* EffectPass(effectB, effectA) */}
|
|
103
|
-
<primitive object={effectB} />
|
|
104
|
-
<primitive object={effectA} />
|
|
105
|
-
</EffectComposer>
|
|
106
|
-
)
|
|
107
|
-
)
|
|
108
|
-
expect(composerRef.current!.passes.map((p) => p.constructor)).toStrictEqual([
|
|
109
|
-
RenderPass,
|
|
110
|
-
Pass,
|
|
111
|
-
EffectPass,
|
|
112
|
-
Pass,
|
|
113
|
-
EffectPass,
|
|
114
|
-
])
|
|
115
|
-
expect(composerRef.current!.passes[1]).toBe(passB)
|
|
116
|
-
// @ts-expect-error
|
|
117
|
-
expect((composerRef.current!.passes[2] as EffectPass).effects).toStrictEqual([effectC])
|
|
118
|
-
expect(composerRef.current!.passes[3]).toBe(passA)
|
|
119
|
-
// @ts-expect-error
|
|
120
|
-
expect((composerRef.current!.passes[4] as EffectPass).effects).toStrictEqual([effectB, effectA])
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it.skip('should split convolution effects', async () => {
|
|
124
|
-
await act(async () => root.render(null))
|
|
125
|
-
})
|
|
126
|
-
})
|