@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.
Files changed (114) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +80 -81
  3. package/dist/EffectComposer.d.ts +14 -6
  4. package/dist/EffectGroup.d.ts +9 -0
  5. package/dist/Selection.d.ts +8 -8
  6. package/dist/createEffectComponent.d.ts +30 -0
  7. package/dist/effects/ASCII.d.ts +29 -7
  8. package/dist/effects/Autofocus.d.ts +8 -7
  9. package/dist/effects/Bloom.d.ts +10 -5
  10. package/dist/effects/BrightnessContrast.d.ts +15 -5
  11. package/dist/effects/ChromaticAberration.d.ts +30 -7
  12. package/dist/effects/ColorAverage.d.ts +7 -8
  13. package/dist/effects/ColorDepth.d.ts +8 -5
  14. package/dist/effects/Depth.d.ts +13 -5
  15. package/dist/effects/DepthOfField.d.ts +7 -18
  16. package/dist/effects/DotScreen.d.ts +15 -5
  17. package/dist/effects/FXAA.d.ts +11 -5
  18. package/dist/effects/Glitch.d.ts +17 -29
  19. package/dist/effects/GodRays.d.ts +7 -19
  20. package/dist/effects/Grid.d.ts +8 -8
  21. package/dist/effects/HueSaturation.d.ts +15 -5
  22. package/dist/effects/LUT.d.ts +4 -3
  23. package/dist/effects/LensFlare.d.ts +52 -11
  24. package/dist/effects/Noise.d.ts +8 -5
  25. package/dist/effects/Outline.d.ts +9 -25
  26. package/dist/effects/Pixelation.d.ts +3 -2
  27. package/dist/effects/Ramp.d.ts +58 -10
  28. package/dist/effects/SMAA.d.ts +10 -5
  29. package/dist/effects/SSAO.d.ts +7 -30
  30. package/dist/effects/ScanlineEffect.d.ts +13 -5
  31. package/dist/effects/SelectiveBloom.d.ts +5 -10
  32. package/dist/effects/Sepia.d.ts +13 -5
  33. package/dist/effects/ShockWave.d.ts +12 -5
  34. package/dist/effects/Texture.d.ts +7 -8
  35. package/dist/effects/TiltShift.d.ts +10 -5
  36. package/dist/effects/TiltShift2.d.ts +44 -8
  37. package/dist/effects/ToneMapping.d.ts +9 -7
  38. package/dist/effects/Vignette.d.ts +19 -5
  39. package/dist/effects/Water.d.ts +17 -5
  40. package/dist/index.d.ts +15 -11
  41. package/dist/index.js +1841 -45
  42. package/dist/index.js.map +1 -1
  43. package/dist/passes/DepthPicking.d.ts +11 -0
  44. package/dist/{effects → passes}/N8AO.d.ts +5 -2
  45. package/dist/util.d.ts +19 -17
  46. package/dist/wrapEffect.d.ts +12 -0
  47. package/package.json +74 -67
  48. package/src/EffectComposer.tsx +379 -200
  49. package/src/EffectGroup.tsx +74 -0
  50. package/src/Selection.tsx +86 -46
  51. package/src/createEffectComponent.tsx +71 -0
  52. package/src/effects/ASCII.tsx +183 -135
  53. package/src/effects/Autofocus.tsx +122 -153
  54. package/src/effects/Bloom.tsx +34 -6
  55. package/src/effects/BrightnessContrast.tsx +7 -4
  56. package/src/effects/ChromaticAberration.tsx +22 -5
  57. package/src/effects/ColorAverage.tsx +4 -15
  58. package/src/effects/ColorDepth.tsx +25 -4
  59. package/src/effects/Depth.tsx +6 -4
  60. package/src/effects/DepthOfField.tsx +109 -89
  61. package/src/effects/DotScreen.tsx +7 -4
  62. package/src/effects/FXAA.tsx +6 -4
  63. package/src/effects/Glitch.tsx +32 -40
  64. package/src/effects/GodRays.tsx +104 -16
  65. package/src/effects/Grid.tsx +27 -21
  66. package/src/effects/HueSaturation.tsx +7 -4
  67. package/src/effects/LUT.tsx +25 -26
  68. package/src/effects/LensFlare.tsx +765 -611
  69. package/src/effects/Noise.tsx +16 -4
  70. package/src/effects/Outline.tsx +84 -117
  71. package/src/effects/Pixelation.tsx +20 -15
  72. package/src/effects/Ramp.tsx +239 -150
  73. package/src/effects/SMAA.tsx +20 -4
  74. package/src/effects/SSAO.tsx +152 -41
  75. package/src/effects/ScanlineEffect.tsx +7 -7
  76. package/src/effects/SelectiveBloom.tsx +98 -126
  77. package/src/effects/Sepia.tsx +6 -4
  78. package/src/effects/ShockWave.tsx +32 -4
  79. package/src/effects/Texture.tsx +28 -23
  80. package/src/effects/TiltShift.tsx +32 -4
  81. package/src/effects/TiltShift2.tsx +156 -90
  82. package/src/effects/ToneMapping.tsx +19 -6
  83. package/src/effects/Vignette.tsx +7 -4
  84. package/src/effects/Water.tsx +50 -35
  85. package/src/index.ts +43 -40
  86. package/src/passes/DepthPicking.tsx +63 -0
  87. package/src/passes/N8AO.tsx +105 -0
  88. package/src/tests/Autofocus.test.tsx +38 -0
  89. package/src/tests/Bloom.test.tsx +76 -0
  90. package/src/tests/ChromaticAberration.test.tsx +81 -0
  91. package/src/tests/ColorDepth.test.tsx +71 -0
  92. package/src/tests/DepthOfField.test.tsx +130 -0
  93. package/src/tests/DepthPicking.test.tsx +250 -0
  94. package/src/tests/EffectComposer.test.tsx +1404 -0
  95. package/src/tests/EffectGroup.test.tsx +337 -0
  96. package/src/tests/Glitch.test.tsx +56 -0
  97. package/src/tests/GodRays.test.tsx +101 -0
  98. package/src/tests/Grid.test.tsx +34 -0
  99. package/src/tests/LUT.test.tsx +64 -0
  100. package/src/tests/N8AO.test.tsx +92 -0
  101. package/src/tests/Outline.test.tsx +211 -0
  102. package/src/tests/SSAO.test.tsx +140 -0
  103. package/src/tests/Selection.test.tsx +324 -0
  104. package/src/tests/SelectiveBloom.test.tsx +166 -0
  105. package/src/tests/ShockWave.test.tsx +95 -0
  106. package/src/tests/TiltShift.test.tsx +76 -0
  107. package/src/tests/createEffectComponent.test.tsx +286 -0
  108. package/src/tests/effects.smoke.test.tsx +238 -0
  109. package/src/tests/test-utils.tsx +96 -0
  110. package/src/tests/wrapEffect.test.tsx +209 -0
  111. package/src/util.tsx +221 -55
  112. package/src/wrapEffect.tsx +123 -0
  113. package/src/EffectComposer.test.tsx +0 -126
  114. package/src/effects/N8AO.tsx +0 -81
@@ -1,90 +1,156 @@
1
- import { Uniform } from 'three'
2
- import { BlendFunction, Effect, EffectAttribute } from 'postprocessing'
3
- import { wrapEffect } from '../util'
4
-
5
- const TiltShiftShader = {
6
- fragmentShader: `
7
-
8
- // original shader by Evan Wallace
9
-
10
- #define MAX_ITERATIONS 100
11
-
12
- uniform float blur;
13
- uniform float taper;
14
- uniform vec2 start;
15
- uniform vec2 end;
16
- uniform vec2 direction;
17
- uniform int samples;
18
-
19
- float random(vec3 scale, float seed) {
20
- /* use the fragment position for a different seed per-pixel */
21
- return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);
22
- }
23
-
24
- void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
25
- vec4 color = vec4(0.0);
26
- float total = 0.0;
27
- vec2 startPixel = vec2(start.x * resolution.x, start.y * resolution.y);
28
- vec2 endPixel = vec2(end.x * resolution.x, end.y * resolution.y);
29
- float f_samples = float(samples);
30
- float half_samples = f_samples / 2.0;
31
-
32
- // use screen diagonal to normalize blur radii
33
- float maxScreenDistance = distance(vec2(0.0), resolution); // diagonal distance
34
- float gradientRadius = taper * (maxScreenDistance);
35
- float blurRadius = blur * (maxScreenDistance / 16.0);
36
-
37
- /* randomize the lookup values to hide the fixed number of samples */
38
- float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);
39
- vec2 normal = normalize(vec2(startPixel.y - endPixel.y, endPixel.x - startPixel.x));
40
- float radius = smoothstep(0.0, 1.0, abs(dot(uv * resolution - startPixel, normal)) / gradientRadius) * blurRadius;
41
-
42
- #pragma unroll_loop_start
43
- for (int i = 0; i <= MAX_ITERATIONS; i++) {
44
- if (i >= samples) { break; } // return early if over sample count
45
- float f_i = float(i);
46
- float s_i = -half_samples + f_i;
47
- float percent = (s_i + offset - 0.5) / half_samples;
48
- float weight = 1.0 - abs(percent);
49
- vec4 sample_i = texture2D(inputBuffer, uv + normalize(direction) / resolution * percent * radius);
50
- /* switch to pre-multiplied alpha to correctly blur transparent images */
51
- sample_i.rgb *= sample_i.a;
52
- color += sample_i * weight;
53
- total += weight;
54
- }
55
- #pragma unroll_loop_end
56
-
57
- outputColor = color / total;
58
-
59
- /* switch back from pre-multiplied alpha */
60
- outputColor.rgb /= outputColor.a + 0.00001;
61
- }
62
- `,
63
- }
64
-
65
- export class TiltShiftEffect extends Effect {
66
- constructor({
67
- blendFunction = BlendFunction.NORMAL,
68
- blur = 0.15, // [0, 1], can go beyond 1 for extra
69
- taper = 0.5, // [0, 1], can go beyond 1 for extra
70
- start = [0.5, 0.0], // [0,1] percentage x,y of screenspace
71
- end = [0.5, 1.0], // [0,1] percentage x,y of screenspace
72
- samples = 10.0, // number of blur samples
73
- direction = [1, 1], // direction of blur
74
- } = {}) {
75
- super('TiltShiftEffect', TiltShiftShader.fragmentShader, {
76
- blendFunction,
77
- attributes: EffectAttribute.CONVOLUTION,
78
- uniforms: new Map<string, Uniform<number | number[]>>([
79
- ['blur', new Uniform(blur)],
80
- ['taper', new Uniform(taper)],
81
- ['start', new Uniform(start)],
82
- ['end', new Uniform(end)],
83
- ['samples', new Uniform(samples)],
84
- ['direction', new Uniform(direction)],
85
- ]),
86
- })
87
- }
88
- }
89
-
90
- export const TiltShift2 = /* @__PURE__ */ wrapEffect(TiltShiftEffect, { blendFunction: BlendFunction.NORMAL })
1
+ import { BlendFunction, Effect, EffectAttribute } from 'postprocessing'
2
+ import type { Ref } from 'react'
3
+ import { Uniform } from 'three'
4
+ import { createEffectComponent } from '../createEffectComponent'
5
+
6
+ const TiltShiftShader = {
7
+ fragmentShader: /* glsl */ `
8
+
9
+ // original shader by Evan Wallace
10
+
11
+ #define MAX_ITERATIONS 100
12
+
13
+ uniform float blur;
14
+ uniform float taper;
15
+ uniform vec2 start;
16
+ uniform vec2 end;
17
+ uniform vec2 direction;
18
+ uniform int samples;
19
+
20
+ float random(vec3 scale, float seed) {
21
+ /* use the fragment position for a different seed per-pixel */
22
+ return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);
23
+ }
24
+
25
+ void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
26
+ vec4 color = vec4(0.0);
27
+ float total = 0.0;
28
+ vec2 startPixel = vec2(start.x * resolution.x, start.y * resolution.y);
29
+ vec2 endPixel = vec2(end.x * resolution.x, end.y * resolution.y);
30
+ float f_samples = float(samples);
31
+ float half_samples = f_samples / 2.0;
32
+
33
+ // use screen diagonal to normalize blur radii
34
+ float maxScreenDistance = distance(vec2(0.0), resolution); // diagonal distance
35
+ float gradientRadius = taper * (maxScreenDistance);
36
+ float blurRadius = blur * (maxScreenDistance / 16.0);
37
+
38
+ /* randomize the lookup values to hide the fixed number of samples */
39
+ float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);
40
+ vec2 normal = normalize(vec2(startPixel.y - endPixel.y, endPixel.x - startPixel.x));
41
+ float radius = smoothstep(0.0, 1.0, abs(dot(uv * resolution - startPixel, normal)) / gradientRadius) * blurRadius;
42
+
43
+ #pragma unroll_loop_start
44
+ for (int i = 0; i <= MAX_ITERATIONS; i++) {
45
+ if (i >= samples) { break; } // return early if over sample count
46
+ float f_i = float(i);
47
+ float s_i = -half_samples + f_i;
48
+ float percent = (s_i + offset - 0.5) / half_samples;
49
+ float weight = 1.0 - abs(percent);
50
+ vec4 sample_i = texture2D(inputBuffer, uv + normalize(direction) / resolution * percent * radius);
51
+ /* switch to pre-multiplied alpha to correctly blur transparent images */
52
+ sample_i.rgb *= sample_i.a;
53
+ color += sample_i * weight;
54
+ total += weight;
55
+ }
56
+ #pragma unroll_loop_end
57
+
58
+ outputColor = color / total;
59
+
60
+ /* switch back from pre-multiplied alpha */
61
+ outputColor.rgb /= outputColor.a + 0.00001;
62
+ }
63
+ `,
64
+ }
65
+
66
+ type Vec2Tuple = [number, number]
67
+
68
+ export class TiltShiftEffect extends Effect {
69
+ constructor({
70
+ blendFunction = BlendFunction.NORMAL,
71
+ blur = 0.15, // [0, 1], can go beyond 1 for extra
72
+ taper = 0.5, // [0, 1], can go beyond 1 for extra
73
+ start = [0.5, 0.0] as Vec2Tuple, // [0,1] percentage x,y of screenspace
74
+ end = [0.5, 1.0] as Vec2Tuple, // [0,1] percentage x,y of screenspace
75
+ samples = 10.0, // number of blur samples
76
+ direction = [1, 1] as Vec2Tuple, // direction of blur
77
+ } = {}) {
78
+ super('TiltShiftEffect', TiltShiftShader.fragmentShader, {
79
+ blendFunction,
80
+ attributes: EffectAttribute.CONVOLUTION,
81
+ uniforms: new Map<string, Uniform<number | Vec2Tuple>>([
82
+ ['blur', new Uniform(blur)],
83
+ ['taper', new Uniform(taper)],
84
+ ['start', new Uniform(start)],
85
+ ['end', new Uniform(end)],
86
+ ['samples', new Uniform(samples)],
87
+ ['direction', new Uniform(direction)],
88
+ ]),
89
+ })
90
+ }
91
+
92
+ private u<T>(name: string): T {
93
+ return this.uniforms.get(name)!.value
94
+ }
95
+
96
+ private setU(name: string, value: unknown): void {
97
+ this.uniforms.get(name)!.value = value
98
+ }
99
+
100
+ get blur(): number {
101
+ return this.u('blur')
102
+ }
103
+ set blur(value: number) {
104
+ this.setU('blur', value)
105
+ }
106
+
107
+ get taper(): number {
108
+ return this.u('taper')
109
+ }
110
+ set taper(value: number) {
111
+ this.setU('taper', value)
112
+ }
113
+
114
+ get start(): Vec2Tuple {
115
+ return this.u('start')
116
+ }
117
+ set start(value: Vec2Tuple) {
118
+ this.setU('start', value)
119
+ }
120
+
121
+ get end(): Vec2Tuple {
122
+ return this.u('end')
123
+ }
124
+ set end(value: Vec2Tuple) {
125
+ this.setU('end', value)
126
+ }
127
+
128
+ get samples(): number {
129
+ return this.u('samples')
130
+ }
131
+ set samples(value: number) {
132
+ this.setU('samples', value)
133
+ }
134
+
135
+ get direction(): Vec2Tuple {
136
+ return this.u('direction')
137
+ }
138
+ set direction(value: Vec2Tuple) {
139
+ this.setU('direction', value)
140
+ }
141
+ }
142
+
143
+ export type TiltShift2Props = {
144
+ blendFunction?: BlendFunction
145
+ blur?: number
146
+ taper?: number
147
+ start?: Vec2Tuple
148
+ end?: Vec2Tuple
149
+ samples?: number
150
+ direction?: Vec2Tuple
151
+ ref?: Ref<TiltShiftEffect>
152
+ }
153
+
154
+ export const TiltShift2 = /* @__PURE__ */ createEffectComponent<typeof TiltShiftEffect, TiltShift2Props>(
155
+ TiltShiftEffect
156
+ )
@@ -1,6 +1,19 @@
1
- import { ToneMappingEffect } from 'postprocessing'
2
- import { type EffectProps, wrapEffect } from '../util'
3
-
4
- export type ToneMappingProps = EffectProps<typeof ToneMappingEffect>
5
-
6
- export const ToneMapping = /* @__PURE__ */ wrapEffect(ToneMappingEffect)
1
+ import { ToneMappingEffect } from 'postprocessing'
2
+ import type { Ref } from 'react'
3
+ import { useMemo } from 'react'
4
+ import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
5
+
6
+ type ToneMappingOptions = EffectOptions<typeof ToneMappingEffect>
7
+
8
+ const ToneMappingImpl = /* @__PURE__ */ createEffectComponent<typeof ToneMappingEffect, ToneMappingOptions>(
9
+ ToneMappingEffect
10
+ )
11
+
12
+ export type ToneMappingProps = ToneMappingOptions & { opacity?: number; ref?: Ref<ToneMappingEffect> }
13
+
14
+ // minLuminance/maxLuminance have no live setter in postprocessing - routed
15
+ // through args so they still work as plain props.
16
+ export function ToneMapping({ minLuminance, maxLuminance, ...liveProps }: ToneMappingProps) {
17
+ const args = useMemo<[ToneMappingOptions]>(() => [{ minLuminance, maxLuminance }], [minLuminance, maxLuminance])
18
+ return <ToneMappingImpl args={args} {...liveProps} />
19
+ }
@@ -1,4 +1,7 @@
1
- import { VignetteEffect } from 'postprocessing'
2
- import { wrapEffect } from '../util'
3
-
4
- export const Vignette = /* @__PURE__ */ wrapEffect(VignetteEffect)
1
+ import { VignetteEffect } from 'postprocessing'
2
+ import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
3
+
4
+ export const Vignette = /* @__PURE__ */ createEffectComponent<
5
+ typeof VignetteEffect,
6
+ EffectOptions<typeof VignetteEffect>
7
+ >(VignetteEffect)
@@ -1,35 +1,50 @@
1
- import { Uniform } from 'three'
2
- import { BlendFunction, Effect, EffectAttribute } from 'postprocessing'
3
- import { wrapEffect } from '../util'
4
-
5
- const WaterShader = {
6
- fragmentShader: /* glsl */ `
7
- uniform float factor;
8
-
9
- void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
10
- vec2 vUv = uv;
11
- float frequency = 6.0 * factor;
12
- float amplitude = 0.015 * factor;
13
- float x = vUv.y * frequency + time * 0.7;
14
- float y = vUv.x * frequency + time * 0.3;
15
- vUv.x += cos(x + y) * amplitude * cos(y);
16
- vUv.y += sin(x - y) * amplitude * cos(y);
17
- vec4 rgba = texture(inputBuffer, vUv);
18
- outputColor = rgba;
19
- }
20
- `,
21
- }
22
-
23
- export class WaterEffectImpl extends Effect {
24
- constructor({ blendFunction = BlendFunction.NORMAL, factor = 0 } = {}) {
25
- super('WaterEffect', WaterShader.fragmentShader, {
26
- blendFunction,
27
- attributes: EffectAttribute.CONVOLUTION,
28
- uniforms: new Map<string, Uniform<number | number[]>>([['factor', new Uniform(factor)]]),
29
- })
30
- }
31
- }
32
-
33
- export const WaterEffect = /* @__PURE__ */ wrapEffect(WaterEffectImpl, {
34
- blendFunction: BlendFunction.NORMAL,
35
- })
1
+ import { BlendFunction, Effect, EffectAttribute } from 'postprocessing'
2
+ import type { Ref } from 'react'
3
+ import { Uniform } from 'three'
4
+ import { createEffectComponent } from '../createEffectComponent'
5
+
6
+ const WaterShader = {
7
+ fragmentShader: /* glsl */ `
8
+ uniform float factor;
9
+
10
+ void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
11
+ vec2 vUv = uv;
12
+ float frequency = 6.0 * factor;
13
+ float amplitude = 0.015 * factor;
14
+ float x = vUv.y * frequency + time * 0.7;
15
+ float y = vUv.x * frequency + time * 0.3;
16
+ vUv.x += cos(x + y) * amplitude * cos(y);
17
+ vUv.y += sin(x - y) * amplitude * cos(y);
18
+ vec4 rgba = texture(inputBuffer, vUv);
19
+ outputColor = rgba;
20
+ }
21
+ `,
22
+ }
23
+
24
+ export class WaterEffectImpl extends Effect {
25
+ constructor({ blendFunction = BlendFunction.NORMAL, factor = 0 } = {}) {
26
+ super('WaterEffect', WaterShader.fragmentShader, {
27
+ blendFunction,
28
+ attributes: EffectAttribute.CONVOLUTION,
29
+ uniforms: new Map<string, Uniform<number>>([['factor', new Uniform(factor)]]),
30
+ })
31
+ }
32
+
33
+ get factor(): number {
34
+ return this.uniforms.get('factor')!.value
35
+ }
36
+
37
+ set factor(value: number) {
38
+ this.uniforms.get('factor')!.value = value
39
+ }
40
+ }
41
+
42
+ export type WaterEffectProps = {
43
+ blendFunction?: BlendFunction
44
+ factor?: number
45
+ ref?: Ref<WaterEffectImpl>
46
+ }
47
+
48
+ export const WaterEffect = /* @__PURE__ */ createEffectComponent<typeof WaterEffectImpl, WaterEffectProps>(
49
+ WaterEffectImpl
50
+ )
package/src/index.ts CHANGED
@@ -1,40 +1,43 @@
1
- export * from './Selection'
2
- export * from './EffectComposer'
3
- export * from './util'
4
-
5
- export * from './effects/Autofocus'
6
- export * from './effects/LensFlare'
7
- export * from './effects/Bloom'
8
- export * from './effects/BrightnessContrast'
9
- export * from './effects/ChromaticAberration'
10
- export * from './effects/ColorAverage'
11
- export * from './effects/ColorDepth'
12
- export * from './effects/Depth'
13
- export * from './effects/DepthOfField'
14
- export * from './effects/DotScreen'
15
- export * from './effects/Glitch'
16
- export * from './effects/GodRays'
17
- export * from './effects/Grid'
18
- export * from './effects/HueSaturation'
19
- export * from './effects/Noise'
20
- export * from './effects/Outline'
21
- export * from './effects/Pixelation'
22
- export * from './effects/ScanlineEffect'
23
- export * from './effects/SelectiveBloom'
24
- export * from './effects/Sepia'
25
- export * from './effects/SSAO'
26
- export * from './effects/SMAA'
27
- export * from './effects/FXAA'
28
- export * from './effects/Ramp'
29
- export * from './effects/Texture'
30
- export * from './effects/ToneMapping'
31
- export * from './effects/Vignette'
32
- export * from './effects/ShockWave'
33
- export * from './effects/LUT'
34
- export * from './effects/TiltShift'
35
- export * from './effects/TiltShift2'
36
- export * from './effects/ASCII'
37
- export * from './effects/Water'
38
-
39
- // These are not effect passes
40
- export * from './effects/N8AO'
1
+ export * from './createEffectComponent'
2
+ export * from './EffectComposer'
3
+ export * from './EffectGroup'
4
+ export * from './Selection'
5
+ export * from './util'
6
+ export * from './wrapEffect'
7
+
8
+ export * from './effects/ASCII'
9
+ export * from './effects/Autofocus'
10
+ export * from './effects/Bloom'
11
+ export * from './effects/BrightnessContrast'
12
+ export * from './effects/ChromaticAberration'
13
+ export * from './effects/ColorAverage'
14
+ export * from './effects/ColorDepth'
15
+ export * from './effects/Depth'
16
+ export * from './effects/DepthOfField'
17
+ export * from './effects/DotScreen'
18
+ export * from './effects/FXAA'
19
+ export * from './effects/Glitch'
20
+ export * from './effects/GodRays'
21
+ export * from './effects/Grid'
22
+ export * from './effects/HueSaturation'
23
+ export * from './effects/LensFlare'
24
+ export * from './effects/LUT'
25
+ export * from './effects/Noise'
26
+ export * from './effects/Outline'
27
+ export * from './effects/Pixelation'
28
+ export * from './effects/Ramp'
29
+ export * from './effects/ScanlineEffect'
30
+ export * from './effects/SelectiveBloom'
31
+ export * from './effects/Sepia'
32
+ export * from './effects/ShockWave'
33
+ export * from './effects/SMAA'
34
+ export * from './effects/SSAO'
35
+ export * from './effects/Texture'
36
+ export * from './effects/TiltShift'
37
+ export * from './effects/TiltShift2'
38
+ export * from './effects/ToneMapping'
39
+ export * from './effects/Vignette'
40
+ export * from './effects/Water'
41
+
42
+ export * from './passes/DepthPicking'
43
+ export * from './passes/N8AO'
@@ -0,0 +1,63 @@
1
+ import { useThree } from '@react-three/fiber'
2
+ import { CopyPass, DepthPickingPass as DepthPickingPassImpl } from 'postprocessing'
3
+ import { use, useCallback, useEffect, useImperativeHandle, useState, type Ref } from 'react'
4
+ import type { Camera } from 'three'
5
+ import { Vector2, Vector3 } from 'three'
6
+ import { EffectComposerContext } from '../EffectComposer'
7
+ import { useDispose } from '../util'
8
+
9
+ export type DepthPickingApi = {
10
+ readDepth: (ndc: Vector2 | Vector3) => Promise<number>
11
+ }
12
+
13
+ export type DepthPickingProps = {
14
+ ref?: Ref<DepthPickingApi>
15
+ }
16
+
17
+ // Mounts a vanilla `postprocessing` DepthPickingPass and exposes its
18
+ // `readDepth` via ref - nothing else. Renders nothing. Pair with
19
+ // `useDepthPicking` for a world-space position instead of raw depth.
20
+ export function DepthPicking({ ref }: DepthPickingProps) {
21
+ const { composer } = use(EffectComposerContext)
22
+
23
+ const [depthPickingPass] = useState(() => new DepthPickingPassImpl())
24
+ const [copyPass] = useState(() => new CopyPass())
25
+ useEffect(() => {
26
+ composer.addPass(depthPickingPass)
27
+ composer.addPass(copyPass)
28
+ return () => {
29
+ composer.removePass(depthPickingPass)
30
+ composer.removePass(copyPass)
31
+ }
32
+ }, [composer, depthPickingPass, copyPass])
33
+
34
+ useDispose(depthPickingPass)
35
+ useDispose(copyPass)
36
+
37
+ useImperativeHandle(ref, () => ({ readDepth: (ndc) => depthPickingPass.readDepth(ndc) }), [depthPickingPass])
38
+
39
+ return null
40
+ }
41
+
42
+ export function useDepthPicking(pass: React.RefObject<DepthPickingApi | null>, camera?: Camera) {
43
+ const composerCamera = use(EffectComposerContext)?.camera
44
+ const defaultCamera = useThree((state) => state.camera)
45
+ const resolvedCamera = camera ?? composerCamera ?? defaultCamera
46
+ const [ndc] = useState(() => new Vector3())
47
+
48
+ return useCallback(
49
+ async (x: number, y: number): Promise<Vector3 | false> => {
50
+ if (!pass.current) return false
51
+ ndc.x = x
52
+ ndc.y = y
53
+ ndc.z = await pass.current.readDepth(ndc)
54
+ ndc.z = ndc.z * 2.0 - 1.0
55
+ const hit = 1 - ndc.z > 0.0000001 // missed if ndc.z is close to 1
56
+ // clone - unproject mutates in place, and ndc is reused across calls,
57
+ // so returning it directly would hand out a reference that changes
58
+ // under the caller on the next pick.
59
+ return hit ? ndc.clone().unproject(resolvedCamera) : false
60
+ },
61
+ [pass, resolvedCamera, ndc]
62
+ )
63
+ }
@@ -0,0 +1,105 @@
1
+ // From https://github.com/N8python/n8ao
2
+ // https://twitter.com/N8Programs/status/1660996748485984261
3
+
4
+ import { ReactThreeFiber, applyProps, useThree } from '@react-three/fiber'
5
+ import { Ref, useLayoutEffect, useMemo } from 'react'
6
+ /* @ts-ignore */
7
+ import { N8AOPostPass } from 'n8ao'
8
+ import { groupPasses } from '../EffectComposer'
9
+ import { useDispose } from '../util'
10
+
11
+ export type N8AOProps = {
12
+ enabled?: boolean
13
+ aoRadius?: number
14
+ distanceFalloff?: number
15
+ intensity?: number
16
+ quality?: 'performance' | 'low' | 'medium' | 'high' | 'ultra'
17
+ aoSamples?: number
18
+ denoiseSamples?: number
19
+ denoiseRadius?: number
20
+ color?: ReactThreeFiber.Color
21
+ halfRes?: boolean
22
+ depthAwareUpsampling?: boolean
23
+ screenSpaceRadius?: boolean
24
+ renderMode?: 0 | 1 | 2 | 3 | 4
25
+ ref?: Ref<N8AOPostPass>
26
+ }
27
+
28
+ export function N8AO({
29
+ enabled = true,
30
+ halfRes,
31
+ screenSpaceRadius,
32
+ quality,
33
+ depthAwareUpsampling = true,
34
+ aoRadius = 5,
35
+ aoSamples = 16,
36
+ denoiseSamples = 4,
37
+ denoiseRadius = 12,
38
+ distanceFalloff = 1,
39
+ intensity = 1,
40
+ color,
41
+ renderMode = 0,
42
+ ref,
43
+ }: N8AOProps) {
44
+ const { camera, scene, invalidate } = useThree()
45
+ const effect = useMemo(() => {
46
+ const instance = new N8AOPostPass(scene, camera)
47
+ // N8AOPostPass isn't a postprocessing Effect, so it's not mergeable via
48
+ // EffectGroup - it's already a standalone Pass, hence its own `enabled`
49
+ // prop below instead. Registering it here still gets it the shared
50
+ // trailing CopyPass safety net (see EffectComposer.tsx) so disabling it
51
+ // while it's the last pass in the chain doesn't blank the canvas.
52
+ groupPasses.add(instance)
53
+ return instance
54
+ }, [camera, scene])
55
+
56
+ // TODO: implement dispose upstream; this effect has memory leaks without
57
+ useDispose(effect)
58
+
59
+ useLayoutEffect(() => {
60
+ effect.enabled = enabled
61
+ invalidate()
62
+ }, [effect, enabled, invalidate])
63
+
64
+ useLayoutEffect(() => {
65
+ applyProps(effect.configuration, {
66
+ color,
67
+ aoRadius,
68
+ distanceFalloff,
69
+ intensity,
70
+ aoSamples,
71
+ denoiseSamples,
72
+ denoiseRadius,
73
+ screenSpaceRadius,
74
+ renderMode,
75
+ halfRes,
76
+ depthAwareUpsampling,
77
+ })
78
+ // effect.configuration is a plain object, never r3f-managed - applyProps'
79
+ // own invalidate (gated behind object.__r3f) never fires for it.
80
+ invalidate()
81
+ }, [
82
+ screenSpaceRadius,
83
+ color,
84
+ aoRadius,
85
+ distanceFalloff,
86
+ intensity,
87
+ aoSamples,
88
+ denoiseSamples,
89
+ denoiseRadius,
90
+ renderMode,
91
+ halfRes,
92
+ depthAwareUpsampling,
93
+ effect,
94
+ invalidate,
95
+ ])
96
+
97
+ useLayoutEffect(() => {
98
+ if (quality) {
99
+ effect.setQualityMode(quality.charAt(0).toUpperCase() + quality.slice(1))
100
+ invalidate()
101
+ }
102
+ }, [effect, quality, invalidate])
103
+
104
+ return <primitive ref={ref} object={effect} />
105
+ }