@takram/three-geospatial 0.8.0 → 0.9.1
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 +29 -0
- package/build/index.cjs +1 -1
- package/build/index.cjs.map +1 -1
- package/build/index.js +580 -598
- package/build/index.js.map +1 -1
- package/build/r3f.cjs +1 -1
- package/build/r3f.js +1 -1
- package/build/shared2.cjs +1 -1
- package/build/shared2.cjs.map +1 -1
- package/build/shared2.js +27 -212
- package/build/shared2.js.map +1 -1
- package/build/shared3.cjs +1 -1
- package/build/shared3.cjs.map +1 -1
- package/build/shared3.js +213 -8
- package/build/shared3.js.map +1 -1
- package/build/webgpu.cjs +6 -1
- package/build/webgpu.cjs.map +1 -1
- package/build/webgpu.js +1002 -812
- package/build/webgpu.js.map +1 -1
- package/package.json +1 -1
- package/src/PointOfView.ts +12 -5
- package/src/STBNLoader.ts +41 -19
- package/src/webgpu/CascadedShadowMapsNode.ts +48 -0
- package/src/webgpu/DualMipmapFilterNode.ts +8 -4
- package/src/webgpu/FilterNode.ts +3 -2
- package/src/webgpu/FnLayout.ts +17 -16
- package/src/webgpu/HighpVelocityNode.ts +2 -2
- package/src/webgpu/LensFlareNode.ts +1 -1
- package/src/webgpu/LensGlareNode.ts +26 -26
- package/src/webgpu/LensHaloNode.ts +2 -1
- package/src/webgpu/OutputTexture3DNode.ts +10 -1
- package/src/webgpu/OutputTextureNode.ts +10 -1
- package/src/webgpu/STBNTextureNode.ts +72 -0
- package/src/webgpu/ScreenSpaceShadowNode.ts +30 -35
- package/src/webgpu/SeparableFilterNode.ts +8 -5
- package/src/webgpu/SingleFilterNode.ts +5 -2
- package/src/webgpu/StorageTexture3DNode.ts +30 -0
- package/src/webgpu/TemporalAntialiasNode.ts +50 -31
- package/src/webgpu/accessors.ts +72 -36
- package/src/webgpu/debug.ts +38 -47
- package/src/webgpu/events.ts +18 -0
- package/src/webgpu/index.ts +4 -0
- package/src/webgpu/math.ts +116 -15
- package/src/webgpu/sampling.ts +39 -5
- package/src/webgpu/transformations.ts +71 -44
- package/types/PointOfView.d.ts +1 -1
- package/types/STBNLoader.d.ts +3 -4
- package/types/webgpu/CascadedShadowMapsNode.d.ts +13 -0
- package/types/webgpu/DualMipmapFilterNode.d.ts +1 -2
- package/types/webgpu/FnLayout.d.ts +4 -4
- package/types/webgpu/LensGlareNode.d.ts +1 -1
- package/types/webgpu/STBNTextureNode.d.ts +10 -0
- package/types/webgpu/ScreenSpaceShadowNode.d.ts +2 -4
- package/types/webgpu/SeparableFilterNode.d.ts +2 -3
- package/types/webgpu/SingleFilterNode.d.ts +1 -2
- package/types/webgpu/StorageTexture3DNode.d.ts +9 -0
- package/types/webgpu/TemporalAntialiasNode.d.ts +1 -1
- package/types/webgpu/accessors.d.ts +9 -8
- package/types/webgpu/debug.d.ts +4 -3
- package/types/webgpu/events.d.ts +3 -0
- package/types/webgpu/index.d.ts +4 -0
- package/types/webgpu/math.d.ts +3 -0
- package/types/webgpu/sampling.d.ts +2 -1
- package/types/webgpu/transformations.d.ts +7 -10
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
mix,
|
|
21
21
|
screenCoordinate,
|
|
22
22
|
screenUV,
|
|
23
|
-
select,
|
|
24
23
|
sqrt,
|
|
25
24
|
step,
|
|
26
25
|
struct,
|
|
@@ -77,8 +76,15 @@ function isSupportedCamera(camera: Camera): camera is SupportedCamera {
|
|
|
77
76
|
)
|
|
78
77
|
}
|
|
79
78
|
|
|
79
|
+
interface RenderPipelineContext {
|
|
80
|
+
context: {
|
|
81
|
+
onBeforeRenderPipeline?: () => void
|
|
82
|
+
onAfterRenderPipeline?: () => void
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
80
86
|
interface PostProcessingContext {
|
|
81
|
-
context
|
|
87
|
+
context: {
|
|
82
88
|
onBeforePostProcessing?: () => void
|
|
83
89
|
onAfterPostProcessing?: () => void
|
|
84
90
|
}
|
|
@@ -101,11 +107,9 @@ const clipAABB = /*#__PURE__*/ FnLayout({
|
|
|
101
107
|
const vUnit = vClip.xyz.div(eClip)
|
|
102
108
|
const absUnit = vUnit.abs().toConst()
|
|
103
109
|
const maxUnit = max(absUnit.x, absUnit.y, absUnit.z).toConst()
|
|
104
|
-
return
|
|
105
|
-
|
|
106
|
-
vec4(pClip, current.a).add(vClip.div(maxUnit)),
|
|
107
|
-
history
|
|
108
|
-
)
|
|
110
|
+
return maxUnit
|
|
111
|
+
.greaterThan(1)
|
|
112
|
+
.select(vec4(pClip, current.a).add(vClip.div(maxUnit)), history)
|
|
109
113
|
})
|
|
110
114
|
|
|
111
115
|
const varianceOffsets = [
|
|
@@ -166,12 +170,17 @@ const currentDepthStruct = /*#__PURE__*/ struct({
|
|
|
166
170
|
})
|
|
167
171
|
|
|
168
172
|
const getCurrentDepth = /*#__PURE__*/ FnVar(
|
|
169
|
-
(depthNode: TextureNode, inputCoord: Node<'ivec2'>) => {
|
|
173
|
+
(depthNode: TextureNode, inputCoord: Node<'ivec2'>) => builder => {
|
|
170
174
|
const closestCoord = ivec2(0).toVar()
|
|
171
175
|
const closestDepth = float(1).toVar()
|
|
172
176
|
for (const [x, y] of neighborOffsets) {
|
|
173
177
|
const neighbor = inputCoord.add(ivec2(x, y)).toConst()
|
|
174
|
-
|
|
178
|
+
let depth = depthNode.load(neighbor).r
|
|
179
|
+
if (builder.renderer.reversedDepthBuffer) {
|
|
180
|
+
depth = depth.oneMinus()
|
|
181
|
+
}
|
|
182
|
+
depth = depth.toConst()
|
|
183
|
+
|
|
175
184
|
If(depth.lessThan(closestDepth), () => {
|
|
176
185
|
closestCoord.assign(neighbor)
|
|
177
186
|
closestDepth.assign(depth)
|
|
@@ -181,7 +190,7 @@ const getCurrentDepth = /*#__PURE__*/ FnVar(
|
|
|
181
190
|
}
|
|
182
191
|
)
|
|
183
192
|
|
|
184
|
-
const subpixelCorrection = FnVar(
|
|
193
|
+
const subpixelCorrection = /*#__PURE__#*/ FnVar(
|
|
185
194
|
(velocityUV: Node<'vec2'>, textureSize: Node<'ivec2'>): Node<'float'> => {
|
|
186
195
|
const velocityTexel = velocityUV.mul(textureSize)
|
|
187
196
|
const phase = velocityTexel.fract().abs()
|
|
@@ -236,18 +245,17 @@ export class TemporalAntialiasNode extends TempNode {
|
|
|
236
245
|
velocityThreshold = uniform(0.1)
|
|
237
246
|
depthError = uniform(0.001)
|
|
238
247
|
|
|
239
|
-
// Static options:
|
|
240
248
|
debugShowRejection = false
|
|
241
249
|
|
|
242
250
|
private readonly textureNode: TextureNode
|
|
243
251
|
|
|
244
|
-
private resolveRT = this.createRenderTarget('
|
|
245
|
-
private historyRT = this.createRenderTarget('
|
|
252
|
+
private resolveRT = this.createRenderTarget('resolve')
|
|
253
|
+
private historyRT = this.createRenderTarget('history')
|
|
246
254
|
private previousDepthTexture?: DepthTexture
|
|
247
255
|
private readonly resolveMaterial = new NodeMaterial()
|
|
248
256
|
private readonly mesh = new QuadMesh()
|
|
249
257
|
private rendererState?: RendererUtils.RendererState
|
|
250
|
-
private
|
|
258
|
+
private needsSyncRenderPipeline = false
|
|
251
259
|
private needsClearHistory = false
|
|
252
260
|
|
|
253
261
|
private readonly resolveNode = texture(this.resolveRT.texture)
|
|
@@ -263,6 +271,10 @@ export class TemporalAntialiasNode extends TempNode {
|
|
|
263
271
|
camera: Camera
|
|
264
272
|
) {
|
|
265
273
|
super('vec4')
|
|
274
|
+
this.updateBeforeType = NodeUpdateType.FRAME
|
|
275
|
+
this.resolveMaterial.name = 'TemporalAntialias_resolve'
|
|
276
|
+
this.mesh.name = 'TemporalAntialias'
|
|
277
|
+
|
|
266
278
|
this.inputNode = inputNode
|
|
267
279
|
this.depthNode = depthNode
|
|
268
280
|
this.velocityNode = velocityNode
|
|
@@ -272,8 +284,6 @@ export class TemporalAntialiasNode extends TempNode {
|
|
|
272
284
|
this.camera = camera
|
|
273
285
|
|
|
274
286
|
this.textureNode = outputTexture(this, this.resolveRT.texture)
|
|
275
|
-
|
|
276
|
-
this.updateBeforeType = NodeUpdateType.FRAME
|
|
277
287
|
}
|
|
278
288
|
|
|
279
289
|
override customCacheKey(): number {
|
|
@@ -292,7 +302,7 @@ export class TemporalAntialiasNode extends TempNode {
|
|
|
292
302
|
texture.generateMipmaps = false
|
|
293
303
|
|
|
294
304
|
const typeName = (this.constructor as typeof Node).type
|
|
295
|
-
texture.name = name != null ? `${typeName}
|
|
305
|
+
texture.name = name != null ? `${typeName}_${name}` : typeName
|
|
296
306
|
|
|
297
307
|
return renderTarget
|
|
298
308
|
}
|
|
@@ -402,7 +412,7 @@ export class TemporalAntialiasNode extends TempNode {
|
|
|
402
412
|
this.swapBuffers()
|
|
403
413
|
|
|
404
414
|
// Don't jitter the camera in subsequent render passes if any:
|
|
405
|
-
if (this.
|
|
415
|
+
if (this.needsSyncRenderPipeline) {
|
|
406
416
|
this.clearViewOffset()
|
|
407
417
|
}
|
|
408
418
|
}
|
|
@@ -411,7 +421,7 @@ export class TemporalAntialiasNode extends TempNode {
|
|
|
411
421
|
const getPreviousDepth = (uv: Node<'vec2'>): Node<'float'> => {
|
|
412
422
|
const { previousDepthNode: depthNode } = this
|
|
413
423
|
const depth = depthNode
|
|
414
|
-
.load(ivec2(uv.mul(
|
|
424
|
+
.load(ivec2(uv.mul(depthNode.size()).sub(0.5)))
|
|
415
425
|
.toConst()
|
|
416
426
|
return renderer.logarithmicDepthBuffer
|
|
417
427
|
? logarithmicToPerspectiveDepth(
|
|
@@ -419,7 +429,9 @@ export class TemporalAntialiasNode extends TempNode {
|
|
|
419
429
|
cameraNear(this.camera),
|
|
420
430
|
cameraFar(this.camera)
|
|
421
431
|
)
|
|
422
|
-
:
|
|
432
|
+
: renderer.reversedDepthBuffer
|
|
433
|
+
? depth.oneMinus()
|
|
434
|
+
: depth
|
|
423
435
|
}
|
|
424
436
|
|
|
425
437
|
return Fn(() => {
|
|
@@ -485,7 +497,7 @@ export class TemporalAntialiasNode extends TempNode {
|
|
|
485
497
|
// Reference: https://github.com/simco50/D3D12_Research/
|
|
486
498
|
const temporalAlpha = mix(
|
|
487
499
|
this.temporalAlpha,
|
|
488
|
-
0.
|
|
500
|
+
0.4,
|
|
489
501
|
subpixelCorrection(velocityUVW.xy, textureSize(this.inputNode))
|
|
490
502
|
).saturate()
|
|
491
503
|
|
|
@@ -501,16 +513,23 @@ export class TemporalAntialiasNode extends TempNode {
|
|
|
501
513
|
}
|
|
502
514
|
|
|
503
515
|
override setup(builder: NodeBuilder): unknown {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
516
|
+
// We have to take care of the renaming of PostProcessing to RenderPipeline
|
|
517
|
+
// in r183, as well as changes to property fields in the context.
|
|
518
|
+
const onBeforeRenderPipeline = (): void => {
|
|
519
|
+
const size = builder.renderer.getDrawingBufferSize(sizeScratch)
|
|
520
|
+
this.setViewOffset(size.width, size.height)
|
|
521
|
+
}
|
|
522
|
+
if (builder.context.renderPipeline != null) {
|
|
523
|
+
const { context } = builder.context
|
|
524
|
+
.renderPipeline as RenderPipelineContext
|
|
525
|
+
context.onBeforeRenderPipeline = onBeforeRenderPipeline
|
|
526
|
+
this.needsSyncRenderPipeline = true
|
|
527
|
+
}
|
|
528
|
+
if (builder.context.postProcessing != null) {
|
|
529
|
+
const { context } = builder.context
|
|
530
|
+
.postProcessing as PostProcessingContext
|
|
531
|
+
context.onBeforePostProcessing = onBeforeRenderPipeline
|
|
532
|
+
this.needsSyncRenderPipeline = true
|
|
514
533
|
}
|
|
515
534
|
|
|
516
535
|
const { resolveMaterial } = this
|
package/src/webgpu/accessors.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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
|
+
Fn,
|
|
11
|
+
positionView,
|
|
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'
|
|
@@ -23,43 +35,67 @@ function getCache<T extends {}, U extends {}>(
|
|
|
23
35
|
return (cache[name] ??= callback()) as U
|
|
24
36
|
}
|
|
25
37
|
|
|
26
|
-
export const projectionMatrix = (camera
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
export const projectionMatrix = (camera?: Camera | null): Node<'mat4'> =>
|
|
39
|
+
camera != null
|
|
40
|
+
? getCache(camera, 'projectionMatrix', () =>
|
|
41
|
+
reference('projectionMatrix', 'mat4', camera).setName(
|
|
42
|
+
'projectionMatrix'
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
: cameraProjectionMatrix
|
|
30
46
|
|
|
31
|
-
export const viewMatrix = (camera
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
47
|
+
export const viewMatrix = (camera?: Camera | null): Node<'mat4'> =>
|
|
48
|
+
camera != null
|
|
49
|
+
? getCache(camera, 'viewMatrix', () =>
|
|
50
|
+
reference('matrixWorldInverse', 'mat4', camera).setName('viewMatrix')
|
|
51
|
+
)
|
|
52
|
+
: cameraViewMatrix
|
|
35
53
|
|
|
36
|
-
export const inverseProjectionMatrix = (
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
)
|
|
41
|
-
|
|
54
|
+
export const inverseProjectionMatrix = (
|
|
55
|
+
camera?: Camera | null
|
|
56
|
+
): Node<'mat4'> =>
|
|
57
|
+
camera != null
|
|
58
|
+
? getCache(camera, 'inverseProjectionMatrix', () =>
|
|
59
|
+
reference('projectionMatrixInverse', 'mat4', camera).setName(
|
|
60
|
+
'inverseProjectionMatrix'
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
: cameraProjectionMatrixInverse
|
|
42
64
|
|
|
43
|
-
export const inverseViewMatrix = (camera
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
65
|
+
export const inverseViewMatrix = (camera?: Camera | null): Node<'mat4'> =>
|
|
66
|
+
camera != null
|
|
67
|
+
? getCache(camera, 'inverseViewMatrix', () =>
|
|
68
|
+
reference('matrixWorld', 'mat4', camera).setName('inverseViewMatrix')
|
|
69
|
+
)
|
|
70
|
+
: cameraWorldMatrix // TODO: Not always
|
|
47
71
|
|
|
48
|
-
export const cameraPositionWorld = (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
72
|
+
export const cameraPositionWorld = (
|
|
73
|
+
camera?: Camera | null
|
|
74
|
+
): UniformNode<Vector3> =>
|
|
75
|
+
camera != null
|
|
76
|
+
? getCache(camera, 'cameraPositionWorld', () =>
|
|
77
|
+
uniform('vec3')
|
|
78
|
+
.setName('cameraPositionWorld')
|
|
79
|
+
.onRenderUpdate((_, { value }) => {
|
|
80
|
+
value.setFromMatrixPosition(camera.matrixWorld)
|
|
81
|
+
})
|
|
82
|
+
)
|
|
83
|
+
: cameraPosition
|
|
56
84
|
|
|
57
|
-
export const cameraNear = (camera
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
85
|
+
export const cameraNear = (camera?: Camera | null): Node<'float'> =>
|
|
86
|
+
camera != null
|
|
87
|
+
? getCache(camera, 'cameraNear', () =>
|
|
88
|
+
reference('near', 'float', camera).setName('cameraNear')
|
|
89
|
+
)
|
|
90
|
+
: cameraNearTSL
|
|
61
91
|
|
|
62
|
-
export const cameraFar = (camera
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
92
|
+
export const cameraFar = (camera?: Camera | null): Node<'float'> =>
|
|
93
|
+
camera != null
|
|
94
|
+
? getCache(camera, 'cameraFar', () =>
|
|
95
|
+
reference('far', 'float', camera).setName('cameraFar')
|
|
96
|
+
)
|
|
97
|
+
: cameraFarTSL
|
|
98
|
+
|
|
99
|
+
export const viewZ = Fn((): Node<'float'> => positionView.z)
|
|
100
|
+
.once()()
|
|
101
|
+
.toVar('viewZ')
|
package/src/webgpu/debug.ts
CHANGED
|
@@ -6,65 +6,56 @@ import { QuadGeometry } from '../QuadGeometry'
|
|
|
6
6
|
|
|
7
7
|
async function debugShader(
|
|
8
8
|
renderer: Renderer,
|
|
9
|
-
|
|
10
|
-
): Promise<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
.
|
|
22
|
-
|
|
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
|
|
25
|
+
export async function debugMaterial(
|
|
28
26
|
renderer: Renderer,
|
|
29
27
|
material: NodeMaterial
|
|
30
|
-
):
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
):
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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(
|
|
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
|
|
60
|
-
|
|
61
|
-
|
|
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
|
+
}
|
package/src/webgpu/index.ts
CHANGED
|
@@ -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'
|
|
@@ -16,6 +18,8 @@ export * from './OutputTexture3DNode'
|
|
|
16
18
|
export * from './OutputTextureNode'
|
|
17
19
|
export * from './sampling'
|
|
18
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'
|
package/src/webgpu/math.ts
CHANGED
|
@@ -1,8 +1,110 @@
|
|
|
1
|
-
import {
|
|
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).
|
|
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
|
-
|
|
31
|
-
'
|
|
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).
|
|
147
|
+
const discriminant = b.pow2().sub(c).toConst()
|
|
46
148
|
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
.
|
|
173
|
+
.toConst()
|
|
73
174
|
|
|
74
175
|
const intersections = vec2(-1)
|
|
75
176
|
If(discriminant.greaterThanEqual(0), () => {
|
package/src/webgpu/sampling.ts
CHANGED
|
@@ -1,16 +1,50 @@
|
|
|
1
|
-
import { add, sub,
|
|
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,
|
|
11
|
-
const size = vec2(
|
|
44
|
+
(textureNode: TextureNode, uvNode: Node<'vec2'> = uv()): Node<'vec4'> => {
|
|
45
|
+
const size = vec2(textureNode.size())
|
|
12
46
|
const texelSize = size.reciprocal()
|
|
13
|
-
const position =
|
|
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
|