@takram/three-geospatial 0.3.0 → 0.5.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/CHANGELOG.md +28 -1
- package/build/index.cjs +1 -1
- package/build/index.cjs.map +1 -1
- package/build/index.js +1109 -2108
- package/build/index.js.map +1 -1
- package/build/r3f.cjs +1 -1
- package/build/r3f.cjs.map +1 -1
- package/build/r3f.js +1 -1
- package/build/r3f.js.map +1 -1
- package/build/shaders.cjs +4 -4
- package/build/shaders.js +7 -7
- package/build/shared.cjs +1 -1
- package/build/shared.cjs.map +1 -1
- package/build/shared.js +8 -206
- package/build/shared.js.map +1 -1
- package/build/shared2.cjs +2 -0
- package/build/shared2.cjs.map +1 -0
- package/build/shared2.js +224 -0
- package/build/shared2.js.map +1 -0
- package/build/shared3.cjs +2 -0
- package/build/shared3.cjs.map +1 -0
- package/build/shared3.js +13 -0
- package/build/shared3.js.map +1 -0
- package/build/webgpu.cjs +2 -0
- package/build/webgpu.cjs.map +1 -0
- package/build/webgpu.js +1336 -0
- package/build/webgpu.js.map +1 -0
- package/package.json +14 -9
- package/src/Ellipsoid.ts +25 -0
- package/src/EllipsoidGeometry.ts +2 -2
- package/src/QuadGeometry.ts +14 -0
- package/src/bufferGeometry.ts +1 -1
- package/src/capabilities.ts +12 -3
- package/src/decorators.ts +11 -6
- package/src/index.ts +2 -2
- package/src/shaders/depth.glsl +3 -3
- package/src/types.ts +2 -0
- package/src/unrollLoops.ts +1 -1
- package/src/webgpu/DownsampleThresholdNode.ts +40 -0
- package/src/webgpu/DualMipmapFilterNode.ts +130 -0
- package/src/webgpu/FilterNode.ts +93 -0
- package/src/webgpu/FnLayout.ts +86 -0
- package/src/webgpu/FnVar.ts +26 -0
- package/src/webgpu/GaussianBlurNode.ts +129 -0
- package/src/webgpu/HighpVelocityNode.ts +115 -0
- package/src/webgpu/KawaseBlurNode.ts +76 -0
- package/src/webgpu/LensFlareNode.ts +128 -0
- package/src/webgpu/LensGhostNode.ts +62 -0
- package/src/webgpu/LensGlareNode.ts +318 -0
- package/src/webgpu/LensHaloNode.ts +99 -0
- package/src/webgpu/MipmapBlurNode.ts +113 -0
- package/src/webgpu/MipmapSurfaceBlurNode.ts +140 -0
- package/src/webgpu/OutputTexture3DNode.ts +34 -0
- package/src/webgpu/OutputTextureNode.ts +33 -0
- package/src/webgpu/RTTextureNode.ts +132 -0
- package/src/webgpu/SeparableFilterNode.ts +98 -0
- package/src/webgpu/SingleFilterNode.ts +80 -0
- package/src/webgpu/TemporalAntialiasNode.ts +571 -0
- package/src/webgpu/accessors.ts +67 -0
- package/src/webgpu/debug.ts +86 -0
- package/src/webgpu/generators.ts +40 -0
- package/src/webgpu/index.ts +21 -0
- package/src/webgpu/internals.ts +37 -0
- package/src/webgpu/math.ts +81 -0
- package/src/webgpu/node.ts +100 -0
- package/src/webgpu/sampling.ts +103 -0
- package/src/webgpu/transformations.ts +106 -0
- package/src/webgpu/utils.ts +13 -0
- package/types/Ellipsoid.d.ts +4 -0
- package/types/QuadGeometry.d.ts +4 -0
- package/types/bufferGeometry.d.ts +2 -2
- package/types/capabilities.d.ts +2 -1
- package/types/decorators.d.ts +8 -5
- package/types/index.d.ts +2 -2
- package/types/types.d.ts +1 -0
- package/types/webgpu/DownsampleThresholdNode.d.ts +11 -0
- package/types/webgpu/DualMipmapFilterNode.d.ts +21 -0
- package/types/webgpu/FilterNode.d.ts +17 -0
- package/types/webgpu/FnLayout.d.ts +21 -0
- package/types/webgpu/FnVar.d.ts +6 -0
- package/types/webgpu/GaussianBlurNode.d.ts +10 -0
- package/types/webgpu/HighpVelocityNode.d.ts +18 -0
- package/types/webgpu/KawaseBlurNode.d.ts +10 -0
- package/types/webgpu/LensFlareNode.d.ts +25 -0
- package/types/webgpu/LensGhostNode.d.ts +8 -0
- package/types/webgpu/LensGlareNode.d.ts +32 -0
- package/types/webgpu/LensHaloNode.d.ts +11 -0
- package/types/webgpu/MipmapBlurNode.d.ts +12 -0
- package/types/webgpu/MipmapSurfaceBlurNode.d.ts +11 -0
- package/types/webgpu/OutputTexture3DNode.d.ts +11 -0
- package/types/webgpu/OutputTextureNode.d.ts +11 -0
- package/types/webgpu/RTTextureNode.d.ts +23 -0
- package/types/webgpu/SeparableFilterNode.d.ts +20 -0
- package/types/webgpu/SingleFilterNode.d.ts +17 -0
- package/types/webgpu/TemporalAntialiasNode.d.ts +56 -0
- package/types/webgpu/accessors.d.ts +10 -0
- package/types/webgpu/debug.d.ts +7 -0
- package/types/webgpu/generators.d.ts +4 -0
- package/types/webgpu/index.d.ts +21 -0
- package/types/webgpu/internals.d.ts +3 -0
- package/types/webgpu/math.d.ts +4 -0
- package/types/webgpu/node.d.ts +33 -0
- package/types/webgpu/sampling.d.ts +2 -0
- package/types/webgpu/transformations.d.ts +12 -0
- package/types/webgpu/utils.d.ts +3 -0
- package/src/assertions.ts +0 -1
- package/types/assertions.d.ts +0 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { add, Fn, mix, nodeObject, uniform, uv, vec2, vec4 } from 'three/tsl'
|
|
2
|
+
import type { NodeBuilder, TextureNode } from 'three/webgpu'
|
|
3
|
+
import invariant from 'tiny-invariant'
|
|
4
|
+
|
|
5
|
+
import { DualMipmapFilterNode } from './DualMipmapFilterNode'
|
|
6
|
+
import type { Node, NodeObject } from './node'
|
|
7
|
+
|
|
8
|
+
const clampToBorder = (uv: NodeObject<'vec2'>): NodeObject<'float'> => {
|
|
9
|
+
return uv.greaterThanEqual(0).all().and(uv.lessThanEqual(1).all()).toFloat()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Implementation of Lena Piquet's bloom filter.
|
|
13
|
+
// Reference: https://www.froyok.fr/blog/2021-12-ue4-custom-bloom
|
|
14
|
+
export class MipmapSurfaceBlurNode extends DualMipmapFilterNode {
|
|
15
|
+
static override get type(): string {
|
|
16
|
+
return 'MipmapSurfaceBlurNode'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
blendAmount = uniform(0.85)
|
|
20
|
+
|
|
21
|
+
constructor(inputNode?: TextureNode | null, levels = 4) {
|
|
22
|
+
super(inputNode, levels)
|
|
23
|
+
this.resolutionScale = 0.5
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
protected override setupDownsampleNode(builder: NodeBuilder): Node {
|
|
27
|
+
const { inputNode, inputTexelSize } = this
|
|
28
|
+
invariant(inputNode != null)
|
|
29
|
+
|
|
30
|
+
return Fn(() => {
|
|
31
|
+
const center = uv()
|
|
32
|
+
const offset1 = vec4(1, 1, -1, -1)
|
|
33
|
+
.mul(inputTexelSize.xyxy)
|
|
34
|
+
.add(center.xyxy)
|
|
35
|
+
const offset2 = vec4(2, 2, -2, -2)
|
|
36
|
+
.mul(inputTexelSize.xyxy)
|
|
37
|
+
.add(center.xyxy)
|
|
38
|
+
const uv01 = offset1.zy.toVertexStage() // -1, 1
|
|
39
|
+
const uv02 = offset1.xy.toVertexStage() // 1, 1
|
|
40
|
+
const uv03 = offset1.zw.toVertexStage() // -1, -1
|
|
41
|
+
const uv04 = offset1.xw.toVertexStage() // 1, -1
|
|
42
|
+
const uv05 = offset2.zy.toVertexStage() // -2, 2
|
|
43
|
+
const uv06 = offset2.xy.toVertexStage() // 2, 2
|
|
44
|
+
const uv07 = offset2.zw.toVertexStage() // -2, -2
|
|
45
|
+
const uv08 = offset2.xw.toVertexStage() // 2, -2
|
|
46
|
+
const uv09 = vec2(center.x, offset2.y).toVertexStage() // 0, 2
|
|
47
|
+
const uv10 = vec2(offset2.z, center.y).toVertexStage() // -2, 0
|
|
48
|
+
const uv11 = vec2(offset2.x, center.y).toVertexStage() // 2, 0
|
|
49
|
+
const uv12 = vec2(center.x, offset2.w).toVertexStage() // 0, -2
|
|
50
|
+
|
|
51
|
+
const innerWeight = 1 / 4 / 2
|
|
52
|
+
const outerWeight = 1 / 9 / 2
|
|
53
|
+
|
|
54
|
+
const output = inputNode.sample(center).mul(outerWeight)
|
|
55
|
+
|
|
56
|
+
let weight: NodeObject
|
|
57
|
+
weight = vec4(
|
|
58
|
+
clampToBorder(uv01),
|
|
59
|
+
clampToBorder(uv02),
|
|
60
|
+
clampToBorder(uv03),
|
|
61
|
+
clampToBorder(uv04)
|
|
62
|
+
).mul(innerWeight)
|
|
63
|
+
|
|
64
|
+
output.addAssign(
|
|
65
|
+
inputNode.sample(uv01).mul(weight.x),
|
|
66
|
+
inputNode.sample(uv02).mul(weight.y),
|
|
67
|
+
inputNode.sample(uv03).mul(weight.z),
|
|
68
|
+
inputNode.sample(uv04).mul(weight.w)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
weight = vec4(
|
|
72
|
+
clampToBorder(uv05),
|
|
73
|
+
clampToBorder(uv06),
|
|
74
|
+
clampToBorder(uv07),
|
|
75
|
+
clampToBorder(uv08)
|
|
76
|
+
).mul(outerWeight)
|
|
77
|
+
|
|
78
|
+
output.addAssign(
|
|
79
|
+
inputNode.sample(uv05).mul(weight.x),
|
|
80
|
+
inputNode.sample(uv06).mul(weight.y),
|
|
81
|
+
inputNode.sample(uv07).mul(weight.z),
|
|
82
|
+
inputNode.sample(uv08).mul(weight.w)
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
weight = vec4(
|
|
86
|
+
clampToBorder(uv09),
|
|
87
|
+
clampToBorder(uv10),
|
|
88
|
+
clampToBorder(uv11),
|
|
89
|
+
clampToBorder(uv12)
|
|
90
|
+
).mul(outerWeight)
|
|
91
|
+
|
|
92
|
+
output.addAssign(
|
|
93
|
+
inputNode.sample(uv09).mul(weight.x),
|
|
94
|
+
inputNode.sample(uv10).mul(weight.y),
|
|
95
|
+
inputNode.sample(uv11).mul(weight.z),
|
|
96
|
+
inputNode.sample(uv12).mul(weight.w)
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
return output
|
|
100
|
+
})()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
protected override setupUpsampleNode(builder: NodeBuilder): Node {
|
|
104
|
+
const { inputNode, inputTexelSize, downsampleNode } = this
|
|
105
|
+
invariant(inputNode != null)
|
|
106
|
+
|
|
107
|
+
const center = uv()
|
|
108
|
+
const offset = vec4(1, 1, -1, -1).mul(inputTexelSize.xyxy).add(center.xyxy)
|
|
109
|
+
const uv1 = vec2(center.x, offset.y).toVertexStage() // 0, 1
|
|
110
|
+
const uv2 = vec2(offset.z, center.y).toVertexStage() // -1, 0
|
|
111
|
+
const uv3 = vec2(offset.x, center.y).toVertexStage() // 1, 0
|
|
112
|
+
const uv4 = vec2(center.x, offset.w).toVertexStage() // 0, -1
|
|
113
|
+
const uv5 = offset.zy.toVertexStage() // -1, 1
|
|
114
|
+
const uv6 = offset.xy.toVertexStage() // 1, 1
|
|
115
|
+
const uv7 = offset.zw.toVertexStage() // -1, -1
|
|
116
|
+
const uv8 = offset.xw.toVertexStage() // 1, -1
|
|
117
|
+
|
|
118
|
+
const output = add(
|
|
119
|
+
inputNode.sample(center).mul(1 / 4),
|
|
120
|
+
add(
|
|
121
|
+
inputNode.sample(uv1),
|
|
122
|
+
inputNode.sample(uv2),
|
|
123
|
+
inputNode.sample(uv3),
|
|
124
|
+
inputNode.sample(uv4)
|
|
125
|
+
).mul(1 / 8),
|
|
126
|
+
add(
|
|
127
|
+
inputNode.sample(uv5),
|
|
128
|
+
inputNode.sample(uv6),
|
|
129
|
+
inputNode.sample(uv7),
|
|
130
|
+
inputNode.sample(uv8)
|
|
131
|
+
).mul(1 / 16)
|
|
132
|
+
)
|
|
133
|
+
return mix(downsampleNode.sample(center), output, this.blendAmount)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const mipmapSurfaceBlur = (
|
|
138
|
+
...args: ConstructorParameters<typeof MipmapSurfaceBlurNode>
|
|
139
|
+
): NodeObject<MipmapSurfaceBlurNode> =>
|
|
140
|
+
nodeObject(new MipmapSurfaceBlurNode(...args))
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Texture } from 'three'
|
|
2
|
+
import { nodeObject } from 'three/tsl'
|
|
3
|
+
import { Texture3DNode, type Node, type NodeBuilder } from 'three/webgpu'
|
|
4
|
+
|
|
5
|
+
import type { NodeObject } from './node'
|
|
6
|
+
|
|
7
|
+
export class OutputTexture3DNode extends Texture3DNode {
|
|
8
|
+
static override get type(): string {
|
|
9
|
+
return 'OutputTexture3DNode'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
owner: Node
|
|
13
|
+
|
|
14
|
+
constructor(owner: Node, texture: Texture) {
|
|
15
|
+
super(texture)
|
|
16
|
+
this.owner = owner
|
|
17
|
+
this.setUpdateMatrix(false)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override setup(builder: NodeBuilder): unknown {
|
|
21
|
+
this.owner.build(builder)
|
|
22
|
+
return super.setup(builder)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
override clone(): this {
|
|
26
|
+
// @ts-expect-error Ignore
|
|
27
|
+
return new this.constructor(this.owner, this.value)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const outputTexture3D = (
|
|
32
|
+
...args: ConstructorParameters<typeof OutputTexture3DNode>
|
|
33
|
+
): NodeObject<OutputTexture3DNode> =>
|
|
34
|
+
nodeObject(new OutputTexture3DNode(...args))
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Texture } from 'three'
|
|
2
|
+
import { nodeObject } from 'three/tsl'
|
|
3
|
+
import { TextureNode, type Node, type NodeBuilder } from 'three/webgpu'
|
|
4
|
+
|
|
5
|
+
import type { NodeObject } from './node'
|
|
6
|
+
|
|
7
|
+
export class OutputTextureNode extends TextureNode {
|
|
8
|
+
static override get type(): string {
|
|
9
|
+
return 'OutputTextureNode'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
owner: Node
|
|
13
|
+
|
|
14
|
+
constructor(owner: Node, texture: Texture) {
|
|
15
|
+
super(texture)
|
|
16
|
+
this.owner = owner
|
|
17
|
+
this.setUpdateMatrix(false)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override setup(builder: NodeBuilder): unknown {
|
|
21
|
+
this.owner.build(builder)
|
|
22
|
+
return super.setup(builder)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
override clone(): this {
|
|
26
|
+
// @ts-expect-error Ignore
|
|
27
|
+
return new this.constructor(this.owner, this.value)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const outputTexture = (
|
|
32
|
+
...args: ConstructorParameters<typeof OutputTextureNode>
|
|
33
|
+
): NodeObject<OutputTextureNode> => nodeObject(new OutputTextureNode(...args))
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { nodeObject, uv } from 'three/tsl'
|
|
2
|
+
import {
|
|
3
|
+
HalfFloatType,
|
|
4
|
+
LinearFilter,
|
|
5
|
+
NodeMaterial,
|
|
6
|
+
NodeUpdateType,
|
|
7
|
+
QuadMesh,
|
|
8
|
+
RendererUtils,
|
|
9
|
+
RenderTarget,
|
|
10
|
+
RGBAFormat,
|
|
11
|
+
TextureNode,
|
|
12
|
+
Vector2,
|
|
13
|
+
type Node,
|
|
14
|
+
type NodeBuilder,
|
|
15
|
+
type NodeFrame
|
|
16
|
+
} from 'three/webgpu'
|
|
17
|
+
|
|
18
|
+
import type { NodeObject } from './node'
|
|
19
|
+
|
|
20
|
+
const { resetRendererState, restoreRendererState } = RendererUtils
|
|
21
|
+
|
|
22
|
+
function createRenderTarget(): RenderTarget {
|
|
23
|
+
const renderTarget = new RenderTarget(1, 1, {
|
|
24
|
+
depthBuffer: false,
|
|
25
|
+
type: HalfFloatType,
|
|
26
|
+
format: RGBAFormat
|
|
27
|
+
})
|
|
28
|
+
const texture = renderTarget.texture
|
|
29
|
+
texture.minFilter = LinearFilter
|
|
30
|
+
texture.magFilter = LinearFilter
|
|
31
|
+
texture.generateMipmaps = false
|
|
32
|
+
return renderTarget
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const sizeScratch = /*#__PURE__*/ new Vector2()
|
|
36
|
+
|
|
37
|
+
// Similar to RTTNode, which is a bit finicky to handle.
|
|
38
|
+
export class RTTextureNode extends TextureNode {
|
|
39
|
+
static override get type(): string {
|
|
40
|
+
return 'RTTextureNode'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
node: Node
|
|
44
|
+
resolutionScale = 1
|
|
45
|
+
|
|
46
|
+
private readonly renderTarget: RenderTarget
|
|
47
|
+
private readonly material = new NodeMaterial()
|
|
48
|
+
private readonly mesh = new QuadMesh(this.material)
|
|
49
|
+
private rendererState?: RendererUtils.RendererState
|
|
50
|
+
|
|
51
|
+
constructor(node: Node, uvNode?: Node) {
|
|
52
|
+
const renderTarget = createRenderTarget()
|
|
53
|
+
super(renderTarget.texture, uvNode != null ? nodeObject(uvNode) : uv())
|
|
54
|
+
this.node = node
|
|
55
|
+
this.renderTarget = renderTarget
|
|
56
|
+
this.updateBeforeType = NodeUpdateType.FRAME
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setSize(width: number, height: number): this {
|
|
60
|
+
const { resolutionScale } = this
|
|
61
|
+
const w = Math.max(Math.round(width * resolutionScale), 1)
|
|
62
|
+
const h = Math.max(Math.round(height * resolutionScale), 1)
|
|
63
|
+
this.renderTarget.setSize(w, h)
|
|
64
|
+
return this
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
override updateBefore({ renderer }: NodeFrame): void {
|
|
68
|
+
if (renderer == null) {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const size = renderer.getDrawingBufferSize(sizeScratch)
|
|
73
|
+
this.setSize(size.x, size.y)
|
|
74
|
+
|
|
75
|
+
this.rendererState = resetRendererState(renderer, this.rendererState)
|
|
76
|
+
|
|
77
|
+
renderer.setRenderTarget(this.renderTarget)
|
|
78
|
+
this.mesh.render(renderer)
|
|
79
|
+
|
|
80
|
+
restoreRendererState(renderer, this.rendererState)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
override setup(builder: NodeBuilder): unknown {
|
|
84
|
+
const { material } = this
|
|
85
|
+
// I don't fully understand why, but updates on "node" doesn't propagate
|
|
86
|
+
// unless giving the builder context.
|
|
87
|
+
material.fragmentNode = nodeObject(this.node).context(builder.getContext())
|
|
88
|
+
material.needsUpdate = true
|
|
89
|
+
return super.setup(builder)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
override dispose(): void {
|
|
93
|
+
this.renderTarget.dispose()
|
|
94
|
+
this.material.dispose()
|
|
95
|
+
this.mesh.geometry.dispose()
|
|
96
|
+
super.dispose()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// @ts-expect-error Ignore
|
|
100
|
+
override clone(): TextureNode {
|
|
101
|
+
const result = new TextureNode(this.value, this.uvNode, this.levelNode)
|
|
102
|
+
result.sampler = this.sampler
|
|
103
|
+
result.referenceNode = this
|
|
104
|
+
return result
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export const rtTexture = (
|
|
109
|
+
...args: ConstructorParameters<typeof RTTextureNode>
|
|
110
|
+
): NodeObject<RTTextureNode> => nodeObject(new RTTextureNode(...args))
|
|
111
|
+
|
|
112
|
+
export const convertToTexture = (
|
|
113
|
+
node: Node & {
|
|
114
|
+
isTextureNode?: boolean
|
|
115
|
+
isSampleNode?: boolean
|
|
116
|
+
getTextureNode?: () => TextureNode
|
|
117
|
+
},
|
|
118
|
+
name?: string
|
|
119
|
+
): NodeObject<TextureNode> => {
|
|
120
|
+
let textureNode: TextureNode
|
|
121
|
+
if (node.isTextureNode === true || node.isSampleNode === true) {
|
|
122
|
+
textureNode = node as TextureNode
|
|
123
|
+
} else if (node.getTextureNode != null) {
|
|
124
|
+
textureNode = node.getTextureNode()
|
|
125
|
+
} else {
|
|
126
|
+
textureNode = new RTTextureNode(node)
|
|
127
|
+
if (name != null) {
|
|
128
|
+
textureNode.value.name = name
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return nodeObject(textureNode)
|
|
132
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Vector2, type RenderTarget } from 'three'
|
|
2
|
+
import { uniform } from 'three/tsl'
|
|
3
|
+
import {
|
|
4
|
+
NodeMaterial,
|
|
5
|
+
QuadMesh,
|
|
6
|
+
RendererUtils,
|
|
7
|
+
type NodeBuilder,
|
|
8
|
+
type NodeFrame,
|
|
9
|
+
type TextureNode
|
|
10
|
+
} from 'three/webgpu'
|
|
11
|
+
import invariant from 'tiny-invariant'
|
|
12
|
+
|
|
13
|
+
import { FilterNode } from './FilterNode'
|
|
14
|
+
import type { Node } from './node'
|
|
15
|
+
|
|
16
|
+
const { resetRendererState, restoreRendererState } = RendererUtils
|
|
17
|
+
|
|
18
|
+
export abstract class SeparableFilterNode extends FilterNode {
|
|
19
|
+
iterations = 1
|
|
20
|
+
|
|
21
|
+
private readonly horizontalRT: RenderTarget
|
|
22
|
+
private readonly verticalRT: RenderTarget
|
|
23
|
+
private readonly material = new NodeMaterial()
|
|
24
|
+
private readonly mesh = new QuadMesh(this.material)
|
|
25
|
+
private rendererState?: RendererUtils.RendererState
|
|
26
|
+
|
|
27
|
+
protected readonly inputTexelSize = uniform(new Vector2())
|
|
28
|
+
protected readonly direction = uniform(new Vector2())
|
|
29
|
+
|
|
30
|
+
constructor(inputNode?: TextureNode | null) {
|
|
31
|
+
super(inputNode)
|
|
32
|
+
|
|
33
|
+
this.horizontalRT = this.createRenderTarget('Horizontal')
|
|
34
|
+
this.verticalRT = this.createRenderTarget('Vertical')
|
|
35
|
+
this.outputTexture = this.verticalRT.texture
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setSize(width: number, height: number): this {
|
|
39
|
+
const { resolutionScale } = this
|
|
40
|
+
const w = Math.max(Math.round(width * resolutionScale), 1)
|
|
41
|
+
const h = Math.max(Math.round(height * resolutionScale), 1)
|
|
42
|
+
this.horizontalRT.setSize(w, h)
|
|
43
|
+
this.verticalRT.setSize(w, h)
|
|
44
|
+
return this
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override updateBefore({ renderer }: NodeFrame): void {
|
|
48
|
+
if (renderer == null) {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const { horizontalRT, verticalRT, mesh, inputNode, direction } = this
|
|
53
|
+
invariant(inputNode != null)
|
|
54
|
+
|
|
55
|
+
const { width, height } = inputNode.value
|
|
56
|
+
this.setSize(width, height)
|
|
57
|
+
this.inputTexelSize.value.set(1 / width, 1 / height)
|
|
58
|
+
|
|
59
|
+
const originalTexture = inputNode.value
|
|
60
|
+
this.rendererState = resetRendererState(renderer, this.rendererState)
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < this.iterations; ++i) {
|
|
63
|
+
direction.value.set(1, 0)
|
|
64
|
+
renderer.setRenderTarget(horizontalRT)
|
|
65
|
+
mesh.render(renderer)
|
|
66
|
+
inputNode.value = horizontalRT.texture
|
|
67
|
+
|
|
68
|
+
direction.value.set(0, 1)
|
|
69
|
+
renderer.setRenderTarget(verticalRT)
|
|
70
|
+
mesh.render(renderer)
|
|
71
|
+
inputNode.value = verticalRT.texture
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
restoreRendererState(renderer, this.rendererState)
|
|
75
|
+
inputNode.value = originalTexture
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
protected abstract setupOutputNode(builder: NodeBuilder): Node
|
|
79
|
+
|
|
80
|
+
override setup(builder: NodeBuilder): unknown {
|
|
81
|
+
const { inputNode } = this
|
|
82
|
+
invariant(inputNode != null)
|
|
83
|
+
|
|
84
|
+
const { material } = this
|
|
85
|
+
material.fragmentNode = this.setupOutputNode(builder)
|
|
86
|
+
material.needsUpdate = true
|
|
87
|
+
|
|
88
|
+
return super.setup(builder)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
override dispose(): void {
|
|
92
|
+
this.horizontalRT.dispose()
|
|
93
|
+
this.verticalRT.dispose()
|
|
94
|
+
this.material.dispose()
|
|
95
|
+
this.mesh.geometry.dispose()
|
|
96
|
+
super.dispose()
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Vector2, type RenderTarget } from 'three'
|
|
2
|
+
import { uniform } from 'three/tsl'
|
|
3
|
+
import {
|
|
4
|
+
NodeMaterial,
|
|
5
|
+
QuadMesh,
|
|
6
|
+
RendererUtils,
|
|
7
|
+
type NodeBuilder,
|
|
8
|
+
type NodeFrame,
|
|
9
|
+
type TextureNode
|
|
10
|
+
} from 'three/webgpu'
|
|
11
|
+
import invariant from 'tiny-invariant'
|
|
12
|
+
|
|
13
|
+
import { FilterNode } from './FilterNode'
|
|
14
|
+
import type { Node } from './node'
|
|
15
|
+
|
|
16
|
+
const { resetRendererState, restoreRendererState } = RendererUtils
|
|
17
|
+
|
|
18
|
+
export abstract class SingleFilterNode extends FilterNode {
|
|
19
|
+
private readonly renderTarget: RenderTarget
|
|
20
|
+
private readonly material = new NodeMaterial()
|
|
21
|
+
private readonly mesh = new QuadMesh(this.material)
|
|
22
|
+
private rendererState?: RendererUtils.RendererState
|
|
23
|
+
|
|
24
|
+
protected readonly inputTexelSize = uniform(new Vector2())
|
|
25
|
+
|
|
26
|
+
constructor(inputNode?: TextureNode | null) {
|
|
27
|
+
super(inputNode)
|
|
28
|
+
|
|
29
|
+
this.renderTarget = this.createRenderTarget()
|
|
30
|
+
this.outputTexture = this.renderTarget.texture
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override setSize(width: number, height: number): this {
|
|
34
|
+
const { resolutionScale } = this
|
|
35
|
+
const w = Math.max(Math.round(width * resolutionScale), 1)
|
|
36
|
+
const h = Math.max(Math.round(height * resolutionScale), 1)
|
|
37
|
+
this.renderTarget.setSize(w, h)
|
|
38
|
+
return this
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
override updateBefore({ renderer }: NodeFrame): void {
|
|
42
|
+
if (renderer == null) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const { inputNode } = this
|
|
47
|
+
invariant(inputNode != null)
|
|
48
|
+
|
|
49
|
+
const { width, height } = inputNode.value
|
|
50
|
+
this.setSize(width, height)
|
|
51
|
+
this.inputTexelSize.value.set(1 / width, 1 / height)
|
|
52
|
+
|
|
53
|
+
this.rendererState = resetRendererState(renderer, this.rendererState)
|
|
54
|
+
|
|
55
|
+
renderer.setRenderTarget(this.renderTarget)
|
|
56
|
+
this.mesh.render(renderer)
|
|
57
|
+
|
|
58
|
+
restoreRendererState(renderer, this.rendererState)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
protected abstract setupOutputNode(builder: NodeBuilder): Node
|
|
62
|
+
|
|
63
|
+
override setup(builder: NodeBuilder): unknown {
|
|
64
|
+
const { inputNode } = this
|
|
65
|
+
invariant(inputNode != null)
|
|
66
|
+
|
|
67
|
+
const { material } = this
|
|
68
|
+
material.fragmentNode = this.setupOutputNode(builder)
|
|
69
|
+
material.needsUpdate = true
|
|
70
|
+
|
|
71
|
+
return super.setup(builder)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
override dispose(): void {
|
|
75
|
+
this.renderTarget.dispose()
|
|
76
|
+
this.material.dispose()
|
|
77
|
+
this.mesh.geometry.dispose()
|
|
78
|
+
super.dispose()
|
|
79
|
+
}
|
|
80
|
+
}
|