@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
package/package.json
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
{
|
2
|
+
"name": "@takram/three-geospatial-effects",
|
3
|
+
"version": "0.0.1-alpha.0",
|
4
|
+
"type": "module",
|
5
|
+
"exports": {
|
6
|
+
".": {
|
7
|
+
"import": "./build/index.js",
|
8
|
+
"require": "./build/index.cjs",
|
9
|
+
"types": "./types/index.d.ts"
|
10
|
+
},
|
11
|
+
"./r3f": {
|
12
|
+
"import": "./build/r3f.js",
|
13
|
+
"require": "./build/r3f.cjs",
|
14
|
+
"types": "./types/r3f/index.d.ts"
|
15
|
+
}
|
16
|
+
},
|
17
|
+
"main": "./build/index.cjs",
|
18
|
+
"module": "./build/index.js",
|
19
|
+
"types": "./types/index.d.ts",
|
20
|
+
"files": [
|
21
|
+
"build",
|
22
|
+
"src",
|
23
|
+
"types",
|
24
|
+
"package.json",
|
25
|
+
"README.md"
|
26
|
+
],
|
27
|
+
"dependencies": {
|
28
|
+
"@takram/three-geospatial": "0.0.1-alpha.1",
|
29
|
+
"n8ao": "^1.9.3"
|
30
|
+
},
|
31
|
+
"peerDependencies": {
|
32
|
+
"@react-three/fiber": ">=8.17.10",
|
33
|
+
"@react-three/postprocessing": ">=2.16.3",
|
34
|
+
"postprocessing": ">=6.36.4",
|
35
|
+
"react": ">=18.0",
|
36
|
+
"three": ">=0.170.0"
|
37
|
+
},
|
38
|
+
"peerDependenciesMeta": {
|
39
|
+
"@react-three/fiber": {
|
40
|
+
"optional": true
|
41
|
+
},
|
42
|
+
"@react-three/postprocessing": {
|
43
|
+
"optional": true
|
44
|
+
},
|
45
|
+
"react": {
|
46
|
+
"optional": true
|
47
|
+
}
|
48
|
+
},
|
49
|
+
"publishConfig": {
|
50
|
+
"access": "public"
|
51
|
+
}
|
52
|
+
}
|
@@ -0,0 +1,81 @@
|
|
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 { Uniform } from 'three'
|
7
|
+
|
8
|
+
import { depthShader } from '@takram/three-geospatial'
|
9
|
+
|
10
|
+
import fragmentShader from './shaders/depthEffect.frag'
|
11
|
+
|
12
|
+
export interface DepthEffectOptions {
|
13
|
+
blendFunction?: BlendFunction
|
14
|
+
useTurbo?: boolean
|
15
|
+
near?: number
|
16
|
+
far?: number
|
17
|
+
}
|
18
|
+
|
19
|
+
export const depthEffectOptionsDefaults = {
|
20
|
+
blendFunction: BlendFunction.SRC,
|
21
|
+
useTurbo: false,
|
22
|
+
near: 1,
|
23
|
+
far: 1000
|
24
|
+
} satisfies DepthEffectOptions
|
25
|
+
|
26
|
+
export class DepthEffect extends Effect {
|
27
|
+
constructor(options?: DepthEffectOptions) {
|
28
|
+
const { blendFunction, useTurbo, near, far } = {
|
29
|
+
...depthEffectOptionsDefaults,
|
30
|
+
...options
|
31
|
+
}
|
32
|
+
|
33
|
+
super(
|
34
|
+
'DepthEffect',
|
35
|
+
/* glsl */ `
|
36
|
+
${depthShader}
|
37
|
+
${fragmentShader}
|
38
|
+
`,
|
39
|
+
{
|
40
|
+
blendFunction,
|
41
|
+
attributes: EffectAttribute.DEPTH,
|
42
|
+
uniforms: new Map([
|
43
|
+
['near', new Uniform(near)],
|
44
|
+
['far', new Uniform(far)]
|
45
|
+
])
|
46
|
+
}
|
47
|
+
)
|
48
|
+
this.useTurbo = useTurbo
|
49
|
+
}
|
50
|
+
|
51
|
+
get useTurbo(): boolean {
|
52
|
+
return this.defines.has('USE_TURBO')
|
53
|
+
}
|
54
|
+
|
55
|
+
set useTurbo(value: boolean) {
|
56
|
+
if (this.useTurbo !== value) {
|
57
|
+
if (value) {
|
58
|
+
this.defines.set('USE_TURBO', '1')
|
59
|
+
} else {
|
60
|
+
this.defines.delete('USE_TURBO')
|
61
|
+
}
|
62
|
+
this.setChanged()
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
get near(): number {
|
67
|
+
return this.uniforms.get('near')!.value
|
68
|
+
}
|
69
|
+
|
70
|
+
set near(value: number) {
|
71
|
+
this.uniforms.get('near')!.value = value
|
72
|
+
}
|
73
|
+
|
74
|
+
get far(): number {
|
75
|
+
return this.uniforms.get('far')!.value
|
76
|
+
}
|
77
|
+
|
78
|
+
set far(value: number) {
|
79
|
+
this.uniforms.get('far')!.value = value
|
80
|
+
}
|
81
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
2
|
+
|
3
|
+
/// <reference types="vite-plugin-glsl/ext" />
|
4
|
+
|
5
|
+
import { BlendFunction, Effect } from 'postprocessing'
|
6
|
+
|
7
|
+
import fragmentShader from './shaders/ditheringEffect.frag'
|
8
|
+
|
9
|
+
export interface DitheringEffectOptions {
|
10
|
+
blendFunction?: BlendFunction
|
11
|
+
}
|
12
|
+
|
13
|
+
export const ditheringOptionsDefaults = {
|
14
|
+
blendFunction: BlendFunction.NORMAL
|
15
|
+
} satisfies DitheringEffectOptions
|
16
|
+
|
17
|
+
export class DitheringEffect extends Effect {
|
18
|
+
constructor(options?: DitheringEffectOptions) {
|
19
|
+
const { blendFunction } = {
|
20
|
+
...ditheringOptionsDefaults,
|
21
|
+
...options
|
22
|
+
}
|
23
|
+
|
24
|
+
super('DitheringEffect', fragmentShader, {
|
25
|
+
blendFunction
|
26
|
+
})
|
27
|
+
}
|
28
|
+
}
|
@@ -0,0 +1,83 @@
|
|
1
|
+
/// <reference types="vite-plugin-glsl/ext" />
|
2
|
+
|
3
|
+
import {
|
4
|
+
NoBlending,
|
5
|
+
ShaderMaterial,
|
6
|
+
Uniform,
|
7
|
+
Vector2,
|
8
|
+
type ShaderMaterialParameters,
|
9
|
+
type Texture
|
10
|
+
} from 'three'
|
11
|
+
|
12
|
+
import fragmentShader from './shaders/downsampleThreshold.frag'
|
13
|
+
import vertexShader from './shaders/downsampleThreshold.vert'
|
14
|
+
|
15
|
+
export interface DownsampleThresholdMaterialParameters
|
16
|
+
extends ShaderMaterialParameters {
|
17
|
+
inputBuffer?: Texture | null
|
18
|
+
thresholdLevel?: number
|
19
|
+
thresholdRange?: number
|
20
|
+
}
|
21
|
+
|
22
|
+
export const downsampleThresholdMaterialParametersDefaults = {
|
23
|
+
thresholdLevel: 10,
|
24
|
+
thresholdRange: 1
|
25
|
+
} satisfies DownsampleThresholdMaterialParameters
|
26
|
+
|
27
|
+
export class DownsampleThresholdMaterial extends ShaderMaterial {
|
28
|
+
constructor(params?: DownsampleThresholdMaterialParameters) {
|
29
|
+
const {
|
30
|
+
inputBuffer = null,
|
31
|
+
thresholdLevel,
|
32
|
+
thresholdRange,
|
33
|
+
...others
|
34
|
+
} = {
|
35
|
+
...downsampleThresholdMaterialParametersDefaults,
|
36
|
+
...params
|
37
|
+
}
|
38
|
+
super({
|
39
|
+
name: 'DownsampleThresholdMaterial',
|
40
|
+
fragmentShader,
|
41
|
+
vertexShader,
|
42
|
+
uniforms: {
|
43
|
+
inputBuffer: new Uniform(inputBuffer),
|
44
|
+
texelSize: new Uniform(new Vector2()),
|
45
|
+
thresholdLevel: new Uniform(thresholdLevel),
|
46
|
+
thresholdRange: new Uniform(thresholdRange)
|
47
|
+
},
|
48
|
+
blending: NoBlending,
|
49
|
+
toneMapped: false,
|
50
|
+
depthWrite: false,
|
51
|
+
depthTest: false,
|
52
|
+
...others
|
53
|
+
})
|
54
|
+
}
|
55
|
+
|
56
|
+
setSize(width: number, height: number): void {
|
57
|
+
this.uniforms.texelSize.value.set(1 / width, 1 / height)
|
58
|
+
}
|
59
|
+
|
60
|
+
get inputBuffer(): Texture | null {
|
61
|
+
return this.uniforms.inputBuffer.value
|
62
|
+
}
|
63
|
+
|
64
|
+
set inputBuffer(value: Texture | null) {
|
65
|
+
this.uniforms.inputBuffer.value = value
|
66
|
+
}
|
67
|
+
|
68
|
+
get thresholdLevel(): number {
|
69
|
+
return this.uniforms.thresholdLevel.value
|
70
|
+
}
|
71
|
+
|
72
|
+
set thresholdLevel(value: number) {
|
73
|
+
this.uniforms.thresholdLevel.value = value
|
74
|
+
}
|
75
|
+
|
76
|
+
get thresholdRange(): number {
|
77
|
+
return this.uniforms.thresholdRange.value
|
78
|
+
}
|
79
|
+
|
80
|
+
set thresholdRange(value: number) {
|
81
|
+
this.uniforms.thresholdRange.value = value
|
82
|
+
}
|
83
|
+
}
|
@@ -0,0 +1,79 @@
|
|
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 { Uniform, type Texture } from 'three'
|
7
|
+
|
8
|
+
import { packingShader } from '@takram/three-geospatial'
|
9
|
+
|
10
|
+
import fragmentShader from './shaders/geometryEffect.frag'
|
11
|
+
|
12
|
+
export type GeometryEffectOutput = 'normal' | 'pbr'
|
13
|
+
|
14
|
+
export interface GeometryEffectOptions {
|
15
|
+
blendFunction?: BlendFunction
|
16
|
+
geometryBuffer?: Texture | null
|
17
|
+
output?: GeometryEffectOutput
|
18
|
+
}
|
19
|
+
|
20
|
+
export const geometryEffectOptionsDefaults = {
|
21
|
+
blendFunction: BlendFunction.SRC,
|
22
|
+
output: 'normal'
|
23
|
+
} satisfies GeometryEffectOptions
|
24
|
+
|
25
|
+
export class GeometryEffect extends Effect {
|
26
|
+
constructor(options?: GeometryEffectOptions) {
|
27
|
+
const {
|
28
|
+
blendFunction,
|
29
|
+
geometryBuffer = null,
|
30
|
+
output
|
31
|
+
} = {
|
32
|
+
...geometryEffectOptionsDefaults,
|
33
|
+
...options
|
34
|
+
}
|
35
|
+
super(
|
36
|
+
'GeometryEffect',
|
37
|
+
/* glsl */ `
|
38
|
+
${packingShader}
|
39
|
+
${fragmentShader}
|
40
|
+
`,
|
41
|
+
{
|
42
|
+
blendFunction,
|
43
|
+
attributes: EffectAttribute.DEPTH,
|
44
|
+
uniforms: new Map<string, Uniform>([
|
45
|
+
['geometryBuffer', new Uniform(geometryBuffer)]
|
46
|
+
])
|
47
|
+
}
|
48
|
+
)
|
49
|
+
this.output = output
|
50
|
+
}
|
51
|
+
|
52
|
+
get geometryBuffer(): Texture | null {
|
53
|
+
return this.uniforms.get('geometryBuffer')!.value
|
54
|
+
}
|
55
|
+
|
56
|
+
set geometryBuffer(value: Texture | null) {
|
57
|
+
this.uniforms.get('geometryBuffer')!.value = value
|
58
|
+
}
|
59
|
+
|
60
|
+
get output(): GeometryEffectOutput {
|
61
|
+
return this.defines.has('OUTPUT_NORMAL') ? 'normal' : 'pbr'
|
62
|
+
}
|
63
|
+
|
64
|
+
set output(value: GeometryEffectOutput) {
|
65
|
+
if (value !== this.output) {
|
66
|
+
if (value === 'normal') {
|
67
|
+
this.defines.set('OUTPUT_NORMAL', '1')
|
68
|
+
} else {
|
69
|
+
this.defines.delete('OUTPUT_NORMAL')
|
70
|
+
}
|
71
|
+
if (value === 'pbr') {
|
72
|
+
this.defines.set('OUTPUT_PBR', '1')
|
73
|
+
} else {
|
74
|
+
this.defines.delete('OUTPUT_PBR')
|
75
|
+
}
|
76
|
+
this.setChanged()
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import { RenderPass } from 'postprocessing'
|
2
|
+
import {
|
3
|
+
HalfFloatType,
|
4
|
+
type Camera,
|
5
|
+
type Material,
|
6
|
+
type Scene,
|
7
|
+
type Texture,
|
8
|
+
type WebGLRenderer,
|
9
|
+
type WebGLRenderTarget
|
10
|
+
} from 'three'
|
11
|
+
|
12
|
+
import { setupMaterialsForGeometryPass } from './setupMaterialsForGeometryPass'
|
13
|
+
|
14
|
+
export class GeometryPass extends RenderPass {
|
15
|
+
readonly geometryTexture: Texture
|
16
|
+
|
17
|
+
constructor(
|
18
|
+
inputBuffer: WebGLRenderTarget,
|
19
|
+
scene?: Scene,
|
20
|
+
camera?: Camera,
|
21
|
+
overrideMaterial?: Material
|
22
|
+
) {
|
23
|
+
super(scene, camera, overrideMaterial)
|
24
|
+
this.geometryTexture = inputBuffer.texture.clone()
|
25
|
+
this.geometryTexture.isRenderTargetTexture = true
|
26
|
+
// We could use UnsignedByteType but it causes banding in aerial
|
27
|
+
// perspective's lighting.
|
28
|
+
this.geometryTexture.type = HalfFloatType
|
29
|
+
|
30
|
+
setupMaterialsForGeometryPass()
|
31
|
+
}
|
32
|
+
|
33
|
+
override render(
|
34
|
+
renderer: WebGLRenderer,
|
35
|
+
inputBuffer: WebGLRenderTarget | null,
|
36
|
+
outputBuffer: WebGLRenderTarget | null,
|
37
|
+
deltaTime?: number,
|
38
|
+
stencilTest?: boolean
|
39
|
+
): void {
|
40
|
+
if (inputBuffer != null) {
|
41
|
+
inputBuffer.textures[1] = this.geometryTexture
|
42
|
+
}
|
43
|
+
super.render(renderer, inputBuffer, null)
|
44
|
+
if (inputBuffer != null) {
|
45
|
+
inputBuffer.textures.length = 1
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
setSize(width: number, height: number): void {
|
50
|
+
this.geometryTexture.image.width = width
|
51
|
+
this.geometryTexture.image.height = height
|
52
|
+
}
|
53
|
+
}
|
@@ -0,0 +1,185 @@
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
2
|
+
|
3
|
+
/// <reference types="vite-plugin-glsl/ext" />
|
4
|
+
|
5
|
+
import {
|
6
|
+
BlendFunction,
|
7
|
+
Effect,
|
8
|
+
KawaseBlurPass,
|
9
|
+
KernelSize,
|
10
|
+
MipmapBlurPass,
|
11
|
+
Resolution,
|
12
|
+
ShaderPass
|
13
|
+
} from 'postprocessing'
|
14
|
+
import {
|
15
|
+
HalfFloatType,
|
16
|
+
Uniform,
|
17
|
+
WebGLRenderTarget,
|
18
|
+
type Event,
|
19
|
+
type TextureDataType,
|
20
|
+
type WebGLRenderer
|
21
|
+
} from 'three'
|
22
|
+
|
23
|
+
import { DownsampleThresholdMaterial } from './DownsampleThresholdMaterial'
|
24
|
+
import { LensFlareFeaturesMaterial } from './LensFlareFeaturesMaterial'
|
25
|
+
|
26
|
+
import fragmentShader from './shaders/lensFlareEffect.frag'
|
27
|
+
|
28
|
+
export interface LensFlareEffectOptions {
|
29
|
+
blendFunction?: BlendFunction
|
30
|
+
resolutionScale?: number
|
31
|
+
width?: number
|
32
|
+
height?: number
|
33
|
+
resolutionX?: number
|
34
|
+
resolutionY?: number
|
35
|
+
intensity?: number
|
36
|
+
}
|
37
|
+
|
38
|
+
export const lensFlareEffectOptionsDefaults = {
|
39
|
+
blendFunction: BlendFunction.NORMAL,
|
40
|
+
resolutionScale: 0.5,
|
41
|
+
width: Resolution.AUTO_SIZE,
|
42
|
+
height: Resolution.AUTO_SIZE,
|
43
|
+
intensity: 0.005
|
44
|
+
} satisfies LensFlareEffectOptions
|
45
|
+
|
46
|
+
// Reference: https://www.froyok.fr/blog/2021-09-ue4-custom-lens-flare/
|
47
|
+
export class LensFlareEffect extends Effect {
|
48
|
+
readonly resolution: Resolution
|
49
|
+
readonly renderTarget1: WebGLRenderTarget
|
50
|
+
readonly renderTarget2: WebGLRenderTarget
|
51
|
+
|
52
|
+
readonly thresholdMaterial: DownsampleThresholdMaterial
|
53
|
+
readonly thresholdPass: ShaderPass
|
54
|
+
readonly blurPass: MipmapBlurPass
|
55
|
+
readonly preBlurPass: KawaseBlurPass
|
56
|
+
readonly featuresMaterial: LensFlareFeaturesMaterial
|
57
|
+
readonly featuresPass: ShaderPass
|
58
|
+
|
59
|
+
constructor(options?: LensFlareEffectOptions) {
|
60
|
+
const {
|
61
|
+
blendFunction,
|
62
|
+
resolutionScale,
|
63
|
+
width,
|
64
|
+
height,
|
65
|
+
resolutionX = width,
|
66
|
+
resolutionY = height,
|
67
|
+
intensity
|
68
|
+
} = {
|
69
|
+
...lensFlareEffectOptionsDefaults,
|
70
|
+
...options
|
71
|
+
}
|
72
|
+
super('LensFlareEffect', fragmentShader, {
|
73
|
+
blendFunction,
|
74
|
+
uniforms: new Map<string, Uniform>([
|
75
|
+
['bloomBuffer', new Uniform(null)],
|
76
|
+
['featuresBuffer', new Uniform(null)],
|
77
|
+
['intensity', new Uniform(1)]
|
78
|
+
])
|
79
|
+
})
|
80
|
+
|
81
|
+
this.renderTarget1 = new WebGLRenderTarget(1, 1, {
|
82
|
+
depthBuffer: false,
|
83
|
+
stencilBuffer: false,
|
84
|
+
type: HalfFloatType
|
85
|
+
})
|
86
|
+
this.renderTarget1.texture.name = 'LensFlare.Target1'
|
87
|
+
|
88
|
+
this.renderTarget2 = new WebGLRenderTarget(1, 1, {
|
89
|
+
depthBuffer: false,
|
90
|
+
stencilBuffer: false,
|
91
|
+
type: HalfFloatType
|
92
|
+
})
|
93
|
+
this.renderTarget2.texture.name = 'LensFlare.Target2'
|
94
|
+
|
95
|
+
this.thresholdMaterial = new DownsampleThresholdMaterial()
|
96
|
+
this.thresholdPass = new ShaderPass(this.thresholdMaterial)
|
97
|
+
|
98
|
+
this.blurPass = new MipmapBlurPass()
|
99
|
+
this.blurPass.levels = 8
|
100
|
+
|
101
|
+
this.preBlurPass = new KawaseBlurPass({
|
102
|
+
kernelSize: KernelSize.SMALL
|
103
|
+
})
|
104
|
+
|
105
|
+
this.featuresMaterial = new LensFlareFeaturesMaterial()
|
106
|
+
this.featuresPass = new ShaderPass(this.featuresMaterial)
|
107
|
+
|
108
|
+
this.uniforms.get('bloomBuffer')!.value = this.blurPass.texture
|
109
|
+
this.uniforms.get('featuresBuffer')!.value = this.renderTarget1.texture
|
110
|
+
|
111
|
+
this.resolution = new Resolution(
|
112
|
+
this,
|
113
|
+
resolutionX,
|
114
|
+
resolutionY,
|
115
|
+
resolutionScale
|
116
|
+
)
|
117
|
+
this.resolution.addEventListener<keyof Event>(
|
118
|
+
'change' as keyof Event,
|
119
|
+
this.onResolutionChange
|
120
|
+
)
|
121
|
+
|
122
|
+
this.intensity = intensity
|
123
|
+
}
|
124
|
+
|
125
|
+
private readonly onResolutionChange = (): void => {
|
126
|
+
this.setSize(this.resolution.baseWidth, this.resolution.baseHeight)
|
127
|
+
}
|
128
|
+
|
129
|
+
override initialize(
|
130
|
+
renderer: WebGLRenderer,
|
131
|
+
alpha: boolean,
|
132
|
+
frameBufferType: TextureDataType
|
133
|
+
): void {
|
134
|
+
this.thresholdPass.initialize(renderer, alpha, frameBufferType)
|
135
|
+
this.blurPass.initialize(renderer, alpha, frameBufferType)
|
136
|
+
this.preBlurPass.initialize(renderer, alpha, frameBufferType)
|
137
|
+
this.featuresPass.initialize(renderer, alpha, frameBufferType)
|
138
|
+
}
|
139
|
+
|
140
|
+
override update(
|
141
|
+
renderer: WebGLRenderer,
|
142
|
+
inputBuffer: WebGLRenderTarget,
|
143
|
+
deltaTime?: number
|
144
|
+
): void {
|
145
|
+
this.thresholdPass.render(renderer, inputBuffer, this.renderTarget1)
|
146
|
+
this.blurPass.render(renderer, this.renderTarget1, null)
|
147
|
+
this.preBlurPass.render(renderer, this.renderTarget1, this.renderTarget2)
|
148
|
+
this.featuresPass.render(renderer, this.renderTarget2, this.renderTarget1)
|
149
|
+
}
|
150
|
+
|
151
|
+
override setSize(width: number, height: number): void {
|
152
|
+
const resolution = this.resolution
|
153
|
+
resolution.setBaseSize(width, height)
|
154
|
+
this.renderTarget1.setSize(resolution.width, resolution.height)
|
155
|
+
this.renderTarget2.setSize(resolution.width, resolution.height)
|
156
|
+
this.thresholdMaterial.setSize(resolution.width, resolution.height)
|
157
|
+
this.blurPass.setSize(resolution.width, resolution.height)
|
158
|
+
this.preBlurPass.setSize(resolution.width, resolution.height)
|
159
|
+
this.featuresMaterial.setSize(resolution.width, resolution.height)
|
160
|
+
}
|
161
|
+
|
162
|
+
get intensity(): number {
|
163
|
+
return this.uniforms.get('intensity')!.value
|
164
|
+
}
|
165
|
+
|
166
|
+
set intensity(value: number) {
|
167
|
+
this.uniforms.get('intensity')!.value = value
|
168
|
+
}
|
169
|
+
|
170
|
+
get thresholdLevel(): number {
|
171
|
+
return this.thresholdMaterial.thresholdLevel
|
172
|
+
}
|
173
|
+
|
174
|
+
set thresholdLevel(value: number) {
|
175
|
+
this.thresholdMaterial.thresholdLevel = value
|
176
|
+
}
|
177
|
+
|
178
|
+
get thresholdRange(): number {
|
179
|
+
return this.thresholdMaterial.thresholdRange
|
180
|
+
}
|
181
|
+
|
182
|
+
set thresholdRange(value: number) {
|
183
|
+
this.thresholdMaterial.thresholdRange = value
|
184
|
+
}
|
185
|
+
}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
/// <reference types="vite-plugin-glsl/ext" />
|
2
|
+
|
3
|
+
import {
|
4
|
+
NoBlending,
|
5
|
+
ShaderMaterial,
|
6
|
+
Uniform,
|
7
|
+
Vector2,
|
8
|
+
type ShaderMaterialParameters,
|
9
|
+
type Texture
|
10
|
+
} from 'three'
|
11
|
+
|
12
|
+
import fragmentShader from './shaders/lensFlareFeatures.frag'
|
13
|
+
import vertexShader from './shaders/lensFlareFeatures.vert'
|
14
|
+
|
15
|
+
export interface LensFlareFeaturesMaterialParameters
|
16
|
+
extends ShaderMaterialParameters {
|
17
|
+
inputBuffer?: Texture | null
|
18
|
+
lensColorTexture?: Texture | null
|
19
|
+
ghostAmount?: number
|
20
|
+
haloAmount?: number
|
21
|
+
chromaticAberration?: number
|
22
|
+
}
|
23
|
+
|
24
|
+
export const lensFlareFeaturesMaterialParametersDefaults = {
|
25
|
+
ghostAmount: 0.001,
|
26
|
+
haloAmount: 0.001,
|
27
|
+
chromaticAberration: 10
|
28
|
+
} satisfies LensFlareFeaturesMaterialParameters
|
29
|
+
|
30
|
+
export class LensFlareFeaturesMaterial extends ShaderMaterial {
|
31
|
+
constructor(params?: LensFlareFeaturesMaterialParameters) {
|
32
|
+
const {
|
33
|
+
inputBuffer = null,
|
34
|
+
ghostAmount,
|
35
|
+
haloAmount,
|
36
|
+
chromaticAberration
|
37
|
+
} = {
|
38
|
+
...lensFlareFeaturesMaterialParametersDefaults,
|
39
|
+
...params
|
40
|
+
}
|
41
|
+
super({
|
42
|
+
name: 'LensFlareFeaturesMaterial',
|
43
|
+
fragmentShader,
|
44
|
+
vertexShader,
|
45
|
+
uniforms: {
|
46
|
+
inputBuffer: new Uniform(inputBuffer),
|
47
|
+
texelSize: new Uniform(new Vector2()),
|
48
|
+
ghostAmount: new Uniform(ghostAmount),
|
49
|
+
haloAmount: new Uniform(haloAmount),
|
50
|
+
chromaticAberration: new Uniform(chromaticAberration)
|
51
|
+
},
|
52
|
+
blending: NoBlending,
|
53
|
+
toneMapped: false,
|
54
|
+
depthWrite: false,
|
55
|
+
depthTest: false
|
56
|
+
})
|
57
|
+
}
|
58
|
+
|
59
|
+
setSize(width: number, height: number): void {
|
60
|
+
const texelSize = this.uniforms.texelSize
|
61
|
+
texelSize.value.x = 1 / width
|
62
|
+
texelSize.value.y = 1 / height
|
63
|
+
}
|
64
|
+
|
65
|
+
get inputBuffer(): Texture | null {
|
66
|
+
return this.uniforms.inputBuffer.value
|
67
|
+
}
|
68
|
+
|
69
|
+
set inputBuffer(value: Texture | null) {
|
70
|
+
this.uniforms.inputBuffer.value = value
|
71
|
+
}
|
72
|
+
|
73
|
+
get ghostAmount(): number {
|
74
|
+
return this.uniforms.ghostAmount.value
|
75
|
+
}
|
76
|
+
|
77
|
+
set ghostAmount(value: number) {
|
78
|
+
this.uniforms.ghostAmount.value = value
|
79
|
+
}
|
80
|
+
|
81
|
+
get haloAmount(): number {
|
82
|
+
return this.uniforms.haloAmount.value
|
83
|
+
}
|
84
|
+
|
85
|
+
set haloAmount(value: number) {
|
86
|
+
this.uniforms.haloAmount.value = value
|
87
|
+
}
|
88
|
+
|
89
|
+
get chromaticAberration(): number {
|
90
|
+
return this.uniforms.chromaticAberration.value
|
91
|
+
}
|
92
|
+
|
93
|
+
set chromaticAberration(value: number) {
|
94
|
+
this.uniforms.chromaticAberration.value = value
|
95
|
+
}
|
96
|
+
}
|