storysplat-viewer 0.2.1 → 0.2.2
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/esm/index.js
CHANGED
|
@@ -76232,805 +76232,228 @@ WebGPUEngine._GlslangDefaultOptions = {
|
|
|
76232
76232
|
WebGPUEngine._InstanceId = 0;
|
|
76233
76233
|
|
|
76234
76234
|
/**
|
|
76235
|
-
*
|
|
76236
|
-
* Note: User agent sniffing is generally unreliable; consider feature detection instead if possible.
|
|
76237
|
-
* This function might return false positives or negatives.
|
|
76238
|
-
* @returns True if the user agent string matches common mobile patterns, false otherwise.
|
|
76239
|
-
*/
|
|
76240
|
-
const isMobileDevice = () => {
|
|
76241
|
-
if (typeof navigator === 'undefined' || !navigator.userAgent) {
|
|
76242
|
-
return false; // Cannot determine without navigator.userAgent
|
|
76243
|
-
}
|
|
76244
|
-
return /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase());
|
|
76245
|
-
};
|
|
76246
|
-
/**
|
|
76247
|
-
* Converts a simple {r, g, b, a} object to a BabylonJS Color4 object.
|
|
76248
|
-
* Handles potential undefined input. Alpha defaults to 1 if not provided.
|
|
76249
|
-
* @param colorObj - The color object { r, g, b, a? } (values 0-1).
|
|
76250
|
-
* @param defaultColor - The default Color4 to return if input is invalid.
|
|
76251
|
-
* @returns A BabylonJS Color4 object.
|
|
76252
|
-
*/
|
|
76253
|
-
const toColor4 = (colorObj, defaultColor = new Color4(1, 1, 1, 1) // Default to opaque white
|
|
76254
|
-
) => {
|
|
76255
|
-
if (colorObj && typeof colorObj.r === 'number' && typeof colorObj.g === 'number' && typeof colorObj.b === 'number') {
|
|
76256
|
-
const alpha = typeof colorObj.a === 'number' ? colorObj.a : 1.0;
|
|
76257
|
-
return new Color4(colorObj.r, colorObj.g, colorObj.b, alpha);
|
|
76258
|
-
}
|
|
76259
|
-
return defaultColor;
|
|
76260
|
-
};
|
|
76261
|
-
/**
|
|
76262
|
-
* Converts a simple {x, y, z} object to a BabylonJS Vector3 object.
|
|
76263
|
-
* Handles potential undefined input.
|
|
76264
|
-
* @param vecObj - The vector object { x, y, z }.
|
|
76265
|
-
* @param defaultVector - The default Vector3 to return if input is invalid.
|
|
76266
|
-
* @returns A BabylonJS Vector3 object.
|
|
76267
|
-
*/
|
|
76268
|
-
const toVector3 = (vecObj, defaultVector = new Vector3(0, 0, 0) // Default to origin
|
|
76269
|
-
) => {
|
|
76270
|
-
if (vecObj && typeof vecObj.x === 'number' && typeof vecObj.y === 'number' && typeof vecObj.z === 'number') {
|
|
76271
|
-
return new Vector3(vecObj.x, vecObj.y, vecObj.z);
|
|
76272
|
-
}
|
|
76273
|
-
return defaultVector;
|
|
76274
|
-
};
|
|
76275
|
-
/**
|
|
76276
|
-
* Converts a simple {_x, _y, _z, _w} object to a BabylonJS Quaternion object.
|
|
76277
|
-
* Handles potential undefined input.
|
|
76278
|
-
* @param quatObj - The quaternion object { _x, _y, _z, _w }.
|
|
76279
|
-
* @param defaultQuaternion - The default Quaternion to return if input is invalid.
|
|
76280
|
-
* @returns A BabylonJS Quaternion object.
|
|
76235
|
+
* Class used to store geometry data (vertex buffers + index buffer)
|
|
76281
76236
|
*/
|
|
76282
|
-
|
|
76283
|
-
|
|
76284
|
-
|
|
76285
|
-
|
|
76237
|
+
class Geometry {
|
|
76238
|
+
/**
|
|
76239
|
+
* Gets or sets the Bias Vector to apply on the bounding elements (box/sphere), the max extend is computed as v += v * bias.x + bias.y, the min is computed as v -= v * bias.x + bias.y
|
|
76240
|
+
*/
|
|
76241
|
+
get boundingBias() {
|
|
76242
|
+
return this._boundingBias;
|
|
76286
76243
|
}
|
|
76287
|
-
|
|
76288
|
-
|
|
76289
|
-
|
|
76290
|
-
|
|
76291
|
-
|
|
76292
|
-
|
|
76293
|
-
|
|
76294
|
-
|
|
76295
|
-
|
|
76296
|
-
|
|
76297
|
-
)
|
|
76298
|
-
if (!hex) {
|
|
76299
|
-
return defaultColor;
|
|
76244
|
+
/**
|
|
76245
|
+
* Gets or sets the Bias Vector to apply on the bounding elements (box/sphere), the max extend is computed as v += v * bias.x + bias.y, the min is computed as v -= v * bias.x + bias.y
|
|
76246
|
+
*/
|
|
76247
|
+
set boundingBias(value) {
|
|
76248
|
+
if (this._boundingBias) {
|
|
76249
|
+
this._boundingBias.copyFrom(value);
|
|
76250
|
+
}
|
|
76251
|
+
else {
|
|
76252
|
+
this._boundingBias = value.clone();
|
|
76253
|
+
}
|
|
76254
|
+
this._updateBoundingInfo(true, null);
|
|
76300
76255
|
}
|
|
76301
|
-
|
|
76302
|
-
|
|
76256
|
+
/**
|
|
76257
|
+
* Static function used to attach a new empty geometry to a mesh
|
|
76258
|
+
* @param mesh defines the mesh to attach the geometry to
|
|
76259
|
+
* @returns the new Geometry
|
|
76260
|
+
*/
|
|
76261
|
+
static CreateGeometryForMesh(mesh) {
|
|
76262
|
+
const geometry = new Geometry(Geometry.RandomId(), mesh.getScene());
|
|
76263
|
+
geometry.applyToMesh(mesh);
|
|
76264
|
+
return geometry;
|
|
76303
76265
|
}
|
|
76304
|
-
|
|
76305
|
-
|
|
76306
|
-
return
|
|
76266
|
+
/** Get the list of meshes using this geometry */
|
|
76267
|
+
get meshes() {
|
|
76268
|
+
return this._meshes;
|
|
76307
76269
|
}
|
|
76308
|
-
|
|
76309
|
-
|
|
76310
|
-
|
|
76311
|
-
|
|
76312
|
-
|
|
76313
|
-
|
|
76314
|
-
|
|
76315
|
-
|
|
76316
|
-
|
|
76317
|
-
|
|
76318
|
-
|
|
76319
|
-
|
|
76320
|
-
|
|
76321
|
-
|
|
76322
|
-
|
|
76323
|
-
|
|
76324
|
-
|
|
76325
|
-
|
|
76326
|
-
|
|
76327
|
-
|
|
76328
|
-
|
|
76329
|
-
|
|
76330
|
-
|
|
76331
|
-
|
|
76332
|
-
|
|
76333
|
-
|
|
76334
|
-
|
|
76335
|
-
|
|
76336
|
-
|
|
76337
|
-
|
|
76338
|
-
|
|
76270
|
+
/**
|
|
76271
|
+
* Creates a new geometry
|
|
76272
|
+
* @param id defines the unique ID
|
|
76273
|
+
* @param scene defines the hosting scene
|
|
76274
|
+
* @param vertexData defines the VertexData used to get geometry data
|
|
76275
|
+
* @param updatable defines if geometry must be updatable (false by default)
|
|
76276
|
+
* @param mesh defines the mesh that will be associated with the geometry
|
|
76277
|
+
*/
|
|
76278
|
+
constructor(id, scene, vertexData, updatable = false, mesh = null) {
|
|
76279
|
+
/**
|
|
76280
|
+
* Gets the delay loading state of the geometry (none by default which means not delayed)
|
|
76281
|
+
*/
|
|
76282
|
+
this.delayLoadState = 0;
|
|
76283
|
+
this._totalVertices = 0;
|
|
76284
|
+
this._isDisposed = false;
|
|
76285
|
+
this._extend = {
|
|
76286
|
+
minimum: new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE),
|
|
76287
|
+
maximum: new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE),
|
|
76288
|
+
};
|
|
76289
|
+
this._indexBufferIsUpdatable = false;
|
|
76290
|
+
this._positionsCache = [];
|
|
76291
|
+
/** @internal */
|
|
76292
|
+
this._parentContainer = null;
|
|
76293
|
+
/**
|
|
76294
|
+
* If set to true (false by default), the bounding info applied to the meshes sharing this geometry will be the bounding info defined at the class level
|
|
76295
|
+
* and won't be computed based on the vertex positions (which is what we get when useBoundingInfoFromGeometry = false)
|
|
76296
|
+
*/
|
|
76297
|
+
this.useBoundingInfoFromGeometry = false;
|
|
76298
|
+
this._scene = scene || EngineStore.LastCreatedScene;
|
|
76299
|
+
if (!this._scene) {
|
|
76300
|
+
return;
|
|
76339
76301
|
}
|
|
76340
|
-
|
|
76341
|
-
|
|
76342
|
-
|
|
76343
|
-
|
|
76344
|
-
|
|
76345
|
-
|
|
76346
|
-
|
|
76347
|
-
|
|
76348
|
-
|
|
76349
|
-
|
|
76350
|
-
|
|
76351
|
-
|
|
76352
|
-
/**
|
|
76353
|
-
* Initializes the BabylonJS Engine and Scene.
|
|
76354
|
-
* Attempts to use WebGPU first, falling back to WebGL2.
|
|
76355
|
-
* @param canvas - The HTML canvas element to render to.
|
|
76356
|
-
* @param data - The StorySplat data containing scene properties.
|
|
76357
|
-
* @param options - Viewer configuration options.
|
|
76358
|
-
* @returns A promise resolving with the initialized engine and scene, or rejecting on failure.
|
|
76359
|
-
*/
|
|
76360
|
-
async function initializeSceneAndEngine(canvas, data, options // Allow passing disableWebGPU internally
|
|
76361
|
-
) {
|
|
76362
|
-
var _a;
|
|
76363
|
-
// Ensure canvas fills its container
|
|
76364
|
-
canvas.style.width = '100%';
|
|
76365
|
-
canvas.style.height = '100%';
|
|
76366
|
-
canvas.style.display = 'block';
|
|
76367
|
-
canvas.style.verticalAlign = 'bottom'; // Prevent extra space below canvas
|
|
76368
|
-
let engine;
|
|
76369
|
-
const disableWebGPU = (_a = options === null || options === void 0 ? void 0 : options.disableWebGPU) !== null && _a !== void 0 ? _a : false;
|
|
76370
|
-
if (disableWebGPU) {
|
|
76371
|
-
// Force WebGL2
|
|
76372
|
-
try {
|
|
76373
|
-
engine = new Engine(canvas, true);
|
|
76374
|
-
console.log("StorySplat Viewer: WebGPU disabled by option, using WebGL2.");
|
|
76302
|
+
this.id = id;
|
|
76303
|
+
this.uniqueId = this._scene.getUniqueId();
|
|
76304
|
+
this._engine = this._scene.getEngine();
|
|
76305
|
+
this._meshes = [];
|
|
76306
|
+
//Init vertex buffer cache
|
|
76307
|
+
this._vertexBuffers = {};
|
|
76308
|
+
this._indices = [];
|
|
76309
|
+
this._updatable = updatable;
|
|
76310
|
+
// vertexData
|
|
76311
|
+
if (vertexData) {
|
|
76312
|
+
this.setAllVerticesData(vertexData, updatable);
|
|
76375
76313
|
}
|
|
76376
|
-
|
|
76377
|
-
|
|
76378
|
-
throw new Error("Failed to initialize WebGL2 engine.");
|
|
76314
|
+
else {
|
|
76315
|
+
this._totalVertices = 0;
|
|
76379
76316
|
}
|
|
76380
|
-
|
|
76381
|
-
|
|
76382
|
-
// Try WebGPU first, then fallback
|
|
76383
|
-
try {
|
|
76384
|
-
// Check if running in a secure context, required for WebGPU
|
|
76385
|
-
if (!window.isSecureContext) {
|
|
76386
|
-
throw new Error("WebGPU requires a secure context (HTTPS or localhost).");
|
|
76387
|
-
}
|
|
76388
|
-
if (WebGPUEngine && WebGPUEngine.IsSupportedAsync) {
|
|
76389
|
-
const supported = await WebGPUEngine.IsSupportedAsync;
|
|
76390
|
-
if (supported) {
|
|
76391
|
-
const webgpuEngine = new WebGPUEngine(canvas, {
|
|
76392
|
-
// Explicitly request high-performance adapter
|
|
76393
|
-
powerPreference: "high-performance",
|
|
76394
|
-
// Enable validation in development environments if needed
|
|
76395
|
-
// enableAllFeatures: true // Use cautiously, might impact performance
|
|
76396
|
-
});
|
|
76397
|
-
await webgpuEngine.initAsync();
|
|
76398
|
-
engine = webgpuEngine; // Use double assertion
|
|
76399
|
-
console.log("StorySplat Viewer: WebGPU engine initialized.");
|
|
76400
|
-
}
|
|
76401
|
-
else {
|
|
76402
|
-
throw new Error("WebGPU is not supported on this browser/device.");
|
|
76403
|
-
}
|
|
76404
|
-
}
|
|
76405
|
-
else {
|
|
76406
|
-
throw new Error("WebGPUEngine not available or IsSupportedAsync missing.");
|
|
76407
|
-
}
|
|
76317
|
+
if (this._engine.getCaps().vertexArrayObject) {
|
|
76318
|
+
this._vertexArrayObjects = {};
|
|
76408
76319
|
}
|
|
76409
|
-
|
|
76410
|
-
|
|
76411
|
-
|
|
76412
|
-
|
|
76413
|
-
engine = new Engine(canvas, true, {
|
|
76414
|
-
// Options for WebGL engine if needed
|
|
76415
|
-
// preserveDrawingBuffer: true, // Example option
|
|
76416
|
-
// stencil: true
|
|
76417
|
-
});
|
|
76418
|
-
console.log("StorySplat Viewer: Initialized WebGL2 engine as fallback.");
|
|
76419
|
-
}
|
|
76420
|
-
catch (webglErr) {
|
|
76421
|
-
console.error("StorySplat Viewer: Failed to initialize WebGL2 engine as fallback:", webglErr);
|
|
76422
|
-
throw new Error("Failed to initialize WebGL2 engine as fallback.");
|
|
76423
|
-
}
|
|
76320
|
+
// applyToMesh
|
|
76321
|
+
if (mesh) {
|
|
76322
|
+
this.applyToMesh(mesh);
|
|
76323
|
+
mesh.computeWorldMatrix(true);
|
|
76424
76324
|
}
|
|
76425
76325
|
}
|
|
76426
|
-
|
|
76427
|
-
|
|
76326
|
+
/**
|
|
76327
|
+
* Gets the current extend of the geometry
|
|
76328
|
+
*/
|
|
76329
|
+
get extend() {
|
|
76330
|
+
return this._extend;
|
|
76428
76331
|
}
|
|
76429
|
-
|
|
76430
|
-
|
|
76431
|
-
|
|
76432
|
-
|
|
76433
|
-
|
|
76434
|
-
|
|
76332
|
+
/**
|
|
76333
|
+
* Gets the hosting scene
|
|
76334
|
+
* @returns the hosting Scene
|
|
76335
|
+
*/
|
|
76336
|
+
getScene() {
|
|
76337
|
+
return this._scene;
|
|
76435
76338
|
}
|
|
76436
|
-
|
|
76437
|
-
|
|
76438
|
-
|
|
76439
|
-
|
|
76339
|
+
/**
|
|
76340
|
+
* Gets the hosting engine
|
|
76341
|
+
* @returns the hosting Engine
|
|
76342
|
+
*/
|
|
76343
|
+
getEngine() {
|
|
76344
|
+
return this._engine;
|
|
76440
76345
|
}
|
|
76441
|
-
|
|
76442
|
-
|
|
76346
|
+
/**
|
|
76347
|
+
* Defines if the geometry is ready to use
|
|
76348
|
+
* @returns true if the geometry is ready to be used
|
|
76349
|
+
*/
|
|
76350
|
+
isReady() {
|
|
76351
|
+
return this.delayLoadState === 1 || this.delayLoadState === 0;
|
|
76443
76352
|
}
|
|
76444
|
-
|
|
76445
|
-
|
|
76446
|
-
|
|
76447
|
-
|
|
76448
|
-
|
|
76449
|
-
|
|
76450
|
-
|
|
76451
|
-
|
|
76452
|
-
|
|
76453
|
-
|
|
76454
|
-
scene.onDisposeObservable.addOnce(() => {
|
|
76455
|
-
console.log("StorySplat Viewer: Disposing scene, removing resize listener.");
|
|
76456
|
-
window.removeEventListener("resize", resizeHandler);
|
|
76457
|
-
// Engine disposal is handled separately in the destroy function
|
|
76458
|
-
});
|
|
76459
|
-
return { engine, scene };
|
|
76460
|
-
}
|
|
76461
|
-
|
|
76462
|
-
// Removed import for shared wheelHandler
|
|
76463
|
-
const DEFAULT_CAMERA_POSITION = new Vector3(0, 1.6, -5);
|
|
76464
|
-
const DEFAULT_CAMERA_TARGET = Vector3.Zero();
|
|
76465
|
-
const DEFAULT_FOV = 0.8;
|
|
76466
|
-
const DEFAULT_MIN_Z = 0.1;
|
|
76467
|
-
const DEFAULT_MAX_Z = 1000;
|
|
76468
|
-
const DEFAULT_SPEED = 0.1;
|
|
76469
|
-
const DEFAULT_INERTIA = 0.9;
|
|
76470
|
-
const DEFAULT_ANGULAR_SENSIBILITY = 2000;
|
|
76471
|
-
// Removed DEFAULT_WHEEL_DELTA_PERCENTAGE and DEFAULT_WHEEL_STEP as they are handled by shared handler or options
|
|
76472
|
-
// Walk Mode Defaults
|
|
76473
|
-
const DEFAULT_APPLY_GRAVITY = true;
|
|
76474
|
-
const DEFAULT_ELLIPSOID = new Vector3(0.5, 0.9, 0.5);
|
|
76475
|
-
const DEFAULT_GRAVITY = -9.81;
|
|
76476
|
-
class CameraManager {
|
|
76477
|
-
constructor(canvas, scene, data, options, // Correct options parameter
|
|
76478
|
-
analyticsManager // Correct analyticsManager parameter
|
|
76479
|
-
) {
|
|
76480
|
-
var _a, _b, _c;
|
|
76481
|
-
this._camera = null;
|
|
76482
|
-
this._currentMode = 'explore';
|
|
76483
|
-
this._uiManager = null; // Add UIManager reference
|
|
76484
|
-
this._analyticsManager = null; // Add AnalyticsManager reference
|
|
76485
|
-
this._canvas = canvas;
|
|
76486
|
-
this._scene = scene;
|
|
76487
|
-
this._data = data; // Store data object
|
|
76488
|
-
this._viewerOptions = options;
|
|
76489
|
-
this._analyticsManager = analyticsManager || null; // Store analytics manager
|
|
76490
|
-
// this._uiManager = uiManager || null; // Don't store here initially
|
|
76491
|
-
this._isMobile = isMobileDevice();
|
|
76492
|
-
this._initializeCamera();
|
|
76493
|
-
// Prioritize initial mode from data, then options, then default to 'explore'
|
|
76494
|
-
const initialMode = (_c = (_a = this._data.initialCameraMode) !== null && _a !== void 0 ? _a : (_b = this._viewerOptions) === null || _b === void 0 ? void 0 : _b.defaultCameraMode) !== null && _c !== void 0 ? _c : 'explore';
|
|
76495
|
-
this.setCameraMode(initialMode, true); // Assert type as CameraMode
|
|
76496
|
-
this._setupSceneDispose();
|
|
76497
|
-
// Removed _setupCustomWheelInput call
|
|
76353
|
+
/**
|
|
76354
|
+
* Gets a value indicating that the geometry should not be serialized
|
|
76355
|
+
*/
|
|
76356
|
+
get doNotSerialize() {
|
|
76357
|
+
for (let index = 0; index < this._meshes.length; index++) {
|
|
76358
|
+
if (!this._meshes[index].doNotSerialize) {
|
|
76359
|
+
return false;
|
|
76360
|
+
}
|
|
76361
|
+
}
|
|
76362
|
+
return true;
|
|
76498
76363
|
}
|
|
76499
|
-
|
|
76500
|
-
|
|
76364
|
+
/** @internal */
|
|
76365
|
+
_rebuild() {
|
|
76366
|
+
if (this._vertexArrayObjects) {
|
|
76367
|
+
this._vertexArrayObjects = {};
|
|
76368
|
+
}
|
|
76369
|
+
// Index buffer
|
|
76370
|
+
if (this._meshes.length !== 0 && this._indices) {
|
|
76371
|
+
this._indexBuffer = this._engine.createIndexBuffer(this._indices, this._updatable, "Geometry_" + this.id + "_IndexBuffer");
|
|
76372
|
+
}
|
|
76373
|
+
// Vertex buffers
|
|
76374
|
+
const buffers = new Set();
|
|
76375
|
+
for (const key in this._vertexBuffers) {
|
|
76376
|
+
buffers.add(this._vertexBuffers[key].getWrapperBuffer());
|
|
76377
|
+
}
|
|
76378
|
+
buffers.forEach((buffer) => {
|
|
76379
|
+
buffer._rebuild();
|
|
76380
|
+
});
|
|
76501
76381
|
}
|
|
76502
|
-
|
|
76503
|
-
|
|
76382
|
+
/**
|
|
76383
|
+
* Affects all geometry data in one call
|
|
76384
|
+
* @param vertexData defines the geometry data
|
|
76385
|
+
* @param updatable defines if the geometry must be flagged as updatable (false as default)
|
|
76386
|
+
*/
|
|
76387
|
+
setAllVerticesData(vertexData, updatable) {
|
|
76388
|
+
vertexData.applyToGeometry(this, updatable);
|
|
76389
|
+
this._notifyUpdate();
|
|
76504
76390
|
}
|
|
76505
|
-
|
|
76506
|
-
|
|
76507
|
-
|
|
76508
|
-
|
|
76509
|
-
|
|
76510
|
-
|
|
76511
|
-
|
|
76512
|
-
|
|
76513
|
-
|
|
76391
|
+
/**
|
|
76392
|
+
* Set specific vertex data
|
|
76393
|
+
* @param kind defines the data kind (Position, normal, etc...)
|
|
76394
|
+
* @param data defines the vertex data to use
|
|
76395
|
+
* @param updatable defines if the vertex must be flagged as updatable (false as default)
|
|
76396
|
+
* @param stride defines the stride to use (0 by default). This value is deduced from the kind value if not specified
|
|
76397
|
+
*/
|
|
76398
|
+
setVerticesData(kind, data, updatable = false, stride) {
|
|
76399
|
+
if (updatable && Array.isArray(data)) {
|
|
76400
|
+
// to avoid converting to Float32Array at each draw call in engine.updateDynamicVertexBuffer, we make the conversion a single time here
|
|
76401
|
+
data = new Float32Array(data);
|
|
76514
76402
|
}
|
|
76515
|
-
|
|
76516
|
-
|
|
76517
|
-
|
|
76518
|
-
|
|
76403
|
+
const buffer = new VertexBuffer(this._engine, data, kind, {
|
|
76404
|
+
updatable,
|
|
76405
|
+
postponeInternalCreation: this._meshes.length === 0,
|
|
76406
|
+
stride,
|
|
76407
|
+
label: "Geometry_" + this.id + "_" + kind,
|
|
76408
|
+
});
|
|
76409
|
+
this.setVerticesBuffer(buffer);
|
|
76410
|
+
}
|
|
76411
|
+
/**
|
|
76412
|
+
* Removes a specific vertex data
|
|
76413
|
+
* @param kind defines the data kind (Position, normal, etc...)
|
|
76414
|
+
*/
|
|
76415
|
+
removeVerticesData(kind) {
|
|
76416
|
+
if (this._vertexBuffers[kind]) {
|
|
76417
|
+
this._vertexBuffers[kind].dispose();
|
|
76418
|
+
delete this._vertexBuffers[kind];
|
|
76519
76419
|
}
|
|
76520
|
-
|
|
76521
|
-
this.
|
|
76420
|
+
if (this._vertexArrayObjects) {
|
|
76421
|
+
this._disposeVertexArrayObjects();
|
|
76522
76422
|
}
|
|
76523
|
-
|
|
76524
|
-
|
|
76525
|
-
|
|
76526
|
-
|
|
76527
|
-
|
|
76423
|
+
}
|
|
76424
|
+
/**
|
|
76425
|
+
* Affect a vertex buffer to the geometry. the vertexBuffer.getKind() function is used to determine where to store the data
|
|
76426
|
+
* @param buffer defines the vertex buffer to use
|
|
76427
|
+
* @param totalVertices defines the total number of vertices for position kind (could be null)
|
|
76428
|
+
* @param disposeExistingBuffer disposes the existing buffer, if any (default: true)
|
|
76429
|
+
*/
|
|
76430
|
+
setVerticesBuffer(buffer, totalVertices = null, disposeExistingBuffer = true) {
|
|
76431
|
+
const kind = buffer.getKind();
|
|
76432
|
+
if (this._vertexBuffers[kind] && disposeExistingBuffer) {
|
|
76433
|
+
this._vertexBuffers[kind].dispose();
|
|
76528
76434
|
}
|
|
76529
|
-
|
|
76530
|
-
|
|
76531
|
-
// --- Apply Common Settings ---
|
|
76532
|
-
// Get settings from data (StorySplatData) or options (ViewerOptions)
|
|
76533
|
-
this._camera.fov = (_b = this._data.fov) !== null && _b !== void 0 ? _b : DEFAULT_FOV; // FOV comes from data only
|
|
76534
|
-
this._camera.minZ = (_e = (_d = (_c = this._viewerOptions) === null || _c === void 0 ? void 0 : _c.cameraMinZ) !== null && _d !== void 0 ? _d : this._data.minClipPlane) !== null && _e !== void 0 ? _e : DEFAULT_MIN_Z; // Use minClipPlane from data
|
|
76535
|
-
this._camera.maxZ = (_h = (_g = (_f = this._viewerOptions) === null || _f === void 0 ? void 0 : _f.cameraMaxZ) !== null && _g !== void 0 ? _g : this._data.maxClipPlane) !== null && _h !== void 0 ? _h : DEFAULT_MAX_Z; // Use maxClipPlane from data
|
|
76536
|
-
this._camera.speed = (_l = (_k = (_j = this._viewerOptions) === null || _j === void 0 ? void 0 : _j.cameraSpeed) !== null && _k !== void 0 ? _k : this._data.cameraMovementSpeed) !== null && _l !== void 0 ? _l : DEFAULT_SPEED; // Use cameraMovementSpeed from data
|
|
76537
|
-
this._camera.inertia = (_o = (_m = this._viewerOptions) === null || _m === void 0 ? void 0 : _m.cameraInertia) !== null && _o !== void 0 ? _o : DEFAULT_INERTIA; // Inertia likely only in options
|
|
76538
|
-
// Map cameraRotationSensitivity from data to angularSensibility if options don't provide it
|
|
76539
|
-
const angularSensibility = (_q = (_p = this._viewerOptions) === null || _p === void 0 ? void 0 : _p.cameraAngularSensibility) !== null && _q !== void 0 ? _q : (this._data.cameraRotationSensitivity ? (DEFAULT_ANGULAR_SENSIBILITY / (this._data.cameraRotationSensitivity / 4000)) : DEFAULT_ANGULAR_SENSIBILITY); // Simple scaling based on default
|
|
76540
|
-
this._camera.angularSensibility = angularSensibility;
|
|
76541
|
-
this._camera.touchAngularSensibility = (_s = (_r = this._viewerOptions) === null || _r === void 0 ? void 0 : _r.cameraTouchAngularSensibility) !== null && _s !== void 0 ? _s : angularSensibility; // Use same sensitivity for touch by default
|
|
76542
|
-
// Apply Y-axis inversion by negating sensitivity if needed
|
|
76543
|
-
const shouldInvert = (_v = (_u = (_t = this._viewerOptions) === null || _t === void 0 ? void 0 : _t.invertCameraRotation) !== null && _u !== void 0 ? _u : this._data.invertCameraRotation) !== null && _v !== void 0 ? _v : false;
|
|
76544
|
-
if (shouldInvert) {
|
|
76545
|
-
this._camera.angularSensibility *= -1;
|
|
76546
|
-
this._camera.touchAngularSensibility *= -1;
|
|
76547
|
-
console.log("StorySplat Viewer: Inverting camera Y-axis rotation.");
|
|
76435
|
+
if (buffer._buffer && buffer._ownsBuffer) {
|
|
76436
|
+
buffer._buffer._increaseReferences();
|
|
76548
76437
|
}
|
|
76549
|
-
|
|
76550
|
-
|
|
76551
|
-
|
|
76552
|
-
|
|
76553
|
-
|
|
76554
|
-
|
|
76555
|
-
|
|
76556
|
-
|
|
76557
|
-
|
|
76558
|
-
|
|
76559
|
-
|
|
76560
|
-
|
|
76561
|
-
|
|
76562
|
-
|
|
76563
|
-
|
|
76564
|
-
|
|
76565
|
-
|
|
76566
|
-
this._scene.collisionsEnabled) {
|
|
76567
|
-
this._scene.collisionsEnabled = true;
|
|
76568
|
-
console.log("StorySplat Viewer: Scene collisions enabled for camera.");
|
|
76438
|
+
this._vertexBuffers[kind] = buffer;
|
|
76439
|
+
const meshes = this._meshes;
|
|
76440
|
+
const numOfMeshes = meshes.length;
|
|
76441
|
+
if (kind === VertexBuffer.PositionKind) {
|
|
76442
|
+
this._totalVertices = totalVertices ?? buffer._maxVerticesCount;
|
|
76443
|
+
this._updateExtend(buffer.getFloatData(this._totalVertices));
|
|
76444
|
+
this._resetPointsArrayCache();
|
|
76445
|
+
// this._extend can be empty if buffer.getFloatData(this._totalVertices) returned null
|
|
76446
|
+
const minimum = (this._extend && this._extend.minimum) || new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
|
|
76447
|
+
const maximum = (this._extend && this._extend.maximum) || new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
76448
|
+
for (let index = 0; index < numOfMeshes; index++) {
|
|
76449
|
+
const mesh = meshes[index];
|
|
76450
|
+
mesh.buildBoundingInfo(minimum, maximum);
|
|
76451
|
+
mesh._createGlobalSubMesh(mesh.isUnIndexed);
|
|
76452
|
+
mesh.computeWorldMatrix(true);
|
|
76453
|
+
mesh.synchronizeInstances();
|
|
76454
|
+
}
|
|
76569
76455
|
}
|
|
76570
|
-
|
|
76571
|
-
setCameraMode(mode, immediate = false) {
|
|
76572
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
76573
|
-
if (!this._camera)
|
|
76574
|
-
return;
|
|
76575
|
-
const allowedModes = (_b = (_a = this._viewerOptions) === null || _a === void 0 ? void 0 : _a.allowedCameraModes) !== null && _b !== void 0 ? _b : ['explore', 'walk', 'tour', 'hybrid'];
|
|
76576
|
-
if (!allowedModes.includes(mode)) {
|
|
76577
|
-
console.warn(`StorySplat Viewer: Camera mode "${mode}" is not allowed by options. Allowed: [${allowedModes.join(', ')}]`);
|
|
76578
|
-
return;
|
|
76579
|
-
}
|
|
76580
|
-
const oldMode = this._currentMode;
|
|
76581
|
-
if (oldMode === mode && !immediate)
|
|
76582
|
-
return;
|
|
76583
|
-
console.log(`StorySplat Viewer: Setting camera mode to ${mode}`);
|
|
76584
|
-
this._currentMode = mode;
|
|
76585
|
-
// Detach controls before reconfiguring
|
|
76586
|
-
this._camera.detachControl();
|
|
76587
|
-
// Reset mode-specific properties
|
|
76588
|
-
this._camera.checkCollisions = false;
|
|
76589
|
-
this._camera.applyGravity = false;
|
|
76590
|
-
// Inputs are now added during initialization and persist.
|
|
76591
|
-
// No need to remove/re-add input types here.
|
|
76592
|
-
// detachControl/attachControl handles focus.
|
|
76593
|
-
switch (mode) {
|
|
76594
|
-
case 'explore':
|
|
76595
|
-
this._configureExploreMode();
|
|
76596
|
-
break;
|
|
76597
|
-
case 'walk':
|
|
76598
|
-
this._configureWalkMode();
|
|
76599
|
-
break;
|
|
76600
|
-
case 'tour':
|
|
76601
|
-
case 'hybrid':
|
|
76602
|
-
this._configureTourMode();
|
|
76603
|
-
break;
|
|
76604
|
-
default:
|
|
76605
|
-
console.warn(`StorySplat Viewer: Unknown camera mode "${mode}". Defaulting to explore.`);
|
|
76606
|
-
this._configureExploreMode();
|
|
76607
|
-
this._currentMode = 'explore';
|
|
76608
|
-
}
|
|
76609
|
-
// Re-attach controls if globally enabled
|
|
76610
|
-
if (((_c = this._viewerOptions) === null || _c === void 0 ? void 0 : _c.cameraControls) !== false) {
|
|
76611
|
-
this._camera.attachControl(this._canvas, true);
|
|
76612
|
-
// Removed DEBUG log
|
|
76613
|
-
// Inputs are added during initialization, attachControl manages focus.
|
|
76614
|
-
}
|
|
76615
|
-
else {
|
|
76616
|
-
console.log("StorySplat Viewer: Camera controls globally disabled by options.");
|
|
76617
|
-
// No activation needed if controls are disabled
|
|
76618
|
-
}
|
|
76619
|
-
// Trigger callback and update UI
|
|
76620
|
-
if (oldMode !== mode) {
|
|
76621
|
-
(_e = (_d = this._viewerOptions) === null || _d === void 0 ? void 0 : _d.onCameraModeChanged) === null || _e === void 0 ? void 0 : _e.call(_d, mode);
|
|
76622
|
-
(_f = this.onCameraModeChange) === null || _f === void 0 ? void 0 : _f.call(this, mode); // Call the new callback
|
|
76623
|
-
(_g = this._analyticsManager) === null || _g === void 0 ? void 0 : _g.trackCameraModeChange(oldMode, mode); // Track event
|
|
76624
|
-
this._updateUIManager(); // Notify UI Manager of the change
|
|
76625
|
-
}
|
|
76626
|
-
}
|
|
76627
|
-
_configureExploreMode() {
|
|
76628
|
-
var _a, _b;
|
|
76629
|
-
if (!this._camera)
|
|
76630
|
-
return;
|
|
76631
|
-
this._camera.checkCollisions = (_b = (_a = this._viewerOptions) === null || _a === void 0 ? void 0 : _a.exploreCollisions) !== null && _b !== void 0 ? _b : false;
|
|
76632
|
-
this._camera.applyGravity = false;
|
|
76633
|
-
// Inputs are now managed globally during initialization.
|
|
76634
|
-
// This method only sets mode-specific camera properties.
|
|
76635
|
-
console.log("Explore mode configured: Collisions=" + this._camera.checkCollisions);
|
|
76636
|
-
}
|
|
76637
|
-
_configureWalkMode() {
|
|
76638
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
76639
|
-
if (!this._camera)
|
|
76640
|
-
return;
|
|
76641
|
-
this._camera.checkCollisions = (_b = (_a = this._viewerOptions) === null || _a === void 0 ? void 0 : _a.walkCollisions) !== null && _b !== void 0 ? _b : true;
|
|
76642
|
-
this._camera.applyGravity = (_d = (_c = this._viewerOptions) === null || _c === void 0 ? void 0 : _c.walkApplyGravity) !== null && _d !== void 0 ? _d : DEFAULT_APPLY_GRAVITY;
|
|
76643
|
-
// Gravity primarily from options
|
|
76644
|
-
const sceneGravityY = (_f = (_e = this._viewerOptions) === null || _e === void 0 ? void 0 : _e.gravity) !== null && _f !== void 0 ? _f : DEFAULT_GRAVITY; // Already checks options
|
|
76645
|
-
this._scene.gravity = new Vector3(0, sceneGravityY, 0);
|
|
76646
|
-
// Ellipsoid primarily from options
|
|
76647
|
-
this._camera.ellipsoid = ((_g = this._viewerOptions) === null || _g === void 0 ? void 0 : _g.cameraEllipsoid) ? toVector3(this._viewerOptions.cameraEllipsoid) : DEFAULT_ELLIPSOID.clone(); // Already checks options
|
|
76648
|
-
// Inputs are now managed globally during initialization.
|
|
76649
|
-
// This method only sets mode-specific camera properties.
|
|
76650
|
-
console.log(`Walk mode configured: Gravity=${this._camera.applyGravity}, Collisions=${this._camera.checkCollisions}`);
|
|
76651
|
-
}
|
|
76652
|
-
_configureTourMode() {
|
|
76653
|
-
if (!this._camera)
|
|
76654
|
-
return;
|
|
76655
|
-
this._camera.checkCollisions = false;
|
|
76656
|
-
this._camera.applyGravity = false;
|
|
76657
|
-
// Inputs are now managed globally during initialization.
|
|
76658
|
-
// Mouse/Touch rotation is handled by the default inputs added earlier.
|
|
76659
|
-
// This method only sets mode-specific camera properties.
|
|
76660
|
-
console.log("Tour/Hybrid mode configured: No gravity, no collisions.");
|
|
76661
|
-
}
|
|
76662
|
-
// Helper to set standard keyboard bindings
|
|
76663
|
-
_setKeyboardInputs() {
|
|
76664
|
-
if (!this._camera)
|
|
76665
|
-
return;
|
|
76666
|
-
const input = this._camera.inputs.attached.keyboard; // Use specific type
|
|
76667
|
-
if (input) {
|
|
76668
|
-
// Clear existing potentially conflicting bindings (optional but safer)
|
|
76669
|
-
input.keysUp = [];
|
|
76670
|
-
input.keysDown = [];
|
|
76671
|
-
input.keysLeft = [];
|
|
76672
|
-
input.keysRight = [];
|
|
76673
|
-
input.keysUpward = [];
|
|
76674
|
-
input.keysDownward = [];
|
|
76675
|
-
// Standard WASD / Arrow Keys
|
|
76676
|
-
input.keysUp.push(87, 38); // W, Up Arrow
|
|
76677
|
-
input.keysDown.push(83, 40); // S, Down Arrow
|
|
76678
|
-
input.keysLeft.push(65, 37); // A, Left Arrow
|
|
76679
|
-
input.keysRight.push(68, 39); // D, Right Arrow
|
|
76680
|
-
// Add Q/E for vertical movement
|
|
76681
|
-
input.keysUpward = [69]; // E key for up
|
|
76682
|
-
input.keysDownward = [81]; // Q key for down
|
|
76683
|
-
}
|
|
76684
|
-
}
|
|
76685
|
-
// --- Custom Mouse Wheel Input Handling Removed ---
|
|
76686
|
-
// The default FreeCameraMouseWheelInput is now used.
|
|
76687
|
-
_setupSceneDispose() {
|
|
76688
|
-
this._scene.onDisposeObservable.addOnce(() => {
|
|
76689
|
-
console.log("StorySplat Viewer: Disposing camera manager and camera.");
|
|
76690
|
-
// No need to remove custom wheel listener anymore
|
|
76691
|
-
this._camera = null;
|
|
76692
|
-
});
|
|
76693
|
-
}
|
|
76694
|
-
// --- UI Update Helper ---
|
|
76695
|
-
_updateUIManager() {
|
|
76696
|
-
if (!this._uiManager)
|
|
76697
|
-
return;
|
|
76698
|
-
this._uiManager.updateModeToggleButtons();
|
|
76699
|
-
this._uiManager.updateExploreWalkToggleButtons();
|
|
76700
|
-
this._uiManager.updateScrollControlsVisibility();
|
|
76701
|
-
}
|
|
76702
|
-
// --- Public API Methods ---
|
|
76703
|
-
// Method to set the UIManager after instantiation
|
|
76704
|
-
setUIManager(uiManager) {
|
|
76705
|
-
this._uiManager = uiManager;
|
|
76706
|
-
// Update UI immediately after manager is set
|
|
76707
|
-
this._updateUIManager();
|
|
76708
|
-
}
|
|
76709
|
-
setPosition(position) {
|
|
76710
|
-
if (this._camera) {
|
|
76711
|
-
this._camera.position = position;
|
|
76712
|
-
}
|
|
76713
|
-
}
|
|
76714
|
-
setTarget(target) {
|
|
76715
|
-
if (this._camera) {
|
|
76716
|
-
this._camera.setTarget(target);
|
|
76717
|
-
}
|
|
76718
|
-
}
|
|
76719
|
-
}
|
|
76720
|
-
|
|
76721
|
-
// Import necessary loaders for .splat files (assuming it uses GLTF internally or a custom loader is registered)
|
|
76722
|
-
// If @babylonjs/loaders is needed and not globally imported, ensure it's imported somewhere,
|
|
76723
|
-
// e.g., in the main index.ts or here. For now, assume SceneLoader handles it.
|
|
76724
|
-
// import "@babylonjs/loaders/glTF"; // Example if GLTF loader is needed explicitly
|
|
76725
|
-
/**
|
|
76726
|
-
* Loads the primary Gaussian Splat asset into the scene.
|
|
76727
|
-
* @param scene - The BabylonJS scene to load the asset into.
|
|
76728
|
-
* @param data - The StorySplat data containing the model URL and scaling info.
|
|
76729
|
-
* @param onProgress - Optional callback function to report loading progress.
|
|
76730
|
-
* Receives percentage (0-100) and an optional status text.
|
|
76731
|
-
* @returns A promise that resolves with an array of the loaded AbstractMesh objects.
|
|
76732
|
-
*/
|
|
76733
|
-
async function loadSplatAsset(scene, data, onProgress // Updated signature
|
|
76734
|
-
) {
|
|
76735
|
-
var _a, _b, _c;
|
|
76736
|
-
const modelUrl = data.loadedModelUrl; // Changed from modelUrl
|
|
76737
|
-
if (!modelUrl) {
|
|
76738
|
-
console.error("StorySplat Viewer: No loadedModelUrl provided in data.");
|
|
76739
|
-
return Promise.reject(new Error("No loadedModelUrl provided in StorySplatData."));
|
|
76740
|
-
}
|
|
76741
|
-
const splatScale = (_a = data.splatScale) !== null && _a !== void 0 ? _a : 1.0;
|
|
76742
|
-
const invertX = (_b = data.invertXScale) !== null && _b !== void 0 ? _b : false;
|
|
76743
|
-
const invertY = (_c = data.invertYScale) !== null && _c !== void 0 ? _c : false;
|
|
76744
|
-
console.log(`StorySplat Viewer: Loading splat asset from ${modelUrl}`);
|
|
76745
|
-
try {
|
|
76746
|
-
// Debug: Check what loaders are registered
|
|
76747
|
-
console.log("StorySplat Viewer: Available SceneLoader plugins:", Object.keys(SceneLoader._RegisteredPlugins || {}));
|
|
76748
|
-
const result = await SceneLoader.ImportMeshAsync("", // meshNames - empty string loads all
|
|
76749
|
-
modelUrl, // rootUrl - the full URL
|
|
76750
|
-
"", // sceneFilename - empty when using full URL
|
|
76751
|
-
scene, (progressEvent) => {
|
|
76752
|
-
if (onProgress) {
|
|
76753
|
-
// Calculate percentage, handle indeterminate state
|
|
76754
|
-
let percentage = 0;
|
|
76755
|
-
if (progressEvent.lengthComputable && progressEvent.total > 0) {
|
|
76756
|
-
percentage = (progressEvent.loaded / progressEvent.total) * 100;
|
|
76757
|
-
}
|
|
76758
|
-
else if (progressEvent.loaded > 0) {
|
|
76759
|
-
// If not lengthComputable but loaded > 0, maybe indicate activity?
|
|
76760
|
-
// This part is tricky without total size. Could use a spinner state.
|
|
76761
|
-
// For simplicity, we'll report 0 or the calculated percentage.
|
|
76762
|
-
}
|
|
76763
|
-
// Report percentage and potentially a status text
|
|
76764
|
-
const statusText = progressEvent.lengthComputable ? `${(progressEvent.loaded / 1024 / 1024).toFixed(2)}MB / ${(progressEvent.total / 1024 / 1024).toFixed(2)}MB` : 'Loading...';
|
|
76765
|
-
onProgress(Math.round(percentage), statusText);
|
|
76766
|
-
}
|
|
76767
|
-
});
|
|
76768
|
-
if (!result.meshes || result.meshes.length === 0) {
|
|
76769
|
-
throw new Error(`No meshes found in the loaded asset: ${modelUrl}`);
|
|
76770
|
-
}
|
|
76771
|
-
console.log(`StorySplat Viewer: Successfully loaded ${result.meshes.length} meshes from ${modelUrl}.`);
|
|
76772
|
-
result.meshes.forEach((mesh) => {
|
|
76773
|
-
// Ensure the mesh is visible and pickable
|
|
76774
|
-
mesh.isVisible = true;
|
|
76775
|
-
mesh.isPickable = true; // Important for interactions like hotspots if they attach to splats
|
|
76776
|
-
// Apply scaling and inversion
|
|
76777
|
-
const scaleX = splatScale * (invertX ? -1 : 1);
|
|
76778
|
-
const scaleY = splatScale * (invertY ? -1 : 1);
|
|
76779
|
-
// Invert Z if only one of X or Y is inverted to maintain handedness
|
|
76780
|
-
// If both inverted or neither inverted, Z scale matches splatScale sign
|
|
76781
|
-
const scaleZ = splatScale * ((invertX !== invertY) ? -1 : 1);
|
|
76782
|
-
mesh.scaling.set(scaleX, scaleY, scaleZ);
|
|
76783
|
-
// Optional: Set collision properties if needed later
|
|
76784
|
-
// mesh.checkCollisions = true; // Enable collisions if required
|
|
76785
|
-
// Optional: Assign a name based on the URL for easier identification
|
|
76786
|
-
mesh.name = `splatRoot_${modelUrl}`; // Name the root mesh if possible
|
|
76787
|
-
});
|
|
76788
|
-
// Add cleanup logic for the loaded meshes
|
|
76789
|
-
const loadedMeshes = result.meshes; // Capture the meshes in this scope
|
|
76790
|
-
const disposeObserver = scene.onDisposeObservable.addOnce(() => {
|
|
76791
|
-
console.log(`StorySplat Viewer: Disposing splat asset: ${modelUrl}`);
|
|
76792
|
-
loadedMeshes.forEach(mesh => {
|
|
76793
|
-
if (mesh && !mesh.isDisposed()) {
|
|
76794
|
-
// Check parentage - only dispose root nodes added by the loader?
|
|
76795
|
-
// Or dispose all meshes returned by the loader. Assuming the latter for now.
|
|
76796
|
-
mesh.dispose(false, true); // Dispose mesh, materials, textures
|
|
76797
|
-
}
|
|
76798
|
-
});
|
|
76799
|
-
});
|
|
76800
|
-
// Store the observer reference on the meshes or a manager if needed for explicit cleanup later
|
|
76801
|
-
// e.g., loadedMeshes[0].metadata = { disposeObserver };
|
|
76802
|
-
return loadedMeshes;
|
|
76803
|
-
}
|
|
76804
|
-
catch (error) {
|
|
76805
|
-
console.error(`StorySplat Viewer: Error loading splat asset from ${modelUrl}:`, error);
|
|
76806
|
-
// Propagate the error
|
|
76807
|
-
throw error;
|
|
76808
|
-
}
|
|
76809
|
-
}
|
|
76810
|
-
|
|
76811
|
-
/**
|
|
76812
|
-
* Class used to store geometry data (vertex buffers + index buffer)
|
|
76813
|
-
*/
|
|
76814
|
-
class Geometry {
|
|
76815
|
-
/**
|
|
76816
|
-
* Gets or sets the Bias Vector to apply on the bounding elements (box/sphere), the max extend is computed as v += v * bias.x + bias.y, the min is computed as v -= v * bias.x + bias.y
|
|
76817
|
-
*/
|
|
76818
|
-
get boundingBias() {
|
|
76819
|
-
return this._boundingBias;
|
|
76820
|
-
}
|
|
76821
|
-
/**
|
|
76822
|
-
* Gets or sets the Bias Vector to apply on the bounding elements (box/sphere), the max extend is computed as v += v * bias.x + bias.y, the min is computed as v -= v * bias.x + bias.y
|
|
76823
|
-
*/
|
|
76824
|
-
set boundingBias(value) {
|
|
76825
|
-
if (this._boundingBias) {
|
|
76826
|
-
this._boundingBias.copyFrom(value);
|
|
76827
|
-
}
|
|
76828
|
-
else {
|
|
76829
|
-
this._boundingBias = value.clone();
|
|
76830
|
-
}
|
|
76831
|
-
this._updateBoundingInfo(true, null);
|
|
76832
|
-
}
|
|
76833
|
-
/**
|
|
76834
|
-
* Static function used to attach a new empty geometry to a mesh
|
|
76835
|
-
* @param mesh defines the mesh to attach the geometry to
|
|
76836
|
-
* @returns the new Geometry
|
|
76837
|
-
*/
|
|
76838
|
-
static CreateGeometryForMesh(mesh) {
|
|
76839
|
-
const geometry = new Geometry(Geometry.RandomId(), mesh.getScene());
|
|
76840
|
-
geometry.applyToMesh(mesh);
|
|
76841
|
-
return geometry;
|
|
76842
|
-
}
|
|
76843
|
-
/** Get the list of meshes using this geometry */
|
|
76844
|
-
get meshes() {
|
|
76845
|
-
return this._meshes;
|
|
76846
|
-
}
|
|
76847
|
-
/**
|
|
76848
|
-
* Creates a new geometry
|
|
76849
|
-
* @param id defines the unique ID
|
|
76850
|
-
* @param scene defines the hosting scene
|
|
76851
|
-
* @param vertexData defines the VertexData used to get geometry data
|
|
76852
|
-
* @param updatable defines if geometry must be updatable (false by default)
|
|
76853
|
-
* @param mesh defines the mesh that will be associated with the geometry
|
|
76854
|
-
*/
|
|
76855
|
-
constructor(id, scene, vertexData, updatable = false, mesh = null) {
|
|
76856
|
-
/**
|
|
76857
|
-
* Gets the delay loading state of the geometry (none by default which means not delayed)
|
|
76858
|
-
*/
|
|
76859
|
-
this.delayLoadState = 0;
|
|
76860
|
-
this._totalVertices = 0;
|
|
76861
|
-
this._isDisposed = false;
|
|
76862
|
-
this._extend = {
|
|
76863
|
-
minimum: new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE),
|
|
76864
|
-
maximum: new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE),
|
|
76865
|
-
};
|
|
76866
|
-
this._indexBufferIsUpdatable = false;
|
|
76867
|
-
this._positionsCache = [];
|
|
76868
|
-
/** @internal */
|
|
76869
|
-
this._parentContainer = null;
|
|
76870
|
-
/**
|
|
76871
|
-
* If set to true (false by default), the bounding info applied to the meshes sharing this geometry will be the bounding info defined at the class level
|
|
76872
|
-
* and won't be computed based on the vertex positions (which is what we get when useBoundingInfoFromGeometry = false)
|
|
76873
|
-
*/
|
|
76874
|
-
this.useBoundingInfoFromGeometry = false;
|
|
76875
|
-
this._scene = scene || EngineStore.LastCreatedScene;
|
|
76876
|
-
if (!this._scene) {
|
|
76877
|
-
return;
|
|
76878
|
-
}
|
|
76879
|
-
this.id = id;
|
|
76880
|
-
this.uniqueId = this._scene.getUniqueId();
|
|
76881
|
-
this._engine = this._scene.getEngine();
|
|
76882
|
-
this._meshes = [];
|
|
76883
|
-
//Init vertex buffer cache
|
|
76884
|
-
this._vertexBuffers = {};
|
|
76885
|
-
this._indices = [];
|
|
76886
|
-
this._updatable = updatable;
|
|
76887
|
-
// vertexData
|
|
76888
|
-
if (vertexData) {
|
|
76889
|
-
this.setAllVerticesData(vertexData, updatable);
|
|
76890
|
-
}
|
|
76891
|
-
else {
|
|
76892
|
-
this._totalVertices = 0;
|
|
76893
|
-
}
|
|
76894
|
-
if (this._engine.getCaps().vertexArrayObject) {
|
|
76895
|
-
this._vertexArrayObjects = {};
|
|
76896
|
-
}
|
|
76897
|
-
// applyToMesh
|
|
76898
|
-
if (mesh) {
|
|
76899
|
-
this.applyToMesh(mesh);
|
|
76900
|
-
mesh.computeWorldMatrix(true);
|
|
76901
|
-
}
|
|
76902
|
-
}
|
|
76903
|
-
/**
|
|
76904
|
-
* Gets the current extend of the geometry
|
|
76905
|
-
*/
|
|
76906
|
-
get extend() {
|
|
76907
|
-
return this._extend;
|
|
76908
|
-
}
|
|
76909
|
-
/**
|
|
76910
|
-
* Gets the hosting scene
|
|
76911
|
-
* @returns the hosting Scene
|
|
76912
|
-
*/
|
|
76913
|
-
getScene() {
|
|
76914
|
-
return this._scene;
|
|
76915
|
-
}
|
|
76916
|
-
/**
|
|
76917
|
-
* Gets the hosting engine
|
|
76918
|
-
* @returns the hosting Engine
|
|
76919
|
-
*/
|
|
76920
|
-
getEngine() {
|
|
76921
|
-
return this._engine;
|
|
76922
|
-
}
|
|
76923
|
-
/**
|
|
76924
|
-
* Defines if the geometry is ready to use
|
|
76925
|
-
* @returns true if the geometry is ready to be used
|
|
76926
|
-
*/
|
|
76927
|
-
isReady() {
|
|
76928
|
-
return this.delayLoadState === 1 || this.delayLoadState === 0;
|
|
76929
|
-
}
|
|
76930
|
-
/**
|
|
76931
|
-
* Gets a value indicating that the geometry should not be serialized
|
|
76932
|
-
*/
|
|
76933
|
-
get doNotSerialize() {
|
|
76934
|
-
for (let index = 0; index < this._meshes.length; index++) {
|
|
76935
|
-
if (!this._meshes[index].doNotSerialize) {
|
|
76936
|
-
return false;
|
|
76937
|
-
}
|
|
76938
|
-
}
|
|
76939
|
-
return true;
|
|
76940
|
-
}
|
|
76941
|
-
/** @internal */
|
|
76942
|
-
_rebuild() {
|
|
76943
|
-
if (this._vertexArrayObjects) {
|
|
76944
|
-
this._vertexArrayObjects = {};
|
|
76945
|
-
}
|
|
76946
|
-
// Index buffer
|
|
76947
|
-
if (this._meshes.length !== 0 && this._indices) {
|
|
76948
|
-
this._indexBuffer = this._engine.createIndexBuffer(this._indices, this._updatable, "Geometry_" + this.id + "_IndexBuffer");
|
|
76949
|
-
}
|
|
76950
|
-
// Vertex buffers
|
|
76951
|
-
const buffers = new Set();
|
|
76952
|
-
for (const key in this._vertexBuffers) {
|
|
76953
|
-
buffers.add(this._vertexBuffers[key].getWrapperBuffer());
|
|
76954
|
-
}
|
|
76955
|
-
buffers.forEach((buffer) => {
|
|
76956
|
-
buffer._rebuild();
|
|
76957
|
-
});
|
|
76958
|
-
}
|
|
76959
|
-
/**
|
|
76960
|
-
* Affects all geometry data in one call
|
|
76961
|
-
* @param vertexData defines the geometry data
|
|
76962
|
-
* @param updatable defines if the geometry must be flagged as updatable (false as default)
|
|
76963
|
-
*/
|
|
76964
|
-
setAllVerticesData(vertexData, updatable) {
|
|
76965
|
-
vertexData.applyToGeometry(this, updatable);
|
|
76966
|
-
this._notifyUpdate();
|
|
76967
|
-
}
|
|
76968
|
-
/**
|
|
76969
|
-
* Set specific vertex data
|
|
76970
|
-
* @param kind defines the data kind (Position, normal, etc...)
|
|
76971
|
-
* @param data defines the vertex data to use
|
|
76972
|
-
* @param updatable defines if the vertex must be flagged as updatable (false as default)
|
|
76973
|
-
* @param stride defines the stride to use (0 by default). This value is deduced from the kind value if not specified
|
|
76974
|
-
*/
|
|
76975
|
-
setVerticesData(kind, data, updatable = false, stride) {
|
|
76976
|
-
if (updatable && Array.isArray(data)) {
|
|
76977
|
-
// to avoid converting to Float32Array at each draw call in engine.updateDynamicVertexBuffer, we make the conversion a single time here
|
|
76978
|
-
data = new Float32Array(data);
|
|
76979
|
-
}
|
|
76980
|
-
const buffer = new VertexBuffer(this._engine, data, kind, {
|
|
76981
|
-
updatable,
|
|
76982
|
-
postponeInternalCreation: this._meshes.length === 0,
|
|
76983
|
-
stride,
|
|
76984
|
-
label: "Geometry_" + this.id + "_" + kind,
|
|
76985
|
-
});
|
|
76986
|
-
this.setVerticesBuffer(buffer);
|
|
76987
|
-
}
|
|
76988
|
-
/**
|
|
76989
|
-
* Removes a specific vertex data
|
|
76990
|
-
* @param kind defines the data kind (Position, normal, etc...)
|
|
76991
|
-
*/
|
|
76992
|
-
removeVerticesData(kind) {
|
|
76993
|
-
if (this._vertexBuffers[kind]) {
|
|
76994
|
-
this._vertexBuffers[kind].dispose();
|
|
76995
|
-
delete this._vertexBuffers[kind];
|
|
76996
|
-
}
|
|
76997
|
-
if (this._vertexArrayObjects) {
|
|
76998
|
-
this._disposeVertexArrayObjects();
|
|
76999
|
-
}
|
|
77000
|
-
}
|
|
77001
|
-
/**
|
|
77002
|
-
* Affect a vertex buffer to the geometry. the vertexBuffer.getKind() function is used to determine where to store the data
|
|
77003
|
-
* @param buffer defines the vertex buffer to use
|
|
77004
|
-
* @param totalVertices defines the total number of vertices for position kind (could be null)
|
|
77005
|
-
* @param disposeExistingBuffer disposes the existing buffer, if any (default: true)
|
|
77006
|
-
*/
|
|
77007
|
-
setVerticesBuffer(buffer, totalVertices = null, disposeExistingBuffer = true) {
|
|
77008
|
-
const kind = buffer.getKind();
|
|
77009
|
-
if (this._vertexBuffers[kind] && disposeExistingBuffer) {
|
|
77010
|
-
this._vertexBuffers[kind].dispose();
|
|
77011
|
-
}
|
|
77012
|
-
if (buffer._buffer && buffer._ownsBuffer) {
|
|
77013
|
-
buffer._buffer._increaseReferences();
|
|
77014
|
-
}
|
|
77015
|
-
this._vertexBuffers[kind] = buffer;
|
|
77016
|
-
const meshes = this._meshes;
|
|
77017
|
-
const numOfMeshes = meshes.length;
|
|
77018
|
-
if (kind === VertexBuffer.PositionKind) {
|
|
77019
|
-
this._totalVertices = totalVertices ?? buffer._maxVerticesCount;
|
|
77020
|
-
this._updateExtend(buffer.getFloatData(this._totalVertices));
|
|
77021
|
-
this._resetPointsArrayCache();
|
|
77022
|
-
// this._extend can be empty if buffer.getFloatData(this._totalVertices) returned null
|
|
77023
|
-
const minimum = (this._extend && this._extend.minimum) || new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
|
|
77024
|
-
const maximum = (this._extend && this._extend.maximum) || new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
77025
|
-
for (let index = 0; index < numOfMeshes; index++) {
|
|
77026
|
-
const mesh = meshes[index];
|
|
77027
|
-
mesh.buildBoundingInfo(minimum, maximum);
|
|
77028
|
-
mesh._createGlobalSubMesh(mesh.isUnIndexed);
|
|
77029
|
-
mesh.computeWorldMatrix(true);
|
|
77030
|
-
mesh.synchronizeInstances();
|
|
77031
|
-
}
|
|
77032
|
-
}
|
|
77033
|
-
this._notifyUpdate(kind);
|
|
76456
|
+
this._notifyUpdate(kind);
|
|
77034
76457
|
}
|
|
77035
76458
|
/**
|
|
77036
76459
|
* Update a specific vertex buffer
|
|
@@ -98988,292 +98411,898 @@ class StandardMaterial extends PushMaterial {
|
|
|
98988
98411
|
static get EmissiveTextureEnabled() {
|
|
98989
98412
|
return MaterialFlags.EmissiveTextureEnabled;
|
|
98990
98413
|
}
|
|
98991
|
-
static set EmissiveTextureEnabled(value) {
|
|
98992
|
-
MaterialFlags.EmissiveTextureEnabled = value;
|
|
98414
|
+
static set EmissiveTextureEnabled(value) {
|
|
98415
|
+
MaterialFlags.EmissiveTextureEnabled = value;
|
|
98416
|
+
}
|
|
98417
|
+
/**
|
|
98418
|
+
* Are specular textures enabled in the application.
|
|
98419
|
+
*/
|
|
98420
|
+
static get SpecularTextureEnabled() {
|
|
98421
|
+
return MaterialFlags.SpecularTextureEnabled;
|
|
98422
|
+
}
|
|
98423
|
+
static set SpecularTextureEnabled(value) {
|
|
98424
|
+
MaterialFlags.SpecularTextureEnabled = value;
|
|
98425
|
+
}
|
|
98426
|
+
/**
|
|
98427
|
+
* Are bump textures enabled in the application.
|
|
98428
|
+
*/
|
|
98429
|
+
static get BumpTextureEnabled() {
|
|
98430
|
+
return MaterialFlags.BumpTextureEnabled;
|
|
98431
|
+
}
|
|
98432
|
+
static set BumpTextureEnabled(value) {
|
|
98433
|
+
MaterialFlags.BumpTextureEnabled = value;
|
|
98434
|
+
}
|
|
98435
|
+
/**
|
|
98436
|
+
* Are lightmap textures enabled in the application.
|
|
98437
|
+
*/
|
|
98438
|
+
static get LightmapTextureEnabled() {
|
|
98439
|
+
return MaterialFlags.LightmapTextureEnabled;
|
|
98440
|
+
}
|
|
98441
|
+
static set LightmapTextureEnabled(value) {
|
|
98442
|
+
MaterialFlags.LightmapTextureEnabled = value;
|
|
98443
|
+
}
|
|
98444
|
+
/**
|
|
98445
|
+
* Are refraction textures enabled in the application.
|
|
98446
|
+
*/
|
|
98447
|
+
static get RefractionTextureEnabled() {
|
|
98448
|
+
return MaterialFlags.RefractionTextureEnabled;
|
|
98449
|
+
}
|
|
98450
|
+
static set RefractionTextureEnabled(value) {
|
|
98451
|
+
MaterialFlags.RefractionTextureEnabled = value;
|
|
98452
|
+
}
|
|
98453
|
+
/**
|
|
98454
|
+
* Are color grading textures enabled in the application.
|
|
98455
|
+
*/
|
|
98456
|
+
static get ColorGradingTextureEnabled() {
|
|
98457
|
+
return MaterialFlags.ColorGradingTextureEnabled;
|
|
98458
|
+
}
|
|
98459
|
+
static set ColorGradingTextureEnabled(value) {
|
|
98460
|
+
MaterialFlags.ColorGradingTextureEnabled = value;
|
|
98461
|
+
}
|
|
98462
|
+
/**
|
|
98463
|
+
* Are fresnels enabled in the application.
|
|
98464
|
+
*/
|
|
98465
|
+
static get FresnelEnabled() {
|
|
98466
|
+
return MaterialFlags.FresnelEnabled;
|
|
98467
|
+
}
|
|
98468
|
+
static set FresnelEnabled(value) {
|
|
98469
|
+
MaterialFlags.FresnelEnabled = value;
|
|
98470
|
+
}
|
|
98471
|
+
}
|
|
98472
|
+
/**
|
|
98473
|
+
* Force all the standard materials to compile to glsl even on WebGPU engines.
|
|
98474
|
+
* False by default. This is mostly meant for backward compatibility.
|
|
98475
|
+
*/
|
|
98476
|
+
StandardMaterial.ForceGLSL = false;
|
|
98477
|
+
__decorate([
|
|
98478
|
+
serializeAsTexture("diffuseTexture")
|
|
98479
|
+
], StandardMaterial.prototype, "_diffuseTexture", void 0);
|
|
98480
|
+
__decorate([
|
|
98481
|
+
expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
|
|
98482
|
+
], StandardMaterial.prototype, "diffuseTexture", void 0);
|
|
98483
|
+
__decorate([
|
|
98484
|
+
serializeAsTexture("ambientTexture")
|
|
98485
|
+
], StandardMaterial.prototype, "_ambientTexture", void 0);
|
|
98486
|
+
__decorate([
|
|
98487
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98488
|
+
], StandardMaterial.prototype, "ambientTexture", void 0);
|
|
98489
|
+
__decorate([
|
|
98490
|
+
serializeAsTexture("opacityTexture")
|
|
98491
|
+
], StandardMaterial.prototype, "_opacityTexture", void 0);
|
|
98492
|
+
__decorate([
|
|
98493
|
+
expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
|
|
98494
|
+
], StandardMaterial.prototype, "opacityTexture", void 0);
|
|
98495
|
+
__decorate([
|
|
98496
|
+
serializeAsTexture("reflectionTexture")
|
|
98497
|
+
], StandardMaterial.prototype, "_reflectionTexture", void 0);
|
|
98498
|
+
__decorate([
|
|
98499
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98500
|
+
], StandardMaterial.prototype, "reflectionTexture", void 0);
|
|
98501
|
+
__decorate([
|
|
98502
|
+
serializeAsTexture("emissiveTexture")
|
|
98503
|
+
], StandardMaterial.prototype, "_emissiveTexture", void 0);
|
|
98504
|
+
__decorate([
|
|
98505
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98506
|
+
], StandardMaterial.prototype, "emissiveTexture", void 0);
|
|
98507
|
+
__decorate([
|
|
98508
|
+
serializeAsTexture("specularTexture")
|
|
98509
|
+
], StandardMaterial.prototype, "_specularTexture", void 0);
|
|
98510
|
+
__decorate([
|
|
98511
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98512
|
+
], StandardMaterial.prototype, "specularTexture", void 0);
|
|
98513
|
+
__decorate([
|
|
98514
|
+
serializeAsTexture("bumpTexture")
|
|
98515
|
+
], StandardMaterial.prototype, "_bumpTexture", void 0);
|
|
98516
|
+
__decorate([
|
|
98517
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98518
|
+
], StandardMaterial.prototype, "bumpTexture", void 0);
|
|
98519
|
+
__decorate([
|
|
98520
|
+
serializeAsTexture("lightmapTexture")
|
|
98521
|
+
], StandardMaterial.prototype, "_lightmapTexture", void 0);
|
|
98522
|
+
__decorate([
|
|
98523
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98524
|
+
], StandardMaterial.prototype, "lightmapTexture", void 0);
|
|
98525
|
+
__decorate([
|
|
98526
|
+
serializeAsTexture("refractionTexture")
|
|
98527
|
+
], StandardMaterial.prototype, "_refractionTexture", void 0);
|
|
98528
|
+
__decorate([
|
|
98529
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98530
|
+
], StandardMaterial.prototype, "refractionTexture", void 0);
|
|
98531
|
+
__decorate([
|
|
98532
|
+
serializeAsColor3("ambient")
|
|
98533
|
+
], StandardMaterial.prototype, "ambientColor", void 0);
|
|
98534
|
+
__decorate([
|
|
98535
|
+
serializeAsColor3("diffuse")
|
|
98536
|
+
], StandardMaterial.prototype, "diffuseColor", void 0);
|
|
98537
|
+
__decorate([
|
|
98538
|
+
serializeAsColor3("specular")
|
|
98539
|
+
], StandardMaterial.prototype, "specularColor", void 0);
|
|
98540
|
+
__decorate([
|
|
98541
|
+
serializeAsColor3("emissive")
|
|
98542
|
+
], StandardMaterial.prototype, "emissiveColor", void 0);
|
|
98543
|
+
__decorate([
|
|
98544
|
+
serialize()
|
|
98545
|
+
], StandardMaterial.prototype, "specularPower", void 0);
|
|
98546
|
+
__decorate([
|
|
98547
|
+
serialize("useAlphaFromDiffuseTexture")
|
|
98548
|
+
], StandardMaterial.prototype, "_useAlphaFromDiffuseTexture", void 0);
|
|
98549
|
+
__decorate([
|
|
98550
|
+
expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
|
|
98551
|
+
], StandardMaterial.prototype, "useAlphaFromDiffuseTexture", void 0);
|
|
98552
|
+
__decorate([
|
|
98553
|
+
serialize("useEmissiveAsIllumination")
|
|
98554
|
+
], StandardMaterial.prototype, "_useEmissiveAsIllumination", void 0);
|
|
98555
|
+
__decorate([
|
|
98556
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98557
|
+
], StandardMaterial.prototype, "useEmissiveAsIllumination", void 0);
|
|
98558
|
+
__decorate([
|
|
98559
|
+
serialize("linkEmissiveWithDiffuse")
|
|
98560
|
+
], StandardMaterial.prototype, "_linkEmissiveWithDiffuse", void 0);
|
|
98561
|
+
__decorate([
|
|
98562
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98563
|
+
], StandardMaterial.prototype, "linkEmissiveWithDiffuse", void 0);
|
|
98564
|
+
__decorate([
|
|
98565
|
+
serialize("useSpecularOverAlpha")
|
|
98566
|
+
], StandardMaterial.prototype, "_useSpecularOverAlpha", void 0);
|
|
98567
|
+
__decorate([
|
|
98568
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98569
|
+
], StandardMaterial.prototype, "useSpecularOverAlpha", void 0);
|
|
98570
|
+
__decorate([
|
|
98571
|
+
serialize("useReflectionOverAlpha")
|
|
98572
|
+
], StandardMaterial.prototype, "_useReflectionOverAlpha", void 0);
|
|
98573
|
+
__decorate([
|
|
98574
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98575
|
+
], StandardMaterial.prototype, "useReflectionOverAlpha", void 0);
|
|
98576
|
+
__decorate([
|
|
98577
|
+
serialize("disableLighting")
|
|
98578
|
+
], StandardMaterial.prototype, "_disableLighting", void 0);
|
|
98579
|
+
__decorate([
|
|
98580
|
+
expandToProperty("_markAllSubMeshesAsLightsDirty")
|
|
98581
|
+
], StandardMaterial.prototype, "disableLighting", void 0);
|
|
98582
|
+
__decorate([
|
|
98583
|
+
serialize("useObjectSpaceNormalMap")
|
|
98584
|
+
], StandardMaterial.prototype, "_useObjectSpaceNormalMap", void 0);
|
|
98585
|
+
__decorate([
|
|
98586
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98587
|
+
], StandardMaterial.prototype, "useObjectSpaceNormalMap", void 0);
|
|
98588
|
+
__decorate([
|
|
98589
|
+
serialize("useParallax")
|
|
98590
|
+
], StandardMaterial.prototype, "_useParallax", void 0);
|
|
98591
|
+
__decorate([
|
|
98592
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98593
|
+
], StandardMaterial.prototype, "useParallax", void 0);
|
|
98594
|
+
__decorate([
|
|
98595
|
+
serialize("useParallaxOcclusion")
|
|
98596
|
+
], StandardMaterial.prototype, "_useParallaxOcclusion", void 0);
|
|
98597
|
+
__decorate([
|
|
98598
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98599
|
+
], StandardMaterial.prototype, "useParallaxOcclusion", void 0);
|
|
98600
|
+
__decorate([
|
|
98601
|
+
serialize()
|
|
98602
|
+
], StandardMaterial.prototype, "parallaxScaleBias", void 0);
|
|
98603
|
+
__decorate([
|
|
98604
|
+
serialize("roughness")
|
|
98605
|
+
], StandardMaterial.prototype, "_roughness", void 0);
|
|
98606
|
+
__decorate([
|
|
98607
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98608
|
+
], StandardMaterial.prototype, "roughness", void 0);
|
|
98609
|
+
__decorate([
|
|
98610
|
+
serialize()
|
|
98611
|
+
], StandardMaterial.prototype, "indexOfRefraction", void 0);
|
|
98612
|
+
__decorate([
|
|
98613
|
+
serialize()
|
|
98614
|
+
], StandardMaterial.prototype, "invertRefractionY", void 0);
|
|
98615
|
+
__decorate([
|
|
98616
|
+
serialize()
|
|
98617
|
+
], StandardMaterial.prototype, "alphaCutOff", void 0);
|
|
98618
|
+
__decorate([
|
|
98619
|
+
serialize("useLightmapAsShadowmap")
|
|
98620
|
+
], StandardMaterial.prototype, "_useLightmapAsShadowmap", void 0);
|
|
98621
|
+
__decorate([
|
|
98622
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98623
|
+
], StandardMaterial.prototype, "useLightmapAsShadowmap", void 0);
|
|
98624
|
+
__decorate([
|
|
98625
|
+
serializeAsFresnelParameters("diffuseFresnelParameters")
|
|
98626
|
+
], StandardMaterial.prototype, "_diffuseFresnelParameters", void 0);
|
|
98627
|
+
__decorate([
|
|
98628
|
+
expandToProperty("_markAllSubMeshesAsFresnelDirty")
|
|
98629
|
+
], StandardMaterial.prototype, "diffuseFresnelParameters", void 0);
|
|
98630
|
+
__decorate([
|
|
98631
|
+
serializeAsFresnelParameters("opacityFresnelParameters")
|
|
98632
|
+
], StandardMaterial.prototype, "_opacityFresnelParameters", void 0);
|
|
98633
|
+
__decorate([
|
|
98634
|
+
expandToProperty("_markAllSubMeshesAsFresnelAndMiscDirty")
|
|
98635
|
+
], StandardMaterial.prototype, "opacityFresnelParameters", void 0);
|
|
98636
|
+
__decorate([
|
|
98637
|
+
serializeAsFresnelParameters("reflectionFresnelParameters")
|
|
98638
|
+
], StandardMaterial.prototype, "_reflectionFresnelParameters", void 0);
|
|
98639
|
+
__decorate([
|
|
98640
|
+
expandToProperty("_markAllSubMeshesAsFresnelDirty")
|
|
98641
|
+
], StandardMaterial.prototype, "reflectionFresnelParameters", void 0);
|
|
98642
|
+
__decorate([
|
|
98643
|
+
serializeAsFresnelParameters("refractionFresnelParameters")
|
|
98644
|
+
], StandardMaterial.prototype, "_refractionFresnelParameters", void 0);
|
|
98645
|
+
__decorate([
|
|
98646
|
+
expandToProperty("_markAllSubMeshesAsFresnelDirty")
|
|
98647
|
+
], StandardMaterial.prototype, "refractionFresnelParameters", void 0);
|
|
98648
|
+
__decorate([
|
|
98649
|
+
serializeAsFresnelParameters("emissiveFresnelParameters")
|
|
98650
|
+
], StandardMaterial.prototype, "_emissiveFresnelParameters", void 0);
|
|
98651
|
+
__decorate([
|
|
98652
|
+
expandToProperty("_markAllSubMeshesAsFresnelDirty")
|
|
98653
|
+
], StandardMaterial.prototype, "emissiveFresnelParameters", void 0);
|
|
98654
|
+
__decorate([
|
|
98655
|
+
serialize("useReflectionFresnelFromSpecular")
|
|
98656
|
+
], StandardMaterial.prototype, "_useReflectionFresnelFromSpecular", void 0);
|
|
98657
|
+
__decorate([
|
|
98658
|
+
expandToProperty("_markAllSubMeshesAsFresnelDirty")
|
|
98659
|
+
], StandardMaterial.prototype, "useReflectionFresnelFromSpecular", void 0);
|
|
98660
|
+
__decorate([
|
|
98661
|
+
serialize("useGlossinessFromSpecularMapAlpha")
|
|
98662
|
+
], StandardMaterial.prototype, "_useGlossinessFromSpecularMapAlpha", void 0);
|
|
98663
|
+
__decorate([
|
|
98664
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98665
|
+
], StandardMaterial.prototype, "useGlossinessFromSpecularMapAlpha", void 0);
|
|
98666
|
+
__decorate([
|
|
98667
|
+
serialize("maxSimultaneousLights")
|
|
98668
|
+
], StandardMaterial.prototype, "_maxSimultaneousLights", void 0);
|
|
98669
|
+
__decorate([
|
|
98670
|
+
expandToProperty("_markAllSubMeshesAsLightsDirty")
|
|
98671
|
+
], StandardMaterial.prototype, "maxSimultaneousLights", void 0);
|
|
98672
|
+
__decorate([
|
|
98673
|
+
serialize("invertNormalMapX")
|
|
98674
|
+
], StandardMaterial.prototype, "_invertNormalMapX", void 0);
|
|
98675
|
+
__decorate([
|
|
98676
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98677
|
+
], StandardMaterial.prototype, "invertNormalMapX", void 0);
|
|
98678
|
+
__decorate([
|
|
98679
|
+
serialize("invertNormalMapY")
|
|
98680
|
+
], StandardMaterial.prototype, "_invertNormalMapY", void 0);
|
|
98681
|
+
__decorate([
|
|
98682
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98683
|
+
], StandardMaterial.prototype, "invertNormalMapY", void 0);
|
|
98684
|
+
__decorate([
|
|
98685
|
+
serialize("twoSidedLighting")
|
|
98686
|
+
], StandardMaterial.prototype, "_twoSidedLighting", void 0);
|
|
98687
|
+
__decorate([
|
|
98688
|
+
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
98689
|
+
], StandardMaterial.prototype, "twoSidedLighting", void 0);
|
|
98690
|
+
__decorate([
|
|
98691
|
+
serialize("applyDecalMapAfterDetailMap")
|
|
98692
|
+
], StandardMaterial.prototype, "_applyDecalMapAfterDetailMap", void 0);
|
|
98693
|
+
__decorate([
|
|
98694
|
+
expandToProperty("_markAllSubMeshesAsMiscDirty")
|
|
98695
|
+
], StandardMaterial.prototype, "applyDecalMapAfterDetailMap", void 0);
|
|
98696
|
+
RegisterClass("BABYLON.StandardMaterial", StandardMaterial);
|
|
98697
|
+
Scene.DefaultMaterialFactory = (scene) => {
|
|
98698
|
+
return new StandardMaterial("default material", scene);
|
|
98699
|
+
};
|
|
98700
|
+
|
|
98701
|
+
/**
|
|
98702
|
+
* Basic check if the current environment appears to be a mobile device based on user agent.
|
|
98703
|
+
* Note: User agent sniffing is generally unreliable; consider feature detection instead if possible.
|
|
98704
|
+
* This function might return false positives or negatives.
|
|
98705
|
+
* @returns True if the user agent string matches common mobile patterns, false otherwise.
|
|
98706
|
+
*/
|
|
98707
|
+
const isMobileDevice = () => {
|
|
98708
|
+
if (typeof navigator === 'undefined' || !navigator.userAgent) {
|
|
98709
|
+
return false; // Cannot determine without navigator.userAgent
|
|
98710
|
+
}
|
|
98711
|
+
return /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase());
|
|
98712
|
+
};
|
|
98713
|
+
/**
|
|
98714
|
+
* Converts a simple {r, g, b, a} object to a BabylonJS Color4 object.
|
|
98715
|
+
* Handles potential undefined input. Alpha defaults to 1 if not provided.
|
|
98716
|
+
* @param colorObj - The color object { r, g, b, a? } (values 0-1).
|
|
98717
|
+
* @param defaultColor - The default Color4 to return if input is invalid.
|
|
98718
|
+
* @returns A BabylonJS Color4 object.
|
|
98719
|
+
*/
|
|
98720
|
+
const toColor4 = (colorObj, defaultColor = new Color4(1, 1, 1, 1) // Default to opaque white
|
|
98721
|
+
) => {
|
|
98722
|
+
if (colorObj && typeof colorObj.r === 'number' && typeof colorObj.g === 'number' && typeof colorObj.b === 'number') {
|
|
98723
|
+
const alpha = typeof colorObj.a === 'number' ? colorObj.a : 1.0;
|
|
98724
|
+
return new Color4(colorObj.r, colorObj.g, colorObj.b, alpha);
|
|
98725
|
+
}
|
|
98726
|
+
return defaultColor;
|
|
98727
|
+
};
|
|
98728
|
+
/**
|
|
98729
|
+
* Converts a simple {x, y, z} object to a BabylonJS Vector3 object.
|
|
98730
|
+
* Handles potential undefined input.
|
|
98731
|
+
* @param vecObj - The vector object { x, y, z }.
|
|
98732
|
+
* @param defaultVector - The default Vector3 to return if input is invalid.
|
|
98733
|
+
* @returns A BabylonJS Vector3 object.
|
|
98734
|
+
*/
|
|
98735
|
+
const toVector3 = (vecObj, defaultVector = new Vector3(0, 0, 0) // Default to origin
|
|
98736
|
+
) => {
|
|
98737
|
+
if (vecObj && typeof vecObj.x === 'number' && typeof vecObj.y === 'number' && typeof vecObj.z === 'number') {
|
|
98738
|
+
return new Vector3(vecObj.x, vecObj.y, vecObj.z);
|
|
98739
|
+
}
|
|
98740
|
+
return defaultVector;
|
|
98741
|
+
};
|
|
98742
|
+
/**
|
|
98743
|
+
* Converts a simple {_x, _y, _z, _w} object to a BabylonJS Quaternion object.
|
|
98744
|
+
* Handles potential undefined input.
|
|
98745
|
+
* @param quatObj - The quaternion object { _x, _y, _z, _w }.
|
|
98746
|
+
* @param defaultQuaternion - The default Quaternion to return if input is invalid.
|
|
98747
|
+
* @returns A BabylonJS Quaternion object.
|
|
98748
|
+
*/
|
|
98749
|
+
const toQuaternion = (quatObj, defaultQuaternion = Quaternion.Identity() // Default to identity
|
|
98750
|
+
) => {
|
|
98751
|
+
if (quatObj && typeof quatObj._x === 'number' && typeof quatObj._y === 'number' && typeof quatObj._z === 'number' && typeof quatObj._w === 'number') {
|
|
98752
|
+
return new Quaternion(quatObj._x, quatObj._y, quatObj._z, quatObj._w);
|
|
98753
|
+
}
|
|
98754
|
+
return defaultQuaternion;
|
|
98755
|
+
};
|
|
98756
|
+
/**
|
|
98757
|
+
* Converts a hex color string (e.g., "#RRGGBB") to a BabylonJS Color3 object.
|
|
98758
|
+
* Handles potential undefined or invalid input.
|
|
98759
|
+
* @param hex - The hex color string.
|
|
98760
|
+
* @param defaultColor - The default Color3 to return if input is invalid.
|
|
98761
|
+
* @returns A BabylonJS Color3 object.
|
|
98762
|
+
*/
|
|
98763
|
+
const hexToColor3 = (hex, defaultColor = new Color3(1, 1, 1) // Default to white
|
|
98764
|
+
) => {
|
|
98765
|
+
if (!hex) {
|
|
98766
|
+
return defaultColor;
|
|
98767
|
+
}
|
|
98768
|
+
try {
|
|
98769
|
+
return Color3.FromHexString(hex);
|
|
98770
|
+
}
|
|
98771
|
+
catch (error) {
|
|
98772
|
+
console.warn(`Invalid hex color format for hexToColor3: ${hex}. Using default.`, error);
|
|
98773
|
+
return defaultColor;
|
|
98774
|
+
}
|
|
98775
|
+
};
|
|
98776
|
+
/**
|
|
98777
|
+
* Applies opacity to a mesh and its children's materials.
|
|
98778
|
+
* Handles StandardMaterial and potentially PBRMaterial alpha/transparencyMode.
|
|
98779
|
+
* @param mesh - The root mesh to apply opacity to.
|
|
98780
|
+
* @param opacity - The opacity value (0-1).
|
|
98781
|
+
*/
|
|
98782
|
+
function applyOpacityToMeshAndChildren(mesh, opacity) {
|
|
98783
|
+
if (!mesh)
|
|
98784
|
+
return;
|
|
98785
|
+
const applyToMaterial = (material) => {
|
|
98786
|
+
if (material) {
|
|
98787
|
+
const clampedOpacity = Math.max(0, Math.min(1, opacity)); // Ensure opacity is 0-1
|
|
98788
|
+
// StandardMaterial
|
|
98789
|
+
if ('alpha' in material) {
|
|
98790
|
+
material.alpha = clampedOpacity;
|
|
98791
|
+
}
|
|
98792
|
+
// PBRMaterial - requires transparencyMode adjustment
|
|
98793
|
+
if ('transparencyMode' in material) {
|
|
98794
|
+
const pbrMaterial = material;
|
|
98795
|
+
if (clampedOpacity < 1) {
|
|
98796
|
+
// Use ALPHABLEND (numeric value 2) if transparent
|
|
98797
|
+
pbrMaterial.transparencyMode = 2; // BABYLON.Constants.PBRMATERIAL_ALPHABLEND;
|
|
98798
|
+
pbrMaterial.alpha = clampedOpacity;
|
|
98799
|
+
}
|
|
98800
|
+
else {
|
|
98801
|
+
// Reset to opaque if opacity is 1
|
|
98802
|
+
pbrMaterial.transparencyMode = null; // Or 0 for OPAQUE
|
|
98803
|
+
pbrMaterial.alpha = 1;
|
|
98804
|
+
}
|
|
98805
|
+
}
|
|
98806
|
+
}
|
|
98807
|
+
};
|
|
98808
|
+
// Apply to the mesh's own material
|
|
98809
|
+
applyToMaterial(mesh.material);
|
|
98810
|
+
// Apply to materials of direct child meshes recursively (optional, depending on need)
|
|
98811
|
+
// If you only want direct children, use getChildMeshes(true)
|
|
98812
|
+
// If you want all descendants, use getChildMeshes(false) - potentially expensive
|
|
98813
|
+
const children = mesh.getChildMeshes ? mesh.getChildMeshes(true) : []; // Direct children only
|
|
98814
|
+
children.forEach(childMesh => {
|
|
98815
|
+
applyOpacityToMeshAndChildren(childMesh, opacity); // Recursive call
|
|
98816
|
+
});
|
|
98817
|
+
}
|
|
98818
|
+
|
|
98819
|
+
/**
|
|
98820
|
+
* Initializes the BabylonJS Engine and Scene.
|
|
98821
|
+
* Attempts to use WebGPU first, falling back to WebGL2.
|
|
98822
|
+
* @param canvas - The HTML canvas element to render to.
|
|
98823
|
+
* @param data - The StorySplat data containing scene properties.
|
|
98824
|
+
* @param options - Viewer configuration options.
|
|
98825
|
+
* @returns A promise resolving with the initialized engine and scene, or rejecting on failure.
|
|
98826
|
+
*/
|
|
98827
|
+
async function initializeSceneAndEngine(canvas, data, options // Allow passing disableWebGPU internally
|
|
98828
|
+
) {
|
|
98829
|
+
var _a;
|
|
98830
|
+
// Ensure canvas fills its container
|
|
98831
|
+
canvas.style.width = '100%';
|
|
98832
|
+
canvas.style.height = '100%';
|
|
98833
|
+
canvas.style.display = 'block';
|
|
98834
|
+
canvas.style.verticalAlign = 'bottom'; // Prevent extra space below canvas
|
|
98835
|
+
let engine;
|
|
98836
|
+
const disableWebGPU = (_a = options === null || options === void 0 ? void 0 : options.disableWebGPU) !== null && _a !== void 0 ? _a : false;
|
|
98837
|
+
if (disableWebGPU) {
|
|
98838
|
+
// Force WebGL2
|
|
98839
|
+
try {
|
|
98840
|
+
engine = new Engine(canvas, true);
|
|
98841
|
+
console.log("StorySplat Viewer: WebGPU disabled by option, using WebGL2.");
|
|
98842
|
+
}
|
|
98843
|
+
catch (err) {
|
|
98844
|
+
console.error("StorySplat Viewer: Failed to initialize WebGL2 engine:", err);
|
|
98845
|
+
throw new Error("Failed to initialize WebGL2 engine.");
|
|
98846
|
+
}
|
|
98847
|
+
}
|
|
98848
|
+
else {
|
|
98849
|
+
// Try WebGPU first, then fallback
|
|
98850
|
+
try {
|
|
98851
|
+
// Check if running in a secure context, required for WebGPU
|
|
98852
|
+
if (!window.isSecureContext) {
|
|
98853
|
+
throw new Error("WebGPU requires a secure context (HTTPS or localhost).");
|
|
98854
|
+
}
|
|
98855
|
+
if (WebGPUEngine && WebGPUEngine.IsSupportedAsync) {
|
|
98856
|
+
const supported = await WebGPUEngine.IsSupportedAsync;
|
|
98857
|
+
if (supported) {
|
|
98858
|
+
const webgpuEngine = new WebGPUEngine(canvas, {
|
|
98859
|
+
// Explicitly request high-performance adapter
|
|
98860
|
+
powerPreference: "high-performance",
|
|
98861
|
+
// Enable validation in development environments if needed
|
|
98862
|
+
// enableAllFeatures: true // Use cautiously, might impact performance
|
|
98863
|
+
});
|
|
98864
|
+
await webgpuEngine.initAsync();
|
|
98865
|
+
engine = webgpuEngine; // Use double assertion
|
|
98866
|
+
console.log("StorySplat Viewer: WebGPU engine initialized.");
|
|
98867
|
+
}
|
|
98868
|
+
else {
|
|
98869
|
+
throw new Error("WebGPU is not supported on this browser/device.");
|
|
98870
|
+
}
|
|
98871
|
+
}
|
|
98872
|
+
else {
|
|
98873
|
+
throw new Error("WebGPUEngine not available or IsSupportedAsync missing.");
|
|
98874
|
+
}
|
|
98875
|
+
}
|
|
98876
|
+
catch (err) {
|
|
98877
|
+
// Fallback to WebGL2 if WebGPU fails or is unavailable
|
|
98878
|
+
console.warn("StorySplat Viewer: WebGPU unavailable or initialization failed, falling back to WebGL2:", err);
|
|
98879
|
+
try {
|
|
98880
|
+
engine = new Engine(canvas, true, {
|
|
98881
|
+
// Options for WebGL engine if needed
|
|
98882
|
+
// preserveDrawingBuffer: true, // Example option
|
|
98883
|
+
// stencil: true
|
|
98884
|
+
});
|
|
98885
|
+
console.log("StorySplat Viewer: Initialized WebGL2 engine as fallback.");
|
|
98886
|
+
}
|
|
98887
|
+
catch (webglErr) {
|
|
98888
|
+
console.error("StorySplat Viewer: Failed to initialize WebGL2 engine as fallback:", webglErr);
|
|
98889
|
+
throw new Error("Failed to initialize WebGL2 engine as fallback.");
|
|
98890
|
+
}
|
|
98891
|
+
}
|
|
98892
|
+
}
|
|
98893
|
+
if (!engine) {
|
|
98894
|
+
throw new Error("Failed to initialize any Babylon engine.");
|
|
98895
|
+
}
|
|
98896
|
+
const scene = new Scene(engine);
|
|
98897
|
+
// Set transparent clear color for HTML mesh compatibility
|
|
98898
|
+
scene.clearColor = new Color4(0, 0, 0, 0);
|
|
98899
|
+
// Create background sphere for background color when no skybox is active
|
|
98900
|
+
const defaultBgColor = new Color3(0.12, 0.12, 0.12); // Dark gray background to match HTML exports
|
|
98901
|
+
let bgColor;
|
|
98902
|
+
const bgColorOption = options === null || options === void 0 ? void 0 : options.backgroundColor; // Options still use {r,g,b,a} format
|
|
98903
|
+
if (bgColorOption) {
|
|
98904
|
+
const color4 = toColor4(bgColorOption, new Color4(defaultBgColor.r, defaultBgColor.g, defaultBgColor.b, 1));
|
|
98905
|
+
bgColor = new Color3(color4.r, color4.g, color4.b);
|
|
98906
|
+
}
|
|
98907
|
+
else if (data.backgroundColor) {
|
|
98908
|
+
bgColor = hexToColor3(data.backgroundColor, defaultBgColor);
|
|
98909
|
+
}
|
|
98910
|
+
else {
|
|
98911
|
+
bgColor = defaultBgColor;
|
|
98912
|
+
}
|
|
98913
|
+
// Store the background color for later use
|
|
98914
|
+
scene._backgroundColor = bgColor;
|
|
98915
|
+
// Create default background color skybox
|
|
98916
|
+
const skyboxMesh = MeshBuilder.CreateBox("backgroundColorSkybox", {
|
|
98917
|
+
size: 1000,
|
|
98918
|
+
sideOrientation: Mesh.BACKSIDE
|
|
98919
|
+
}, scene);
|
|
98920
|
+
const skyboxMaterial = new StandardMaterial("backgroundColorMaterial", scene);
|
|
98921
|
+
skyboxMaterial.disableLighting = true;
|
|
98922
|
+
skyboxMaterial.emissiveColor = bgColor;
|
|
98923
|
+
skyboxMaterial.backFaceCulling = false;
|
|
98924
|
+
skyboxMaterial.reflectionTexture = null;
|
|
98925
|
+
skyboxMaterial.diffuseColor = new Color3(0, 0, 0);
|
|
98926
|
+
skyboxMaterial.specularColor = new Color3(0, 0, 0);
|
|
98927
|
+
skyboxMesh.material = skyboxMaterial;
|
|
98928
|
+
skyboxMesh.infiniteDistance = true;
|
|
98929
|
+
skyboxMesh.isPickable = false;
|
|
98930
|
+
skyboxMesh.renderingGroupId = 0;
|
|
98931
|
+
// Apply rotation if provided in data
|
|
98932
|
+
if (data.skyboxRotation !== undefined && typeof data.skyboxRotation === 'number') {
|
|
98933
|
+
skyboxMesh.rotation.y = data.skyboxRotation;
|
|
98934
|
+
}
|
|
98935
|
+
scene._backgroundColorSkybox = skyboxMesh;
|
|
98936
|
+
// Ambient color is typically handled by lights (e.g., HemisphericLight groundColor)
|
|
98937
|
+
// Removing direct ambientColor setting from sceneProperties
|
|
98938
|
+
// Set a default ambient if needed, but lightingManager should handle specifics
|
|
98939
|
+
scene.ambientColor = new Color3(0.2, 0.2, 0.2); // Default dim ambient
|
|
98940
|
+
// Add resize listener
|
|
98941
|
+
const resizeHandler = () => {
|
|
98942
|
+
engine.resize();
|
|
98943
|
+
};
|
|
98944
|
+
window.addEventListener("resize", resizeHandler);
|
|
98945
|
+
// Add a cleanup function to the scene context
|
|
98946
|
+
scene.onDisposeObservable.addOnce(() => {
|
|
98947
|
+
console.log("StorySplat Viewer: Disposing scene, removing resize listener.");
|
|
98948
|
+
window.removeEventListener("resize", resizeHandler);
|
|
98949
|
+
// Engine disposal is handled separately in the destroy function
|
|
98950
|
+
});
|
|
98951
|
+
return { engine, scene };
|
|
98952
|
+
}
|
|
98953
|
+
|
|
98954
|
+
// Removed import for shared wheelHandler
|
|
98955
|
+
const DEFAULT_CAMERA_POSITION = new Vector3(0, 1.6, -5);
|
|
98956
|
+
const DEFAULT_CAMERA_TARGET = Vector3.Zero();
|
|
98957
|
+
const DEFAULT_FOV = 0.8;
|
|
98958
|
+
const DEFAULT_MIN_Z = 0.1;
|
|
98959
|
+
const DEFAULT_MAX_Z = 1000;
|
|
98960
|
+
const DEFAULT_SPEED = 0.1;
|
|
98961
|
+
const DEFAULT_INERTIA = 0.9;
|
|
98962
|
+
const DEFAULT_ANGULAR_SENSIBILITY = 2000;
|
|
98963
|
+
// Removed DEFAULT_WHEEL_DELTA_PERCENTAGE and DEFAULT_WHEEL_STEP as they are handled by shared handler or options
|
|
98964
|
+
// Walk Mode Defaults
|
|
98965
|
+
const DEFAULT_APPLY_GRAVITY = true;
|
|
98966
|
+
const DEFAULT_ELLIPSOID = new Vector3(0.5, 0.9, 0.5);
|
|
98967
|
+
const DEFAULT_GRAVITY = -9.81;
|
|
98968
|
+
class CameraManager {
|
|
98969
|
+
constructor(canvas, scene, data, options, // Correct options parameter
|
|
98970
|
+
analyticsManager // Correct analyticsManager parameter
|
|
98971
|
+
) {
|
|
98972
|
+
var _a, _b, _c;
|
|
98973
|
+
this._camera = null;
|
|
98974
|
+
this._currentMode = 'explore';
|
|
98975
|
+
this._uiManager = null; // Add UIManager reference
|
|
98976
|
+
this._analyticsManager = null; // Add AnalyticsManager reference
|
|
98977
|
+
this._canvas = canvas;
|
|
98978
|
+
this._scene = scene;
|
|
98979
|
+
this._data = data; // Store data object
|
|
98980
|
+
this._viewerOptions = options;
|
|
98981
|
+
this._analyticsManager = analyticsManager || null; // Store analytics manager
|
|
98982
|
+
// this._uiManager = uiManager || null; // Don't store here initially
|
|
98983
|
+
this._isMobile = isMobileDevice();
|
|
98984
|
+
this._initializeCamera();
|
|
98985
|
+
// Prioritize initial mode from data, then options, then default to 'explore'
|
|
98986
|
+
const initialMode = (_c = (_a = this._data.initialCameraMode) !== null && _a !== void 0 ? _a : (_b = this._viewerOptions) === null || _b === void 0 ? void 0 : _b.defaultCameraMode) !== null && _c !== void 0 ? _c : 'explore';
|
|
98987
|
+
this.setCameraMode(initialMode, true); // Assert type as CameraMode
|
|
98988
|
+
this._setupSceneDispose();
|
|
98989
|
+
// Removed _setupCustomWheelInput call
|
|
98990
|
+
}
|
|
98991
|
+
get camera() {
|
|
98992
|
+
return this._camera;
|
|
98993
|
+
}
|
|
98994
|
+
get currentMode() {
|
|
98995
|
+
return this._currentMode;
|
|
98996
|
+
}
|
|
98997
|
+
_initializeCamera() {
|
|
98998
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
|
|
98999
|
+
let initialPosition = DEFAULT_CAMERA_POSITION;
|
|
99000
|
+
let initialRotation = undefined; // Use rotation instead of target
|
|
99001
|
+
// Try to get initial pose from the first waypoint
|
|
99002
|
+
const firstWaypoint = (_a = this._data.waypoints) === null || _a === void 0 ? void 0 : _a[0];
|
|
99003
|
+
if (firstWaypoint) {
|
|
99004
|
+
initialPosition = new Vector3(firstWaypoint.x, firstWaypoint.y, firstWaypoint.z);
|
|
99005
|
+
initialRotation = toQuaternion(firstWaypoint.rotation); // Use helper
|
|
99006
|
+
}
|
|
99007
|
+
this._camera = new UniversalCamera("viewerCamera", initialPosition, this._scene);
|
|
99008
|
+
// Set initial rotation if derived from waypoint, otherwise set default target
|
|
99009
|
+
if (initialRotation) {
|
|
99010
|
+
this._camera.rotationQuaternion = initialRotation;
|
|
99011
|
+
}
|
|
99012
|
+
else {
|
|
99013
|
+
this._camera.setTarget(DEFAULT_CAMERA_TARGET);
|
|
99014
|
+
}
|
|
99015
|
+
// --- Add Standard Inputs ---
|
|
99016
|
+
this._camera.inputs.addKeyboard();
|
|
99017
|
+
this._camera.inputs.addMouse();
|
|
99018
|
+
if (this._isMobile) {
|
|
99019
|
+
this._camera.inputs.addTouch();
|
|
99020
|
+
}
|
|
99021
|
+
// Keyboard bindings need to be set *after* inputs are added
|
|
99022
|
+
this._setKeyboardInputs();
|
|
99023
|
+
// --- Apply Common Settings ---
|
|
99024
|
+
// Get settings from data (StorySplatData) or options (ViewerOptions)
|
|
99025
|
+
this._camera.fov = (_b = this._data.fov) !== null && _b !== void 0 ? _b : DEFAULT_FOV; // FOV comes from data only
|
|
99026
|
+
this._camera.minZ = (_e = (_d = (_c = this._viewerOptions) === null || _c === void 0 ? void 0 : _c.cameraMinZ) !== null && _d !== void 0 ? _d : this._data.minClipPlane) !== null && _e !== void 0 ? _e : DEFAULT_MIN_Z; // Use minClipPlane from data
|
|
99027
|
+
this._camera.maxZ = (_h = (_g = (_f = this._viewerOptions) === null || _f === void 0 ? void 0 : _f.cameraMaxZ) !== null && _g !== void 0 ? _g : this._data.maxClipPlane) !== null && _h !== void 0 ? _h : DEFAULT_MAX_Z; // Use maxClipPlane from data
|
|
99028
|
+
this._camera.speed = (_l = (_k = (_j = this._viewerOptions) === null || _j === void 0 ? void 0 : _j.cameraSpeed) !== null && _k !== void 0 ? _k : this._data.cameraMovementSpeed) !== null && _l !== void 0 ? _l : DEFAULT_SPEED; // Use cameraMovementSpeed from data
|
|
99029
|
+
this._camera.inertia = (_o = (_m = this._viewerOptions) === null || _m === void 0 ? void 0 : _m.cameraInertia) !== null && _o !== void 0 ? _o : DEFAULT_INERTIA; // Inertia likely only in options
|
|
99030
|
+
// Map cameraRotationSensitivity from data to angularSensibility if options don't provide it
|
|
99031
|
+
const angularSensibility = (_q = (_p = this._viewerOptions) === null || _p === void 0 ? void 0 : _p.cameraAngularSensibility) !== null && _q !== void 0 ? _q : (this._data.cameraRotationSensitivity ? (DEFAULT_ANGULAR_SENSIBILITY / (this._data.cameraRotationSensitivity / 4000)) : DEFAULT_ANGULAR_SENSIBILITY); // Simple scaling based on default
|
|
99032
|
+
this._camera.angularSensibility = angularSensibility;
|
|
99033
|
+
this._camera.touchAngularSensibility = (_s = (_r = this._viewerOptions) === null || _r === void 0 ? void 0 : _r.cameraTouchAngularSensibility) !== null && _s !== void 0 ? _s : angularSensibility; // Use same sensitivity for touch by default
|
|
99034
|
+
// Apply Y-axis inversion by negating sensitivity if needed
|
|
99035
|
+
const shouldInvert = (_v = (_u = (_t = this._viewerOptions) === null || _t === void 0 ? void 0 : _t.invertCameraRotation) !== null && _u !== void 0 ? _u : this._data.invertCameraRotation) !== null && _v !== void 0 ? _v : false;
|
|
99036
|
+
if (shouldInvert) {
|
|
99037
|
+
this._camera.angularSensibility *= -1;
|
|
99038
|
+
this._camera.touchAngularSensibility *= -1;
|
|
99039
|
+
console.log("StorySplat Viewer: Inverting camera Y-axis rotation.");
|
|
99040
|
+
}
|
|
99041
|
+
// --- Wheel Input ---
|
|
99042
|
+
// Default wheel input is now used unless options customize it elsewhere.
|
|
99043
|
+
// No need to remove default or handle custom wheel here.
|
|
99044
|
+
// Initial collision/gravity state
|
|
99045
|
+
this._camera.checkCollisions = false;
|
|
99046
|
+
this._camera.applyGravity = false;
|
|
99047
|
+
// Ellipsoid primarily from options
|
|
99048
|
+
this._camera.ellipsoid = ((_w = this._viewerOptions) === null || _w === void 0 ? void 0 : _w.cameraEllipsoid) ? toVector3(this._viewerOptions.cameraEllipsoid) : DEFAULT_ELLIPSOID.clone();
|
|
99049
|
+
// Gravity primarily from options
|
|
99050
|
+
const sceneGravityY = (_y = (_x = this._scene.gravity) === null || _x === void 0 ? void 0 : _x.y) !== null && _y !== void 0 ? _y : ((_0 = (_z = this._viewerOptions) === null || _z === void 0 ? void 0 : _z.gravity) !== null && _0 !== void 0 ? _0 : DEFAULT_GRAVITY);
|
|
99051
|
+
this._scene.gravity = new Vector3(0, sceneGravityY, 0);
|
|
99052
|
+
// Enable scene collisions if needed - removed checks for _initialSettings
|
|
99053
|
+
if (((_2 = (_1 = this._viewerOptions) === null || _1 === void 0 ? void 0 : _1.allowedCameraModes) === null || _2 === void 0 ? void 0 : _2.includes('walk')) ||
|
|
99054
|
+
((_3 = this._viewerOptions) === null || _3 === void 0 ? void 0 : _3.defaultCameraMode) === 'walk' ||
|
|
99055
|
+
((_4 = this._viewerOptions) === null || _4 === void 0 ? void 0 : _4.exploreCollisions) ||
|
|
99056
|
+
((_5 = this._viewerOptions) === null || _5 === void 0 ? void 0 : _5.walkCollisions) ||
|
|
99057
|
+
((_6 = this._viewerOptions) === null || _6 === void 0 ? void 0 : _6.cameraEllipsoid) || // Check if ellipsoid is defined in options
|
|
99058
|
+
this._scene.collisionsEnabled) {
|
|
99059
|
+
this._scene.collisionsEnabled = true;
|
|
99060
|
+
console.log("StorySplat Viewer: Scene collisions enabled for camera.");
|
|
99061
|
+
}
|
|
99062
|
+
}
|
|
99063
|
+
setCameraMode(mode, immediate = false) {
|
|
99064
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
99065
|
+
if (!this._camera)
|
|
99066
|
+
return;
|
|
99067
|
+
const allowedModes = (_b = (_a = this._viewerOptions) === null || _a === void 0 ? void 0 : _a.allowedCameraModes) !== null && _b !== void 0 ? _b : ['explore', 'walk', 'tour', 'hybrid'];
|
|
99068
|
+
if (!allowedModes.includes(mode)) {
|
|
99069
|
+
console.warn(`StorySplat Viewer: Camera mode "${mode}" is not allowed by options. Allowed: [${allowedModes.join(', ')}]`);
|
|
99070
|
+
return;
|
|
99071
|
+
}
|
|
99072
|
+
const oldMode = this._currentMode;
|
|
99073
|
+
if (oldMode === mode && !immediate)
|
|
99074
|
+
return;
|
|
99075
|
+
console.log(`StorySplat Viewer: Setting camera mode to ${mode}`);
|
|
99076
|
+
this._currentMode = mode;
|
|
99077
|
+
// Detach controls before reconfiguring
|
|
99078
|
+
this._camera.detachControl();
|
|
99079
|
+
// Reset mode-specific properties
|
|
99080
|
+
this._camera.checkCollisions = false;
|
|
99081
|
+
this._camera.applyGravity = false;
|
|
99082
|
+
// Inputs are now added during initialization and persist.
|
|
99083
|
+
// No need to remove/re-add input types here.
|
|
99084
|
+
// detachControl/attachControl handles focus.
|
|
99085
|
+
switch (mode) {
|
|
99086
|
+
case 'explore':
|
|
99087
|
+
this._configureExploreMode();
|
|
99088
|
+
break;
|
|
99089
|
+
case 'walk':
|
|
99090
|
+
this._configureWalkMode();
|
|
99091
|
+
break;
|
|
99092
|
+
case 'tour':
|
|
99093
|
+
case 'hybrid':
|
|
99094
|
+
this._configureTourMode();
|
|
99095
|
+
break;
|
|
99096
|
+
default:
|
|
99097
|
+
console.warn(`StorySplat Viewer: Unknown camera mode "${mode}". Defaulting to explore.`);
|
|
99098
|
+
this._configureExploreMode();
|
|
99099
|
+
this._currentMode = 'explore';
|
|
99100
|
+
}
|
|
99101
|
+
// Re-attach controls if globally enabled
|
|
99102
|
+
if (((_c = this._viewerOptions) === null || _c === void 0 ? void 0 : _c.cameraControls) !== false) {
|
|
99103
|
+
this._camera.attachControl(this._canvas, true);
|
|
99104
|
+
// Removed DEBUG log
|
|
99105
|
+
// Inputs are added during initialization, attachControl manages focus.
|
|
99106
|
+
}
|
|
99107
|
+
else {
|
|
99108
|
+
console.log("StorySplat Viewer: Camera controls globally disabled by options.");
|
|
99109
|
+
// No activation needed if controls are disabled
|
|
99110
|
+
}
|
|
99111
|
+
// Trigger callback and update UI
|
|
99112
|
+
if (oldMode !== mode) {
|
|
99113
|
+
(_e = (_d = this._viewerOptions) === null || _d === void 0 ? void 0 : _d.onCameraModeChanged) === null || _e === void 0 ? void 0 : _e.call(_d, mode);
|
|
99114
|
+
(_f = this.onCameraModeChange) === null || _f === void 0 ? void 0 : _f.call(this, mode); // Call the new callback
|
|
99115
|
+
(_g = this._analyticsManager) === null || _g === void 0 ? void 0 : _g.trackCameraModeChange(oldMode, mode); // Track event
|
|
99116
|
+
this._updateUIManager(); // Notify UI Manager of the change
|
|
99117
|
+
}
|
|
98993
99118
|
}
|
|
98994
|
-
|
|
98995
|
-
|
|
98996
|
-
|
|
98997
|
-
|
|
98998
|
-
|
|
99119
|
+
_configureExploreMode() {
|
|
99120
|
+
var _a, _b;
|
|
99121
|
+
if (!this._camera)
|
|
99122
|
+
return;
|
|
99123
|
+
this._camera.checkCollisions = (_b = (_a = this._viewerOptions) === null || _a === void 0 ? void 0 : _a.exploreCollisions) !== null && _b !== void 0 ? _b : false;
|
|
99124
|
+
this._camera.applyGravity = false;
|
|
99125
|
+
// Inputs are now managed globally during initialization.
|
|
99126
|
+
// This method only sets mode-specific camera properties.
|
|
99127
|
+
console.log("Explore mode configured: Collisions=" + this._camera.checkCollisions);
|
|
98999
99128
|
}
|
|
99000
|
-
|
|
99001
|
-
|
|
99129
|
+
_configureWalkMode() {
|
|
99130
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
99131
|
+
if (!this._camera)
|
|
99132
|
+
return;
|
|
99133
|
+
this._camera.checkCollisions = (_b = (_a = this._viewerOptions) === null || _a === void 0 ? void 0 : _a.walkCollisions) !== null && _b !== void 0 ? _b : true;
|
|
99134
|
+
this._camera.applyGravity = (_d = (_c = this._viewerOptions) === null || _c === void 0 ? void 0 : _c.walkApplyGravity) !== null && _d !== void 0 ? _d : DEFAULT_APPLY_GRAVITY;
|
|
99135
|
+
// Gravity primarily from options
|
|
99136
|
+
const sceneGravityY = (_f = (_e = this._viewerOptions) === null || _e === void 0 ? void 0 : _e.gravity) !== null && _f !== void 0 ? _f : DEFAULT_GRAVITY; // Already checks options
|
|
99137
|
+
this._scene.gravity = new Vector3(0, sceneGravityY, 0);
|
|
99138
|
+
// Ellipsoid primarily from options
|
|
99139
|
+
this._camera.ellipsoid = ((_g = this._viewerOptions) === null || _g === void 0 ? void 0 : _g.cameraEllipsoid) ? toVector3(this._viewerOptions.cameraEllipsoid) : DEFAULT_ELLIPSOID.clone(); // Already checks options
|
|
99140
|
+
// Inputs are now managed globally during initialization.
|
|
99141
|
+
// This method only sets mode-specific camera properties.
|
|
99142
|
+
console.log(`Walk mode configured: Gravity=${this._camera.applyGravity}, Collisions=${this._camera.checkCollisions}`);
|
|
99002
99143
|
}
|
|
99003
|
-
|
|
99004
|
-
|
|
99005
|
-
|
|
99006
|
-
|
|
99007
|
-
|
|
99144
|
+
_configureTourMode() {
|
|
99145
|
+
if (!this._camera)
|
|
99146
|
+
return;
|
|
99147
|
+
this._camera.checkCollisions = false;
|
|
99148
|
+
this._camera.applyGravity = false;
|
|
99149
|
+
// Inputs are now managed globally during initialization.
|
|
99150
|
+
// Mouse/Touch rotation is handled by the default inputs added earlier.
|
|
99151
|
+
// This method only sets mode-specific camera properties.
|
|
99152
|
+
console.log("Tour/Hybrid mode configured: No gravity, no collisions.");
|
|
99008
99153
|
}
|
|
99009
|
-
|
|
99010
|
-
|
|
99154
|
+
// Helper to set standard keyboard bindings
|
|
99155
|
+
_setKeyboardInputs() {
|
|
99156
|
+
if (!this._camera)
|
|
99157
|
+
return;
|
|
99158
|
+
const input = this._camera.inputs.attached.keyboard; // Use specific type
|
|
99159
|
+
if (input) {
|
|
99160
|
+
// Clear existing potentially conflicting bindings (optional but safer)
|
|
99161
|
+
input.keysUp = [];
|
|
99162
|
+
input.keysDown = [];
|
|
99163
|
+
input.keysLeft = [];
|
|
99164
|
+
input.keysRight = [];
|
|
99165
|
+
input.keysUpward = [];
|
|
99166
|
+
input.keysDownward = [];
|
|
99167
|
+
// Standard WASD / Arrow Keys
|
|
99168
|
+
input.keysUp.push(87, 38); // W, Up Arrow
|
|
99169
|
+
input.keysDown.push(83, 40); // S, Down Arrow
|
|
99170
|
+
input.keysLeft.push(65, 37); // A, Left Arrow
|
|
99171
|
+
input.keysRight.push(68, 39); // D, Right Arrow
|
|
99172
|
+
// Add Q/E for vertical movement
|
|
99173
|
+
input.keysUpward = [69]; // E key for up
|
|
99174
|
+
input.keysDownward = [81]; // Q key for down
|
|
99175
|
+
}
|
|
99011
99176
|
}
|
|
99012
|
-
|
|
99013
|
-
|
|
99014
|
-
|
|
99015
|
-
|
|
99016
|
-
|
|
99177
|
+
// --- Custom Mouse Wheel Input Handling Removed ---
|
|
99178
|
+
// The default FreeCameraMouseWheelInput is now used.
|
|
99179
|
+
_setupSceneDispose() {
|
|
99180
|
+
this._scene.onDisposeObservable.addOnce(() => {
|
|
99181
|
+
console.log("StorySplat Viewer: Disposing camera manager and camera.");
|
|
99182
|
+
// No need to remove custom wheel listener anymore
|
|
99183
|
+
this._camera = null;
|
|
99184
|
+
});
|
|
99017
99185
|
}
|
|
99018
|
-
|
|
99019
|
-
|
|
99186
|
+
// --- UI Update Helper ---
|
|
99187
|
+
_updateUIManager() {
|
|
99188
|
+
if (!this._uiManager)
|
|
99189
|
+
return;
|
|
99190
|
+
this._uiManager.updateModeToggleButtons();
|
|
99191
|
+
this._uiManager.updateExploreWalkToggleButtons();
|
|
99192
|
+
this._uiManager.updateScrollControlsVisibility();
|
|
99020
99193
|
}
|
|
99021
|
-
|
|
99022
|
-
|
|
99023
|
-
|
|
99024
|
-
|
|
99025
|
-
|
|
99194
|
+
// --- Public API Methods ---
|
|
99195
|
+
// Method to set the UIManager after instantiation
|
|
99196
|
+
setUIManager(uiManager) {
|
|
99197
|
+
this._uiManager = uiManager;
|
|
99198
|
+
// Update UI immediately after manager is set
|
|
99199
|
+
this._updateUIManager();
|
|
99026
99200
|
}
|
|
99027
|
-
|
|
99028
|
-
|
|
99201
|
+
setPosition(position) {
|
|
99202
|
+
if (this._camera) {
|
|
99203
|
+
this._camera.position = position;
|
|
99204
|
+
}
|
|
99029
99205
|
}
|
|
99030
|
-
|
|
99031
|
-
|
|
99032
|
-
|
|
99033
|
-
|
|
99034
|
-
return MaterialFlags.ColorGradingTextureEnabled;
|
|
99206
|
+
setTarget(target) {
|
|
99207
|
+
if (this._camera) {
|
|
99208
|
+
this._camera.setTarget(target);
|
|
99209
|
+
}
|
|
99035
99210
|
}
|
|
99036
|
-
|
|
99037
|
-
|
|
99211
|
+
}
|
|
99212
|
+
|
|
99213
|
+
// Import necessary loaders for .splat files (assuming it uses GLTF internally or a custom loader is registered)
|
|
99214
|
+
// If @babylonjs/loaders is needed and not globally imported, ensure it's imported somewhere,
|
|
99215
|
+
// e.g., in the main index.ts or here. For now, assume SceneLoader handles it.
|
|
99216
|
+
// import "@babylonjs/loaders/glTF"; // Example if GLTF loader is needed explicitly
|
|
99217
|
+
/**
|
|
99218
|
+
* Loads the primary Gaussian Splat asset into the scene.
|
|
99219
|
+
* @param scene - The BabylonJS scene to load the asset into.
|
|
99220
|
+
* @param data - The StorySplat data containing the model URL and scaling info.
|
|
99221
|
+
* @param onProgress - Optional callback function to report loading progress.
|
|
99222
|
+
* Receives percentage (0-100) and an optional status text.
|
|
99223
|
+
* @returns A promise that resolves with an array of the loaded AbstractMesh objects.
|
|
99224
|
+
*/
|
|
99225
|
+
async function loadSplatAsset(scene, data, onProgress // Updated signature
|
|
99226
|
+
) {
|
|
99227
|
+
var _a, _b, _c, _d, _e;
|
|
99228
|
+
const modelUrl = data.loadedModelUrl; // Changed from modelUrl
|
|
99229
|
+
if (!modelUrl) {
|
|
99230
|
+
console.error("StorySplat Viewer: No loadedModelUrl provided in data.");
|
|
99231
|
+
return Promise.reject(new Error("No loadedModelUrl provided in StorySplatData."));
|
|
99038
99232
|
}
|
|
99039
|
-
|
|
99040
|
-
|
|
99041
|
-
|
|
99042
|
-
|
|
99043
|
-
|
|
99233
|
+
const splatScale = (_a = data.splatScale) !== null && _a !== void 0 ? _a : 1.0;
|
|
99234
|
+
const invertX = (_b = data.invertXScale) !== null && _b !== void 0 ? _b : false;
|
|
99235
|
+
const invertY = (_c = data.invertYScale) !== null && _c !== void 0 ? _c : false;
|
|
99236
|
+
const position = (_d = data.splatPosition) !== null && _d !== void 0 ? _d : [0, 0, 0];
|
|
99237
|
+
const rotation = (_e = data.splatRotation) !== null && _e !== void 0 ? _e : [0, 0, 0];
|
|
99238
|
+
console.log(`StorySplat Viewer: Loading splat asset from ${modelUrl}`);
|
|
99239
|
+
try {
|
|
99240
|
+
// Debug: Check what loaders are registered
|
|
99241
|
+
console.log("StorySplat Viewer: Available SceneLoader plugins:", Object.keys(SceneLoader._RegisteredPlugins || {}));
|
|
99242
|
+
const result = await SceneLoader.ImportMeshAsync("", // meshNames - empty string loads all
|
|
99243
|
+
modelUrl, // rootUrl - the full URL
|
|
99244
|
+
"", // sceneFilename - empty when using full URL
|
|
99245
|
+
scene, (progressEvent) => {
|
|
99246
|
+
if (onProgress) {
|
|
99247
|
+
// Calculate percentage, handle indeterminate state
|
|
99248
|
+
let percentage = 0;
|
|
99249
|
+
if (progressEvent.lengthComputable && progressEvent.total > 0) {
|
|
99250
|
+
percentage = (progressEvent.loaded / progressEvent.total) * 100;
|
|
99251
|
+
}
|
|
99252
|
+
else if (progressEvent.loaded > 0) {
|
|
99253
|
+
// If not lengthComputable but loaded > 0, maybe indicate activity?
|
|
99254
|
+
// This part is tricky without total size. Could use a spinner state.
|
|
99255
|
+
// For simplicity, we'll report 0 or the calculated percentage.
|
|
99256
|
+
}
|
|
99257
|
+
// Report percentage and potentially a status text
|
|
99258
|
+
const statusText = progressEvent.lengthComputable ? `${(progressEvent.loaded / 1024 / 1024).toFixed(2)}MB / ${(progressEvent.total / 1024 / 1024).toFixed(2)}MB` : 'Loading...';
|
|
99259
|
+
onProgress(Math.round(percentage), statusText);
|
|
99260
|
+
}
|
|
99261
|
+
});
|
|
99262
|
+
if (!result.meshes || result.meshes.length === 0) {
|
|
99263
|
+
throw new Error(`No meshes found in the loaded asset: ${modelUrl}`);
|
|
99264
|
+
}
|
|
99265
|
+
console.log(`StorySplat Viewer: Successfully loaded ${result.meshes.length} meshes from ${modelUrl}.`);
|
|
99266
|
+
result.meshes.forEach((mesh) => {
|
|
99267
|
+
// Ensure the mesh is visible and pickable
|
|
99268
|
+
mesh.isVisible = true;
|
|
99269
|
+
mesh.isPickable = true; // Important for interactions like hotspots if they attach to splats
|
|
99270
|
+
// Apply scaling and inversion
|
|
99271
|
+
const scaleX = splatScale * (invertX ? -1 : 1);
|
|
99272
|
+
const scaleY = splatScale * (invertY ? -1 : 1);
|
|
99273
|
+
// Invert Z if only one of X or Y is inverted to maintain handedness
|
|
99274
|
+
// If both inverted or neither inverted, Z scale matches splatScale sign
|
|
99275
|
+
const scaleZ = splatScale * ((invertX !== invertY) ? -1 : 1);
|
|
99276
|
+
mesh.scaling.set(scaleX, scaleY, scaleZ);
|
|
99277
|
+
mesh.position.set(position[0], position[1], position[2]);
|
|
99278
|
+
mesh.rotation.set(rotation[0], rotation[1], rotation[2]);
|
|
99279
|
+
// Optional: Set collision properties if needed later
|
|
99280
|
+
// mesh.checkCollisions = true; // Enable collisions if required
|
|
99281
|
+
// Optional: Assign a name based on the URL for easier identification
|
|
99282
|
+
mesh.name = `splatRoot_${modelUrl}`; // Name the root mesh if possible
|
|
99283
|
+
});
|
|
99284
|
+
// Add cleanup logic for the loaded meshes
|
|
99285
|
+
const loadedMeshes = result.meshes; // Capture the meshes in this scope
|
|
99286
|
+
const disposeObserver = scene.onDisposeObservable.addOnce(() => {
|
|
99287
|
+
console.log(`StorySplat Viewer: Disposing splat asset: ${modelUrl}`);
|
|
99288
|
+
loadedMeshes.forEach(mesh => {
|
|
99289
|
+
if (mesh && !mesh.isDisposed()) {
|
|
99290
|
+
// Check parentage - only dispose root nodes added by the loader?
|
|
99291
|
+
// Or dispose all meshes returned by the loader. Assuming the latter for now.
|
|
99292
|
+
mesh.dispose(false, true); // Dispose mesh, materials, textures
|
|
99293
|
+
}
|
|
99294
|
+
});
|
|
99295
|
+
});
|
|
99296
|
+
// Store the observer reference on the meshes or a manager if needed for explicit cleanup later
|
|
99297
|
+
// e.g., loadedMeshes[0].metadata = { disposeObserver };
|
|
99298
|
+
return loadedMeshes;
|
|
99044
99299
|
}
|
|
99045
|
-
|
|
99046
|
-
|
|
99300
|
+
catch (error) {
|
|
99301
|
+
console.error(`StorySplat Viewer: Error loading splat asset from ${modelUrl}:`, error);
|
|
99302
|
+
// Propagate the error
|
|
99303
|
+
throw error;
|
|
99047
99304
|
}
|
|
99048
99305
|
}
|
|
99049
|
-
/**
|
|
99050
|
-
* Force all the standard materials to compile to glsl even on WebGPU engines.
|
|
99051
|
-
* False by default. This is mostly meant for backward compatibility.
|
|
99052
|
-
*/
|
|
99053
|
-
StandardMaterial.ForceGLSL = false;
|
|
99054
|
-
__decorate([
|
|
99055
|
-
serializeAsTexture("diffuseTexture")
|
|
99056
|
-
], StandardMaterial.prototype, "_diffuseTexture", void 0);
|
|
99057
|
-
__decorate([
|
|
99058
|
-
expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
|
|
99059
|
-
], StandardMaterial.prototype, "diffuseTexture", void 0);
|
|
99060
|
-
__decorate([
|
|
99061
|
-
serializeAsTexture("ambientTexture")
|
|
99062
|
-
], StandardMaterial.prototype, "_ambientTexture", void 0);
|
|
99063
|
-
__decorate([
|
|
99064
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99065
|
-
], StandardMaterial.prototype, "ambientTexture", void 0);
|
|
99066
|
-
__decorate([
|
|
99067
|
-
serializeAsTexture("opacityTexture")
|
|
99068
|
-
], StandardMaterial.prototype, "_opacityTexture", void 0);
|
|
99069
|
-
__decorate([
|
|
99070
|
-
expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
|
|
99071
|
-
], StandardMaterial.prototype, "opacityTexture", void 0);
|
|
99072
|
-
__decorate([
|
|
99073
|
-
serializeAsTexture("reflectionTexture")
|
|
99074
|
-
], StandardMaterial.prototype, "_reflectionTexture", void 0);
|
|
99075
|
-
__decorate([
|
|
99076
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99077
|
-
], StandardMaterial.prototype, "reflectionTexture", void 0);
|
|
99078
|
-
__decorate([
|
|
99079
|
-
serializeAsTexture("emissiveTexture")
|
|
99080
|
-
], StandardMaterial.prototype, "_emissiveTexture", void 0);
|
|
99081
|
-
__decorate([
|
|
99082
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99083
|
-
], StandardMaterial.prototype, "emissiveTexture", void 0);
|
|
99084
|
-
__decorate([
|
|
99085
|
-
serializeAsTexture("specularTexture")
|
|
99086
|
-
], StandardMaterial.prototype, "_specularTexture", void 0);
|
|
99087
|
-
__decorate([
|
|
99088
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99089
|
-
], StandardMaterial.prototype, "specularTexture", void 0);
|
|
99090
|
-
__decorate([
|
|
99091
|
-
serializeAsTexture("bumpTexture")
|
|
99092
|
-
], StandardMaterial.prototype, "_bumpTexture", void 0);
|
|
99093
|
-
__decorate([
|
|
99094
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99095
|
-
], StandardMaterial.prototype, "bumpTexture", void 0);
|
|
99096
|
-
__decorate([
|
|
99097
|
-
serializeAsTexture("lightmapTexture")
|
|
99098
|
-
], StandardMaterial.prototype, "_lightmapTexture", void 0);
|
|
99099
|
-
__decorate([
|
|
99100
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99101
|
-
], StandardMaterial.prototype, "lightmapTexture", void 0);
|
|
99102
|
-
__decorate([
|
|
99103
|
-
serializeAsTexture("refractionTexture")
|
|
99104
|
-
], StandardMaterial.prototype, "_refractionTexture", void 0);
|
|
99105
|
-
__decorate([
|
|
99106
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99107
|
-
], StandardMaterial.prototype, "refractionTexture", void 0);
|
|
99108
|
-
__decorate([
|
|
99109
|
-
serializeAsColor3("ambient")
|
|
99110
|
-
], StandardMaterial.prototype, "ambientColor", void 0);
|
|
99111
|
-
__decorate([
|
|
99112
|
-
serializeAsColor3("diffuse")
|
|
99113
|
-
], StandardMaterial.prototype, "diffuseColor", void 0);
|
|
99114
|
-
__decorate([
|
|
99115
|
-
serializeAsColor3("specular")
|
|
99116
|
-
], StandardMaterial.prototype, "specularColor", void 0);
|
|
99117
|
-
__decorate([
|
|
99118
|
-
serializeAsColor3("emissive")
|
|
99119
|
-
], StandardMaterial.prototype, "emissiveColor", void 0);
|
|
99120
|
-
__decorate([
|
|
99121
|
-
serialize()
|
|
99122
|
-
], StandardMaterial.prototype, "specularPower", void 0);
|
|
99123
|
-
__decorate([
|
|
99124
|
-
serialize("useAlphaFromDiffuseTexture")
|
|
99125
|
-
], StandardMaterial.prototype, "_useAlphaFromDiffuseTexture", void 0);
|
|
99126
|
-
__decorate([
|
|
99127
|
-
expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
|
|
99128
|
-
], StandardMaterial.prototype, "useAlphaFromDiffuseTexture", void 0);
|
|
99129
|
-
__decorate([
|
|
99130
|
-
serialize("useEmissiveAsIllumination")
|
|
99131
|
-
], StandardMaterial.prototype, "_useEmissiveAsIllumination", void 0);
|
|
99132
|
-
__decorate([
|
|
99133
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99134
|
-
], StandardMaterial.prototype, "useEmissiveAsIllumination", void 0);
|
|
99135
|
-
__decorate([
|
|
99136
|
-
serialize("linkEmissiveWithDiffuse")
|
|
99137
|
-
], StandardMaterial.prototype, "_linkEmissiveWithDiffuse", void 0);
|
|
99138
|
-
__decorate([
|
|
99139
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99140
|
-
], StandardMaterial.prototype, "linkEmissiveWithDiffuse", void 0);
|
|
99141
|
-
__decorate([
|
|
99142
|
-
serialize("useSpecularOverAlpha")
|
|
99143
|
-
], StandardMaterial.prototype, "_useSpecularOverAlpha", void 0);
|
|
99144
|
-
__decorate([
|
|
99145
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99146
|
-
], StandardMaterial.prototype, "useSpecularOverAlpha", void 0);
|
|
99147
|
-
__decorate([
|
|
99148
|
-
serialize("useReflectionOverAlpha")
|
|
99149
|
-
], StandardMaterial.prototype, "_useReflectionOverAlpha", void 0);
|
|
99150
|
-
__decorate([
|
|
99151
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99152
|
-
], StandardMaterial.prototype, "useReflectionOverAlpha", void 0);
|
|
99153
|
-
__decorate([
|
|
99154
|
-
serialize("disableLighting")
|
|
99155
|
-
], StandardMaterial.prototype, "_disableLighting", void 0);
|
|
99156
|
-
__decorate([
|
|
99157
|
-
expandToProperty("_markAllSubMeshesAsLightsDirty")
|
|
99158
|
-
], StandardMaterial.prototype, "disableLighting", void 0);
|
|
99159
|
-
__decorate([
|
|
99160
|
-
serialize("useObjectSpaceNormalMap")
|
|
99161
|
-
], StandardMaterial.prototype, "_useObjectSpaceNormalMap", void 0);
|
|
99162
|
-
__decorate([
|
|
99163
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99164
|
-
], StandardMaterial.prototype, "useObjectSpaceNormalMap", void 0);
|
|
99165
|
-
__decorate([
|
|
99166
|
-
serialize("useParallax")
|
|
99167
|
-
], StandardMaterial.prototype, "_useParallax", void 0);
|
|
99168
|
-
__decorate([
|
|
99169
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99170
|
-
], StandardMaterial.prototype, "useParallax", void 0);
|
|
99171
|
-
__decorate([
|
|
99172
|
-
serialize("useParallaxOcclusion")
|
|
99173
|
-
], StandardMaterial.prototype, "_useParallaxOcclusion", void 0);
|
|
99174
|
-
__decorate([
|
|
99175
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99176
|
-
], StandardMaterial.prototype, "useParallaxOcclusion", void 0);
|
|
99177
|
-
__decorate([
|
|
99178
|
-
serialize()
|
|
99179
|
-
], StandardMaterial.prototype, "parallaxScaleBias", void 0);
|
|
99180
|
-
__decorate([
|
|
99181
|
-
serialize("roughness")
|
|
99182
|
-
], StandardMaterial.prototype, "_roughness", void 0);
|
|
99183
|
-
__decorate([
|
|
99184
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99185
|
-
], StandardMaterial.prototype, "roughness", void 0);
|
|
99186
|
-
__decorate([
|
|
99187
|
-
serialize()
|
|
99188
|
-
], StandardMaterial.prototype, "indexOfRefraction", void 0);
|
|
99189
|
-
__decorate([
|
|
99190
|
-
serialize()
|
|
99191
|
-
], StandardMaterial.prototype, "invertRefractionY", void 0);
|
|
99192
|
-
__decorate([
|
|
99193
|
-
serialize()
|
|
99194
|
-
], StandardMaterial.prototype, "alphaCutOff", void 0);
|
|
99195
|
-
__decorate([
|
|
99196
|
-
serialize("useLightmapAsShadowmap")
|
|
99197
|
-
], StandardMaterial.prototype, "_useLightmapAsShadowmap", void 0);
|
|
99198
|
-
__decorate([
|
|
99199
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99200
|
-
], StandardMaterial.prototype, "useLightmapAsShadowmap", void 0);
|
|
99201
|
-
__decorate([
|
|
99202
|
-
serializeAsFresnelParameters("diffuseFresnelParameters")
|
|
99203
|
-
], StandardMaterial.prototype, "_diffuseFresnelParameters", void 0);
|
|
99204
|
-
__decorate([
|
|
99205
|
-
expandToProperty("_markAllSubMeshesAsFresnelDirty")
|
|
99206
|
-
], StandardMaterial.prototype, "diffuseFresnelParameters", void 0);
|
|
99207
|
-
__decorate([
|
|
99208
|
-
serializeAsFresnelParameters("opacityFresnelParameters")
|
|
99209
|
-
], StandardMaterial.prototype, "_opacityFresnelParameters", void 0);
|
|
99210
|
-
__decorate([
|
|
99211
|
-
expandToProperty("_markAllSubMeshesAsFresnelAndMiscDirty")
|
|
99212
|
-
], StandardMaterial.prototype, "opacityFresnelParameters", void 0);
|
|
99213
|
-
__decorate([
|
|
99214
|
-
serializeAsFresnelParameters("reflectionFresnelParameters")
|
|
99215
|
-
], StandardMaterial.prototype, "_reflectionFresnelParameters", void 0);
|
|
99216
|
-
__decorate([
|
|
99217
|
-
expandToProperty("_markAllSubMeshesAsFresnelDirty")
|
|
99218
|
-
], StandardMaterial.prototype, "reflectionFresnelParameters", void 0);
|
|
99219
|
-
__decorate([
|
|
99220
|
-
serializeAsFresnelParameters("refractionFresnelParameters")
|
|
99221
|
-
], StandardMaterial.prototype, "_refractionFresnelParameters", void 0);
|
|
99222
|
-
__decorate([
|
|
99223
|
-
expandToProperty("_markAllSubMeshesAsFresnelDirty")
|
|
99224
|
-
], StandardMaterial.prototype, "refractionFresnelParameters", void 0);
|
|
99225
|
-
__decorate([
|
|
99226
|
-
serializeAsFresnelParameters("emissiveFresnelParameters")
|
|
99227
|
-
], StandardMaterial.prototype, "_emissiveFresnelParameters", void 0);
|
|
99228
|
-
__decorate([
|
|
99229
|
-
expandToProperty("_markAllSubMeshesAsFresnelDirty")
|
|
99230
|
-
], StandardMaterial.prototype, "emissiveFresnelParameters", void 0);
|
|
99231
|
-
__decorate([
|
|
99232
|
-
serialize("useReflectionFresnelFromSpecular")
|
|
99233
|
-
], StandardMaterial.prototype, "_useReflectionFresnelFromSpecular", void 0);
|
|
99234
|
-
__decorate([
|
|
99235
|
-
expandToProperty("_markAllSubMeshesAsFresnelDirty")
|
|
99236
|
-
], StandardMaterial.prototype, "useReflectionFresnelFromSpecular", void 0);
|
|
99237
|
-
__decorate([
|
|
99238
|
-
serialize("useGlossinessFromSpecularMapAlpha")
|
|
99239
|
-
], StandardMaterial.prototype, "_useGlossinessFromSpecularMapAlpha", void 0);
|
|
99240
|
-
__decorate([
|
|
99241
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99242
|
-
], StandardMaterial.prototype, "useGlossinessFromSpecularMapAlpha", void 0);
|
|
99243
|
-
__decorate([
|
|
99244
|
-
serialize("maxSimultaneousLights")
|
|
99245
|
-
], StandardMaterial.prototype, "_maxSimultaneousLights", void 0);
|
|
99246
|
-
__decorate([
|
|
99247
|
-
expandToProperty("_markAllSubMeshesAsLightsDirty")
|
|
99248
|
-
], StandardMaterial.prototype, "maxSimultaneousLights", void 0);
|
|
99249
|
-
__decorate([
|
|
99250
|
-
serialize("invertNormalMapX")
|
|
99251
|
-
], StandardMaterial.prototype, "_invertNormalMapX", void 0);
|
|
99252
|
-
__decorate([
|
|
99253
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99254
|
-
], StandardMaterial.prototype, "invertNormalMapX", void 0);
|
|
99255
|
-
__decorate([
|
|
99256
|
-
serialize("invertNormalMapY")
|
|
99257
|
-
], StandardMaterial.prototype, "_invertNormalMapY", void 0);
|
|
99258
|
-
__decorate([
|
|
99259
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99260
|
-
], StandardMaterial.prototype, "invertNormalMapY", void 0);
|
|
99261
|
-
__decorate([
|
|
99262
|
-
serialize("twoSidedLighting")
|
|
99263
|
-
], StandardMaterial.prototype, "_twoSidedLighting", void 0);
|
|
99264
|
-
__decorate([
|
|
99265
|
-
expandToProperty("_markAllSubMeshesAsTexturesDirty")
|
|
99266
|
-
], StandardMaterial.prototype, "twoSidedLighting", void 0);
|
|
99267
|
-
__decorate([
|
|
99268
|
-
serialize("applyDecalMapAfterDetailMap")
|
|
99269
|
-
], StandardMaterial.prototype, "_applyDecalMapAfterDetailMap", void 0);
|
|
99270
|
-
__decorate([
|
|
99271
|
-
expandToProperty("_markAllSubMeshesAsMiscDirty")
|
|
99272
|
-
], StandardMaterial.prototype, "applyDecalMapAfterDetailMap", void 0);
|
|
99273
|
-
RegisterClass("BABYLON.StandardMaterial", StandardMaterial);
|
|
99274
|
-
Scene.DefaultMaterialFactory = (scene) => {
|
|
99275
|
-
return new StandardMaterial("default material", scene);
|
|
99276
|
-
};
|
|
99277
99306
|
|
|
99278
99307
|
ThinEngine.prototype.updateVideoTexture = function (texture, video, invertY) {
|
|
99279
99308
|
if (!texture || texture._isDisabled) {
|
|
@@ -143326,8 +143355,10 @@ function setupSkybox(scene, options) {
|
|
|
143326
143355
|
// Ensure the URL is absolute or correctly relative to the viewer's deployment location
|
|
143327
143356
|
const texture = new BABYLON$1.CubeTexture(options.activeSkyboxUrl, scene);
|
|
143328
143357
|
// Assign the texture to the scene's skybox
|
|
143329
|
-
|
|
143330
|
-
|
|
143358
|
+
const skybox = scene.createDefaultSkybox(texture, true, 1000, 0.0, false); // PBR=true, scale=1000, blur=0.0, set reflection=false initially
|
|
143359
|
+
if (skybox && typeof options.skyboxRotation === "number") {
|
|
143360
|
+
skybox.rotation.y = options.skyboxRotation;
|
|
143361
|
+
}
|
|
143331
143362
|
console.log(`Skybox loaded from: ${options.activeSkyboxUrl}`);
|
|
143332
143363
|
}
|
|
143333
143364
|
catch (error) {
|
|
@@ -164198,10 +164229,35 @@ class CustomScriptManager {
|
|
|
164198
164229
|
// Clean up any previous executions
|
|
164199
164230
|
this.cleanup();
|
|
164200
164231
|
try {
|
|
164232
|
+
const renderObservers = [];
|
|
164233
|
+
// Create a wrapped version of scene.registerBeforeRender that we can track
|
|
164234
|
+
const wrappedScene = Object.create(this.scene);
|
|
164235
|
+
wrappedScene.registerBeforeRender = (callback) => {
|
|
164236
|
+
// Wrap the callback in error handling
|
|
164237
|
+
const safeCallback = () => {
|
|
164238
|
+
try {
|
|
164239
|
+
callback();
|
|
164240
|
+
}
|
|
164241
|
+
catch (err) {
|
|
164242
|
+
console.error('Error in custom script render callback:', err);
|
|
164243
|
+
// Remove all observers to prevent continuous errors
|
|
164244
|
+
renderObservers.forEach(observer => {
|
|
164245
|
+
this.scene.onBeforeRenderObservable.remove(observer);
|
|
164246
|
+
});
|
|
164247
|
+
renderObservers.length = 0;
|
|
164248
|
+
}
|
|
164249
|
+
};
|
|
164250
|
+
const observer = this.scene.onBeforeRenderObservable.add(safeCallback);
|
|
164251
|
+
renderObservers.push(observer);
|
|
164252
|
+
// Store cleanup function
|
|
164253
|
+
this.scriptCleanup.push(() => {
|
|
164254
|
+
this.scene.onBeforeRenderObservable.remove(observer);
|
|
164255
|
+
});
|
|
164256
|
+
};
|
|
164201
164257
|
// Create the execution context
|
|
164202
164258
|
const func = new Function('scene', 'camera', 'BABYLON', 'canvas', 'getScrollPercentage', 'getCurrentWaypointIndex', 'getHotspots', 'getHTMLMeshes', 'getSplats', this.customScript);
|
|
164203
|
-
// Execute the script
|
|
164204
|
-
func(
|
|
164259
|
+
// Execute the script with wrapped scene
|
|
164260
|
+
func(wrappedScene, this.camera, BABYLON$1, this.scene.getEngine().getRenderingCanvas(), () => this.scrollPercentage, () => this.currentWaypointIndex, () => this.hotspots, () => this.htmlMeshes, () => this.scene.meshes.filter(mesh => mesh.name.includes('splat')));
|
|
164205
164261
|
console.log('Custom script executed successfully in viewer');
|
|
164206
164262
|
}
|
|
164207
164263
|
catch (error) {
|
|
@@ -165007,7 +165063,7 @@ options) {
|
|
|
165007
165063
|
// but keeping original scale/invert settings from transformed data.
|
|
165008
165064
|
const tempData = Object.assign(Object.assign({}, data), { loadedModelUrl: newSplatUrl,
|
|
165009
165065
|
// Keep original scale/invert settings
|
|
165010
|
-
splatScale: data.splatScale, invertXScale: data.invertXScale, invertYScale: data.invertYScale,
|
|
165066
|
+
splatScale: data.splatScale, invertXScale: data.invertXScale, invertYScale: data.invertYScale, splatPosition: data.splatPosition, splatRotation: data.splatRotation,
|
|
165011
165067
|
// Ensure other potentially relevant fields from data are present if needed
|
|
165012
165068
|
waypoints: data.waypoints, hotspots: data.hotspots });
|
|
165013
165069
|
splatRootMeshes = await loadSplatAsset(scene, tempData, (percentage, text) => {
|