@react-three/postprocessing 2.12.3 → 2.13.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.
@@ -0,0 +1,16 @@
1
+ /// <reference types="react" />
2
+ import { Effect } from 'postprocessing';
3
+ interface IASCIIEffectProps {
4
+ characters?: string;
5
+ fontSize?: number;
6
+ cellSize?: number;
7
+ color?: string;
8
+ invert?: boolean;
9
+ }
10
+ declare class ASCIIEffect extends Effect {
11
+ constructor({ characters, fontSize, cellSize, color, invert, }?: IASCIIEffectProps);
12
+ /** Draws the characters on a Canvas and returns a texture */
13
+ createCharactersTexture(characters: string, fontSize: number): THREE.Texture;
14
+ }
15
+ export declare const ASCII: import("react").ForwardRefExoticComponent<IASCIIEffectProps & import("react").RefAttributes<ASCIIEffect>>;
16
+ export {};
@@ -1,4 +1,5 @@
1
1
  /// <reference types="react" />
2
+ import { ReactThreeFiber } from '@react-three/fiber';
2
3
  type N8AOProps = {
3
4
  aoRadius?: number;
4
5
  distanceFalloff?: number;
@@ -7,6 +8,7 @@ type N8AOProps = {
7
8
  aoSamples?: number;
8
9
  denoiseSamples?: number;
9
10
  denoiseRadius?: number;
11
+ color?: ReactThreeFiber.Color;
10
12
  };
11
13
  export declare const N8AO: import("react").ForwardRefExoticComponent<N8AOProps & import("react").RefAttributes<N8AOPostPass>>;
12
14
  export {};
package/dist/index.cjs CHANGED
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var THREE = require('three');
5
4
  var React = require('react');
5
+ var THREE = require('three');
6
6
  var fiber = require('@react-three/fiber');
7
7
  var postprocessing = require('postprocessing');
8
- var maath = require('maath');
9
8
  var threeStdlib = require('three-stdlib');
10
- var n8ao = require('n8ao');
9
+ var maath = require('maath');
11
10
  var screenSpaceReflections = require('screen-space-reflections');
11
+ var n8ao = require('n8ao');
12
12
 
13
13
  function _interopNamespaceDefault(e) {
14
14
  var n = Object.create(null);
@@ -29,6 +29,35 @@ function _interopNamespaceDefault(e) {
29
29
 
30
30
  var THREE__namespace = /*#__PURE__*/_interopNamespaceDefault(THREE);
31
31
 
32
+ const selectionContext = React.createContext(null);
33
+ function Selection({ children, enabled = true }) {
34
+ const [selected, select] = React.useState([]);
35
+ const value = React.useMemo(() => ({ selected, select, enabled }), [selected, select, enabled]);
36
+ return jsxRuntime.jsx(selectionContext.Provider, { value: value, children: children });
37
+ }
38
+ function Select({ enabled = false, children, ...props }) {
39
+ const group = React.useRef(null);
40
+ const api = React.useContext(selectionContext);
41
+ React.useEffect(() => {
42
+ if (api && enabled) {
43
+ let changed = false;
44
+ const current = [];
45
+ group.current.traverse((o) => {
46
+ o.type === 'Mesh' && current.push(o);
47
+ if (api.selected.indexOf(o) === -1)
48
+ changed = true;
49
+ });
50
+ if (changed) {
51
+ api.select((state) => [...state, ...current]);
52
+ return () => {
53
+ api.select((state) => state.filter((selected) => !current.includes(selected)));
54
+ };
55
+ }
56
+ }
57
+ }, [enabled, children, api]);
58
+ return (jsxRuntime.jsx("group", { ref: group, ...props, children: children }));
59
+ }
60
+
32
61
  const EffectComposerContext = React.createContext(null);
33
62
  const EffectComposer = React.memo(React.forwardRef(({ children, camera: _camera, scene: _scene, resolutionScale, enabled = true, renderPriority = 1, autoClear = true, depthBuffer, disableNormalPass, stencilBuffer, multisampling = 8, frameBufferType = THREE.HalfFloatType, }, ref) => {
34
63
  const { gl, scene: defaultScene, camera: defaultCamera, size } = fiber.useThree();
@@ -120,6 +149,35 @@ const EffectComposer = React.memo(React.forwardRef(({ children, camera: _camera,
120
149
  return (jsxRuntime.jsx(EffectComposerContext.Provider, { value: state, children: jsxRuntime.jsx("group", { ref: group, children: children }) }));
121
150
  }));
122
151
 
152
+ const resolveRef = (ref) => typeof ref === 'object' && ref != null && 'current' in ref ? ref.current : ref;
153
+ let i = 0;
154
+ const components = new WeakMap();
155
+ const wrapEffect = (effect, defaults) =>
156
+ /* @__PURE__ */ React.forwardRef(function Effect({ blendFunction = defaults === null || defaults === void 0 ? void 0 : defaults.blendFunction, opacity = defaults === null || defaults === void 0 ? void 0 : defaults.opacity, ...props }, ref) {
157
+ let Component = components.get(effect);
158
+ if (!Component) {
159
+ const key = `@react-three/postprocessing/${effect.name}-${i++}`;
160
+ fiber.extend({ [key]: effect });
161
+ components.set(effect, (Component = key));
162
+ }
163
+ const camera = fiber.useThree((state) => state.camera);
164
+ const args = React.useMemo(() => { var _a, _b; return [...((_a = defaults === null || defaults === void 0 ? void 0 : defaults.args) !== null && _a !== void 0 ? _a : []), ...((_b = props.args) !== null && _b !== void 0 ? _b : [{ ...defaults, ...props }])]; },
165
+ // eslint-disable-next-line react-hooks/exhaustive-deps
166
+ [JSON.stringify(props)]);
167
+ return (jsxRuntime.jsx(Component, { camera: camera, "blendMode-blendFunction": blendFunction, "blendMode-opacity-value": opacity, ...props, ref: ref, args: args }));
168
+ });
169
+ const useVector2 = (props, key) => {
170
+ const value = props[key];
171
+ return React.useMemo(() => {
172
+ if (typeof value === 'number')
173
+ return new THREE__namespace.Vector2(value, value);
174
+ else if (value)
175
+ return new THREE__namespace.Vector2(...value);
176
+ else
177
+ return new THREE__namespace.Vector2();
178
+ }, [value]);
179
+ };
180
+
123
181
  const DepthOfField = React.forwardRef(function DepthOfField({ target, depthTexture, ...props }, ref) {
124
182
  const invalidate = fiber.useThree((state) => state.invalidate);
125
183
  const { camera } = React.useContext(EffectComposerContext);
@@ -224,35 +282,6 @@ const Autofocus = React.forwardRef(({ target = undefined, mouse: followMouse = f
224
282
  : null, jsxRuntime.jsx(DepthOfField, { ref: dofRef, ...props, target: hitpoint })] }));
225
283
  });
226
284
 
227
- const resolveRef = (ref) => typeof ref === 'object' && ref != null && 'current' in ref ? ref.current : ref;
228
- let i = 0;
229
- const components = new WeakMap();
230
- const wrapEffect = (effect, defaults) =>
231
- /* @__PURE__ */ React.forwardRef(function Effect({ blendFunction = defaults === null || defaults === void 0 ? void 0 : defaults.blendFunction, opacity = defaults === null || defaults === void 0 ? void 0 : defaults.opacity, ...props }, ref) {
232
- let Component = components.get(effect);
233
- if (!Component) {
234
- const key = `@react-three/postprocessing/${effect.name}-${i++}`;
235
- fiber.extend({ [key]: effect });
236
- components.set(effect, (Component = key));
237
- }
238
- const camera = fiber.useThree((state) => state.camera);
239
- const args = React.useMemo(() => { var _a, _b; return [...((_a = defaults === null || defaults === void 0 ? void 0 : defaults.args) !== null && _a !== void 0 ? _a : []), ...((_b = props.args) !== null && _b !== void 0 ? _b : [{ ...defaults, ...props }])]; },
240
- // eslint-disable-next-line react-hooks/exhaustive-deps
241
- [JSON.stringify(props)]);
242
- return (jsxRuntime.jsx(Component, { camera: camera, "blendMode-blendFunction": blendFunction, "blendMode-opacity-value": opacity, ...props, ref: ref, args: args }));
243
- });
244
- const useVector2 = (props, key) => {
245
- const value = props[key];
246
- return React.useMemo(() => {
247
- if (typeof value === 'number')
248
- return new THREE__namespace.Vector2(value, value);
249
- else if (value)
250
- return new THREE__namespace.Vector2(...value);
251
- else
252
- return new THREE__namespace.Vector2();
253
- }, [value]);
254
- };
255
-
256
285
  const Bloom = wrapEffect(postprocessing.BloomEffect, {
257
286
  blendFunction: postprocessing.BlendFunction.ADD,
258
287
  });
@@ -313,35 +342,6 @@ const HueSaturation = wrapEffect(postprocessing.HueSaturationEffect);
313
342
 
314
343
  const Noise = wrapEffect(postprocessing.NoiseEffect, { blendFunction: postprocessing.BlendFunction.COLOR_DODGE });
315
344
 
316
- const selectionContext = React.createContext(null);
317
- function Selection({ children, enabled = true }) {
318
- const [selected, select] = React.useState([]);
319
- const value = React.useMemo(() => ({ selected, select, enabled }), [selected, select, enabled]);
320
- return jsxRuntime.jsx(selectionContext.Provider, { value: value, children: children });
321
- }
322
- function Select({ enabled = false, children, ...props }) {
323
- const group = React.useRef(null);
324
- const api = React.useContext(selectionContext);
325
- React.useEffect(() => {
326
- if (api && enabled) {
327
- let changed = false;
328
- const current = [];
329
- group.current.traverse((o) => {
330
- o.type === 'Mesh' && current.push(o);
331
- if (api.selected.indexOf(o) === -1)
332
- changed = true;
333
- });
334
- if (changed) {
335
- api.select((state) => [...state, ...current]);
336
- return () => {
337
- api.select((state) => state.filter((selected) => !current.includes(selected)));
338
- };
339
- }
340
- }
341
- }, [enabled, children, api]);
342
- return (jsxRuntime.jsx("group", { ref: group, ...props, children: children }));
343
- }
344
-
345
345
  const Outline = React.forwardRef(function Outline({ selection = [], selectionLayer = 10, blendFunction, patternTexture, edgeStrength, pulseSpeed, visibleEdgeColor, hiddenEdgeColor, width, height, kernelSize, blur, xRay, ...props }, forwardRef) {
346
346
  const invalidate = fiber.useThree((state) => state.invalidate);
347
347
  const { scene, camera } = React.useContext(EffectComposerContext);
@@ -367,7 +367,6 @@ const Outline = React.forwardRef(function Outline({ selection = [], selectionLay
367
367
  hiddenEdgeColor,
368
368
  kernelSize,
369
369
  patternTexture,
370
- props,
371
370
  pulseSpeed,
372
371
  scene,
373
372
  visibleEdgeColor,
@@ -510,26 +509,6 @@ const SSAO = React.forwardRef(function SSAO(props, ref) {
510
509
  return jsxRuntime.jsx("primitive", { ref: ref, object: effect, dispose: null });
511
510
  });
512
511
 
513
- const N8AO = React.forwardRef(({ quality, aoRadius = 5, aoSamples = 16, denoiseSamples = 4, denoiseRadius = 12, distanceFalloff = 1, intensity = 1, }, ref) => {
514
- const { camera, scene } = fiber.useThree();
515
- const effect = React.useMemo(() => new n8ao.N8AOPostPass(scene, camera), []);
516
- React.useLayoutEffect(() => {
517
- Object.assign(effect.configuration, {
518
- aoRadius,
519
- distanceFalloff,
520
- intensity,
521
- aoSamples,
522
- denoiseSamples,
523
- denoiseRadius,
524
- });
525
- }, [aoRadius, distanceFalloff, intensity, aoSamples, denoiseSamples, denoiseRadius]);
526
- React.useLayoutEffect(() => {
527
- if (quality)
528
- effect.setQualityMode(quality.charAt(0).toUpperCase() + quality.slice(1));
529
- }, [quality]);
530
- return jsxRuntime.jsx("primitive", { ref: ref, object: effect });
531
- });
532
-
533
512
  const SMAA = wrapEffect(postprocessing.SMAAEffect);
534
513
 
535
514
  const Texture = React.forwardRef(function Texture({ textureSrc, texture, ...props }, ref) {
@@ -646,6 +625,93 @@ class TiltShiftEffect extends postprocessing.Effect {
646
625
  }
647
626
  const TiltShift2 = wrapEffect(TiltShiftEffect, { blendFunction: postprocessing.BlendFunction.NORMAL });
648
627
 
628
+ const fragment = `
629
+ uniform sampler2D uCharacters;
630
+ uniform float uCharactersCount;
631
+ uniform float uCellSize;
632
+ uniform bool uInvert;
633
+ uniform vec3 uColor;
634
+
635
+ const vec2 SIZE = vec2(16.);
636
+
637
+ vec3 greyscale(vec3 color, float strength) {
638
+ float g = dot(color, vec3(0.299, 0.587, 0.114));
639
+ return mix(color, vec3(g), strength);
640
+ }
641
+
642
+ vec3 greyscale(vec3 color) {
643
+ return greyscale(color, 1.0);
644
+ }
645
+
646
+ void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
647
+ vec2 cell = resolution / uCellSize;
648
+ vec2 grid = 1.0 / cell;
649
+ vec2 pixelizedUV = grid * (0.5 + floor(uv / grid));
650
+ vec4 pixelized = texture2D(inputBuffer, pixelizedUV);
651
+ float greyscaled = greyscale(pixelized.rgb).r;
652
+
653
+ if (uInvert) {
654
+ greyscaled = 1.0 - greyscaled;
655
+ }
656
+
657
+ float characterIndex = floor((uCharactersCount - 1.0) * greyscaled);
658
+ vec2 characterPosition = vec2(mod(characterIndex, SIZE.x), floor(characterIndex / SIZE.y));
659
+ vec2 offset = vec2(characterPosition.x, -characterPosition.y) / SIZE;
660
+ vec2 charUV = mod(uv * (cell / SIZE), 1.0 / SIZE) - vec2(0., 1.0 / SIZE) + offset;
661
+ vec4 asciiCharacter = texture2D(uCharacters, charUV);
662
+
663
+ asciiCharacter.rgb = uColor * asciiCharacter.r;
664
+ asciiCharacter.a = pixelized.a;
665
+ outputColor = asciiCharacter;
666
+ }
667
+ `;
668
+ class ASCIIEffect extends postprocessing.Effect {
669
+ constructor({ characters = ` .:,'-^=*+?!|0#X%WM@`, fontSize = 54, cellSize = 16, color = '#ffffff', invert = false, } = {}) {
670
+ const uniforms = new Map([
671
+ ['uCharacters', new THREE.Uniform(new THREE.Texture())],
672
+ ['uCellSize', new THREE.Uniform(cellSize)],
673
+ ['uCharactersCount', new THREE.Uniform(characters.length)],
674
+ ['uColor', new THREE.Uniform(new THREE.Color(color))],
675
+ ['uInvert', new THREE.Uniform(invert)],
676
+ ]);
677
+ super('ASCIIEffect', fragment, { uniforms });
678
+ const charactersTextureUniform = this.uniforms.get('uCharacters');
679
+ if (charactersTextureUniform) {
680
+ charactersTextureUniform.value = this.createCharactersTexture(characters, fontSize);
681
+ }
682
+ }
683
+ /** Draws the characters on a Canvas and returns a texture */
684
+ createCharactersTexture(characters, fontSize) {
685
+ const canvas = document.createElement('canvas');
686
+ const SIZE = 1024;
687
+ const MAX_PER_ROW = 16;
688
+ const CELL = SIZE / MAX_PER_ROW;
689
+ canvas.width = canvas.height = SIZE;
690
+ const texture = new THREE.CanvasTexture(canvas, undefined, THREE.RepeatWrapping, THREE.RepeatWrapping, THREE.NearestFilter, THREE.NearestFilter);
691
+ const context = canvas.getContext('2d');
692
+ if (!context) {
693
+ throw new Error('Context not available');
694
+ }
695
+ context.clearRect(0, 0, SIZE, SIZE);
696
+ context.font = `${fontSize}px arial`;
697
+ context.textAlign = 'center';
698
+ context.textBaseline = 'middle';
699
+ context.fillStyle = '#fff';
700
+ for (let i = 0; i < characters.length; i++) {
701
+ const char = characters[i];
702
+ const x = i % MAX_PER_ROW;
703
+ const y = Math.floor(i / MAX_PER_ROW);
704
+ context.fillText(char, x * CELL + CELL / 2, y * CELL + CELL / 2);
705
+ }
706
+ texture.needsUpdate = true;
707
+ return texture;
708
+ }
709
+ }
710
+ const ASCII = React.forwardRef(({ characters = ` .:,'-^=*+?!|0#X%WM@`, fontSize = 54, cellSize = 16, color = '#ffffff', invert = false }, fref) => {
711
+ const effect = React.useMemo(() => new ASCIIEffect({ characters, fontSize, cellSize, color, invert }), [characters, fontSize, cellSize, color, invert]);
712
+ return jsxRuntime.jsx("primitive", { ref: fref, object: effect });
713
+ });
714
+
649
715
  const SSR = React.forwardRef(function SSR({ ENABLE_BLUR = true, USE_MRT = true, ...props }, ref) {
650
716
  const { invalidate } = fiber.useThree();
651
717
  const { scene, camera } = React.useContext(EffectComposerContext);
@@ -667,6 +733,28 @@ const SSR = React.forwardRef(function SSR({ ENABLE_BLUR = true, USE_MRT = true,
667
733
  return jsxRuntime.jsx("primitive", { ref: ref, object: effect, ...props });
668
734
  });
669
735
 
736
+ const N8AO = React.forwardRef(({ quality, aoRadius = 5, aoSamples = 16, denoiseSamples = 4, denoiseRadius = 12, distanceFalloff = 1, intensity = 1, color, }, ref) => {
737
+ const { camera, scene } = fiber.useThree();
738
+ const effect = React.useMemo(() => new n8ao.N8AOPostPass(scene, camera), []);
739
+ React.useLayoutEffect(() => {
740
+ fiber.applyProps(effect.configuration, {
741
+ color,
742
+ aoRadius,
743
+ distanceFalloff,
744
+ intensity,
745
+ aoSamples,
746
+ denoiseSamples,
747
+ denoiseRadius,
748
+ });
749
+ }, [color, aoRadius, distanceFalloff, intensity, aoSamples, denoiseSamples, denoiseRadius]);
750
+ React.useLayoutEffect(() => {
751
+ if (quality)
752
+ effect.setQualityMode(quality.charAt(0).toUpperCase() + quality.slice(1));
753
+ }, [quality]);
754
+ return jsxRuntime.jsx("primitive", { ref: ref, object: effect });
755
+ });
756
+
757
+ exports.ASCII = ASCII;
670
758
  exports.Autofocus = Autofocus;
671
759
  exports.Bloom = Bloom;
672
760
  exports.BrightnessContrast = BrightnessContrast;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ export * from './Selection';
2
+ export * from './EffectComposer';
3
+ export * from './util';
1
4
  export * from './effects/Autofocus';
2
5
  export * from './effects/Bloom';
3
6
  export * from './effects/BrightnessContrast';
@@ -5,7 +8,7 @@ export * from './effects/ChromaticAberration';
5
8
  export * from './effects/ColorAverage';
6
9
  export * from './effects/ColorDepth';
7
10
  export * from './effects/Depth';
8
- export { DepthOfField } from './effects/DepthOfField';
11
+ export * from './effects/DepthOfField';
9
12
  export * from './effects/DotScreen';
10
13
  export * from './effects/Glitch';
11
14
  export * from './effects/GodRays';
@@ -18,7 +21,6 @@ export * from './effects/ScanlineEffect';
18
21
  export * from './effects/SelectiveBloom';
19
22
  export * from './effects/Sepia';
20
23
  export * from './effects/SSAO';
21
- export * from './effects/N8AO';
22
24
  export * from './effects/SMAA';
23
25
  export * from './effects/Texture';
24
26
  export * from './effects/ToneMapping';
@@ -27,7 +29,6 @@ export * from './effects/ShockWave';
27
29
  export * from './effects/LUT';
28
30
  export * from './effects/TiltShift';
29
31
  export * from './effects/TiltShift2';
32
+ export * from './effects/ASCII';
30
33
  export * from './effects/SSR';
31
- export * from './Selection';
32
- export * from './EffectComposer';
33
- export * from './util';
34
+ export * from './effects/N8AO';
package/dist/index.js CHANGED
@@ -1,13 +1,42 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import React, { createContext, useState, useMemo, useRef, useContext, useEffect, forwardRef, useLayoutEffect, useImperativeHandle, useCallback } from 'react';
2
3
  import * as THREE from 'three';
3
- import { HalfFloatType, Vector3, TextureLoader, sRGBEncoding, RepeatWrapping, Uniform } from 'three';
4
- import React, { createContext, forwardRef, useMemo, useEffect, useRef, useLayoutEffect, useImperativeHandle, useContext, useState, useCallback } from 'react';
5
- import { useThree, useFrame, useInstanceHandle, createPortal, extend, useLoader } from '@react-three/fiber';
4
+ import { HalfFloatType, Vector3, TextureLoader, sRGBEncoding, RepeatWrapping, Uniform, Texture as Texture$1, Color, CanvasTexture, NearestFilter } from 'three';
5
+ import { useThree, useFrame, useInstanceHandle, extend, createPortal, useLoader, applyProps } from '@react-three/fiber';
6
6
  import { EffectComposer as EffectComposer$1, RenderPass, NormalPass, DepthDownsamplingPass, Effect, EffectPass, Pass, DepthOfFieldEffect, MaskFunction, DepthPickingPass, CopyPass, BlendFunction, BloomEffect, BrightnessContrastEffect, ChromaticAberrationEffect, ColorAverageEffect, ColorDepthEffect, DepthEffect, DotScreenEffect, GlitchEffect, GlitchMode, GodRaysEffect, GridEffect, HueSaturationEffect, NoiseEffect, OutlineEffect, PixelationEffect, ScanlineEffect, SelectiveBloomEffect, SepiaEffect, SSAOEffect, SMAAEffect, TextureEffect, ToneMappingEffect, VignetteEffect, ShockWaveEffect, LUT3DEffect, TiltShiftEffect as TiltShiftEffect$1, EffectAttribute } from 'postprocessing';
7
- import { easing } from 'maath';
8
7
  import { isWebGL2Available } from 'three-stdlib';
9
- import { N8AOPostPass } from 'n8ao';
8
+ import { easing } from 'maath';
10
9
  import { SSREffect } from 'screen-space-reflections';
10
+ import { N8AOPostPass } from 'n8ao';
11
+
12
+ const selectionContext = createContext(null);
13
+ function Selection({ children, enabled = true }) {
14
+ const [selected, select] = useState([]);
15
+ const value = useMemo(() => ({ selected, select, enabled }), [selected, select, enabled]);
16
+ return jsx(selectionContext.Provider, { value: value, children: children });
17
+ }
18
+ function Select({ enabled = false, children, ...props }) {
19
+ const group = useRef(null);
20
+ const api = useContext(selectionContext);
21
+ useEffect(() => {
22
+ if (api && enabled) {
23
+ let changed = false;
24
+ const current = [];
25
+ group.current.traverse((o) => {
26
+ o.type === 'Mesh' && current.push(o);
27
+ if (api.selected.indexOf(o) === -1)
28
+ changed = true;
29
+ });
30
+ if (changed) {
31
+ api.select((state) => [...state, ...current]);
32
+ return () => {
33
+ api.select((state) => state.filter((selected) => !current.includes(selected)));
34
+ };
35
+ }
36
+ }
37
+ }, [enabled, children, api]);
38
+ return (jsx("group", { ref: group, ...props, children: children }));
39
+ }
11
40
 
12
41
  const EffectComposerContext = createContext(null);
13
42
  const EffectComposer = React.memo(forwardRef(({ children, camera: _camera, scene: _scene, resolutionScale, enabled = true, renderPriority = 1, autoClear = true, depthBuffer, disableNormalPass, stencilBuffer, multisampling = 8, frameBufferType = HalfFloatType, }, ref) => {
@@ -100,6 +129,35 @@ const EffectComposer = React.memo(forwardRef(({ children, camera: _camera, scene
100
129
  return (jsx(EffectComposerContext.Provider, { value: state, children: jsx("group", { ref: group, children: children }) }));
101
130
  }));
102
131
 
132
+ const resolveRef = (ref) => typeof ref === 'object' && ref != null && 'current' in ref ? ref.current : ref;
133
+ let i = 0;
134
+ const components = new WeakMap();
135
+ const wrapEffect = (effect, defaults) =>
136
+ /* @__PURE__ */ React.forwardRef(function Effect({ blendFunction = defaults === null || defaults === void 0 ? void 0 : defaults.blendFunction, opacity = defaults === null || defaults === void 0 ? void 0 : defaults.opacity, ...props }, ref) {
137
+ let Component = components.get(effect);
138
+ if (!Component) {
139
+ const key = `@react-three/postprocessing/${effect.name}-${i++}`;
140
+ extend({ [key]: effect });
141
+ components.set(effect, (Component = key));
142
+ }
143
+ const camera = useThree((state) => state.camera);
144
+ const args = React.useMemo(() => { var _a, _b; return [...((_a = defaults === null || defaults === void 0 ? void 0 : defaults.args) !== null && _a !== void 0 ? _a : []), ...((_b = props.args) !== null && _b !== void 0 ? _b : [{ ...defaults, ...props }])]; },
145
+ // eslint-disable-next-line react-hooks/exhaustive-deps
146
+ [JSON.stringify(props)]);
147
+ return (jsx(Component, { camera: camera, "blendMode-blendFunction": blendFunction, "blendMode-opacity-value": opacity, ...props, ref: ref, args: args }));
148
+ });
149
+ const useVector2 = (props, key) => {
150
+ const value = props[key];
151
+ return React.useMemo(() => {
152
+ if (typeof value === 'number')
153
+ return new THREE.Vector2(value, value);
154
+ else if (value)
155
+ return new THREE.Vector2(...value);
156
+ else
157
+ return new THREE.Vector2();
158
+ }, [value]);
159
+ };
160
+
103
161
  const DepthOfField = forwardRef(function DepthOfField({ target, depthTexture, ...props }, ref) {
104
162
  const invalidate = useThree((state) => state.invalidate);
105
163
  const { camera } = useContext(EffectComposerContext);
@@ -204,35 +262,6 @@ const Autofocus = forwardRef(({ target = undefined, mouse: followMouse = false,
204
262
  : null, jsx(DepthOfField, { ref: dofRef, ...props, target: hitpoint })] }));
205
263
  });
206
264
 
207
- const resolveRef = (ref) => typeof ref === 'object' && ref != null && 'current' in ref ? ref.current : ref;
208
- let i = 0;
209
- const components = new WeakMap();
210
- const wrapEffect = (effect, defaults) =>
211
- /* @__PURE__ */ React.forwardRef(function Effect({ blendFunction = defaults === null || defaults === void 0 ? void 0 : defaults.blendFunction, opacity = defaults === null || defaults === void 0 ? void 0 : defaults.opacity, ...props }, ref) {
212
- let Component = components.get(effect);
213
- if (!Component) {
214
- const key = `@react-three/postprocessing/${effect.name}-${i++}`;
215
- extend({ [key]: effect });
216
- components.set(effect, (Component = key));
217
- }
218
- const camera = useThree((state) => state.camera);
219
- const args = React.useMemo(() => { var _a, _b; return [...((_a = defaults === null || defaults === void 0 ? void 0 : defaults.args) !== null && _a !== void 0 ? _a : []), ...((_b = props.args) !== null && _b !== void 0 ? _b : [{ ...defaults, ...props }])]; },
220
- // eslint-disable-next-line react-hooks/exhaustive-deps
221
- [JSON.stringify(props)]);
222
- return (jsx(Component, { camera: camera, "blendMode-blendFunction": blendFunction, "blendMode-opacity-value": opacity, ...props, ref: ref, args: args }));
223
- });
224
- const useVector2 = (props, key) => {
225
- const value = props[key];
226
- return React.useMemo(() => {
227
- if (typeof value === 'number')
228
- return new THREE.Vector2(value, value);
229
- else if (value)
230
- return new THREE.Vector2(...value);
231
- else
232
- return new THREE.Vector2();
233
- }, [value]);
234
- };
235
-
236
265
  const Bloom = wrapEffect(BloomEffect, {
237
266
  blendFunction: BlendFunction.ADD,
238
267
  });
@@ -293,35 +322,6 @@ const HueSaturation = wrapEffect(HueSaturationEffect);
293
322
 
294
323
  const Noise = wrapEffect(NoiseEffect, { blendFunction: BlendFunction.COLOR_DODGE });
295
324
 
296
- const selectionContext = createContext(null);
297
- function Selection({ children, enabled = true }) {
298
- const [selected, select] = useState([]);
299
- const value = useMemo(() => ({ selected, select, enabled }), [selected, select, enabled]);
300
- return jsx(selectionContext.Provider, { value: value, children: children });
301
- }
302
- function Select({ enabled = false, children, ...props }) {
303
- const group = useRef(null);
304
- const api = useContext(selectionContext);
305
- useEffect(() => {
306
- if (api && enabled) {
307
- let changed = false;
308
- const current = [];
309
- group.current.traverse((o) => {
310
- o.type === 'Mesh' && current.push(o);
311
- if (api.selected.indexOf(o) === -1)
312
- changed = true;
313
- });
314
- if (changed) {
315
- api.select((state) => [...state, ...current]);
316
- return () => {
317
- api.select((state) => state.filter((selected) => !current.includes(selected)));
318
- };
319
- }
320
- }
321
- }, [enabled, children, api]);
322
- return (jsx("group", { ref: group, ...props, children: children }));
323
- }
324
-
325
325
  const Outline = forwardRef(function Outline({ selection = [], selectionLayer = 10, blendFunction, patternTexture, edgeStrength, pulseSpeed, visibleEdgeColor, hiddenEdgeColor, width, height, kernelSize, blur, xRay, ...props }, forwardRef) {
326
326
  const invalidate = useThree((state) => state.invalidate);
327
327
  const { scene, camera } = useContext(EffectComposerContext);
@@ -347,7 +347,6 @@ const Outline = forwardRef(function Outline({ selection = [], selectionLayer = 1
347
347
  hiddenEdgeColor,
348
348
  kernelSize,
349
349
  patternTexture,
350
- props,
351
350
  pulseSpeed,
352
351
  scene,
353
352
  visibleEdgeColor,
@@ -490,26 +489,6 @@ const SSAO = forwardRef(function SSAO(props, ref) {
490
489
  return jsx("primitive", { ref: ref, object: effect, dispose: null });
491
490
  });
492
491
 
493
- const N8AO = forwardRef(({ quality, aoRadius = 5, aoSamples = 16, denoiseSamples = 4, denoiseRadius = 12, distanceFalloff = 1, intensity = 1, }, ref) => {
494
- const { camera, scene } = useThree();
495
- const effect = useMemo(() => new N8AOPostPass(scene, camera), []);
496
- useLayoutEffect(() => {
497
- Object.assign(effect.configuration, {
498
- aoRadius,
499
- distanceFalloff,
500
- intensity,
501
- aoSamples,
502
- denoiseSamples,
503
- denoiseRadius,
504
- });
505
- }, [aoRadius, distanceFalloff, intensity, aoSamples, denoiseSamples, denoiseRadius]);
506
- useLayoutEffect(() => {
507
- if (quality)
508
- effect.setQualityMode(quality.charAt(0).toUpperCase() + quality.slice(1));
509
- }, [quality]);
510
- return jsx("primitive", { ref: ref, object: effect });
511
- });
512
-
513
492
  const SMAA = wrapEffect(SMAAEffect);
514
493
 
515
494
  const Texture = forwardRef(function Texture({ textureSrc, texture, ...props }, ref) {
@@ -626,6 +605,93 @@ class TiltShiftEffect extends Effect {
626
605
  }
627
606
  const TiltShift2 = wrapEffect(TiltShiftEffect, { blendFunction: BlendFunction.NORMAL });
628
607
 
608
+ const fragment = `
609
+ uniform sampler2D uCharacters;
610
+ uniform float uCharactersCount;
611
+ uniform float uCellSize;
612
+ uniform bool uInvert;
613
+ uniform vec3 uColor;
614
+
615
+ const vec2 SIZE = vec2(16.);
616
+
617
+ vec3 greyscale(vec3 color, float strength) {
618
+ float g = dot(color, vec3(0.299, 0.587, 0.114));
619
+ return mix(color, vec3(g), strength);
620
+ }
621
+
622
+ vec3 greyscale(vec3 color) {
623
+ return greyscale(color, 1.0);
624
+ }
625
+
626
+ void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
627
+ vec2 cell = resolution / uCellSize;
628
+ vec2 grid = 1.0 / cell;
629
+ vec2 pixelizedUV = grid * (0.5 + floor(uv / grid));
630
+ vec4 pixelized = texture2D(inputBuffer, pixelizedUV);
631
+ float greyscaled = greyscale(pixelized.rgb).r;
632
+
633
+ if (uInvert) {
634
+ greyscaled = 1.0 - greyscaled;
635
+ }
636
+
637
+ float characterIndex = floor((uCharactersCount - 1.0) * greyscaled);
638
+ vec2 characterPosition = vec2(mod(characterIndex, SIZE.x), floor(characterIndex / SIZE.y));
639
+ vec2 offset = vec2(characterPosition.x, -characterPosition.y) / SIZE;
640
+ vec2 charUV = mod(uv * (cell / SIZE), 1.0 / SIZE) - vec2(0., 1.0 / SIZE) + offset;
641
+ vec4 asciiCharacter = texture2D(uCharacters, charUV);
642
+
643
+ asciiCharacter.rgb = uColor * asciiCharacter.r;
644
+ asciiCharacter.a = pixelized.a;
645
+ outputColor = asciiCharacter;
646
+ }
647
+ `;
648
+ class ASCIIEffect extends Effect {
649
+ constructor({ characters = ` .:,'-^=*+?!|0#X%WM@`, fontSize = 54, cellSize = 16, color = '#ffffff', invert = false, } = {}) {
650
+ const uniforms = new Map([
651
+ ['uCharacters', new Uniform(new Texture$1())],
652
+ ['uCellSize', new Uniform(cellSize)],
653
+ ['uCharactersCount', new Uniform(characters.length)],
654
+ ['uColor', new Uniform(new Color(color))],
655
+ ['uInvert', new Uniform(invert)],
656
+ ]);
657
+ super('ASCIIEffect', fragment, { uniforms });
658
+ const charactersTextureUniform = this.uniforms.get('uCharacters');
659
+ if (charactersTextureUniform) {
660
+ charactersTextureUniform.value = this.createCharactersTexture(characters, fontSize);
661
+ }
662
+ }
663
+ /** Draws the characters on a Canvas and returns a texture */
664
+ createCharactersTexture(characters, fontSize) {
665
+ const canvas = document.createElement('canvas');
666
+ const SIZE = 1024;
667
+ const MAX_PER_ROW = 16;
668
+ const CELL = SIZE / MAX_PER_ROW;
669
+ canvas.width = canvas.height = SIZE;
670
+ const texture = new CanvasTexture(canvas, undefined, RepeatWrapping, RepeatWrapping, NearestFilter, NearestFilter);
671
+ const context = canvas.getContext('2d');
672
+ if (!context) {
673
+ throw new Error('Context not available');
674
+ }
675
+ context.clearRect(0, 0, SIZE, SIZE);
676
+ context.font = `${fontSize}px arial`;
677
+ context.textAlign = 'center';
678
+ context.textBaseline = 'middle';
679
+ context.fillStyle = '#fff';
680
+ for (let i = 0; i < characters.length; i++) {
681
+ const char = characters[i];
682
+ const x = i % MAX_PER_ROW;
683
+ const y = Math.floor(i / MAX_PER_ROW);
684
+ context.fillText(char, x * CELL + CELL / 2, y * CELL + CELL / 2);
685
+ }
686
+ texture.needsUpdate = true;
687
+ return texture;
688
+ }
689
+ }
690
+ const ASCII = forwardRef(({ characters = ` .:,'-^=*+?!|0#X%WM@`, fontSize = 54, cellSize = 16, color = '#ffffff', invert = false }, fref) => {
691
+ const effect = useMemo(() => new ASCIIEffect({ characters, fontSize, cellSize, color, invert }), [characters, fontSize, cellSize, color, invert]);
692
+ return jsx("primitive", { ref: fref, object: effect });
693
+ });
694
+
629
695
  const SSR = forwardRef(function SSR({ ENABLE_BLUR = true, USE_MRT = true, ...props }, ref) {
630
696
  const { invalidate } = useThree();
631
697
  const { scene, camera } = useContext(EffectComposerContext);
@@ -647,4 +713,25 @@ const SSR = forwardRef(function SSR({ ENABLE_BLUR = true, USE_MRT = true, ...pro
647
713
  return jsx("primitive", { ref: ref, object: effect, ...props });
648
714
  });
649
715
 
650
- export { Autofocus, Bloom, BrightnessContrast, ChromaticAberration, ColorAverage, ColorDepth, Depth, DepthOfField, DotScreen, EffectComposer, EffectComposerContext, Glitch, GodRays, Grid, HueSaturation, LUT, N8AO, Noise, Outline, Pixelation, SMAA, SSAO, SSR, Scanline, Select, Selection, SelectiveBloom, Sepia, ShockWave, Texture, TiltShift, TiltShift2, TiltShiftEffect, ToneMapping, Vignette, resolveRef, selectionContext, useVector2, wrapEffect };
716
+ const N8AO = forwardRef(({ quality, aoRadius = 5, aoSamples = 16, denoiseSamples = 4, denoiseRadius = 12, distanceFalloff = 1, intensity = 1, color, }, ref) => {
717
+ const { camera, scene } = useThree();
718
+ const effect = useMemo(() => new N8AOPostPass(scene, camera), []);
719
+ useLayoutEffect(() => {
720
+ applyProps(effect.configuration, {
721
+ color,
722
+ aoRadius,
723
+ distanceFalloff,
724
+ intensity,
725
+ aoSamples,
726
+ denoiseSamples,
727
+ denoiseRadius,
728
+ });
729
+ }, [color, aoRadius, distanceFalloff, intensity, aoSamples, denoiseSamples, denoiseRadius]);
730
+ useLayoutEffect(() => {
731
+ if (quality)
732
+ effect.setQualityMode(quality.charAt(0).toUpperCase() + quality.slice(1));
733
+ }, [quality]);
734
+ return jsx("primitive", { ref: ref, object: effect });
735
+ });
736
+
737
+ export { ASCII, Autofocus, Bloom, BrightnessContrast, ChromaticAberration, ColorAverage, ColorDepth, Depth, DepthOfField, DotScreen, EffectComposer, EffectComposerContext, Glitch, GodRays, Grid, HueSaturation, LUT, N8AO, Noise, Outline, Pixelation, SMAA, SSAO, SSR, Scanline, Select, Selection, SelectiveBloom, Sepia, ShockWave, Texture, TiltShift, TiltShift2, TiltShiftEffect, ToneMapping, Vignette, resolveRef, selectionContext, useVector2, wrapEffect };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-three/postprocessing",
3
- "version": "2.12.3",
3
+ "version": "2.13.0",
4
4
  "description": "postprocessing wrapper for React and @react-three/fiber",
5
5
  "keywords": [
6
6
  "postprocessing",
@@ -48,8 +48,8 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "maath": "^0.5.3",
51
- "n8ao": "^1.2.1",
52
- "postprocessing": "^6.30.2",
51
+ "n8ao": "^1.3.1",
52
+ "postprocessing": "^6.31.0",
53
53
  "screen-space-reflections": "2.5.0",
54
54
  "three-stdlib": "^2.21.10"
55
55
  },