@luma.gl/engine 9.1.0-alpha.9 → 9.1.0-beta.11

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 (194) hide show
  1. package/dist/animation/key-frames.js +1 -0
  2. package/dist/animation/key-frames.js.map +1 -0
  3. package/dist/animation/timeline.js +1 -0
  4. package/dist/animation/timeline.js.map +1 -0
  5. package/dist/animation-loop/animation-loop-template.js +1 -0
  6. package/dist/animation-loop/animation-loop-template.js.map +1 -0
  7. package/dist/animation-loop/animation-loop.d.ts +2 -0
  8. package/dist/animation-loop/animation-loop.d.ts.map +1 -1
  9. package/dist/animation-loop/animation-loop.js +24 -6
  10. package/dist/animation-loop/animation-loop.js.map +1 -0
  11. package/dist/animation-loop/animation-props.js +1 -0
  12. package/dist/animation-loop/animation-props.js.map +1 -0
  13. package/dist/animation-loop/make-animation-loop.d.ts +5 -1
  14. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
  15. package/dist/animation-loop/make-animation-loop.js +3 -1
  16. package/dist/animation-loop/make-animation-loop.js.map +1 -0
  17. package/dist/animation-loop/request-animation-frame.d.ts +4 -2
  18. package/dist/animation-loop/request-animation-frame.d.ts.map +1 -1
  19. package/dist/animation-loop/request-animation-frame.js +5 -3
  20. package/dist/animation-loop/request-animation-frame.js.map +1 -0
  21. package/dist/application-utils/load-file.d.ts +1 -1
  22. package/dist/application-utils/load-file.d.ts.map +1 -1
  23. package/dist/application-utils/load-file.js +2 -2
  24. package/dist/application-utils/load-file.js.map +1 -0
  25. package/dist/application-utils/random.js +1 -0
  26. package/dist/application-utils/random.js.map +1 -0
  27. package/dist/async-texture/async-texture.d.ts +14 -2
  28. package/dist/async-texture/async-texture.d.ts.map +1 -1
  29. package/dist/async-texture/async-texture.js +31 -0
  30. package/dist/async-texture/async-texture.js.map +1 -0
  31. package/dist/compute/buffer-transform.d.ts +41 -0
  32. package/dist/compute/buffer-transform.d.ts.map +1 -0
  33. package/dist/{transform → compute}/buffer-transform.js +19 -12
  34. package/dist/compute/buffer-transform.js.map +1 -0
  35. package/dist/{computation.d.ts → compute/computation.d.ts} +3 -3
  36. package/dist/compute/computation.d.ts.map +1 -0
  37. package/dist/{computation.js → compute/computation.js} +7 -8
  38. package/dist/compute/computation.js.map +1 -0
  39. package/dist/compute/swap.d.ts +48 -0
  40. package/dist/compute/swap.d.ts.map +1 -0
  41. package/dist/compute/swap.js +91 -0
  42. package/dist/compute/swap.js.map +1 -0
  43. package/dist/{transform → compute}/texture-transform.d.ts +0 -6
  44. package/dist/compute/texture-transform.d.ts.map +1 -0
  45. package/dist/{transform → compute}/texture-transform.js +7 -13
  46. package/dist/compute/texture-transform.js.map +1 -0
  47. package/dist/debug/copy-texture-to-image.js +1 -0
  48. package/dist/debug/copy-texture-to-image.js.map +1 -0
  49. package/dist/debug/debug-framebuffer.js +2 -1
  50. package/dist/debug/debug-framebuffer.js.map +1 -0
  51. package/dist/debug/debug-shader-layout.js +2 -1
  52. package/dist/debug/debug-shader-layout.js.map +1 -0
  53. package/dist/debug/pixel-data-utils.js +1 -0
  54. package/dist/debug/pixel-data-utils.js.map +1 -0
  55. package/dist/dist.dev.js +2588 -5862
  56. package/dist/dist.min.js +420 -103
  57. package/dist/factories/pipeline-factory.d.ts.map +1 -0
  58. package/dist/{lib → factories}/pipeline-factory.js +1 -0
  59. package/dist/factories/pipeline-factory.js.map +1 -0
  60. package/dist/factories/shader-factory.d.ts.map +1 -0
  61. package/dist/{lib → factories}/shader-factory.js +1 -0
  62. package/dist/factories/shader-factory.js.map +1 -0
  63. package/dist/geometries/cone-geometry.js +1 -0
  64. package/dist/geometries/cone-geometry.js.map +1 -0
  65. package/dist/geometries/cube-geometry.js +1 -0
  66. package/dist/geometries/cube-geometry.js.map +1 -0
  67. package/dist/geometries/cylinder-geometry.js +1 -0
  68. package/dist/geometries/cylinder-geometry.js.map +1 -0
  69. package/dist/geometries/ico-sphere-geometry.js +1 -0
  70. package/dist/geometries/ico-sphere-geometry.js.map +1 -0
  71. package/dist/geometries/plane-geometry.js +1 -0
  72. package/dist/geometries/plane-geometry.js.map +1 -0
  73. package/dist/geometries/sphere-geometry.js +1 -0
  74. package/dist/geometries/sphere-geometry.js.map +1 -0
  75. package/dist/geometries/truncated-cone-geometry.js +1 -0
  76. package/dist/geometries/truncated-cone-geometry.js.map +1 -0
  77. package/dist/geometry/geometry-table.js +1 -0
  78. package/dist/geometry/geometry-table.js.map +1 -0
  79. package/dist/geometry/geometry-utils.js +1 -0
  80. package/dist/geometry/geometry-utils.js.map +1 -0
  81. package/dist/geometry/geometry.js +1 -0
  82. package/dist/geometry/geometry.js.map +1 -0
  83. package/dist/geometry/gpu-geometry.js +1 -0
  84. package/dist/geometry/gpu-geometry.js.map +1 -0
  85. package/dist/geometry/gpu-table.js +1 -0
  86. package/dist/geometry/gpu-table.js.map +1 -0
  87. package/dist/index.cjs +1268 -173
  88. package/dist/index.cjs.map +4 -4
  89. package/dist/index.d.ts +23 -12
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +19 -9
  92. package/dist/index.js.map +1 -0
  93. package/dist/model/model.d.ts +11 -10
  94. package/dist/model/model.d.ts.map +1 -1
  95. package/dist/model/model.js +77 -58
  96. package/dist/model/model.js.map +1 -0
  97. package/dist/model/split-uniforms-and-bindings.d.ts +1 -1
  98. package/dist/model/split-uniforms-and-bindings.d.ts.map +1 -1
  99. package/dist/model/split-uniforms-and-bindings.js +2 -1
  100. package/dist/model/split-uniforms-and-bindings.js.map +1 -0
  101. package/dist/models/billboard-texture-model.d.ts +23 -0
  102. package/dist/models/billboard-texture-model.d.ts.map +1 -0
  103. package/dist/models/billboard-texture-model.js +78 -0
  104. package/dist/models/billboard-texture-model.js.map +1 -0
  105. package/dist/models/billboard-texture-module.d.ts +10 -0
  106. package/dist/models/billboard-texture-module.d.ts.map +1 -0
  107. package/dist/models/billboard-texture-module.js +37 -0
  108. package/dist/models/billboard-texture-module.js.map +1 -0
  109. package/dist/{lib → models}/clip-space.d.ts +3 -1
  110. package/dist/models/clip-space.d.ts.map +1 -0
  111. package/dist/models/clip-space.js +77 -0
  112. package/dist/models/clip-space.js.map +1 -0
  113. package/dist/modules/picking/color-picking.d.ts +28 -0
  114. package/dist/modules/picking/color-picking.d.ts.map +1 -0
  115. package/dist/modules/picking/color-picking.js +177 -0
  116. package/dist/modules/picking/color-picking.js.map +1 -0
  117. package/dist/modules/picking/index-picking.d.ts +32 -0
  118. package/dist/modules/picking/index-picking.d.ts.map +1 -0
  119. package/dist/modules/picking/index-picking.js +148 -0
  120. package/dist/modules/picking/index-picking.js.map +1 -0
  121. package/dist/modules/picking/legacy-picking-manager.d.ts +27 -0
  122. package/dist/modules/picking/legacy-picking-manager.d.ts.map +1 -0
  123. package/dist/modules/picking/legacy-picking-manager.js +76 -0
  124. package/dist/modules/picking/legacy-picking-manager.js.map +1 -0
  125. package/dist/modules/picking/picking-manager.d.ts +45 -0
  126. package/dist/modules/picking/picking-manager.d.ts.map +1 -0
  127. package/dist/modules/picking/picking-manager.js +101 -0
  128. package/dist/modules/picking/picking-manager.js.map +1 -0
  129. package/dist/modules/picking/picking-uniforms.d.ts +79 -0
  130. package/dist/modules/picking/picking-uniforms.d.ts.map +1 -0
  131. package/dist/modules/picking/picking-uniforms.js +109 -0
  132. package/dist/modules/picking/picking-uniforms.js.map +1 -0
  133. package/dist/passes/get-fragment-shader.d.ts +12 -0
  134. package/dist/passes/get-fragment-shader.d.ts.map +1 -0
  135. package/dist/passes/get-fragment-shader.js +117 -0
  136. package/dist/passes/get-fragment-shader.js.map +1 -0
  137. package/dist/passes/shader-pass-renderer.d.ts +63 -0
  138. package/dist/passes/shader-pass-renderer.d.ts.map +1 -0
  139. package/dist/passes/shader-pass-renderer.js +197 -0
  140. package/dist/passes/shader-pass-renderer.js.map +1 -0
  141. package/dist/scenegraph/group-node.js +1 -0
  142. package/dist/scenegraph/group-node.js.map +1 -0
  143. package/dist/scenegraph/model-node.js +1 -0
  144. package/dist/scenegraph/model-node.js.map +1 -0
  145. package/dist/scenegraph/scenegraph-node.js +1 -0
  146. package/dist/scenegraph/scenegraph-node.js.map +1 -0
  147. package/dist/shader-inputs.d.ts +8 -21
  148. package/dist/shader-inputs.d.ts.map +1 -1
  149. package/dist/shader-inputs.js +15 -11
  150. package/dist/shader-inputs.js.map +1 -0
  151. package/dist/utils/deep-equal.js +1 -0
  152. package/dist/utils/deep-equal.js.map +1 -0
  153. package/dist/utils/uid.js +1 -0
  154. package/dist/utils/uid.js.map +1 -0
  155. package/package.json +6 -6
  156. package/src/animation-loop/animation-loop.ts +27 -6
  157. package/src/animation-loop/make-animation-loop.ts +8 -3
  158. package/src/animation-loop/request-animation-frame.ts +4 -3
  159. package/src/application-utils/load-file.ts +2 -4
  160. package/src/async-texture/async-texture.ts +39 -7
  161. package/src/{transform → compute}/buffer-transform.ts +30 -14
  162. package/src/{computation.ts → compute/computation.ts} +14 -8
  163. package/src/compute/swap.ts +116 -0
  164. package/src/{transform → compute}/texture-transform.ts +6 -16
  165. package/src/debug/debug-framebuffer.ts +1 -1
  166. package/src/debug/debug-shader-layout.ts +1 -1
  167. package/src/index.ts +35 -16
  168. package/src/model/model.ts +116 -66
  169. package/src/model/split-uniforms-and-bindings.ts +4 -4
  170. package/src/models/billboard-texture-model.ts +98 -0
  171. package/src/models/billboard-texture-module.ts +49 -0
  172. package/src/models/clip-space.ts +88 -0
  173. package/src/modules/picking/README.md +88 -0
  174. package/src/modules/picking/color-picking.ts +190 -0
  175. package/src/modules/picking/index-picking.ts +156 -0
  176. package/src/modules/picking/legacy-picking-manager.ts +99 -0
  177. package/src/modules/picking/picking-manager.ts +137 -0
  178. package/src/modules/picking/picking-uniforms.ts +179 -0
  179. package/src/passes/get-fragment-shader.ts +129 -0
  180. package/src/passes/shader-pass-renderer.ts +252 -0
  181. package/src/shader-inputs.ts +27 -48
  182. package/dist/computation.d.ts.map +0 -1
  183. package/dist/lib/clip-space.d.ts.map +0 -1
  184. package/dist/lib/clip-space.js +0 -46
  185. package/dist/lib/pipeline-factory.d.ts.map +0 -1
  186. package/dist/lib/shader-factory.d.ts.map +0 -1
  187. package/dist/transform/buffer-transform.d.ts +0 -35
  188. package/dist/transform/buffer-transform.d.ts.map +0 -1
  189. package/dist/transform/texture-transform.d.ts.map +0 -1
  190. package/src/lib/clip-space.ts +0 -53
  191. /package/dist/{lib → factories}/pipeline-factory.d.ts +0 -0
  192. /package/dist/{lib → factories}/shader-factory.d.ts +0 -0
  193. /package/src/{lib → factories}/pipeline-factory.ts +0 -0
  194. /package/src/{lib → factories}/shader-factory.ts +0 -0
@@ -0,0 +1,179 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {NumberArray4} from '@math.gl/types';
6
+ import type {ShaderModule} from '@luma.gl/shadertools';
7
+
8
+ /** Default color for auto highlight, a cyan color */
9
+ const DEFAULT_HIGHLIGHT_COLOR: NumberArray4 = [0, 1, 1, 1];
10
+
11
+ export const INVALID_INDEX = -1;
12
+
13
+ /**
14
+ * Props for the picking module, which depending on mode renders picking colors or highlighted item.
15
+ * When active, renders picking colors, assumed to be rendered to off-screen "picking" buffer.
16
+ * When inactive, renders normal colors, with the exception of selected object which is rendered with highlight
17
+ * can distinguish between 2^32 different objects in each of 2^32 different batches.
18
+ */
19
+ export type PickingProps = {
20
+ /** Are we picking? I.e. rendering picking colors? */
21
+ isActive?: boolean;
22
+ /** Whether to use instance_index (built-in) or a custom application supplied index (usually from an attribute) */
23
+ indexMode?: 'instance' | 'custom';
24
+ /** Batch index (used when rendering multiple models to identify which model was picked), defaults to 0 */
25
+ batchIndex?: number;
26
+
27
+ /** Index of the highlighted batch, defaults to 0 */
28
+ highlightedBatchIndex?: number | null;
29
+ /** Set an index to highlight that item, or `null` to explicitly clear **/
30
+ highlightedObjectIndex?: number | null;
31
+ /** Color of visual highlight of "selected" item () */
32
+ highlightColor?: NumberArray4;
33
+ };
34
+
35
+ /**
36
+ * Uniforms for the picking module, which renders picking colors and highlighted item.
37
+ * When active, renders picking colors, assumed to be rendered to off-screen "picking" buffer.
38
+ * When inactive, renders normal colors, with the exception of selected object which is rendered with highlight
39
+ */
40
+ export type PickingUniforms = {
41
+ /**
42
+ * When true, renders picking colors. Set when rendering to off-screen "picking" buffer.
43
+ * When false, renders normal colors, with the exception of selected object which is rendered with highlight
44
+ */
45
+ isActive: boolean;
46
+ /** Set to true when picking an attribute value instead of object index */
47
+ indexMode: 0 | 1;
48
+ /** Index of batch currently being rendered */
49
+ batchIndex: number;
50
+
51
+ /** Do we have a highlighted item? */
52
+ isHighlightActive: boolean;
53
+ /** Color of visual highlight of "selected" item. Note: RGBA components must in the range 0-1 */
54
+ highlightColor: NumberArray4;
55
+ /** Indicates which batch to visually highlight an item in (defaults to 0) */
56
+ highlightedBatchIndex: number;
57
+ /** Indicates which index in the batch to highlight an item in */
58
+ highlightedObjectIndex: number;
59
+ };
60
+
61
+ export type PickingBindings = {};
62
+
63
+ // GLSL_UNIFORMS
64
+
65
+ const uniformTypes: Required<ShaderModule<PickingProps, PickingUniforms>>['uniformTypes'] = {
66
+ isActive: 'i32',
67
+ indexMode: 'i32',
68
+ batchIndex: 'i32',
69
+
70
+ isHighlightActive: 'i32',
71
+ highlightedBatchIndex: 'i32',
72
+ highlightedObjectIndex: 'i32',
73
+ highlightColor: 'vec4<f32>'
74
+ };
75
+
76
+ export const GLSL_UNIFORMS = /* glsl */ `\
77
+ precision highp float;
78
+ precision highp int;
79
+
80
+ uniform pickingUniforms {
81
+ int isActive;
82
+ int indexMode;
83
+ int batchIndex;
84
+
85
+ int isHighlightActive;
86
+ int highlightedBatchIndex;
87
+ int highlightedObjectIndex;
88
+ vec4 highlightColor;
89
+ } picking;
90
+ `;
91
+
92
+ export const WGSL_UNIFORMS = /* wgsl */ `\
93
+ struct pickingUniforms {
94
+ isActive: int32;
95
+ indexMode: int32;
96
+ batchIndex: int32;
97
+
98
+ isHighlightActive: int32;
99
+ highlightedBatchIndex: int32;
100
+ highlightedObjectIndex: int32;
101
+ highlightColor: vec4<f32>;
102
+ } picking;
103
+ `;
104
+
105
+ function getUniforms(props: PickingProps = {}, prevUniforms?: PickingUniforms): PickingUniforms {
106
+ const uniforms = {...prevUniforms} as PickingUniforms;
107
+
108
+ // picking
109
+ if (props.isActive !== undefined) {
110
+ uniforms.isActive = Boolean(props.isActive);
111
+ }
112
+
113
+ switch (props.indexMode) {
114
+ case 'instance':
115
+ uniforms.indexMode = 0;
116
+ break;
117
+ case 'custom':
118
+ uniforms.indexMode = 1;
119
+ break;
120
+ case undefined:
121
+ // no change
122
+ break;
123
+ }
124
+
125
+ switch (props.highlightedObjectIndex) {
126
+ case undefined:
127
+ // Unless highlightedObjectColor explicitly null or set, do not update state
128
+ break;
129
+ case null:
130
+ // Clear highlight
131
+ uniforms.isHighlightActive = false;
132
+ uniforms.highlightedObjectIndex = INVALID_INDEX;
133
+ break;
134
+ default:
135
+ uniforms.isHighlightActive = true;
136
+ uniforms.highlightedObjectIndex = props.highlightedObjectIndex;
137
+ }
138
+
139
+ if (typeof props.highlightedBatchIndex === 'number') {
140
+ uniforms.highlightedBatchIndex = props.highlightedBatchIndex;
141
+ }
142
+
143
+ if (props.highlightColor) {
144
+ uniforms.highlightColor = props.highlightColor;
145
+ }
146
+
147
+ return uniforms;
148
+ }
149
+
150
+ /**
151
+ * Provides support for color-based picking and highlighting.
152
+ *
153
+ * In particular, supports picking a specific instance in an instanced
154
+ * draw call and highlighting an instance based on its picking color,
155
+ * and correspondingly, supports picking and highlighting groups of
156
+ * primitives with the same picking color in non-instanced draw-calls
157
+ *
158
+ * @note Color based picking has the significant advantage in that it can be added to any
159
+ * existing shader without requiring any additional picking logic.
160
+ */
161
+ export const pickingUniforms = {
162
+ props: {} as PickingProps,
163
+ uniforms: {} as PickingUniforms,
164
+
165
+ name: 'picking',
166
+
167
+ uniformTypes,
168
+ defaultUniforms: {
169
+ isActive: false,
170
+ indexMode: 0,
171
+ batchIndex: 0,
172
+ isHighlightActive: true,
173
+ highlightedBatchIndex: INVALID_INDEX,
174
+ highlightedObjectIndex: INVALID_INDEX,
175
+ highlightColor: DEFAULT_HIGHLIGHT_COLOR
176
+ },
177
+
178
+ getUniforms
179
+ } as const satisfies ShaderModule<PickingProps, PickingUniforms, PickingBindings>;
@@ -0,0 +1,129 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {ShaderPass} from '@luma.gl/shadertools';
6
+
7
+ /**
8
+ * Gets fragment shader source for a shader pass sub pass
9
+ * @param options
10
+ * @returns
11
+ */
12
+ export function getFragmentShaderForRenderPass(options: {
13
+ shaderPass: ShaderPass;
14
+ action: 'filter' | 'sample';
15
+ shadingLanguage: 'wgsl' | 'glsl';
16
+ }): string {
17
+ const {shaderPass, action, shadingLanguage} = options;
18
+ switch (action) {
19
+ case 'filter':
20
+ const filterFunc = `${shaderPass.name}_filterColor_ext`;
21
+ return shadingLanguage === 'wgsl'
22
+ ? getFilterShaderWGSL(filterFunc)
23
+ : getFilterShaderGLSL(filterFunc);
24
+
25
+ case 'sample':
26
+ const samplerFunc = `${shaderPass.name}_sampleColor`;
27
+ return shadingLanguage === 'wgsl'
28
+ ? getSamplerShaderWGSL(samplerFunc)
29
+ : getSamplerShaderGLSL(samplerFunc);
30
+
31
+ default:
32
+ throw new Error(`${shaderPass.name} no fragment shader generated for shader pass`);
33
+ }
34
+ }
35
+
36
+ /** Get a filtering WGSL fragment shader */
37
+ function getFilterShaderWGSL(func: string) {
38
+ return /* wgsl */ `\
39
+ // Binding 0:1 is reserved for shader passes
40
+ @group(0) @binding(0) var<uniform> brightnessContrast : brightnessContrastUniforms;
41
+ @group(0) @binding(1) var texture: texture_2d<f32>;
42
+ @group(0) @binding(2) var sampler: sampler;
43
+
44
+ struct FragmentInputs = {
45
+ @location(0) fragUV: vec2f,
46
+ @location(1) fragPosition: vec4f,
47
+ @location(2) fragCoordinate: vec4f
48
+ };
49
+
50
+ @fragment
51
+ fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4f {
52
+ let texSize = textureDimensions(texture, 0);
53
+ var fragColor = textureSample(texture, sampler, fragUV);
54
+ fragColor = ${func}(gl_FragColor, texSize, texCoord);
55
+ return fragColor;
56
+ }
57
+ `;
58
+ }
59
+
60
+ /** Get a sampling WGSL fragment shader */
61
+ function getSamplerShaderWGSL(func: string) {
62
+ return /* wgsl */ `\
63
+ // Binding 0:1 is reserved for shader passes
64
+ @group(0) @binding(0) var<uniform> brightnessContrast : brightnessContrastUniforms;
65
+ @group(0) @binding(1) var texture: texture_2d<f32>;
66
+ @group(0) @binding(2) var sampler: sampler;
67
+
68
+ struct FragmentInputs = {
69
+ @location(0) fragUV: vec2f,
70
+ @location(1) fragPosition: vec4f,
71
+ @location(2) fragCoordinate: vec4f
72
+ };
73
+
74
+ @fragment
75
+ fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4f {
76
+ let texSize = textureDimensions(texture, 0);
77
+ var fragColor = textureSample(texture, sampler, fragUV);
78
+ fragColor = ${func}(gl_FragColor, texSize, texCoord);
79
+ return fragColor;
80
+ }
81
+ `;
82
+ }
83
+
84
+ /** Get a filtering GLSL fragment shader */
85
+ function getFilterShaderGLSL(func: string) {
86
+ return /* glsl */ `\
87
+ #version 300 es
88
+
89
+ uniform sampler2D sourceTexture;
90
+
91
+ in vec2 position;
92
+ in vec2 coordinate;
93
+ in vec2 uv;
94
+
95
+ out vec4 fragColor;
96
+
97
+ void main() {
98
+ vec2 texCoord = coordinate;
99
+ ivec2 iTexSize = textureSize(sourceTexture, 0);
100
+ vec2 texSize = vec2(float(iTexSize.x), float(iTexSize.y));
101
+
102
+ fragColor = texture(sourceTexture, texCoord);
103
+ fragColor = ${func}(fragColor, texSize, texCoord);
104
+ }
105
+ `;
106
+ }
107
+
108
+ /** Get a sampling GLSL fragment shader */
109
+ function getSamplerShaderGLSL(func: string) {
110
+ return /* glsl */ `\
111
+ #version 300 es
112
+
113
+ uniform sampler2D sourceTexture;
114
+
115
+ in vec2 position;
116
+ in vec2 coordinate;
117
+ in vec2 uv;
118
+
119
+ out vec4 fragColor;
120
+
121
+ void main() {
122
+ vec2 texCoord = coordinate;
123
+ ivec2 iTexSize = textureSize(sourceTexture, 0);
124
+ vec2 texSize = vec2(float(iTexSize.x), float(iTexSize.y));
125
+
126
+ fragColor = ${func}(sourceTexture, texSize, texCoord);
127
+ }
128
+ `;
129
+ }
@@ -0,0 +1,252 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {Device, RenderPass, Texture} from '@luma.gl/core';
6
+ import type {ShaderPass} from '@luma.gl/shadertools';
7
+ import {initializeShaderModule} from '@luma.gl/shadertools';
8
+ import {ShaderInputs} from '../shader-inputs';
9
+ import {AsyncTexture} from '../async-texture/async-texture';
10
+ import {ClipSpace} from '../models/clip-space';
11
+ import {SwapFramebuffers} from '../compute/swap';
12
+ import {BackgroundTextureModel} from '../models/billboard-texture-model';
13
+
14
+ import {getFragmentShaderForRenderPass} from './get-fragment-shader';
15
+
16
+ type ShaderSubPass = NonNullable<ShaderPass['passes']>[0];
17
+
18
+ /** Props for ShaderPassRenderer */
19
+ export type ShaderPassRendererProps = {
20
+ /** List of ShaderPasses to apply to the sourceTexture */
21
+ shaderPasses: ShaderPass[];
22
+ /** Optional typed ShaderInputs object for setting uniforms */
23
+ shaderInputs: ShaderInputs;
24
+ };
25
+
26
+ /** A pass that renders a given texture into screen space */
27
+ export class ShaderPassRenderer {
28
+ device: Device;
29
+ shaderInputs: ShaderInputs;
30
+ passRenderers: PassRenderer[];
31
+ swapFramebuffers: SwapFramebuffers;
32
+ /** For rendering to the screen */
33
+ clipSpace: ClipSpace;
34
+ textureModel: BackgroundTextureModel;
35
+
36
+ constructor(device: Device, props: ShaderPassRendererProps) {
37
+ this.device = device;
38
+
39
+ props.shaderPasses.map(shaderPass => initializeShaderModule(shaderPass));
40
+
41
+ const modules = props.shaderPasses.reduce(
42
+ (object, shaderPass) => ({...object, [shaderPass.name]: shaderPass}),
43
+ {}
44
+ );
45
+ this.shaderInputs = props.shaderInputs || new ShaderInputs(modules);
46
+
47
+ const size = device.getCanvasContext().getPixelSize();
48
+ this.swapFramebuffers = new SwapFramebuffers(device, {
49
+ colorAttachments: ['rgba8unorm'],
50
+ width: size[0],
51
+ height: size[1]
52
+ });
53
+
54
+ this.textureModel = new BackgroundTextureModel(device, {
55
+ backgroundTexture: this.swapFramebuffers.current.colorAttachments[0].texture
56
+ });
57
+
58
+ this.clipSpace = new ClipSpace(device, {
59
+ source: /* wgsl */ `\
60
+ @group(0) @binding(0) var sourceTexture: texture_2d<f32>;
61
+ @group(0) @binding(1) var sourceTextureSampler: sampler;
62
+
63
+ @fragment
64
+ fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
65
+ let texCoord: vec2<f32> = inputs.coordinate;
66
+ return textureSample(sourceTexture, sourceTextureSampler, texCoord);
67
+ }
68
+ `,
69
+
70
+ fs: /* glsl */ `\
71
+ #version 300 es
72
+
73
+ uniform sampler2D sourceTexture;
74
+ in vec2 uv;
75
+ in vec2 coordinate;
76
+ out vec4 fragColor;
77
+
78
+ void main() {
79
+ vec2 texCoord = coordinate;
80
+ fragColor = texture(sourceTexture, coordinate);
81
+ }
82
+ `
83
+ });
84
+
85
+ this.passRenderers = props.shaderPasses.map(shaderPass => new PassRenderer(device, shaderPass));
86
+ }
87
+
88
+ /** Destroys resources created by this ShaderPassRenderer */
89
+ destroy() {
90
+ for (const subPassRenderer of this.passRenderers) {
91
+ subPassRenderer.destroy();
92
+ }
93
+ this.swapFramebuffers.destroy();
94
+ this.clipSpace.destroy();
95
+ }
96
+
97
+ resize(width: number, height: number): void {
98
+ this.swapFramebuffers.resize({width, height});
99
+ // this.props.passes.forEach(pass => pass.resize(width, height));
100
+ }
101
+
102
+ renderToScreen(options: {sourceTexture: AsyncTexture; uniforms: any; bindings: any}): boolean {
103
+ // Run the shader passes and generate an output texture
104
+ const outputTexture = this.renderToTexture(options);
105
+ if (!outputTexture) {
106
+ // source texture not yet loaded
107
+ return false;
108
+ }
109
+
110
+ const renderPass = this.device.beginRenderPass({clearColor: [0, 0, 0, 1], clearDepth: 1});
111
+ this.clipSpace.setBindings({sourceTexture: outputTexture});
112
+ this.clipSpace.draw(renderPass);
113
+ renderPass.end();
114
+ return true;
115
+ }
116
+
117
+ /** Runs the shaderPasses in sequence on the sourceTexture and returns a texture with the results.
118
+ * @returns null if the the sourceTexture has not yet been loaded
119
+ */
120
+ renderToTexture(options: {
121
+ sourceTexture: AsyncTexture;
122
+ uniforms: any;
123
+ bindings: any;
124
+ }): Texture | null {
125
+ const {sourceTexture} = options;
126
+ if (!sourceTexture.isReady) {
127
+ return null;
128
+ }
129
+
130
+ this.textureModel.destroy();
131
+ this.textureModel = new BackgroundTextureModel(this.device, {
132
+ backgroundTexture: sourceTexture
133
+ });
134
+
135
+ // Clear the current texture before we begin
136
+ const clearTexturePass = this.device.beginRenderPass({
137
+ framebuffer: this.swapFramebuffers.current,
138
+ clearColor: [0, 0, 0, 1]
139
+ });
140
+ this.textureModel.draw(clearTexturePass);
141
+ clearTexturePass.end();
142
+
143
+ // const commandEncoder = this.device.createCommandEncoder();
144
+ // commandEncoder.copyTextureToTexture({
145
+ // sourceTexture: sourceTexture.texture,
146
+ // destinationTexture: this.swapFramebuffers.current.colorAttachments[0].texture
147
+ // });
148
+ // commandEncoder.finish();
149
+
150
+ let first = true;
151
+ for (const passRenderer of this.passRenderers) {
152
+ for (const subPassRenderer of passRenderer.subPassRenderers) {
153
+ if (!first) {
154
+ this.swapFramebuffers.swap();
155
+ }
156
+ first = false;
157
+
158
+ const swapBufferTexture = this.swapFramebuffers.current.colorAttachments[0].texture;
159
+
160
+ const bindings = {
161
+ sourceTexture: swapBufferTexture
162
+ // texSize: [sourceTextures.width, sourceTextures.height]
163
+ };
164
+
165
+ const renderPass = this.device.beginRenderPass({
166
+ framebuffer: this.swapFramebuffers.next,
167
+ clearColor: [0, 0, 0, 1],
168
+ clearDepth: 1
169
+ });
170
+ subPassRenderer.render({renderPass, bindings});
171
+ renderPass.end();
172
+ }
173
+ }
174
+
175
+ this.swapFramebuffers.swap();
176
+ const outputTexture = this.swapFramebuffers.current.colorAttachments[0].texture;
177
+ return outputTexture;
178
+ }
179
+ }
180
+
181
+ /** renders one ShaderPass */
182
+ class PassRenderer {
183
+ shaderPass: ShaderPass;
184
+ subPassRenderers: SubPassRenderer[];
185
+
186
+ constructor(device: Device, shaderPass: ShaderPass, props = {}) {
187
+ this.shaderPass = shaderPass;
188
+ // const id = `${shaderPass.name}-pass`;
189
+
190
+ const subPasses = shaderPass.passes || [];
191
+ // normalizePasses(gl, module, id, props);
192
+
193
+ this.subPassRenderers = subPasses.map(subPass => {
194
+ // const idn = `${id}-${subPasses.length + 1}`;
195
+ return new SubPassRenderer(device, shaderPass, subPass);
196
+ });
197
+ }
198
+
199
+ destroy() {
200
+ for (const subPassRenderer of this.subPassRenderers) {
201
+ subPassRenderer.destroy();
202
+ }
203
+ }
204
+ }
205
+
206
+ /** Renders one subpass of a ShaderPass */
207
+ class SubPassRenderer {
208
+ model: ClipSpace;
209
+ shaderPass: ShaderPass;
210
+ subPass: ShaderSubPass;
211
+
212
+ constructor(device: Device, shaderPass: ShaderPass, subPass: ShaderSubPass) {
213
+ this.shaderPass = shaderPass;
214
+ this.subPass = subPass;
215
+ const action =
216
+ subPass.action || (subPass.filter && 'filter') || (subPass.sampler && 'sample') || 'filter';
217
+ const fs = getFragmentShaderForRenderPass({
218
+ shaderPass,
219
+ action,
220
+ shadingLanguage: device.info.shadingLanguage
221
+ });
222
+
223
+ this.model = new ClipSpace(device, {
224
+ id: `${shaderPass.name}-subpass`,
225
+ source: fs,
226
+ fs,
227
+ modules: [shaderPass],
228
+ parameters: {
229
+ depthWriteEnabled: false,
230
+ depthCompare: 'always'
231
+ }
232
+ });
233
+ }
234
+
235
+ destroy() {
236
+ this.model.destroy();
237
+ }
238
+
239
+ render(options: {renderPass: RenderPass; bindings: any}): void {
240
+ const {renderPass, bindings} = options;
241
+
242
+ this.model.shaderInputs.setProps({
243
+ [this.shaderPass.name]: this.shaderPass.uniforms || {}
244
+ });
245
+ this.model.shaderInputs.setProps({
246
+ [this.shaderPass.name]: this.subPass.uniforms || {}
247
+ });
248
+ // this.model.setBindings(this.subPass.bindings || {});
249
+ this.model.setBindings(bindings || {});
250
+ this.model.draw(renderPass);
251
+ }
252
+ }