@react-three/postprocessing 3.0.5 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -7
- package/dist/EffectComposer.d.ts +9 -2
- package/dist/EffectGroup.d.ts +9 -0
- package/dist/createEffectComponent.d.ts +30 -0
- package/dist/effects/ASCII.d.ts +28 -7
- package/dist/effects/Autofocus.d.ts +1 -1
- package/dist/effects/Bloom.d.ts +9 -1
- package/dist/effects/BrightnessContrast.d.ts +14 -1
- package/dist/effects/ChromaticAberration.d.ts +26 -3
- package/dist/effects/ColorAverage.d.ts +7 -7
- package/dist/effects/ColorDepth.d.ts +7 -1
- package/dist/effects/Depth.d.ts +12 -1
- package/dist/effects/DotScreen.d.ts +14 -1
- package/dist/effects/FXAA.d.ts +10 -1
- package/dist/effects/Glitch.d.ts +16 -11
- package/dist/effects/GodRays.d.ts +1 -1
- package/dist/effects/Grid.d.ts +7 -6
- package/dist/effects/HueSaturation.d.ts +14 -1
- package/dist/effects/LUT.d.ts +1 -1
- package/dist/effects/LensFlare.d.ts +46 -5
- package/dist/effects/Noise.d.ts +7 -1
- package/dist/effects/Outline.d.ts +6 -3
- package/dist/effects/Pixelation.d.ts +1 -1
- package/dist/effects/Ramp.d.ts +58 -6
- package/dist/effects/SMAA.d.ts +9 -1
- package/dist/effects/SSAO.d.ts +1 -1
- package/dist/effects/ScanlineEffect.d.ts +12 -1
- package/dist/effects/SelectiveBloom.d.ts +1 -1
- package/dist/effects/Sepia.d.ts +12 -1
- package/dist/effects/ShockWave.d.ts +11 -1
- package/dist/effects/Texture.d.ts +4 -4
- package/dist/effects/TiltShift.d.ts +9 -1
- package/dist/effects/TiltShift2.d.ts +44 -4
- package/dist/effects/ToneMapping.d.ts +9 -3
- package/dist/effects/Vignette.d.ts +18 -1
- package/dist/effects/Water.d.ts +17 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2205 -713
- package/dist/index.js.map +1 -1
- package/dist/passes/DepthPicking.d.ts +11 -0
- package/dist/{effects → passes}/N8AO.d.ts +2 -1
- package/dist/util.d.ts +9 -15
- package/dist/wrapEffect.d.ts +3 -3
- package/package.json +6 -5
- package/src/EffectComposer.tsx +143 -42
- package/src/EffectGroup.tsx +74 -0
- package/src/createEffectComponent.tsx +71 -0
- package/src/effects/ASCII.tsx +75 -28
- package/src/effects/Autofocus.tsx +24 -77
- package/src/effects/Bloom.tsx +32 -4
- package/src/effects/BrightnessContrast.tsx +5 -2
- package/src/effects/ChromaticAberration.tsx +13 -21
- package/src/effects/ColorAverage.tsx +3 -16
- package/src/effects/ColorDepth.tsx +23 -2
- package/src/effects/Depth.tsx +4 -2
- package/src/effects/DepthOfField.tsx +48 -26
- package/src/effects/DotScreen.tsx +5 -2
- package/src/effects/FXAA.tsx +4 -2
- package/src/effects/Glitch.tsx +26 -31
- package/src/effects/GodRays.tsx +90 -6
- package/src/effects/Grid.tsx +17 -18
- package/src/effects/HueSaturation.tsx +5 -2
- package/src/effects/LUT.tsx +9 -11
- package/src/effects/LensFlare.tsx +209 -55
- package/src/effects/Noise.tsx +14 -2
- package/src/effects/Outline.tsx +55 -56
- package/src/effects/Pixelation.tsx +11 -8
- package/src/effects/Ramp.tsx +96 -7
- package/src/effects/SMAA.tsx +18 -2
- package/src/effects/SSAO.tsx +130 -22
- package/src/effects/ScanlineEffect.tsx +6 -6
- package/src/effects/SelectiveBloom.tsx +26 -44
- package/src/effects/Sepia.tsx +4 -2
- package/src/effects/ShockWave.tsx +30 -2
- package/src/effects/Texture.tsx +10 -9
- package/src/effects/TiltShift.tsx +30 -2
- package/src/effects/TiltShift2.tsx +72 -6
- package/src/effects/ToneMapping.tsx +16 -3
- package/src/effects/Vignette.tsx +5 -2
- package/src/effects/Water.tsx +21 -6
- package/src/index.ts +4 -2
- package/src/passes/DepthPicking.tsx +63 -0
- package/src/{effects → passes}/N8AO.tsx +28 -4
- package/src/tests/Autofocus.test.tsx +38 -0
- package/src/tests/Bloom.test.tsx +76 -0
- package/src/tests/ChromaticAberration.test.tsx +50 -0
- package/src/tests/ColorDepth.test.tsx +71 -0
- package/src/tests/DepthOfField.test.tsx +130 -0
- package/src/tests/DepthPicking.test.tsx +250 -0
- package/src/tests/EffectComposer.test.tsx +501 -8
- package/src/tests/EffectGroup.test.tsx +337 -0
- package/src/tests/Glitch.test.tsx +56 -0
- package/src/tests/GodRays.test.tsx +101 -0
- package/src/tests/Grid.test.tsx +34 -0
- package/src/tests/LUT.test.tsx +64 -0
- package/src/tests/N8AO.test.tsx +92 -0
- package/src/tests/Outline.test.tsx +122 -0
- package/src/tests/SSAO.test.tsx +140 -0
- package/src/tests/SelectiveBloom.test.tsx +48 -0
- package/src/tests/ShockWave.test.tsx +95 -0
- package/src/tests/TiltShift.test.tsx +76 -0
- package/src/tests/createEffectComponent.test.tsx +286 -0
- package/src/tests/effects.smoke.test.tsx +46 -42
- package/src/util.tsx +148 -23
- package/src/wrapEffect.tsx +3 -2
- package/dist/tests/test-utils.d.ts +0 -12
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
// Created by Anderson Mancini 2023
|
|
2
2
|
// From https://github.com/ektogamat/R3F-Ultimate-Lens-Flare
|
|
3
3
|
|
|
4
|
-
import { useFrame, useThree } from '@react-three/fiber'
|
|
4
|
+
import { useFrame, useThree, type ReactThreeFiber } from '@react-three/fiber'
|
|
5
5
|
import { easing } from 'maath'
|
|
6
6
|
import { BlendFunction, Effect } from 'postprocessing'
|
|
7
|
-
import { useContext, useEffect, useRef, useState } from 'react'
|
|
7
|
+
import { useContext, useEffect, useRef, useState, type Ref } from 'react'
|
|
8
8
|
import { Color, Mesh, Texture, Uniform, Vector2, Vector3 } from 'three'
|
|
9
9
|
|
|
10
|
+
import { createEffectComponent } from '../createEffectComponent'
|
|
10
11
|
import { EffectComposerContext } from '../EffectComposer'
|
|
11
|
-
import {
|
|
12
|
+
import { useMergeRefs, useVector3 } from '../util'
|
|
12
13
|
|
|
13
14
|
const LensFlareShader = {
|
|
14
15
|
fragmentShader: /* glsl */ `
|
|
@@ -441,26 +442,26 @@ type LensFlareEffectOptions = {
|
|
|
441
442
|
|
|
442
443
|
export class LensFlareEffect extends Effect {
|
|
443
444
|
constructor({
|
|
444
|
-
blendFunction,
|
|
445
|
-
enabled,
|
|
446
|
-
glareSize,
|
|
447
|
-
lensPosition,
|
|
448
|
-
screenRes,
|
|
449
|
-
starPoints,
|
|
450
|
-
flareSize,
|
|
451
|
-
flareSpeed,
|
|
452
|
-
flareShape,
|
|
453
|
-
animated,
|
|
454
|
-
anamorphic,
|
|
455
|
-
colorGain,
|
|
456
|
-
lensDirtTexture,
|
|
457
|
-
haloScale,
|
|
458
|
-
secondaryGhosts,
|
|
459
|
-
aditionalStreaks,
|
|
460
|
-
ghostScale,
|
|
461
|
-
opacity,
|
|
462
|
-
starBurst,
|
|
463
|
-
}: LensFlareEffectOptions) {
|
|
445
|
+
blendFunction = BlendFunction.NORMAL,
|
|
446
|
+
enabled = true,
|
|
447
|
+
glareSize = 0.2,
|
|
448
|
+
lensPosition = new Vector3(-25, 6, -60),
|
|
449
|
+
screenRes = new Vector2(0, 0),
|
|
450
|
+
starPoints = 6,
|
|
451
|
+
flareSize = 0.01,
|
|
452
|
+
flareSpeed = 0.01,
|
|
453
|
+
flareShape = 0.01,
|
|
454
|
+
animated = true,
|
|
455
|
+
anamorphic = false,
|
|
456
|
+
colorGain = new Color(20, 20, 20),
|
|
457
|
+
lensDirtTexture = null,
|
|
458
|
+
haloScale = 0.5,
|
|
459
|
+
secondaryGhosts = true,
|
|
460
|
+
aditionalStreaks = true,
|
|
461
|
+
ghostScale = 0.0,
|
|
462
|
+
opacity = 1.0,
|
|
463
|
+
starBurst = false,
|
|
464
|
+
}: Partial<LensFlareEffectOptions> = {}) {
|
|
464
465
|
super('LensFlareEffect', LensFlareShader.fragmentShader, {
|
|
465
466
|
blendFunction,
|
|
466
467
|
uniforms: new Map<string, Uniform>([
|
|
@@ -493,40 +494,191 @@ export class LensFlareEffect extends Effect {
|
|
|
493
494
|
time.value += deltaTime
|
|
494
495
|
}
|
|
495
496
|
}
|
|
497
|
+
|
|
498
|
+
private u<T>(name: string): T {
|
|
499
|
+
return this.uniforms.get(name)!.value
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
private setU(name: string, value: unknown): void {
|
|
503
|
+
this.uniforms.get(name)!.value = value
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
get enabled(): boolean {
|
|
507
|
+
return this.u('enabled')
|
|
508
|
+
}
|
|
509
|
+
set enabled(value: boolean) {
|
|
510
|
+
this.setU('enabled', value)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
get glareSize(): number {
|
|
514
|
+
return this.u('glareSize')
|
|
515
|
+
}
|
|
516
|
+
set glareSize(value: number) {
|
|
517
|
+
this.setU('glareSize', value)
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
get lensPosition(): Vector3 {
|
|
521
|
+
return this.u('lensPosition')
|
|
522
|
+
}
|
|
523
|
+
set lensPosition(value: Vector3) {
|
|
524
|
+
this.setU('lensPosition', value)
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
get screenRes(): Vector2 {
|
|
528
|
+
return this.u('screenRes')
|
|
529
|
+
}
|
|
530
|
+
set screenRes(value: Vector2) {
|
|
531
|
+
this.setU('screenRes', value)
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
get starPoints(): number {
|
|
535
|
+
return this.u('starPoints')
|
|
536
|
+
}
|
|
537
|
+
set starPoints(value: number) {
|
|
538
|
+
this.setU('starPoints', value)
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
get flareSize(): number {
|
|
542
|
+
return this.u('flareSize')
|
|
543
|
+
}
|
|
544
|
+
set flareSize(value: number) {
|
|
545
|
+
this.setU('flareSize', value)
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
get flareSpeed(): number {
|
|
549
|
+
return this.u('flareSpeed')
|
|
550
|
+
}
|
|
551
|
+
set flareSpeed(value: number) {
|
|
552
|
+
this.setU('flareSpeed', value)
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
get flareShape(): number {
|
|
556
|
+
return this.u('flareShape')
|
|
557
|
+
}
|
|
558
|
+
set flareShape(value: number) {
|
|
559
|
+
this.setU('flareShape', value)
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
get animated(): boolean {
|
|
563
|
+
return this.u('animated')
|
|
564
|
+
}
|
|
565
|
+
set animated(value: boolean) {
|
|
566
|
+
this.setU('animated', value)
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
get anamorphic(): boolean {
|
|
570
|
+
return this.u('anamorphic')
|
|
571
|
+
}
|
|
572
|
+
set anamorphic(value: boolean) {
|
|
573
|
+
this.setU('anamorphic', value)
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
get colorGain(): Color {
|
|
577
|
+
return this.u('colorGain')
|
|
578
|
+
}
|
|
579
|
+
set colorGain(value: Color) {
|
|
580
|
+
this.setU('colorGain', value)
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
get lensDirtTexture(): Texture | null {
|
|
584
|
+
return this.u('lensDirtTexture')
|
|
585
|
+
}
|
|
586
|
+
set lensDirtTexture(value: Texture | null) {
|
|
587
|
+
this.setU('lensDirtTexture', value)
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
get haloScale(): number {
|
|
591
|
+
return this.u('haloScale')
|
|
592
|
+
}
|
|
593
|
+
set haloScale(value: number) {
|
|
594
|
+
this.setU('haloScale', value)
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
get secondaryGhosts(): boolean {
|
|
598
|
+
return this.u('secondaryGhosts')
|
|
599
|
+
}
|
|
600
|
+
set secondaryGhosts(value: boolean) {
|
|
601
|
+
this.setU('secondaryGhosts', value)
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
get aditionalStreaks(): boolean {
|
|
605
|
+
return this.u('aditionalStreaks')
|
|
606
|
+
}
|
|
607
|
+
set aditionalStreaks(value: boolean) {
|
|
608
|
+
this.setU('aditionalStreaks', value)
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
get ghostScale(): number {
|
|
612
|
+
return this.u('ghostScale')
|
|
613
|
+
}
|
|
614
|
+
set ghostScale(value: number) {
|
|
615
|
+
this.setU('ghostScale', value)
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
get starBurst(): boolean {
|
|
619
|
+
return this.u('starBurst')
|
|
620
|
+
}
|
|
621
|
+
set starBurst(value: boolean) {
|
|
622
|
+
this.setU('starBurst', value)
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
get opacity(): number {
|
|
626
|
+
return this.u('opacity')
|
|
627
|
+
}
|
|
628
|
+
set opacity(value: number) {
|
|
629
|
+
this.setU('opacity', value)
|
|
630
|
+
}
|
|
496
631
|
}
|
|
497
632
|
|
|
498
|
-
type LensFlareProps = {
|
|
633
|
+
type LensFlareProps = Omit<Partial<LensFlareEffectOptions>, 'lensPosition'> & {
|
|
499
634
|
/** Position of the effect */
|
|
500
|
-
lensPosition?: Vector3
|
|
635
|
+
lensPosition?: ReactThreeFiber.Vector3
|
|
501
636
|
/** The time that it takes to fade the occlusion */
|
|
502
637
|
smoothTime?: number
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
638
|
+
ref?: Ref<LensFlareEffect>
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
const LensFlareWrapped = /* @__PURE__ */ createEffectComponent<
|
|
642
|
+
typeof LensFlareEffect,
|
|
643
|
+
Partial<LensFlareEffectOptions> & { ref?: Ref<LensFlareEffect> }
|
|
644
|
+
>(LensFlareEffect)
|
|
645
|
+
|
|
646
|
+
// Stable identity so a parent re-render (e.g. a Leva control) doesn't hand
|
|
647
|
+
// r3f a brand-new Vector2 every time - r3f would then `.copy()` it onto the
|
|
648
|
+
// uniform in place, stomping the viewport-driven value the effect below
|
|
649
|
+
// maintains and leaving screenRes at (0, 0) until the next resize. Never
|
|
650
|
+
// mutated (only ever copied *from*), so it's safe to share across instances.
|
|
651
|
+
const DEFAULT_SCREEN_RES = /* @__PURE__ */ new Vector2(0, 0)
|
|
652
|
+
|
|
653
|
+
// Same reasoning as DEFAULT_SCREEN_RES above - shared, read-only default.
|
|
654
|
+
const DEFAULT_LENS_POSITION = /* @__PURE__ */ new Vector3(-25, 6, -60)
|
|
655
|
+
|
|
656
|
+
export const LensFlare = (props: LensFlareProps) => {
|
|
657
|
+
const {
|
|
658
|
+
ref: forwardedRef,
|
|
659
|
+
smoothTime = 0.07,
|
|
660
|
+
blendFunction = BlendFunction.NORMAL,
|
|
661
|
+
enabled = true,
|
|
662
|
+
glareSize = 0.2,
|
|
663
|
+
screenRes,
|
|
664
|
+
starPoints = 6,
|
|
665
|
+
flareSize = 0.01,
|
|
666
|
+
flareSpeed = 0.01,
|
|
667
|
+
flareShape = 0.01,
|
|
668
|
+
animated = true,
|
|
669
|
+
anamorphic = false,
|
|
670
|
+
colorGain = new Color(20, 20, 20),
|
|
671
|
+
lensDirtTexture = null,
|
|
672
|
+
haloScale = 0.5,
|
|
673
|
+
secondaryGhosts = true,
|
|
674
|
+
aditionalStreaks = true,
|
|
675
|
+
ghostScale = 0.0,
|
|
676
|
+
opacity = 1.0,
|
|
677
|
+
starBurst = false,
|
|
678
|
+
} = props
|
|
679
|
+
|
|
680
|
+
const lensPosition = useVector3({ lensPosition: props.lensPosition ?? DEFAULT_LENS_POSITION }, 'lensPosition')
|
|
681
|
+
|
|
530
682
|
const viewport = useThree(({ viewport }) => viewport)
|
|
531
683
|
const raycaster = useThree(({ raycaster }) => raycaster)
|
|
532
684
|
const { scene, camera } = useContext(EffectComposerContext)
|
|
@@ -534,6 +686,7 @@ export const LensFlare = ({
|
|
|
534
686
|
const [projectedPosition] = useState(() => new Vector3())
|
|
535
687
|
|
|
536
688
|
const ref = useRef<LensFlareEffect>(null)
|
|
689
|
+
const setRef = useMergeRefs(ref, forwardedRef)
|
|
537
690
|
|
|
538
691
|
useFrame((_, delta) => {
|
|
539
692
|
if (!ref?.current) return
|
|
@@ -541,7 +694,7 @@ export const LensFlare = ({
|
|
|
541
694
|
const uOpacity = ref.current.uniforms.get('opacity')
|
|
542
695
|
if (!uLensPosition || !uOpacity) return
|
|
543
696
|
|
|
544
|
-
let target =
|
|
697
|
+
let target = 0
|
|
545
698
|
|
|
546
699
|
projectedPosition.copy(lensPosition).project(camera)
|
|
547
700
|
if (projectedPosition.z > 1) return
|
|
@@ -555,6 +708,7 @@ export const LensFlare = ({
|
|
|
555
708
|
const intersects = raycaster.intersectObjects(scene.children, true)
|
|
556
709
|
const { object } = intersects[0] || {}
|
|
557
710
|
if (object) {
|
|
711
|
+
target = 1
|
|
558
712
|
if (object.userData?.lensflare === 'no-occlusion') {
|
|
559
713
|
target = 0
|
|
560
714
|
} else if (object instanceof Mesh) {
|
|
@@ -586,12 +740,12 @@ export const LensFlare = ({
|
|
|
586
740
|
|
|
587
741
|
return (
|
|
588
742
|
<LensFlareWrapped
|
|
589
|
-
ref={
|
|
743
|
+
ref={setRef}
|
|
590
744
|
blendFunction={blendFunction}
|
|
591
745
|
enabled={enabled}
|
|
592
746
|
glareSize={glareSize}
|
|
593
747
|
lensPosition={lensPosition}
|
|
594
|
-
screenRes={screenRes}
|
|
748
|
+
screenRes={screenRes ?? DEFAULT_SCREEN_RES}
|
|
595
749
|
starPoints={starPoints}
|
|
596
750
|
flareSize={flareSize}
|
|
597
751
|
flareSpeed={flareSpeed}
|
package/src/effects/Noise.tsx
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import { BlendFunction, NoiseEffect } from 'postprocessing'
|
|
2
|
-
import {
|
|
2
|
+
import type { Ref } from 'react'
|
|
3
|
+
import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
const NoiseImpl = /* @__PURE__ */ createEffectComponent<typeof NoiseEffect, EffectOptions<typeof NoiseEffect>>(
|
|
6
|
+
NoiseEffect
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
export type NoiseProps = EffectOptions<typeof NoiseEffect> & {
|
|
10
|
+
opacity?: number
|
|
11
|
+
ref?: Ref<NoiseEffect>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function Noise({ blendFunction = BlendFunction.COLOR_DODGE, ...props }: NoiseProps) {
|
|
15
|
+
return <NoiseImpl blendFunction={blendFunction} {...props} />
|
|
16
|
+
}
|
package/src/effects/Outline.tsx
CHANGED
|
@@ -1,83 +1,82 @@
|
|
|
1
1
|
import { OutlineEffect } from 'postprocessing'
|
|
2
|
-
import { Ref, RefObject, use, useMemo } from 'react'
|
|
3
|
-
import { Object3D } from 'three'
|
|
2
|
+
import { Ref, RefObject, use, useEffect, useMemo } from 'react'
|
|
3
|
+
import { Color, Object3D, type ColorRepresentation } from 'three'
|
|
4
4
|
import { EffectComposerContext } from '../EffectComposer'
|
|
5
|
-
import { EMPTY_ARRAY, useDispose, useSelectionSync } from '../util'
|
|
5
|
+
import { applyPierced, EMPTY_ARRAY, readPierced, useDispose, useLiveDefaults, useSelectionSync } from '../util'
|
|
6
6
|
|
|
7
7
|
type ObjectRef = RefObject<Object3D | null>
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
type OutlineEffectOptions = NonNullable<ConstructorParameters<typeof OutlineEffect>[2]>
|
|
10
|
+
|
|
11
|
+
export type OutlineProps = Omit<OutlineEffectOptions, 'visibleEdgeColor' | 'hiddenEdgeColor'> &
|
|
10
12
|
Partial<{
|
|
11
13
|
selection: Object3D | Object3D[] | ObjectRef | ObjectRef[]
|
|
12
14
|
selectionLayer: number
|
|
15
|
+
visibleEdgeColor: ColorRepresentation
|
|
16
|
+
hiddenEdgeColor: ColorRepresentation
|
|
13
17
|
ref?: Ref<OutlineEffect>
|
|
14
18
|
}>
|
|
15
19
|
|
|
20
|
+
// Every OutlineEffect option that has a real setter (verified against
|
|
21
|
+
// postprocessing's source) - resolutionScale/resolutionX/resolutionY are
|
|
22
|
+
// the only ones without one, since they only feed the internal blur pass
|
|
23
|
+
// at construction time. scene/camera are required constructor args, so
|
|
24
|
+
// OutlineEffect can't use createEffectComponent (needs `new Effect()` to
|
|
25
|
+
// work with zero args) - built by hand instead.
|
|
26
|
+
const LIVE_KEYS = [
|
|
27
|
+
'patternTexture',
|
|
28
|
+
'patternScale',
|
|
29
|
+
'edgeStrength',
|
|
30
|
+
'pulseSpeed',
|
|
31
|
+
'visibleEdgeColor',
|
|
32
|
+
'hiddenEdgeColor',
|
|
33
|
+
'multisampling',
|
|
34
|
+
'width',
|
|
35
|
+
'height',
|
|
36
|
+
'kernelSize',
|
|
37
|
+
'blur',
|
|
38
|
+
'xRay',
|
|
39
|
+
'dithering',
|
|
40
|
+
'blendMode-blendFunction',
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
// The setter stores whatever it's given as-is, unlike the constructor -
|
|
44
|
+
// wrap in a Color here too, or a raw hex/string breaks the shader uniform.
|
|
45
|
+
function set(effect: OutlineEffect, key: string, value: unknown): void {
|
|
46
|
+
if (key === 'visibleEdgeColor' || key === 'hiddenEdgeColor') applyPierced(effect, key, new Color(value as never))
|
|
47
|
+
else applyPierced(effect, key, value)
|
|
48
|
+
}
|
|
49
|
+
|
|
16
50
|
export function Outline({
|
|
17
51
|
selection = EMPTY_ARRAY,
|
|
18
52
|
selectionLayer = 10,
|
|
19
53
|
blendFunction,
|
|
20
|
-
patternTexture,
|
|
21
|
-
patternScale,
|
|
22
|
-
edgeStrength,
|
|
23
|
-
pulseSpeed,
|
|
24
|
-
visibleEdgeColor,
|
|
25
|
-
hiddenEdgeColor,
|
|
26
|
-
multisampling,
|
|
27
54
|
resolutionScale,
|
|
28
55
|
resolutionX,
|
|
29
56
|
resolutionY,
|
|
30
|
-
width,
|
|
31
|
-
height,
|
|
32
|
-
kernelSize,
|
|
33
|
-
blur,
|
|
34
|
-
xRay,
|
|
35
57
|
ref,
|
|
58
|
+
...liveProps
|
|
36
59
|
}: OutlineProps) {
|
|
37
|
-
const { scene, camera } = use(EffectComposerContext)
|
|
60
|
+
const { scene, camera, autoClear } = use(EffectComposerContext)
|
|
38
61
|
|
|
39
62
|
const effect = useMemo(
|
|
40
|
-
() =>
|
|
41
|
-
|
|
42
|
-
blendFunction,
|
|
43
|
-
patternTexture,
|
|
44
|
-
patternScale,
|
|
45
|
-
edgeStrength,
|
|
46
|
-
pulseSpeed,
|
|
47
|
-
visibleEdgeColor,
|
|
48
|
-
hiddenEdgeColor,
|
|
49
|
-
multisampling,
|
|
50
|
-
resolutionScale,
|
|
51
|
-
resolutionX,
|
|
52
|
-
resolutionY,
|
|
53
|
-
width,
|
|
54
|
-
height,
|
|
55
|
-
kernelSize,
|
|
56
|
-
blur,
|
|
57
|
-
xRay,
|
|
58
|
-
}),
|
|
59
|
-
[
|
|
60
|
-
blendFunction,
|
|
61
|
-
patternTexture,
|
|
62
|
-
patternScale,
|
|
63
|
-
edgeStrength,
|
|
64
|
-
pulseSpeed,
|
|
65
|
-
visibleEdgeColor,
|
|
66
|
-
hiddenEdgeColor,
|
|
67
|
-
multisampling,
|
|
68
|
-
resolutionScale,
|
|
69
|
-
resolutionX,
|
|
70
|
-
resolutionY,
|
|
71
|
-
width,
|
|
72
|
-
height,
|
|
73
|
-
kernelSize,
|
|
74
|
-
blur,
|
|
75
|
-
xRay,
|
|
76
|
-
camera,
|
|
77
|
-
scene,
|
|
78
|
-
]
|
|
63
|
+
() => new OutlineEffect(scene, camera, { resolutionScale, resolutionX, resolutionY }),
|
|
64
|
+
[scene, camera, resolutionScale, resolutionX, resolutionY]
|
|
79
65
|
)
|
|
80
66
|
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (autoClear !== false) {
|
|
69
|
+
console.warn('Outline requires <EffectComposer autoClear={false}> to render correctly.')
|
|
70
|
+
}
|
|
71
|
+
}, [autoClear])
|
|
72
|
+
|
|
73
|
+
useLiveDefaults(
|
|
74
|
+
effect,
|
|
75
|
+
{ ...liveProps, 'blendMode-blendFunction': blendFunction } as Record<string, unknown>,
|
|
76
|
+
LIVE_KEYS,
|
|
77
|
+
readPierced,
|
|
78
|
+
set
|
|
79
|
+
)
|
|
81
80
|
useSelectionSync(effect, selection, selectionLayer)
|
|
82
81
|
useDispose(effect)
|
|
83
82
|
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { PixelationEffect } from 'postprocessing'
|
|
2
|
-
import { Ref
|
|
3
|
-
import {
|
|
2
|
+
import type { Ref } from 'react'
|
|
3
|
+
import { createEffectComponent } from '../createEffectComponent'
|
|
4
|
+
|
|
5
|
+
// PixelationEffect's sole constructor arg is a bare number, not an options
|
|
6
|
+
// object - granularity is a real live setter though, so it's just a normal
|
|
7
|
+
// prop; only the curated default (5, vs the class's own default of 30)
|
|
8
|
+
// needs a thin wrapper.
|
|
9
|
+
const PixelationImpl = /* @__PURE__ */ createEffectComponent<typeof PixelationEffect, { granularity?: number }>(
|
|
10
|
+
PixelationEffect
|
|
11
|
+
)
|
|
4
12
|
|
|
5
13
|
export type PixelationProps = {
|
|
6
14
|
granularity?: number
|
|
@@ -8,10 +16,5 @@ export type PixelationProps = {
|
|
|
8
16
|
}
|
|
9
17
|
|
|
10
18
|
export function Pixelation({ granularity = 5, ref }: PixelationProps) {
|
|
11
|
-
|
|
12
|
-
const effect = useMemo(() => new PixelationEffect(granularity), [granularity])
|
|
13
|
-
|
|
14
|
-
useDispose(effect)
|
|
15
|
-
|
|
16
|
-
return <primitive ref={ref} object={effect} />
|
|
19
|
+
return <PixelationImpl granularity={granularity} ref={ref} />
|
|
17
20
|
}
|
package/src/effects/Ramp.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Effect } from 'postprocessing'
|
|
1
|
+
import { BlendFunction, Effect } from 'postprocessing'
|
|
2
|
+
import type { Ref } from 'react'
|
|
2
3
|
import { Uniform } from 'three'
|
|
3
|
-
import {
|
|
4
|
+
import { createEffectComponent } from '../createEffectComponent'
|
|
4
5
|
|
|
5
6
|
const RampShader = {
|
|
6
7
|
fragmentShader: /* glsl */ `
|
|
@@ -72,6 +73,9 @@ export enum RampType {
|
|
|
72
73
|
MirroredLinear,
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
type RampTuple2 = [number, number]
|
|
77
|
+
type RampTuple4 = [number, number, number, number]
|
|
78
|
+
|
|
75
79
|
export class RampEffect extends Effect {
|
|
76
80
|
constructor({
|
|
77
81
|
/**
|
|
@@ -83,25 +87,25 @@ export class RampEffect extends Effect {
|
|
|
83
87
|
*
|
|
84
88
|
* Ranges from `[0 - 1]` as `[x, y]`. Default is `[0.5, 0.5]`.
|
|
85
89
|
*/
|
|
86
|
-
rampStart = [0.5, 0.5],
|
|
90
|
+
rampStart = [0.5, 0.5] as RampTuple2,
|
|
87
91
|
/**
|
|
88
92
|
* Ending point of the ramp gradient in normalized coordinates.
|
|
89
93
|
*
|
|
90
94
|
* Ranges from `[0 - 1]` as `[x, y]`. Default is `[1, 1]`
|
|
91
95
|
*/
|
|
92
|
-
rampEnd = [1, 1],
|
|
96
|
+
rampEnd = [1, 1] as RampTuple2,
|
|
93
97
|
/**
|
|
94
98
|
* Color at the starting point of the gradient.
|
|
95
99
|
*
|
|
96
100
|
* Default is black: `[0, 0, 0, 1]`
|
|
97
101
|
*/
|
|
98
|
-
startColor = [0, 0, 0, 1],
|
|
102
|
+
startColor = [0, 0, 0, 1] as RampTuple4,
|
|
99
103
|
/**
|
|
100
104
|
* Color at the ending point of the gradient.
|
|
101
105
|
*
|
|
102
106
|
* Default is white: `[1, 1, 1, 1]`
|
|
103
107
|
*/
|
|
104
|
-
endColor = [1, 1, 1, 1],
|
|
108
|
+
endColor = [1, 1, 1, 1] as RampTuple4,
|
|
105
109
|
/**
|
|
106
110
|
* Bias for the interpolation curve when both bias and gain are 0.5.
|
|
107
111
|
*
|
|
@@ -145,6 +149,91 @@ export class RampEffect extends Effect {
|
|
|
145
149
|
]),
|
|
146
150
|
})
|
|
147
151
|
}
|
|
152
|
+
|
|
153
|
+
private u<T>(name: string): T {
|
|
154
|
+
return this.uniforms.get(name)!.value
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private setU(name: string, value: unknown): void {
|
|
158
|
+
this.uniforms.get(name)!.value = value
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
get rampType(): RampType {
|
|
162
|
+
return this.u('rampType')
|
|
163
|
+
}
|
|
164
|
+
set rampType(value: RampType) {
|
|
165
|
+
this.setU('rampType', value)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
get rampStart(): RampTuple2 {
|
|
169
|
+
return this.u('rampStart')
|
|
170
|
+
}
|
|
171
|
+
set rampStart(value: RampTuple2) {
|
|
172
|
+
this.setU('rampStart', value)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
get rampEnd(): RampTuple2 {
|
|
176
|
+
return this.u('rampEnd')
|
|
177
|
+
}
|
|
178
|
+
set rampEnd(value: RampTuple2) {
|
|
179
|
+
this.setU('rampEnd', value)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
get startColor(): RampTuple4 {
|
|
183
|
+
return this.u('startColor')
|
|
184
|
+
}
|
|
185
|
+
set startColor(value: RampTuple4) {
|
|
186
|
+
this.setU('startColor', value)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
get endColor(): RampTuple4 {
|
|
190
|
+
return this.u('endColor')
|
|
191
|
+
}
|
|
192
|
+
set endColor(value: RampTuple4) {
|
|
193
|
+
this.setU('endColor', value)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
get rampBias(): number {
|
|
197
|
+
return this.u('rampBias')
|
|
198
|
+
}
|
|
199
|
+
set rampBias(value: number) {
|
|
200
|
+
this.setU('rampBias', value)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
get rampGain(): number {
|
|
204
|
+
return this.u('rampGain')
|
|
205
|
+
}
|
|
206
|
+
set rampGain(value: number) {
|
|
207
|
+
this.setU('rampGain', value)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
get rampMask(): boolean {
|
|
211
|
+
return this.u('rampMask')
|
|
212
|
+
}
|
|
213
|
+
set rampMask(value: boolean) {
|
|
214
|
+
this.setU('rampMask', value)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
get rampInvert(): boolean {
|
|
218
|
+
return this.u('rampInvert')
|
|
219
|
+
}
|
|
220
|
+
set rampInvert(value: boolean) {
|
|
221
|
+
this.setU('rampInvert', value)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export type RampProps = {
|
|
226
|
+
blendFunction?: BlendFunction
|
|
227
|
+
rampType?: RampType
|
|
228
|
+
rampStart?: RampTuple2
|
|
229
|
+
rampEnd?: RampTuple2
|
|
230
|
+
startColor?: RampTuple4
|
|
231
|
+
endColor?: RampTuple4
|
|
232
|
+
rampBias?: number
|
|
233
|
+
rampGain?: number
|
|
234
|
+
rampMask?: boolean
|
|
235
|
+
rampInvert?: boolean
|
|
236
|
+
ref?: Ref<RampEffect>
|
|
148
237
|
}
|
|
149
238
|
|
|
150
|
-
export const Ramp = /* @__PURE__ */
|
|
239
|
+
export const Ramp = /* @__PURE__ */ createEffectComponent<typeof RampEffect, RampProps>(RampEffect)
|
package/src/effects/SMAA.tsx
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
import { SMAAEffect } from 'postprocessing'
|
|
2
|
-
import {
|
|
2
|
+
import type { Ref } from 'react'
|
|
3
|
+
import { useMemo } from 'react'
|
|
4
|
+
import { createEffectComponent, type EffectOptions } from '../createEffectComponent'
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
type SMAAOptions = EffectOptions<typeof SMAAEffect>
|
|
7
|
+
|
|
8
|
+
const SMAAImpl = /* @__PURE__ */ createEffectComponent<typeof SMAAEffect, SMAAOptions>(SMAAEffect)
|
|
9
|
+
|
|
10
|
+
export type SMAAProps = SMAAOptions & { opacity?: number; ref?: Ref<SMAAEffect> }
|
|
11
|
+
|
|
12
|
+
// preset/edgeDetectionMode/predicationMode have no live setter in
|
|
13
|
+
// postprocessing - routed through args so they still work as plain props.
|
|
14
|
+
export function SMAA({ preset, edgeDetectionMode, predicationMode, ...liveProps }: SMAAProps) {
|
|
15
|
+
const args = useMemo<[SMAAOptions]>(
|
|
16
|
+
() => [{ preset, edgeDetectionMode, predicationMode }],
|
|
17
|
+
[preset, edgeDetectionMode, predicationMode]
|
|
18
|
+
)
|
|
19
|
+
return <SMAAImpl args={args} {...liveProps} />
|
|
20
|
+
}
|