@react-three/postprocessing 3.0.0-rc.1 → 3.0.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.
Files changed (45) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +81 -81
  3. package/package.json +68 -68
  4. package/src/EffectComposer.test.tsx +126 -126
  5. package/src/EffectComposer.tsx +200 -200
  6. package/src/Selection.tsx +46 -46
  7. package/src/effects/ASCII.tsx +135 -135
  8. package/src/effects/Autofocus.tsx +153 -153
  9. package/src/effects/Bloom.tsx +6 -6
  10. package/src/effects/BrightnessContrast.tsx +4 -4
  11. package/src/effects/ChromaticAberration.tsx +5 -5
  12. package/src/effects/ColorAverage.tsx +15 -15
  13. package/src/effects/ColorDepth.tsx +4 -4
  14. package/src/effects/Depth.tsx +4 -4
  15. package/src/effects/DepthOfField.tsx +89 -89
  16. package/src/effects/DotScreen.tsx +4 -4
  17. package/src/effects/FXAA.tsx +4 -4
  18. package/src/effects/Glitch.tsx +40 -40
  19. package/src/effects/GodRays.tsx +16 -16
  20. package/src/effects/Grid.tsx +21 -21
  21. package/src/effects/HueSaturation.tsx +4 -4
  22. package/src/effects/LUT.tsx +26 -26
  23. package/src/effects/LensFlare.tsx +611 -611
  24. package/src/effects/N8AO.tsx +81 -81
  25. package/src/effects/Noise.tsx +4 -4
  26. package/src/effects/Outline.tsx +117 -117
  27. package/src/effects/Pixelation.tsx +15 -15
  28. package/src/effects/Ramp.tsx +150 -150
  29. package/src/effects/SMAA.tsx +4 -4
  30. package/src/effects/SSAO.tsx +41 -41
  31. package/src/effects/ScanlineEffect.tsx +7 -7
  32. package/src/effects/SelectiveBloom.tsx +126 -126
  33. package/src/effects/Sepia.tsx +4 -4
  34. package/src/effects/ShockWave.tsx +4 -4
  35. package/src/effects/Texture.tsx +23 -23
  36. package/src/effects/TiltShift.tsx +4 -4
  37. package/src/effects/TiltShift2.tsx +90 -90
  38. package/src/effects/ToneMapping.tsx +6 -6
  39. package/src/effects/Vignette.tsx +4 -4
  40. package/src/effects/Water.tsx +35 -35
  41. package/src/index.ts +40 -40
  42. package/src/util.tsx +55 -55
  43. package/dist/index.d.ts +0 -1
  44. package/dist/index.js +0 -555
  45. package/dist/index.js.map +0 -1
@@ -1,200 +1,200 @@
1
- import type { TextureDataType, Group, Camera, Scene } from 'three'
2
- import { HalfFloatType, NoToneMapping } from 'three'
3
- import {
4
- type JSX,
5
- memo,
6
- forwardRef,
7
- useMemo,
8
- useEffect,
9
- useLayoutEffect,
10
- createContext,
11
- useRef,
12
- useImperativeHandle,
13
- } from 'react'
14
- import { useThree, useFrame, type Instance } from '@react-three/fiber'
15
- import {
16
- EffectComposer as EffectComposerImpl,
17
- RenderPass,
18
- EffectPass,
19
- NormalPass,
20
- DepthDownsamplingPass,
21
- Effect,
22
- Pass,
23
- EffectAttribute,
24
- } from 'postprocessing'
25
-
26
- export const EffectComposerContext = /* @__PURE__ */ createContext<{
27
- composer: EffectComposerImpl
28
- normalPass: NormalPass | null
29
- downSamplingPass: DepthDownsamplingPass | null
30
- camera: Camera
31
- scene: Scene
32
- resolutionScale?: number
33
- }>(null!)
34
-
35
- export type EffectComposerProps = {
36
- enabled?: boolean
37
- children: JSX.Element | JSX.Element[]
38
- depthBuffer?: boolean
39
- /** Only used for SSGI currently, leave it disabled for everything else unless it's needed */
40
- enableNormalPass?: boolean
41
- stencilBuffer?: boolean
42
- autoClear?: boolean
43
- resolutionScale?: number
44
- multisampling?: number
45
- frameBufferType?: TextureDataType
46
- renderPriority?: number
47
- camera?: Camera
48
- scene?: Scene
49
- }
50
-
51
- const isConvolution = (effect: Effect): boolean =>
52
- (effect.getAttributes() & EffectAttribute.CONVOLUTION) === EffectAttribute.CONVOLUTION
53
-
54
- export const EffectComposer = /* @__PURE__ */ memo(
55
- /* @__PURE__ */ forwardRef<EffectComposerImpl, EffectComposerProps>(
56
- (
57
- {
58
- children,
59
- camera: _camera,
60
- scene: _scene,
61
- resolutionScale,
62
- enabled = true,
63
- renderPriority = 1,
64
- autoClear = true,
65
- depthBuffer,
66
- enableNormalPass,
67
- stencilBuffer,
68
- multisampling = 8,
69
- frameBufferType = HalfFloatType,
70
- },
71
- ref
72
- ) => {
73
- const { gl, scene: defaultScene, camera: defaultCamera, size } = useThree()
74
- const scene = _scene || defaultScene
75
- const camera = _camera || defaultCamera
76
-
77
- const [composer, normalPass, downSamplingPass] = useMemo(() => {
78
- // Initialize composer
79
- const effectComposer = new EffectComposerImpl(gl, {
80
- depthBuffer,
81
- stencilBuffer,
82
- multisampling,
83
- frameBufferType,
84
- })
85
-
86
- // Add render pass
87
- effectComposer.addPass(new RenderPass(scene, camera))
88
-
89
- // Create normal pass
90
- let downSamplingPass = null
91
- let normalPass = null
92
- if (enableNormalPass) {
93
- normalPass = new NormalPass(scene, camera)
94
- normalPass.enabled = false
95
- effectComposer.addPass(normalPass)
96
- if (resolutionScale !== undefined) {
97
- downSamplingPass = new DepthDownsamplingPass({ normalBuffer: normalPass.texture, resolutionScale })
98
- downSamplingPass.enabled = false
99
- effectComposer.addPass(downSamplingPass)
100
- }
101
- }
102
-
103
- return [effectComposer, normalPass, downSamplingPass]
104
- }, [
105
- camera,
106
- gl,
107
- depthBuffer,
108
- stencilBuffer,
109
- multisampling,
110
- frameBufferType,
111
- scene,
112
- enableNormalPass,
113
- resolutionScale,
114
- ])
115
-
116
- useEffect(() => composer?.setSize(size.width, size.height), [composer, size])
117
- useFrame(
118
- (_, delta) => {
119
- if (enabled) {
120
- const currentAutoClear = gl.autoClear
121
- gl.autoClear = autoClear
122
- if (stencilBuffer && !autoClear) gl.clearStencil()
123
- composer.render(delta)
124
- gl.autoClear = currentAutoClear
125
- }
126
- },
127
- enabled ? renderPriority : 0
128
- )
129
-
130
- const group = useRef<Group>(null!)
131
- useLayoutEffect(() => {
132
- const passes: Pass[] = []
133
-
134
- // TODO: rewrite all of this with R3F v9
135
- const groupInstance = (group.current as Group & { __r3f: Instance<Group> }).__r3f
136
-
137
- if (groupInstance && composer) {
138
- const children = groupInstance.children
139
-
140
- for (let i = 0; i < children.length; i++) {
141
- const child = children[i].object
142
-
143
- if (child instanceof Effect) {
144
- const effects: Effect[] = [child]
145
-
146
- if (!isConvolution(child)) {
147
- let next: unknown = null
148
- while ((next = children[i + 1]?.object) instanceof Effect) {
149
- if (isConvolution(next)) break
150
- effects.push(next)
151
- i++
152
- }
153
- }
154
-
155
- const pass = new EffectPass(camera, ...effects)
156
- passes.push(pass)
157
- } else if (child instanceof Pass) {
158
- passes.push(child)
159
- }
160
- }
161
-
162
- for (const pass of passes) composer?.addPass(pass)
163
-
164
- if (normalPass) normalPass.enabled = true
165
- if (downSamplingPass) downSamplingPass.enabled = true
166
- }
167
-
168
- return () => {
169
- for (const pass of passes) composer?.removePass(pass)
170
- if (normalPass) normalPass.enabled = false
171
- if (downSamplingPass) downSamplingPass.enabled = false
172
- }
173
- }, [composer, children, camera, normalPass, downSamplingPass])
174
-
175
- // Disable tone mapping because threejs disallows tonemapping on render targets
176
- useEffect(() => {
177
- const currentTonemapping = gl.toneMapping
178
- gl.toneMapping = NoToneMapping
179
- return () => {
180
- gl.toneMapping = currentTonemapping
181
- }
182
- }, [gl])
183
-
184
- // Memoize state, otherwise it would trigger all consumers on every render
185
- const state = useMemo(
186
- () => ({ composer, normalPass, downSamplingPass, resolutionScale, camera, scene }),
187
- [composer, normalPass, downSamplingPass, resolutionScale, camera, scene]
188
- )
189
-
190
- // Expose the composer
191
- useImperativeHandle(ref, () => composer, [composer])
192
-
193
- return (
194
- <EffectComposerContext.Provider value={state}>
195
- <group ref={group}>{children}</group>
196
- </EffectComposerContext.Provider>
197
- )
198
- }
199
- )
200
- )
1
+ import type { TextureDataType, Group, Camera, Scene } from 'three'
2
+ import { HalfFloatType, NoToneMapping } from 'three'
3
+ import {
4
+ type JSX,
5
+ memo,
6
+ forwardRef,
7
+ useMemo,
8
+ useEffect,
9
+ useLayoutEffect,
10
+ createContext,
11
+ useRef,
12
+ useImperativeHandle,
13
+ } from 'react'
14
+ import { useThree, useFrame, type Instance } from '@react-three/fiber'
15
+ import {
16
+ EffectComposer as EffectComposerImpl,
17
+ RenderPass,
18
+ EffectPass,
19
+ NormalPass,
20
+ DepthDownsamplingPass,
21
+ Effect,
22
+ Pass,
23
+ EffectAttribute,
24
+ } from 'postprocessing'
25
+
26
+ export const EffectComposerContext = /* @__PURE__ */ createContext<{
27
+ composer: EffectComposerImpl
28
+ normalPass: NormalPass | null
29
+ downSamplingPass: DepthDownsamplingPass | null
30
+ camera: Camera
31
+ scene: Scene
32
+ resolutionScale?: number
33
+ }>(null!)
34
+
35
+ export type EffectComposerProps = {
36
+ enabled?: boolean
37
+ children: JSX.Element | JSX.Element[]
38
+ depthBuffer?: boolean
39
+ /** Only used for SSGI currently, leave it disabled for everything else unless it's needed */
40
+ enableNormalPass?: boolean
41
+ stencilBuffer?: boolean
42
+ autoClear?: boolean
43
+ resolutionScale?: number
44
+ multisampling?: number
45
+ frameBufferType?: TextureDataType
46
+ renderPriority?: number
47
+ camera?: Camera
48
+ scene?: Scene
49
+ }
50
+
51
+ const isConvolution = (effect: Effect): boolean =>
52
+ (effect.getAttributes() & EffectAttribute.CONVOLUTION) === EffectAttribute.CONVOLUTION
53
+
54
+ export const EffectComposer = /* @__PURE__ */ memo(
55
+ /* @__PURE__ */ forwardRef<EffectComposerImpl, EffectComposerProps>(
56
+ (
57
+ {
58
+ children,
59
+ camera: _camera,
60
+ scene: _scene,
61
+ resolutionScale,
62
+ enabled = true,
63
+ renderPriority = 1,
64
+ autoClear = true,
65
+ depthBuffer,
66
+ enableNormalPass,
67
+ stencilBuffer,
68
+ multisampling = 8,
69
+ frameBufferType = HalfFloatType,
70
+ },
71
+ ref
72
+ ) => {
73
+ const { gl, scene: defaultScene, camera: defaultCamera, size } = useThree()
74
+ const scene = _scene || defaultScene
75
+ const camera = _camera || defaultCamera
76
+
77
+ const [composer, normalPass, downSamplingPass] = useMemo(() => {
78
+ // Initialize composer
79
+ const effectComposer = new EffectComposerImpl(gl, {
80
+ depthBuffer,
81
+ stencilBuffer,
82
+ multisampling,
83
+ frameBufferType,
84
+ })
85
+
86
+ // Add render pass
87
+ effectComposer.addPass(new RenderPass(scene, camera))
88
+
89
+ // Create normal pass
90
+ let downSamplingPass = null
91
+ let normalPass = null
92
+ if (enableNormalPass) {
93
+ normalPass = new NormalPass(scene, camera)
94
+ normalPass.enabled = false
95
+ effectComposer.addPass(normalPass)
96
+ if (resolutionScale !== undefined) {
97
+ downSamplingPass = new DepthDownsamplingPass({ normalBuffer: normalPass.texture, resolutionScale })
98
+ downSamplingPass.enabled = false
99
+ effectComposer.addPass(downSamplingPass)
100
+ }
101
+ }
102
+
103
+ return [effectComposer, normalPass, downSamplingPass]
104
+ }, [
105
+ camera,
106
+ gl,
107
+ depthBuffer,
108
+ stencilBuffer,
109
+ multisampling,
110
+ frameBufferType,
111
+ scene,
112
+ enableNormalPass,
113
+ resolutionScale,
114
+ ])
115
+
116
+ useEffect(() => composer?.setSize(size.width, size.height), [composer, size])
117
+ useFrame(
118
+ (_, delta) => {
119
+ if (enabled) {
120
+ const currentAutoClear = gl.autoClear
121
+ gl.autoClear = autoClear
122
+ if (stencilBuffer && !autoClear) gl.clearStencil()
123
+ composer.render(delta)
124
+ gl.autoClear = currentAutoClear
125
+ }
126
+ },
127
+ enabled ? renderPriority : 0
128
+ )
129
+
130
+ const group = useRef<Group>(null!)
131
+ useLayoutEffect(() => {
132
+ const passes: Pass[] = []
133
+
134
+ // TODO: rewrite all of this with R3F v9
135
+ const groupInstance = (group.current as Group & { __r3f: Instance<Group> }).__r3f
136
+
137
+ if (groupInstance && composer) {
138
+ const children = groupInstance.children
139
+
140
+ for (let i = 0; i < children.length; i++) {
141
+ const child = children[i].object
142
+
143
+ if (child instanceof Effect) {
144
+ const effects: Effect[] = [child]
145
+
146
+ if (!isConvolution(child)) {
147
+ let next: unknown = null
148
+ while ((next = children[i + 1]?.object) instanceof Effect) {
149
+ if (isConvolution(next)) break
150
+ effects.push(next)
151
+ i++
152
+ }
153
+ }
154
+
155
+ const pass = new EffectPass(camera, ...effects)
156
+ passes.push(pass)
157
+ } else if (child instanceof Pass) {
158
+ passes.push(child)
159
+ }
160
+ }
161
+
162
+ for (const pass of passes) composer?.addPass(pass)
163
+
164
+ if (normalPass) normalPass.enabled = true
165
+ if (downSamplingPass) downSamplingPass.enabled = true
166
+ }
167
+
168
+ return () => {
169
+ for (const pass of passes) composer?.removePass(pass)
170
+ if (normalPass) normalPass.enabled = false
171
+ if (downSamplingPass) downSamplingPass.enabled = false
172
+ }
173
+ }, [composer, children, camera, normalPass, downSamplingPass])
174
+
175
+ // Disable tone mapping because threejs disallows tonemapping on render targets
176
+ useEffect(() => {
177
+ const currentTonemapping = gl.toneMapping
178
+ gl.toneMapping = NoToneMapping
179
+ return () => {
180
+ gl.toneMapping = currentTonemapping
181
+ }
182
+ }, [gl])
183
+
184
+ // Memoize state, otherwise it would trigger all consumers on every render
185
+ const state = useMemo(
186
+ () => ({ composer, normalPass, downSamplingPass, resolutionScale, camera, scene }),
187
+ [composer, normalPass, downSamplingPass, resolutionScale, camera, scene]
188
+ )
189
+
190
+ // Expose the composer
191
+ useImperativeHandle(ref, () => composer, [composer])
192
+
193
+ return (
194
+ <EffectComposerContext.Provider value={state}>
195
+ <group ref={group}>{children}</group>
196
+ </EffectComposerContext.Provider>
197
+ )
198
+ }
199
+ )
200
+ )
package/src/Selection.tsx CHANGED
@@ -1,46 +1,46 @@
1
- import * as THREE from 'three'
2
- import React, { createContext, useState, useContext, useEffect, useRef, useMemo } from 'react'
3
- import { type ThreeElements } from '@react-three/fiber'
4
-
5
- export type Api = {
6
- selected: THREE.Object3D[]
7
- select: React.Dispatch<React.SetStateAction<THREE.Object3D[]>>
8
- enabled: boolean
9
- }
10
- export type SelectApi = Omit<ThreeElements['group'], 'ref'> & {
11
- enabled?: boolean
12
- }
13
-
14
- export const selectionContext = /* @__PURE__ */ createContext<Api | null>(null)
15
-
16
- export function Selection({ children, enabled = true }: { enabled?: boolean; children: React.ReactNode }) {
17
- const [selected, select] = useState<THREE.Object3D[]>([])
18
- const value = useMemo(() => ({ selected, select, enabled }), [selected, select, enabled])
19
- return <selectionContext.Provider value={value}>{children}</selectionContext.Provider>
20
- }
21
-
22
- export function Select({ enabled = false, children, ...props }: SelectApi) {
23
- const group = useRef<THREE.Group>(null!)
24
- const api = useContext(selectionContext)
25
- useEffect(() => {
26
- if (api && enabled) {
27
- let changed = false
28
- const current: THREE.Object3D[] = []
29
- group.current.traverse((o) => {
30
- o.type === 'Mesh' && current.push(o)
31
- if (api.selected.indexOf(o) === -1) changed = true
32
- })
33
- if (changed) {
34
- api.select((state) => [...state, ...current])
35
- return () => {
36
- api.select((state) => state.filter((selected) => !current.includes(selected)))
37
- }
38
- }
39
- }
40
- }, [enabled, children, api])
41
- return (
42
- <group ref={group} {...props}>
43
- {children}
44
- </group>
45
- )
46
- }
1
+ import * as THREE from 'three'
2
+ import React, { createContext, useState, useContext, useEffect, useRef, useMemo } from 'react'
3
+ import { type ThreeElements } from '@react-three/fiber'
4
+
5
+ export type Api = {
6
+ selected: THREE.Object3D[]
7
+ select: React.Dispatch<React.SetStateAction<THREE.Object3D[]>>
8
+ enabled: boolean
9
+ }
10
+ export type SelectApi = Omit<ThreeElements['group'], 'ref'> & {
11
+ enabled?: boolean
12
+ }
13
+
14
+ export const selectionContext = /* @__PURE__ */ createContext<Api | null>(null)
15
+
16
+ export function Selection({ children, enabled = true }: { enabled?: boolean; children: React.ReactNode }) {
17
+ const [selected, select] = useState<THREE.Object3D[]>([])
18
+ const value = useMemo(() => ({ selected, select, enabled }), [selected, select, enabled])
19
+ return <selectionContext.Provider value={value}>{children}</selectionContext.Provider>
20
+ }
21
+
22
+ export function Select({ enabled = false, children, ...props }: SelectApi) {
23
+ const group = useRef<THREE.Group>(null!)
24
+ const api = useContext(selectionContext)
25
+ useEffect(() => {
26
+ if (api && enabled) {
27
+ let changed = false
28
+ const current: THREE.Object3D[] = []
29
+ group.current.traverse((o) => {
30
+ o.type === 'Mesh' && current.push(o)
31
+ if (api.selected.indexOf(o) === -1) changed = true
32
+ })
33
+ if (changed) {
34
+ api.select((state) => [...state, ...current])
35
+ return () => {
36
+ api.select((state) => state.filter((selected) => !current.includes(selected)))
37
+ }
38
+ }
39
+ }
40
+ }, [enabled, children, api])
41
+ return (
42
+ <group ref={group} {...props}>
43
+ {children}
44
+ </group>
45
+ )
46
+ }