@luma.gl/engine 9.1.0-alpha.2 → 9.1.0-beta.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/dist/animation/key-frames.js +1 -0
- package/dist/animation/key-frames.js.map +1 -0
- package/dist/animation/timeline.js +1 -0
- package/dist/animation/timeline.js.map +1 -0
- package/dist/animation-loop/animation-loop-template.js +1 -0
- package/dist/animation-loop/animation-loop-template.js.map +1 -0
- package/dist/animation-loop/animation-loop.d.ts +2 -0
- package/dist/animation-loop/animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/animation-loop.js +24 -6
- package/dist/animation-loop/animation-loop.js.map +1 -0
- package/dist/animation-loop/animation-props.js +1 -0
- package/dist/animation-loop/animation-props.js.map +1 -0
- package/dist/animation-loop/make-animation-loop.d.ts +5 -1
- package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/make-animation-loop.js +3 -1
- package/dist/animation-loop/make-animation-loop.js.map +1 -0
- package/dist/animation-loop/request-animation-frame.d.ts +4 -2
- package/dist/animation-loop/request-animation-frame.d.ts.map +1 -1
- package/dist/animation-loop/request-animation-frame.js +5 -3
- package/dist/animation-loop/request-animation-frame.js.map +1 -0
- package/dist/application-utils/load-file.d.ts +1 -1
- package/dist/application-utils/load-file.d.ts.map +1 -1
- package/dist/application-utils/load-file.js +2 -2
- package/dist/application-utils/load-file.js.map +1 -0
- package/dist/application-utils/random.js +1 -0
- package/dist/application-utils/random.js.map +1 -0
- package/dist/async-texture/async-texture.d.ts +14 -2
- package/dist/async-texture/async-texture.d.ts.map +1 -1
- package/dist/async-texture/async-texture.js +40 -3
- package/dist/async-texture/async-texture.js.map +1 -0
- package/dist/compute/buffer-transform.d.ts +41 -0
- package/dist/compute/buffer-transform.d.ts.map +1 -0
- package/dist/{transform → compute}/buffer-transform.js +19 -12
- package/dist/compute/buffer-transform.js.map +1 -0
- package/dist/{computation.d.ts → compute/computation.d.ts} +3 -3
- package/dist/compute/computation.d.ts.map +1 -0
- package/dist/{computation.js → compute/computation.js} +7 -8
- package/dist/compute/computation.js.map +1 -0
- package/dist/compute/swap.d.ts +48 -0
- package/dist/compute/swap.d.ts.map +1 -0
- package/dist/compute/swap.js +91 -0
- package/dist/compute/swap.js.map +1 -0
- package/dist/{transform → compute}/texture-transform.d.ts +0 -6
- package/dist/compute/texture-transform.d.ts.map +1 -0
- package/dist/{transform → compute}/texture-transform.js +10 -15
- package/dist/compute/texture-transform.js.map +1 -0
- package/dist/debug/copy-texture-to-image.js +1 -0
- package/dist/debug/copy-texture-to-image.js.map +1 -0
- package/dist/debug/debug-framebuffer.js +2 -1
- package/dist/debug/debug-framebuffer.js.map +1 -0
- package/dist/debug/debug-shader-layout.js +2 -1
- package/dist/debug/debug-shader-layout.js.map +1 -0
- package/dist/debug/pixel-data-utils.js +1 -0
- package/dist/debug/pixel-data-utils.js.map +1 -0
- package/dist/dist.dev.js +2952 -5816
- package/dist/dist.min.js +422 -91
- package/dist/{lib → factories}/pipeline-factory.d.ts +11 -1
- package/dist/factories/pipeline-factory.d.ts.map +1 -0
- package/dist/factories/pipeline-factory.js +181 -0
- package/dist/factories/pipeline-factory.js.map +1 -0
- package/dist/{lib → factories}/shader-factory.d.ts +5 -1
- package/dist/factories/shader-factory.d.ts.map +1 -0
- package/dist/{lib → factories}/shader-factory.js +39 -4
- package/dist/factories/shader-factory.js.map +1 -0
- package/dist/geometries/cone-geometry.js +1 -0
- package/dist/geometries/cone-geometry.js.map +1 -0
- package/dist/geometries/cube-geometry.js +1 -0
- package/dist/geometries/cube-geometry.js.map +1 -0
- package/dist/geometries/cylinder-geometry.js +1 -0
- package/dist/geometries/cylinder-geometry.js.map +1 -0
- package/dist/geometries/ico-sphere-geometry.js +1 -0
- package/dist/geometries/ico-sphere-geometry.js.map +1 -0
- package/dist/geometries/plane-geometry.js +1 -0
- package/dist/geometries/plane-geometry.js.map +1 -0
- package/dist/geometries/sphere-geometry.js +1 -0
- package/dist/geometries/sphere-geometry.js.map +1 -0
- package/dist/geometries/truncated-cone-geometry.js +1 -0
- package/dist/geometries/truncated-cone-geometry.js.map +1 -0
- package/dist/geometry/geometry-table.js +1 -0
- package/dist/geometry/geometry-table.js.map +1 -0
- package/dist/geometry/geometry-utils.js +1 -0
- package/dist/geometry/geometry-utils.js.map +1 -0
- package/dist/geometry/geometry.js +1 -0
- package/dist/geometry/geometry.js.map +1 -0
- package/dist/geometry/gpu-geometry.js +1 -0
- package/dist/geometry/gpu-geometry.js.map +1 -0
- package/dist/geometry/gpu-table.js +1 -0
- package/dist/geometry/gpu-table.js.map +1 -0
- package/dist/index.cjs +1440 -217
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +23 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -9
- package/dist/index.js.map +1 -0
- package/dist/model/model.d.ts +11 -10
- package/dist/model/model.d.ts.map +1 -1
- package/dist/model/model.js +92 -69
- package/dist/model/model.js.map +1 -0
- package/dist/model/split-uniforms-and-bindings.d.ts +1 -1
- package/dist/model/split-uniforms-and-bindings.d.ts.map +1 -1
- package/dist/model/split-uniforms-and-bindings.js +2 -1
- package/dist/model/split-uniforms-and-bindings.js.map +1 -0
- package/dist/models/billboard-texture-model.d.ts +23 -0
- package/dist/models/billboard-texture-model.d.ts.map +1 -0
- package/dist/models/billboard-texture-model.js +78 -0
- package/dist/models/billboard-texture-model.js.map +1 -0
- package/dist/models/billboard-texture-module.d.ts +10 -0
- package/dist/models/billboard-texture-module.d.ts.map +1 -0
- package/dist/models/billboard-texture-module.js +37 -0
- package/dist/models/billboard-texture-module.js.map +1 -0
- package/dist/{lib → models}/clip-space.d.ts +3 -1
- package/dist/models/clip-space.d.ts.map +1 -0
- package/dist/models/clip-space.js +77 -0
- package/dist/models/clip-space.js.map +1 -0
- package/dist/modules/picking/color-picking.d.ts +28 -0
- package/dist/modules/picking/color-picking.d.ts.map +1 -0
- package/dist/modules/picking/color-picking.js +177 -0
- package/dist/modules/picking/color-picking.js.map +1 -0
- package/dist/modules/picking/index-picking.d.ts +32 -0
- package/dist/modules/picking/index-picking.d.ts.map +1 -0
- package/dist/modules/picking/index-picking.js +148 -0
- package/dist/modules/picking/index-picking.js.map +1 -0
- package/dist/modules/picking/legacy-picking-manager.d.ts +27 -0
- package/dist/modules/picking/legacy-picking-manager.d.ts.map +1 -0
- package/dist/modules/picking/legacy-picking-manager.js +76 -0
- package/dist/modules/picking/legacy-picking-manager.js.map +1 -0
- package/dist/modules/picking/picking-manager.d.ts +45 -0
- package/dist/modules/picking/picking-manager.d.ts.map +1 -0
- package/dist/modules/picking/picking-manager.js +101 -0
- package/dist/modules/picking/picking-manager.js.map +1 -0
- package/dist/modules/picking/picking-uniforms.d.ts +79 -0
- package/dist/modules/picking/picking-uniforms.d.ts.map +1 -0
- package/dist/modules/picking/picking-uniforms.js +109 -0
- package/dist/modules/picking/picking-uniforms.js.map +1 -0
- package/dist/passes/get-fragment-shader.d.ts +12 -0
- package/dist/passes/get-fragment-shader.d.ts.map +1 -0
- package/dist/passes/get-fragment-shader.js +117 -0
- package/dist/passes/get-fragment-shader.js.map +1 -0
- package/dist/passes/shader-pass-renderer.d.ts +63 -0
- package/dist/passes/shader-pass-renderer.d.ts.map +1 -0
- package/dist/passes/shader-pass-renderer.js +197 -0
- package/dist/passes/shader-pass-renderer.js.map +1 -0
- package/dist/scenegraph/group-node.js +1 -0
- package/dist/scenegraph/group-node.js.map +1 -0
- package/dist/scenegraph/model-node.js +1 -0
- package/dist/scenegraph/model-node.js.map +1 -0
- package/dist/scenegraph/scenegraph-node.js +1 -0
- package/dist/scenegraph/scenegraph-node.js.map +1 -0
- package/dist/shader-inputs.d.ts +8 -19
- package/dist/shader-inputs.d.ts.map +1 -1
- package/dist/shader-inputs.js +28 -18
- package/dist/shader-inputs.js.map +1 -0
- package/dist/utils/deep-equal.js +1 -0
- package/dist/utils/deep-equal.js.map +1 -0
- package/dist/utils/uid.js +1 -0
- package/dist/utils/uid.js.map +1 -0
- package/package.json +6 -6
- package/src/animation-loop/animation-loop.ts +27 -6
- package/src/animation-loop/make-animation-loop.ts +8 -3
- package/src/animation-loop/request-animation-frame.ts +4 -3
- package/src/application-utils/load-file.ts +2 -4
- package/src/async-texture/async-texture.ts +48 -10
- package/src/{transform → compute}/buffer-transform.ts +30 -14
- package/src/{computation.ts → compute/computation.ts} +14 -8
- package/src/compute/swap.ts +116 -0
- package/src/{transform → compute}/texture-transform.ts +9 -18
- package/src/debug/debug-framebuffer.ts +1 -1
- package/src/debug/debug-shader-layout.ts +1 -1
- package/src/factories/pipeline-factory.ts +222 -0
- package/src/{lib → factories}/shader-factory.ts +41 -5
- package/src/index.ts +35 -16
- package/src/model/model.ts +132 -77
- package/src/model/split-uniforms-and-bindings.ts +4 -4
- package/src/models/billboard-texture-model.ts +98 -0
- package/src/models/billboard-texture-module.ts +49 -0
- package/src/models/clip-space.ts +88 -0
- package/src/modules/picking/README.md +88 -0
- package/src/modules/picking/color-picking.ts +190 -0
- package/src/modules/picking/index-picking.ts +156 -0
- package/src/modules/picking/legacy-picking-manager.ts +99 -0
- package/src/modules/picking/picking-manager.ts +137 -0
- package/src/modules/picking/picking-uniforms.ts +179 -0
- package/src/passes/get-fragment-shader.ts +129 -0
- package/src/passes/shader-pass-renderer.ts +252 -0
- package/src/shader-inputs.ts +44 -59
- package/dist/computation.d.ts.map +0 -1
- package/dist/lib/clip-space.d.ts.map +0 -1
- package/dist/lib/clip-space.js +0 -46
- package/dist/lib/pipeline-factory.d.ts.map +0 -1
- package/dist/lib/pipeline-factory.js +0 -98
- package/dist/lib/shader-factory.d.ts.map +0 -1
- package/dist/transform/buffer-transform.d.ts +0 -35
- package/dist/transform/buffer-transform.d.ts.map +0 -1
- package/dist/transform/texture-transform.d.ts.map +0 -1
- package/src/lib/clip-space.ts +0 -53
- package/src/lib/pipeline-factory.ts +0 -126
package/src/model/model.ts
CHANGED
|
@@ -4,31 +4,51 @@
|
|
|
4
4
|
|
|
5
5
|
// A lot of imports, but then Model is where it all comes together...
|
|
6
6
|
import type {TypedArray} from '@math.gl/types';
|
|
7
|
-
import type {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
import type {
|
|
8
|
+
RenderPipelineProps,
|
|
9
|
+
RenderPipelineParameters,
|
|
10
|
+
BufferLayout,
|
|
11
|
+
Shader,
|
|
12
|
+
VertexArray,
|
|
13
|
+
TransformFeedback,
|
|
14
|
+
AttributeInfo,
|
|
15
|
+
Binding,
|
|
16
|
+
UniformValue,
|
|
17
|
+
PrimitiveTopology
|
|
18
|
+
} from '@luma.gl/core';
|
|
19
|
+
import {
|
|
20
|
+
Device,
|
|
21
|
+
DeviceFeature,
|
|
22
|
+
Buffer,
|
|
23
|
+
Texture,
|
|
24
|
+
TextureView,
|
|
25
|
+
Sampler,
|
|
26
|
+
RenderPipeline,
|
|
27
|
+
RenderPass,
|
|
28
|
+
UniformStore,
|
|
29
|
+
log,
|
|
30
|
+
getTypedArrayFromDataType,
|
|
31
|
+
getAttributeInfosFromLayouts,
|
|
32
|
+
_BufferLayoutHelper
|
|
33
|
+
} from '@luma.gl/core';
|
|
14
34
|
|
|
15
35
|
import type {ShaderModule, PlatformInfo} from '@luma.gl/shadertools';
|
|
16
36
|
import {ShaderAssembler, getShaderLayoutFromWGSL} from '@luma.gl/shadertools';
|
|
17
37
|
|
|
18
38
|
import type {Geometry} from '../geometry/geometry';
|
|
19
39
|
import {GPUGeometry, makeGPUGeometry} from '../geometry/gpu-geometry';
|
|
20
|
-
import {PipelineFactory} from '../
|
|
21
|
-
import {ShaderFactory} from '../
|
|
40
|
+
import {PipelineFactory} from '../factories/pipeline-factory';
|
|
41
|
+
import {ShaderFactory} from '../factories/shader-factory';
|
|
22
42
|
import {getDebugTableForShaderLayout} from '../debug/debug-shader-layout';
|
|
23
43
|
import {debugFramebuffer} from '../debug/debug-framebuffer';
|
|
24
44
|
import {deepEqual} from '../utils/deep-equal';
|
|
25
45
|
import {uid} from '../utils/uid';
|
|
26
|
-
import {splitUniformsAndBindings} from './split-uniforms-and-bindings';
|
|
27
|
-
|
|
28
46
|
import {ShaderInputs} from '../shader-inputs';
|
|
29
47
|
// import type {AsyncTextureProps} from '../async-texture/async-texture';
|
|
30
48
|
import {AsyncTexture} from '../async-texture/async-texture';
|
|
31
49
|
|
|
50
|
+
import {splitUniformsAndBindings} from './split-uniforms-and-bindings';
|
|
51
|
+
|
|
32
52
|
const LOG_DRAW_PRIORITY = 2;
|
|
33
53
|
const LOG_DRAW_TIMEOUT = 10000;
|
|
34
54
|
|
|
@@ -201,6 +221,14 @@ export class Model {
|
|
|
201
221
|
/** "Time" of last draw. Monotonically increasing timestamp */
|
|
202
222
|
_lastDrawTimestamp: number = -1;
|
|
203
223
|
|
|
224
|
+
get [Symbol.toStringTag](): string {
|
|
225
|
+
return 'Model';
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
toString(): string {
|
|
229
|
+
return `Model(${this.id})`;
|
|
230
|
+
}
|
|
231
|
+
|
|
204
232
|
constructor(device: Device, props: ModelProps) {
|
|
205
233
|
this.props = {...Model.defaultProps, ...props};
|
|
206
234
|
props = this.props;
|
|
@@ -275,7 +303,8 @@ export class Model {
|
|
|
275
303
|
this.pipeline = this._updatePipeline();
|
|
276
304
|
|
|
277
305
|
this.vertexArray = device.createVertexArray({
|
|
278
|
-
|
|
306
|
+
shaderLayout: this.pipeline.shaderLayout,
|
|
307
|
+
bufferLayout: this.pipeline.bufferLayout
|
|
279
308
|
});
|
|
280
309
|
|
|
281
310
|
// Now we can apply geometry attributes
|
|
@@ -307,11 +336,11 @@ export class Model {
|
|
|
307
336
|
this.setBindings(props.bindings);
|
|
308
337
|
}
|
|
309
338
|
if (props.uniforms) {
|
|
310
|
-
this.
|
|
339
|
+
this.setUniformsWebGL(props.uniforms);
|
|
311
340
|
}
|
|
312
341
|
if (props.moduleSettings) {
|
|
313
342
|
// log.warn('Model.props.moduleSettings is deprecated. Use Model.shaderInputs.setProps()')();
|
|
314
|
-
this.
|
|
343
|
+
this.updateModuleSettingsWebGL(props.moduleSettings);
|
|
315
344
|
}
|
|
316
345
|
if (props.transformFeedback) {
|
|
317
346
|
this.transformFeedback = props.transformFeedback;
|
|
@@ -322,16 +351,19 @@ export class Model {
|
|
|
322
351
|
}
|
|
323
352
|
|
|
324
353
|
destroy(): void {
|
|
325
|
-
if (this._destroyed)
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
this.shaderFactory.release(this.pipeline.
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
354
|
+
if (!this._destroyed) {
|
|
355
|
+
// Release pipeline before we destroy the shaders used by the pipeline
|
|
356
|
+
this.pipelineFactory.release(this.pipeline);
|
|
357
|
+
// Release the shaders
|
|
358
|
+
this.shaderFactory.release(this.pipeline.vs);
|
|
359
|
+
if (this.pipeline.fs) {
|
|
360
|
+
this.shaderFactory.release(this.pipeline.fs);
|
|
361
|
+
}
|
|
362
|
+
this._uniformStore.destroy();
|
|
363
|
+
// TODO - mark resource as managed and destroyIfManaged() ?
|
|
364
|
+
this._gpuGeometry?.destroy();
|
|
365
|
+
this._destroyed = true;
|
|
366
|
+
}
|
|
335
367
|
}
|
|
336
368
|
|
|
337
369
|
// Draw call
|
|
@@ -352,7 +384,7 @@ export class Model {
|
|
|
352
384
|
this._needsRedraw ||= reason;
|
|
353
385
|
}
|
|
354
386
|
|
|
355
|
-
predraw() {
|
|
387
|
+
predraw(): void {
|
|
356
388
|
// Update uniform buffers if needed
|
|
357
389
|
this.updateShaderInputs();
|
|
358
390
|
// Check if the pipeline is invalidated
|
|
@@ -360,10 +392,22 @@ export class Model {
|
|
|
360
392
|
}
|
|
361
393
|
|
|
362
394
|
draw(renderPass: RenderPass): boolean {
|
|
363
|
-
this.
|
|
395
|
+
const loadingBinding = this._areBindingsLoading();
|
|
396
|
+
if (loadingBinding) {
|
|
397
|
+
log.info(LOG_DRAW_PRIORITY, `>>> DRAWING ABORTED ${this.id}: ${loadingBinding} not loaded`)();
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
try {
|
|
402
|
+
renderPass.pushDebugGroup(`${this}.predraw(${renderPass})`);
|
|
403
|
+
this.predraw();
|
|
404
|
+
} finally {
|
|
405
|
+
renderPass.popDebugGroup();
|
|
406
|
+
}
|
|
364
407
|
|
|
365
408
|
let drawSuccess: boolean;
|
|
366
409
|
try {
|
|
410
|
+
renderPass.pushDebugGroup(`${this}.draw(${renderPass})`);
|
|
367
411
|
this._logDrawCallStart();
|
|
368
412
|
|
|
369
413
|
// Update the pipeline if invalidated
|
|
@@ -374,6 +418,7 @@ export class Model {
|
|
|
374
418
|
// Set pipeline state, we may be sharing a pipeline so we need to set all state on every draw
|
|
375
419
|
// Any caching needs to be done inside the pipeline functions
|
|
376
420
|
// TODO this is a busy initialized check for all bindings every frame
|
|
421
|
+
|
|
377
422
|
const syncBindings = this._getBindings();
|
|
378
423
|
this.pipeline.setBindings(syncBindings, {
|
|
379
424
|
disableWarnings: this.props.disableWarnings
|
|
@@ -402,6 +447,7 @@ export class Model {
|
|
|
402
447
|
topology: this.topology
|
|
403
448
|
});
|
|
404
449
|
} finally {
|
|
450
|
+
renderPass.popDebugGroup();
|
|
405
451
|
this._logDrawCallEnd();
|
|
406
452
|
}
|
|
407
453
|
this._logFramebuffer(renderPass);
|
|
@@ -428,7 +474,11 @@ export class Model {
|
|
|
428
474
|
const gpuGeometry = geometry && makeGPUGeometry(this.device, geometry);
|
|
429
475
|
if (gpuGeometry) {
|
|
430
476
|
this.setTopology(gpuGeometry.topology || 'triangle-list');
|
|
431
|
-
|
|
477
|
+
const bufferLayoutHelper = new _BufferLayoutHelper(this.bufferLayout);
|
|
478
|
+
this.bufferLayout = bufferLayoutHelper.mergeBufferLayouts(
|
|
479
|
+
gpuGeometry.bufferLayout,
|
|
480
|
+
this.bufferLayout
|
|
481
|
+
);
|
|
432
482
|
if (this.vertexArray) {
|
|
433
483
|
this._setGeometryAttributes(gpuGeometry);
|
|
434
484
|
}
|
|
@@ -452,8 +502,9 @@ export class Model {
|
|
|
452
502
|
* @note Triggers a pipeline rebuild / pipeline cache fetch
|
|
453
503
|
*/
|
|
454
504
|
setBufferLayout(bufferLayout: BufferLayout[]): void {
|
|
505
|
+
const bufferLayoutHelper = new _BufferLayoutHelper(this.bufferLayout);
|
|
455
506
|
this.bufferLayout = this._gpuGeometry
|
|
456
|
-
? mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout)
|
|
507
|
+
? bufferLayoutHelper.mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout)
|
|
457
508
|
: bufferLayout;
|
|
458
509
|
this._setPipelineNeedsUpdate('bufferLayout');
|
|
459
510
|
|
|
@@ -463,7 +514,8 @@ export class Model {
|
|
|
463
514
|
// vertex array needs to be updated if we update buffer layout,
|
|
464
515
|
// but not if we update parameters
|
|
465
516
|
this.vertexArray = this.device.createVertexArray({
|
|
466
|
-
|
|
517
|
+
shaderLayout: this.pipeline.shaderLayout,
|
|
518
|
+
bufferLayout: this.pipeline.bufferLayout
|
|
467
519
|
});
|
|
468
520
|
|
|
469
521
|
// Reapply geometry attributes to the new vertex array
|
|
@@ -513,10 +565,12 @@ export class Model {
|
|
|
513
565
|
setShaderInputs(shaderInputs: ShaderInputs): void {
|
|
514
566
|
this.shaderInputs = shaderInputs;
|
|
515
567
|
this._uniformStore = new UniformStore(this.shaderInputs.modules);
|
|
516
|
-
// Create uniform buffer bindings for all modules
|
|
517
|
-
for (const moduleName of Object.
|
|
518
|
-
|
|
519
|
-
|
|
568
|
+
// Create uniform buffer bindings for all modules that actually have uniforms
|
|
569
|
+
for (const [moduleName, module] of Object.entries(this.shaderInputs.modules)) {
|
|
570
|
+
if (shaderModuleHasUniforms(module)) {
|
|
571
|
+
const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
|
|
572
|
+
this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
|
|
573
|
+
}
|
|
520
574
|
}
|
|
521
575
|
this.setNeedsRedraw('shaderInputs');
|
|
522
576
|
}
|
|
@@ -524,6 +578,7 @@ export class Model {
|
|
|
524
578
|
/** Update uniform buffers from the model's shader inputs */
|
|
525
579
|
updateShaderInputs(): void {
|
|
526
580
|
this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
|
|
581
|
+
this.setBindings(this.shaderInputs.getBindingValues());
|
|
527
582
|
// TODO - this is already tracked through buffer/texture update times?
|
|
528
583
|
this.setNeedsRedraw('shaderInputs');
|
|
529
584
|
}
|
|
@@ -558,22 +613,27 @@ export class Model {
|
|
|
558
613
|
* @note Overrides any attributes previously set with the same name
|
|
559
614
|
*/
|
|
560
615
|
setAttributes(buffers: Record<string, Buffer>, options?: {disableWarnings?: boolean}): void {
|
|
616
|
+
const disableWarnings = options?.disableWarnings ?? this.props.disableWarnings;
|
|
561
617
|
if (buffers.indices) {
|
|
562
618
|
log.warn(
|
|
563
619
|
`Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`
|
|
564
620
|
)();
|
|
565
621
|
}
|
|
622
|
+
|
|
623
|
+
const bufferLayoutHelper = new _BufferLayoutHelper(this.bufferLayout);
|
|
624
|
+
|
|
625
|
+
// Check if all buffers have a layout
|
|
566
626
|
for (const [bufferName, buffer] of Object.entries(buffers)) {
|
|
567
|
-
const bufferLayout =
|
|
568
|
-
getAttributeNames(layout).includes(bufferName)
|
|
569
|
-
);
|
|
627
|
+
const bufferLayout = bufferLayoutHelper.getBufferLayout(bufferName);
|
|
570
628
|
if (!bufferLayout) {
|
|
571
|
-
|
|
629
|
+
if (!disableWarnings) {
|
|
630
|
+
log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)();
|
|
631
|
+
}
|
|
572
632
|
continue; // eslint-disable-line no-continue
|
|
573
633
|
}
|
|
574
634
|
|
|
575
635
|
// For an interleaved attribute we may need to set multiple attributes
|
|
576
|
-
const attributeNames =
|
|
636
|
+
const attributeNames = bufferLayoutHelper.getAttributeNamesForBuffer(bufferLayout);
|
|
577
637
|
let set = false;
|
|
578
638
|
for (const attributeName of attributeNames) {
|
|
579
639
|
const attributeInfo = this._attributeInfos[attributeName];
|
|
@@ -582,7 +642,7 @@ export class Model {
|
|
|
582
642
|
set = true;
|
|
583
643
|
}
|
|
584
644
|
}
|
|
585
|
-
if (!set && !
|
|
645
|
+
if (!set && !disableWarnings) {
|
|
586
646
|
log.warn(
|
|
587
647
|
`Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"`
|
|
588
648
|
)();
|
|
@@ -623,7 +683,7 @@ export class Model {
|
|
|
623
683
|
* @deprecated WebGL only, use uniform buffers for portability
|
|
624
684
|
* @param uniforms
|
|
625
685
|
*/
|
|
626
|
-
|
|
686
|
+
setUniformsWebGL(uniforms: Record<string, UniformValue>): void {
|
|
627
687
|
if (!isObjectEmpty(uniforms)) {
|
|
628
688
|
this.pipeline.setUniformsWebGL(uniforms);
|
|
629
689
|
Object.assign(this.uniforms, uniforms);
|
|
@@ -634,7 +694,7 @@ export class Model {
|
|
|
634
694
|
/**
|
|
635
695
|
* @deprecated Updates shader module settings (which results in uniforms being set)
|
|
636
696
|
*/
|
|
637
|
-
|
|
697
|
+
updateModuleSettingsWebGL(props: Record<string, any>): void {
|
|
638
698
|
// log.warn('Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()')();
|
|
639
699
|
const {bindings, uniforms} = splitUniformsAndBindings(this._getModuleUniforms(props));
|
|
640
700
|
Object.assign(this.bindings, bindings);
|
|
@@ -644,19 +704,32 @@ export class Model {
|
|
|
644
704
|
|
|
645
705
|
// Internal methods
|
|
646
706
|
|
|
647
|
-
/**
|
|
707
|
+
/** Check that bindings are loaded. Returns id of first binding that is still loading. */
|
|
708
|
+
_areBindingsLoading(): string | false {
|
|
709
|
+
for (const binding of Object.values(this.bindings)) {
|
|
710
|
+
if (binding instanceof AsyncTexture && !binding.isReady) {
|
|
711
|
+
return binding.id;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/** Extracts texture view from loaded async textures. Returns null if any textures have not yet been loaded. */
|
|
648
718
|
_getBindings(): Record<string, Binding> {
|
|
649
|
-
|
|
650
|
-
|
|
719
|
+
const validBindings: Record<string, Binding> = {};
|
|
720
|
+
|
|
721
|
+
for (const [name, binding] of Object.entries(this.bindings)) {
|
|
651
722
|
if (binding instanceof AsyncTexture) {
|
|
723
|
+
// Check that async textures are loaded
|
|
652
724
|
if (binding.isReady) {
|
|
653
|
-
|
|
725
|
+
validBindings[name] = binding.texture;
|
|
654
726
|
}
|
|
655
727
|
} else {
|
|
656
|
-
|
|
728
|
+
validBindings[name] = binding;
|
|
657
729
|
}
|
|
658
|
-
|
|
659
|
-
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
return validBindings;
|
|
660
733
|
}
|
|
661
734
|
|
|
662
735
|
/** Get the timestamp of the latest updated bound GPU memory resource (buffer/texture). */
|
|
@@ -731,7 +804,7 @@ export class Model {
|
|
|
731
804
|
id: `${this.id}-vertex`,
|
|
732
805
|
stage: 'vertex',
|
|
733
806
|
source: this.source || this.vs,
|
|
734
|
-
|
|
807
|
+
debugShaders: this.props.debugShaders
|
|
735
808
|
});
|
|
736
809
|
|
|
737
810
|
let fs: Shader | null = null;
|
|
@@ -742,7 +815,7 @@ export class Model {
|
|
|
742
815
|
id: `${this.id}-fragment`,
|
|
743
816
|
stage: 'fragment',
|
|
744
817
|
source: this.source || this.fs,
|
|
745
|
-
|
|
818
|
+
debugShaders: this.props.debugShaders
|
|
746
819
|
});
|
|
747
820
|
}
|
|
748
821
|
|
|
@@ -812,10 +885,11 @@ export class Model {
|
|
|
812
885
|
|
|
813
886
|
protected _drawCount = 0;
|
|
814
887
|
_logFramebuffer(renderPass: RenderPass): void {
|
|
815
|
-
const debugFramebuffers =
|
|
888
|
+
const debugFramebuffers = this.device.props.debugFramebuffers;
|
|
816
889
|
this._drawCount++;
|
|
817
890
|
// Update first 3 frames and then every 60 frames
|
|
818
|
-
if (!debugFramebuffers
|
|
891
|
+
if (!debugFramebuffers) {
|
|
892
|
+
// } || (this._drawCount++ > 3 && this._drawCount % 60)) {
|
|
819
893
|
return;
|
|
820
894
|
}
|
|
821
895
|
// TODO - display framebuffer output in debug window
|
|
@@ -862,22 +936,12 @@ export class Model {
|
|
|
862
936
|
}
|
|
863
937
|
}
|
|
864
938
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
/** TODO - move to core, document add tests */
|
|
868
|
-
function mergeBufferLayouts(layouts1: BufferLayout[], layouts2: BufferLayout[]): BufferLayout[] {
|
|
869
|
-
const layouts = [...layouts1];
|
|
870
|
-
for (const attribute of layouts2) {
|
|
871
|
-
const index = layouts.findIndex(attribute2 => attribute2.name === attribute.name);
|
|
872
|
-
if (index < 0) {
|
|
873
|
-
layouts.push(attribute);
|
|
874
|
-
} else {
|
|
875
|
-
layouts[index] = attribute;
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
return layouts;
|
|
939
|
+
function shaderModuleHasUniforms(module: ShaderModule): boolean {
|
|
940
|
+
return Boolean(module.uniformTypes && !isObjectEmpty(module.uniformTypes));
|
|
879
941
|
}
|
|
880
942
|
|
|
943
|
+
// HELPERS
|
|
944
|
+
|
|
881
945
|
/** Create a shadertools platform info from the Device */
|
|
882
946
|
export function getPlatformInfo(device: Device): PlatformInfo {
|
|
883
947
|
return {
|
|
@@ -890,21 +954,12 @@ export function getPlatformInfo(device: Device): PlatformInfo {
|
|
|
890
954
|
};
|
|
891
955
|
}
|
|
892
956
|
|
|
893
|
-
/** Get attribute names from a BufferLayout */
|
|
894
|
-
function getAttributeNames(bufferLayout: BufferLayout): string[] {
|
|
895
|
-
return bufferLayout.attributes
|
|
896
|
-
? bufferLayout.attributes?.map(layout => layout.attribute)
|
|
897
|
-
: [bufferLayout.name];
|
|
898
|
-
}
|
|
899
|
-
|
|
900
957
|
/** Returns true if given object is empty, false otherwise. */
|
|
901
958
|
function isObjectEmpty(obj: object): boolean {
|
|
902
|
-
let isEmpty = true;
|
|
903
959
|
// @ts-ignore key is unused
|
|
904
960
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
905
961
|
for (const key in obj) {
|
|
906
|
-
|
|
907
|
-
break;
|
|
962
|
+
return false;
|
|
908
963
|
}
|
|
909
|
-
return
|
|
964
|
+
return true;
|
|
910
965
|
}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
import type {UniformValue, Binding} from '@luma.gl/core';
|
|
6
6
|
import {isNumericArray} from '@math.gl/types';
|
|
7
7
|
|
|
8
|
-
export function isUniformValue(value: unknown):
|
|
9
|
-
return isNumericArray(value)
|
|
8
|
+
export function isUniformValue(value: unknown): value is UniformValue {
|
|
9
|
+
return isNumericArray(value) || typeof value === 'number' || typeof value === 'boolean';
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
type UniformsAndBindings = {
|
|
@@ -21,9 +21,9 @@ export function splitUniformsAndBindings(
|
|
|
21
21
|
Object.keys(uniforms).forEach(name => {
|
|
22
22
|
const uniform = uniforms[name];
|
|
23
23
|
if (isUniformValue(uniform)) {
|
|
24
|
-
result.uniforms[name] = uniform
|
|
24
|
+
result.uniforms[name] = uniform;
|
|
25
25
|
} else {
|
|
26
|
-
result.bindings[name] = uniform
|
|
26
|
+
result.bindings[name] = uniform;
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {Device, Texture} from '@luma.gl/core';
|
|
6
|
+
import {AsyncTexture} from '../async-texture/async-texture';
|
|
7
|
+
import {ClipSpace} from './clip-space';
|
|
8
|
+
|
|
9
|
+
const BACKGROUND_FS_WGSL = /* wgsl */ `\
|
|
10
|
+
@group(0) @binding(0) var backgroundTexture: texture_2d<f32>;
|
|
11
|
+
@group(0) @binding(1) var backgroundTextureSampler: sampler;
|
|
12
|
+
|
|
13
|
+
fn billboardTexture_getTextureUV(coordinates: vec2<f32>) -> vec2<f32> {
|
|
14
|
+
let iTexSize: vec2<u32> = textureDimensions(backgroundTexture, 0) * 2;
|
|
15
|
+
let texSize: vec2<f32> = vec2<f32>(f32(iTexSize.x), f32(iTexSize.y));
|
|
16
|
+
var position: vec2<f32> = coordinates.xy / texSize;
|
|
17
|
+
return position;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@fragment
|
|
21
|
+
fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
|
|
22
|
+
let position: vec2<f32> = billboardTexture_getTextureUV(inputs.coordinate);
|
|
23
|
+
return textureSample(backgroundTexture, backgroundTextureSampler, position);
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
const BACKGROUND_FS = /* glsl */ `\
|
|
28
|
+
#version 300 es
|
|
29
|
+
precision highp float;
|
|
30
|
+
|
|
31
|
+
uniform sampler2D backgroundTexture;
|
|
32
|
+
out vec4 fragColor;
|
|
33
|
+
|
|
34
|
+
vec2 billboardTexture_getTextureUV() {
|
|
35
|
+
ivec2 iTexSize = textureDimensions(backgroundTexture, 0) * 2;
|
|
36
|
+
vec2 texSize = vec2(float(iTexSize.x), float(iTexSize.y));
|
|
37
|
+
vec2 position = gl_FragCoord.xy / texSize;
|
|
38
|
+
return position;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
void main(void) {
|
|
42
|
+
vec2 position = billboardTexture_getTextureUV();
|
|
43
|
+
fragColor = texture(backgroundTexture, position);
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Props for a Model that renders a bitmap into the "background", i.e covering the screen
|
|
49
|
+
*/
|
|
50
|
+
export type BackgroundTextureModelProps = {
|
|
51
|
+
/** id of this model */
|
|
52
|
+
id?: string;
|
|
53
|
+
/** The texture to render */
|
|
54
|
+
backgroundTexture: Texture | AsyncTexture;
|
|
55
|
+
/** If true, the texture is rendered into transparent areas of the screen only, i.e blended in where background alpha is small */
|
|
56
|
+
blend?: boolean;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Model that renders a bitmap into the "background", i.e covering the screen
|
|
61
|
+
*/
|
|
62
|
+
export class BackgroundTextureModel extends ClipSpace {
|
|
63
|
+
constructor(device: Device, props: BackgroundTextureModelProps) {
|
|
64
|
+
super(device, {
|
|
65
|
+
id: props.id || 'background-texture-model',
|
|
66
|
+
source: BACKGROUND_FS_WGSL,
|
|
67
|
+
fs: BACKGROUND_FS,
|
|
68
|
+
parameters: {
|
|
69
|
+
depthWriteEnabled: false,
|
|
70
|
+
depthCompare: 'always',
|
|
71
|
+
...(props.blend
|
|
72
|
+
? {
|
|
73
|
+
blend: true,
|
|
74
|
+
blendColorOperation: 'add',
|
|
75
|
+
blendAlphaOperation: 'add',
|
|
76
|
+
blendColorSrcFactor: 'one',
|
|
77
|
+
blendColorDstFactor: 'one-minus-src-color',
|
|
78
|
+
blendAlphaSrcFactor: 'one',
|
|
79
|
+
blendAlphaDstFactor: 'one-minus-src-alpha'
|
|
80
|
+
}
|
|
81
|
+
: {})
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
this.setTexture(props.backgroundTexture);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
setTexture(backgroundTexture: Texture | AsyncTexture): void {
|
|
89
|
+
this.setBindings({
|
|
90
|
+
backgroundTexture
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
override predraw(): void {
|
|
95
|
+
this.shaderInputs.setProps({});
|
|
96
|
+
super.predraw();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {ShaderModule} from '@luma.gl/shadertools';
|
|
6
|
+
|
|
7
|
+
const BACKGROUND_FS = /* glsl */ `\
|
|
8
|
+
#version 300 es
|
|
9
|
+
|
|
10
|
+
uniform billboardTextureUniforms {
|
|
11
|
+
vec2 topLeft;
|
|
12
|
+
vec2 bottomRight;
|
|
13
|
+
} billboardTexture;
|
|
14
|
+
|
|
15
|
+
precision highp float;
|
|
16
|
+
uniform sampler2D backgroundTexture;
|
|
17
|
+
out vec4 fragColor;
|
|
18
|
+
|
|
19
|
+
vec2 billboardTexture_getTextureUV() {
|
|
20
|
+
ivec2 iTexSize = textureSize(backgroundTexture, 0) * 2;
|
|
21
|
+
vec2 texSize = vec2(float(iTexSize.x), float(iTexSize.y));
|
|
22
|
+
vec2 position = gl_FragCoord.xy / texSize;
|
|
23
|
+
return position;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
void main(void) {
|
|
27
|
+
vec2 position = billboardTexture_getTextureUV();
|
|
28
|
+
fragColor = texture(backgroundTexture, position);
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
type BillboardTextureProps = {
|
|
33
|
+
aspect: number;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type BillboardTextureUniforms = {
|
|
37
|
+
topLeft: [number, number];
|
|
38
|
+
bottomRight: [number, number];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const billboardTexture = {
|
|
42
|
+
name: 'billboardTexture',
|
|
43
|
+
fs: BACKGROUND_FS,
|
|
44
|
+
dependencies: [],
|
|
45
|
+
uniformTypes: {
|
|
46
|
+
topLeft: 'vec2<f32>',
|
|
47
|
+
bottomRight: 'vec2<f32>'
|
|
48
|
+
}
|
|
49
|
+
} as const satisfies ShaderModule<BillboardTextureProps, BillboardTextureUniforms>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
// ClipSpace
|
|
6
|
+
import {Device} from '@luma.gl/core';
|
|
7
|
+
import {Model, ModelProps} from '../model/model';
|
|
8
|
+
import {Geometry} from '../geometry/geometry';
|
|
9
|
+
import {uid} from '../utils/uid';
|
|
10
|
+
|
|
11
|
+
const CLIPSPACE_VERTEX_SHADER_WGSL = /* wgsl */ `\
|
|
12
|
+
struct VertexInputs {
|
|
13
|
+
@location(0) clipSpacePosition: vec2<f32>,
|
|
14
|
+
@location(1) texCoord: vec2<f32>,
|
|
15
|
+
@location(2) coordinate: vec2<f32>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
struct FragmentInputs {
|
|
19
|
+
@builtin(position) Position : vec4<f32>,
|
|
20
|
+
@location(0) position : vec2<f32>,
|
|
21
|
+
@location(1) coordinate : vec2<f32>,
|
|
22
|
+
@location(2) uv : vec2<f32>
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
@vertex
|
|
26
|
+
fn vertexMain(inputs: VertexInputs) -> FragmentInputs {
|
|
27
|
+
var outputs: FragmentInputs;
|
|
28
|
+
outputs.Position = vec4(inputs.clipSpacePosition, 0., 1.);
|
|
29
|
+
outputs.position = inputs.clipSpacePosition;
|
|
30
|
+
outputs.coordinate = inputs.coordinate;
|
|
31
|
+
outputs.uv = inputs.texCoord;
|
|
32
|
+
return outputs;
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
const CLIPSPACE_VERTEX_SHADER = /* glsl */ `\
|
|
37
|
+
#version 300 es
|
|
38
|
+
in vec2 clipSpacePosition;
|
|
39
|
+
in vec2 texCoord;
|
|
40
|
+
in vec2 coordinate;
|
|
41
|
+
|
|
42
|
+
out vec2 position;
|
|
43
|
+
out vec2 coordinate;
|
|
44
|
+
out vec2 uv;
|
|
45
|
+
|
|
46
|
+
void main(void) {
|
|
47
|
+
gl_Position = vec4(clipSpacePosition, 0., 1.);
|
|
48
|
+
position = clipSpacePosition;
|
|
49
|
+
coordinate = coordinate;
|
|
50
|
+
uv = texCoord;
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
/* eslint-disable indent, no-multi-spaces */
|
|
55
|
+
const POSITIONS = [-1, -1, 1, -1, -1, 1, 1, 1];
|
|
56
|
+
|
|
57
|
+
/** Props for ClipSpace */
|
|
58
|
+
export type ClipSpaceProps = Omit<ModelProps, 'vs' | 'vertexCount' | 'geometry'>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A flat geometry that covers the "visible area" that the GPU renders.
|
|
62
|
+
*/
|
|
63
|
+
export class ClipSpace extends Model {
|
|
64
|
+
constructor(device: Device, props: ClipSpaceProps) {
|
|
65
|
+
const TEX_COORDS = POSITIONS.map(coord => (coord === -1 ? 0 : coord));
|
|
66
|
+
|
|
67
|
+
// For WGSL we need to append the supplied fragment shader to the default vertex shader source
|
|
68
|
+
if (props.source) {
|
|
69
|
+
props = {...props, source: `${CLIPSPACE_VERTEX_SHADER_WGSL}\n${props.source}`};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
super(device, {
|
|
73
|
+
id: props.id || uid('clip-space'),
|
|
74
|
+
...props,
|
|
75
|
+
vs: CLIPSPACE_VERTEX_SHADER,
|
|
76
|
+
vertexCount: 4,
|
|
77
|
+
geometry: new Geometry({
|
|
78
|
+
topology: 'triangle-strip',
|
|
79
|
+
vertexCount: 4,
|
|
80
|
+
attributes: {
|
|
81
|
+
clipSpacePosition: {size: 2, value: new Float32Array(POSITIONS)},
|
|
82
|
+
texCoord: {size: 2, value: new Float32Array(TEX_COORDS)},
|
|
83
|
+
coordinate: {size: 2, value: new Float32Array(TEX_COORDS)}
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|