@takram/three-geospatial-effects 0.0.1-alpha.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.
- package/README.md +15 -0
- package/build/index.cjs +1 -0
- package/build/index.js +25 -0
- package/build/r3f.cjs +748 -0
- package/build/r3f.js +1645 -0
- package/build/shared.cjs +315 -0
- package/build/shared.js +741 -0
- package/package.json +52 -0
- package/src/DepthEffect.ts +81 -0
- package/src/DitheringEffect.ts +28 -0
- package/src/DownsampleThresholdMaterial.ts +83 -0
- package/src/GeometryEffect.ts +79 -0
- package/src/GeometryPass.ts +53 -0
- package/src/LensFlareEffect.ts +185 -0
- package/src/LensFlareFeaturesMaterial.ts +96 -0
- package/src/NormalEffect.ts +135 -0
- package/src/createHaldLookupTexture.ts +20 -0
- package/src/index.ts +7 -0
- package/src/r3f/Depth.tsx +8 -0
- package/src/r3f/Dithering.tsx +5 -0
- package/src/r3f/EffectComposer.tsx +189 -0
- package/src/r3f/Geometry.tsx +45 -0
- package/src/r3f/LensFlare.tsx +30 -0
- package/src/r3f/Normal.tsx +49 -0
- package/src/r3f/SSAO.tsx +123 -0
- package/src/r3f/index.ts +8 -0
- package/src/r3f/types.ts +12 -0
- package/src/setupMaterialsForGeometryPass.ts +131 -0
- package/src/shaders/depthEffect.frag +26 -0
- package/src/shaders/ditheringEffect.frag +7 -0
- package/src/shaders/downsampleThreshold.frag +73 -0
- package/src/shaders/downsampleThreshold.vert +34 -0
- package/src/shaders/geometryEffect.frag +17 -0
- package/src/shaders/lensFlareEffect.frag +12 -0
- package/src/shaders/lensFlareFeatures.frag +73 -0
- package/src/shaders/lensFlareFeatures.vert +10 -0
- package/src/shaders/normalEffect.frag +37 -0
- package/src/shaders/ssr.frag +381 -0
- package/src/shaders/ssr.vert +6 -0
- package/src/shaders/ssrEffect.frag +6 -0
- package/types/DepthEffect.d.ts +23 -0
- package/types/DitheringEffect.d.ts +11 -0
- package/types/DownsampleThresholdMaterial.d.ts +21 -0
- package/types/GeometryEffect.d.ts +20 -0
- package/types/GeometryPass.d.ts +9 -0
- package/types/LensFlareEffect.d.ts +43 -0
- package/types/LensFlareFeaturesMaterial.d.ts +26 -0
- package/types/NormalEffect.d.ts +27 -0
- package/types/createHaldLookupTexture.d.ts +4 -0
- package/types/index.d.ts +7 -0
- package/types/r3f/Depth.d.ts +8 -0
- package/types/r3f/Dithering.d.ts +6 -0
- package/types/r3f/EffectComposer.d.ts +25 -0
- package/types/r3f/Geometry.d.ts +6 -0
- package/types/r3f/LensFlare.d.ts +6 -0
- package/types/r3f/Normal.d.ts +6 -0
- package/types/r3f/SSAO.d.ts +26 -0
- package/types/r3f/index.d.ts +8 -0
- package/types/r3f/types.d.ts +8 -0
- package/types/setupMaterialsForGeometryPass.d.ts +8 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
2
|
+
|
3
|
+
/// <reference types="vite-plugin-glsl/ext" />
|
4
|
+
|
5
|
+
import { BlendFunction, Effect, EffectAttribute } from 'postprocessing'
|
6
|
+
import {
|
7
|
+
Matrix4,
|
8
|
+
Uniform,
|
9
|
+
type Camera,
|
10
|
+
type Texture,
|
11
|
+
type WebGLRenderer,
|
12
|
+
type WebGLRenderTarget
|
13
|
+
} from 'three'
|
14
|
+
|
15
|
+
import {
|
16
|
+
depthShader,
|
17
|
+
packingShader,
|
18
|
+
transformShader
|
19
|
+
} from '@takram/three-geospatial'
|
20
|
+
|
21
|
+
import fragmentShader from './shaders/normalEffect.frag'
|
22
|
+
|
23
|
+
export interface NormalEffectOptions {
|
24
|
+
blendFunction?: BlendFunction
|
25
|
+
normalBuffer?: Texture | null
|
26
|
+
octEncoded?: boolean
|
27
|
+
reconstructFromDepth?: boolean
|
28
|
+
}
|
29
|
+
|
30
|
+
export const normalEffectOptionsDefaults = {
|
31
|
+
blendFunction: BlendFunction.SRC,
|
32
|
+
octEncoded: false,
|
33
|
+
reconstructFromDepth: false
|
34
|
+
} satisfies NormalEffectOptions
|
35
|
+
|
36
|
+
export class NormalEffect extends Effect {
|
37
|
+
constructor(
|
38
|
+
private camera: Camera,
|
39
|
+
options?: NormalEffectOptions
|
40
|
+
) {
|
41
|
+
const {
|
42
|
+
blendFunction,
|
43
|
+
normalBuffer = null,
|
44
|
+
octEncoded,
|
45
|
+
reconstructFromDepth
|
46
|
+
} = {
|
47
|
+
...normalEffectOptionsDefaults,
|
48
|
+
...options
|
49
|
+
}
|
50
|
+
super(
|
51
|
+
'NormalEffect',
|
52
|
+
/* glsl */ `
|
53
|
+
${depthShader}
|
54
|
+
${packingShader}
|
55
|
+
${transformShader}
|
56
|
+
${fragmentShader}
|
57
|
+
`,
|
58
|
+
{
|
59
|
+
blendFunction,
|
60
|
+
attributes: EffectAttribute.DEPTH,
|
61
|
+
uniforms: new Map<string, Uniform>([
|
62
|
+
['normalBuffer', new Uniform(normalBuffer)],
|
63
|
+
['projectionMatrix', new Uniform(new Matrix4())],
|
64
|
+
['inverseProjectionMatrix', new Uniform(new Matrix4())]
|
65
|
+
])
|
66
|
+
}
|
67
|
+
)
|
68
|
+
if (camera != null) {
|
69
|
+
this.mainCamera = camera
|
70
|
+
}
|
71
|
+
this.octEncoded = octEncoded
|
72
|
+
this.reconstructFromDepth = reconstructFromDepth
|
73
|
+
}
|
74
|
+
|
75
|
+
get mainCamera(): Camera {
|
76
|
+
return this.camera
|
77
|
+
}
|
78
|
+
|
79
|
+
override set mainCamera(value: Camera) {
|
80
|
+
this.camera = value
|
81
|
+
}
|
82
|
+
|
83
|
+
update(
|
84
|
+
renderer: WebGLRenderer,
|
85
|
+
inputBuffer: WebGLRenderTarget,
|
86
|
+
deltaTime?: number
|
87
|
+
): void {
|
88
|
+
const uniforms = this.uniforms
|
89
|
+
const projectionMatrix = uniforms.get('projectionMatrix')!
|
90
|
+
const inverseProjectionMatrix = uniforms.get('inverseProjectionMatrix')!
|
91
|
+
const camera = this.camera
|
92
|
+
if (camera != null) {
|
93
|
+
projectionMatrix.value.copy(camera.projectionMatrix)
|
94
|
+
inverseProjectionMatrix.value.copy(camera.projectionMatrixInverse)
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
get normalBuffer(): Texture | null {
|
99
|
+
return this.uniforms.get('normalBuffer')!.value
|
100
|
+
}
|
101
|
+
|
102
|
+
set normalBuffer(value: Texture | null) {
|
103
|
+
this.uniforms.get('normalBuffer')!.value = value
|
104
|
+
}
|
105
|
+
|
106
|
+
get octEncoded(): boolean {
|
107
|
+
return this.defines.has('OCT_ENCODED')
|
108
|
+
}
|
109
|
+
|
110
|
+
set octEncoded(value: boolean) {
|
111
|
+
if (value !== this.octEncoded) {
|
112
|
+
if (value) {
|
113
|
+
this.defines.set('OCT_ENCODED', '1')
|
114
|
+
} else {
|
115
|
+
this.defines.delete('OCT_ENCODED')
|
116
|
+
}
|
117
|
+
this.setChanged()
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
get reconstructFromDepth(): boolean {
|
122
|
+
return this.defines.has('RECONSTRUCT_FROM_DEPTH')
|
123
|
+
}
|
124
|
+
|
125
|
+
set reconstructFromDepth(value: boolean) {
|
126
|
+
if (value !== this.reconstructFromDepth) {
|
127
|
+
if (value) {
|
128
|
+
this.defines.set('RECONSTRUCT_FROM_DEPTH', '1')
|
129
|
+
} else {
|
130
|
+
this.defines.delete('RECONSTRUCT_FROM_DEPTH')
|
131
|
+
}
|
132
|
+
this.setChanged()
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { LookupTexture, RawImageData } from 'postprocessing'
|
2
|
+
import { type Texture } from 'three'
|
3
|
+
|
4
|
+
export function createHaldLookupTexture(texture: Texture): LookupTexture {
|
5
|
+
const { image } = texture
|
6
|
+
const { width, height } = image
|
7
|
+
if (width !== height) {
|
8
|
+
throw new Error('Hald CLUT image must be square.')
|
9
|
+
}
|
10
|
+
const size = Math.cbrt(width * height)
|
11
|
+
if (size % 1 !== 0) {
|
12
|
+
throw new Error('Hald CLUT image must be cubic.')
|
13
|
+
}
|
14
|
+
const { data } = RawImageData.from(image)
|
15
|
+
const lut = new LookupTexture(data, size)
|
16
|
+
lut.name = texture.name
|
17
|
+
lut.type = texture.type
|
18
|
+
texture.colorSpace = lut.colorSpace
|
19
|
+
return lut
|
20
|
+
}
|
package/src/index.ts
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
import { wrapEffect } from '@react-three/postprocessing'
|
2
|
+
import { type ComponentPropsWithoutRef } from 'react'
|
3
|
+
|
4
|
+
import { DepthEffect } from '../DepthEffect'
|
5
|
+
|
6
|
+
export const Depth = wrapEffect(DepthEffect)
|
7
|
+
|
8
|
+
export type DepthProps = ComponentPropsWithoutRef<typeof Depth>
|
@@ -0,0 +1,189 @@
|
|
1
|
+
import { useFrame, useInstanceHandle, useThree } from '@react-three/fiber'
|
2
|
+
import { EffectComposerContext } from '@react-three/postprocessing'
|
3
|
+
import {
|
4
|
+
Effect,
|
5
|
+
EffectAttribute,
|
6
|
+
EffectComposer as EffectComposerImpl,
|
7
|
+
EffectPass,
|
8
|
+
Pass
|
9
|
+
} from 'postprocessing'
|
10
|
+
import {
|
11
|
+
forwardRef,
|
12
|
+
useEffect,
|
13
|
+
useImperativeHandle,
|
14
|
+
useLayoutEffect,
|
15
|
+
useMemo,
|
16
|
+
useRef,
|
17
|
+
type Context,
|
18
|
+
type ReactNode
|
19
|
+
} from 'react'
|
20
|
+
import {
|
21
|
+
HalfFloatType,
|
22
|
+
NoToneMapping,
|
23
|
+
type Camera,
|
24
|
+
type Scene,
|
25
|
+
type TextureDataType
|
26
|
+
} from 'three'
|
27
|
+
|
28
|
+
import { GeometryPass } from '../GeometryPass'
|
29
|
+
|
30
|
+
type InferContextValue<T> = T extends Context<infer U> ? U : never
|
31
|
+
|
32
|
+
export interface EffectComposerContextValue
|
33
|
+
extends InferContextValue<typeof EffectComposerContext> {
|
34
|
+
geometryPass?: GeometryPass
|
35
|
+
}
|
36
|
+
|
37
|
+
export interface EffectComposerProps {
|
38
|
+
enabled?: boolean
|
39
|
+
depthBuffer?: boolean
|
40
|
+
stencilBuffer?: boolean
|
41
|
+
autoClear?: boolean
|
42
|
+
resolutionScale?: number
|
43
|
+
multisampling?: number
|
44
|
+
frameBufferType?: TextureDataType
|
45
|
+
renderPriority?: number
|
46
|
+
camera?: Camera
|
47
|
+
scene?: Scene
|
48
|
+
children?: ReactNode
|
49
|
+
}
|
50
|
+
|
51
|
+
function isConvolution(effect: Effect): boolean {
|
52
|
+
return (
|
53
|
+
(effect.getAttributes() & EffectAttribute.CONVOLUTION) ===
|
54
|
+
EffectAttribute.CONVOLUTION
|
55
|
+
)
|
56
|
+
}
|
57
|
+
|
58
|
+
export const EffectComposer = /*#__PURE__*/ forwardRef<
|
59
|
+
EffectComposerImpl,
|
60
|
+
EffectComposerProps
|
61
|
+
>(function EffectComposer(
|
62
|
+
{
|
63
|
+
children,
|
64
|
+
camera: cameraProp,
|
65
|
+
scene: sceneProp,
|
66
|
+
enabled = true,
|
67
|
+
renderPriority = 1,
|
68
|
+
autoClear = true,
|
69
|
+
resolutionScale,
|
70
|
+
depthBuffer,
|
71
|
+
stencilBuffer = false,
|
72
|
+
multisampling = 8,
|
73
|
+
frameBufferType = HalfFloatType
|
74
|
+
},
|
75
|
+
forwardedRef
|
76
|
+
) {
|
77
|
+
const gl = useThree(({ gl }) => gl)
|
78
|
+
const defaultScene = useThree(({ scene }) => scene)
|
79
|
+
const defaultCamera = useThree(({ camera }) => camera)
|
80
|
+
const scene = sceneProp ?? defaultScene
|
81
|
+
const camera = cameraProp ?? defaultCamera
|
82
|
+
|
83
|
+
const [composer, geometryPass] = useMemo(() => {
|
84
|
+
const composer = new EffectComposerImpl(gl, {
|
85
|
+
depthBuffer,
|
86
|
+
stencilBuffer,
|
87
|
+
multisampling,
|
88
|
+
frameBufferType
|
89
|
+
})
|
90
|
+
const geometryPass = new GeometryPass(composer.inputBuffer, scene, camera)
|
91
|
+
composer.addPass(geometryPass)
|
92
|
+
return [composer, geometryPass]
|
93
|
+
}, [
|
94
|
+
gl,
|
95
|
+
scene,
|
96
|
+
camera,
|
97
|
+
depthBuffer,
|
98
|
+
stencilBuffer,
|
99
|
+
multisampling,
|
100
|
+
frameBufferType
|
101
|
+
])
|
102
|
+
|
103
|
+
const size = useThree(({ size }) => size)
|
104
|
+
useEffect(() => {
|
105
|
+
composer?.setSize(size.width, size.height)
|
106
|
+
}, [composer, size])
|
107
|
+
|
108
|
+
useFrame(
|
109
|
+
(state, delta) => {
|
110
|
+
if (enabled) {
|
111
|
+
const currentAutoClear = gl.autoClear
|
112
|
+
gl.autoClear = autoClear
|
113
|
+
if (stencilBuffer && !autoClear) {
|
114
|
+
gl.clearStencil()
|
115
|
+
}
|
116
|
+
composer.render(delta)
|
117
|
+
gl.autoClear = currentAutoClear
|
118
|
+
}
|
119
|
+
},
|
120
|
+
enabled ? renderPriority : 0
|
121
|
+
)
|
122
|
+
|
123
|
+
const group = useRef(null)
|
124
|
+
const instance = useInstanceHandle(group)
|
125
|
+
useLayoutEffect(() => {
|
126
|
+
const passes: Pass[] = []
|
127
|
+
if (group.current != null && instance.current != null && composer != null) {
|
128
|
+
const children = instance.current.objects as unknown[]
|
129
|
+
for (let i = 0; i < children.length; ++i) {
|
130
|
+
const child = children[i]
|
131
|
+
if (child instanceof Effect) {
|
132
|
+
const effects: Effect[] = [child]
|
133
|
+
if (!isConvolution(child)) {
|
134
|
+
let next: unknown = null
|
135
|
+
while ((next = children[i + 1]) instanceof Effect) {
|
136
|
+
if (isConvolution(next)) {
|
137
|
+
break
|
138
|
+
}
|
139
|
+
effects.push(next)
|
140
|
+
++i
|
141
|
+
}
|
142
|
+
}
|
143
|
+
const pass = new EffectPass(camera, ...effects)
|
144
|
+
passes.push(pass)
|
145
|
+
} else if (child instanceof Pass) {
|
146
|
+
passes.push(child)
|
147
|
+
}
|
148
|
+
}
|
149
|
+
for (const pass of passes) {
|
150
|
+
composer?.addPass(pass)
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
return () => {
|
155
|
+
for (const pass of passes) {
|
156
|
+
composer?.removePass(pass)
|
157
|
+
}
|
158
|
+
}
|
159
|
+
}, [composer, children, camera, instance])
|
160
|
+
|
161
|
+
useEffect(() => {
|
162
|
+
const currentToneMapping = gl.toneMapping
|
163
|
+
gl.toneMapping = NoToneMapping
|
164
|
+
return () => {
|
165
|
+
gl.toneMapping = currentToneMapping
|
166
|
+
}
|
167
|
+
}, [gl])
|
168
|
+
|
169
|
+
const context = useMemo(
|
170
|
+
(): EffectComposerContextValue => ({
|
171
|
+
composer,
|
172
|
+
camera,
|
173
|
+
scene,
|
174
|
+
geometryPass,
|
175
|
+
normalPass: null,
|
176
|
+
downSamplingPass: null,
|
177
|
+
resolutionScale
|
178
|
+
}),
|
179
|
+
[composer, camera, scene, geometryPass, resolutionScale]
|
180
|
+
)
|
181
|
+
|
182
|
+
useImperativeHandle(forwardedRef, () => composer, [composer])
|
183
|
+
|
184
|
+
return (
|
185
|
+
<EffectComposerContext.Provider value={context}>
|
186
|
+
<group ref={group}>{children}</group>
|
187
|
+
</EffectComposerContext.Provider>
|
188
|
+
)
|
189
|
+
})
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import { EffectComposerContext } from '@react-three/postprocessing'
|
2
|
+
import { forwardRef, useContext, useEffect, useMemo } from 'react'
|
3
|
+
|
4
|
+
import {
|
5
|
+
GeometryEffect,
|
6
|
+
geometryEffectOptionsDefaults,
|
7
|
+
type GeometryEffectOptions
|
8
|
+
} from '../GeometryEffect'
|
9
|
+
import { type EffectComposerContextValue } from './EffectComposer'
|
10
|
+
import { type EffectProps } from './types'
|
11
|
+
|
12
|
+
export interface GeometryProps
|
13
|
+
extends EffectProps<typeof GeometryEffect, GeometryEffectOptions> {}
|
14
|
+
|
15
|
+
export const Geometry = /*#__PURE__*/ forwardRef<GeometryEffect, GeometryProps>(
|
16
|
+
function Geometry(props, forwardedRef) {
|
17
|
+
const { blendFunction, ...others } = {
|
18
|
+
...geometryEffectOptionsDefaults,
|
19
|
+
...props
|
20
|
+
}
|
21
|
+
|
22
|
+
const { geometryPass } = useContext(
|
23
|
+
EffectComposerContext
|
24
|
+
) as EffectComposerContextValue
|
25
|
+
|
26
|
+
const effect = useMemo(
|
27
|
+
() => new GeometryEffect({ blendFunction }),
|
28
|
+
[blendFunction]
|
29
|
+
)
|
30
|
+
useEffect(() => {
|
31
|
+
return () => {
|
32
|
+
effect.dispose()
|
33
|
+
}
|
34
|
+
}, [effect])
|
35
|
+
|
36
|
+
return (
|
37
|
+
<primitive
|
38
|
+
ref={forwardedRef}
|
39
|
+
object={effect}
|
40
|
+
geometryBuffer={geometryPass?.geometryTexture}
|
41
|
+
{...others}
|
42
|
+
/>
|
43
|
+
)
|
44
|
+
}
|
45
|
+
)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { forwardRef, useEffect, useMemo } from 'react'
|
2
|
+
|
3
|
+
import {
|
4
|
+
LensFlareEffect,
|
5
|
+
lensFlareEffectOptionsDefaults,
|
6
|
+
type LensFlareEffectOptions
|
7
|
+
} from '../LensFlareEffect'
|
8
|
+
import { type EffectProps } from './types'
|
9
|
+
|
10
|
+
export interface LensFlareProps
|
11
|
+
extends EffectProps<typeof LensFlareEffect, LensFlareEffectOptions> {}
|
12
|
+
|
13
|
+
export const LensFlare = /*#__PURE__*/ forwardRef<
|
14
|
+
LensFlareEffect,
|
15
|
+
LensFlareProps
|
16
|
+
>(function LensFlare(props, forwardedRef) {
|
17
|
+
const { blendFunction, ...others } = {
|
18
|
+
...lensFlareEffectOptionsDefaults,
|
19
|
+
...props
|
20
|
+
}
|
21
|
+
|
22
|
+
const effect = useMemo(() => new LensFlareEffect(), [])
|
23
|
+
useEffect(() => {
|
24
|
+
return () => {
|
25
|
+
effect.dispose()
|
26
|
+
}
|
27
|
+
}, [effect])
|
28
|
+
|
29
|
+
return <primitive ref={forwardedRef} object={effect} {...others} />
|
30
|
+
})
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import { EffectComposerContext } from '@react-three/postprocessing'
|
2
|
+
import { forwardRef, useContext, useEffect, useMemo } from 'react'
|
3
|
+
|
4
|
+
import {
|
5
|
+
NormalEffect,
|
6
|
+
normalEffectOptionsDefaults,
|
7
|
+
type NormalEffectOptions
|
8
|
+
} from '../NormalEffect'
|
9
|
+
import { type EffectComposerContextValue } from './EffectComposer'
|
10
|
+
import { type EffectProps } from './types'
|
11
|
+
|
12
|
+
export interface NormalProps
|
13
|
+
extends EffectProps<typeof NormalEffect, NormalEffectOptions> {}
|
14
|
+
|
15
|
+
export const Normal = /*#__PURE__*/ forwardRef<NormalEffect, NormalProps>(
|
16
|
+
function Normal(props, forwardedRef) {
|
17
|
+
const { blendFunction, ...others } = {
|
18
|
+
...normalEffectOptionsDefaults,
|
19
|
+
...props
|
20
|
+
}
|
21
|
+
|
22
|
+
const { geometryPass, normalPass, camera } = useContext(
|
23
|
+
EffectComposerContext
|
24
|
+
) as EffectComposerContextValue
|
25
|
+
|
26
|
+
const effect = useMemo(
|
27
|
+
() => new NormalEffect(camera, { blendFunction }),
|
28
|
+
[camera, blendFunction]
|
29
|
+
)
|
30
|
+
useEffect(() => {
|
31
|
+
return () => {
|
32
|
+
effect.dispose()
|
33
|
+
}
|
34
|
+
}, [effect])
|
35
|
+
|
36
|
+
return (
|
37
|
+
<primitive
|
38
|
+
ref={forwardedRef}
|
39
|
+
object={effect}
|
40
|
+
mainCamera={camera}
|
41
|
+
normalBuffer={
|
42
|
+
geometryPass?.geometryTexture ?? normalPass?.texture ?? null
|
43
|
+
}
|
44
|
+
{...others}
|
45
|
+
octEncoded={geometryPass?.geometryTexture != null}
|
46
|
+
/>
|
47
|
+
)
|
48
|
+
}
|
49
|
+
)
|
package/src/r3f/SSAO.tsx
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
import { applyProps, useThree } from '@react-three/fiber'
|
2
|
+
import { N8AOPostPass } from 'n8ao'
|
3
|
+
import { type Effect } from 'postprocessing'
|
4
|
+
import { forwardRef, useEffect, useLayoutEffect, useMemo, useRef } from 'react'
|
5
|
+
import { Color } from 'three'
|
6
|
+
|
7
|
+
export interface SSAOProps {
|
8
|
+
aoSamples?: number
|
9
|
+
aoRadius?: number
|
10
|
+
aoTones?: number
|
11
|
+
denoiseSamples?: number
|
12
|
+
denoiseRadius?: number
|
13
|
+
distanceFalloff?: number
|
14
|
+
intensity?: number
|
15
|
+
denoiseIterations?: number
|
16
|
+
renderMode?: number
|
17
|
+
biasOffset?: number
|
18
|
+
biasMultiplier?: number
|
19
|
+
color?: Color
|
20
|
+
gammaCorrection?: boolean
|
21
|
+
logarithmicDepthBuffer?: boolean
|
22
|
+
screenSpaceRadius?: boolean
|
23
|
+
halfRes?: boolean
|
24
|
+
depthAwareUpsampling?: boolean
|
25
|
+
colorMultiply?: boolean
|
26
|
+
transparencyAware?: boolean
|
27
|
+
accumulate?: boolean
|
28
|
+
}
|
29
|
+
|
30
|
+
export const SSAO = /*#__PURE__*/ forwardRef<Effect, SSAOProps>(function SSAO(
|
31
|
+
{
|
32
|
+
aoSamples = 16,
|
33
|
+
aoRadius = 5,
|
34
|
+
aoTones = 0,
|
35
|
+
denoiseSamples = 8,
|
36
|
+
denoiseRadius = 12,
|
37
|
+
distanceFalloff = 1,
|
38
|
+
intensity = 1, // Changed
|
39
|
+
denoiseIterations = 2,
|
40
|
+
renderMode = 0,
|
41
|
+
biasOffset = 0,
|
42
|
+
biasMultiplier = 0,
|
43
|
+
color = new Color(0, 0, 0),
|
44
|
+
gammaCorrection = false, // Changed
|
45
|
+
logarithmicDepthBuffer = false,
|
46
|
+
screenSpaceRadius = false,
|
47
|
+
halfRes = false,
|
48
|
+
depthAwareUpsampling = true,
|
49
|
+
colorMultiply = true,
|
50
|
+
transparencyAware = false,
|
51
|
+
accumulate = false
|
52
|
+
},
|
53
|
+
forwardedRef
|
54
|
+
) {
|
55
|
+
const { camera, scene, size } = useThree()
|
56
|
+
const effect = useMemo(
|
57
|
+
() => new N8AOPostPass(scene, camera, size.width, size.height),
|
58
|
+
// TODO: Change of scene and camera break the pass.
|
59
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
60
|
+
[]
|
61
|
+
)
|
62
|
+
|
63
|
+
const effectRef = useRef(effect)
|
64
|
+
effectRef.current = effect
|
65
|
+
|
66
|
+
useLayoutEffect(() => {
|
67
|
+
effectRef.current.setSize(size.width, size.height)
|
68
|
+
}, [size.width, size.height])
|
69
|
+
|
70
|
+
useLayoutEffect(() => {
|
71
|
+
applyProps(effectRef.current.configuration, {
|
72
|
+
aoSamples,
|
73
|
+
aoRadius,
|
74
|
+
aoTones,
|
75
|
+
denoiseSamples,
|
76
|
+
denoiseRadius,
|
77
|
+
distanceFalloff,
|
78
|
+
intensity,
|
79
|
+
denoiseIterations,
|
80
|
+
renderMode,
|
81
|
+
biasOffset,
|
82
|
+
biasMultiplier,
|
83
|
+
color,
|
84
|
+
gammaCorrection,
|
85
|
+
logarithmicDepthBuffer,
|
86
|
+
screenSpaceRadius,
|
87
|
+
halfRes,
|
88
|
+
depthAwareUpsampling,
|
89
|
+
colorMultiply,
|
90
|
+
transparencyAware,
|
91
|
+
accumulate
|
92
|
+
})
|
93
|
+
}, [
|
94
|
+
aoSamples,
|
95
|
+
aoRadius,
|
96
|
+
aoTones,
|
97
|
+
denoiseSamples,
|
98
|
+
denoiseRadius,
|
99
|
+
distanceFalloff,
|
100
|
+
intensity,
|
101
|
+
denoiseIterations,
|
102
|
+
renderMode,
|
103
|
+
biasOffset,
|
104
|
+
biasMultiplier,
|
105
|
+
color,
|
106
|
+
gammaCorrection,
|
107
|
+
logarithmicDepthBuffer,
|
108
|
+
screenSpaceRadius,
|
109
|
+
halfRes,
|
110
|
+
depthAwareUpsampling,
|
111
|
+
colorMultiply,
|
112
|
+
transparencyAware,
|
113
|
+
accumulate
|
114
|
+
])
|
115
|
+
|
116
|
+
useEffect(() => {
|
117
|
+
return () => {
|
118
|
+
effect.dispose()
|
119
|
+
}
|
120
|
+
}, [effect])
|
121
|
+
|
122
|
+
return <primitive ref={forwardedRef} object={effect} />
|
123
|
+
})
|
package/src/r3f/index.ts
ADDED
package/src/r3f/types.ts
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
import { type Node } from '@react-three/fiber'
|
2
|
+
import { type EffectConstructor } from '@react-three/postprocessing'
|
3
|
+
import { type BlendFunction } from 'postprocessing'
|
4
|
+
|
5
|
+
export type EffectProps<T extends EffectConstructor, Options = {}> = Node<
|
6
|
+
InstanceType<T>,
|
7
|
+
T
|
8
|
+
> &
|
9
|
+
Options & {
|
10
|
+
blendFunction?: BlendFunction
|
11
|
+
opacity?: number
|
12
|
+
}
|