@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,8 +1,21 @@
1
- import { Vector3, type Camera } from 'three'
2
- import { reference, uniform } from 'three/tsl'
1
+ import type { Camera, Vector3 } from 'three'
2
+ import {
3
+ cameraFar as cameraFarTSL,
4
+ cameraNear as cameraNearTSL,
5
+ cameraPosition,
6
+ cameraProjectionMatrix,
7
+ cameraProjectionMatrixInverse,
8
+ cameraViewMatrix,
9
+ cameraWorldMatrix,
10
+ depth,
11
+ Fn,
12
+ reference,
13
+ uniform
14
+ } from 'three/tsl'
3
15
  import type { UniformNode } from 'three/webgpu'
4
16
 
5
17
  import type { Node } from './node'
18
+ import { depthToViewZ } from './transformations'
6
19
 
7
20
  let caches: WeakMap<{}, Record<string, {}>> | undefined
8
21
 
@@ -23,43 +36,69 @@ function getCache<T extends {}, U extends {}>(
23
36
  return (cache[name] ??= callback()) as U
24
37
  }
25
38
 
26
- export const projectionMatrix = (camera: Camera): Node<'mat4'> =>
27
- getCache(camera, 'projectionMatrix', () =>
28
- reference('projectionMatrix', 'mat4', camera).setName('projectionMatrix')
29
- )
39
+ export const projectionMatrix = (camera?: Camera | null): Node<'mat4'> =>
40
+ camera != null
41
+ ? getCache(camera, 'projectionMatrix', () =>
42
+ reference('projectionMatrix', 'mat4', camera).setName(
43
+ 'projectionMatrix'
44
+ )
45
+ )
46
+ : cameraProjectionMatrix
30
47
 
31
- export const viewMatrix = (camera: Camera): Node<'mat4'> =>
32
- getCache(camera, 'viewMatrix', () =>
33
- reference('matrixWorldInverse', 'mat4', camera).setName('viewMatrix')
34
- )
48
+ export const viewMatrix = (camera?: Camera | null): Node<'mat4'> =>
49
+ camera != null
50
+ ? getCache(camera, 'viewMatrix', () =>
51
+ reference('matrixWorldInverse', 'mat4', camera).setName('viewMatrix')
52
+ )
53
+ : cameraViewMatrix
35
54
 
36
- export const inverseProjectionMatrix = (camera: Camera): Node<'mat4'> =>
37
- getCache(camera, 'inverseProjectionMatrix', () =>
38
- reference('projectionMatrixInverse', 'mat4', camera).setName(
39
- 'inverseProjectionMatrix'
40
- )
41
- )
55
+ export const inverseProjectionMatrix = (
56
+ camera?: Camera | null
57
+ ): Node<'mat4'> =>
58
+ camera != null
59
+ ? getCache(camera, 'inverseProjectionMatrix', () =>
60
+ reference('projectionMatrixInverse', 'mat4', camera).setName(
61
+ 'inverseProjectionMatrix'
62
+ )
63
+ )
64
+ : cameraProjectionMatrixInverse
42
65
 
43
- export const inverseViewMatrix = (camera: Camera): Node<'mat4'> =>
44
- getCache(camera, 'inverseViewMatrix', () =>
45
- reference('matrixWorld', 'mat4', camera).setName('inverseViewMatrix')
46
- )
66
+ export const inverseViewMatrix = (camera?: Camera | null): Node<'mat4'> =>
67
+ camera != null
68
+ ? getCache(camera, 'inverseViewMatrix', () =>
69
+ reference('matrixWorld', 'mat4', camera).setName('inverseViewMatrix')
70
+ )
71
+ : cameraWorldMatrix // TODO: Not always
47
72
 
48
- export const cameraPositionWorld = (camera: Camera): UniformNode<Vector3> =>
49
- getCache(camera, 'cameraPositionWorld', () =>
50
- uniform(new Vector3())
51
- .setName('cameraPositionWorld')
52
- .onRenderUpdate((_, { value }) => {
53
- value.setFromMatrixPosition(camera.matrixWorld)
54
- })
55
- )
73
+ export const cameraPositionWorld = (
74
+ camera?: Camera | null
75
+ ): UniformNode<Vector3> =>
76
+ camera != null
77
+ ? getCache(camera, 'cameraPositionWorld', () =>
78
+ uniform('vec3')
79
+ .setName('cameraPositionWorld')
80
+ .onRenderUpdate((_, { value }) => {
81
+ value.setFromMatrixPosition(camera.matrixWorld)
82
+ })
83
+ )
84
+ : cameraPosition
56
85
 
57
- export const cameraNear = (camera: Camera): Node<'float'> =>
58
- getCache(camera, 'cameraNear', () =>
59
- reference('near', 'float', camera).setName('cameraNear')
60
- )
86
+ export const cameraNear = (camera?: Camera | null): Node<'float'> =>
87
+ camera != null
88
+ ? getCache(camera, 'cameraNear', () =>
89
+ reference('near', 'float', camera).setName('cameraNear')
90
+ )
91
+ : cameraNearTSL
61
92
 
62
- export const cameraFar = (camera: Camera): Node<'float'> =>
63
- getCache(camera, 'cameraFar', () =>
64
- reference('far', 'float', camera).setName('cameraFar')
65
- )
93
+ export const cameraFar = (camera?: Camera | null): Node<'float'> =>
94
+ camera != null
95
+ ? getCache(camera, 'cameraFar', () =>
96
+ reference('far', 'float', camera).setName('cameraFar')
97
+ )
98
+ : cameraFarTSL
99
+
100
+ export const viewZ = Fn(
101
+ ({ camera }): Node<'float'> => depthToViewZ(depth, camera)
102
+ )
103
+ .once()()
104
+ .toVar('viewZ')
@@ -6,65 +6,56 @@ import { QuadGeometry } from '../QuadGeometry'
6
6
 
7
7
  async function debugShader(
8
8
  renderer: Renderer,
9
- mesh: Mesh
10
- ): Promise<
11
- Awaited<{
12
- fragmentShader: string | null
13
- vertexShader: string | null
14
- }>
15
- > {
16
- return await renderer.debug
17
- .getShaderAsync(new Scene(), new Camera(), mesh)
18
- .then(result => {
19
- return result
20
- })
21
- .catch((error: unknown) => {
22
- console.error(error)
23
- return { fragmentShader: null, vertexShader: null }
24
- })
9
+ material: NodeMaterial
10
+ ): Promise<{
11
+ vertexShader: string | null
12
+ fragmentShader: string | null
13
+ }> {
14
+ const mesh = new Mesh(new QuadGeometry(), material)
15
+ try {
16
+ return await renderer.debug.getShaderAsync(new Scene(), new Camera(), mesh)
17
+ } catch (error: unknown) {
18
+ console.error(error)
19
+ return { vertexShader: null, fragmentShader: null }
20
+ } finally {
21
+ mesh.geometry.dispose()
22
+ }
25
23
  }
26
24
 
27
- export function debugFragmentNode(
25
+ export async function debugMaterial(
28
26
  renderer: Renderer,
29
27
  material: NodeMaterial
30
- ): void {
31
- const mesh = new Mesh(new QuadGeometry(), material)
32
- void debugShader(renderer, mesh)
33
- .then(result => {
34
- console.log(result.fragmentShader)
35
- })
36
- .finally(() => {
37
- mesh.geometry.dispose()
38
- })
28
+ ): Promise<string | null> {
29
+ const { vertexShader, fragmentShader } = await debugShader(renderer, material)
30
+ return vertexShader != null && fragmentShader != null
31
+ ? `// Vertex shader\n\n${vertexShader}\n// Fragment shader\n\n${fragmentShader}`
32
+ : null
39
33
  }
40
34
 
41
- export function debugVertexNode(
35
+ export async function debugVertexNode(
42
36
  renderer: Renderer,
43
37
  material: NodeMaterial
44
- ): void {
45
- const mesh = new Mesh(new QuadGeometry(), material)
46
- void debugShader(renderer, mesh)
47
- .then(result => {
48
- console.log(result.vertexShader)
49
- })
50
- .finally(() => {
51
- mesh.geometry.dispose()
52
- })
38
+ ): Promise<string | null> {
39
+ return (await debugShader(renderer, material)).vertexShader
40
+ }
41
+
42
+ export async function debugFragmentNode(
43
+ renderer: Renderer,
44
+ material: NodeMaterial
45
+ ): Promise<string | null> {
46
+ return (await debugShader(renderer, material)).fragmentShader
53
47
  }
54
48
 
55
- export function debugNode(renderer: Renderer, node: Node): void {
49
+ export async function debugNode(
50
+ renderer: Renderer,
51
+ node: Node
52
+ ): Promise<string | null> {
56
53
  const material = new NodeMaterial()
57
54
  material.vertexNode = vec4(positionGeometry.xy, 0, 1)
58
- material.fragmentNode = node
59
- const mesh = new Mesh(new QuadGeometry(), material)
60
- void debugShader(renderer, mesh)
61
- .then(result => {
62
- console.log(result.fragmentShader)
63
- })
64
- .finally(() => {
65
- material.dispose()
66
- mesh.geometry.dispose()
67
- })
55
+ material.fragmentNode = node.toConst('debugNode')
56
+ const shader = await debugShader(renderer, material)
57
+ material.dispose()
58
+ return shader.fragmentShader
68
59
  }
69
60
 
70
61
  export function hookFunction<
@@ -0,0 +1,18 @@
1
+ import { OnBeforeObjectUpdate, OnObjectUpdate } from 'three/tsl'
2
+ import { NodeUpdateType, type Node, type NodeFrame } from 'three/webgpu'
3
+
4
+ // TODO: File a PR for these:
5
+
6
+ export const OnFrameUpdate = (callback: (frame: NodeFrame) => void): Node => {
7
+ const node = OnObjectUpdate(callback)
8
+ node.updateType = NodeUpdateType.NONE
9
+ return node
10
+ }
11
+
12
+ export const OnBeforeFrameUpdate = (
13
+ callback: (frame: NodeFrame) => void
14
+ ): Node => {
15
+ const node = OnBeforeObjectUpdate(callback)
16
+ node.updateBeforeType = NodeUpdateType.FRAME
17
+ return node
18
+ }
@@ -1,6 +1,8 @@
1
1
  export * from './accessors'
2
+ export * from './CascadedShadowMapsNode'
2
3
  export * from './debug'
3
4
  export * from './DownsampleThresholdNode'
5
+ export * from './events'
4
6
  export * from './FnLayout'
5
7
  export * from './FnVar'
6
8
  export * from './GaussianBlurNode'
@@ -14,8 +16,10 @@ export * from './MipmapSurfaceBlurNode'
14
16
  export * from './node'
15
17
  export * from './OutputTexture3DNode'
16
18
  export * from './OutputTextureNode'
17
- export * from './RTTextureNode'
18
19
  export * from './sampling'
20
+ export * from './ScreenSpaceShadowNode'
21
+ export * from './STBNTextureNode'
22
+ export * from './StorageTexture3DNode'
19
23
  export * from './TemporalAntialiasNode'
20
24
  export * from './transformations'
21
25
  export * from './utils'
@@ -1,8 +1,110 @@
1
- import { dot, If, sqrt, struct, vec2, vec4 } from 'three/tsl'
1
+ import {
2
+ bool,
3
+ bvec2,
4
+ bvec3,
5
+ bvec4,
6
+ dot,
7
+ If,
8
+ overloadingFn,
9
+ sqrt,
10
+ struct,
11
+ uvec2,
12
+ uvec3,
13
+ uvec4,
14
+ vec2
15
+ } from 'three/tsl'
2
16
 
17
+ import { FnLayout } from './FnLayout'
3
18
  import { FnVar } from './FnVar'
4
19
  import type { Node } from './node'
5
20
 
21
+ const bvec2Not = /*#__PURE__*/ FnLayout({
22
+ name: 'bvec2Not',
23
+ type: 'bvec2',
24
+ inputs: [{ name: 'x', type: 'bvec2' }]
25
+ })(([x]) => x.notEqual(bool(true)))
26
+
27
+ const bvec3Not = /*#__PURE__*/ FnLayout({
28
+ name: 'bvec3Not',
29
+ type: 'bvec3',
30
+ inputs: [{ name: 'x', type: 'bvec3' }]
31
+ })(([x]) => x.notEqual(bool(true)))
32
+
33
+ const bvec4Not = /*#__PURE__*/ FnLayout({
34
+ name: 'bvec4Not',
35
+ type: 'bvec4',
36
+ inputs: [{ name: 'x', type: 'bvec4' }]
37
+ })(([x]) => x.notEqual(bool(true)))
38
+
39
+ // WORKAROUND: PR on this https://github.com/mrdoob/three.js/pull/33442
40
+ export const bvecNot = /*#__PURE__*/ overloadingFn([
41
+ bvec2Not,
42
+ bvec3Not,
43
+ bvec4Not
44
+ ])
45
+
46
+ const bvec2And = /*#__PURE__*/ FnLayout({
47
+ name: 'bvec2And',
48
+ type: 'bvec2',
49
+ inputs: [
50
+ { name: 'x', type: 'bvec2' },
51
+ { name: 'y', type: 'bvec2' }
52
+ ]
53
+ })(([x, y]) => bvec2(uvec2(x).mul(uvec2(y))))
54
+
55
+ const bvec3And = /*#__PURE__*/ FnLayout({
56
+ name: 'bvec3And',
57
+ type: 'bvec3',
58
+ inputs: [
59
+ { name: 'x', type: 'bvec3' },
60
+ { name: 'y', type: 'bvec3' }
61
+ ]
62
+ })(([x, y]) => bvec3(uvec3(x).mul(uvec3(y))))
63
+
64
+ const bvec4And = /*#__PURE__*/ FnLayout({
65
+ name: 'bvec4And',
66
+ type: 'bvec4',
67
+ inputs: [
68
+ { name: 'x', type: 'bvec4' },
69
+ { name: 'y', type: 'bvec4' }
70
+ ]
71
+ })(([x, y]) => bvec4(uvec4(x).mul(uvec4(y))))
72
+
73
+ export const bvecAnd = /*#__PURE__*/ overloadingFn([
74
+ bvec2And,
75
+ bvec3And,
76
+ bvec4And
77
+ ])
78
+
79
+ const bvec2Or = /*#__PURE__*/ FnLayout({
80
+ name: 'bvec2Or',
81
+ type: 'bvec2',
82
+ inputs: [
83
+ { name: 'x', type: 'bvec2' },
84
+ { name: 'y', type: 'bvec2' }
85
+ ]
86
+ })(([x, y]) => uvec2(x).add(uvec2(y)).notEqual(0))
87
+
88
+ const bvec3Or = /*#__PURE__*/ FnLayout({
89
+ name: 'bvec3Or',
90
+ type: 'bvec3',
91
+ inputs: [
92
+ { name: 'x', type: 'bvec3' },
93
+ { name: 'y', type: 'bvec3' }
94
+ ]
95
+ })(([x, y]) => uvec3(x).add(uvec3(y)).notEqual(0))
96
+
97
+ const bvec4Or = /*#__PURE__*/ FnLayout({
98
+ name: 'bvec4Or',
99
+ type: 'bvec4',
100
+ inputs: [
101
+ { name: 'x', type: 'bvec4' },
102
+ { name: 'y', type: 'bvec4' }
103
+ ]
104
+ })(([x, y]) => uvec4(x).add(uvec4(y)).notEqual(0))
105
+
106
+ export const bvecOr = /*#__PURE__*/ overloadingFn([bvec2Or, bvec3Or, bvec4Or])
107
+
6
108
  // Reference: https://iquilezles.org/articles/intersectors/
7
109
 
8
110
  export const raySphereIntersection = /*#__PURE__*/ FnVar(
@@ -15,7 +117,7 @@ export const raySphereIntersection = /*#__PURE__*/ FnVar(
15
117
  const a = rayOrigin.sub(center)
16
118
  const b = dot(rayDirection, a)
17
119
  const c = dot(a, a).sub(radius.pow2())
18
- const discriminant = b.pow2().sub(c).toVar()
120
+ const discriminant = b.pow2().sub(c).toConst()
19
121
 
20
122
  const intersection = vec2(-1)
21
123
  If(discriminant.greaterThanEqual(0), () => {
@@ -26,10 +128,10 @@ export const raySphereIntersection = /*#__PURE__*/ FnVar(
26
128
  }
27
129
  )
28
130
 
29
- export const raySpheresIntersectionsStruct = /*#__PURE__*/ struct(
30
- { near: 'vec4', far: 'vec4' },
31
- 'raySpheresIntersections'
32
- )
131
+ export const raySpheresIntersectionsStruct = /*#__PURE__*/ struct({
132
+ near: 'vec4',
133
+ far: 'vec4'
134
+ })
33
135
 
34
136
  // Derive ray-sphere intersections with multiple radii at once:
35
137
  export const raySpheresIntersections = /*#__PURE__*/ FnVar(
@@ -42,15 +144,14 @@ export const raySpheresIntersections = /*#__PURE__*/ FnVar(
42
144
  const a = rayOrigin.sub(center)
43
145
  const b = dot(rayDirection, a)
44
146
  const c = dot(a, a).sub(radii.pow2())
45
- const discriminant = b.pow2().sub(c).toVar()
147
+ const discriminant = b.pow2().sub(c).toConst()
46
148
 
47
- const near = vec4(-1)
48
- const far = vec4(-1)
49
- If(discriminant.greaterThanEqual(0), () => {
50
- const Q = sqrt(discriminant)
51
- near.assign(b.negate().sub(Q))
52
- far.assign(b.negate().add(Q))
53
- })
149
+ // Reference: https://github.com/GameTechDev/OutdoorLightScattering/blob/master/fx/Common.fxh#L148
150
+ const mask = vec2(discriminant.greaterThanEqual(0)).toConst()
151
+ const inverseMask = mask.oneMinus().toConst()
152
+ const Q = sqrt(discriminant.max(0)).toConst()
153
+ const near = mask.mul(b.negate().sub(Q)).sub(inverseMask)
154
+ const far = mask.mul(b.negate().add(Q)).sub(inverseMask)
54
155
  return raySpheresIntersectionsStruct(near, far)
55
156
  }
56
157
  )
@@ -69,7 +170,7 @@ export const rayEllipsoidIntersection = /*#__PURE__*/ FnVar(
69
170
  const discriminant = b
70
171
  .pow2()
71
172
  .sub(a.mul(c.sub(1)))
72
- .toVar()
173
+ .toConst()
73
174
 
74
175
  const intersections = vec2(-1)
75
176
  If(discriminant.greaterThanEqual(0), () => {
@@ -1,16 +1,50 @@
1
- import { add, sub, textureSize, vec2 } from 'three/tsl'
2
- import type { TextureNode } from 'three/webgpu'
1
+ import { add, ivec2, ivec4, sub, uv, vec2, vec4 } from 'three/tsl'
2
+ import type { ConstNode, TextureNode } from 'three/webgpu'
3
3
 
4
+ import { reinterpretType } from '../types'
4
5
  import { FnVar } from './FnVar'
5
6
  import type { Node } from './node'
6
7
 
8
+ const components = ['x', 'y', 'z', 'w'] as const
9
+
10
+ // WORKAROUND: TextureNode doesn't have gather() yet.
11
+ // See: https://www.w3.org/TR/WGSL/#texturegather
12
+ export const textureGather = /*#__PURE__*/ FnVar(
13
+ (
14
+ textureNode: TextureNode,
15
+ uvNode: Node<'vec2'>,
16
+ component = 0
17
+ ): Node<'vec4'> => {
18
+ let componentValue
19
+ if (typeof component === 'number') {
20
+ componentValue = component
21
+ } else if ((component as any)?.isConstNode === true) {
22
+ reinterpretType<ConstNode<number>>(component)
23
+ componentValue = component.value
24
+ } else {
25
+ throw new Error('Component must be a constant.')
26
+ }
27
+
28
+ const size = textureNode.size()
29
+ const coord = ivec2(uvNode.mul(size).sub(0.5).floor()).toConst()
30
+ const i = ivec4(coord, coord.add(1)).toConst()
31
+ const c = components[componentValue] // element() fails for depth textures
32
+ return vec4(
33
+ textureNode.load(i.xw)[c], // min, max
34
+ textureNode.load(i.zw)[c], // max, max
35
+ textureNode.load(i.zy)[c], // max, min
36
+ textureNode.load(i.xy)[c] // min, min
37
+ )
38
+ }
39
+ )
40
+
7
41
  // 9-taps version of Catmull-Rom sampling.
8
42
  // Reference: https://gist.github.com/TheRealMJP/c83b8c0f46b63f3a88a5986f4fa982b1
9
43
  export const textureCatmullRom = /*#__PURE__*/ FnVar(
10
- (textureNode: TextureNode, uv: Node<'vec2'>): Node<'vec4'> => {
11
- const size = vec2(textureSize(textureNode))
44
+ (textureNode: TextureNode, uvNode: Node<'vec2'> = uv()): Node<'vec4'> => {
45
+ const size = vec2(textureNode.size())
12
46
  const texelSize = size.reciprocal()
13
- const position = uv.mul(size)
47
+ const position = uvNode.mul(size)
14
48
  const centerPosition = position.sub(0.5).floor().add(0.5)
15
49
 
16
50
  // Compute the fractional offset from our starting texel to our original
@@ -1,4 +1,7 @@
1
+ import type { Camera } from 'three'
1
2
  import {
3
+ cameraFar as cameraFarTSL,
4
+ cameraNear as cameraNearTSL,
2
5
  cos,
3
6
  int,
4
7
  logarithmicDepthToViewZ,
@@ -14,44 +17,54 @@ import {
14
17
  viewZToPerspectiveDepth
15
18
  } from 'three/tsl'
16
19
 
20
+ import { cameraFar, cameraNear } from './accessors'
21
+ import { FnLayout } from './FnLayout'
22
+ import { FnVar } from './FnVar'
17
23
  import type { Node } from './node'
18
24
 
19
- export interface DepthOptions {
20
- perspective?: boolean
21
- logarithmic?: boolean
22
- }
23
-
24
- export const depthToViewZ = (
25
- depth: Node<'float'>,
26
- near: Node<'float'>,
27
- far: Node<'float'>,
28
- { perspective = true, logarithmic = false }: DepthOptions = {}
29
- ): Node<'float'> => {
30
- return logarithmic
31
- ? logarithmicDepthToViewZ(depth, near, far)
32
- : perspective
33
- ? perspectiveDepthToViewZ(depth, near, far)
34
- : orthographicDepthToViewZ(depth, near, far)
35
- }
25
+ export const depthToViewZ = /*#__PURE__*/ FnVar(
26
+ (
27
+ depth: Node<'float'>,
28
+ camera?: Camera | null,
29
+ near?: Node<'float'> | null,
30
+ far?: Node<'float'> | null
31
+ ) =>
32
+ (builder): Node<'float'> => {
33
+ near ??= cameraNear(camera)
34
+ far ??= cameraFar(camera)
35
+ const perspective = camera?.isPerspectiveCamera === true
36
+ const logarithmic = builder.renderer.logarithmicDepthBuffer
37
+ return logarithmic
38
+ ? logarithmicDepthToViewZ(depth, near, far)
39
+ : perspective
40
+ ? perspectiveDepthToViewZ(depth, near, far)
41
+ : orthographicDepthToViewZ(depth, near, far)
42
+ }
43
+ )
36
44
 
37
45
  export const logarithmicToPerspectiveDepth = (
38
46
  depth: Node<'float'>,
39
- near: Node<'float'>,
40
- far: Node<'float'>
47
+ near?: Node<'float'> | null,
48
+ far?: Node<'float'> | null
41
49
  ): Node<'float'> => {
50
+ near ??= cameraNearTSL
51
+ far ??= cameraFarTSL
42
52
  const viewZ = logarithmicDepthToViewZ(depth, near, far)
43
53
  return viewZToPerspectiveDepth(viewZ, near, far)
44
54
  }
45
55
 
46
56
  export const perspectiveToLogarithmicDepth = (
47
57
  depth: Node<'float'>,
48
- near: Node<'float'>,
49
- far: Node<'float'>
58
+ near?: Node<'float'> | null,
59
+ far?: Node<'float'> | null
50
60
  ): Node<'float'> => {
61
+ near ??= cameraNearTSL
62
+ far ??= cameraFarTSL
51
63
  const viewZ = perspectiveDepthToViewZ(depth, near, far)
52
64
  return viewZToLogarithmicDepth(viewZ, near, far)
53
65
  }
54
66
 
67
+ // TODO: Reconsider interface
55
68
  export const screenToPositionView = (
56
69
  uv: Node<'vec2'>,
57
70
  depth: Node<'float'>,
@@ -68,34 +81,48 @@ export const screenToPositionView = (
68
81
 
69
82
  // A fifth-order polynomial approximation of Turbo color map.
70
83
  // See: https://observablehq.com/@mbostock/turbo
71
- const turboCoeffs = [
72
- /*#__PURE__*/ vec3(58.1375, 2.7747, 26.8183),
73
- /*#__PURE__*/ vec3(-150.5666, 4.2109, -88.5066),
74
- /*#__PURE__*/ vec3(130.5887, -14.0195, 109.0745),
75
- /*#__PURE__*/ vec3(-42.3277, 4.8052, -60.1097),
76
- /*#__PURE__*/ vec3(4.5974, 2.1856, 12.5925),
77
- /*#__PURE__*/ vec3(0.1357, 0.0914, 0.1067)
84
+ const turboCoeffs: ReadonlyArray<[number, number, number]> = [
85
+ [58.1375, 2.7747, 26.8183],
86
+ [-150.5666, 4.2109, -88.5066],
87
+ [130.5887, -14.0195, 109.0745],
88
+ [-42.3277, 4.8052, -60.1097],
89
+ [4.5974, 2.1856, 12.5925],
90
+ [0.1357, 0.0914, 0.1067]
78
91
  ]
79
92
 
80
- export const turbo = (x: Node<'float'>): Node<'vec3'> => {
81
- return turboCoeffs
82
- .slice(1)
83
- .reduce<Node>((y, offset) => offset.add(x.mul(y)), turboCoeffs[0])
84
- }
93
+ export const turbo = /*#__PURE__*/ FnLayout({
94
+ name: 'turbo',
95
+ type: 'vec3',
96
+ inputs: [{ name: 'x', type: 'float' }]
97
+ })(([x]) => {
98
+ const y = vec3(...turboCoeffs[0]).toVar()
99
+ for (let i = 1; i < turboCoeffs.length; ++i) {
100
+ y.assign(vec3(...turboCoeffs[i]).add(x.mul(y)))
101
+ }
102
+ return y
103
+ })
85
104
 
86
- export const depthToColor = (
87
- depth: Node<'float'>,
88
- near: Node<'float'>,
89
- far: Node<'float'>,
90
- options?: DepthOptions
91
- ): Node<'vec3'> => {
92
- const viewZ = depthToViewZ(depth, near, far, options)
93
- return turbo(viewZToLogarithmicDepth(viewZ, near, far))
94
- }
105
+ export const depthToColor = FnVar(
106
+ (
107
+ depth: Node<'float'>,
108
+ camera?: Camera,
109
+ near?: Node<'float'>,
110
+ far?: Node<'float'>
111
+ ): Node<'vec3'> => {
112
+ near ??= cameraNear(camera)
113
+ far ??= cameraFar(camera)
114
+ const viewZ = depthToViewZ(depth, camera, near, far)
115
+ return turbo(viewZToLogarithmicDepth(viewZ, near, far))
116
+ }
117
+ )
95
118
 
96
- export const equirectToDirectionWorld = (uv: Node<'vec2'>): Node<'vec3'> => {
119
+ export const equirectToDirectionWorld = /*#__PURE__*/ FnLayout({
120
+ name: 'equirectToDirectionWorld',
121
+ type: 'vec3',
122
+ inputs: [{ name: 'uv', type: 'vec2' }]
123
+ })(([uv]) => {
97
124
  const lambda = sub(0.5, uv.x).mul(PI2)
98
125
  const phi = sub(uv.y, 0.5).mul(PI)
99
126
  const cosPhi = cos(phi)
100
127
  return vec3(cosPhi.mul(cos(lambda)), sin(phi), cosPhi.mul(sin(lambda)))
101
- }
128
+ })
@@ -15,5 +15,5 @@ export declare class PointOfView {
15
15
  copy(other: PointOfView): this;
16
16
  equals(other: PointOfView): boolean;
17
17
  decompose(target: Vector3, eye: Vector3, quaternion: Quaternion, up?: Vector3, ellipsoid?: Ellipsoid): void;
18
- setFromCamera(camera: Camera, ellipsoid?: Ellipsoid): this | undefined;
18
+ setFromCamera(camera: Camera, ellipsoid?: Ellipsoid, target?: Vector3): this | undefined;
19
19
  }
@@ -1,5 +1,4 @@
1
- import { Data3DTexture, LoadingManager } from 'three';
2
- import { DataTextureLoader } from './DataTextureLoader';
3
- export declare class STBNLoader extends DataTextureLoader<Data3DTexture> {
4
- constructor(manager?: LoadingManager);
1
+ import { Data3DTexture, Loader } from 'three';
2
+ export declare class STBNLoader extends Loader<Data3DTexture> {
3
+ load(url: string, onLoad?: (data: Data3DTexture) => void, onProgress?: (event: ProgressEvent) => void, onError?: (error: unknown) => void): Data3DTexture;
5
4
  }