@luma.gl/engine 9.0.0-beta.6 → 9.0.0-beta.7
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/computation.d.ts +95 -0
- package/dist/computation.d.ts.map +1 -0
- package/dist/computation.js +248 -0
- package/dist/debug/copy-texture-to-image.js +1 -1
- package/dist/dist.dev.js +573 -278
- package/dist/geometry/gpu-geometry.d.ts.map +1 -1
- package/dist/geometry/gpu-geometry.js +4 -5
- package/dist/index.cjs +573 -285
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/clip-space.js +5 -7
- package/dist/lib/pipeline-factory.d.ts +10 -6
- package/dist/lib/pipeline-factory.d.ts.map +1 -1
- package/dist/lib/pipeline-factory.js +44 -22
- package/dist/lib/shader-factory.d.ts.map +1 -1
- package/dist/lib/shader-factory.js +6 -4
- package/dist/model/model.d.ts +45 -44
- package/dist/model/model.d.ts.map +1 -1
- package/dist/model/model.js +171 -104
- package/dist/scenegraph/model-node.d.ts +1 -1
- package/dist.min.js +2 -2
- package/package.json +2 -2
- package/src/computation.ts +346 -0
- package/src/geometry/gpu-geometry.ts +4 -5
- package/src/index.ts +2 -0
- package/src/lib/pipeline-factory.ts +58 -27
- package/src/lib/shader-factory.ts +6 -4
- package/src/model/model.ts +201 -130
package/dist/model/model.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// luma.gl
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
|
-
import { Buffer,
|
|
5
|
-
import {
|
|
4
|
+
import { Buffer, Texture, TextureView, Sampler } from '@luma.gl/core';
|
|
5
|
+
import { RenderPipeline, UniformStore } from '@luma.gl/core';
|
|
6
|
+
import { log, uid, deepEqual, isObjectEmpty, splitUniformsAndBindings } from '@luma.gl/core';
|
|
6
7
|
import { getTypedArrayFromDataType, getAttributeInfosFromLayouts } from '@luma.gl/core';
|
|
7
8
|
import { ShaderAssembler, getShaderLayoutFromWGSL } from '@luma.gl/shadertools';
|
|
8
|
-
import { ShaderInputs } from "../shader-inputs.js";
|
|
9
9
|
import { makeGPUGeometry } from "../geometry/gpu-geometry.js";
|
|
10
|
+
import { ShaderInputs } from "../shader-inputs.js";
|
|
10
11
|
import { PipelineFactory } from "../lib/pipeline-factory.js";
|
|
11
12
|
import { ShaderFactory } from "../lib/shader-factory.js";
|
|
12
13
|
import { getDebugTableForShaderLayout } from "../debug/debug-shader-layout.js";
|
|
@@ -48,6 +49,7 @@ export class Model {
|
|
|
48
49
|
};
|
|
49
50
|
device;
|
|
50
51
|
id;
|
|
52
|
+
source;
|
|
51
53
|
vs;
|
|
52
54
|
fs;
|
|
53
55
|
pipelineFactory;
|
|
@@ -88,12 +90,15 @@ export class Model {
|
|
|
88
90
|
/** ShaderInputs instance */
|
|
89
91
|
shaderInputs;
|
|
90
92
|
_uniformStore;
|
|
91
|
-
_pipelineNeedsUpdate = 'newly created';
|
|
92
93
|
_attributeInfos = {};
|
|
93
94
|
_gpuGeometry = null;
|
|
94
95
|
_getModuleUniforms;
|
|
95
96
|
props;
|
|
97
|
+
_pipelineNeedsUpdate = 'newly created';
|
|
98
|
+
_needsRedraw = 'initializing';
|
|
96
99
|
_destroyed = false;
|
|
100
|
+
/** "Time" of last draw. Monotonically increasing timestamp */
|
|
101
|
+
_lastDrawTimestamp = -1;
|
|
97
102
|
constructor(device, props) {
|
|
98
103
|
this.props = { ...Model.defaultProps, ...props };
|
|
99
104
|
props = this.props;
|
|
@@ -103,32 +108,36 @@ export class Model {
|
|
|
103
108
|
// Setup shader module inputs
|
|
104
109
|
const moduleMap = Object.fromEntries(this.props.modules?.map(module => [module.name, module]) || []);
|
|
105
110
|
this.setShaderInputs(props.shaderInputs || new ShaderInputs(moduleMap));
|
|
106
|
-
const isWebGPU = this.device.info.type === 'webgpu';
|
|
107
|
-
// TODO - hack to support unified WGSL shader
|
|
108
|
-
// TODO - this is wrong, compile a single shader
|
|
109
|
-
if (this.props.source) {
|
|
110
|
-
if (isWebGPU) {
|
|
111
|
-
this.props.shaderLayout ||= getShaderLayoutFromWGSL(this.props.source);
|
|
112
|
-
}
|
|
113
|
-
this.props.fs = this.props.source;
|
|
114
|
-
this.props.vs = this.props.source;
|
|
115
|
-
}
|
|
116
|
-
// Support WGSL shader layout introspection
|
|
117
|
-
if (isWebGPU && typeof this.props.vs !== 'string') {
|
|
118
|
-
this.props.shaderLayout ||= getShaderLayoutFromWGSL(this.props.vs.wgsl);
|
|
119
|
-
}
|
|
120
111
|
// Setup shader assembler
|
|
121
112
|
const platformInfo = getPlatformInfo(device);
|
|
122
113
|
// Extract modules from shader inputs if not supplied
|
|
123
114
|
const modules = (this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || [];
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
115
|
+
const isWebGPU = this.device.type === 'webgpu';
|
|
116
|
+
// WebGPU
|
|
117
|
+
// TODO - hack to support unified WGSL shader
|
|
118
|
+
// TODO - this is wrong, compile a single shader
|
|
119
|
+
if (isWebGPU && this.props.source) {
|
|
120
|
+
// WGSL
|
|
121
|
+
this.props.shaderLayout ||= getShaderLayoutFromWGSL(this.props.source);
|
|
122
|
+
const { source, getUniforms } = this.props.shaderAssembler.assembleShader({
|
|
123
|
+
platformInfo,
|
|
124
|
+
...this.props,
|
|
125
|
+
modules
|
|
126
|
+
});
|
|
127
|
+
this.source = source;
|
|
128
|
+
this._getModuleUniforms = getUniforms;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
// GLSL
|
|
132
|
+
const { vs, fs, getUniforms } = this.props.shaderAssembler.assembleShaderPair({
|
|
133
|
+
platformInfo,
|
|
134
|
+
...this.props,
|
|
135
|
+
modules
|
|
136
|
+
});
|
|
137
|
+
this.vs = vs;
|
|
138
|
+
this.fs = fs;
|
|
139
|
+
this._getModuleUniforms = getUniforms;
|
|
140
|
+
}
|
|
132
141
|
this.vertexCount = this.props.vertexCount;
|
|
133
142
|
this.instanceCount = this.props.instanceCount;
|
|
134
143
|
this.topology = this.props.topology;
|
|
@@ -136,7 +145,7 @@ export class Model {
|
|
|
136
145
|
this.parameters = this.props.parameters;
|
|
137
146
|
// Geometry, if provided, sets topology and vertex cound
|
|
138
147
|
if (props.geometry) {
|
|
139
|
-
this.
|
|
148
|
+
this.setGeometry(props.geometry);
|
|
140
149
|
}
|
|
141
150
|
this.pipelineFactory =
|
|
142
151
|
props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
|
|
@@ -194,31 +203,55 @@ export class Model {
|
|
|
194
203
|
return;
|
|
195
204
|
this.pipelineFactory.release(this.pipeline);
|
|
196
205
|
this.shaderFactory.release(this.pipeline.vs);
|
|
197
|
-
|
|
206
|
+
if (this.pipeline.fs) {
|
|
207
|
+
this.shaderFactory.release(this.pipeline.fs);
|
|
208
|
+
}
|
|
198
209
|
this._uniformStore.destroy();
|
|
210
|
+
// TODO - mark resource as managed and destroyIfManaged() ?
|
|
211
|
+
this._gpuGeometry?.destroy();
|
|
199
212
|
this._destroyed = true;
|
|
200
213
|
}
|
|
201
214
|
// Draw call
|
|
215
|
+
/** Query redraw status. Clears the status. */
|
|
216
|
+
needsRedraw() {
|
|
217
|
+
// Catch any writes to already bound resources
|
|
218
|
+
if (this._getBindingsUpdateTimestamp() > this._lastDrawTimestamp) {
|
|
219
|
+
this.setNeedsRedraw('contents of bound textures or buffers updated');
|
|
220
|
+
}
|
|
221
|
+
const needsRedraw = this._needsRedraw;
|
|
222
|
+
this._needsRedraw = false;
|
|
223
|
+
return needsRedraw;
|
|
224
|
+
}
|
|
225
|
+
/** Mark the model as needing a redraw */
|
|
226
|
+
setNeedsRedraw(reason) {
|
|
227
|
+
this._needsRedraw ||= reason;
|
|
228
|
+
}
|
|
202
229
|
predraw() {
|
|
203
230
|
// Update uniform buffers if needed
|
|
204
231
|
this.updateShaderInputs();
|
|
232
|
+
// Check if the pipeline is invalidated
|
|
233
|
+
this.pipeline = this._updatePipeline();
|
|
205
234
|
}
|
|
206
235
|
draw(renderPass) {
|
|
207
236
|
this.predraw();
|
|
237
|
+
let drawSuccess;
|
|
208
238
|
try {
|
|
209
239
|
this._logDrawCallStart();
|
|
210
|
-
//
|
|
211
|
-
// TODO -
|
|
240
|
+
// Update the pipeline if invalidated
|
|
241
|
+
// TODO - inside RenderPass is likely the worst place to do this from performance perspective.
|
|
242
|
+
// Application can call Model.predraw() to avoid this.
|
|
212
243
|
this.pipeline = this._updatePipeline();
|
|
213
244
|
// Set pipeline state, we may be sharing a pipeline so we need to set all state on every draw
|
|
214
245
|
// Any caching needs to be done inside the pipeline functions
|
|
215
246
|
this.pipeline.setBindings(this.bindings);
|
|
216
|
-
|
|
247
|
+
if (!isObjectEmpty(this.uniforms)) {
|
|
248
|
+
this.pipeline.setUniformsWebGL(this.uniforms);
|
|
249
|
+
}
|
|
217
250
|
const { indexBuffer } = this.vertexArray;
|
|
218
251
|
const indexCount = indexBuffer
|
|
219
252
|
? indexBuffer.byteLength / (indexBuffer.indexType === 'uint32' ? 4 : 2)
|
|
220
253
|
: undefined;
|
|
221
|
-
this.pipeline.draw({
|
|
254
|
+
drawSuccess = this.pipeline.draw({
|
|
222
255
|
renderPass,
|
|
223
256
|
vertexArray: this.vertexArray,
|
|
224
257
|
vertexCount: this.vertexCount,
|
|
@@ -231,6 +264,15 @@ export class Model {
|
|
|
231
264
|
this._logDrawCallEnd();
|
|
232
265
|
}
|
|
233
266
|
this._logFramebuffer(renderPass);
|
|
267
|
+
// Update needsRedraw flag
|
|
268
|
+
if (drawSuccess) {
|
|
269
|
+
this._lastDrawTimestamp = this.device.timestamp;
|
|
270
|
+
this._needsRedraw = false;
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
this._needsRedraw = 'waiting for resource initialization';
|
|
274
|
+
}
|
|
275
|
+
return drawSuccess;
|
|
234
276
|
}
|
|
235
277
|
// Update fixed fields (can trigger pipeline rebuild)
|
|
236
278
|
/**
|
|
@@ -239,33 +281,16 @@ export class Model {
|
|
|
239
281
|
* @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU
|
|
240
282
|
*/
|
|
241
283
|
setGeometry(geometry) {
|
|
284
|
+
this._gpuGeometry?.destroy();
|
|
242
285
|
const gpuGeometry = geometry && makeGPUGeometry(this.device, geometry);
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
this.
|
|
247
|
-
|
|
248
|
-
return gpuGeometry;
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Updates the optional geometry attributes
|
|
252
|
-
* Geometry, sets several attributes, indexBuffer, and also vertex count
|
|
253
|
-
* @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU
|
|
254
|
-
*/
|
|
255
|
-
_setGeometryAttributes(gpuGeometry) {
|
|
256
|
-
// Filter geometry attribute so that we don't issue warnings for unused attributes
|
|
257
|
-
const attributes = { ...gpuGeometry.attributes };
|
|
258
|
-
for (const [attributeName] of Object.entries(attributes)) {
|
|
259
|
-
if (!this.pipeline.shaderLayout.attributes.find(layout => layout.name === attributeName) &&
|
|
260
|
-
attributeName !== 'positions') {
|
|
261
|
-
delete attributes[attributeName];
|
|
286
|
+
if (gpuGeometry) {
|
|
287
|
+
this.setTopology(gpuGeometry.topology || 'triangle-list');
|
|
288
|
+
this.bufferLayout = mergeBufferLayouts(gpuGeometry.bufferLayout, this.bufferLayout);
|
|
289
|
+
if (this.vertexArray) {
|
|
290
|
+
this._setGeometryAttributes(gpuGeometry);
|
|
262
291
|
}
|
|
263
292
|
}
|
|
264
|
-
|
|
265
|
-
this.vertexCount = gpuGeometry.vertexCount;
|
|
266
|
-
this.setIndexBuffer(gpuGeometry.indices);
|
|
267
|
-
this.setAttributes(gpuGeometry.attributes, { ignoreUnknownAttributes: true });
|
|
268
|
-
this.setAttributes(attributes, { ignoreUnknownAttributes: this.props.ignoreUnknownAttributes });
|
|
293
|
+
this._gpuGeometry = gpuGeometry;
|
|
269
294
|
}
|
|
270
295
|
/**
|
|
271
296
|
* Updates the primitive topology ('triangle-list', 'triangle-strip' etc).
|
|
@@ -285,7 +310,6 @@ export class Model {
|
|
|
285
310
|
this.bufferLayout = this._gpuGeometry
|
|
286
311
|
? mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout)
|
|
287
312
|
: bufferLayout;
|
|
288
|
-
this._setPipelineNeedsUpdate('bufferLayout');
|
|
289
313
|
// Recreate the pipeline
|
|
290
314
|
this.pipeline = this._updatePipeline();
|
|
291
315
|
// vertex array needs to be updated if we update buffer layout,
|
|
@@ -297,6 +321,7 @@ export class Model {
|
|
|
297
321
|
if (this._gpuGeometry) {
|
|
298
322
|
this._setGeometryAttributes(this._gpuGeometry);
|
|
299
323
|
}
|
|
324
|
+
this._setPipelineNeedsUpdate('bufferLayout');
|
|
300
325
|
}
|
|
301
326
|
/**
|
|
302
327
|
* Set GPU parameters.
|
|
@@ -316,6 +341,7 @@ export class Model {
|
|
|
316
341
|
*/
|
|
317
342
|
setVertexCount(vertexCount) {
|
|
318
343
|
this.vertexCount = vertexCount;
|
|
344
|
+
this.setNeedsRedraw('vertexCount');
|
|
319
345
|
}
|
|
320
346
|
/**
|
|
321
347
|
* Updates the instance count (used in draw calls)
|
|
@@ -323,6 +349,7 @@ export class Model {
|
|
|
323
349
|
*/
|
|
324
350
|
setInstanceCount(instanceCount) {
|
|
325
351
|
this.instanceCount = instanceCount;
|
|
352
|
+
this.setNeedsRedraw('instanceCount');
|
|
326
353
|
}
|
|
327
354
|
setShaderInputs(shaderInputs) {
|
|
328
355
|
this.shaderInputs = shaderInputs;
|
|
@@ -332,51 +359,26 @@ export class Model {
|
|
|
332
359
|
const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
|
|
333
360
|
this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
|
|
334
361
|
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Updates shader module settings (which results in uniforms being set)
|
|
338
|
-
*/
|
|
339
|
-
setShaderModuleProps(props) {
|
|
340
|
-
const uniforms = this._getModuleUniforms(props);
|
|
341
|
-
// Extract textures & framebuffers set by the modules
|
|
342
|
-
// TODO better way to extract bindings
|
|
343
|
-
const keys = Object.keys(uniforms).filter(k => {
|
|
344
|
-
const uniform = uniforms[k];
|
|
345
|
-
return !isNumberArray(uniform) && typeof uniform !== 'number' && typeof uniform !== 'boolean';
|
|
346
|
-
});
|
|
347
|
-
const bindings = {};
|
|
348
|
-
for (const k of keys) {
|
|
349
|
-
bindings[k] = uniforms[k];
|
|
350
|
-
delete uniforms[k];
|
|
351
|
-
}
|
|
362
|
+
this.setNeedsRedraw('shaderInputs');
|
|
352
363
|
}
|
|
353
364
|
updateShaderInputs() {
|
|
354
365
|
this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
* @deprecated Updates shader module settings (which results in uniforms being set)
|
|
358
|
-
*/
|
|
359
|
-
updateModuleSettings(props) {
|
|
360
|
-
log.warn('Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()')();
|
|
361
|
-
const { bindings, uniforms } = splitUniformsAndBindings(this._getModuleUniforms(props));
|
|
362
|
-
Object.assign(this.bindings, bindings);
|
|
363
|
-
Object.assign(this.uniforms, uniforms);
|
|
366
|
+
// TODO - this is already tracked through buffer/texture update times?
|
|
367
|
+
this.setNeedsRedraw('shaderInputs');
|
|
364
368
|
}
|
|
365
369
|
/**
|
|
366
370
|
* Sets bindings (textures, samplers, uniform buffers)
|
|
367
371
|
*/
|
|
368
372
|
setBindings(bindings) {
|
|
369
373
|
Object.assign(this.bindings, bindings);
|
|
374
|
+
this.setNeedsRedraw('bindings');
|
|
370
375
|
}
|
|
371
376
|
/**
|
|
372
|
-
*
|
|
373
|
-
* @deprecated WebGL only, use uniform buffers for portability
|
|
374
|
-
* @param uniforms
|
|
375
|
-
* @returns self for chaining
|
|
377
|
+
* Updates optional transform feedback. WebGL only.
|
|
376
378
|
*/
|
|
377
|
-
|
|
378
|
-
this.
|
|
379
|
-
|
|
379
|
+
setTransformFeedback(transformFeedback) {
|
|
380
|
+
this.transformFeedback = transformFeedback;
|
|
381
|
+
this.setNeedsRedraw('transformFeedback');
|
|
380
382
|
}
|
|
381
383
|
/**
|
|
382
384
|
* Sets the index buffer
|
|
@@ -384,12 +386,7 @@ export class Model {
|
|
|
384
386
|
*/
|
|
385
387
|
setIndexBuffer(indexBuffer) {
|
|
386
388
|
this.vertexArray.setIndexBuffer(indexBuffer);
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Updates optional transform feedback. WebGL only.
|
|
390
|
-
*/
|
|
391
|
-
setTransformFeedback(transformFeedback) {
|
|
392
|
-
this.transformFeedback = transformFeedback;
|
|
389
|
+
this.setNeedsRedraw('indexBuffer');
|
|
393
390
|
}
|
|
394
391
|
/**
|
|
395
392
|
* Sets attributes (buffers)
|
|
@@ -419,6 +416,7 @@ export class Model {
|
|
|
419
416
|
log.warn(`Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"`)();
|
|
420
417
|
}
|
|
421
418
|
}
|
|
419
|
+
this.setNeedsRedraw('attributes');
|
|
422
420
|
}
|
|
423
421
|
/**
|
|
424
422
|
* Sets constant attributes
|
|
@@ -438,10 +436,75 @@ export class Model {
|
|
|
438
436
|
log.warn(`Model "${this.id}: Ignoring constant supplied for unknown attribute "${attributeName}"`)();
|
|
439
437
|
}
|
|
440
438
|
}
|
|
439
|
+
this.setNeedsRedraw('constants');
|
|
440
|
+
}
|
|
441
|
+
// DEPRECATED METHODS
|
|
442
|
+
/**
|
|
443
|
+
* Sets individual uniforms
|
|
444
|
+
* @deprecated WebGL only, use uniform buffers for portability
|
|
445
|
+
* @param uniforms
|
|
446
|
+
*/
|
|
447
|
+
setUniforms(uniforms) {
|
|
448
|
+
if (!isObjectEmpty(uniforms)) {
|
|
449
|
+
this.pipeline.setUniformsWebGL(uniforms);
|
|
450
|
+
Object.assign(this.uniforms, uniforms);
|
|
451
|
+
}
|
|
452
|
+
this.setNeedsRedraw('uniforms');
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* @deprecated Updates shader module settings (which results in uniforms being set)
|
|
456
|
+
*/
|
|
457
|
+
updateModuleSettings(props) {
|
|
458
|
+
log.warn('Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()')();
|
|
459
|
+
const { bindings, uniforms } = splitUniformsAndBindings(this._getModuleUniforms(props));
|
|
460
|
+
Object.assign(this.bindings, bindings);
|
|
461
|
+
Object.assign(this.uniforms, uniforms);
|
|
462
|
+
this.setNeedsRedraw('moduleSettings');
|
|
463
|
+
}
|
|
464
|
+
// Internal methods
|
|
465
|
+
/** Get the timestamp of the latest updated bound GPU memory resource (buffer/texture). */
|
|
466
|
+
_getBindingsUpdateTimestamp() {
|
|
467
|
+
let timestamp = 0;
|
|
468
|
+
for (const binding of Object.values(this.bindings)) {
|
|
469
|
+
if (binding instanceof TextureView) {
|
|
470
|
+
timestamp = Math.max(timestamp, binding.texture.updateTimestamp);
|
|
471
|
+
}
|
|
472
|
+
else if (binding instanceof Buffer || binding instanceof Texture) {
|
|
473
|
+
timestamp = Math.max(timestamp, binding.updateTimestamp);
|
|
474
|
+
}
|
|
475
|
+
else if (!(binding instanceof Sampler)) {
|
|
476
|
+
timestamp = Math.max(timestamp, binding.buffer.updateTimestamp);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return timestamp;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Updates the optional geometry attributes
|
|
483
|
+
* Geometry, sets several attributes, indexBuffer, and also vertex count
|
|
484
|
+
* @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU
|
|
485
|
+
*/
|
|
486
|
+
_setGeometryAttributes(gpuGeometry) {
|
|
487
|
+
// Filter geometry attribute so that we don't issue warnings for unused attributes
|
|
488
|
+
const attributes = { ...gpuGeometry.attributes };
|
|
489
|
+
for (const [attributeName] of Object.entries(attributes)) {
|
|
490
|
+
if (!this.pipeline.shaderLayout.attributes.find(layout => layout.name === attributeName) &&
|
|
491
|
+
attributeName !== 'positions') {
|
|
492
|
+
delete attributes[attributeName];
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
// TODO - delete previous geometry?
|
|
496
|
+
this.vertexCount = gpuGeometry.vertexCount;
|
|
497
|
+
this.setIndexBuffer(gpuGeometry.indices);
|
|
498
|
+
this.setAttributes(gpuGeometry.attributes, { ignoreUnknownAttributes: true });
|
|
499
|
+
this.setAttributes(attributes, { ignoreUnknownAttributes: this.props.ignoreUnknownAttributes });
|
|
500
|
+
this.setNeedsRedraw('geometry attributes');
|
|
441
501
|
}
|
|
502
|
+
/** Mark pipeline as needing update */
|
|
442
503
|
_setPipelineNeedsUpdate(reason) {
|
|
443
|
-
this._pipelineNeedsUpdate
|
|
504
|
+
this._pipelineNeedsUpdate ||= reason;
|
|
505
|
+
this.setNeedsRedraw(reason);
|
|
444
506
|
}
|
|
507
|
+
/** Update pipeline if needed */
|
|
445
508
|
_updatePipeline() {
|
|
446
509
|
if (this._pipelineNeedsUpdate) {
|
|
447
510
|
let prevShaderVs = null;
|
|
@@ -455,17 +518,21 @@ export class Model {
|
|
|
455
518
|
const vs = this.shaderFactory.createShader({
|
|
456
519
|
id: `${this.id}-vertex`,
|
|
457
520
|
stage: 'vertex',
|
|
458
|
-
source: this.vs,
|
|
521
|
+
source: this.source || this.vs,
|
|
459
522
|
debug: this.props.debugShaders
|
|
460
523
|
});
|
|
461
|
-
|
|
462
|
-
|
|
524
|
+
let fs = null;
|
|
525
|
+
if (this.source) {
|
|
526
|
+
fs = vs;
|
|
527
|
+
}
|
|
528
|
+
else if (this.fs) {
|
|
529
|
+
fs = this.shaderFactory.createShader({
|
|
463
530
|
id: `${this.id}-fragment`,
|
|
464
531
|
stage: 'fragment',
|
|
465
|
-
source: this.fs,
|
|
532
|
+
source: this.source || this.fs,
|
|
466
533
|
debug: this.props.debugShaders
|
|
467
|
-
})
|
|
468
|
-
|
|
534
|
+
});
|
|
535
|
+
}
|
|
469
536
|
this.pipeline = this.pipelineFactory.createRenderPipeline({
|
|
470
537
|
...this.props,
|
|
471
538
|
bufferLayout: this.bufferLayout,
|
|
@@ -576,7 +643,7 @@ function mergeBufferLayouts(layouts1, layouts2) {
|
|
|
576
643
|
/** Create a shadertools platform info from the Device */
|
|
577
644
|
export function getPlatformInfo(device) {
|
|
578
645
|
return {
|
|
579
|
-
type: device.
|
|
646
|
+
type: device.type,
|
|
580
647
|
shaderLanguage: device.info.shadingLanguage,
|
|
581
648
|
shaderLanguageVersion: device.info.shadingLanguageVersion,
|
|
582
649
|
gpu: device.info.gpu,
|
|
@@ -13,6 +13,6 @@ export declare class ModelNode extends ScenegraphNode {
|
|
|
13
13
|
constructor(props: ModelNodeProps);
|
|
14
14
|
getBounds(): [number[], number[]] | null;
|
|
15
15
|
destroy(): void;
|
|
16
|
-
draw(renderPass?: RenderPass):
|
|
16
|
+
draw(renderPass?: RenderPass): boolean;
|
|
17
17
|
}
|
|
18
18
|
//# sourceMappingURL=model-node.d.ts.map
|