@luma.gl/engine 9.1.0-alpha.9 → 9.1.0-beta.3
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 +31 -0
- 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 +2697 -5857
- package/dist/dist.min.js +420 -103
- 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 +1416 -209
- 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 +93 -70
- 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 -21
- package/dist/shader-inputs.d.ts.map +1 -1
- package/dist/shader-inputs.js +15 -11
- 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 +39 -7
- 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 +133 -78
- 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 +27 -48
- 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;
|
|
@@ -213,6 +241,7 @@ export class Model {
|
|
|
213
241
|
const moduleMap = Object.fromEntries(
|
|
214
242
|
this.props.modules?.map(module => [module.name, module]) || []
|
|
215
243
|
);
|
|
244
|
+
// @ts-expect-error Fix typings
|
|
216
245
|
this.setShaderInputs(props.shaderInputs || new ShaderInputs(moduleMap));
|
|
217
246
|
|
|
218
247
|
// Setup shader assembler
|
|
@@ -274,7 +303,8 @@ export class Model {
|
|
|
274
303
|
this.pipeline = this._updatePipeline();
|
|
275
304
|
|
|
276
305
|
this.vertexArray = device.createVertexArray({
|
|
277
|
-
|
|
306
|
+
shaderLayout: this.pipeline.shaderLayout,
|
|
307
|
+
bufferLayout: this.pipeline.bufferLayout
|
|
278
308
|
});
|
|
279
309
|
|
|
280
310
|
// Now we can apply geometry attributes
|
|
@@ -306,11 +336,11 @@ export class Model {
|
|
|
306
336
|
this.setBindings(props.bindings);
|
|
307
337
|
}
|
|
308
338
|
if (props.uniforms) {
|
|
309
|
-
this.
|
|
339
|
+
this.setUniformsWebGL(props.uniforms);
|
|
310
340
|
}
|
|
311
341
|
if (props.moduleSettings) {
|
|
312
342
|
// log.warn('Model.props.moduleSettings is deprecated. Use Model.shaderInputs.setProps()')();
|
|
313
|
-
this.
|
|
343
|
+
this.updateModuleSettingsWebGL(props.moduleSettings);
|
|
314
344
|
}
|
|
315
345
|
if (props.transformFeedback) {
|
|
316
346
|
this.transformFeedback = props.transformFeedback;
|
|
@@ -321,16 +351,19 @@ export class Model {
|
|
|
321
351
|
}
|
|
322
352
|
|
|
323
353
|
destroy(): void {
|
|
324
|
-
if (this._destroyed)
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
this.shaderFactory.release(this.pipeline.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
+
}
|
|
334
367
|
}
|
|
335
368
|
|
|
336
369
|
// Draw call
|
|
@@ -351,7 +384,7 @@ export class Model {
|
|
|
351
384
|
this._needsRedraw ||= reason;
|
|
352
385
|
}
|
|
353
386
|
|
|
354
|
-
predraw() {
|
|
387
|
+
predraw(): void {
|
|
355
388
|
// Update uniform buffers if needed
|
|
356
389
|
this.updateShaderInputs();
|
|
357
390
|
// Check if the pipeline is invalidated
|
|
@@ -359,10 +392,22 @@ export class Model {
|
|
|
359
392
|
}
|
|
360
393
|
|
|
361
394
|
draw(renderPass: RenderPass): boolean {
|
|
362
|
-
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
|
+
}
|
|
363
407
|
|
|
364
408
|
let drawSuccess: boolean;
|
|
365
409
|
try {
|
|
410
|
+
renderPass.pushDebugGroup(`${this}.draw(${renderPass})`);
|
|
366
411
|
this._logDrawCallStart();
|
|
367
412
|
|
|
368
413
|
// Update the pipeline if invalidated
|
|
@@ -373,6 +418,7 @@ export class Model {
|
|
|
373
418
|
// Set pipeline state, we may be sharing a pipeline so we need to set all state on every draw
|
|
374
419
|
// Any caching needs to be done inside the pipeline functions
|
|
375
420
|
// TODO this is a busy initialized check for all bindings every frame
|
|
421
|
+
|
|
376
422
|
const syncBindings = this._getBindings();
|
|
377
423
|
this.pipeline.setBindings(syncBindings, {
|
|
378
424
|
disableWarnings: this.props.disableWarnings
|
|
@@ -401,6 +447,7 @@ export class Model {
|
|
|
401
447
|
topology: this.topology
|
|
402
448
|
});
|
|
403
449
|
} finally {
|
|
450
|
+
renderPass.popDebugGroup();
|
|
404
451
|
this._logDrawCallEnd();
|
|
405
452
|
}
|
|
406
453
|
this._logFramebuffer(renderPass);
|
|
@@ -427,7 +474,11 @@ export class Model {
|
|
|
427
474
|
const gpuGeometry = geometry && makeGPUGeometry(this.device, geometry);
|
|
428
475
|
if (gpuGeometry) {
|
|
429
476
|
this.setTopology(gpuGeometry.topology || 'triangle-list');
|
|
430
|
-
|
|
477
|
+
const bufferLayoutHelper = new _BufferLayoutHelper(this.bufferLayout);
|
|
478
|
+
this.bufferLayout = bufferLayoutHelper.mergeBufferLayouts(
|
|
479
|
+
gpuGeometry.bufferLayout,
|
|
480
|
+
this.bufferLayout
|
|
481
|
+
);
|
|
431
482
|
if (this.vertexArray) {
|
|
432
483
|
this._setGeometryAttributes(gpuGeometry);
|
|
433
484
|
}
|
|
@@ -451,8 +502,9 @@ export class Model {
|
|
|
451
502
|
* @note Triggers a pipeline rebuild / pipeline cache fetch
|
|
452
503
|
*/
|
|
453
504
|
setBufferLayout(bufferLayout: BufferLayout[]): void {
|
|
505
|
+
const bufferLayoutHelper = new _BufferLayoutHelper(this.bufferLayout);
|
|
454
506
|
this.bufferLayout = this._gpuGeometry
|
|
455
|
-
? mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout)
|
|
507
|
+
? bufferLayoutHelper.mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout)
|
|
456
508
|
: bufferLayout;
|
|
457
509
|
this._setPipelineNeedsUpdate('bufferLayout');
|
|
458
510
|
|
|
@@ -462,7 +514,8 @@ export class Model {
|
|
|
462
514
|
// vertex array needs to be updated if we update buffer layout,
|
|
463
515
|
// but not if we update parameters
|
|
464
516
|
this.vertexArray = this.device.createVertexArray({
|
|
465
|
-
|
|
517
|
+
shaderLayout: this.pipeline.shaderLayout,
|
|
518
|
+
bufferLayout: this.pipeline.bufferLayout
|
|
466
519
|
});
|
|
467
520
|
|
|
468
521
|
// Reapply geometry attributes to the new vertex array
|
|
@@ -512,10 +565,12 @@ export class Model {
|
|
|
512
565
|
setShaderInputs(shaderInputs: ShaderInputs): void {
|
|
513
566
|
this.shaderInputs = shaderInputs;
|
|
514
567
|
this._uniformStore = new UniformStore(this.shaderInputs.modules);
|
|
515
|
-
// Create uniform buffer bindings for all modules
|
|
516
|
-
for (const moduleName of Object.
|
|
517
|
-
|
|
518
|
-
|
|
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
|
+
}
|
|
519
574
|
}
|
|
520
575
|
this.setNeedsRedraw('shaderInputs');
|
|
521
576
|
}
|
|
@@ -523,7 +578,7 @@ export class Model {
|
|
|
523
578
|
/** Update uniform buffers from the model's shader inputs */
|
|
524
579
|
updateShaderInputs(): void {
|
|
525
580
|
this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
|
|
526
|
-
this.setBindings(this.shaderInputs.
|
|
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
|
+
}
|