@takram/three-geospatial 0.7.1 → 0.9.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.
Files changed (71) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +1 -1
  3. package/build/index.cjs +1 -1
  4. package/build/index.cjs.map +1 -1
  5. package/build/index.js +580 -598
  6. package/build/index.js.map +1 -1
  7. package/build/r3f.cjs +1 -1
  8. package/build/r3f.js +1 -1
  9. package/build/shared2.cjs +1 -1
  10. package/build/shared2.cjs.map +1 -1
  11. package/build/shared2.js +27 -212
  12. package/build/shared2.js.map +1 -1
  13. package/build/shared3.cjs +1 -1
  14. package/build/shared3.cjs.map +1 -1
  15. package/build/shared3.js +213 -8
  16. package/build/shared3.js.map +1 -1
  17. package/build/webgpu.cjs +6 -1
  18. package/build/webgpu.cjs.map +1 -1
  19. package/build/webgpu.js +1111 -768
  20. package/build/webgpu.js.map +1 -1
  21. package/package.json +1 -1
  22. package/src/EllipsoidGeometry.ts +1 -1
  23. package/src/PointOfView.ts +12 -5
  24. package/src/STBNLoader.ts +41 -19
  25. package/src/unrollLoops.ts +1 -1
  26. package/src/webgpu/CascadedShadowMapsNode.ts +48 -0
  27. package/src/webgpu/DualMipmapFilterNode.ts +8 -4
  28. package/src/webgpu/FilterNode.ts +5 -3
  29. package/src/webgpu/FnLayout.ts +17 -16
  30. package/src/webgpu/HighpVelocityNode.ts +9 -4
  31. package/src/webgpu/LensFlareNode.ts +12 -16
  32. package/src/webgpu/LensGlareNode.ts +28 -32
  33. package/src/webgpu/LensHaloNode.ts +2 -1
  34. package/src/webgpu/OutputTexture3DNode.ts +10 -0
  35. package/src/webgpu/OutputTextureNode.ts +10 -0
  36. package/src/webgpu/STBNTextureNode.ts +58 -0
  37. package/src/webgpu/ScreenSpaceShadowNode.ts +685 -0
  38. package/src/webgpu/SeparableFilterNode.ts +8 -5
  39. package/src/webgpu/SingleFilterNode.ts +5 -2
  40. package/src/webgpu/StorageTexture3DNode.ts +30 -0
  41. package/src/webgpu/TemporalAntialiasNode.ts +178 -137
  42. package/src/webgpu/accessors.ts +75 -36
  43. package/src/webgpu/debug.ts +38 -47
  44. package/src/webgpu/events.ts +18 -0
  45. package/src/webgpu/index.ts +5 -1
  46. package/src/webgpu/math.ts +116 -15
  47. package/src/webgpu/sampling.ts +39 -5
  48. package/src/webgpu/transformations.ts +71 -44
  49. package/types/PointOfView.d.ts +1 -1
  50. package/types/STBNLoader.d.ts +3 -4
  51. package/types/webgpu/CascadedShadowMapsNode.d.ts +13 -0
  52. package/types/webgpu/DualMipmapFilterNode.d.ts +1 -2
  53. package/types/webgpu/FnLayout.d.ts +4 -4
  54. package/types/webgpu/HighpVelocityNode.d.ts +1 -0
  55. package/types/webgpu/LensFlareNode.d.ts +2 -3
  56. package/types/webgpu/LensGlareNode.d.ts +1 -1
  57. package/types/webgpu/STBNTextureNode.d.ts +9 -0
  58. package/types/webgpu/ScreenSpaceShadowNode.d.ts +33 -0
  59. package/types/webgpu/SeparableFilterNode.d.ts +2 -3
  60. package/types/webgpu/SingleFilterNode.d.ts +1 -2
  61. package/types/webgpu/StorageTexture3DNode.d.ts +9 -0
  62. package/types/webgpu/TemporalAntialiasNode.d.ts +9 -10
  63. package/types/webgpu/accessors.d.ts +9 -8
  64. package/types/webgpu/debug.d.ts +4 -3
  65. package/types/webgpu/events.d.ts +3 -0
  66. package/types/webgpu/index.d.ts +5 -1
  67. package/types/webgpu/math.d.ts +3 -0
  68. package/types/webgpu/sampling.d.ts +2 -1
  69. package/types/webgpu/transformations.d.ts +7 -10
  70. package/src/webgpu/RTTextureNode.ts +0 -130
  71. package/types/webgpu/RTTextureNode.d.ts +0 -22
@@ -1,17 +1,17 @@
1
1
  import type {
2
2
  ProxiedTuple,
3
3
  ShaderCallNodeInternal,
4
- ShaderNodeFn,
5
- Struct
4
+ ShaderNodeFn
6
5
  } from 'three/src/nodes/TSL.js'
7
6
  import { Fn } from 'three/tsl'
8
- import type { NodeBuilder, Texture3DNode, TextureNode } from 'three/webgpu'
7
+ import { StructTypeNode, type NodeBuilder } from 'three/webgpu'
9
8
 
10
9
  import type { Node, NodeType } from './node'
11
10
 
12
- // Note that "texture" and "texture3D" are just placeholders until TSL supports
13
- // texture types.
14
- type FnLayoutType = NodeType | Struct | 'texture' | 'texture3D'
11
+ type FnLayoutType =
12
+ | NodeType
13
+ | (new (...args: any[]) => any)
14
+ | ((...args: any[]) => any)
15
15
 
16
16
  export interface FnLayoutInput<T extends FnLayoutType = FnLayoutType> {
17
17
  name: string
@@ -30,13 +30,11 @@ export interface FnLayout<
30
30
 
31
31
  type InferNodeObject<T extends FnLayoutType> = T extends NodeType
32
32
  ? Node<T>
33
- : T extends Struct
34
- ? ReturnType<T>
35
- : T extends 'texture'
36
- ? TextureNode
37
- : T extends 'texture3D'
38
- ? Texture3DNode
39
- : never
33
+ : T extends new (...args: any[]) => any
34
+ ? InstanceType<T>
35
+ : T extends (...args: any[]) => any
36
+ ? ReturnType<T>
37
+ : never
40
38
 
41
39
  type InferNodeObjects<Inputs extends readonly FnLayoutInput[]> = {
42
40
  [K in keyof Inputs]: Inputs[K] extends FnLayoutInput<infer T>
@@ -58,10 +56,13 @@ function transformType(type: FnLayoutType): string {
58
56
  if (typeof type === 'string') {
59
57
  return type
60
58
  }
61
- if (type.layout.name == null) {
62
- throw new Error('Struct name is required.')
59
+ if ('layout' in type && type.layout instanceof StructTypeNode) {
60
+ if (type.layout.name == null) {
61
+ throw new Error('Struct name is required.')
62
+ }
63
+ return type.layout.name
63
64
  }
64
- return type.layout.name
65
+ throw new Error(`Unsupported layout type: ${type}`)
65
66
  }
66
67
 
67
68
  export function FnLayout<
@@ -20,11 +20,11 @@ export class HighpVelocityNode extends TempNode {
20
20
 
21
21
  projectionMatrix?: Matrix4 | null
22
22
 
23
- private readonly currentProjectionMatrix = uniform(new Matrix4())
24
- private readonly previousProjectionMatrix = uniform('mat4' as const)
23
+ private readonly currentProjectionMatrix = uniform('mat4')
24
+ private readonly previousProjectionMatrix = uniform('mat4')
25
25
 
26
- private readonly currentModelViewMatrix = uniform(new Matrix4())
27
- private readonly previousModelViewMatrix = uniform('mat4' as const)
26
+ private readonly currentModelViewMatrix = uniform('mat4')
27
+ private readonly previousModelViewMatrix = uniform('mat4')
28
28
  private readonly objectModelViewMatrices = new WeakMap<Object3D, Matrix4>()
29
29
 
30
30
  constructor() {
@@ -42,6 +42,11 @@ export class HighpVelocityNode extends TempNode {
42
42
  this.updateAfterType = NodeUpdateType.OBJECT
43
43
  }
44
44
 
45
+ setProjectionMatrix(value: Matrix4 | null): this {
46
+ this.projectionMatrix = value
47
+ return this
48
+ }
49
+
45
50
  // Executed once per frame:
46
51
  override update({ camera }: NodeFrame): void {
47
52
  if (camera == null) {
@@ -1,5 +1,10 @@
1
- import { add, Fn, uniform } from 'three/tsl'
2
- import { TempNode, type NodeBuilder, type TextureNode } from 'three/webgpu'
1
+ import { add, convertToTexture, Fn, rtt, uniform } from 'three/tsl'
2
+ import {
3
+ TempNode,
4
+ type NodeBuilder,
5
+ type RTTNode,
6
+ type TextureNode
7
+ } from 'three/webgpu'
3
8
  import invariant from 'tiny-invariant'
4
9
 
5
10
  import { DownsampleThresholdNode } from './DownsampleThresholdNode'
@@ -9,11 +14,6 @@ import { LensGlareNode } from './LensGlareNode'
9
14
  import { LensHaloNode } from './LensHaloNode'
10
15
  import { MipmapSurfaceBlurNode } from './MipmapSurfaceBlurNode'
11
16
  import type { Node } from './node'
12
- import {
13
- convertToTexture,
14
- rtTexture,
15
- type RTTextureNode
16
- } from './RTTextureNode'
17
17
  import { isWebGPU } from './utils'
18
18
 
19
19
  export class LensFlareNode extends TempNode {
@@ -31,7 +31,7 @@ export class LensFlareNode extends TempNode {
31
31
 
32
32
  bloomIntensity = uniform(0.05)
33
33
 
34
- featuresNode: RTTextureNode
34
+ featuresNode: RTTNode
35
35
 
36
36
  constructor(inputNode?: TextureNode | null) {
37
37
  super('vec4')
@@ -44,9 +44,9 @@ export class LensFlareNode extends TempNode {
44
44
  this.bloomNode = new MipmapSurfaceBlurNode(null, 8)
45
45
  this.glareNode = new LensGlareNode()
46
46
 
47
- this.featuresNode = rtTexture(add(this.ghostNode, this.haloNode))
48
- this.featuresNode.value.name = 'LensFlareNode.Features'
49
- this.featuresNode.resolutionScale = 0.5
47
+ this.featuresNode = rtt(add(this.ghostNode, this.haloNode))
48
+ this.featuresNode.value.name = 'LensFlare_features'
49
+ this.featuresNode.pixelRatio = 0.5
50
50
 
51
51
  // Use the full resolution because the thresholdNode already downsamples the
52
52
  // input texture.
@@ -112,8 +112,4 @@ export class LensFlareNode extends TempNode {
112
112
  }
113
113
 
114
114
  export const lensFlare = (inputNode: Node | null): LensFlareNode =>
115
- new LensFlareNode(
116
- inputNode != null
117
- ? convertToTexture(inputNode, 'LensFlareNode.Input')
118
- : null
119
- )
115
+ new LensFlareNode(inputNode != null ? convertToTexture(inputNode) : null)
@@ -10,6 +10,7 @@ import {
10
10
  import { hash } from 'three/src/nodes/core/NodeUtils.js'
11
11
  import {
12
12
  atomicAdd,
13
+ convertToTexture,
13
14
  Fn,
14
15
  globalId,
15
16
  If,
@@ -28,9 +29,9 @@ import {
28
29
  vec4
29
30
  } from 'three/tsl'
30
31
  import {
32
+ IndirectStorageBufferAttribute,
31
33
  MeshBasicNodeMaterial,
32
34
  RendererUtils,
33
- StorageBufferAttribute,
34
35
  type ComputeNode,
35
36
  type NodeBuilder,
36
37
  type NodeFrame,
@@ -40,7 +41,6 @@ import invariant from 'tiny-invariant'
40
41
 
41
42
  import { FilterNode } from './FilterNode'
42
43
  import type { Node } from './node'
43
- import { convertToTexture } from './RTTextureNode'
44
44
 
45
45
  const { resetRendererState, restoreRendererState } = RendererUtils
46
46
 
@@ -92,7 +92,12 @@ export class LensGlareNode extends FilterNode {
92
92
 
93
93
  private computeNode?: ComputeNode
94
94
 
95
- private readonly counterBuffer = new StorageBufferAttribute(1, 1)
95
+ // drawIndexedIndirect format:
96
+ // [indexCount, instanceCount, firstIndex, baseVertex, firstInstance]
97
+ private readonly indirectBuffer = new IndirectStorageBufferAttribute(
98
+ new Uint32Array([6, 0, 0, 0, 0]),
99
+ 1
100
+ )
96
101
  private instanceBuffer = instancedArray(1, instanceStruct)
97
102
 
98
103
  private readonly renderTarget = this.createRenderTarget()
@@ -106,16 +111,19 @@ export class LensGlareNode extends FilterNode {
106
111
  private readonly camera = new PerspectiveCamera()
107
112
  private rendererState?: RendererUtils.RendererState
108
113
 
109
- private readonly inputTexelSize = uniform(new Vector2())
110
- private readonly outputTexelSize = uniform(new Vector2())
111
- private readonly geometryRatio = uniform(new Vector2())
114
+ private readonly inputTexelSize = uniform('vec2')
115
+ private readonly outputTexelSize = uniform('vec2')
116
+ private readonly geometryRatio = uniform('vec2')
112
117
 
113
118
  constructor(inputNode?: TextureNode | null) {
114
119
  super(inputNode)
120
+ this.material.name = 'LensGlare'
121
+
115
122
  this.inputNode = inputNode
116
123
  this.resolutionScale = 0.5
117
124
 
118
125
  this.outputTexture = this.renderTarget.texture
126
+ this.mesh.geometry.indirect = this.indirectBuffer
119
127
  }
120
128
 
121
129
  override customCacheKey(): number {
@@ -151,7 +159,7 @@ export class LensGlareNode extends FilterNode {
151
159
  const { width: inputWidth, height: inputHeight } = inputNode.value
152
160
  this.setSize(inputWidth, inputHeight) // Compute node is initialized here.
153
161
 
154
- const { computeNode, counterBuffer, renderTarget } = this
162
+ const { computeNode, indirectBuffer, renderTarget } = this
155
163
  invariant(computeNode != null)
156
164
 
157
165
  this.inputTexelSize.value.set(1 / inputWidth, 1 / inputHeight)
@@ -165,24 +173,12 @@ export class LensGlareNode extends FilterNode {
165
173
  const { width: outputWidth, height: outputHeight } = renderTarget
166
174
  this.outputTexelSize.value.set(1 / outputWidth, 1 / outputHeight)
167
175
 
168
- // Reset the counter:
169
- counterBuffer.array[0] = 0
170
- counterBuffer.needsUpdate = true
176
+ // Reset instanceCount in the indirect buffer:
177
+ indirectBuffer.array[1] = 0
178
+ indirectBuffer.needsUpdate = true
171
179
 
172
180
  void renderer.compute(computeNode)
173
181
 
174
- renderer
175
- .getArrayBufferAsync(counterBuffer)
176
- .then(arrayBuffer => {
177
- // TODO: This is indeed a couple of frames behind, thus the number of
178
- // computed instances above and the number of instances to be drawn by
179
- // the mesh differ.
180
- this.mesh.count = new Uint32Array(arrayBuffer)[0]
181
- })
182
- .catch((error: unknown) => {
183
- console.error(error)
184
- })
185
-
186
182
  this.rendererState = resetRendererState(renderer, this.rendererState)
187
183
 
188
184
  renderer.setRenderTarget(renderTarget)
@@ -195,16 +191,16 @@ export class LensGlareNode extends FilterNode {
195
191
  const {
196
192
  spikePairCount,
197
193
  inputNode,
198
- counterBuffer,
194
+ indirectBuffer,
199
195
  instanceBuffer,
200
196
  outputTexelSize
201
197
  } = this
202
198
  invariant(inputNode != null)
203
199
 
204
- const counterStorage = storage(
205
- counterBuffer,
200
+ const indirectStorage = storage(
201
+ indirectBuffer,
206
202
  'uint',
207
- counterBuffer.count
203
+ indirectBuffer.count
208
204
  ).toAtomic()
209
205
 
210
206
  this.computeNode = Fn(() => {
@@ -218,7 +214,11 @@ export class LensGlareNode extends FilterNode {
218
214
  const inputLuminance = inputColor.a // Alpha channel stores luminance
219
215
 
220
216
  If(inputLuminance.greaterThan(0.1), () => {
221
- const countBefore = atomicAdd(counterStorage.element(0), spikePairCount)
217
+ // The first element is instanceCount in the drawIndexedIndirect buffer.
218
+ const countBefore = atomicAdd(
219
+ indirectStorage.element(1),
220
+ spikePairCount
221
+ )
222
222
  for (let i = 0; i < spikePairCount; ++i) {
223
223
  const instance = instanceBuffer.element(countBefore.add(i))
224
224
  instance.get('color').assign(inputColor.rgb)
@@ -308,8 +308,4 @@ export class LensGlareNode extends FilterNode {
308
308
  }
309
309
 
310
310
  export const lensGlare = (inputNode: Node | null): LensGlareNode =>
311
- new LensGlareNode(
312
- inputNode != null
313
- ? convertToTexture(inputNode, 'LensGlareNode.Input')
314
- : null
315
- )
311
+ new LensGlareNode(inputNode != null ? convertToTexture(inputNode) : null)
@@ -38,8 +38,9 @@ export class LensHaloNode extends TempNode {
38
38
 
39
39
  constructor(inputNode?: TextureNode | null) {
40
40
  super('vec3')
41
- this.inputNode = inputNode
42
41
  this.updateBeforeType = NodeUpdateType.FRAME
42
+
43
+ this.inputNode = inputNode
43
44
  }
44
45
 
45
46
  override updateBefore({ renderer }: NodeFrame): void {
@@ -1,6 +1,8 @@
1
1
  import type { Texture } from 'three'
2
2
  import { Texture3DNode, type Node, type NodeBuilder } from 'three/webgpu'
3
3
 
4
+ import { reinterpretType } from '../types'
5
+
4
6
  export class OutputTexture3DNode extends Texture3DNode {
5
7
  static override get type(): string {
6
8
  return 'OutputTexture3DNode'
@@ -11,6 +13,14 @@ export class OutputTexture3DNode extends Texture3DNode {
11
13
  constructor(owner: Node, texture: Texture) {
12
14
  super(texture)
13
15
  this.owner = owner
16
+
17
+ // WORKAROUND: Missing method as of r182. Adding these in the module
18
+ // augmentation breaks VSCode's auto completion.
19
+ reinterpretType<
20
+ typeof this & {
21
+ setUpdateMatrix: (value: boolean) => void
22
+ }
23
+ >(this)
14
24
  this.setUpdateMatrix(false)
15
25
  }
16
26
 
@@ -1,6 +1,8 @@
1
1
  import type { Texture } from 'three'
2
2
  import { TextureNode, type Node, type NodeBuilder } from 'three/webgpu'
3
3
 
4
+ import { reinterpretType } from '../types'
5
+
4
6
  export class OutputTextureNode extends TextureNode {
5
7
  static override get type(): string {
6
8
  return 'OutputTextureNode'
@@ -11,6 +13,14 @@ export class OutputTextureNode extends TextureNode {
11
13
  constructor(owner: Node, texture: Texture) {
12
14
  super(texture)
13
15
  this.owner = owner
16
+
17
+ // WORKAROUND: Missing method as of r182. Adding these in the module
18
+ // augmentation breaks VSCode's auto completion.
19
+ reinterpretType<
20
+ typeof this & {
21
+ setUpdateMatrix: (value: boolean) => void
22
+ }
23
+ >(this)
14
24
  this.setUpdateMatrix(false)
15
25
  }
16
26
 
@@ -0,0 +1,58 @@
1
+ import { hashString } from 'three/src/nodes/core/NodeUtils.js'
2
+ import { Fn, frameId, nodeImmutable, screenCoordinate, vec3 } from 'three/tsl'
3
+ import {
4
+ Data3DTexture,
5
+ NearestFilter,
6
+ RedFormat,
7
+ RepeatWrapping,
8
+ Texture3DNode,
9
+ type NodeBuilder
10
+ } from 'three/webgpu'
11
+
12
+ import { DEFAULT_STBN_URL } from '../constants'
13
+ import { STBNLoader } from '../STBNLoader'
14
+
15
+ const emptyTexture3D = /*#__PURE__*/ (() => {
16
+ const texture = new Data3DTexture(new Uint8Array(1))
17
+ texture.format = RedFormat
18
+ // BUG: TextureNode doesn't update these when the texture is swapped.
19
+ texture.minFilter = NearestFilter
20
+ texture.magFilter = NearestFilter
21
+ texture.wrapS = RepeatWrapping
22
+ texture.wrapT = RepeatWrapping
23
+ texture.wrapR = RepeatWrapping
24
+ texture.needsUpdate = true
25
+ return texture
26
+ })()
27
+
28
+ export class STBNTextureNode extends Texture3DNode {
29
+ url = DEFAULT_STBN_URL
30
+
31
+ constructor() {
32
+ super(emptyTexture3D)
33
+ }
34
+
35
+ override customCacheKey(): number {
36
+ return hashString(this.url)
37
+ }
38
+
39
+ override setup(builder: NodeBuilder): unknown {
40
+ new STBNLoader()
41
+ .loadAsync(this.url)
42
+ .then(texture => {
43
+ this.value = texture
44
+ })
45
+ .catch((error: unknown) => {
46
+ console.error(error)
47
+ })
48
+ return super.setup(builder)
49
+ }
50
+ }
51
+
52
+ export const stbnTexture = /*#__PURE__*/ nodeImmutable(STBNTextureNode)
53
+
54
+ export const stbn = /*#__PURE__*/ Fn(() => {
55
+ return stbnTexture
56
+ .sample(vec3(screenCoordinate.xy, frameId.mod(64)).div(vec3(128, 128, 64)))
57
+ .r.toConst('stbn')
58
+ }).once()()