@pacem/pacem-3d 1.0.0-bessel → 1.0.0-binet
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/browser/pacem-3d.js +646 -2
- package/dist/browser/pacem-3d.js.map +1 -1
- package/dist/browser/pacem-3d.min.js +1 -1
- package/dist/bundle/pacem-3d.min.mjs +1 -1
- package/dist/bundle/pacem-3d.mjs +180 -1
- package/dist/bundle/pacem-3d.mjs.map +2 -2
- package/dist/docs/pacem-3d.json +29096 -0
- package/dist/esm/constants.js +3 -1
- package/dist/esm/converters.js +5 -1
- package/dist/esm/decorators.js +8 -1
- package/dist/esm/detector.js +4 -1
- package/dist/esm/geometry.js +13 -1
- package/dist/esm/index-components-drawing3d.js +1 -1
- package/dist/esm/index-components.js +1 -1
- package/dist/esm/index-drawing3d.js +1 -1
- package/dist/esm/index-iife.js +1 -1
- package/dist/esm/index-root.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/stage.js +11 -1
- package/dist/esm/types.js +77 -1
- package/package.json +2 -1
- package/typings/index.d.ts +411 -0
package/dist/browser/pacem-3d.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @pacem/pacem-3d v1.0.0-
|
|
2
|
+
* @pacem/pacem-3d v1.0.0-binet (https://js.pacem.it)
|
|
3
3
|
* Pacem (https://pacem.it)
|
|
4
4
|
* Licensed under Apache-2.0
|
|
5
5
|
*/
|
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
9
|
//namespace Pacem.Drawing3D {
|
|
10
|
+
/** Converts a `"x y z"` attribute string to/from a {@link Vector3D}. */
|
|
10
11
|
const Point3DConverter = {
|
|
11
12
|
convert: (attr) => pacemNumerical.Geometry.LinearAlgebra.Vector3D.parse(attr),
|
|
12
13
|
convertBack: (prop) => `${prop.x || 0} ${prop.y || 0} ${prop.z || 0}`
|
|
13
14
|
};
|
|
15
|
+
/** Converts a `"x y z"` (3 components) or `"n"` (single uniform component, broadcast to all 3 axes) attribute string to/from a {@link Vector3D}. Used e.g. for `scale`/`offset`. */
|
|
14
16
|
const Point3DOrNumberConverter = {
|
|
15
17
|
convert: (attr) => {
|
|
16
18
|
const arr = pacemFoundation.parseAsNumericalArray(attr);
|
|
@@ -29,10 +31,12 @@
|
|
|
29
31
|
},
|
|
30
32
|
convertBack: (prop) => `${prop.x || 0} ${prop.y || 0} ${prop.z || 0}`
|
|
31
33
|
};
|
|
34
|
+
/** Converts a `"x y z w"` attribute string to/from a {@link Quaternion}. Used e.g. for `rotate`. */
|
|
32
35
|
const QuaternionConverter = {
|
|
33
36
|
convert: (attr) => pacemNumerical.Geometry.LinearAlgebra.Quaternion.parse(attr),
|
|
34
37
|
convertBack: (prop) => `${prop.x || 0} ${prop.y || 0} ${prop.z || 0} ${prop.w || 0}`
|
|
35
38
|
};
|
|
39
|
+
/** Converts an attribute string to/from either a `boolean` (`"true"`/`"false"`) or a `number`. */
|
|
36
40
|
const BooleanOrNumberConverter = {
|
|
37
41
|
convert: (attr) => {
|
|
38
42
|
if (attr === 'true')
|
|
@@ -44,7 +48,9 @@
|
|
|
44
48
|
convertBack: (prop) => prop.toString()
|
|
45
49
|
};
|
|
46
50
|
|
|
51
|
+
/** Middle segment shared by every custom element tag name in this package (e.g. `pacem-3d`, `pacem-3d-mesh`). */
|
|
47
52
|
const TAG_MIDDLE_NAME = "3d";
|
|
53
|
+
/** Conversion factor from degrees to radians. */
|
|
48
54
|
const DEG2RAD = Math.PI / 180;
|
|
49
55
|
|
|
50
56
|
var __decorate$l = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
|
|
@@ -54,6 +60,12 @@
|
|
|
54
60
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
55
61
|
};
|
|
56
62
|
//namespace Pacem.Components.Drawing3D {
|
|
63
|
+
/**
|
|
64
|
+
* `<pacem-3d>`: the root 3d stage element. Hosts the {@link RenderableElement} scene graph (groups, meshes, lights,
|
|
65
|
+
* cameras) declared as children or provided via {@link datasource}, delegates all actual scene-building/rendering/
|
|
66
|
+
* hit-testing to the pluggable {@link adapter} ({@link Pacem3DAdapterElement}), and dispatches pointer interaction
|
|
67
|
+
* events ({@link RenderableEvent}/{@link DragEvent}) for the items under the cursor.
|
|
68
|
+
*/
|
|
57
69
|
let Pacem3DElement = class Pacem3DElement extends pacemCore.Components.PacemItemsContainerElement {
|
|
58
70
|
constructor() {
|
|
59
71
|
super(...arguments);
|
|
@@ -118,9 +130,11 @@
|
|
|
118
130
|
validate(item) {
|
|
119
131
|
return item instanceof RenderableElement;
|
|
120
132
|
}
|
|
133
|
+
/** @readonly Gets the DOM element the scene is mounted into. */
|
|
121
134
|
get stage() {
|
|
122
135
|
return this._container;
|
|
123
136
|
}
|
|
137
|
+
/** @readonly Gets the technology-dependent native scene instance, as reported by the active {@link adapter}. */
|
|
124
138
|
get scene() {
|
|
125
139
|
return this.adapter && this.adapter.getScene(this);
|
|
126
140
|
}
|
|
@@ -265,9 +279,11 @@
|
|
|
265
279
|
super.disconnectedCallback();
|
|
266
280
|
}
|
|
267
281
|
#size;
|
|
282
|
+
/** @readonly Gets the current viewport size, as last reported by the internal resize observer. */
|
|
268
283
|
get size() {
|
|
269
284
|
return this.#size;
|
|
270
285
|
}
|
|
286
|
+
/** Renders the whole scene through the active {@link adapter}, or just updates the given `item` if provided. */
|
|
271
287
|
render(item, deepUpdate, now = performance.now()) {
|
|
272
288
|
if (!pacemCore.Utils.isNull(item)) {
|
|
273
289
|
const adapter = this.adapter;
|
|
@@ -330,38 +346,49 @@
|
|
|
330
346
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
331
347
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
332
348
|
};
|
|
349
|
+
/** Type guard checking whether `object` implements the {@link Stage} contract. */
|
|
333
350
|
function isStage(object) {
|
|
334
351
|
return !pacemCore.Utils.isNull(object) && 'render' in object && typeof object['render'] === 'function';
|
|
335
352
|
}
|
|
353
|
+
/** Type guard checking whether `object` implements the {@link Renderable} contract (i.e. it is attached to a valid {@link Stage}). */
|
|
336
354
|
function isRenderable(object) {
|
|
337
355
|
return isStage(object?.stage);
|
|
338
356
|
}
|
|
357
|
+
/** Type guard checking whether `object` implements the {@link Ui3DObject} contract (i.e. it exposes a {@link Ui3DObject.transformMatrix}). */
|
|
339
358
|
function isUi3DObject(object) {
|
|
340
359
|
return 'transformMatrix' in object && isRenderable(object);
|
|
341
360
|
}
|
|
361
|
+
/** Type guard checking whether `object` implements the {@link Camera} contract. */
|
|
342
362
|
function isCamera(object) {
|
|
343
363
|
return 'type' in object && 'up' in object && 'lookAt' in object && isRenderable(object);
|
|
344
364
|
}
|
|
365
|
+
/** Type guard checking whether `object` is a {@link PerspectiveCamera}. */
|
|
345
366
|
function isPerspectiveCamera(object) {
|
|
346
367
|
return isCamera(object) && 'type' in object && object.type === 'perspective';
|
|
347
368
|
}
|
|
369
|
+
/** Type guard checking whether `object` is an {@link OrthographicCamera}. */
|
|
348
370
|
function isOrthographicCamera(object) {
|
|
349
371
|
return isCamera(object) && 'type' in object && object.type === 'orthographic';
|
|
350
372
|
}
|
|
373
|
+
/** Type guard checking whether `object` implements the {@link Light} contract. */
|
|
351
374
|
function isLight(object) {
|
|
352
375
|
return 'type' in object && (object.type === 'ambient' || object.type === 'omni' || object.type === 'direction' || object.type == 'spot') && isRenderable(object);
|
|
353
376
|
}
|
|
377
|
+
/** Type guard checking whether `object` implements the {@link Mesh} contract. */
|
|
354
378
|
function isMesh(object) {
|
|
355
379
|
return 'geometry' in object && isUi3DObject(object);
|
|
356
380
|
}
|
|
381
|
+
/** Type guard checking whether `object` implements the {@link NodeGeometry} contract. */
|
|
357
382
|
function isGeometry(object) {
|
|
358
383
|
return 'positions' in object && pacemCore.Utils.isArray(object.positions);
|
|
359
384
|
}
|
|
385
|
+
/** Type guard checking whether `object` implements the {@link MeshGeometry} contract (a {@link NodeGeometry} with triangle indices/normals/UVs). */
|
|
360
386
|
function isMeshGeometry(object) {
|
|
361
387
|
return ('triangleIndices' in object && pacemCore.Utils.isArray(object.triangleIndices)
|
|
362
388
|
|| 'normals' in object && pacemCore.Utils.isArray(object.normals)
|
|
363
389
|
|| 'textureCoordinates' in object && pacemCore.Utils.isArray(object.textureCoordinates)) && isGeometry(object);
|
|
364
390
|
}
|
|
391
|
+
/** Type guard checking whether `object` implements the {@link Group} contract. */
|
|
365
392
|
function isGroup(object) {
|
|
366
393
|
return 'childRenderables' in object && pacemCore.Utils.isArray(object['childRenderables']) && isUi3DObject(object);
|
|
367
394
|
}
|
|
@@ -397,6 +424,7 @@
|
|
|
397
424
|
const orthogonal = pacemNumerical.Geometry.LinearAlgebra.Vector3D.cross(vAB, vAC);
|
|
398
425
|
return pacemNumerical.Geometry.LinearAlgebra.Vector3D.unit(orthogonal);
|
|
399
426
|
}
|
|
427
|
+
/** Base class for the custom UI events dispatched by 3d elements/the stage, carrying the source pointer's projected {@link point} in 3d world space alongside the original DOM event. */
|
|
400
428
|
class UI3DEvent extends pacemCore.CustomUIEvent {
|
|
401
429
|
constructor(type, eventInit, originalEvent, point) {
|
|
402
430
|
super(type, eventInit, originalEvent);
|
|
@@ -408,24 +436,36 @@
|
|
|
408
436
|
return this.#point;
|
|
409
437
|
}
|
|
410
438
|
}
|
|
439
|
+
/** Event dispatched while a {@link Renderable} item is being dragged (`itemdragstart`/`itemdrag`/`itemdragend`-like events), carrying a {@link DragEventArgs} payload. */
|
|
411
440
|
class DragEvent extends UI3DEvent {
|
|
412
441
|
}
|
|
442
|
+
/** Event dispatched for pointer interactions (click/over/out/down/up) with a {@link Renderable} item, carrying the item itself as its `detail`. */
|
|
413
443
|
class RenderableEvent extends UI3DEvent {
|
|
414
444
|
constructor(type, args, originalEvent, p) {
|
|
415
445
|
super(type, { detail: args, bubbles: true, cancelable: true }, originalEvent, p);
|
|
416
446
|
}
|
|
417
447
|
}
|
|
448
|
+
/** Identifies which aspect of a {@link Renderable} changed since the last render, so the adapter can update only the stale part of the underlying native object. */
|
|
418
449
|
var StalePropertyFlag;
|
|
419
450
|
(function (StalePropertyFlag) {
|
|
451
|
+
/** The object's {@link Renderable.position} changed. */
|
|
420
452
|
StalePropertyFlag["Position"] = "position";
|
|
453
|
+
/** The object's {@link Ui3DObject.transformMatrix} (rotate/scale/offset) changed. */
|
|
421
454
|
StalePropertyFlag["Transform"] = "transform";
|
|
455
|
+
/** The mesh/line {@link NodeGeometry} changed. */
|
|
422
456
|
StalePropertyFlag["Geometry"] = "geometry";
|
|
457
|
+
/** The group's child collection changed. */
|
|
423
458
|
StalePropertyFlag["Children"] = "children";
|
|
459
|
+
/** The mesh's {@link Material}/{@link Mesh.backMaterial} changed. */
|
|
424
460
|
StalePropertyFlag["Material"] = "material";
|
|
461
|
+
/** A {@link Light}-specific property (color, intensity, target, ...) changed. */
|
|
425
462
|
StalePropertyFlag["Light"] = "light";
|
|
463
|
+
/** A {@link Camera}-specific property (near, far, fov, frustum, ...) changed. */
|
|
426
464
|
StalePropertyFlag["Camera"] = "camera";
|
|
465
|
+
/** The object's {@link Renderable.hide} visibility changed. */
|
|
427
466
|
StalePropertyFlag["Visibility"] = "visibility";
|
|
428
467
|
})(StalePropertyFlag || (StalePropertyFlag = {}));
|
|
468
|
+
/** Type guard checking whether `object` implements the {@link Interaction} contract. */
|
|
429
469
|
function isInteraction(object) {
|
|
430
470
|
return typeof object === 'object' && 'time' in object && typeof object['time'] === 'number';
|
|
431
471
|
}
|
|
@@ -439,12 +479,20 @@
|
|
|
439
479
|
GROUP_SELECTOR: pacemCore.P + '-' + TAG_MIDDLE_NAME + '-group',
|
|
440
480
|
DEFAULT_COORDS: { x: 0, y: 0, z: 0 }
|
|
441
481
|
};
|
|
482
|
+
/**
|
|
483
|
+
* Abstract base of every scene-graph custom element usable inside a {@link Pacem3DElement} stage (groups, meshes,
|
|
484
|
+
* native objects, lights, cameras). Implements {@link Renderable}, wires the element into the ancestor stage/parent
|
|
485
|
+
* chain, and tracks which aspects of the object are stale (via {@link StalePropertyFlag}) so the active
|
|
486
|
+
* {@link Pacem3DAdapterElement} can update only what changed on the next render.
|
|
487
|
+
*/
|
|
442
488
|
class RenderableElement extends pacemCore.Components.PacemCrossItemsContainerElement {
|
|
443
489
|
constructor() {
|
|
444
490
|
super(...arguments);
|
|
491
|
+
/** Gets or sets the element's position, in 3d world (or parent-local) space. */
|
|
445
492
|
this.position = Constants.DEFAULT_COORDS;
|
|
446
493
|
this.#staleFlags = [];
|
|
447
494
|
}
|
|
495
|
+
/** When implemented in a derived class (e.g. {@link Pacem3DGroupElement}), determines whether `_` may be nested under this element. Denies any child by default. */
|
|
448
496
|
validate(_) {
|
|
449
497
|
// by default no children allowed (Group will except)
|
|
450
498
|
return false;
|
|
@@ -453,9 +501,11 @@
|
|
|
453
501
|
// override
|
|
454
502
|
return this.parent || this.stage;
|
|
455
503
|
}
|
|
504
|
+
/** @readonly Gets the ancestor {@link Pacem3DElement} stage this element belongs to. */
|
|
456
505
|
get stage() {
|
|
457
506
|
return this['_scene'] = this['_scene'] || pacemCore.CustomElementUtils.findAncestorOfType(this, Pacem3DElement);
|
|
458
507
|
}
|
|
508
|
+
/** @readonly Gets the closest ancestor {@link RenderableElement} (e.g. the containing group), if any. */
|
|
459
509
|
get parent() {
|
|
460
510
|
return this['_drawableParent'] = this['_drawableParent'] || pacemCore.CustomElementUtils.findAncestor(this, i => i instanceof RenderableElement);
|
|
461
511
|
}
|
|
@@ -479,6 +529,7 @@
|
|
|
479
529
|
}
|
|
480
530
|
}
|
|
481
531
|
#staleFlags;
|
|
532
|
+
/** @readonly Gets the list of {@link StalePropertyFlag}s accumulated since the element was last rendered/updated by the adapter. */
|
|
482
533
|
get flags() {
|
|
483
534
|
return this.#staleFlags;
|
|
484
535
|
}
|
|
@@ -502,6 +553,11 @@
|
|
|
502
553
|
__decorate$k([
|
|
503
554
|
pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.Boolean })
|
|
504
555
|
], RenderableElement.prototype, "inert", void 0);
|
|
556
|
+
/**
|
|
557
|
+
* Abstract base of every {@link RenderableElement} that also carries an affine 3d transform (rotate/scale/offset,
|
|
558
|
+
* combined into {@link transformMatrix}). Extended by {@link Pacem3DGroupElement}, {@link Pacem3DMeshElement} and
|
|
559
|
+
* {@link Pacem3DObjectElement}.
|
|
560
|
+
*/
|
|
505
561
|
class Ui3DElement extends RenderableElement {
|
|
506
562
|
// #endregion
|
|
507
563
|
propertyChangedCallback(name, old, val, first) {
|
|
@@ -573,12 +629,14 @@
|
|
|
573
629
|
__decorate$k([
|
|
574
630
|
pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.Number })
|
|
575
631
|
], Ui3DElement.prototype, "translateZ", void 0);
|
|
632
|
+
/** `<pacem-3d-group>`: a {@link Ui3DElement} container that groups child {@link RenderableElement}s (declarative or from {@link datasource}) so its own transform applies to all of them. */
|
|
576
633
|
let Pacem3DGroupElement = class Pacem3DGroupElement extends Ui3DElement {
|
|
577
634
|
validate(child) {
|
|
578
635
|
// overrides default denial
|
|
579
636
|
return child instanceof RenderableElement;
|
|
580
637
|
}
|
|
581
638
|
#children = [];
|
|
639
|
+
/** @readonly Gets the renderable children currently belonging to the group. */
|
|
582
640
|
get childRenderables() {
|
|
583
641
|
return this.#children;
|
|
584
642
|
}
|
|
@@ -599,6 +657,7 @@
|
|
|
599
657
|
Pacem3DGroupElement = __decorate$k([
|
|
600
658
|
pacemCore.CustomElement({ tagName: Constants.GROUP_SELECTOR })
|
|
601
659
|
], Pacem3DGroupElement);
|
|
660
|
+
/** `<pacem-3d-mesh>`: a {@link Ui3DElement} that renders a {@link NodeGeometry} (mesh or line) with a front/back {@link Material}. */
|
|
602
661
|
let Pacem3DMeshElement = class Pacem3DMeshElement extends Ui3DElement {
|
|
603
662
|
propertyChangedCallback(name, old, val, first) {
|
|
604
663
|
super.propertyChangedCallback(name, old, val, first);
|
|
@@ -625,6 +684,7 @@
|
|
|
625
684
|
Pacem3DMeshElement = __decorate$k([
|
|
626
685
|
pacemCore.CustomElement({ tagName: Constants.MESH_SELECTOR })
|
|
627
686
|
], Pacem3DMeshElement);
|
|
687
|
+
/** `<pacem-3d-object>`: a {@link Ui3DElement} that loads/embeds a pre-built 3d asset (`obj`, `fbx`, or a native scene-graph object) instead of an explicit {@link Pacem3DMeshElement} geometry. */
|
|
628
688
|
let Pacem3DObjectElement = class Pacem3DObjectElement extends Ui3DElement {
|
|
629
689
|
propertyChangedCallback(name, old, val, first) {
|
|
630
690
|
super.propertyChangedCallback(name, old, val, first);
|
|
@@ -642,12 +702,17 @@
|
|
|
642
702
|
Pacem3DObjectElement = __decorate$k([
|
|
643
703
|
pacemCore.CustomElement({ tagName: Constants.OBJECT_SELECTOR })
|
|
644
704
|
], Pacem3DObjectElement);
|
|
705
|
+
/** `<pacem-3d-light>`: a {@link RenderableElement} light source (point/omni, spot or directional) illuminating the scene. */
|
|
645
706
|
let Pacem3DLightElement = class Pacem3DLightElement extends RenderableElement {
|
|
646
707
|
constructor() {
|
|
647
708
|
super(...arguments);
|
|
709
|
+
/** Gets or sets the light intensity/brightness. */
|
|
648
710
|
this.intensity = .85;
|
|
711
|
+
/** Gets or sets the point the light is aimed at (spotlight-specific). */
|
|
649
712
|
this.target = Constants.DEFAULT_COORDS;
|
|
713
|
+
/** Gets or sets the light color. */
|
|
650
714
|
this.color = '#fff';
|
|
715
|
+
/** Gets or sets the kind of light source. */
|
|
651
716
|
this.type = 'omni';
|
|
652
717
|
}
|
|
653
718
|
propertyChangedCallback(name, old, val, first) {
|
|
@@ -677,12 +742,21 @@
|
|
|
677
742
|
Pacem3DLightElement = __decorate$k([
|
|
678
743
|
pacemCore.CustomElement({ tagName: Constants.LIGHT_SELECTOR })
|
|
679
744
|
], Pacem3DLightElement);
|
|
745
|
+
/**
|
|
746
|
+
* Abstract base of the camera custom elements ({@link Pacem3DPerspectiveCameraElement}, {@link Pacem3DOrthographicCameraElement})
|
|
747
|
+
* that can be added to a {@link Pacem3DElement} stage. Implements {@link Camera}, tracking the eye-to-target
|
|
748
|
+
* {@link boundingSphere} used e.g. by {@link Pacem3DAdapterElement.zoomFit}.
|
|
749
|
+
*/
|
|
680
750
|
class Pacem3DCameraElement extends RenderableElement {
|
|
681
751
|
constructor() {
|
|
682
752
|
super(...arguments);
|
|
753
|
+
/** Gets or sets the near clipping plane distance. */
|
|
683
754
|
this.near = 0.1;
|
|
755
|
+
/** Gets or sets the far clipping plane distance. */
|
|
684
756
|
this.far = 1000.0;
|
|
757
|
+
/** Gets or sets the up vector, in world coordinates. */
|
|
685
758
|
this.up = pacemNumerical.Geometry.LinearAlgebra.Vector3D.j();
|
|
759
|
+
/** Gets or sets the target the camera looks at, in world coordinates. */
|
|
686
760
|
this.lookAt = Constants.DEFAULT_COORDS;
|
|
687
761
|
}
|
|
688
762
|
#sphere;
|
|
@@ -694,6 +768,7 @@
|
|
|
694
768
|
const currentValue = this.#sphere = { center, radius };
|
|
695
769
|
this.dispatchEvent(new pacemCore.PropertyChangeEvent({ currentValue, propertyName: 'boundingSphere', oldValue }));
|
|
696
770
|
}
|
|
771
|
+
/** @readonly Gets the sphere centered on {@link lookAt} with radius equal to the eye-to-target distance. */
|
|
697
772
|
get boundingSphere() {
|
|
698
773
|
return this.#sphere;
|
|
699
774
|
}
|
|
@@ -723,15 +798,20 @@
|
|
|
723
798
|
__decorate$k([
|
|
724
799
|
pacemCore.Watch({ emit: false, converter: Point3DConverter })
|
|
725
800
|
], Pacem3DCameraElement.prototype, "lookAt", void 0);
|
|
801
|
+
/** `<pacem-3d-perspective-camera>`: a {@link Pacem3DCameraElement} that projects the scene through a perspective frustum (vanishing point), defined by {@link fov} and {@link aspect}. */
|
|
726
802
|
let Pacem3DPerspectiveCameraElement = class Pacem3DPerspectiveCameraElement extends Pacem3DCameraElement {
|
|
727
803
|
constructor() {
|
|
728
804
|
super(...arguments);
|
|
805
|
+
/** Gets or sets the vertical field of view, in degrees. */
|
|
729
806
|
this.fov = 45;
|
|
807
|
+
/** Gets or sets the viewport width/height ratio. */
|
|
730
808
|
this.aspect = 1;
|
|
731
809
|
}
|
|
810
|
+
/** @readonly Gets the camera discriminator: always `"perspective"`. */
|
|
732
811
|
get type() {
|
|
733
812
|
return "perspective";
|
|
734
813
|
}
|
|
814
|
+
/** @readonly Gets the viewport width/height ratio (alias of {@link aspect}). */
|
|
735
815
|
get aspectRatio() {
|
|
736
816
|
return this.aspect;
|
|
737
817
|
}
|
|
@@ -754,14 +834,20 @@
|
|
|
754
834
|
Pacem3DPerspectiveCameraElement = __decorate$k([
|
|
755
835
|
pacemCore.CustomElement({ tagName: Constants.PERSPECTIVE_CAMERA_SELECTOR })
|
|
756
836
|
], Pacem3DPerspectiveCameraElement);
|
|
837
|
+
/** `<pacem-3d-orthographic-camera>`: a {@link Pacem3DCameraElement} that projects the scene through a fixed, non-diminishing (parallel) frustum, defined by the {@link top}/{@link left}/{@link bottom}/{@link right} coordinates. */
|
|
757
838
|
let Pacem3DOrthographicCameraElement = class Pacem3DOrthographicCameraElement extends Pacem3DCameraElement {
|
|
758
839
|
constructor() {
|
|
759
840
|
super(...arguments);
|
|
841
|
+
/** Gets or sets the top frustum coordinate (e.g. 1). */
|
|
760
842
|
this.top = 1;
|
|
843
|
+
/** Gets or sets the left frustum coordinate (e.g. -1). */
|
|
761
844
|
this.left = -1;
|
|
845
|
+
/** Gets or sets the bottom frustum coordinate (e.g. -1). */
|
|
762
846
|
this.bottom = -1;
|
|
847
|
+
/** Gets or sets the right frustum coordinate (e.g. 1). */
|
|
763
848
|
this.right = 1;
|
|
764
849
|
}
|
|
850
|
+
/** @readonly Gets the camera discriminator: always `"orthographic"`. */
|
|
765
851
|
get type() {
|
|
766
852
|
return "orthographic";
|
|
767
853
|
}
|
|
@@ -792,12 +878,19 @@
|
|
|
792
878
|
Pacem3DOrthographicCameraElement = __decorate$k([
|
|
793
879
|
pacemCore.CustomElement({ tagName: Constants.ORTHO_CAMERA_SELECTOR })
|
|
794
880
|
], Pacem3DOrthographicCameraElement);
|
|
881
|
+
/**
|
|
882
|
+
* Pluggable rendering-backend contract assignable to a {@link Pacem3DElement}'s `adapter` property. Concrete adapters
|
|
883
|
+
* ({@link Pacem3DThreeAdapterElement} for Three.js/WebGL, {@link Pacem3DWebgpuAdapterElement} for WebGPU) are
|
|
884
|
+
* responsible for initializing/disposing the underlying native scene and DOM surface, sizing it, translating the
|
|
885
|
+
* {@link RenderableElement} scene graph into native objects, hit-testing (raycasting) and producing snapshot images.
|
|
886
|
+
*/
|
|
795
887
|
class Pacem3DAdapterElement extends pacemCore.PacemEventTarget {
|
|
796
888
|
}
|
|
797
889
|
|
|
798
890
|
//namespace Pacem.Components.Drawing3D {
|
|
799
891
|
/** @deprecated*/
|
|
800
892
|
class Pacem3DDetector {
|
|
893
|
+
/** Probes the browser for WebGL support by attempting to create a rendering context, populating {@link info} and {@link supported}. */
|
|
801
894
|
constructor() {
|
|
802
895
|
this._detected = {
|
|
803
896
|
supported: false, info: {}
|
|
@@ -861,9 +954,11 @@
|
|
|
861
954
|
addLine('misc', 'Supported Extensions', ctx.getSupportedExtensions() || []);
|
|
862
955
|
}
|
|
863
956
|
}
|
|
957
|
+
/** @readonly Gets the detected WebGL capabilities/limits, grouped by section (`main`, `bits`, `shader`, `tex`, `misc`). */
|
|
864
958
|
get info() {
|
|
865
959
|
return this._detected.info;
|
|
866
960
|
}
|
|
961
|
+
/** @readonly Gets whether a WebGL rendering context could be created on this browser/device. */
|
|
867
962
|
get supported() {
|
|
868
963
|
return this._detected.supported;
|
|
869
964
|
}
|
|
@@ -876,6 +971,7 @@
|
|
|
876
971
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
877
972
|
};
|
|
878
973
|
//namespace Pacem.Drawing3D {
|
|
974
|
+
/** Identifies the shading model (and, correspondingly, the concrete `Material` shape) applied to a mesh's faces. */
|
|
879
975
|
var KnownShader;
|
|
880
976
|
(function (KnownShader) {
|
|
881
977
|
KnownShader["Basic"] = "basic";
|
|
@@ -885,34 +981,49 @@
|
|
|
885
981
|
KnownShader["Line"] = "line";
|
|
886
982
|
KnownShader["Custom"] = "custom";
|
|
887
983
|
})(KnownShader || (KnownShader = {}));
|
|
984
|
+
/** Type guard checking whether `obj` implements the {@link Material} contract. */
|
|
888
985
|
function isMaterial(obj) {
|
|
889
986
|
return /*'color' in obj &&*/ 'shader' in obj;
|
|
890
987
|
}
|
|
988
|
+
/** Type guard checking whether `obj` implements the {@link BasicMaterial} contract. */
|
|
891
989
|
function isBasicMaterial(obj) {
|
|
892
990
|
return isMaterial(obj) && obj.shader === KnownShader.Basic;
|
|
893
991
|
}
|
|
992
|
+
/** Type guard checking whether `obj` implements the {@link LineMaterial} contract. */
|
|
894
993
|
function isLineMaterial(obj) {
|
|
895
994
|
return isMaterial(obj) && obj.shader === KnownShader.Line;
|
|
896
995
|
}
|
|
996
|
+
/** Type guard checking whether `obj` implements the {@link LambertMaterial} contract. */
|
|
897
997
|
function isLambertMaterial(obj) {
|
|
898
998
|
return isMaterial(obj) && obj.shader === KnownShader.Lambert;
|
|
899
999
|
}
|
|
1000
|
+
/** Type guard checking whether `obj` implements the {@link PhongMaterial} contract. */
|
|
900
1001
|
function isPhongMaterial(obj) {
|
|
901
1002
|
return isMaterial(obj) && obj.shader === KnownShader.Phong;
|
|
902
1003
|
}
|
|
1004
|
+
/** Type guard checking whether `obj` implements the {@link StandardMaterial} contract. */
|
|
903
1005
|
function isStandardMaterial(obj) {
|
|
904
1006
|
return isMaterial(obj) && obj.shader === KnownShader.Standard;
|
|
905
1007
|
}
|
|
1008
|
+
/** Type guard checking whether `obj` implements the {@link ShaderMaterial} contract. */
|
|
906
1009
|
function isShaderMaterial(obj) {
|
|
907
1010
|
return isMaterial(obj) && obj.shader === KnownShader.Custom;
|
|
908
1011
|
}
|
|
909
1012
|
//namespace Pacem.Components.Drawing3D {
|
|
1013
|
+
/**
|
|
1014
|
+
* Abstract base of the declarative material custom elements — {@link BasicMaterialElement}, {@link LambertMaterialElement},
|
|
1015
|
+
* {@link LineMaterialElement}, {@link PhongMaterialElement} and {@link StandardMaterialElement} — that assemble a
|
|
1016
|
+
* {@link Material} (with its `shader`-specific extra properties) out of shared and shader-specific watched attributes,
|
|
1017
|
+
* ready to be assigned to a `Pacem3DMeshElement`'s `material`/`backMaterial` property.
|
|
1018
|
+
*/
|
|
910
1019
|
class MaterialElement extends pacemCore.PacemEventTarget {
|
|
1020
|
+
/** @param shader The {@link KnownShader} this element's {@link createMaterial} produces. */
|
|
911
1021
|
constructor(shader) {
|
|
912
1022
|
super();
|
|
913
1023
|
this.#shader = shader;
|
|
914
1024
|
}
|
|
915
1025
|
#shader;
|
|
1026
|
+
/** Gets the shading model this element produces materials for. */
|
|
916
1027
|
get shader() {
|
|
917
1028
|
return this.#shader;
|
|
918
1029
|
}
|
|
@@ -947,11 +1058,13 @@
|
|
|
947
1058
|
super.viewActivatedCallback();
|
|
948
1059
|
this.updateMaterial();
|
|
949
1060
|
}
|
|
1061
|
+
/** Recomputes {@link material} via {@link createMaterial}, flagging it as {@link StalePropertyFlag.Material}. */
|
|
950
1062
|
updateMaterial() {
|
|
951
1063
|
this.createMaterial().then(m => {
|
|
952
1064
|
this.material = pacemCore.Utils.extend(m, { flags: [StalePropertyFlag.Material] });
|
|
953
1065
|
});
|
|
954
1066
|
}
|
|
1067
|
+
/** Builds the base {@link Material} out of the shared watched attributes (`opacity`, `wireframe`, `color`, `hide`, `map`); overridden by subclasses to add their shader-specific properties. */
|
|
955
1068
|
async createMaterial() {
|
|
956
1069
|
return {
|
|
957
1070
|
opacity: this.opacity ?? 1.0,
|
|
@@ -991,6 +1104,7 @@
|
|
|
991
1104
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
992
1105
|
};
|
|
993
1106
|
//namespace Pacem.Components.Drawing3D {
|
|
1107
|
+
/** `<pacem-3d-material-basic>`: produces a {@link BasicMaterial} (unlit shading model): rendered at flat color, unaffected by scene lighting. */
|
|
994
1108
|
let BasicMaterialElement = class BasicMaterialElement extends MaterialElement {
|
|
995
1109
|
constructor() {
|
|
996
1110
|
super(KnownShader.Basic);
|
|
@@ -1007,10 +1121,12 @@
|
|
|
1007
1121
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1008
1122
|
};
|
|
1009
1123
|
//namespace Pacem.Components.Drawing3D {
|
|
1124
|
+
/** `<pacem-3d-material-lambert>`: produces a {@link LambertMaterial} (Lambertian shading model): matte, non-specular reflection of scene lighting, with no glossy highlights. */
|
|
1010
1125
|
let LambertMaterialElement = class LambertMaterialElement extends MaterialElement {
|
|
1011
1126
|
constructor() {
|
|
1012
1127
|
super(KnownShader.Lambert);
|
|
1013
1128
|
}
|
|
1129
|
+
/** Builds the {@link LambertMaterial}, adding `emissiveColor`, `reflectivity` and `refractionRatio` to the base {@link Material}. */
|
|
1014
1130
|
async createMaterial() {
|
|
1015
1131
|
return pacemCore.Utils.extend({
|
|
1016
1132
|
emissiveColor: this.emissiveColor || '#000',
|
|
@@ -1051,6 +1167,7 @@
|
|
|
1051
1167
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1052
1168
|
};
|
|
1053
1169
|
//namespace Pacem.Components.Drawing3D {
|
|
1170
|
+
/** `<pacem-3d-material-line>`: produces a {@link LineMaterial} for rendering {@link PacemLineElement} polylines (stroke width, joins, caps, dash pattern). */
|
|
1054
1171
|
let LineMaterialElement = class LineMaterialElement extends MaterialElement {
|
|
1055
1172
|
constructor() {
|
|
1056
1173
|
super(KnownShader.Line);
|
|
@@ -1068,6 +1185,7 @@
|
|
|
1068
1185
|
}
|
|
1069
1186
|
}
|
|
1070
1187
|
}
|
|
1188
|
+
/** Builds the {@link LineMaterial}, adding `lineWidth`, `lineJoin`, `lineCap` and `dashArray` to the base {@link Material}. */
|
|
1071
1189
|
async createMaterial() {
|
|
1072
1190
|
return pacemCore.Utils.extend({
|
|
1073
1191
|
lineWidth: this.lineWidth ?? 1,
|
|
@@ -1105,10 +1223,12 @@
|
|
|
1105
1223
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1106
1224
|
};
|
|
1107
1225
|
//namespace Pacem.Components.Drawing3D {
|
|
1226
|
+
/** `<pacem-3d-material-phong>`: produces a {@link PhongMaterial} (Phong shading model): diffuse reflection plus a specular highlight of adjustable shininess. */
|
|
1108
1227
|
let PhongMaterialElement = class PhongMaterialElement extends MaterialElement {
|
|
1109
1228
|
constructor() {
|
|
1110
1229
|
super(KnownShader.Phong);
|
|
1111
1230
|
}
|
|
1231
|
+
/** Builds the {@link PhongMaterial}, adding the diffuse (`emissiveColor`, `reflectivity`, `refractionRatio`) and specular (`specularColor`, `shininess`, `flatShading`) properties to the base {@link Material}. */
|
|
1112
1232
|
async createMaterial() {
|
|
1113
1233
|
return pacemCore.Utils.extend({
|
|
1114
1234
|
emissiveColor: this.emissiveColor || '#000',
|
|
@@ -1164,10 +1284,12 @@
|
|
|
1164
1284
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1165
1285
|
};
|
|
1166
1286
|
//namespace Pacem.Components.Drawing3D {
|
|
1287
|
+
/** `<pacem-3d-material-standard>`: produces a {@link StandardMaterial} using a physically-based (metalness/roughness) shading model. */
|
|
1167
1288
|
let StandardMaterialElement = class StandardMaterialElement extends MaterialElement {
|
|
1168
1289
|
constructor() {
|
|
1169
1290
|
super(KnownShader.Standard);
|
|
1170
1291
|
}
|
|
1292
|
+
/** Builds the {@link StandardMaterial}, adding `emissiveColor`, `refractionRatio`, `metalness`, `roughness` and `flatShading` to the base {@link Material}. */
|
|
1171
1293
|
async createMaterial() {
|
|
1172
1294
|
return pacemCore.Utils.extend({
|
|
1173
1295
|
emissiveColor: this.emissiveColor || '#000',
|
|
@@ -1218,6 +1340,12 @@
|
|
|
1218
1340
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1219
1341
|
};
|
|
1220
1342
|
//namespace Pacem.Components.Drawing3D {
|
|
1343
|
+
/**
|
|
1344
|
+
* Abstract base of the declarative geometric-primitive custom elements — {@link PacemBoxElement}, {@link PacemConeElement},
|
|
1345
|
+
* {@link PacemCylinderElement}, {@link PacemLineElement}, {@link PacemPlaneElement}, {@link PacemSphereElement},
|
|
1346
|
+
* {@link PacemTorusElement} and the {@link PolyhedronElement} family — that compute a {@link NodeGeometry} out of their
|
|
1347
|
+
* own shape parameters, ready to be assigned to a `Pacem3DMeshElement`'s `geometry` property.
|
|
1348
|
+
*/
|
|
1221
1349
|
class Pacem3DPrimitiveElement extends pacemCore.PacemEventTarget {
|
|
1222
1350
|
viewActivatedCallback() {
|
|
1223
1351
|
super.viewActivatedCallback();
|
|
@@ -1231,6 +1359,13 @@
|
|
|
1231
1359
|
], Pacem3DPrimitiveElement.prototype, "geometry", void 0);
|
|
1232
1360
|
|
|
1233
1361
|
//namespace Pacem.Drawing3D {
|
|
1362
|
+
/**
|
|
1363
|
+
* Property decorator factory that turns the decorated field into an accessor backed by a private field, invoking
|
|
1364
|
+
* `callback` with the property name and old/new values whenever it is set to a different value. Used by
|
|
1365
|
+
* {@link NodeGeometry}/{@link LineGeometry}/{@link MeshGeometry} to flag themselves as dirty ({@link StalePropertyFlag.Geometry})
|
|
1366
|
+
* whenever their vertex data changes.
|
|
1367
|
+
* @param callback Invoked (with `this` bound to the decorated instance) on every effective change of the property.
|
|
1368
|
+
*/
|
|
1234
1369
|
function NotifyChange(callback) {
|
|
1235
1370
|
return (target, prop, descriptor) => {
|
|
1236
1371
|
const backingField = `_${prop}_${pacemCore.Utils.uniqueCode()}_backingField`;
|
|
@@ -1265,10 +1400,15 @@
|
|
|
1265
1400
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1266
1401
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1267
1402
|
};
|
|
1403
|
+
/**
|
|
1404
|
+
* Abstract base for the concrete geometry classes ({@link LineGeometry}, {@link MeshGeometry}) that back a
|
|
1405
|
+
* {@link Pacem3DMeshElement}'s `geometry` property, providing shared bounding-volume computation helpers.
|
|
1406
|
+
*/
|
|
1268
1407
|
class NodeGeometry {
|
|
1269
1408
|
constructor(positions = []) {
|
|
1270
1409
|
this.positions = positions;
|
|
1271
1410
|
}
|
|
1411
|
+
/** Computes the centroid (average) of the given positions. */
|
|
1272
1412
|
static barycenter(positions) {
|
|
1273
1413
|
var bary = { x: 0, y: 0, z: 0 };
|
|
1274
1414
|
if (!pacemCore.Utils.isNullOrEmpty(positions)) {
|
|
@@ -1286,6 +1426,7 @@
|
|
|
1286
1426
|
}
|
|
1287
1427
|
return bary;
|
|
1288
1428
|
}
|
|
1429
|
+
/** Computes the axis-aligned {@link Box3D} enclosing the given positions. */
|
|
1289
1430
|
static boundingBox(positions) {
|
|
1290
1431
|
const output = {
|
|
1291
1432
|
minX: +Infinity, minY: +Infinity, minZ: +Infinity,
|
|
@@ -1304,6 +1445,7 @@
|
|
|
1304
1445
|
}
|
|
1305
1446
|
return output;
|
|
1306
1447
|
}
|
|
1448
|
+
/** Marks the geometry as stale, flagging it with {@link StalePropertyFlag.Geometry} for the next render. */
|
|
1307
1449
|
setAsDirty() {
|
|
1308
1450
|
setSelfAsDirty.call(this);
|
|
1309
1451
|
}
|
|
@@ -1312,27 +1454,32 @@
|
|
|
1312
1454
|
const me = this;
|
|
1313
1455
|
me.flags = [/* no further specifications, other than 'geometry' */ StalePropertyFlag.Geometry];
|
|
1314
1456
|
}
|
|
1457
|
+
/** A {@link NodeGeometry} rendered as a polyline through its {@link positions} (no faces/triangles). */
|
|
1315
1458
|
class LineGeometry extends NodeGeometry {
|
|
1316
1459
|
}
|
|
1317
1460
|
__decorate$c([
|
|
1318
1461
|
NotifyChange(setSelfAsDirty)
|
|
1319
1462
|
], LineGeometry.prototype, "positions", void 0);
|
|
1463
|
+
/** A {@link MeshGeometry} implementation with lazily-computed {@link barycenter}/{@link boundingBox} and settable {@link boundingSphere}, used as the `geometry` of a {@link Pacem3DMeshElement}. */
|
|
1320
1464
|
class MeshGeometry extends NodeGeometry {
|
|
1321
1465
|
#boundingBox;
|
|
1322
1466
|
#boundingSphere;
|
|
1323
1467
|
#barycenter;
|
|
1468
|
+
/** Gets or sets the centroid of {@link positions}; computed on first access if not explicitly set. */
|
|
1324
1469
|
get barycenter() {
|
|
1325
1470
|
return this.#barycenter ??= NodeGeometry.barycenter(this.positions);
|
|
1326
1471
|
}
|
|
1327
1472
|
set barycenter(point) {
|
|
1328
1473
|
this.#barycenter = point;
|
|
1329
1474
|
}
|
|
1475
|
+
/** Gets or sets the axis-aligned bounding box; computed from {@link positions} on first access if not explicitly set. */
|
|
1330
1476
|
get boundingBox() {
|
|
1331
1477
|
return this.#boundingBox ??= NodeGeometry.boundingBox(this.positions);
|
|
1332
1478
|
}
|
|
1333
1479
|
set boundingBox(bbox) {
|
|
1334
1480
|
this.#boundingBox = bbox;
|
|
1335
1481
|
}
|
|
1482
|
+
/** Gets or sets the bounding sphere. */
|
|
1336
1483
|
get boundingSphere() {
|
|
1337
1484
|
return this.#boundingSphere;
|
|
1338
1485
|
}
|
|
@@ -1367,7 +1514,9 @@
|
|
|
1367
1514
|
};
|
|
1368
1515
|
var PacemBoxElement_1;
|
|
1369
1516
|
//namespace Pacem.Components.Drawing3D {
|
|
1517
|
+
/** `<pacem-3d-primitive-box>`: computes the {@link MeshGeometry} of a rectangular cuboid (box). */
|
|
1370
1518
|
let PacemBoxElement = PacemBoxElement_1 = class PacemBoxElement extends Pacem3DPrimitiveElement {
|
|
1519
|
+
/** Builds the {@link MeshGeometry} of a box with the given size and per-axis segment subdivisions (all default to `1`). */
|
|
1371
1520
|
static createMeshGeometry(width, height, depth, widthSegments, heightSegments, depthSegments) {
|
|
1372
1521
|
const w = width || 1, h = height || 1, d = depth || 1, sw = widthSegments || 1, sh = heightSegments || 1, sd = depthSegments || 1;
|
|
1373
1522
|
const positions = [];
|
|
@@ -1541,6 +1690,7 @@
|
|
|
1541
1690
|
//
|
|
1542
1691
|
return geom;
|
|
1543
1692
|
}
|
|
1693
|
+
/** Computes the box geometry from the default (unset) shape parameters. */
|
|
1544
1694
|
createDefaultGeometry() {
|
|
1545
1695
|
return PacemBoxElement_1.createMeshGeometry();
|
|
1546
1696
|
}
|
|
@@ -1588,7 +1738,9 @@
|
|
|
1588
1738
|
};
|
|
1589
1739
|
var PacemConeElement_1;
|
|
1590
1740
|
//namespace Pacem.Components.Drawing3D {
|
|
1741
|
+
/** `<pacem-3d-primitive-cone>`: computes the {@link MeshGeometry} of a cone (a circular base tapering to an apex point). */
|
|
1591
1742
|
let PacemConeElement = PacemConeElement_1 = class PacemConeElement extends Pacem3DPrimitiveElement {
|
|
1743
|
+
/** Builds the {@link MeshGeometry} of a cone with the given base radius, height, side count, lateral-surface segments and base-cap segments. */
|
|
1592
1744
|
static createMeshGeometry(radius = 1, height = 1, sides = 18, heightSegments = 5, capSegments = 1) {
|
|
1593
1745
|
const r = radius;
|
|
1594
1746
|
const nodes = [], uv = [], indices = [];
|
|
@@ -1699,6 +1851,7 @@
|
|
|
1699
1851
|
// TODO: barycenter, boundingBox, boundingSphere
|
|
1700
1852
|
return geom;
|
|
1701
1853
|
}
|
|
1854
|
+
/** Computes the cone geometry from the default (unset) shape parameters. */
|
|
1702
1855
|
createDefaultGeometry() {
|
|
1703
1856
|
return PacemConeElement_1.createMeshGeometry();
|
|
1704
1857
|
}
|
|
@@ -1742,7 +1895,9 @@
|
|
|
1742
1895
|
};
|
|
1743
1896
|
var PacemCylinderElement_1;
|
|
1744
1897
|
//namespace Pacem.Components.Drawing3D {
|
|
1898
|
+
/** `<pacem-3d-primitive-cylinder>`: computes the {@link MeshGeometry} of a cylinder (two parallel circular caps joined by a straight lateral surface). */
|
|
1745
1899
|
let PacemCylinderElement = PacemCylinderElement_1 = class PacemCylinderElement extends Pacem3DPrimitiveElement {
|
|
1900
|
+
/** Builds the {@link MeshGeometry} of a cylinder with the given radius, height, side count, lateral-surface segments and cap segments. */
|
|
1746
1901
|
static createMeshGeometry(radius = 1, height = 1, sides = 18, heightSegments = 5, capSegments = 1) {
|
|
1747
1902
|
const r = radius;
|
|
1748
1903
|
const nodes = [], uv = [], indices = [];
|
|
@@ -1899,6 +2054,7 @@
|
|
|
1899
2054
|
// TODO: barycenter, boundingBox, boundingSphere
|
|
1900
2055
|
return geom;
|
|
1901
2056
|
}
|
|
2057
|
+
/** Computes the cylinder geometry from the default (unset) shape parameters. */
|
|
1902
2058
|
createDefaultGeometry() {
|
|
1903
2059
|
return PacemCylinderElement_1.createMeshGeometry();
|
|
1904
2060
|
}
|
|
@@ -1943,10 +2099,13 @@
|
|
|
1943
2099
|
var PacemLineElement_1;
|
|
1944
2100
|
//namespace Pacem.Components.Drawing3D {
|
|
1945
2101
|
const DEFAULT_LINE = [{ x: 0, y: 0, z: 0 }, { x: 0, y: 1, z: 0 }];
|
|
2102
|
+
/** `<pacem-3d-primitive-line>`: computes the {@link LineGeometry} of a polyline connecting a sequence of points. */
|
|
1946
2103
|
let PacemLineElement = PacemLineElement_1 = class PacemLineElement extends Pacem3DPrimitiveElement {
|
|
2104
|
+
/** Builds the {@link LineGeometry} out of the given vertices (a single segment from `(0,0,0)` to `(0,1,0)` when omitted). */
|
|
1947
2105
|
static createLineGeometry(positions) {
|
|
1948
2106
|
return new LineGeometry(positions || DEFAULT_LINE);
|
|
1949
2107
|
}
|
|
2108
|
+
/** Computes the line geometry from the default (unset) vertex positions. */
|
|
1950
2109
|
createDefaultGeometry() {
|
|
1951
2110
|
return PacemLineElement_1.createLineGeometry();
|
|
1952
2111
|
}
|
|
@@ -1974,7 +2133,9 @@
|
|
|
1974
2133
|
};
|
|
1975
2134
|
var PacemPlaneElement_1;
|
|
1976
2135
|
//namespace Pacem.Components.Drawing3D {
|
|
2136
|
+
/** `<pacem-3d-primitive-plane>`: computes the {@link MeshGeometry} of a flat rectangular surface lying on the xz plane. */
|
|
1977
2137
|
let PacemPlaneElement = PacemPlaneElement_1 = class PacemPlaneElement extends Pacem3DPrimitiveElement {
|
|
2138
|
+
/** Builds the {@link MeshGeometry} of a flat rectangle with the given width, length and per-axis segment subdivisions (defaulting to `1`x`1`, 4 segments each way). */
|
|
1978
2139
|
static createMeshGeometry(width, length, widthSegments, lengthSegments) {
|
|
1979
2140
|
width ||= 1.0;
|
|
1980
2141
|
length ||= 1.0;
|
|
@@ -2019,6 +2180,7 @@
|
|
|
2019
2180
|
// TODO: barycenter, boundingBox, boundingSphere
|
|
2020
2181
|
return geom;
|
|
2021
2182
|
}
|
|
2183
|
+
/** Computes the plane geometry from the default (unset) shape parameters. */
|
|
2022
2184
|
createDefaultGeometry() {
|
|
2023
2185
|
return PacemPlaneElement_1.createMeshGeometry();
|
|
2024
2186
|
}
|
|
@@ -2074,6 +2236,12 @@
|
|
|
2074
2236
|
}
|
|
2075
2237
|
};
|
|
2076
2238
|
const Point3D = pacemNumerical.Geometry.LinearAlgebra.Vector3D;
|
|
2239
|
+
/**
|
|
2240
|
+
* Abstract base of the regular-polyhedron (Platonic solid) primitive custom elements — {@link PacemTetrahedronElement},
|
|
2241
|
+
* {@link PacemOctahedronElement}, {@link PacemHexahedronElement}, {@link PacemIcosahedronElement} and
|
|
2242
|
+
* {@link PacemDodecahedronElement} — each computing the {@link MeshGeometry} of a solid inscribed in a sphere of the
|
|
2243
|
+
* given {@link radius}.
|
|
2244
|
+
*/
|
|
2077
2245
|
class PolyhedronElement extends Pacem3DPrimitiveElement {
|
|
2078
2246
|
propertyChangedCallback(name, old, val, first) {
|
|
2079
2247
|
super.propertyChangedCallback(name, old, val, first);
|
|
@@ -2084,6 +2252,7 @@
|
|
|
2084
2252
|
_assignMeshGeometry(radius) {
|
|
2085
2253
|
this.geometry = this.createMeshGeometry(radius > .0 ? radius : 1.0);
|
|
2086
2254
|
}
|
|
2255
|
+
/** Computes the polyhedron geometry using a radius of `1` when {@link radius} hasn't been explicitly set. */
|
|
2087
2256
|
createDefaultGeometry() {
|
|
2088
2257
|
return this.createMeshGeometry(1.0);
|
|
2089
2258
|
}
|
|
@@ -2092,7 +2261,9 @@
|
|
|
2092
2261
|
pacemCore.Watch({ emit: false, converter: pacemCore.PropertyConverters.Number })
|
|
2093
2262
|
], PolyhedronElement.prototype, "radius", void 0);
|
|
2094
2263
|
// #region Tetrahedron
|
|
2264
|
+
/** `<pacem-3d-primitive-tetrahedron>`: computes the {@link MeshGeometry} of a regular tetrahedron (a Platonic solid with 4 triangular faces). */
|
|
2095
2265
|
let PacemTetrahedronElement = PacemTetrahedronElement_1 = class PacemTetrahedronElement extends PolyhedronElement {
|
|
2266
|
+
/** Builds the {@link MeshGeometry} of a tetrahedron inscribed in a sphere of the given radius (defaults to `1`). */
|
|
2096
2267
|
static createMeshGeometry(radius) {
|
|
2097
2268
|
radius ||= 1.0;
|
|
2098
2269
|
const nodesCoordsString = "0 0.5774 -0.8165, 0 0.5774 0.8165, 0.8165 -0.5774 0, -0.8165 -0.5774 0";
|
|
@@ -2129,7 +2300,9 @@
|
|
|
2129
2300
|
], PacemTetrahedronElement);
|
|
2130
2301
|
// #endregion
|
|
2131
2302
|
// #region Octahedron
|
|
2303
|
+
/** `<pacem-3d-primitive-octahedron>`: computes the {@link MeshGeometry} of a regular octahedron (a Platonic solid with 8 triangular faces). */
|
|
2132
2304
|
let PacemOctahedronElement = PacemOctahedronElement_1 = class PacemOctahedronElement extends PolyhedronElement {
|
|
2305
|
+
/** Builds the {@link MeshGeometry} of an octahedron inscribed in a sphere of the given radius (defaults to `1`). */
|
|
2133
2306
|
static createMeshGeometry(radius) {
|
|
2134
2307
|
radius ||= 1.0;
|
|
2135
2308
|
// -------------------------------------------------------------------------------------------------
|
|
@@ -2168,7 +2341,9 @@
|
|
|
2168
2341
|
], PacemOctahedronElement);
|
|
2169
2342
|
// #endregion
|
|
2170
2343
|
// #region Hexahedron
|
|
2344
|
+
/** `<pacem-3d-primitive-hexahedron>`: computes the {@link MeshGeometry} of a regular hexahedron (a Platonic solid with 6 square faces, i.e. a cube). */
|
|
2171
2345
|
let PacemHexahedronElement = PacemHexahedronElement_1 = class PacemHexahedronElement extends PolyhedronElement {
|
|
2346
|
+
/** Builds the {@link MeshGeometry} of a cube inscribed in a sphere of the given radius (defaults to `1`), as an equal-sided {@link PacemBoxElement}. */
|
|
2172
2347
|
static createMeshGeometry(radius) {
|
|
2173
2348
|
radius ||= 1.0;
|
|
2174
2349
|
const inv_sqrt3 = 1.0 / Math.sqrt(3.0);
|
|
@@ -2186,7 +2361,9 @@
|
|
|
2186
2361
|
], PacemHexahedronElement);
|
|
2187
2362
|
// #endregion
|
|
2188
2363
|
// #region Icosahedron
|
|
2364
|
+
/** `<pacem-3d-primitive-icosahedron>`: computes the {@link MeshGeometry} of a regular icosahedron (a Platonic solid with 20 triangular faces). */
|
|
2189
2365
|
let PacemIcosahedronElement = PacemIcosahedronElement_1 = class PacemIcosahedronElement extends PolyhedronElement {
|
|
2366
|
+
/** Builds the {@link MeshGeometry} of an icosahedron inscribed in a sphere of the given radius (defaults to `1`). */
|
|
2190
2367
|
static createMeshGeometry(radius) {
|
|
2191
2368
|
radius ||= 1.0;
|
|
2192
2369
|
const nodesCoordsString = "0 0.850651 -0.525731, 0 0.850651 0.525731, 0.850651 0.525731 0, 0.525731 0 -0.850651, -0.525731 0 -0.850651, -0.850651 0.525731 0, -0.525731 0 0.850651, 0.525731 0 0.850651, 0.850651 -0.525731 0, 0 -0.850651 0.525731, 0 -0.850651 -0.525731, -0.850651 -0.525731 0";
|
|
@@ -2246,7 +2423,9 @@
|
|
|
2246
2423
|
], PacemIcosahedronElement);
|
|
2247
2424
|
// #endregion
|
|
2248
2425
|
// #region Dodecahedron
|
|
2426
|
+
/** `<pacem-3d-primitive-dodecahedron>`: computes the {@link MeshGeometry} of a regular dodecahedron (a Platonic solid with 12 pentagonal faces). */
|
|
2249
2427
|
let PacemDodecahedronElement = PacemDodecahedronElement_1 = class PacemDodecahedronElement extends PolyhedronElement {
|
|
2428
|
+
/** Builds the {@link MeshGeometry} of a dodecahedron inscribed in a sphere of the given radius (defaults to `1`). */
|
|
2250
2429
|
static createMeshGeometry(radius) {
|
|
2251
2430
|
radius ||= 1.0;
|
|
2252
2431
|
const n1 = Point3D.from(0.356822 * radius, 0.934172 * radius, 0 * radius);
|
|
@@ -2371,7 +2550,9 @@
|
|
|
2371
2550
|
};
|
|
2372
2551
|
var PacemSphereElement_1;
|
|
2373
2552
|
//namespace Pacem.Components.Drawing3D {
|
|
2553
|
+
/** `<pacem-3d-primitive-sphere>`: computes the {@link MeshGeometry} of a UV sphere. */
|
|
2374
2554
|
let PacemSphereElement = PacemSphereElement_1 = class PacemSphereElement extends Pacem3DPrimitiveElement {
|
|
2555
|
+
/** Builds the {@link MeshGeometry} of a sphere with the given radius (defaults to `1`) and tessellation (defaults to `8`). */
|
|
2375
2556
|
static createMeshGeometry(radius = 1, segs = 8) {
|
|
2376
2557
|
//
|
|
2377
2558
|
const nodes = [];
|
|
@@ -2453,6 +2634,7 @@
|
|
|
2453
2634
|
computeSharpVertexNormals(geom);
|
|
2454
2635
|
return geom;
|
|
2455
2636
|
}
|
|
2637
|
+
/** Computes the sphere geometry from the default (unset) shape parameters. */
|
|
2456
2638
|
createDefaultGeometry() {
|
|
2457
2639
|
return PacemSphereElement_1.createMeshGeometry();
|
|
2458
2640
|
}
|
|
@@ -2484,7 +2666,9 @@
|
|
|
2484
2666
|
};
|
|
2485
2667
|
var PacemTorusElement_1;
|
|
2486
2668
|
//namespace Pacem.Components.Drawing3D {
|
|
2669
|
+
/** `<pacem-3d-primitive-torus>`: computes the {@link MeshGeometry} of a torus (donut shape): a tube revolved around a central axis. */
|
|
2487
2670
|
let PacemTorusElement = PacemTorusElement_1 = class PacemTorusElement extends Pacem3DPrimitiveElement {
|
|
2671
|
+
/** Builds the {@link MeshGeometry} of a torus with the given outer/inner radii and ring/tube segment counts. */
|
|
2488
2672
|
static createMeshGeometry(radius = 1, innerRadius = .25, segments = 24, sides = 12) {
|
|
2489
2673
|
//
|
|
2490
2674
|
const nodes = [];
|
|
@@ -2535,6 +2719,7 @@
|
|
|
2535
2719
|
computeSharpVertexNormals(geom);
|
|
2536
2720
|
return geom;
|
|
2537
2721
|
}
|
|
2722
|
+
/** Computes the torus geometry from the default (unset) shape parameters. */
|
|
2538
2723
|
createDefaultGeometry() {
|
|
2539
2724
|
return PacemTorusElement_1.createMeshGeometry();
|
|
2540
2725
|
}
|
|
@@ -2582,21 +2767,29 @@
|
|
|
2582
2767
|
const clipY = y / rect.height * -2 + 1;
|
|
2583
2768
|
return { x: clipX, y: clipY };
|
|
2584
2769
|
}
|
|
2770
|
+
/** Shared helpers used by the concrete `pacem-3d` rendering-backend adapters (Three.js, WebGPU): type guards, buffer flattening, camera lookup and pointer-to-clip-space conversion. */
|
|
2585
2771
|
class AdapterUtils {
|
|
2772
|
+
/** Returns whether the given object is a {@link MeshGeometry} (has `positions` and `triangleIndices` arrays). */
|
|
2586
2773
|
static isMeshGeometry(obj) {
|
|
2587
2774
|
return 'positions' in obj && pacemCore.Utils.isArray(obj.positions)
|
|
2588
2775
|
&& 'triangleIndices' in obj && pacemCore.Utils.isArray(obj.triangleIndices);
|
|
2589
2776
|
}
|
|
2777
|
+
/** Returns whether the given object is a {@link Vector3D} (has numeric `x`/`y`/`z`). */
|
|
2590
2778
|
static isVector3D(obj) {
|
|
2591
2779
|
return 'x' in obj && typeof obj.x === 'number'
|
|
2592
2780
|
&& 'y' in obj && typeof obj.y === 'number'
|
|
2593
2781
|
&& 'z' in obj && typeof obj.z === 'number';
|
|
2594
2782
|
}
|
|
2783
|
+
/** Returns whether the given object is an {@link Rgba} color (has numeric `r`/`g`/`b`). */
|
|
2595
2784
|
static isRgba(obj) {
|
|
2596
2785
|
return 'r' in obj && typeof obj.r === 'number'
|
|
2597
2786
|
&& 'g' in obj && typeof obj.g === 'number'
|
|
2598
2787
|
&& 'b' in obj && typeof obj.b === 'number';
|
|
2599
2788
|
}
|
|
2789
|
+
/**
|
|
2790
|
+
* Flattens an array of 3D vectors, UV coordinates, or RGBA colors into a single flat number array (interleaved components), ready for a GPU buffer.
|
|
2791
|
+
* @param array Array of {@link Vector3D}, {@link UVMap} entries, or {@link Rgba} values to flatten
|
|
2792
|
+
*/
|
|
2600
2793
|
static flattenVectorArray(array) {
|
|
2601
2794
|
const retval = [];
|
|
2602
2795
|
for (let v of array) {
|
|
@@ -2612,6 +2805,10 @@
|
|
|
2612
2805
|
}
|
|
2613
2806
|
return retval;
|
|
2614
2807
|
}
|
|
2808
|
+
/**
|
|
2809
|
+
* Returns the first non-hidden {@link Camera} among the given renderables, if any.
|
|
2810
|
+
* @param items Renderable items to search
|
|
2811
|
+
*/
|
|
2615
2812
|
static findCamera(items) {
|
|
2616
2813
|
return (items || []).find(r => isCamera(r) && !r.hide);
|
|
2617
2814
|
}
|
|
@@ -2861,6 +3058,12 @@
|
|
|
2861
3058
|
throw new Error('The wait for THREE adapter initialization timed out.');
|
|
2862
3059
|
}
|
|
2863
3060
|
}
|
|
3061
|
+
/**
|
|
3062
|
+
* `<pacem-3d-three-adapter>`: {@link Pacem3DAdapterElement} rendering backend built on top of the
|
|
3063
|
+
* {@link https://threejs.org/ | Three.js}/WebGL library (lazily loaded from a CDN on first use). Translates the
|
|
3064
|
+
* {@link RenderableElement} scene graph into `THREE.Object3D`s, renders them with a `THREE.WebGLRenderer` and
|
|
3065
|
+
* supports mouse-driven orbit controls via {@link orbit}.
|
|
3066
|
+
*/
|
|
2864
3067
|
let Pacem3DThreeAdapterElement = class Pacem3DThreeAdapterElement extends Pacem3DAdapterElement {
|
|
2865
3068
|
constructor() {
|
|
2866
3069
|
super(...arguments);
|
|
@@ -3284,43 +3487,74 @@
|
|
|
3284
3487
|
], Pacem3DThreeAdapterElement);
|
|
3285
3488
|
|
|
3286
3489
|
//namespace Pacem.Drawing3D.WebGPU {
|
|
3490
|
+
/** Prefix prepended to every WebGPU resource label ({@link GPURenderPipeline}s, bind groups, layouts, shader modules, ...) created by this adapter, so they're easy to spot in browser devtools/profilers. */
|
|
3287
3491
|
const LABEL_PREFIX = 'pacem-3d-';
|
|
3492
|
+
/** Maximum value representable by a 32-bit unsigned integer (2^32 - 1). Used as the color-picking "no object" sentinel `u32` id. */
|
|
3288
3493
|
const U32_MAX = 4_294_967_295;
|
|
3289
3494
|
// #region vertex state
|
|
3495
|
+
/** Vertex buffer slot (index into {@link GPUVertexState.buffers}) carrying mesh vertex positions (or the packed position+normal+uv buffer, see {@link PipelineOptions.packedVertices}). */
|
|
3290
3496
|
const VERTEX_BUFFER_INDEX_MESH_POSITION = 0;
|
|
3497
|
+
/** Vertex buffer slot (index into {@link GPUVertexState.buffers}) carrying mesh vertex normals, when vertices aren't packed. */
|
|
3291
3498
|
const VERTEX_BUFFER_INDEX_MESH_NORMAL = 1;
|
|
3499
|
+
/** Vertex buffer slot (index into {@link GPUVertexState.buffers}) carrying mesh UV coordinates, when vertices aren't packed. */
|
|
3292
3500
|
const VERTEX_BUFFER_INDEX_MESH_UV = 2;
|
|
3501
|
+
/** `@location` index of the surface normal in the generated WGSL `VertexOutput` struct. */
|
|
3293
3502
|
const VERTEX_OUTPUT_LOCATION_NORMAL = 0;
|
|
3503
|
+
/** `@location` index of the world-space vertex position in the generated WGSL `VertexOutput` struct. */
|
|
3294
3504
|
const VERTEX_OUTPUT_LOCATION_VERTEX = 1;
|
|
3505
|
+
/** `@location` index of the UV coordinate in the generated WGSL `VertexOutput` struct. */
|
|
3295
3506
|
const VERTEX_OUTPUT_LOCATION_UV = 2;
|
|
3507
|
+
/** `@location` index of the vertex/triangle index in the generated WGSL `VertexOutput` struct. */
|
|
3296
3508
|
const VERTEX_OUTPUT_LOCATION_INDEX = 3;
|
|
3509
|
+
/** `@location` index of the picking ray data in the generated WGSL `VertexOutput` struct. */
|
|
3297
3510
|
const VERTEX_OUTPUT_LOCATION_RAY = 4;
|
|
3511
|
+
/** `@location` index of the instance index in the generated WGSL `VertexOutput` struct. */
|
|
3298
3512
|
const VERTEX_OUTPUT_LOCATION_INSTANCE = 5;
|
|
3513
|
+
/** `@group` index of the world/normal transform uniform bind group. */
|
|
3299
3514
|
const UNIFORM_GROUP_INDEX_TRANSFORM = 1;
|
|
3515
|
+
/** `@group` index of the camera view/projection uniform bind group. */
|
|
3300
3516
|
const UNIFORM_GROUP_INDEX_CAMERA = 0;
|
|
3517
|
+
/** `@group` index of the pointer/interaction uniform bind group. Deliberately aliased to {@link UNIFORM_GROUP_INDEX_CAMERA} so interaction data shares the camera's binding group. */
|
|
3301
3518
|
const UNIFORM_GROUP_INDEX_INTERACTION = UNIFORM_GROUP_INDEX_CAMERA; // put it in camera same binding group
|
|
3519
|
+
/** `@group` index of the line-geometry storage bind group (positions + line properties). */
|
|
3302
3520
|
const STORAGE_GROUP_INDEX_LINE = 2;
|
|
3521
|
+
/** `@group` index of the color-picking (object-id) uniform bind group. */
|
|
3303
3522
|
const UNIFORM_GROUP_INDEX_COLORPICKING = 2;
|
|
3523
|
+
/** `@binding` index of the world/normal transform uniform, within {@link UNIFORM_GROUP_INDEX_TRANSFORM}. */
|
|
3304
3524
|
const UNIFORM_BINDING_INDEX_TRANSFORM = 0;
|
|
3525
|
+
/** `@binding` index of the camera view/projection uniform, within {@link UNIFORM_GROUP_INDEX_CAMERA}. */
|
|
3305
3526
|
const UNIFORM_BINDING_INDEX_CAMERA = 0;
|
|
3527
|
+
/** `@binding` index of the pointer/interaction uniform, within {@link UNIFORM_GROUP_INDEX_INTERACTION}. */
|
|
3306
3528
|
const UNIFORM_BINDING_INDEX_INTERACTION = 1;
|
|
3307
3529
|
// #endregion
|
|
3308
3530
|
// #region fragment state
|
|
3531
|
+
/** `@group` index of the material (storage buffer + optional texture/sampler) bind group. */
|
|
3309
3532
|
const MATERIAL_GROUP_INDEX = 2;
|
|
3533
|
+
/** `@group` index of the per-light uniform bind group, immediately following {@link MATERIAL_GROUP_INDEX}. */
|
|
3310
3534
|
const UNIFORM_GROUP_INDEX_LIGHTING = MATERIAL_GROUP_INDEX + 1;
|
|
3535
|
+
/** `@binding` index of the material storage buffer, within {@link MATERIAL_GROUP_INDEX}. */
|
|
3311
3536
|
const STORAGE_MATERIAL_INDEX = 0;
|
|
3537
|
+
/** `@binding` index of the material's texture sampler, within {@link MATERIAL_GROUP_INDEX}. */
|
|
3312
3538
|
const SAMPLER_BINDING_INDEX = 1;
|
|
3539
|
+
/** `@binding` index of the material's texture, within {@link MATERIAL_GROUP_INDEX}. */
|
|
3313
3540
|
const TEXTURE_BINDING_INDEX = 2;
|
|
3541
|
+
/** WGSL identifier used to reference the running vertex/fragment color in generated shader fragments (spliced in and out by texture/lighting stages). */
|
|
3314
3542
|
const VERTEX_COLOR_REFERENCE = 'color';
|
|
3543
|
+
/** WGSL identifier used to reference the accumulated ambient-light contribution in generated fragment shader code. */
|
|
3315
3544
|
const AMBIENT_COLOR_REFERENCE = 'ambient';
|
|
3545
|
+
/** WGSL identifier used to reference the accumulated (directional/omni) lighting contribution in generated fragment shader code. */
|
|
3316
3546
|
const LIGHTING_COLOR_REFERENCE = 'lighting';
|
|
3317
3547
|
// #endregion
|
|
3318
3548
|
// #region WGSL
|
|
3549
|
+
/** Name of the WGSL struct describing per-vertex input attributes, used by generated vertex shader code. */
|
|
3319
3550
|
const WGSL_VERTEXINPUT_STRUCT_NAME = 'VertexInput';
|
|
3551
|
+
/** Name of the WGSL struct describing vertex-stage output / fragment-stage input, used by generated vertex and fragment shader code. */
|
|
3320
3552
|
const WGSL_VERTEXOUTPUT_STRUCT_NAME = 'VertexOutput';
|
|
3553
|
+
/** Name of the WGSL struct describing the pointer/interaction uniform data, used by generated shader code. */
|
|
3321
3554
|
const WGSL_INTERACTIONDATA_STRUCT_NAME = 'InteractionData';
|
|
3322
3555
|
// #endregion
|
|
3323
3556
|
// Kinda polyfill for WebGPU constants, as TypeScript 6.0 does include WebGPU types but does NOT include these constants for magic numbers:
|
|
3557
|
+
/** Polyfill for the WebGPU `GPUBufferUsage` bitflags (`lib.dom` declares the `GPUBufferUsageFlags` type but not these numeric flag values). Combine with `|` when creating a {@link GPUBuffer}, e.g. `GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST`. */
|
|
3324
3558
|
var GPUBufferUsage;
|
|
3325
3559
|
(function (GPUBufferUsage) {
|
|
3326
3560
|
GPUBufferUsage[GPUBufferUsage["COPY_SRC"] = 4] = "COPY_SRC";
|
|
@@ -3334,6 +3568,7 @@
|
|
|
3334
3568
|
GPUBufferUsage[GPUBufferUsage["UNIFORM"] = 64] = "UNIFORM";
|
|
3335
3569
|
GPUBufferUsage[GPUBufferUsage["VERTEX"] = 32] = "VERTEX";
|
|
3336
3570
|
})(GPUBufferUsage || (GPUBufferUsage = {}));
|
|
3571
|
+
/** Polyfill for the WebGPU `GPUTextureUsage` bitflags (`lib.dom` declares the `GPUTextureUsageFlags` type but not these numeric flag values). Combine with `|` when creating a {@link GPUTexture}. */
|
|
3337
3572
|
var GPUTextureUsage;
|
|
3338
3573
|
(function (GPUTextureUsage) {
|
|
3339
3574
|
GPUTextureUsage[GPUTextureUsage["COPY_SRC"] = 1] = "COPY_SRC";
|
|
@@ -3342,18 +3577,21 @@
|
|
|
3342
3577
|
GPUTextureUsage[GPUTextureUsage["STORAGE_BINDING"] = 8] = "STORAGE_BINDING";
|
|
3343
3578
|
GPUTextureUsage[GPUTextureUsage["TEXTURE_BINDING"] = 4] = "TEXTURE_BINDING";
|
|
3344
3579
|
})(GPUTextureUsage || (GPUTextureUsage = {}));
|
|
3580
|
+
/** Polyfill for the WebGPU `GPUShaderStage` bitflags (`lib.dom` declares the `GPUShaderStageFlags` type but not these numeric flag values). Combine with `|` in {@link GPUBindGroupLayoutEntry.visibility}, e.g. `GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT`. */
|
|
3345
3581
|
var GPUShaderStage;
|
|
3346
3582
|
(function (GPUShaderStage) {
|
|
3347
3583
|
GPUShaderStage[GPUShaderStage["VERTEX"] = 1] = "VERTEX";
|
|
3348
3584
|
GPUShaderStage[GPUShaderStage["FRAGMENT"] = 2] = "FRAGMENT";
|
|
3349
3585
|
GPUShaderStage[GPUShaderStage["COMPUTE"] = 4] = "COMPUTE";
|
|
3350
3586
|
})(GPUShaderStage || (GPUShaderStage = {}));
|
|
3587
|
+
/** Polyfill for the WebGPU `GPUMapMode` flags (`lib.dom` declares the type but not these numeric values). Used with {@link GPUBuffer.mapAsync}. */
|
|
3351
3588
|
var GPUMapMode;
|
|
3352
3589
|
(function (GPUMapMode) {
|
|
3353
3590
|
GPUMapMode[GPUMapMode["READ"] = 1] = "READ";
|
|
3354
3591
|
GPUMapMode[GPUMapMode["WRITE"] = 2] = "WRITE";
|
|
3355
3592
|
})(GPUMapMode || (GPUMapMode = {}));
|
|
3356
3593
|
|
|
3594
|
+
/** Categorizes a bind group by the role of the resources it carries (mesh transforms, camera, texture, light, interaction data), used to look up {@link BindGroupDefinition}s via {@link WGSL.bindings}. */
|
|
3357
3595
|
var WGSLBindingType;
|
|
3358
3596
|
(function (WGSLBindingType) {
|
|
3359
3597
|
WGSLBindingType["Mesh"] = "mesh";
|
|
@@ -3364,7 +3602,20 @@
|
|
|
3364
3602
|
})(WGSLBindingType || (WGSLBindingType = {}));
|
|
3365
3603
|
|
|
3366
3604
|
//namespace Pacem.Drawing3D.WebGPU {
|
|
3605
|
+
/**
|
|
3606
|
+
* Low-level factory for typed {@link GPUBuffer}s (vertex, uniform, storage, index) used throughout the WebGPU backend
|
|
3607
|
+
* to upload CPU-side geometry/material/uniform data to the GPU. Vertex and index buffers are populated immediately
|
|
3608
|
+
* (via `mappedAtCreation`); uniform and storage buffers are allocated empty, sized to `data`, and are expected to be
|
|
3609
|
+
* populated later via {@link GPUQueue.writeBuffer} (see {@link Buffer}/`abstractions.ts` and the `fresh`-tracking
|
|
3610
|
+
* buffer accessors in `renderablebuffer.ts`).
|
|
3611
|
+
*/
|
|
3367
3612
|
class Buffers {
|
|
3613
|
+
/**
|
|
3614
|
+
* Creates a {@link GPUBuffer} usable as a vertex buffer (`VERTEX | COPY_DST`), writing `data` into it immediately.
|
|
3615
|
+
* @param device The {@link GPUDevice} to allocate the buffer on.
|
|
3616
|
+
* @param data Vertex attribute data (e.g. flattened positions/normals/uv coordinates).
|
|
3617
|
+
* @param label Optional debug label.
|
|
3618
|
+
*/
|
|
3368
3619
|
static create(device, data, label = '') {
|
|
3369
3620
|
const buffer = device.createBuffer({
|
|
3370
3621
|
size: data.byteLength, label,
|
|
@@ -3387,6 +3638,12 @@
|
|
|
3387
3638
|
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
|
|
3388
3639
|
});
|
|
3389
3640
|
}
|
|
3641
|
+
/**
|
|
3642
|
+
* Creates a {@link GPUBuffer} usable as an index buffer (`INDEX | COPY_DST`), writing `data` into it immediately.
|
|
3643
|
+
* @param device The {@link GPUDevice} to allocate the buffer on.
|
|
3644
|
+
* @param data 16-bit vertex indices.
|
|
3645
|
+
* @param label Optional debug label.
|
|
3646
|
+
*/
|
|
3390
3647
|
static createIndexed(device, data, label = '') {
|
|
3391
3648
|
const buffer = device.createBuffer({
|
|
3392
3649
|
size: data.byteLength, label,
|
|
@@ -3398,6 +3655,10 @@
|
|
|
3398
3655
|
return buffer;
|
|
3399
3656
|
}
|
|
3400
3657
|
}
|
|
3658
|
+
/**
|
|
3659
|
+
* Helpers to build {@link GPUVertexBufferLayout}s describing how a vertex buffer's contents map to shader `@location`
|
|
3660
|
+
* inputs, for use in a {@link GPURenderPipelineDescriptor.vertex} state.
|
|
3661
|
+
*/
|
|
3401
3662
|
class BufferLayouts {
|
|
3402
3663
|
static createVertex(shaderLocationStart = 0, size = 3, ...sizes) {
|
|
3403
3664
|
const attributes = [];
|
|
@@ -3419,6 +3680,7 @@
|
|
|
3419
3680
|
}
|
|
3420
3681
|
}
|
|
3421
3682
|
|
|
3683
|
+
/** Fallback options used by {@link getBasicMaterialFragmentWgsl}: mirrors the `VERTEX_OUTPUT_LOCATION_*` layout produced by `mesh-vertex.ts` and reads the diffuse color from {@link MATERIAL_GROUP_INDEX}/{@link STORAGE_MATERIAL_INDEX}. */
|
|
3422
3684
|
const DefaultBasicMaterialFragmentOptions = {
|
|
3423
3685
|
outputNormalLocation: VERTEX_OUTPUT_LOCATION_NORMAL,
|
|
3424
3686
|
outputVertexLocation: VERTEX_OUTPUT_LOCATION_VERTEX,
|
|
@@ -3429,9 +3691,16 @@
|
|
|
3429
3691
|
storageMaterialGroupIndex: MATERIAL_GROUP_INDEX,
|
|
3430
3692
|
storageMaterialBindingIndex: STORAGE_MATERIAL_INDEX,
|
|
3431
3693
|
};
|
|
3694
|
+
/** Joins a {@link WGSLFragmentExtra} string array (`definitions`/`bindings`) with CRLF newlines, or returns an empty string when omitted. */
|
|
3432
3695
|
function adaptWGSLStringArray$1(array = []) {
|
|
3433
3696
|
return array.join('\r\n');
|
|
3434
3697
|
}
|
|
3698
|
+
/**
|
|
3699
|
+
* Turns a {@link WGSLFragmentExtra.modifiers} array into a block of WGSL statements to inline into `main`. Entries
|
|
3700
|
+
* already ending with `;` are emitted verbatim; bare expressions are wrapped into `${VERTEX_COLOR_REFERENCE} = <expr>;`
|
|
3701
|
+
* so lighting/texture snippets (see {@link ambientLight}/{@link directionalLight}/{@link omniLight}/{@link textureMap})
|
|
3702
|
+
* can either replace or contribute to the running `color`/`ambient`/`lighting` accumulators.
|
|
3703
|
+
*/
|
|
3435
3704
|
function adaptWGSLModifierStringArray$1(array = []) {
|
|
3436
3705
|
let output = '';
|
|
3437
3706
|
for (let modifier of array) {
|
|
@@ -3445,6 +3714,21 @@
|
|
|
3445
3714
|
}
|
|
3446
3715
|
return output;
|
|
3447
3716
|
}
|
|
3717
|
+
/**
|
|
3718
|
+
* Composes the fragment shader for the "basic" (unlit-by-default) material: it reads a flat `diffuseColor` from a
|
|
3719
|
+
* storage buffer, then lets `extensions.modifiers` (lighting/texture snippets) accumulate into the `color`,
|
|
3720
|
+
* `ambient` and `lighting` WGSL variables ({@link VERTEX_COLOR_REFERENCE}/{@link AMBIENT_COLOR_REFERENCE}/{@link LIGHTING_COLOR_REFERENCE}).
|
|
3721
|
+
* If nothing wrote a `lighting` color (alpha stays `0`), it is treated as fully lit (`white`) so the material
|
|
3722
|
+
* renders unshaded when no light snippet is attached; the final output is `color * lighting + ambient`.
|
|
3723
|
+
*
|
|
3724
|
+
* Splices `extensions.definitions`/`extensions.bindings`/`extensions.modifiers` (see {@link WGSLFragmentExtra}) into
|
|
3725
|
+
* the `// definitions`, `// bindings` and body sections of the generated source, alongside the fixed
|
|
3726
|
+
* `diffuseColor` storage binding and the `@fragment fn main` signature matching `mesh-vertex.ts`'s `VertexOutput`.
|
|
3727
|
+
*
|
|
3728
|
+
* @param extensions Extra WGSL `definitions`/`bindings`/`modifiers` to merge in (e.g. lighting/texture contributions).
|
|
3729
|
+
* @param options Location/binding overrides; defaults to {@link DefaultBasicMaterialFragmentOptions}, matching the vertex-stage outputs produced by `mesh-vertex.ts`.
|
|
3730
|
+
* @returns Complete WGSL fragment-shader source with a single `@fragment fn main` entry point returning `@location(0) vec4f`.
|
|
3731
|
+
*/
|
|
3448
3732
|
function getBasicMaterialFragmentWgsl(extensions = {}, options = DefaultBasicMaterialFragmentOptions) {
|
|
3449
3733
|
const opts = pacemCore.Utils.extend({}, DefaultBasicMaterialFragmentOptions, options);
|
|
3450
3734
|
const definitions = adaptWGSLStringArray$1(extensions.definitions), bindings = adaptWGSLStringArray$1(extensions.bindings), modifiers = adaptWGSLModifierStringArray$1(extensions.modifiers);
|
|
@@ -3481,15 +3765,22 @@ const white = vec4f(1,1,1,1);
|
|
|
3481
3765
|
}`;
|
|
3482
3766
|
}
|
|
3483
3767
|
|
|
3768
|
+
/** Fallback options used by {@link getLineMaterialFragmentWgsl}: reads instance/vertex index from locations 0/1 (matching `line-vertex.ts`'s `VertexOutput`) and the color storage buffer at {@link STORAGE_GROUP_INDEX_LINE}` + 1`/{@link STORAGE_MATERIAL_INDEX}. */
|
|
3484
3769
|
const DefaultLineMaterialFragmentOptions = {
|
|
3485
3770
|
outputInstanceIndexLocation: 0,
|
|
3486
3771
|
outputVertexIndexLocation: 1,
|
|
3487
3772
|
storageMaterialGroupIndex: STORAGE_GROUP_INDEX_LINE + 1,
|
|
3488
3773
|
storageMaterialBindingIndex: STORAGE_MATERIAL_INDEX,
|
|
3489
3774
|
};
|
|
3775
|
+
/** Joins a {@link WGSLFragmentExtra} string array (`definitions`/`bindings`) with CRLF newlines, or returns an empty string when omitted. */
|
|
3490
3776
|
function adaptWGSLStringArray(array = []) {
|
|
3491
3777
|
return array.join('\r\n');
|
|
3492
3778
|
}
|
|
3779
|
+
/**
|
|
3780
|
+
* Turns a {@link WGSLFragmentExtra.modifiers} array into a block of WGSL statements to inline into `main`. Entries
|
|
3781
|
+
* already ending with `;` are emitted verbatim (assumed to be full statements); bare expressions are wrapped into
|
|
3782
|
+
* `output = <expr>;` so each modifier can either replace or contribute to the fragment's `output` color variable.
|
|
3783
|
+
*/
|
|
3493
3784
|
function adaptWGSLModifierStringArray(array = []) {
|
|
3494
3785
|
let output = '';
|
|
3495
3786
|
for (let modifier of array) {
|
|
@@ -3503,6 +3794,20 @@ const white = vec4f(1,1,1,1);
|
|
|
3503
3794
|
}
|
|
3504
3795
|
return output;
|
|
3505
3796
|
}
|
|
3797
|
+
/**
|
|
3798
|
+
* Composes the fragment shader for line/polyline rendering: it looks up the current vertex's color from a
|
|
3799
|
+
* per-vertex `vertexColors` storage buffer (indexed modulo its length via `getVertexColor`, so a shorter palette
|
|
3800
|
+
* cycles/repeats across a longer line) and returns it as `@location(0) vec4f`, honoring any `extensions.modifiers`
|
|
3801
|
+
* applied afterwards (e.g. dashing, fading).
|
|
3802
|
+
*
|
|
3803
|
+
* Splices `extensions.definitions`/`extensions.bindings`/`extensions.modifiers` (see {@link WGSLFragmentExtra},
|
|
3804
|
+
* typically produced by the light snippets in this folder) into the `// definitions`, `// bindings` and body
|
|
3805
|
+
* sections of the generated source, in addition to the fixed `vertexColors` storage binding.
|
|
3806
|
+
*
|
|
3807
|
+
* @param extensions Extra WGSL `definitions`/`bindings`/`modifiers` to merge in (e.g. lighting contributions).
|
|
3808
|
+
* @param options Binding/location overrides; defaults to {@link DefaultLineMaterialFragmentOptions}, matching the vertex-stage outputs produced by `line-vertex.ts`.
|
|
3809
|
+
* @returns Complete WGSL fragment-shader source with a single `@fragment fn main` entry point.
|
|
3810
|
+
*/
|
|
3506
3811
|
function getLineMaterialFragmentWgsl(extensions = {}, options = DefaultLineMaterialFragmentOptions) {
|
|
3507
3812
|
const opts = pacemCore.Utils.extend({}, DefaultLineMaterialFragmentOptions, options);
|
|
3508
3813
|
const definitions = adaptWGSLStringArray(extensions.definitions), bindings = adaptWGSLStringArray(extensions.bindings), modifiers = adaptWGSLModifierStringArray(extensions.modifiers);
|
|
@@ -3534,7 +3839,18 @@ fn getVertexColor(index: u32) -> vec4f {
|
|
|
3534
3839
|
}
|
|
3535
3840
|
|
|
3536
3841
|
//namespace Pacem.Drawing3D.WebGPU {
|
|
3842
|
+
/**
|
|
3843
|
+
* Factory that converts a scene-facing {@link Material3D} (`../../materials/material.ts`) into its WebGPU-side
|
|
3844
|
+
* counterpart ({@link Material}, `abstractions.ts`): a {@link BasicMaterial} or {@link LineMaterial} wrapping the GPU
|
|
3845
|
+
* buffer/texture/WGSL-fragment logic consumed when building render pipelines (see `pipelinefactory.ts`).
|
|
3846
|
+
*/
|
|
3537
3847
|
class Materials {
|
|
3848
|
+
/**
|
|
3849
|
+
* Wraps `material` in the {@link Material} implementation matching its `shader`.
|
|
3850
|
+
* @param material The scene material to wrap.
|
|
3851
|
+
* @returns A {@link BasicMaterial} or {@link LineMaterial}, depending on `material.shader`.
|
|
3852
|
+
* @throws {TypeError} If `material.shader` isn't one of the supported {@link KnownShader} values.
|
|
3853
|
+
*/
|
|
3538
3854
|
static create(material) {
|
|
3539
3855
|
if (isBasicMaterial(material)) {
|
|
3540
3856
|
return new BasicMaterial(material);
|
|
@@ -3576,6 +3892,11 @@ fn getVertexColor(index: u32) -> vec4f {
|
|
|
3576
3892
|
return retval;
|
|
3577
3893
|
}
|
|
3578
3894
|
}
|
|
3895
|
+
/**
|
|
3896
|
+
* WebGPU-side counterpart of a {@link BasicMaterial3D}: supplies the diffuse-color storage buffer (inherited from
|
|
3897
|
+
* {@link MaterialBase.buffer}) and, when the material has a `texture`, allocates the backing {@link GPUTexture}
|
|
3898
|
+
* (pixel data is copied in later by the mesh pipeline's material bind-group setup, see `pipelinefactory.ts`).
|
|
3899
|
+
*/
|
|
3579
3900
|
class BasicMaterial extends MaterialBase {
|
|
3580
3901
|
get shader() {
|
|
3581
3902
|
return KnownShader.Basic;
|
|
@@ -3586,6 +3907,10 @@ fn getVertexColor(index: u32) -> vec4f {
|
|
|
3586
3907
|
throw new TypeError("Basic material expected.");
|
|
3587
3908
|
}
|
|
3588
3909
|
}
|
|
3910
|
+
/**
|
|
3911
|
+
* Allocates the (uninitialized) {@link GPUTexture} for the material's `texture`, if any.
|
|
3912
|
+
* @param key Must be `'texture'`; any other {@link MaterialKey} (or a material without a `texture`) yields `null`.
|
|
3913
|
+
*/
|
|
3589
3914
|
texture({ device }, key = 'texture') {
|
|
3590
3915
|
const material = this.material;
|
|
3591
3916
|
if (key === 'texture' && !pacemCore.Utils.isNull(material.texture)) {
|
|
@@ -3600,8 +3925,14 @@ fn getVertexColor(index: u32) -> vec4f {
|
|
|
3600
3925
|
return null;
|
|
3601
3926
|
}
|
|
3602
3927
|
// TODO: put it in the material instance/interface
|
|
3928
|
+
/** Basic-material fragment shader WGSL source generator; see `wgsl/basic-material-fragment.ts`. */
|
|
3603
3929
|
static { this.fragment = getBasicMaterialFragmentWgsl; }
|
|
3604
3930
|
}
|
|
3931
|
+
/**
|
|
3932
|
+
* WebGPU-side counterpart of a {@link LineMaterial3D}: supplies the diffuse-color storage buffer (inherited from
|
|
3933
|
+
* {@link MaterialBase.buffer}) plus a dedicated `'line'` uniform buffer holding the canvas size and half line-width,
|
|
3934
|
+
* consumed by the line vertex shader (`wgsl/line-vertex.ts`).
|
|
3935
|
+
*/
|
|
3605
3936
|
class LineMaterial extends MaterialBase {
|
|
3606
3937
|
get shader() {
|
|
3607
3938
|
return KnownShader.Line;
|
|
@@ -3612,6 +3943,12 @@ fn getVertexColor(index: u32) -> vec4f {
|
|
|
3612
3943
|
throw new TypeError("Line material expected.");
|
|
3613
3944
|
}
|
|
3614
3945
|
}
|
|
3946
|
+
/**
|
|
3947
|
+
* Returns the `'line'` uniform buffer (canvas width/height and half line-width) for `key === 'line'`; otherwise
|
|
3948
|
+
* defers to the inherited diffuse-color buffer.
|
|
3949
|
+
* @param ctx WebGPU context supplying the device and canvas.
|
|
3950
|
+
* @param key Which buffer to build; only `'line'` is handled specially.
|
|
3951
|
+
*/
|
|
3615
3952
|
buffer(ctx, key) {
|
|
3616
3953
|
switch (key) {
|
|
3617
3954
|
case 'line':
|
|
@@ -3623,18 +3960,38 @@ fn getVertexColor(index: u32) -> vec4f {
|
|
|
3623
3960
|
return super.buffer(ctx);
|
|
3624
3961
|
}
|
|
3625
3962
|
}
|
|
3963
|
+
/** Lines have no texture support; always returns `null`. */
|
|
3626
3964
|
texture(_) {
|
|
3627
3965
|
return null;
|
|
3628
3966
|
}
|
|
3967
|
+
/** Line-material fragment shader WGSL source generator; see `wgsl/line-material-fragment.ts`. */
|
|
3629
3968
|
static { this.fragment = getLineMaterialFragmentWgsl; }
|
|
3630
3969
|
}
|
|
3631
3970
|
|
|
3632
3971
|
//namespace Pacem.Drawing3D.WebGPU {
|
|
3972
|
+
/** Placeholder identifiers (`input`, `data`) fed to a {@link VertexInputModifierDelegate}/{@link VertexOutputModifierDelegate} callback when {@link extractMeshVertexModifierFunctionComponents} needs to materialize its WGSL source before parsing it. */
|
|
3633
3973
|
const defaultVertexGeometryModifierArgs = ['input', 'data'];
|
|
3634
3974
|
//const defaultVertexGeometryModifier: VertexInputModifierDelegate = (...defaultVertexGeometryModifierArgs) => {
|
|
3635
3975
|
// const [inputRef, dataRef] = defaultVertexGeometryModifierArgs;
|
|
3636
3976
|
// return `fn echo(${inputRef}: ${WGSL_VERTEXINPUT_STRUCT_NAME}, ${dataRef}: ${WGSL_INTERACTIONDATA_STRUCT_NAME}) -> ${WGSL_VERTEXINPUT_STRUCT_NAME} { return ${inputRef}; }`;
|
|
3637
3977
|
//};
|
|
3978
|
+
/**
|
|
3979
|
+
* Parses a user-supplied vertex-stage modifier (see {@link VertexInputModifierDelegate}/{@link VertexOutputModifierDelegate},
|
|
3980
|
+
* consumed by `mesh-vertex.ts`'s `getMeshVertexWgsl`) into its WGSL function name, parameter names and body, so the
|
|
3981
|
+
* caller can inline it as a standalone `fn` definition and reference it by name from the generated vertex shader.
|
|
3982
|
+
*
|
|
3983
|
+
* If `wgsl` is a callback rather than a raw string, it is first invoked with the placeholder argument names in
|
|
3984
|
+
* {@link defaultVertexGeometryModifierArgs} to obtain its WGSL source. The resulting source is then matched against
|
|
3985
|
+
* `fn <name>(<arg0>: <ArgType>, <arg1>: InteractionData) -> <ArgType> { <body> }`, where `<ArgType>` must be either
|
|
3986
|
+
* `VertexInput` ({@link WGSL_VERTEXINPUT_STRUCT_NAME}) or `VertexOutput` ({@link WGSL_VERTEXOUTPUT_STRUCT_NAME}) and
|
|
3987
|
+
* must match on both sides of the signature (an input modifier both takes and returns `VertexInput`, an output
|
|
3988
|
+
* modifier both takes and returns `VertexOutput`), with the second parameter always typed
|
|
3989
|
+
* {@link WGSL_INTERACTIONDATA_STRUCT_NAME}.
|
|
3990
|
+
*
|
|
3991
|
+
* @param wgsl Raw WGSL function source, or a delegate that produces it when called with `(inputRef, interactionDataRef)`.
|
|
3992
|
+
* @returns The parsed function's `name`, its two parameter `args` (in order), and its `body` (the statements between the braces, trimmed).
|
|
3993
|
+
* @throws If the source doesn't match the required single-function signature, or if its parameter types are inconsistent with the modifier contract.
|
|
3994
|
+
*/
|
|
3638
3995
|
function extractMeshVertexModifierFunctionComponents(wgsl) {
|
|
3639
3996
|
if (typeof wgsl !== 'string') {
|
|
3640
3997
|
wgsl = wgsl(...defaultVertexGeometryModifierArgs);
|
|
@@ -3661,6 +4018,7 @@ fn getVertexColor(index: u32) -> vec4f {
|
|
|
3661
4018
|
}
|
|
3662
4019
|
}
|
|
3663
4020
|
|
|
4021
|
+
/** Fallback options used by {@link getMeshVertexWgsl}: the standard `VERTEX_OUTPUT_LOCATION_*`/`VERTEX_BUFFER_INDEX_MESH_*` layout and the transform/camera/interaction uniform coordinates shared across mesh pipelines. */
|
|
3664
4022
|
const DefaultMeshVertexOptions = {
|
|
3665
4023
|
outputNormalLocation: VERTEX_OUTPUT_LOCATION_NORMAL,
|
|
3666
4024
|
outputVertexLocation: VERTEX_OUTPUT_LOCATION_VERTEX,
|
|
@@ -3678,6 +4036,23 @@ fn getVertexColor(index: u32) -> vec4f {
|
|
|
3678
4036
|
uniformInteractionBindingIndex: UNIFORM_BINDING_INDEX_INTERACTION,
|
|
3679
4037
|
uniformInteractionGroupIndex: UNIFORM_GROUP_INDEX_INTERACTION,
|
|
3680
4038
|
};
|
|
4039
|
+
/**
|
|
4040
|
+
* Composes the standard vertex shader used to draw mesh geometry: it transforms each vertex position by the
|
|
4041
|
+
* world/view/projection matrices, transforms the normal by the (precomputed) normal matrix, passes UVs through
|
|
4042
|
+
* unchanged, and computes an eye-to-vertex `ray` (normalized `worldPosition - camera.position`) plus the built-in
|
|
4043
|
+
* vertex/instance indices — everything the fragment shaders in this folder (see `basic-material-fragment.ts`,
|
|
4044
|
+
* `standard-material-fragment.ts`) expect to find on `VertexOutput`.
|
|
4045
|
+
*
|
|
4046
|
+
* Declares the `VertexOutput`/`VertexInput`/`Transforms`/`Camera`/`InteractionData` WGSL structs (using the
|
|
4047
|
+
* `WGSL_*_STRUCT_NAME` constants so downstream shaders can reference them by the same names), binds the
|
|
4048
|
+
* `transforms`/`camera`/`interaction` uniforms at the configured `@group`/`@binding` coordinates, and — if
|
|
4049
|
+
* `options.inputModifier`/`options.outputModifier` are supplied (raw WGSL or a {@link VertexInputModifierDelegate}/{@link VertexOutputModifierDelegate}) —
|
|
4050
|
+
* parses them via {@link extractMeshVertexModifierFunctionComponents} and inlines them as extra `fn` definitions
|
|
4051
|
+
* invoked before returning, letting user code rewrite the input geometry or tweak the computed output per-vertex.
|
|
4052
|
+
*
|
|
4053
|
+
* @param options Location/binding overrides and optional input/output WGSL modifiers; defaults to {@link DefaultMeshVertexOptions}.
|
|
4054
|
+
* @returns Complete WGSL vertex-shader source with a single `@vertex fn main` entry point returning `VertexOutput`.
|
|
4055
|
+
*/
|
|
3681
4056
|
function getMeshVertexWgsl(options = DefaultMeshVertexOptions) {
|
|
3682
4057
|
if (options != DefaultMeshVertexOptions) {
|
|
3683
4058
|
options = pacemCore.Utils.extend({}, DefaultMeshVertexOptions, options);
|
|
@@ -3769,6 +4144,7 @@ ${modifierFnOutput}
|
|
|
3769
4144
|
}`;
|
|
3770
4145
|
}
|
|
3771
4146
|
|
|
4147
|
+
/** Fallback options used by {@link getDefaultLineVertexWgsl}/{@link getFatLineVertexWgsl}: positions/dimensions read from {@link STORAGE_GROUP_INDEX_LINE}, transform/camera uniforms from the shared {@link UNIFORM_GROUP_INDEX_TRANSFORM}/{@link UNIFORM_GROUP_INDEX_CAMERA} coordinates. */
|
|
3772
4148
|
const DefaultLineVertexOptions = {
|
|
3773
4149
|
inputPositionLocation: VERTEX_BUFFER_INDEX_MESH_POSITION,
|
|
3774
4150
|
outputInstanceIndexLocation: 0,
|
|
@@ -3782,6 +4158,7 @@ ${modifierFnOutput}
|
|
|
3782
4158
|
uniformWorldGroupIndex: UNIFORM_GROUP_INDEX_TRANSFORM,
|
|
3783
4159
|
uniformWorldBindingIndex: UNIFORM_BINDING_INDEX_TRANSFORM,
|
|
3784
4160
|
};
|
|
4161
|
+
/** Builds the `VertexOutput` struct shared by both line vertex shaders below: clip-space `position` plus flat `instance`/`index` varyings, at the configured output locations, consumed by `line-material-fragment.ts`. */
|
|
3785
4162
|
function getVertexOutputStructDefinition(opts) {
|
|
3786
4163
|
return `struct ${WGSL_VERTEXOUTPUT_STRUCT_NAME} {
|
|
3787
4164
|
@builtin(position) position : vec4f, // clip space position
|
|
@@ -3789,6 +4166,19 @@ ${modifierFnOutput}
|
|
|
3789
4166
|
@location(${opts.outputVertexIndexLocation}) @interpolate(flat) index : u32, // vertex index
|
|
3790
4167
|
}`;
|
|
3791
4168
|
}
|
|
4169
|
+
/**
|
|
4170
|
+
* Composes the vertex shader for thin (native-line-width, 1px) line rendering: each vertex reads its `x`/`y`/`z`
|
|
4171
|
+
* directly out of a flattened `positions: array<f32>` storage buffer (three floats per point, indexed by the
|
|
4172
|
+
* built-in `vertex_index`) rather than a vertex-buffer attribute, then applies the usual world/view/projection
|
|
4173
|
+
* transform chain. `instance_index` is passed through unchanged so the fragment stage
|
|
4174
|
+
* (`line-material-fragment.ts`) can look up a per-vertex color.
|
|
4175
|
+
*
|
|
4176
|
+
* Declares `VertexOutput`/`Transforms`/`Camera` WGSL structs and binds `transforms`/`camera`/`positions` at the
|
|
4177
|
+
* configured `@group`/`@binding` coordinates.
|
|
4178
|
+
*
|
|
4179
|
+
* @param options Location/binding overrides; defaults to {@link DefaultLineVertexOptions}.
|
|
4180
|
+
* @returns Complete WGSL vertex-shader source with a single `@vertex fn main` entry point returning `VertexOutput`.
|
|
4181
|
+
*/
|
|
3792
4182
|
function getDefaultLineVertexWgsl(options = DefaultLineVertexOptions) {
|
|
3793
4183
|
const opts = pacemCore.Utils.extend({}, DefaultLineVertexOptions, options);
|
|
3794
4184
|
return `${getVertexOutputStructDefinition(opts)}
|
|
@@ -3825,6 +4215,25 @@ struct Camera {
|
|
|
3825
4215
|
index);
|
|
3826
4216
|
}`;
|
|
3827
4217
|
}
|
|
4218
|
+
/**
|
|
4219
|
+
* Composes the vertex shader for "fat" (screen-space-thickness) line rendering: unlike
|
|
4220
|
+
* {@link getDefaultLineVertexWgsl}, it expects to be invoked with 6 vertices per line segment (a quad split into
|
|
4221
|
+
* two triangles, per the index-to-corner mapping documented in `computeOffsetPosition`'s inline diagram) and
|
|
4222
|
+
* offsets each corner perpendicular to the segment's screen-space direction by half of a uniform pixel width, so
|
|
4223
|
+
* the line renders at a constant on-screen thickness regardless of distance from the camera.
|
|
4224
|
+
*
|
|
4225
|
+
* `computeClipPosition` reads a point's `x`/`y`/`z` out of the flattened `positions: array<f32>` storage buffer
|
|
4226
|
+
* (as in {@link getDefaultLineVertexWgsl}) and transforms it to clip space; `computeOffsetPosition` then derives
|
|
4227
|
+
* the two endpoints' NDC direction, builds a perpendicular offset scaled by `dimensions.halfLineWidth` and the
|
|
4228
|
+
* viewport size, and picks/offsets the correct quad corner based on `vertex_index` (segment endpoint is
|
|
4229
|
+
* `instance_index`/`instance_index + 1`).
|
|
4230
|
+
*
|
|
4231
|
+
* Declares `VertexOutput`/`Transforms`/`Camera`/`Pixels` WGSL structs and binds `transforms`/`camera`/`positions`/`dimensions`
|
|
4232
|
+
* at the configured `@group`/`@binding` coordinates (`dimensions` carries `viewportWidth`, `viewportHeight` and `halfLineWidth` in pixels).
|
|
4233
|
+
*
|
|
4234
|
+
* @param options Location/binding overrides; defaults to {@link DefaultLineVertexOptions}.
|
|
4235
|
+
* @returns Complete WGSL vertex-shader source with a single `@vertex fn main` entry point returning `VertexOutput`.
|
|
4236
|
+
*/
|
|
3828
4237
|
function getFatLineVertexWgsl(options = DefaultLineVertexOptions) {
|
|
3829
4238
|
const opts = pacemCore.Utils.extend({}, DefaultLineVertexOptions, options);
|
|
3830
4239
|
return `${getVertexOutputStructDefinition(opts)}
|
|
@@ -3942,7 +4351,17 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
3942
4351
|
|
|
3943
4352
|
//namespace Pacem.Drawing3D.WebGPU {
|
|
3944
4353
|
/**
|
|
3945
|
-
*
|
|
4354
|
+
* Composes the fragment shader used by the {@link Raycaster} off-screen pass for GPU-based, color-coded object
|
|
4355
|
+
* picking: instead of computing a lit color, it simply outputs the renderable's own numeric `id` (bound as a
|
|
4356
|
+
* `ColorPicker` uniform) into a single-channel `r32uint` render target, so the CPU side can later read back the
|
|
4357
|
+
* pixel under the pointer and resolve it to the {@link Renderable} that was drawn there.
|
|
4358
|
+
*
|
|
4359
|
+
* Declares the `ColorPicker` struct (`id: u32`) and its `var<uniform>` binding at `@binding(0)` within the given
|
|
4360
|
+
* `@group`; unlike the material fragments in this folder it takes no {@link WGSLFragmentExtra} — it is not meant to
|
|
4361
|
+
* be extended with lighting/texture snippets.
|
|
4362
|
+
*
|
|
4363
|
+
* @param groupIndex `@group` index at which the per-renderable `ColorPicker` uniform is bound; defaults to {@link UNIFORM_GROUP_INDEX_COLORPICKING}.
|
|
4364
|
+
* @returns Complete WGSL fragment-shader source with a single `@fragment fn main` entry point returning `@location(0) u32`.
|
|
3946
4365
|
*/
|
|
3947
4366
|
function getColorPickingFragmentWgsl(groupIndex = UNIFORM_GROUP_INDEX_COLORPICKING) {
|
|
3948
4367
|
return `struct ColorPicker {
|
|
@@ -3958,9 +4377,25 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
3958
4377
|
`;
|
|
3959
4378
|
}
|
|
3960
4379
|
|
|
4380
|
+
/** Fallback references used by {@link textureMap} when not overridden: reads UV coordinates from the `uv` varying. */
|
|
3961
4381
|
const DefaultTextureMapReferences = {
|
|
3962
4382
|
uv: 'uv',
|
|
3963
4383
|
};
|
|
4384
|
+
/**
|
|
4385
|
+
* Builds a {@link WGSLFragmentExtra} that samples a 2D texture and tints it by a base color: `textureSample(tex, sampler, uv) * inputColor`.
|
|
4386
|
+
* Declares a fresh `sampler`/`texture_2d<f32>` pair (uniquely named per call via {@link Utils.uniqueCode}) as `bindings`
|
|
4387
|
+
* at consecutive `@binding` indices (`binding` for the sampler, `binding + 1` for the texture) within the given
|
|
4388
|
+
* `@group`, and emits no `definitions`.
|
|
4389
|
+
*
|
|
4390
|
+
* As `modifiers`, either a single bare sample-and-multiply expression (single consumer), or, when
|
|
4391
|
+
* `references.outputColors` lists multiple output variable names, one assignment per name — the first computes the
|
|
4392
|
+
* sample, the rest copy it — so several downstream color channels (e.g. diffuse and ambient) can share one texture fetch.
|
|
4393
|
+
*
|
|
4394
|
+
* @param references WGSL identifiers for the UV coordinates (`uv`, defaults to `'uv'`), the base color to tint (`inputColor`, required) and, optionally, one or more output variable names (`outputColors`) to assign the sampled color to.
|
|
4395
|
+
* @param group `@group` index at which the generated sampler/texture pair is bound.
|
|
4396
|
+
* @param binding `@binding` index (within `group`) for the sampler; the texture is bound at `binding + 1`. Defaults to {@link SAMPLER_BINDING_INDEX}.
|
|
4397
|
+
* @returns Fragment-shader `bindings`/`modifiers` meant to be spliced into a material fragment shader (see {@link getBasicMaterialFragmentWgsl}/{@link getStandardMaterialFragmentWgsl}).
|
|
4398
|
+
*/
|
|
3964
4399
|
function textureMap(references = DefaultTextureMapReferences, group, binding = SAMPLER_BINDING_INDEX) {
|
|
3965
4400
|
const key = pacemCore.Utils.uniqueCode();
|
|
3966
4401
|
const samplerReference = `sampler_${key}`;
|
|
@@ -3984,9 +4419,27 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
3984
4419
|
};
|
|
3985
4420
|
}
|
|
3986
4421
|
|
|
4422
|
+
/** Fallback references used by {@link directionalLight} when not overridden: reads the world-space `normal` varying and treats the base color as `white`. */
|
|
3987
4423
|
const DefaultDirectionalLightReferences = {
|
|
3988
4424
|
normal: 'normal', inputColor: 'white'
|
|
3989
4425
|
};
|
|
4426
|
+
/**
|
|
4427
|
+
* Builds a {@link WGSLFragmentExtra} implementing a directional (sun-like, parallel-rays) light: a Lambertian
|
|
4428
|
+
* diffuse term computed from the dot product between the surface normal and the (negated, normalized) light
|
|
4429
|
+
* direction, modulated by the light's color and intensity. Unlike {@link omniLight}, it carries no position/falloff
|
|
4430
|
+
* or specular term.
|
|
4431
|
+
*
|
|
4432
|
+
* Emits, as `definitions`, a `DirectionalLight` struct (`color: vec4f`, `direction: vec3f`, `intensity: f32`) and a
|
|
4433
|
+
* `computeDirectional` helper function; as `bindings`, a `var<uniform>` declaration for the light data at the given
|
|
4434
|
+
* `@group`/`@binding` coordinates; and, as `modifiers`, either a statement that accumulates the contribution into
|
|
4435
|
+
* `references.outputColor` (`+=`) when provided, or a bare expression otherwise (for single-light use sites that
|
|
4436
|
+
* assign it directly).
|
|
4437
|
+
*
|
|
4438
|
+
* @param references WGSL identifiers for the surface normal (`normal`), the base color to shade (`inputColor`) and, optionally, the color variable to accumulate into (`outputColor`).
|
|
4439
|
+
* @param group `@group` index at which the generated `DirectionalLight` uniform is bound.
|
|
4440
|
+
* @param binding `@binding` index (within `group`) at which the generated `DirectionalLight` uniform is bound.
|
|
4441
|
+
* @returns Fragment-shader `definitions`/`bindings`/`modifiers` meant to be spliced into a material fragment shader (see {@link getBasicMaterialFragmentWgsl}/{@link getStandardMaterialFragmentWgsl}).
|
|
4442
|
+
*/
|
|
3990
4443
|
function directionalLight(references, group, binding) {
|
|
3991
4444
|
const key = pacemCore.Utils.uniqueCode();
|
|
3992
4445
|
const lightReference = `directional_${key}`;
|
|
@@ -4015,9 +4468,27 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
4015
4468
|
};
|
|
4016
4469
|
}
|
|
4017
4470
|
|
|
4471
|
+
/** Fallback references used by {@link omniLight} when not overridden: reads the world-space `normal`/`vertex`/`ray` varyings, treats the base color as `white` and disables the specular term (`empty` color, `0` shininess). */
|
|
4018
4472
|
const DefaultOmniLightReferences = {
|
|
4019
4473
|
normal: 'normal', position: 'vertex', ray: 'ray', inputColor: 'white', specularColor: 'empty', shininess: '0'
|
|
4020
4474
|
};
|
|
4475
|
+
/**
|
|
4476
|
+
* Builds a {@link WGSLFragmentExtra} implementing an omnidirectional (point) light with a Blinn-Phong-like
|
|
4477
|
+
* specular term: a Lambertian diffuse factor from the normal-to-light direction (light position minus surface
|
|
4478
|
+
* position, i.e. no distance falloff), plus a specular highlight from the half-vector between the light direction
|
|
4479
|
+
* and the eye-to-vertex ray, scaled by `shininess`. Unlike {@link directionalLight}, the light has a `position` in
|
|
4480
|
+
* world space rather than a constant direction.
|
|
4481
|
+
*
|
|
4482
|
+
* Emits, as `definitions`, an `OmniLight` struct (`color: vec4f`, `position: vec3f`, `intensity: f32`) and a
|
|
4483
|
+
* `computeOmni` helper function; as `bindings`, a `var<uniform>` declaration for the light data at the given
|
|
4484
|
+
* `@group`/`@binding` coordinates; and, as `modifiers`, either a statement that accumulates the contribution into
|
|
4485
|
+
* `references.outputColor` (`+=`) when provided, or a bare expression otherwise.
|
|
4486
|
+
*
|
|
4487
|
+
* @param references WGSL identifiers for the surface normal (`normal`), world-space position (`position`), eye-to-vertex ray (`ray`), base color (`inputColor`), specular color (`specularColor`), shininess factor (`shininess`) and, optionally, the color variable to accumulate into (`outputColor`).
|
|
4488
|
+
* @param group `@group` index at which the generated `OmniLight` uniform is bound.
|
|
4489
|
+
* @param binding `@binding` index (within `group`) at which the generated `OmniLight` uniform is bound.
|
|
4490
|
+
* @returns Fragment-shader `definitions`/`bindings`/`modifiers` meant to be spliced into a material fragment shader (see {@link getBasicMaterialFragmentWgsl}/{@link getStandardMaterialFragmentWgsl}).
|
|
4491
|
+
*/
|
|
4021
4492
|
function omniLight(references, group, binding) {
|
|
4022
4493
|
const key = pacemCore.Utils.uniqueCode();
|
|
4023
4494
|
const lightReference = `omni_${key}`;
|
|
@@ -4054,6 +4525,20 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
4054
4525
|
};
|
|
4055
4526
|
}
|
|
4056
4527
|
|
|
4528
|
+
/**
|
|
4529
|
+
* Builds a {@link WGSLFragmentExtra} implementing the ambient light contribution to a fragment shader: it multiplies the
|
|
4530
|
+
* fragment's base color by a uniform light color/intensity, uniformly across the surface (no dependency on normal or
|
|
4531
|
+
* view direction, unlike {@link directionalLight}/{@link omniLight}).
|
|
4532
|
+
*
|
|
4533
|
+
* Emits, as `definitions`, an `AmbientLight` struct (`color: vec4f`, `intensity: f32`) and a `computeAmbient` helper
|
|
4534
|
+
* function; as `bindings`, a `var<uniform>` declaration for the light data at the given `@group`/`@binding`
|
|
4535
|
+
* coordinates; and, as `modifiers`, a statement assigning the computed color into `references.outputColor`.
|
|
4536
|
+
*
|
|
4537
|
+
* @param references WGSL identifiers for the color to shade (`inputColor`) and the variable to assign the ambient-lit result to (`outputColor`). Both are required.
|
|
4538
|
+
* @param group `@group` index at which the generated `AmbientLight` uniform is bound.
|
|
4539
|
+
* @param binding `@binding` index (within `group`) at which the generated `AmbientLight` uniform is bound.
|
|
4540
|
+
* @returns Fragment-shader `definitions`/`bindings`/`modifiers` meant to be spliced into a material fragment shader (see {@link getBasicMaterialFragmentWgsl}/{@link getStandardMaterialFragmentWgsl}).
|
|
4541
|
+
*/
|
|
4057
4542
|
function ambientLight(references, group, binding) {
|
|
4058
4543
|
const key = pacemCore.Utils.uniqueCode();
|
|
4059
4544
|
const lightReference = `ambient_${key}`;
|
|
@@ -4080,6 +4565,11 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
4080
4565
|
const Vector3D$3 = pacemNumerical.Geometry.LinearAlgebra.Vector3D;
|
|
4081
4566
|
const Matrix3D$2 = pacemNumerical.Geometry.LinearAlgebra.Matrix3D;
|
|
4082
4567
|
const DEFAULT_SIZE = { width: 1, height: 1 };
|
|
4568
|
+
/**
|
|
4569
|
+
* Factory that converts a scene-facing {@link Camera3D} (`../../types.ts`) into its WebGPU-side counterpart
|
|
4570
|
+
* ({@link Camera}, `abstractions.ts`): either a {@link PerspectiveCamera} or an {@link OrthographicCamera}, exposing
|
|
4571
|
+
* `view()`/`projection()` matrices consumed when building the camera's uniform buffer (see `renderablebuffer.ts`).
|
|
4572
|
+
*/
|
|
4083
4573
|
class Cameras {
|
|
4084
4574
|
/**
|
|
4085
4575
|
* Creates a new webgpu {@link Camera} given a canonic one.
|
|
@@ -4153,13 +4643,24 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
4153
4643
|
assertNearFarCorrectness(near, far);
|
|
4154
4644
|
return Matrix3D$2.from(2 / (right - left), 0, 0, 0, 0, 2 / (top - bottom), 0, 0, 0, 0, 1 / (near - far), 0, (left + right) / (left - right), (top + bottom) / (bottom - top), near / (near - far), 1);
|
|
4155
4645
|
}
|
|
4646
|
+
/**
|
|
4647
|
+
* WebGPU-side counterpart of an {@link OrthographicCamera3D}: computes the view matrix from `position`/`lookAt`/`up`,
|
|
4648
|
+
* and an orthographic projection matrix from the camera's `left`/`right`/`top`/`bottom`/`near`/`far` planes, scaled
|
|
4649
|
+
* by the eye-to-target distance and (if given) the viewport aspect ratio.
|
|
4650
|
+
*/
|
|
4156
4651
|
class OrthographicCamera {
|
|
4157
4652
|
constructor(_camera) {
|
|
4158
4653
|
this._camera = _camera;
|
|
4159
4654
|
}
|
|
4655
|
+
/** Computes the view matrix for `camera`; see {@link view} for a bound instance-method equivalent. */
|
|
4160
4656
|
static view(camera) {
|
|
4161
4657
|
return view(camera.position, camera.lookAt, camera.up);
|
|
4162
4658
|
}
|
|
4659
|
+
/**
|
|
4660
|
+
* Computes the orthographic projection matrix for `camera`.
|
|
4661
|
+
* @param camera Source orthographic camera.
|
|
4662
|
+
* @param size Viewport size, used to correct the projected frustum for aspect ratio; defaults to a 1:1 viewport.
|
|
4663
|
+
*/
|
|
4163
4664
|
static projection(camera, size = DEFAULT_SIZE) {
|
|
4164
4665
|
const eye = camera.position, target = camera.lookAt;
|
|
4165
4666
|
const z = Vector3D$3.subtract(target, eye);
|
|
@@ -4173,27 +4674,42 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
4173
4674
|
const right = camera.right * w, left = camera.left * w;
|
|
4174
4675
|
return orthographic(left, right, top, bottom, camera.near, camera.far);
|
|
4175
4676
|
}
|
|
4677
|
+
/** Computes the view matrix for the wrapped camera. See {@link Camera.view}. */
|
|
4176
4678
|
view() {
|
|
4177
4679
|
return OrthographicCamera.view(this._camera);
|
|
4178
4680
|
}
|
|
4681
|
+
/** Computes the orthographic projection matrix for the wrapped camera. See {@link Camera.projection}. */
|
|
4179
4682
|
projection(size) {
|
|
4180
4683
|
return OrthographicCamera.projection(this._camera, size);
|
|
4181
4684
|
}
|
|
4182
4685
|
}
|
|
4686
|
+
/**
|
|
4687
|
+
* WebGPU-side counterpart of a {@link PerspectiveCamera3D}: computes the view matrix from `position`/`lookAt`/`up`,
|
|
4688
|
+
* and a perspective projection matrix from the camera's vertical field of view, aspect ratio and near/far clip planes.
|
|
4689
|
+
*/
|
|
4183
4690
|
class PerspectiveCamera {
|
|
4184
4691
|
constructor(_camera) {
|
|
4185
4692
|
this._camera = _camera;
|
|
4186
4693
|
}
|
|
4694
|
+
/** Computes the view matrix for `camera`; see {@link view} for a bound instance-method equivalent. */
|
|
4187
4695
|
static view(camera) {
|
|
4188
4696
|
return view(camera.position, camera.lookAt, camera.up);
|
|
4189
4697
|
}
|
|
4698
|
+
/**
|
|
4699
|
+
* Computes the perspective projection matrix for `camera`, combining its `aspectRatio` with `size`'s
|
|
4700
|
+
* (`size.width / size.height`) to correct for non-square viewports.
|
|
4701
|
+
* @param camera Source perspective camera.
|
|
4702
|
+
* @param size Viewport size, used to correct for aspect ratio; defaults to a 1:1 viewport.
|
|
4703
|
+
*/
|
|
4190
4704
|
static projection(camera, size = DEFAULT_SIZE) {
|
|
4191
4705
|
const aspectRatio = (size.width / size.height) / camera.aspectRatio;
|
|
4192
4706
|
return perspective(camera.fov, aspectRatio, camera.near, camera.far);
|
|
4193
4707
|
}
|
|
4708
|
+
/** Computes the view matrix for the wrapped camera. See {@link Camera.view}. */
|
|
4194
4709
|
view() {
|
|
4195
4710
|
return PerspectiveCamera.view(this._camera);
|
|
4196
4711
|
}
|
|
4712
|
+
/** Computes the perspective projection matrix for the wrapped camera. See {@link Camera.projection}. */
|
|
4197
4713
|
projection(size) {
|
|
4198
4714
|
return PerspectiveCamera.projection(this._camera, size);
|
|
4199
4715
|
}
|
|
@@ -4228,6 +4744,13 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
4228
4744
|
}
|
|
4229
4745
|
throw new Error(`Renderable is not supported.`);
|
|
4230
4746
|
}
|
|
4747
|
+
/**
|
|
4748
|
+
* Drives one render (or raycast) pass over a fixed snapshot of the scene: iterates the meshes accumulated in a
|
|
4749
|
+
* {@link RenderableBufferSet}, invoking a callback for each mesh together with the shared camera and lights, and
|
|
4750
|
+
* seals (clears the stale-property flags of) every buffer that participated in a successful draw. Rebuilt by
|
|
4751
|
+
* `renderer.ts`'s `RendererClass` whenever the scene graph changes (see `update`), and driven once per frame by
|
|
4752
|
+
* `RendererClass.render`/`RendererClass.raycast`.
|
|
4753
|
+
*/
|
|
4231
4754
|
class RenderLooper {
|
|
4232
4755
|
constructor(_set) {
|
|
4233
4756
|
this._set = _set;
|
|
@@ -4236,6 +4759,13 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
4236
4759
|
get items() {
|
|
4237
4760
|
return this._set;
|
|
4238
4761
|
}
|
|
4762
|
+
/**
|
|
4763
|
+
* Invokes `render(mesh, camera, lights)` for every non-disposed mesh buffer in the set, skipping meshes for
|
|
4764
|
+
* which `render` returns `false` (e.g. hidden items). After each successful call, clears the
|
|
4765
|
+
* {@link StalePropertyFlag}s on the mesh buffer and, the first time each occurs, on the shared camera/light
|
|
4766
|
+
* buffers; group buffers are always sealed at the end regardless of whether any mesh rendered.
|
|
4767
|
+
* @param render Callback invoked once per mesh with its buffer, the (single) camera buffer and all light buffers; return `false` to skip that mesh (its flags are left untouched).
|
|
4768
|
+
*/
|
|
4239
4769
|
loop(render) {
|
|
4240
4770
|
const { meshes, cameras, groups, lights } = this._set;
|
|
4241
4771
|
const camera = cameras[0];
|
|
@@ -4266,7 +4796,18 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
4266
4796
|
}
|
|
4267
4797
|
}
|
|
4268
4798
|
}
|
|
4799
|
+
/**
|
|
4800
|
+
* Factory for {@link ManagedBuffer}s wrapping non-{@link Renderable} scene data — geometry ({@link NodeGeometry}/
|
|
4801
|
+
* {@link MeshGeometry}), material ({@link Material3D}) and interaction (pointer/time/viewport) state — so this data
|
|
4802
|
+
* can be shared and cached across the {@link RenderableBuffer}s that reference it (e.g. a geometry instance reused by
|
|
4803
|
+
* several meshes), rather than re-uploaded to the GPU per mesh.
|
|
4804
|
+
*/
|
|
4269
4805
|
class ManagedBuffers {
|
|
4806
|
+
/**
|
|
4807
|
+
* Wraps `item` in the {@link ManagedBuffer} implementation matching its runtime type.
|
|
4808
|
+
* @param item A geometry ({@link NodeGeometry}/{@link MeshGeometry}), material ({@link Material3D}) or {@link Interaction} instance.
|
|
4809
|
+
* @throws {Error} If `item`'s type isn't recognized.
|
|
4810
|
+
*/
|
|
4270
4811
|
static create(item) {
|
|
4271
4812
|
if (isGeometry(item)) {
|
|
4272
4813
|
item.key ??= 'geometry_' + pacemCore.Utils.uniqueCode();
|
|
@@ -4281,10 +4822,28 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
4281
4822
|
throw new Error(`Object is not supported.`);
|
|
4282
4823
|
}
|
|
4283
4824
|
}
|
|
4825
|
+
/**
|
|
4826
|
+
* Factory and stale-flag utilities for {@link RenderableBuffer}s wrapping {@link Renderable} scene items (groups,
|
|
4827
|
+
* meshes, cameras, lights). Callers (see `renderer.ts`'s `RendererClass`) cache one buffer per item across frames, so
|
|
4828
|
+
* the underlying GPU resources persist until the item is removed from the scene.
|
|
4829
|
+
*/
|
|
4284
4830
|
class RenderableBuffers {
|
|
4831
|
+
/**
|
|
4832
|
+
* Wraps `item` in the {@link RenderableBuffer} implementation matching its kind (group/mesh/camera/light),
|
|
4833
|
+
* recursively wrapping a group's children.
|
|
4834
|
+
* @param item The scene renderable to wrap.
|
|
4835
|
+
* @param args Extra constructor arguments forwarded to mesh buffers (the shared geometry/material {@link ManagedBuffer} caches; see `renderer.ts`).
|
|
4836
|
+
* @throws {Error} If `item`'s type isn't recognized.
|
|
4837
|
+
*/
|
|
4285
4838
|
static create(item, ...args) {
|
|
4286
4839
|
return createRenderableBuffer(item, null, ...args);
|
|
4287
4840
|
}
|
|
4841
|
+
/**
|
|
4842
|
+
* Clears the {@link StalePropertyFlag}s on `buffer`'s underlying item, marking it as up to date until the next
|
|
4843
|
+
* scene-graph mutation flags it again.
|
|
4844
|
+
* @param buffer The buffer whose item's flags should be cleared.
|
|
4845
|
+
* @param includeParent Whether to also clear the parent group buffer's flags, recursively up the hierarchy.
|
|
4846
|
+
*/
|
|
4288
4847
|
static clearFlags(buffer, includeParent = false) {
|
|
4289
4848
|
buffer.item.flags.splice(0);
|
|
4290
4849
|
if (includeParent) {
|
|
@@ -4294,6 +4853,11 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
4294
4853
|
}
|
|
4295
4854
|
}
|
|
4296
4855
|
}
|
|
4856
|
+
/**
|
|
4857
|
+
* Returns the union of `buffer`'s own {@link StalePropertyFlag}s with those of all its ancestor group buffers —
|
|
4858
|
+
* the effective set of "what changed" a re-render of this item needs to account for.
|
|
4859
|
+
* @param buffer The buffer to compute the effective flag set for.
|
|
4860
|
+
*/
|
|
4297
4861
|
static allFlags(buffer) {
|
|
4298
4862
|
const bufferBase = buffer;
|
|
4299
4863
|
const parentBufferBase = bufferBase.parent;
|
|
@@ -5046,8 +5610,17 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
5046
5610
|
}
|
|
5047
5611
|
};
|
|
5048
5612
|
const EMPTY_BIND_DELEGATE = (_) => { };
|
|
5613
|
+
/**
|
|
5614
|
+
* Factory for {@link RenderPipeline}s: given a {@link Context} and a set of {@link RenderableBuffer}s (a mesh/line plus its
|
|
5615
|
+
* camera and lights), builds the WGSL shaders, {@link GPUBindGroupLayout}s, {@link GPUPipelineLayout} and the underlying
|
|
5616
|
+
* {@link GPURenderPipeline}(s) needed to draw (and, separately, color-pick/raycast) that combination. Built pipelines are
|
|
5617
|
+
* memoized per {@link Context} and reused as long as the shader "recipe" (mesh material/shader, light count/types, WGSL
|
|
5618
|
+
* modifier version) doesn't change. This is the machinery {@link Pacem3DWebgpuAdapterElement}'s {@link Renderer} implementation
|
|
5619
|
+
* (`renderer.ts`) drives every frame.
|
|
5620
|
+
*/
|
|
5049
5621
|
class RenderPipelines {
|
|
5050
5622
|
static { this._memoizer = new WeakMap(); }
|
|
5623
|
+
/** Clears the {@link RenderPipeline} cache associated with the given {@link Context} (e.g. on device loss/adapter teardown). Does not explicitly destroy the underlying GPU objects — they're released with the {@link GPUDevice}. */
|
|
5051
5624
|
static dispose(ctx) {
|
|
5052
5625
|
const memoizer = this._memoizer;
|
|
5053
5626
|
const cache = memoizer.get(ctx);
|
|
@@ -5056,6 +5629,12 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
5056
5629
|
memoizer.delete(ctx);
|
|
5057
5630
|
}
|
|
5058
5631
|
}
|
|
5632
|
+
/**
|
|
5633
|
+
* Builds (or reuses, via {@link create}'s cache) the render pipeline for `items` and wraps it as a color-picking-only
|
|
5634
|
+
* {@link RenderPipeline}, whose `frame` delegate draws object ids into an `r32uint` target instead of the normal color target.
|
|
5635
|
+
* Returns `null` if the resolved pipeline isn't a mesh or line pipeline (i.e. doesn't support raycasting).
|
|
5636
|
+
* @param items The mesh/line, camera and lights to raycast, in the same shape expected by {@link create}.
|
|
5637
|
+
*/
|
|
5059
5638
|
static createColorPicking(ctx, items) {
|
|
5060
5639
|
const renderPipeline = RenderPipelines.create(ctx, items);
|
|
5061
5640
|
if (renderPipeline instanceof MeshRenderPipelineClass
|
|
@@ -5066,6 +5645,20 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
5066
5645
|
}
|
|
5067
5646
|
return null;
|
|
5068
5647
|
}
|
|
5648
|
+
/**
|
|
5649
|
+
* Builds (or returns the memoized) {@link RenderPipeline} for the given renderables: the first buffer must wrap a
|
|
5650
|
+
* {@link Mesh} (with either a {@link MeshGeometry} or a {@link LineMaterial}), followed by its {@link Camera} buffer
|
|
5651
|
+
* and zero or more {@link Light} buffers. Generates the mesh/line's WGSL vertex and fragment shaders (via
|
|
5652
|
+
* {@link MeshWGSLBuilder}/{@link LineWGSLBuilder}), compiles them into {@link GPUShaderModule}s, creates the
|
|
5653
|
+
* {@link GPUBindGroupLayout}s/{@link GPUPipelineLayout} and the resulting {@link GPURenderPipeline} (plus a matching
|
|
5654
|
+
* color-picking pipeline). The pipeline is cached per {@link Context} keyed by shader "recipe" + WGSL modifiers version,
|
|
5655
|
+
* so repeated calls with an equivalent recipe skip rebuilding.
|
|
5656
|
+
* @param ctx WebGPU context (device/canvas/format) to build the pipeline against.
|
|
5657
|
+
* @param items `[mesh, camera, ...lights]` renderable buffers.
|
|
5658
|
+
* @param pipelineOptions Optional overrides for primitive topology, multisampling, vertex packing and WGSL modifiers.
|
|
5659
|
+
* @returns The built (or cached) {@link RenderPipeline}.
|
|
5660
|
+
* @throws {Error} If no mesh is provided, the mesh's geometry/material combination isn't supported, or the first argument isn't a mesh.
|
|
5661
|
+
*/
|
|
5069
5662
|
static create(ctx, [mesh, camera, ...lights], pipelineOptions) {
|
|
5070
5663
|
const memoizer = RenderPipelines._memoizer;
|
|
5071
5664
|
let cache = memoizer.get(ctx);
|
|
@@ -6206,6 +6799,12 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
6206
6799
|
// #endregion
|
|
6207
6800
|
|
|
6208
6801
|
//namespace Pacem.Drawing3D.WebGPU {
|
|
6802
|
+
/**
|
|
6803
|
+
* Factory/registry for {@link Raycaster}s: builds (or returns the memoized) color-picking {@link Raycaster} for a
|
|
6804
|
+
* given {@link Context}, used by the {@link Renderer}'s `raycast` implementation (`renderer.ts`) to hit-test pointer
|
|
6805
|
+
* clicks/hovers against rendered items. Raycasters are memoized per {@link Context} so their off-screen render
|
|
6806
|
+
* target/readback buffer are reused across calls instead of being reallocated every raycast.
|
|
6807
|
+
*/
|
|
6209
6808
|
class Raycasters {
|
|
6210
6809
|
// learn from:
|
|
6211
6810
|
// https://webglfundamentals.org/webgl/lessons/webgl-qna-how-to-get-the-3d-coordinates-of-a-mouse-click.html
|
|
@@ -6213,6 +6812,7 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
6213
6812
|
// https://shi-yan.github.io/webgpuunleashed/Control/object_picking.html
|
|
6214
6813
|
// https://gist.github.com/greggman/57c3c0d3cf1db14f1baad2d9b0094397 (color picking)
|
|
6215
6814
|
static { this._memoizer = new WeakMap(); }
|
|
6815
|
+
/** Destroys and clears all {@link Raycaster}s memoized for `ctx` (e.g. on device loss/adapter teardown). */
|
|
6216
6816
|
static dispose(ctx) {
|
|
6217
6817
|
const memoizer = this._memoizer;
|
|
6218
6818
|
if (memoizer.has(ctx)) {
|
|
@@ -6397,12 +6997,28 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
6397
6997
|
|
|
6398
6998
|
//namespace Pacem.Drawing3D.WebGPU {
|
|
6399
6999
|
const Vector3D$1 = pacemNumerical.Geometry.LinearAlgebra.Vector3D;
|
|
7000
|
+
/** Reason a WebGPU {@link Renderer} failed to initialize, as reported via a rejected {@link Renderers.create} promise (see {@link WebGPUIssue}). */
|
|
6400
7001
|
var WebGPUIssueCause;
|
|
6401
7002
|
(function (WebGPUIssueCause) {
|
|
7003
|
+
/** `navigator.gpu` is unavailable — the browser/OS doesn't support WebGPU at all. */
|
|
6402
7004
|
WebGPUIssueCause[WebGPUIssueCause["NotSupported"] = 0] = "NotSupported";
|
|
7005
|
+
/** WebGPU is supported, but no {@link GPUAdapter}/{@link GPUDevice} could be obtained (e.g. disabled via flags, denied, or hardware unsupported). */
|
|
6403
7006
|
WebGPUIssueCause[WebGPUIssueCause["Disabled"] = 1] = "Disabled";
|
|
6404
7007
|
})(WebGPUIssueCause || (WebGPUIssueCause = {}));
|
|
7008
|
+
/**
|
|
7009
|
+
* Factory for the WebGPU {@link Renderer} consumed by {@link Pacem3DWebgpuAdapterElement}. Requests a
|
|
7010
|
+
* {@link GPUAdapter}/{@link GPUDevice}, configures the stage canvas's {@link GPUCanvasContext}, and wraps everything
|
|
7011
|
+
* in a {@link Renderer} implementation that owns: the per-frame render/raycast loop (via {@link RenderLooper}), the
|
|
7012
|
+
* mesh/geometry/material buffer caches ({@link RenderableBuffers}/{@link ManagedBuffers}), the multisample/depth
|
|
7013
|
+
* render targets, and pointer hit-testing ({@link Raycasters}).
|
|
7014
|
+
*/
|
|
6405
7015
|
class Renderers {
|
|
7016
|
+
/**
|
|
7017
|
+
* Creates and asynchronously initializes a WebGPU {@link Renderer} for `stage`'s canvas.
|
|
7018
|
+
* @param stage The owning `<pacem-3d>` element whose wrapper hosts the render canvas.
|
|
7019
|
+
* @param config Whether to enable per-frame WebGPU validation error scopes (a perf hog — debug builds only) and optional WGSL shader modifiers.
|
|
7020
|
+
* @returns A promise resolving to the ready {@link Renderer}, or rejecting with a {@link WebGPUIssue} if WebGPU isn't supported or no adapter/device could be obtained.
|
|
7021
|
+
*/
|
|
6406
7022
|
static create(stage, config) {
|
|
6407
7023
|
return new Promise((resolve, reject) => {
|
|
6408
7024
|
if (!navigator.gpu) {
|
|
@@ -6834,11 +7450,13 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
6834
7450
|
const WEBGPU_RAYCAST_CALLBACK_PROP = 'WebGPURaycastCallback';
|
|
6835
7451
|
const WEBGPU_RAYCAST_PIXEL_PROP = 'WebGPURaycastPixel';
|
|
6836
7452
|
const GETVAL = pacemCore.CustomElementUtils.getAttachedPropertyValue, SETVAL = pacemCore.CustomElementUtils.setAttachedPropertyValue, DELVAL = pacemCore.CustomElementUtils.deleteAttachedPropertyValue;
|
|
7453
|
+
/** `<pacem-3d-wgsl-script>`: declares a WGSL snippet (vertex input/output or fragment stage) that a parent {@link Pacem3DWebgpuAdapterElement} splices into its render pipeline shaders, tracked via a content {@link version} hash. */
|
|
6837
7454
|
let Pacem3DWgslScriptElement = class Pacem3DWgslScriptElement extends pacemCore.Components.PacemItemElement {
|
|
6838
7455
|
findContainer() {
|
|
6839
7456
|
return pacemCore.CustomElementUtils.findAncestor(this, n => n instanceof Pacem3DWebgpuAdapterElement);
|
|
6840
7457
|
}
|
|
6841
7458
|
#version = '';
|
|
7459
|
+
/** @readonly Gets a hash of the current {@link wgsl} content, changing whenever it does. */
|
|
6842
7460
|
get version() {
|
|
6843
7461
|
return this.#version;
|
|
6844
7462
|
}
|
|
@@ -6881,6 +7499,12 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
6881
7499
|
Pacem3DWgslScriptElement = __decorate$2([
|
|
6882
7500
|
pacemCore.CustomElement({ tagName: pacemCore.P + '-3d-wgsl-script' })
|
|
6883
7501
|
], Pacem3DWgslScriptElement);
|
|
7502
|
+
/**
|
|
7503
|
+
* `<pacem-3d-webgpu-adapter>`: {@link Pacem3DAdapterElement} rendering backend built directly on the browser's
|
|
7504
|
+
* WebGPU API. Manages one {@link Renderer} per stage it is assigned to, hosts child {@link Pacem3DWgslScriptElement}
|
|
7505
|
+
* shader customizations (via {@link modifiers}), and falls back gracefully (see {@link supported}/{@link active})
|
|
7506
|
+
* when WebGPU isn't available.
|
|
7507
|
+
*/
|
|
6884
7508
|
let Pacem3DWebgpuAdapterElement = class Pacem3DWebgpuAdapterElement extends Pacem3DAdapterElement {
|
|
6885
7509
|
constructor() {
|
|
6886
7510
|
super(...arguments);
|
|
@@ -6902,9 +7526,11 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
6902
7526
|
renderer?.resize(size);
|
|
6903
7527
|
}
|
|
6904
7528
|
#items;
|
|
7529
|
+
/** @readonly Gets the child {@link Pacem3DWgslScriptElement} shader-customization items currently registered. */
|
|
6905
7530
|
get items() {
|
|
6906
7531
|
return this.#items;
|
|
6907
7532
|
}
|
|
7533
|
+
/** Registers a child {@link Pacem3DWgslScriptElement}, re-parsing the WGSL {@link modifiers} it contributes. */
|
|
6908
7534
|
register(item) {
|
|
6909
7535
|
const items = this.#items;
|
|
6910
7536
|
if (item instanceof Pacem3DWgslScriptElement && !items.includes(item)) {
|
|
@@ -6915,6 +7541,7 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
6915
7541
|
}
|
|
6916
7542
|
return false;
|
|
6917
7543
|
}
|
|
7544
|
+
/** Unregisters a previously-registered {@link Pacem3DWgslScriptElement}, re-parsing the WGSL {@link modifiers} accordingly. */
|
|
6918
7545
|
unregister(item) {
|
|
6919
7546
|
const items = this.#items;
|
|
6920
7547
|
const ndx = items.indexOf(item);
|
|
@@ -6930,9 +7557,11 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
6930
7557
|
#renderers;
|
|
6931
7558
|
#supported;
|
|
6932
7559
|
#active;
|
|
7560
|
+
/** @readonly Gets whether WebGPU is supported by the current browser/device. */
|
|
6933
7561
|
get supported() {
|
|
6934
7562
|
return this.#supported;
|
|
6935
7563
|
}
|
|
7564
|
+
/** @readonly Gets whether the adapter is currently able to render (false once a {@link WebGPUIssue} disables it). */
|
|
6936
7565
|
get active() {
|
|
6937
7566
|
return this.#active;
|
|
6938
7567
|
}
|
|
@@ -7395,6 +8024,11 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
7395
8024
|
scene.removeEventListener('render', this._renderHandler, false);
|
|
7396
8025
|
}
|
|
7397
8026
|
}
|
|
8027
|
+
/**
|
|
8028
|
+
* `<pacem-3d-orbit-camera>`: a behavior element that, applied to a {@link Pacem3DCameraElement}, attaches pointer/wheel
|
|
8029
|
+
* driven orbit (rotate/pan/zoom around a target) interaction by instantiating and configuring an
|
|
8030
|
+
* {@link OrbitCameraBehavior} for each decorated element.
|
|
8031
|
+
*/
|
|
7398
8032
|
let PacemOrbitCameraBehaviorElement = class PacemOrbitCameraBehaviorElement extends pacemCore.Behaviors.PacemBehavior {
|
|
7399
8033
|
constructor() {
|
|
7400
8034
|
super(...arguments);
|
|
@@ -7575,7 +8209,12 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
7575
8209
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7576
8210
|
};
|
|
7577
8211
|
//namespace Pacem.Drawing3D {
|
|
8212
|
+
/** Parses the text content of a Wavefront `.obj` file into a {@link MeshGeometry} (vertices, triangle indices, UVs and normals). */
|
|
7578
8213
|
class OBJParser {
|
|
8214
|
+
/**
|
|
8215
|
+
* Parses `v` (vertex), `vt` (texture coordinate), `vn` (normal) and `f` (face) records out of `content`,
|
|
8216
|
+
* triangulating any face with more than 3 vertices (fan triangulation).
|
|
8217
|
+
*/
|
|
7579
8218
|
static parse(content) {
|
|
7580
8219
|
// vertices
|
|
7581
8220
|
const vertices = [];
|
|
@@ -7648,7 +8287,12 @@ fn computeOffsetPosition(p0: vec4f, p1: vec4f, index: u32) -> vec4f {
|
|
|
7648
8287
|
return new MeshGeometry(vertices, positions, uv, normals);
|
|
7649
8288
|
}
|
|
7650
8289
|
}
|
|
8290
|
+
/** Model-file parsing entry point, registered as the `parse3D` markup transformer for converting raw asset text into a {@link NodeGeometry} or {@link Material}. */
|
|
7651
8291
|
class Parser3D {
|
|
8292
|
+
/**
|
|
8293
|
+
* Parses `content` according to `type` into a {@link NodeGeometry} (currently only the `'obj'` Wavefront format,
|
|
8294
|
+
* via {@link OBJParser}) or a {@link Material}. Throws for any other/unsupported `type` (e.g. `'mtl'`, not yet implemented).
|
|
8295
|
+
*/
|
|
7652
8296
|
static parseGeometry(content, type) {
|
|
7653
8297
|
switch (type.toLowerCase()) {
|
|
7654
8298
|
case 'obj':
|