babylonjs-addons 9.26.0 → 9.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1328,6 +1328,432 @@ declare namespace ADDONS {
1328
1328
  export function ToCrowdAgentParams(agentParams: IAgentParametersV2): Partial<any>;
1329
1329
 
1330
1330
 
1331
+ /**
1332
+ * MultiTexture: composes an array of image files into a single TEXTURE_2D_ARRAY that can be
1333
+ * assigned to a material slot like any other texture.
1334
+ *
1335
+ * Lives in @babylonjs/addons (not core) because it is an application-oriented, optional feature
1336
+ * with WebGL2/WebGPU requirements, URL polling, and a non-trivial memory footprint.
1337
+ */
1338
+ /**
1339
+ * Options for creating a MultiTexture.
1340
+ */
1341
+ export interface IMultiTextureOptions {
1342
+ /** Fixed layer resolution. REQUIRED. Positive integer. */
1343
+ width: number;
1344
+ /** Fixed layer resolution. REQUIRED. Positive integer. */
1345
+ height: number;
1346
+ /** Array depth to allocate. Optional positive integer; default: urls.length. Must be \>= urls.length and \<= the engine's texture2DArrayMaxLayerCount (else throw). Required when urls is empty. */
1347
+ maxLayers?: number;
1348
+ /** Default MultiBlendMode.ALPHA_BLEND. */
1349
+ blendMode?: MultiBlendMode;
1350
+ /** Default false. Passed to BABYLON.RawTexture2DArray: mip levels of the LAYER array. On WebGL2 they are consumed by the composite when rttScale less than 1 (trilinear minification); on WebGPU the composite fetches texels exactly, so these mips only affect direct per-layer sampling via `arrayTexture`. The composite RTT itself never has mips (consumed at 1:1 by materials). */
1351
+ generateMipMaps?: boolean;
1352
+ /** Default Texture.TRILINEAR_SAMPLINGMODE. Passed to BABYLON.RawTexture2DArray. On WebGL2 the composite shader reads the layers through this sampler, so it also drives the composite's mag/min filtering; on WebGPU the composite fetches texels exactly (see the class notes), so it only affects direct per-layer sampling via `arrayTexture`. */
1353
+ samplingMode?: number;
1354
+ /** Default false. Passed through to UploadImageToTexture2DArrayLayer. */
1355
+ premultiplyAlpha?: boolean;
1356
+ /** "resize" (default): scale to width×height. "strict": rejects mismatched dims. */
1357
+ fit?: "resize" | "strict";
1358
+ /** Composite RTT resolution = width*rttScale × height*rttScale. Default 1. On WebGL2 values other than 1 produce a filtered (bilinear) rescale of the composite; on WebGPU the composite fetches its texels exactly, so rttScale effectively rescales the render target without filtering. */
1359
+ rttScale?: number;
1360
+ /** Default false. HEAD-polling change detection. */
1361
+ watch?: boolean;
1362
+ /** Default 2000 ms. Only used when watch is true. */
1363
+ pollInterval?: number;
1364
+ /** Fired once after all initial layers have settled (success or failure). */
1365
+ onLoad?: () => void;
1366
+ /** Fired on any async failure (init, updateLayer, poll). Not thrown. */
1367
+ onError?: (message?: string, exception?: any) => void;
1368
+ }
1369
+ /**
1370
+ * Register side effects for MultiTexture.
1371
+ * Registers the core 2D-array image-source extensions for both backends (the WebGL2
1372
+ * `engine.texture2DArrayImageSource` and its WebGPU counterpart) lazily at first use, matching
1373
+ * the Atmosphere addon's convention. Safe to call multiple times; only the first call has an effect.
1374
+ */
1375
+ export function RegisterMultiTexture(): void;
1376
+ /**
1377
+ * Composes an array of image files into a single TEXTURE_2D_ARRAY and blends the layers per pixel
1378
+ * according to a selectable {@link MultiBlendMode}. The blended result is written to a render-target
1379
+ * texture that can be assigned to materials like any other texture.
1380
+ *
1381
+ * Requires a WebGL2 or WebGPU engine (TEXTURE_2D_ARRAY + sampler2DArray). The constructor throws
1382
+ * synchronously on WebGL1.
1383
+ *
1384
+ * Supported source formats are the raster formats your browser can decode with createImageBitmap
1385
+ * (PNG, JPEG, WebP, AVIF, GIF first frame, BMP). Compressed/container formats such as KTX2 are NOT
1386
+ * supported: the existing KTX2 transcode path goes straight to the GPU (which would bypass the
1387
+ * CPU pixel cache this class maintains), and KTX2 containers hold the whole array in a single file
1388
+ * (which conflicts with the one-file-per-layer-index update model).
1389
+ *
1390
+ * Notes:
1391
+ * - `url` is null (the base texture loader is not used); the `urls` property is the source of truth.
1392
+ * - By default every decoded layer is read back into a CPU `Uint8ClampedArray` (see `pixels`). This
1393
+ * costs one canvas readback (and a full-width×height RGBA CPU copy) per (re)load of a layer — it
1394
+ * runs on every initial load, `updateLayerAsync` reload, and watch-triggered reload, so frequent
1395
+ * reloads or large layers carry a CPU/memory cost (roughly `width × height × 4` bytes per layer).
1396
+ * - With `premultiplyAlpha: true` the GPU layers are stored premultiplied, but the CPU `pixels`
1397
+ * cache still holds the raw decoded (non-premultiplied) bytes.
1398
+ * - The default ALPHA_BLEND mode composites the layers with standard source-over blending: each
1399
+ * layer is drawn over the accumulated result, so later layers cover earlier ones and a fully
1400
+ * opaque layer hides everything below it. With straight-alpha layers (premultiplyAlpha: false)
1401
+ * the fold is the source-over `over` operator (`outA = layer.a + outA * (1 - layer.a)`); with
1402
+ * the premultiplied form (`out = layer + out * (1 - layer.a)`). The composite always outputs
1403
+ * straight RGBA, so materials see identical pixels regardless of `premultiplyAlpha` (which
1404
+ * only controls the layer storage/fold).
1405
+ * - ALPHA_MAX picks the sample with the highest alpha; ties (equal alpha) resolve to the highest
1406
+ * layer index (last input draws over earlier ones).
1407
+ * - With zero active layers, ALPHA_BLEND/ALPHA_MAX/ADD/SUBTRACT/SCREEN output transparent black
1408
+ * and MULTIPLY outputs white (empty-product identity).
1409
+ * - Compositing is performed independently of the scene render loop: MultiTexture re-composites
1410
+ * its internal render target explicitly after every mutation (layer add/insert/remove/update,
1411
+ * blend-mode change, array growth), so `scene.proceduralTexturesEnabled` has no effect on it.
1412
+ * - How the composite samples the layer array depends on the engine backend, but both are
1413
+ * filtered and honour `samplingMode`. On WebGL2 the GLSL composite shader reads the layers
1414
+ * through the array sampler (`texture(...)`), so `samplingMode` affects the output, `rttScale`
1415
+ * other than 1 produces a filtered bilinear rescale, and (with `generateMipMaps: true`)
1416
+ * trilinear minification can use the layer mips. On WebGPU the WGSL composite shader samples
1417
+ * the layer array through its sampler at mip 0 (`textureSampleLevel(..., 0.0)`), so `samplingMode`
1418
+ * affects the output but only mip-0 filtering applies (no mip-level selection) and `rttScale`
1419
+ * rescale is filtered at mip 0. The `_arrayTexture` sampler that materials use to read the
1420
+ * per-layer array is unaffected by this backend difference.
1421
+ * - `MultiTexture` lives in `@babylonjs/addons` and lazily registers the core 2D-array
1422
+ * image-source extensions on first construction, matching the `Atmosphere` addon's convention.
1423
+ * No engine mutation occurs at addons import time. `RegisterMultiTexture()` calls both the WebGL2
1424
+ * (`engine.texture2DArrayImageSource`) and WebGPU pure registration functions, so a pure/tree-shaken
1425
+ * WebGPU build receives `updateTextureArrayLayerFromImageSource` without any extra consumer import.
1426
+ * - The allocated array depth (options.maxLayers ?? urls.length) must be a positive integer and no
1427
+ * larger than the device limit getCaps().texture2DArrayMaxLayerCount. Empty urls are only accepted
1428
+ * together with an explicit options.maxLayers. addLayerAsync/insertLayerAsync double the depth when it is
1429
+ * full and throw a RangeError if the doubled depth would exceed that limit.
1430
+ */
1431
+ export class MultiTexture extends BABYLON.BaseTexture {
1432
+ /**
1433
+ * The internal BABYLON.ProceduralTexture that composites the layers into the render-target texture
1434
+ * assigned to materials. MultiTexture composes, rather than extends, BABYLON.ProceduralTexture: it
1435
+ * creates this composite with `skipSceneRegistration: true` so the scene render loop does not
1436
+ * drive it, and calls {@link _renderComposite} explicitly after each mutation. All texture
1437
+ * surface methods (isReady/getInternalTexture) forward to it.
1438
+ */
1439
+ get composite(): BABYLON.ProceduralTexture;
1440
+ private _compositeInternal;
1441
+ /** Fired once after all initial layers have settled (success or failure). */
1442
+ readonly onLoadObservable: BABYLON.Observable<MultiTexture>;
1443
+ private _layers;
1444
+ private _layerCount;
1445
+ private _maxLayers;
1446
+ private _deviceMaxLayerCap;
1447
+ private _blendMode;
1448
+ private _pollTimer;
1449
+ /** True while a _poll() tick is in flight; overlapping interval firings early-return so a slow tick never double-fetches. */
1450
+ private _pollInFlight;
1451
+ private _canvas;
1452
+ private _ctx;
1453
+ private _disposed;
1454
+ private _mtOptions;
1455
+ private _arrayTexture;
1456
+ /** Number of in-flight mip-suppressed operations (init pool + mutations). See _suppressArrayMips. */
1457
+ private _mipSuppressCount;
1458
+ /**
1459
+ * Number of active layers (drives the uLayerCount uniform). Changes only via addLayerAsync/removeLayerAsync.
1460
+ */
1461
+ get layerCount(): number;
1462
+ /**
1463
+ * The underlying TEXTURE_2D_ARRAY, for users who want to sample individual layers directly.
1464
+ */
1465
+ get arrayTexture(): BABYLON.RawTexture2DArray;
1466
+ /**
1467
+ * Forwards to the internal composite: the render-target texture that composites the layers is
1468
+ * owned by the composite, so the material samples it through here.
1469
+ * @returns The composite's internal texture.
1470
+ */
1471
+ getInternalTexture(): BABYLON.Nullable<BABYLON.InternalTexture>;
1472
+ /**
1473
+ * Forwards to the internal composite: ready once the composite's render-target texture is ready.
1474
+ * @returns True if the composite's render-target texture is ready, otherwise false.
1475
+ */
1476
+ isReady(): boolean;
1477
+ /**
1478
+ * Renders the internal composite, applying the current layer uploads and blend mode.
1479
+ * The composite only draws once its effect is compiled (shaders load asynchronously), so the
1480
+ * first render is deferred to the compiled callback instead of drawing a stale/empty target.
1481
+ */
1482
+ private _renderComposite;
1483
+ /**
1484
+ * Forwards to the composite: the composite render-target is what materials sample.
1485
+ * @returns The composite render-target size.
1486
+ */
1487
+ getSize(): BABYLON.ISize;
1488
+ /**
1489
+ * Forwards to the composite: the composite render-target base size is what materials sample.
1490
+ * @returns The composite render-target base size.
1491
+ */
1492
+ getBaseSize(): BABYLON.ISize;
1493
+ /**
1494
+ * Forwards to the composite's sampling mode.
1495
+ * @returns the composite render-target's sampling mode.
1496
+ */
1497
+ get samplingMode(): number;
1498
+ /**
1499
+ * Forwards to the composite, which owns the render-target texture the material binds.
1500
+ * @param samplingMode the new sampling mode
1501
+ * @param generateMipMaps whether to generate mip maps
1502
+ */
1503
+ updateSamplingMode(samplingMode: number, generateMipMaps?: boolean): void;
1504
+ /**
1505
+ * Forwards to the composite's render-target texture.
1506
+ * @param faceIndex defines the face of the texture to read (in case of cube texture)
1507
+ * @param level defines the LOD level of the texture to read (in case of Mip Maps)
1508
+ * @param buffer defines a user defined buffer to fill with data (can be null)
1509
+ * @param flushRenderer true to flush the renderer from the pending commands before reading the pixels
1510
+ * @param noDataConversion false to convert the data to Uint8Array (if texture type is UNSIGNED_BYTE) or to Float32Array (if texture type is anything but UNSIGNED_BYTE). If true, the type of the generated buffer (if buffer==null) will depend on the type of the texture
1511
+ * @param x defines the region x coordinates to start reading from (default to 0)
1512
+ * @param y defines the region y coordinates to start reading from (default to 0)
1513
+ * @param width defines the region width to read from (default to the texture size at level)
1514
+ * @param height defines the region width to read from (default to the texture size at level)
1515
+ * @returns the composite render-target's pixel buffer promise.
1516
+ */
1517
+ readPixels(faceIndex?: number, level?: number, buffer?: BABYLON.Nullable<ArrayBufferView>, flushRenderer?: boolean, noDataConversion?: boolean, x?: number, y?: number, width?: number, height?: number): BABYLON.Nullable<Promise<ArrayBufferView>>;
1518
+ /**
1519
+ * Forwards to the composite's render-target texture.
1520
+ * @param faceIndex defines the face of the texture to read (in case of cube texture)
1521
+ * @param level defines the LOD level of the texture to read (in case of Mip Maps)
1522
+ * @param buffer defines a user defined buffer to fill with data (can be null)
1523
+ * @param flushRenderer true to flush the renderer from the pending commands before reading the pixels
1524
+ * @param noDataConversion false to convert the data to Uint8Array (if texture type is UNSIGNED_BYTE) or to Float32Array (if texture type is anything but UNSIGNED_BYTE). If true, the type of the generated buffer (if buffer==null) will depend on the type of the texture
1525
+ * @returns the composite render-target's pixel buffer.
1526
+ */
1527
+ _readPixelsSync(faceIndex?: number, level?: number, buffer?: BABYLON.Nullable<ArrayBufferView>, flushRenderer?: boolean, noDataConversion?: boolean): BABYLON.Nullable<ArrayBufferView>;
1528
+ /**
1529
+ * Forwards to the composite render-target's format.
1530
+ * @returns the composite render-target's internal format.
1531
+ */
1532
+ get textureFormat(): number;
1533
+ /**
1534
+ * Forwards to the composite render-target's type.
1535
+ * @returns the composite render-target's internal type.
1536
+ */
1537
+ get textureType(): number;
1538
+ /**
1539
+ * The input URLs, in layer order. Updated by addLayerAsync/insertLayerAsync/removeLayerAsync/updateLayerAsync.
1540
+ */
1541
+ readonly urls: string[];
1542
+ /**
1543
+ * CPU pixel cache. `pixels[i]` is a full `width × height × 4` RGBA (non-premultiplied) copy of
1544
+ * decoded layer i, or `null` if that layer has not loaded (yet) or failed to load. It is
1545
+ * repopulated on every (re)load of a layer (initial load, `updateLayerAsync`, watch reload) and
1546
+ * cleared on dispose. Memory footprint is approximately `width × height × 4` bytes per loaded
1547
+ * layer; skip it if you only need the GPU composite and do not read `pixels`.
1548
+ */
1549
+ readonly pixels: Array<Uint8ClampedArray | null>;
1550
+ /**
1551
+ * Creates a new MultiTexture.
1552
+ * @param name defines the name of the texture
1553
+ * @param urls defines the array of image URLs to load as layers
1554
+ * @param scene defines the hosting scene
1555
+ * @param options defines the creation options (width/height required)
1556
+ */
1557
+ constructor(name: string, urls: string[], scene: BABYLON.Scene, options: IMultiTextureOptions);
1558
+ /**
1559
+ * How the layers combine. Setting it swaps the composite fragment shader and triggers one
1560
+ * re-composite.
1561
+ */
1562
+ get blendMode(): MultiBlendMode;
1563
+ set blendMode(value: MultiBlendMode);
1564
+ /**
1565
+ * Replaces a layer by URL. Fetches, decodes and uploads layer i only.
1566
+ * Exactly one texSubImage3D is issued for the target layer; uLayerCount is unchanged.
1567
+ * @param index defines the layer index to replace
1568
+ * @param url defines the new source for the layer
1569
+ * @returns a promise resolving once the layer has been uploaded
1570
+ */
1571
+ updateLayerAsync(index: number, url: string): Promise<void>;
1572
+ /**
1573
+ * Appends a new layer at the end and returns its index. Grows the underlying array (doubling its
1574
+ * depth and re-uploading the existing layers from their retained bitmaps) when the current depth
1575
+ * is exhausted. Throws a RangeError if the doubled depth would exceed the device's
1576
+ * texture2DArrayMaxLayerCount.
1577
+ * @param url defines the URL of the image to load as the new layer
1578
+ * @returns a promise resolving to the index of the new layer
1579
+ */
1580
+ addLayerAsync(url: string): Promise<number>;
1581
+ /**
1582
+ * Inserts a new layer at the given index and returns it. Layers at index and above shift up by
1583
+ * one: loaded layers are re-uploaded from their retained bitmaps, and a shifted layer that is
1584
+ * still loading lands in its new slot when its in-flight load settles (loads resolve against
1585
+ * their layer entry, never against a stale index). uLayerCount is incremented. Inserting at
1586
+ * `layerCount` appends (addLayerAsync-equivalent). Grows the underlying array (doubling its depth)
1587
+ * when the current depth is exhausted, same as addLayerAsync, and throws a RangeError if the doubled
1588
+ * depth would exceed the device's texture2DArrayMaxLayerCount.
1589
+ * @param index defines the layer index to insert at (0..layerCount, inclusive)
1590
+ * @param url defines the URL of the image to load as the new layer
1591
+ * @returns a promise resolving to the index of the inserted layer
1592
+ */
1593
+ insertLayerAsync(index: number, url: string): Promise<number>;
1594
+ /**
1595
+ * Removes a layer. Higher indices shift down (re-uploaded from their retained bitmaps) and
1596
+ * uLayerCount is decremented.
1597
+ * @param index defines the layer index to remove
1598
+ * @returns a promise resolving once the shift is done
1599
+ */
1600
+ removeLayerAsync(index: number): Promise<void>;
1601
+ /**
1602
+ * Disposes the texture: stops the watch poller, closes every retained bitmap, disposes the layer
1603
+ * array and releases the composite render target through the standard procedural-texture path.
1604
+ */
1605
+ dispose(): void;
1606
+ /**
1607
+ * Clones the texture: builds a fresh MultiTexture in the same scene with the same name, the
1608
+ * current layer urls and the resolved options (layer resolution, current array capacity,
1609
+ * current blend mode, sampling mode, mipmap generation, RTT scale, fit and watch settings).
1610
+ * The clone re-fetches and re-decodes its layers from scratch; it never shares the 2D array
1611
+ * texture, the pixel cache or the load callbacks (onLoad/onError are not inherited).
1612
+ * @returns the cloned texture
1613
+ */
1614
+ clone(): MultiTexture;
1615
+ /**
1616
+ * MultiTexture is intentionally not scene-serializable: the scene loader has no parser for it,
1617
+ * so the payload produced by the inherited base serialization could never be reconstructed
1618
+ * (urls, capacity, blend mode and watch options have no serialized fields). Fails explicitly
1619
+ * instead of returning a misleading JSON object.
1620
+ * @param _allowEmptyName accepted for signature compatibility; ignored
1621
+ * @throws Error always
1622
+ */
1623
+ serialize(_allowEmptyName?: boolean): never;
1624
+ private _buildDefines;
1625
+ private _bitmapOptions;
1626
+ private _reportError;
1627
+ private _createLayerEntry;
1628
+ private _loadEntryOrThrow;
1629
+ private _loadEntryAndReport;
1630
+ private _warnWatchFailure;
1631
+ private _uploadToLayer;
1632
+ private _reuploadSlot;
1633
+ private _clearLayerSlot;
1634
+ private _loadEntry;
1635
+ private _uploadBitmap;
1636
+ private _initialize;
1637
+ private _pushLayerEntry;
1638
+ private _growArray;
1639
+ private _suppressArrayMips;
1640
+ private _generateArrayMips;
1641
+ private _startPolling;
1642
+ private _poll;
1643
+ }
1644
+ /**
1645
+ * Blend modes controlling how the layers of a MultiTexture are combined per pixel.
1646
+ */
1647
+ export enum MultiBlendMode {
1648
+ /**
1649
+ * Default. Composites the layers with standard source-over alpha blending: each layer is drawn
1650
+ * over the accumulated result, so later layers cover earlier ones and a fully opaque layer
1651
+ * (a = 1) completely hides everything below it. With straight-alpha layers (premultiplyAlpha:
1652
+ * false) the fold is `outA = layer.a + outA * (1 - layer.a)`; with premultiplied layers it is
1653
+ * the premultiplied form `out = layer + out * (1 - layer.a)`. The composite always outputs
1654
+ * straight RGBA, so materials see identical pixels regardless of `premultiplyAlpha` (which
1655
+ * only controls the layer storage/fold). Zero active layers output transparent black.
1656
+ */
1657
+ ALPHA_BLEND = 0,
1658
+ /** Keeps the sample with the highest alpha among the layers (ties: highest index wins). Zero active layers output transparent black. */
1659
+ ALPHA_MAX = 1,
1660
+ /** Adds all layers per channel, clamped to 1. */
1661
+ ADD = 2,
1662
+ /** Multiplies all layers per channel (empty product is 1). */
1663
+ MULTIPLY = 3,
1664
+ /** Starts from layer 0 and subtracts every following layer, clamped to 0. */
1665
+ SUBTRACT = 4,
1666
+ /** Screens all layers per channel. */
1667
+ SCREEN = 5
1668
+ }
1669
+
1670
+
1671
+
1672
+
1673
+ /** @internal */
1674
+ export var multiTextureCompositeSubtractPixelShaderWGSL: {
1675
+ name: string;
1676
+ shader: string;
1677
+ };
1678
+
1679
+
1680
+ /** @internal */
1681
+ export var multiTextureCompositeScreenPixelShaderWGSL: {
1682
+ name: string;
1683
+ shader: string;
1684
+ };
1685
+
1686
+
1687
+ /** @internal */
1688
+ export var multiTextureCompositeMultiplyPixelShaderWGSL: {
1689
+ name: string;
1690
+ shader: string;
1691
+ };
1692
+
1693
+
1694
+ /** @internal */
1695
+ export var multiTextureCompositeAlphaMaxPixelShaderWGSL: {
1696
+ name: string;
1697
+ shader: string;
1698
+ };
1699
+
1700
+
1701
+ /** @internal */
1702
+ export var multiTextureCompositeAlphaBlendPixelShaderWGSL: {
1703
+ name: string;
1704
+ shader: string;
1705
+ };
1706
+
1707
+
1708
+ /** @internal */
1709
+ export var multiTextureCompositeAddPixelShaderWGSL: {
1710
+ name: string;
1711
+ shader: string;
1712
+ };
1713
+
1714
+
1715
+ /** @internal */
1716
+ export var multiTextureCompositeSubtractPixelShader: {
1717
+ name: string;
1718
+ shader: string;
1719
+ };
1720
+
1721
+
1722
+ /** @internal */
1723
+ export var multiTextureCompositeScreenPixelShader: {
1724
+ name: string;
1725
+ shader: string;
1726
+ };
1727
+
1728
+
1729
+ /** @internal */
1730
+ export var multiTextureCompositeMultiplyPixelShader: {
1731
+ name: string;
1732
+ shader: string;
1733
+ };
1734
+
1735
+
1736
+ /** @internal */
1737
+ export var multiTextureCompositeAlphaMaxPixelShader: {
1738
+ name: string;
1739
+ shader: string;
1740
+ };
1741
+
1742
+
1743
+ /** @internal */
1744
+ export var multiTextureCompositeAlphaBlendPixelShader: {
1745
+ name: string;
1746
+ shader: string;
1747
+ };
1748
+
1749
+
1750
+ /** @internal */
1751
+ export var multiTextureCompositeAddPixelShader: {
1752
+ name: string;
1753
+ shader: string;
1754
+ };
1755
+
1756
+
1331
1757
  /**
1332
1758
  * Abstract Node class from Babylon.js
1333
1759
  */