@myned-ai/gsplat-flame-avatar-renderer 1.0.5 → 1.0.6

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gsplat-flame-avatar-renderer.cjs.min.js","sources":["../src/enums/LogLevel.js","../src/enums/RenderMode.js","../src/enums/SceneFormat.js","../src/enums/SceneRevealMode.js","../src/enums/SplatRenderMode.js","../src/enums/EngineConstants.js","../src/errors/ApplicationError.js","../src/utils/Logger.js","../src/utils/Util.js","../src/utils/ValidationUtils.js","../src/utils/ObjectPool.js","../src/utils/BlobUrlManager.js","../src/utils/RenderLoop.js","../src/utils/EventEmitter.js","../src/renderer/AppConstants.js","../src/renderer/AnimationManager.js","../src/core/SplatScene.js","../src/core/SplatGeometry.js","../src/core/SplatTree.js","../src/materials/SplatMaterial.js","../src/materials/SplatMaterial3D.js","../src/materials/SplatMaterial2D.js","../src/core/SplatMesh.js","../src/loaders/DirectLoadError.js","../src/buffers/UncompressedSplatArray.js","../src/buffers/SplatBuffer.js","../src/buffers/SplatPartitioner.js","../src/buffers/SplatBufferGenerator.js","../src/loaders/PlyParserUtils.js","../src/loaders/INRIAV1PlyParser.js","../src/loaders/PlyParser.js","../src/loaders/PlyLoader.js","../src/raycaster/Ray.js","../src/raycaster/Hit.js","../src/raycaster/Raycaster.js","../src/worker/SortWorker.js","../src/core/Viewer.js","../src/renderer/GaussianSplatRenderer.js","../src/flame/FlameConstants.js","../src/flame/utils.js","../src/flame/FlameTextureManager.js","../src/flame/FlameAnimator.js","../src/utils/LoaderUtils.js"],"sourcesContent":["/**\r\n * Log level enumeration for controlling verbosity\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n */\r\nexport const LogLevel = {\r\n None: 0,\r\n Error: 1,\r\n Warning: 2,\r\n Info: 3,\r\n Debug: 4\r\n};\r\n","/**\r\n * Render mode enumeration\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n */\r\nexport const RenderMode = {\r\n Always: 0,\r\n OnChange: 1,\r\n Never: 2\r\n};\r\n","/**\r\n * Scene format enumeration for supported file types\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * Simplified for FLAME avatar usage - only PLY format is supported.\r\n */\r\nexport const SceneFormat = {\r\n 'Ply': 0\r\n};\r\n\r\n/**\r\n * Determine scene format from file path\r\n * @param {string} path - File path\r\n * @returns {number|null} Scene format or null if unknown\r\n */\r\nexport const sceneFormatFromPath = (path) => {\r\n if (path.endsWith('.ply')) return SceneFormat.Ply;\r\n return null;\r\n};\r\n","/**\r\n * Scene reveal mode enumeration\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n */\r\nexport const SceneRevealMode = {\r\n Default: 0,\r\n Gradual: 1,\r\n Instant: 2\r\n};\r\n","/**\r\n * Splat render mode enumeration\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n */\r\nexport const SplatRenderMode = {\r\n ThreeD: 0,\r\n TwoD: 1\r\n};\r\n","/**\r\n * EngineConstants\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * Core constants for Gaussian Splat rendering.\r\n */\r\n\r\nexport class Constants {\r\n static DefaultSplatSortDistanceMapPrecision = 16;\r\n static MemoryPageSize = 65536;\r\n static BytesPerFloat = 4;\r\n static BytesPerInt = 4;\r\n static MaxScenes = 32;\r\n static ProgressiveLoadSectionSize = 262144;\r\n static ProgressiveLoadSectionDelayDuration = 15;\r\n static SphericalHarmonics8BitCompressionRange = 3;\r\n}\r\n\r\nexport const DefaultSphericalHarmonics8BitCompressionRange = Constants.SphericalHarmonics8BitCompressionRange;\r\n\r\n// SplatMesh constants\r\nexport const COVARIANCES_ELEMENTS_PER_SPLAT = 6;\r\nexport const CENTER_COLORS_ELEMENTS_PER_SPLAT = 4;\r\n\r\nexport const COVARIANCES_ELEMENTS_PER_TEXEL_STORED = 4;\r\nexport const COVARIANCES_ELEMENTS_PER_TEXEL_ALLOCATED = 4;\r\nexport const COVARIANCES_ELEMENTS_PER_TEXEL_COMPRESSED_STORED = 6;\r\nexport const COVARIANCES_ELEMENTS_PER_TEXEL_COMPRESSED_ALLOCATED = 8;\r\nexport const SCALES_ROTATIONS_ELEMENTS_PER_TEXEL = 4;\r\nexport const CENTER_COLORS_ELEMENTS_PER_TEXEL = 4;\r\nexport const SCENE_INDEXES_ELEMENTS_PER_TEXEL = 1;\r\n\r\nexport const SCENE_FADEIN_RATE_FAST = 0.012;\r\nexport const SCENE_FADEIN_RATE_GRADUAL = 0.003;\r\n\r\n// Viewer constants\r\nexport const THREE_CAMERA_FOV = 50;\r\nexport const MINIMUM_DISTANCE_TO_NEW_FOCAL_POINT = 0.5;\r\nexport const CONSECUTIVE_RENDERED_FRAMES_FOR_FPS_CALCULATION = 60;\r\nexport const MIN_SPLAT_COUNT_TO_SHOW_SPLAT_TREE_LOADING_SPINNER = 1500000;\r\nexport const FOCUS_MARKER_FADE_IN_SPEED = 0.4;\r\nexport const FOCUS_MARKER_FADE_OUT_SPEED = 0.12;\r\n\r\n// Internal load types for loaders\r\nexport const InternalLoadType = {\r\n DirectToSplatBuffer: 0,\r\n DirectToSplatArray: 1,\r\n DownloadBeforeProcessing: 2\r\n};\r\n\r\n// Loader status\r\nexport const LoaderStatus = {\r\n 'Downloading': 0,\r\n 'Processing': 1,\r\n 'Done': 2\r\n};\r\n","/**\r\n * ApplicationError - Base error class for all application errors\r\n *\r\n * Provides structured error handling with error codes and cause tracking.\r\n * All domain-specific errors should extend this class.\r\n *\r\n * @extends Error\r\n */\r\nexport class ApplicationError extends Error {\r\n /**\r\n * Create an ApplicationError\r\n * @param {string} message - Human-readable error message\r\n * @param {string} code - Machine-readable error code for programmatic handling\r\n * @param {Error} [cause=null] - Original error that caused this error (for error chaining)\r\n */\r\n constructor(message, code, cause = null) {\r\n super(message);\r\n this.name = this.constructor.name;\r\n this.code = code;\r\n this.cause = cause;\r\n\r\n // Capture stack trace, excluding constructor call from it\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, this.constructor);\r\n }\r\n }\r\n\r\n /**\r\n * Convert error to JSON for logging/transmission\r\n * @returns {object} JSON representation of error\r\n */\r\n toJSON() {\r\n return {\r\n name: this.name,\r\n message: this.message,\r\n code: this.code,\r\n stack: this.stack,\r\n cause: this.cause ? {\r\n name: this.cause.name,\r\n message: this.cause.message\r\n } : null\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * ValidationError - Thrown when input validation fails\r\n *\r\n * Used for invalid parameters, out-of-range values, or malformed data.\r\n *\r\n * @extends ApplicationError\r\n */\r\nexport class ValidationError extends ApplicationError {\r\n /**\r\n * Create a ValidationError\r\n * @param {string} message - Validation failure description\r\n * @param {string} field - Name of the field that failed validation\r\n * @param {Error} [cause=null] - Original error that caused this validation failure\r\n */\r\n constructor(message, field, cause = null) {\r\n super(message, 'VALIDATION_ERROR', cause);\r\n this.field = field;\r\n }\r\n}\r\n\r\n/**\r\n * NetworkError - Thrown when network operations fail\r\n *\r\n * Used for fetch failures, timeouts, or HTTP error responses.\r\n *\r\n * @extends ApplicationError\r\n */\r\nexport class NetworkError extends ApplicationError {\r\n /**\r\n * Create a NetworkError\r\n * @param {string} message - Network error description\r\n * @param {number} [statusCode=0] - HTTP status code (if applicable)\r\n * @param {Error} [cause=null] - Original error that caused this network failure\r\n */\r\n constructor(message, statusCode = 0, cause = null) {\r\n super(message, 'NETWORK_ERROR', cause);\r\n this.statusCode = statusCode;\r\n }\r\n}\r\n\r\n/**\r\n * AssetLoadError - Thrown when asset loading fails\r\n *\r\n * Used for failures loading models, textures, or other asset files.\r\n *\r\n * @extends ApplicationError\r\n */\r\nexport class AssetLoadError extends ApplicationError {\r\n /**\r\n * Create an AssetLoadError\r\n * @param {string} message - Asset load failure description\r\n * @param {string} assetPath - Path to the asset that failed to load\r\n * @param {Error} [cause=null] - Original error that caused this load failure\r\n */\r\n constructor(message, assetPath, cause = null) {\r\n super(message, 'ASSET_LOAD_ERROR', cause);\r\n this.assetPath = assetPath;\r\n }\r\n}\r\n\r\n/**\r\n * ResourceDisposedError - Thrown when attempting to use a disposed resource\r\n *\r\n * Used to prevent use-after-dispose bugs.\r\n *\r\n * @extends ApplicationError\r\n */\r\nexport class ResourceDisposedError extends ApplicationError {\r\n /**\r\n * Create a ResourceDisposedError\r\n * @param {string} resourceName - Name of the disposed resource\r\n */\r\n constructor(resourceName) {\r\n super(\r\n `Cannot use ${resourceName}: resource has been disposed`,\r\n 'RESOURCE_DISPOSED_ERROR'\r\n );\r\n this.resourceName = resourceName;\r\n }\r\n}\r\n\r\n/**\r\n * InitializationError - Thrown when initialization fails\r\n *\r\n * Used when required setup steps fail or prerequisites are not met.\r\n *\r\n * @extends ApplicationError\r\n */\r\nexport class InitializationError extends ApplicationError {\r\n /**\r\n * Create an InitializationError\r\n * @param {string} message - Initialization failure description\r\n * @param {string} component - Name of component that failed to initialize\r\n * @param {Error} [cause=null] - Original error that caused this initialization failure\r\n */\r\n constructor(message, component, cause = null) {\r\n super(message, 'INITIALIZATION_ERROR', cause);\r\n this.component = component;\r\n }\r\n}\r\n\r\n/**\r\n * ParseError - Thrown when parsing data fails\r\n *\r\n * Used for malformed file formats, invalid JSON, or corrupt data.\r\n *\r\n * @extends ApplicationError\r\n */\r\nexport class ParseError extends ApplicationError {\r\n /**\r\n * Create a ParseError\r\n * @param {string} message - Parse failure description\r\n * @param {string} dataType - Type of data being parsed (e.g., 'JSON', 'PLY', 'GLB')\r\n * @param {Error} [cause=null] - Original error that caused this parse failure\r\n */\r\n constructor(message, dataType, cause = null) {\r\n super(message, 'PARSE_ERROR', cause);\r\n this.dataType = dataType;\r\n }\r\n}\r\n\r\n/**\r\n * ConfigurationError - Thrown when configuration is invalid\r\n *\r\n * Used for invalid settings, missing required configuration, or conflicting options.\r\n *\r\n * @extends ApplicationError\r\n */\r\nexport class ConfigurationError extends ApplicationError {\r\n /**\r\n * Create a ConfigurationError\r\n * @param {string} message - Configuration error description\r\n * @param {string} configKey - Configuration key that is invalid\r\n * @param {Error} [cause=null] - Original error\r\n */\r\n constructor(message, configKey, cause = null) {\r\n super(message, 'CONFIGURATION_ERROR', cause);\r\n this.configKey = configKey;\r\n }\r\n}\r\n","/**\r\n * Logger - Structured logging system\r\n *\r\n * Provides leveled logging with optional output suppression for production.\r\n * Replaces direct console.log calls for better control and debugging.\r\n */\r\n\r\n/**\r\n * Logger levels in order of severity\r\n * Note: Named LoggerLevel to avoid conflict with existing LogLevel enum\r\n */\r\nexport const LoggerLevel = Object.freeze({\r\n DEBUG: 0,\r\n INFO: 1,\r\n WARN: 2,\r\n ERROR: 3,\r\n NONE: 4\r\n});\r\n\r\n/**\r\n * Logger class for structured application logging\r\n */\r\nexport class Logger {\r\n /**\r\n * Create a Logger instance\r\n * @param {string} namespace - Logger namespace (e.g., 'Renderer', 'Loader')\r\n * @param {number} [minLevel=LoggerLevel.INFO] - Minimum log level to output\r\n */\r\n constructor(namespace, minLevel = LoggerLevel.INFO) {\r\n this.namespace = namespace;\r\n this.minLevel = minLevel;\r\n }\r\n\r\n /**\r\n * Set minimum log level\r\n * @param {number} level - Minimum level from LoggerLevel enum\r\n */\r\n setLevel(level) {\r\n this.minLevel = level;\r\n }\r\n\r\n /**\r\n * Format log message with namespace and timestamp\r\n * @private\r\n * @param {string} level - Log level name\r\n * @param {Array} args - Log arguments\r\n * @returns {Array} Formatted arguments\r\n */\r\n _format(level, args) {\r\n const timestamp = new Date().toISOString();\r\n const prefix = `[${timestamp}] [${level}] [${this.namespace}]`;\r\n return [prefix, ...args];\r\n }\r\n\r\n /**\r\n * Log debug message (most verbose)\r\n * @param {...*} args - Arguments to log\r\n */\r\n debug(...args) {\r\n if (this.minLevel <= LoggerLevel.DEBUG) {\r\n console.debug(...this._format('DEBUG', args));\r\n }\r\n }\r\n\r\n /**\r\n * Log info message\r\n * @param {...*} args - Arguments to log\r\n */\r\n info(...args) {\r\n if (this.minLevel <= LoggerLevel.INFO) {\r\n console.info(...this._format('INFO', args));\r\n }\r\n }\r\n\r\n /**\r\n * Log warning message\r\n * @param {...*} args - Arguments to log\r\n */\r\n warn(...args) {\r\n if (this.minLevel <= LoggerLevel.WARN) {\r\n console.warn(...this._format('WARN', args));\r\n }\r\n }\r\n\r\n /**\r\n * Log error message\r\n * @param {...*} args - Arguments to log\r\n */\r\n error(...args) {\r\n if (this.minLevel <= LoggerLevel.ERROR) {\r\n console.error(...this._format('ERROR', args));\r\n }\r\n }\r\n\r\n /**\r\n * Log error with stack trace\r\n * @param {Error} error - Error object\r\n * @param {string} [context] - Additional context\r\n */\r\n errorWithTrace(error, context = '') {\r\n if (this.minLevel <= LoggerLevel.ERROR) {\r\n const contextStr = context ? ` Context: ${context}` : '';\r\n console.error(...this._format('ERROR', [\r\n `${error.message}${contextStr}`,\r\n '\\nStack:', error.stack\r\n ]));\r\n }\r\n }\r\n\r\n /**\r\n * Create a child logger with extended namespace\r\n * @param {string} childNamespace - Child namespace to append\r\n * @returns {Logger} New logger with combined namespace\r\n */\r\n child(childNamespace) {\r\n return new Logger(`${this.namespace}:${childNamespace}`, this.minLevel);\r\n }\r\n}\r\n\r\n/**\r\n * Global logger registry\r\n * @private\r\n */\r\nconst loggers = new Map();\r\n\r\n/**\r\n * Global log level (affects all new loggers)\r\n * @private\r\n */\r\nlet globalLogLevel = LoggerLevel.INFO;\r\n\r\n/**\r\n * Set global log level for all loggers\r\n * @param {number} level - Log level from LoggerLevel enum\r\n */\r\nexport function setGlobalLogLevel(level) {\r\n globalLogLevel = level;\r\n // Update existing loggers\r\n for (const logger of loggers.values()) {\r\n logger.setLevel(level);\r\n }\r\n}\r\n\r\n/**\r\n * Get or create a logger for a namespace\r\n * @param {string} namespace - Logger namespace\r\n * @returns {Logger} Logger instance\r\n */\r\nexport function getLogger(namespace) {\r\n if (!loggers.has(namespace)) {\r\n loggers.set(namespace, new Logger(namespace, globalLogLevel));\r\n }\r\n return loggers.get(namespace);\r\n}\r\n\r\n/**\r\n * Configure logging for production (suppress all logs)\r\n */\r\nexport function configureForProduction() {\r\n setGlobalLogLevel(LoggerLevel.NONE);\r\n}\r\n\r\n/**\r\n * Configure logging for development (show all logs)\r\n */\r\nexport function configureForDevelopment() {\r\n setGlobalLogLevel(LoggerLevel.DEBUG);\r\n}\r\n\r\n// Export default logger for convenience\r\nexport default getLogger('App');\r\n","/**\r\n * Core utility functions for Gaussian Splat rendering\r\n *\r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n *\r\n * Import paths adjusted for gsplat-flame-avatar package structure.\r\n */\r\n\r\nimport { DataUtils } from 'three';\r\nimport { NetworkError } from '../errors/index.js';\r\nimport { getLogger } from './Logger.js';\r\n\r\nconst logger = getLogger('Util');\r\n\r\n/**\r\n * Custom error for aborted operations\r\n * @deprecated Use NetworkError instead for consistency\r\n */\r\nexport class AbortedPromiseError extends Error {\r\n constructor(msg) {\r\n super(msg);\r\n this.name = 'AbortedPromiseError';\r\n this.code = 'ABORTED';\r\n }\r\n}\r\n\r\n/**\r\n * Fetch with progress tracking using standard AbortController\r\n *\r\n * @param {string} path - URL to fetch\r\n * @param {Function} [onProgress] - Progress callback (percent, percentLabel, chunk, fileSize)\r\n * @param {boolean} [saveChunks=true] - Whether to save and return downloaded chunks\r\n * @param {object} [headers] - Optional HTTP headers\r\n * @returns {Promise<ArrayBuffer>} Promise that resolves with downloaded data\r\n * @throws {NetworkError} If fetch fails or is aborted\r\n */\r\nexport const fetchWithProgress = function(path, onProgress, saveChunks = true, headers) {\r\n\r\n const abortController = new AbortController();\r\n const signal = abortController.signal;\r\n let aborted = false;\r\n\r\n let onProgressCalledAtComplete = false;\r\n const localOnProgress = (percent, percentLabel, chunk, fileSize) => {\r\n if (onProgress && !onProgressCalledAtComplete) {\r\n try {\r\n onProgress(percent, percentLabel, chunk, fileSize);\r\n if (percent === 100) {\r\n onProgressCalledAtComplete = true;\r\n }\r\n } catch (error) {\r\n // Don't let progress callback errors break the download\r\n logger.error('Error in progress callback:', error);\r\n }\r\n }\r\n };\r\n\r\n const promise = new Promise((resolve, reject) => {\r\n const fetchOptions = { signal };\r\n if (headers) fetchOptions.headers = headers;\r\n\r\n fetch(path, fetchOptions)\r\n .then(async (data) => {\r\n // Handle HTTP error responses\r\n if (!data.ok) {\r\n let errorText = '';\r\n try {\r\n errorText = await data.text();\r\n } catch {\r\n // Ignore if we can't read error text\r\n }\r\n reject(new NetworkError(\r\n `Fetch failed: ${data.statusText}${errorText ? ' - ' + errorText : ''}`,\r\n data.status\r\n ));\r\n return;\r\n }\r\n\r\n const reader = data.body?.getReader();\r\n if (!reader) {\r\n reject(new NetworkError('Response body is not readable', 0));\r\n return;\r\n }\r\n\r\n let bytesDownloaded = 0;\r\n const _fileSize = data.headers.get('Content-Length');\r\n const fileSize = _fileSize ? parseInt(_fileSize, 10) : undefined;\r\n\r\n const chunks = [];\r\n\r\n while (!aborted) {\r\n try {\r\n const { value: chunk, done } = await reader.read();\r\n if (done) {\r\n localOnProgress(100, '100%', chunk, fileSize);\r\n if (saveChunks) {\r\n const buffer = new Blob(chunks).arrayBuffer();\r\n resolve(buffer);\r\n } else {\r\n resolve();\r\n }\r\n break;\r\n }\r\n bytesDownloaded += chunk.length;\r\n let percent;\r\n let percentLabel;\r\n if (fileSize !== undefined) {\r\n percent = (bytesDownloaded / fileSize) * 100;\r\n percentLabel = `${percent.toFixed(2)}%`;\r\n }\r\n if (saveChunks) {\r\n chunks.push(chunk);\r\n }\r\n localOnProgress(percent, percentLabel, chunk, fileSize);\r\n } catch (error) {\r\n reject(new NetworkError(\r\n `Error reading response stream: ${error.message}`,\r\n 0,\r\n error\r\n ));\r\n return;\r\n }\r\n }\r\n })\r\n .catch((error) => {\r\n // Don't wrap if already a NetworkError\r\n if (error instanceof NetworkError) {\r\n reject(error);\r\n } else if (error.name === 'AbortError') {\r\n reject(new NetworkError('Fetch aborted by user', 0, error));\r\n } else {\r\n reject(new NetworkError(\r\n `Fetch failed: ${error.message || 'Unknown error'}`,\r\n 0,\r\n error\r\n ));\r\n }\r\n });\r\n });\r\n\r\n // Attach abort functionality to the promise\r\n promise.abort = (reason) => {\r\n aborted = true;\r\n abortController.abort(reason);\r\n };\r\n promise.abortController = abortController;\r\n\r\n return promise;\r\n};\r\n\r\n// Clamp value between min and max\r\nexport const clamp = function(val, min, max) {\r\n return Math.max(Math.min(val, max), min);\r\n};\r\n\r\n// Get current time in seconds\r\nexport const getCurrentTime = function() {\r\n return performance.now() / 1000;\r\n};\r\n\r\n// Dispose all meshes in a scene graph\r\nexport const disposeAllMeshes = (object3D) => {\r\n if (object3D.geometry) {\r\n object3D.geometry.dispose();\r\n object3D.geometry = null;\r\n }\r\n if (object3D.material) {\r\n object3D.material.dispose();\r\n object3D.material = null;\r\n }\r\n if (object3D.children) {\r\n for (let child of object3D.children) {\r\n disposeAllMeshes(child);\r\n }\r\n }\r\n};\r\n\r\n// Delayed execution helper\r\nexport const delayedExecute = (func, fast) => {\r\n return new Promise((resolve) => {\r\n window.setTimeout(() => {\r\n resolve(func());\r\n }, fast ? 1 : 50);\r\n });\r\n};\r\n\r\n// Get spherical harmonics component count for degree\r\nexport const getSphericalHarmonicsComponentCountForDegree = (sphericalHarmonicsDegree = 0) => {\r\n switch (sphericalHarmonicsDegree) {\r\n case 1:\r\n return 9;\r\n case 2:\r\n return 24;\r\n }\r\n return 0;\r\n};\r\n\r\n// Create native promise with extracted components\r\nexport const nativePromiseWithExtractedComponents = () => {\r\n let resolver;\r\n let rejecter;\r\n const promise = new Promise((resolve, reject) => {\r\n resolver = resolve;\r\n rejecter = reject;\r\n });\r\n return {\r\n 'promise': promise,\r\n 'resolve': resolver,\r\n 'reject': rejecter\r\n };\r\n};\r\n\r\n/**\r\n * Create a promise with extracted resolve/reject functions and optional abort capability\r\n * Uses standard Promise with attached abort method\r\n */\r\nexport const abortablePromiseWithExtractedComponents = (abortHandler) => {\r\n let resolver;\r\n let rejecter;\r\n const promise = new Promise((resolve, reject) => {\r\n resolver = resolve;\r\n rejecter = reject;\r\n });\r\n \r\n // Attach abort method to promise\r\n promise.abort = abortHandler || (() => {});\r\n \r\n return {\r\n 'promise': promise,\r\n 'resolve': resolver,\r\n 'reject': rejecter\r\n };\r\n};\r\n\r\n// Semver class for version handling\r\nexport class Semver {\r\n constructor(major, minor, patch) {\r\n this.major = major;\r\n this.minor = minor;\r\n this.patch = patch;\r\n }\r\n\r\n toString() {\r\n return `${this.major}_${this.minor}_${this.patch}`;\r\n }\r\n}\r\n\r\n// iOS detection\r\nexport function isIOS() {\r\n const ua = navigator.userAgent;\r\n return ua.indexOf('iPhone') > 0 || ua.indexOf('iPad') > 0;\r\n}\r\n\r\nexport function getIOSSemever() {\r\n if (isIOS()) {\r\n const extract = navigator.userAgent.match(/OS (\\d+)_(\\d+)_?(\\d+)?/);\r\n return new Semver(\r\n parseInt(extract[1] || 0, 10),\r\n parseInt(extract[2] || 0, 10),\r\n parseInt(extract[3] || 0, 10)\r\n );\r\n }\r\n return null;\r\n}\r\n\r\n// Half float conversion utilities\r\nexport const toHalfFloat = DataUtils.toHalfFloat.bind(DataUtils);\r\nexport const fromHalfFloat = DataUtils.fromHalfFloat.bind(DataUtils);\r\n\r\n// Default spherical harmonics compression range (imported from enums)\r\nimport { DefaultSphericalHarmonics8BitCompressionRange } from '../enums/EngineConstants.js';\r\nexport { DefaultSphericalHarmonics8BitCompressionRange };\r\nexport const DefaultSphericalHarmonics8BitCompressionHalfRange = DefaultSphericalHarmonics8BitCompressionRange / 2.0;\r\n\r\n// Uncompress float based on compression level\r\nexport const toUncompressedFloat = (f, compressionLevel, isSH = false, range8BitMin, range8BitMax) => {\r\n if (compressionLevel === 0) {\r\n return f;\r\n } else if (compressionLevel === 1 || (compressionLevel === 2 && !isSH)) {\r\n return DataUtils.fromHalfFloat(f);\r\n } else if (compressionLevel === 2) {\r\n return fromUint8(f, range8BitMin, range8BitMax);\r\n }\r\n};\r\n\r\n// Convert to uint8\r\nexport const toUint8 = (v, rangeMin, rangeMax) => {\r\n v = clamp(v, rangeMin, rangeMax);\r\n const range = (rangeMax - rangeMin);\r\n return clamp(Math.floor((v - rangeMin) / range * 255), 0, 255);\r\n};\r\n\r\n// Convert from uint8\r\nexport const fromUint8 = (v, rangeMin, rangeMax) => {\r\n const range = (rangeMax - rangeMin);\r\n return (v / 255 * range + rangeMin);\r\n};\r\n\r\n// Half float to uint8\r\nexport const fromHalfFloatToUint8 = (v, rangeMin, rangeMax) => {\r\n return toUint8(fromHalfFloat(v), rangeMin, rangeMax);\r\n};\r\n\r\n// Uint8 to half float\r\nexport const fromUint8ToHalfFloat = (v, rangeMin, rangeMax) => {\r\n return toHalfFloat(fromUint8(v, rangeMin, rangeMax));\r\n};\r\n\r\n// Read float from DataView based on compression level\r\nexport const dataViewFloatForCompressionLevel = (dataView, floatIndex, compressionLevel, isSH = false) => {\r\n if (compressionLevel === 0) {\r\n return dataView.getFloat32(floatIndex * 4, true);\r\n } else if (compressionLevel === 1 || (compressionLevel === 2 && !isSH)) {\r\n return dataView.getUint16(floatIndex * 2, true);\r\n } else {\r\n return dataView.getUint8(floatIndex, true);\r\n }\r\n};\r\n\r\n// Convert between compression levels\r\nexport const convertBetweenCompressionLevels = function() {\r\n const noop = (v) => v;\r\n\r\n return function(val, fromLevel, toLevel, isSH = false) {\r\n if (fromLevel === toLevel) return val;\r\n let outputConversionFunc = noop;\r\n\r\n if (fromLevel === 2 && isSH) {\r\n if (toLevel === 1) outputConversionFunc = fromUint8ToHalfFloat;\r\n else if (toLevel === 0) {\r\n outputConversionFunc = fromUint8;\r\n }\r\n } else if (fromLevel === 2 || fromLevel === 1) {\r\n if (toLevel === 0) outputConversionFunc = fromHalfFloat;\r\n else if (toLevel === 2) {\r\n if (!isSH) outputConversionFunc = noop;\r\n else outputConversionFunc = fromHalfFloatToUint8;\r\n }\r\n } else if (fromLevel === 0) {\r\n if (toLevel === 1) outputConversionFunc = toHalfFloat;\r\n else if (toLevel === 2) {\r\n if (!isSH) outputConversionFunc = toHalfFloat;\r\n else outputConversionFunc = toUint8;\r\n }\r\n }\r\n\r\n return outputConversionFunc(val);\r\n };\r\n}();\r\n\r\n// Copy between buffers\r\nexport const copyBetweenBuffers = (srcBuffer, srcOffset, destBuffer, destOffset, byteCount = 0) => {\r\n const src = new Uint8Array(srcBuffer, srcOffset);\r\n const dest = new Uint8Array(destBuffer, destOffset);\r\n for (let i = 0; i < byteCount; i++) {\r\n dest[i] = src[i];\r\n }\r\n};\r\n\r\n// Float to half float conversion\r\nexport const floatToHalf = function() {\r\n const floatView = new Float32Array(1);\r\n const int32View = new Int32Array(floatView.buffer);\r\n\r\n return function(val) {\r\n floatView[0] = val;\r\n const x = int32View[0];\r\n\r\n let bits = (x >> 16) & 0x8000;\r\n let m = (x >> 12) & 0x07ff;\r\n const e = (x >> 23) & 0xff;\r\n\r\n if (e < 103) return bits;\r\n\r\n if (e > 142) {\r\n bits |= 0x7c00;\r\n bits |= ((e == 255) ? 0 : 1) && (x & 0x007fffff);\r\n return bits;\r\n }\r\n\r\n if (e < 113) {\r\n m |= 0x0800;\r\n bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);\r\n return bits;\r\n }\r\n\r\n bits |= ((e - 112) << 10) | (m >> 1);\r\n bits += m & 1;\r\n return bits;\r\n };\r\n}();\r\n\r\n// Encode float as uint\r\nexport const uintEncodedFloat = function() {\r\n const floatView = new Float32Array(1);\r\n const int32View = new Int32Array(floatView.buffer);\r\n\r\n return function(f) {\r\n floatView[0] = f;\r\n return int32View[0];\r\n };\r\n}();\r\n\r\n// RGBA to integer\r\nexport const rgbaToInteger = function(r, g, b, a) {\r\n return r + (g << 8) + (b << 16) + (a << 24);\r\n};\r\n\r\n// RGBA array to integer\r\nexport const rgbaArrayToInteger = function(arr, offset) {\r\n return arr[offset] + (arr[offset + 1] << 8) + (arr[offset + 2] << 16) + (arr[offset + 3] << 24);\r\n};\r\n\r\n// BASE_COMPONENT_COUNT for UncompressedSplatArray\r\nexport const BASE_COMPONENT_COUNT = 14;\r\n","/**\r\n * ValidationUtils - Security-focused validation utilities\r\n *\r\n * CRITICAL: All external inputs MUST be validated before use.\r\n * This module provides allowlist-based validation following security best practices.\r\n */\r\n\r\nimport { ValidationError } from '../errors/index.js';\r\n\r\n/**\r\n * Allowed URL protocols (allowlist approach)\r\n */\r\nconst ALLOWED_PROTOCOLS = Object.freeze(['https:', 'http:', 'blob:', 'data:']);\r\n\r\n/**\r\n * Validate and sanitize a URL\r\n *\r\n * @param {string} url - URL to validate\r\n * @param {string} [baseURL] - Base URL for relative URLs (defaults to window.location.href)\r\n * @returns {string} Sanitized absolute URL\r\n * @throws {ValidationError} If URL is invalid or uses disallowed protocol\r\n */\r\nexport function validateUrl(url, baseURL) {\r\n if (typeof url !== 'string' || url.length === 0) {\r\n throw new ValidationError('URL must be a non-empty string', 'url');\r\n }\r\n\r\n let parsed;\r\n try {\r\n // Use base URL if provided, otherwise use window location (browser only)\r\n const base = baseURL || (typeof window !== 'undefined' ? window.location.href : undefined);\r\n parsed = new URL(url, base);\r\n } catch (error) {\r\n throw new ValidationError(\r\n `Invalid URL format: ${url}`,\r\n 'url',\r\n error\r\n );\r\n }\r\n\r\n // Validate protocol against allowlist\r\n if (!ALLOWED_PROTOCOLS.includes(parsed.protocol)) {\r\n throw new ValidationError(\r\n `Disallowed protocol: ${parsed.protocol}. Allowed protocols: ${ALLOWED_PROTOCOLS.join(', ')}`,\r\n 'url.protocol'\r\n );\r\n }\r\n\r\n return parsed.href;\r\n}\r\n\r\n/**\r\n * Validate asset path to prevent path traversal attacks\r\n *\r\n * @param {string} path - File path to validate\r\n * @returns {string} Validated path\r\n * @throws {ValidationError} If path contains traversal sequences\r\n */\r\nexport function validateAssetPath(path) {\r\n if (typeof path !== 'string' || path.length === 0) {\r\n throw new ValidationError('Asset path must be a non-empty string', 'path');\r\n }\r\n\r\n // Check for path traversal sequences\r\n const dangerousPatterns = ['../', '..\\\\', '%2e%2e/', '%2e%2e\\\\'];\r\n const normalizedPath = path.toLowerCase();\r\n\r\n for (const pattern of dangerousPatterns) {\r\n if (normalizedPath.includes(pattern)) {\r\n throw new ValidationError(\r\n `Path traversal detected in asset path: ${path}`,\r\n 'path'\r\n );\r\n }\r\n }\r\n\r\n return path;\r\n}\r\n\r\n/**\r\n * Validate file extension against allowlist\r\n *\r\n * @param {string} filename - Filename to validate\r\n * @param {string[]} allowedExtensions - Array of allowed extensions (e.g., ['.ply', '.glb'])\r\n * @returns {string} Validated filename\r\n * @throws {ValidationError} If extension is not allowed\r\n */\r\nexport function validateFileExtension(filename, allowedExtensions) {\r\n if (typeof filename !== 'string' || filename.length === 0) {\r\n throw new ValidationError('Filename must be a non-empty string', 'filename');\r\n }\r\n\r\n if (!Array.isArray(allowedExtensions) || allowedExtensions.length === 0) {\r\n throw new ValidationError(\r\n 'allowedExtensions must be a non-empty array',\r\n 'allowedExtensions'\r\n );\r\n }\r\n\r\n const extension = filename.slice(filename.lastIndexOf('.')).toLowerCase();\r\n const normalizedAllowed = allowedExtensions.map(ext => ext.toLowerCase());\r\n\r\n if (!normalizedAllowed.includes(extension)) {\r\n throw new ValidationError(\r\n `File extension ${extension} not allowed. Allowed: ${allowedExtensions.join(', ')}`,\r\n 'filename'\r\n );\r\n }\r\n\r\n return filename;\r\n}\r\n\r\n/**\r\n * Validate numeric value is within range\r\n *\r\n * @param {number} value - Value to validate\r\n * @param {number} min - Minimum allowed value (inclusive)\r\n * @param {number} max - Maximum allowed value (inclusive)\r\n * @param {string} fieldName - Name of field for error messages\r\n * @returns {number} Validated value\r\n * @throws {ValidationError} If value is not a number or out of range\r\n */\r\nexport function validateNumberInRange(value, min, max, fieldName) {\r\n if (typeof value !== 'number' || isNaN(value)) {\r\n throw new ValidationError(\r\n `${fieldName} must be a valid number`,\r\n fieldName\r\n );\r\n }\r\n\r\n if (value < min || value > max) {\r\n throw new ValidationError(\r\n `${fieldName} must be between ${min} and ${max}, got ${value}`,\r\n fieldName\r\n );\r\n }\r\n\r\n return value;\r\n}\r\n\r\n/**\r\n * Validate integer value\r\n *\r\n * @param {number} value - Value to validate\r\n * @param {string} fieldName - Name of field for error messages\r\n * @returns {number} Validated integer\r\n * @throws {ValidationError} If value is not an integer\r\n */\r\nexport function validateInteger(value, fieldName) {\r\n if (typeof value !== 'number' || !Number.isInteger(value)) {\r\n throw new ValidationError(\r\n `${fieldName} must be an integer`,\r\n fieldName\r\n );\r\n }\r\n\r\n return value;\r\n}\r\n\r\n/**\r\n * Validate positive integer\r\n *\r\n * @param {number} value - Value to validate\r\n * @param {string} fieldName - Name of field for error messages\r\n * @returns {number} Validated positive integer\r\n * @throws {ValidationError} If value is not a positive integer\r\n */\r\nexport function validatePositiveInteger(value, fieldName) {\r\n validateInteger(value, fieldName);\r\n\r\n if (value <= 0) {\r\n throw new ValidationError(\r\n `${fieldName} must be positive, got ${value}`,\r\n fieldName\r\n );\r\n }\r\n\r\n return value;\r\n}\r\n\r\n/**\r\n * Validate object has required properties\r\n *\r\n * @param {object} obj - Object to validate\r\n * @param {string[]} requiredProps - Array of required property names\r\n * @param {string} objectName - Name of object for error messages\r\n * @returns {object} Validated object\r\n * @throws {ValidationError} If object is invalid or missing required properties\r\n */\r\nexport function validateRequiredProperties(obj, requiredProps, objectName) {\r\n if (obj === null || typeof obj !== 'object') {\r\n throw new ValidationError(\r\n `${objectName} must be an object`,\r\n objectName\r\n );\r\n }\r\n\r\n for (const prop of requiredProps) {\r\n if (!(prop in obj) || obj[prop] === undefined) {\r\n throw new ValidationError(\r\n `${objectName} missing required property: ${prop}`,\r\n `${objectName}.${prop}`\r\n );\r\n }\r\n }\r\n\r\n return obj;\r\n}\r\n\r\n/**\r\n * Validate array buffer\r\n *\r\n * @param {ArrayBuffer} buffer - Buffer to validate\r\n * @param {string} fieldName - Name of field for error messages\r\n * @param {number} [minSize=0] - Minimum size in bytes\r\n * @returns {ArrayBuffer} Validated buffer\r\n * @throws {ValidationError} If buffer is invalid or too small\r\n */\r\nexport function validateArrayBuffer(buffer, fieldName, minSize = 0) {\r\n if (!(buffer instanceof ArrayBuffer)) {\r\n throw new ValidationError(\r\n `${fieldName} must be an ArrayBuffer`,\r\n fieldName\r\n );\r\n }\r\n\r\n if (buffer.byteLength < minSize) {\r\n throw new ValidationError(\r\n `${fieldName} must be at least ${minSize} bytes, got ${buffer.byteLength}`,\r\n fieldName\r\n );\r\n }\r\n\r\n return buffer;\r\n}\r\n\r\n/**\r\n * Validate enum value against allowed values\r\n *\r\n * @param {*} value - Value to validate\r\n * @param {Array} allowedValues - Array of allowed values\r\n * @param {string} fieldName - Name of field for error messages\r\n * @returns {*} Validated value\r\n * @throws {ValidationError} If value is not in allowed values\r\n */\r\nexport function validateEnum(value, allowedValues, fieldName) {\r\n if (!allowedValues.includes(value)) {\r\n throw new ValidationError(\r\n `${fieldName} must be one of: ${allowedValues.join(', ')}. Got: ${value}`,\r\n fieldName\r\n );\r\n }\r\n\r\n return value;\r\n}\r\n\r\n/**\r\n * Validate callback function\r\n *\r\n * @param {Function} callback - Callback to validate\r\n * @param {string} fieldName - Name of field for error messages\r\n * @param {boolean} [required=true] - Whether callback is required\r\n * @returns {Function|null} Validated callback or null if not required and not provided\r\n * @throws {ValidationError} If callback is required but not a function\r\n */\r\nexport function validateCallback(callback, fieldName, required = true) {\r\n if (callback === null || callback === undefined) {\r\n if (required) {\r\n throw new ValidationError(\r\n `${fieldName} is required`,\r\n fieldName\r\n );\r\n }\r\n return null;\r\n }\r\n\r\n if (typeof callback !== 'function') {\r\n throw new ValidationError(\r\n `${fieldName} must be a function`,\r\n fieldName\r\n );\r\n }\r\n\r\n return callback;\r\n}\r\n\r\n/**\r\n * Validate hex color string\r\n *\r\n * @param {string} value - Color string to validate\r\n * @param {string} fieldName - Name of field for error messages\r\n * @returns {string} Validated color string\r\n * @throws {ValidationError} If color format is invalid\r\n */\r\nexport function validateHexColor(value, fieldName) {\r\n if (typeof value !== 'string') {\r\n throw new ValidationError(\r\n `${fieldName} must be a string`,\r\n fieldName\r\n );\r\n }\r\n\r\n const hexColorRegex = /^(#|0x)[0-9A-Fa-f]{6}$/i;\r\n if (!hexColorRegex.test(value)) {\r\n throw new ValidationError(\r\n `${fieldName} must be a valid hex color (e.g., #FFFFFF or 0xFFFFFF)`,\r\n fieldName\r\n );\r\n }\r\n\r\n return value;\r\n}\r\n\r\n/**\r\n * Validate DOM element\r\n *\r\n * @param {HTMLElement} element - Element to validate\r\n * @param {string} fieldName - Name of field for error messages\r\n * @returns {HTMLElement} Validated element\r\n * @throws {ValidationError} If element is not a valid DOM element\r\n */\r\nexport function validateDOMElement(element, fieldName) {\r\n if (typeof HTMLElement !== 'undefined' && !(element instanceof HTMLElement)) {\r\n throw new ValidationError(\r\n `${fieldName} must be a valid HTML element`,\r\n fieldName\r\n );\r\n }\r\n\r\n return element;\r\n}\r\n","/**\r\n * ObjectPool - Memory-efficient object pooling\r\n *\r\n * Reduces garbage collection pressure by reusing objects instead of\r\n * repeatedly allocating and deallocating them. Critical for real-time rendering.\r\n */\r\n\r\nimport { Vector3, Matrix4, Quaternion, Euler } from 'three';\r\n\r\n/**\r\n * Generic object pool\r\n */\r\nexport class ObjectPool {\r\n /**\r\n * Create an ObjectPool\r\n * @param {Function} factory - Function that creates new objects\r\n * @param {Function} reset - Function that resets an object to initial state\r\n * @param {number} [initialSize=10] - Number of objects to pre-allocate\r\n */\r\n constructor(factory, reset, initialSize = 10) {\r\n this._factory = factory;\r\n this._reset = reset;\r\n this._pool = [];\r\n this._allocated = 0;\r\n this._maxSize = initialSize * 10; // Prevent unbounded growth\r\n\r\n // Pre-allocate initial objects\r\n for (let i = 0; i < initialSize; i++) {\r\n this._pool.push(factory());\r\n }\r\n }\r\n\r\n /**\r\n * Acquire an object from the pool\r\n * @returns {*} Pooled object\r\n */\r\n acquire() {\r\n this._allocated++;\r\n if (this._pool.length > 0) {\r\n return this._pool.pop();\r\n }\r\n // Pool exhausted, create new object\r\n return this._factory();\r\n }\r\n\r\n /**\r\n * Release an object back to the pool\r\n * @param {*} obj - Object to return to pool\r\n */\r\n release(obj) {\r\n this._allocated--;\r\n if (this._pool.length < this._maxSize) {\r\n this._reset(obj);\r\n this._pool.push(obj);\r\n }\r\n // If pool is at max size, let object be garbage collected\r\n }\r\n\r\n /**\r\n * Release multiple objects\r\n * @param {Array} objects - Objects to return to pool\r\n */\r\n releaseAll(objects) {\r\n for (const obj of objects) {\r\n this.release(obj);\r\n }\r\n }\r\n\r\n /**\r\n * Get pool statistics\r\n * @returns {object} Pool stats\r\n */\r\n getStats() {\r\n return {\r\n available: this._pool.length,\r\n allocated: this._allocated,\r\n maxSize: this._maxSize\r\n };\r\n }\r\n\r\n /**\r\n * Clear the pool and release all objects\r\n */\r\n dispose() {\r\n this._pool.length = 0;\r\n this._allocated = 0;\r\n }\r\n}\r\n\r\n/**\r\n * Pre-configured pools for common Three.js objects\r\n */\r\n\r\n/**\r\n * Vector3 pool\r\n * @type {ObjectPool}\r\n */\r\nexport const vector3Pool = new ObjectPool(\r\n () => new Vector3(),\r\n (v) => v.set(0, 0, 0),\r\n 50 // Pre-allocate 50 vectors\r\n);\r\n\r\n/**\r\n * Matrix4 pool\r\n * @type {ObjectPool}\r\n */\r\nexport const matrix4Pool = new ObjectPool(\r\n () => new Matrix4(),\r\n (m) => m.identity(),\r\n 20 // Pre-allocate 20 matrices\r\n);\r\n\r\n/**\r\n * Quaternion pool\r\n * @type {ObjectPool}\r\n */\r\nexport const quaternionPool = new ObjectPool(\r\n () => new Quaternion(),\r\n (q) => q.set(0, 0, 0, 1),\r\n 30 // Pre-allocate 30 quaternions\r\n);\r\n\r\n/**\r\n * Euler pool\r\n * @type {ObjectPool}\r\n */\r\nexport const eulerPool = new ObjectPool(\r\n () => new Euler(),\r\n (e) => e.set(0, 0, 0),\r\n 30 // Pre-allocate 30 eulers\r\n);\r\n\r\n/**\r\n * Scoped pool allocation helper\r\n *\r\n * Automatically releases pooled objects when scope exits.\r\n * Use with try/finally to ensure cleanup.\r\n *\r\n * @example\r\n * const scope = new PoolScope();\r\n * try {\r\n * const v1 = scope.vector3();\r\n * const v2 = scope.vector3();\r\n * // Use vectors...\r\n * } finally {\r\n * scope.releaseAll();\r\n * }\r\n */\r\nexport class PoolScope {\r\n constructor() {\r\n this._allocated = [];\r\n }\r\n\r\n /**\r\n * Acquire a Vector3 from pool\r\n * @returns {Vector3} Pooled vector\r\n */\r\n vector3() {\r\n const obj = vector3Pool.acquire();\r\n this._allocated.push({ pool: vector3Pool, obj });\r\n return obj;\r\n }\r\n\r\n /**\r\n * Acquire a Matrix4 from pool\r\n * @returns {Matrix4} Pooled matrix\r\n */\r\n matrix4() {\r\n const obj = matrix4Pool.acquire();\r\n this._allocated.push({ pool: matrix4Pool, obj });\r\n return obj;\r\n }\r\n\r\n /**\r\n * Acquire a Quaternion from pool\r\n * @returns {Quaternion} Pooled quaternion\r\n */\r\n quaternion() {\r\n const obj = quaternionPool.acquire();\r\n this._allocated.push({ pool: quaternionPool, obj });\r\n return obj;\r\n }\r\n\r\n /**\r\n * Acquire an Euler from pool\r\n * @returns {Euler} Pooled euler\r\n */\r\n euler() {\r\n const obj = eulerPool.acquire();\r\n this._allocated.push({ pool: eulerPool, obj });\r\n return obj;\r\n }\r\n\r\n /**\r\n * Release all objects allocated in this scope\r\n */\r\n releaseAll() {\r\n for (const { pool, obj } of this._allocated) {\r\n pool.release(obj);\r\n }\r\n this._allocated.length = 0;\r\n }\r\n\r\n /**\r\n * Get count of allocated objects in this scope\r\n * @returns {number} Number of allocated objects\r\n */\r\n getAllocatedCount() {\r\n return this._allocated.length;\r\n }\r\n}\r\n\r\n/**\r\n * Module-level temporary objects for hot-path reuse\r\n * IMPORTANT: These are NOT thread-safe. Only use in single-threaded contexts.\r\n * Reset these before use to avoid stale data.\r\n */\r\nexport const tempVector3A = new Vector3();\r\nexport const tempVector3B = new Vector3();\r\nexport const tempVector3C = new Vector3();\r\nexport const tempMatrix4A = new Matrix4();\r\nexport const tempMatrix4B = new Matrix4();\r\nexport const tempQuaternionA = new Quaternion();\r\nexport const tempQuaternionB = new Quaternion();\r\n\r\n/**\r\n * Get pool statistics for all pre-configured pools\r\n * @returns {object} Statistics for all pools\r\n */\r\nexport function getPoolStats() {\r\n return {\r\n vector3: vector3Pool.getStats(),\r\n matrix4: matrix4Pool.getStats(),\r\n quaternion: quaternionPool.getStats(),\r\n euler: eulerPool.getStats()\r\n };\r\n}\r\n\r\n/**\r\n * Dispose all pre-configured pools\r\n */\r\nexport function disposeAllPools() {\r\n vector3Pool.dispose();\r\n matrix4Pool.dispose();\r\n quaternionPool.dispose();\r\n eulerPool.dispose();\r\n}\r\n","/**\r\n * BlobUrlManager - Secure blob URL lifecycle management\r\n *\r\n * Tracks blob URLs and ensures they are revoked to prevent memory leaks\r\n * and unauthorized access. Critical for security and resource management.\r\n */\r\n\r\nimport { getLogger } from './Logger.js';\r\nimport { ValidationError } from '../errors/index.js';\r\n\r\nconst logger = getLogger('BlobUrlManager');\r\n\r\n/**\r\n * BlobUrlManager - Manages blob URL lifecycle\r\n */\r\nexport class BlobUrlManager {\r\n constructor() {\r\n /**\r\n * Map of blob URL to metadata\r\n * @private\r\n */\r\n this._urls = new Map();\r\n\r\n /**\r\n * Whether manager has been disposed\r\n * @private\r\n */\r\n this._disposed = false;\r\n }\r\n\r\n /**\r\n * Assert manager is not disposed\r\n * @private\r\n * @throws {Error} If manager is disposed\r\n */\r\n _assertNotDisposed() {\r\n if (this._disposed) {\r\n throw new Error('BlobUrlManager has been disposed');\r\n }\r\n }\r\n\r\n /**\r\n * Create a blob URL from data\r\n *\r\n * @param {Blob|ArrayBuffer|Uint8Array} data - Data to create blob from\r\n * @param {string} mimeType - MIME type (e.g., 'model/gltf-binary')\r\n * @param {string} [label] - Optional label for debugging\r\n * @returns {string} Blob URL\r\n * @throws {ValidationError} If data or mimeType is invalid\r\n */\r\n createBlobUrl(data, mimeType, label = '') {\r\n this._assertNotDisposed();\r\n\r\n // Validate mimeType\r\n if (typeof mimeType !== 'string' || mimeType.length === 0) {\r\n throw new ValidationError(\r\n 'mimeType must be a non-empty string',\r\n 'mimeType'\r\n );\r\n }\r\n\r\n // Convert data to Blob if needed\r\n let blob;\r\n if (data instanceof Blob) {\r\n blob = data;\r\n } else if (data instanceof ArrayBuffer || data instanceof Uint8Array) {\r\n blob = new Blob([data], { type: mimeType });\r\n } else {\r\n throw new ValidationError(\r\n 'data must be Blob, ArrayBuffer, or Uint8Array',\r\n 'data'\r\n );\r\n }\r\n\r\n // Create blob URL\r\n const url = URL.createObjectURL(blob);\r\n\r\n // Track metadata\r\n this._urls.set(url, {\r\n createdAt: Date.now(),\r\n mimeType,\r\n label: label || 'unlabeled',\r\n size: blob.size\r\n });\r\n\r\n logger.debug(`Created blob URL: ${label || url.substring(0, 50)}, size: ${blob.size} bytes`);\r\n\r\n return url;\r\n }\r\n\r\n /**\r\n * Register an externally created blob URL for tracking\r\n *\r\n * @param {string} url - Blob URL to track\r\n * @param {string} [label] - Optional label for debugging\r\n * @throws {ValidationError} If URL is not a blob URL\r\n */\r\n registerBlobUrl(url, label = '') {\r\n this._assertNotDisposed();\r\n\r\n if (typeof url !== 'string' || !url.startsWith('blob:')) {\r\n throw new ValidationError(\r\n 'url must be a valid blob URL',\r\n 'url'\r\n );\r\n }\r\n\r\n if (!this._urls.has(url)) {\r\n this._urls.set(url, {\r\n createdAt: Date.now(),\r\n mimeType: 'unknown',\r\n label: label || 'registered-external',\r\n size: 0\r\n });\r\n\r\n logger.debug(`Registered external blob URL: ${label || url.substring(0, 50)}`);\r\n }\r\n }\r\n\r\n /**\r\n * Revoke a blob URL and remove from tracking\r\n *\r\n * @param {string} url - Blob URL to revoke\r\n * @returns {boolean} True if URL was tracked and revoked\r\n */\r\n revokeBlobUrl(url) {\r\n this._assertNotDisposed();\r\n\r\n if (this._urls.has(url)) {\r\n const metadata = this._urls.get(url);\r\n URL.revokeObjectURL(url);\r\n this._urls.delete(url);\r\n\r\n logger.debug(`Revoked blob URL: ${metadata.label}, age: ${Date.now() - metadata.createdAt}ms`);\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Revoke all blob URLs and clear tracking\r\n */\r\n revokeAll() {\r\n this._assertNotDisposed();\r\n\r\n logger.debug(`Revoking ${this._urls.size} blob URLs`);\r\n\r\n for (const url of this._urls.keys()) {\r\n URL.revokeObjectURL(url);\r\n }\r\n\r\n this._urls.clear();\r\n }\r\n\r\n /**\r\n * Get tracked blob URL metadata\r\n *\r\n * @param {string} url - Blob URL\r\n * @returns {object|null} Metadata or null if not tracked\r\n */\r\n getMetadata(url) {\r\n return this._urls.get(url) || null;\r\n }\r\n\r\n /**\r\n * Get all tracked blob URLs\r\n *\r\n * @returns {Array<{url: string, metadata: object}>} Array of URL info\r\n */\r\n getAllTrackedUrls() {\r\n const urls = [];\r\n for (const [url, metadata] of this._urls.entries()) {\r\n urls.push({ url, metadata });\r\n }\r\n return urls;\r\n }\r\n\r\n /**\r\n * Get statistics about tracked URLs\r\n *\r\n * @returns {object} Statistics\r\n */\r\n getStats() {\r\n let totalSize = 0;\r\n let oldestAge = 0;\r\n const now = Date.now();\r\n\r\n for (const metadata of this._urls.values()) {\r\n totalSize += metadata.size;\r\n const age = now - metadata.createdAt;\r\n if (age > oldestAge) {\r\n oldestAge = age;\r\n }\r\n }\r\n\r\n return {\r\n count: this._urls.size,\r\n totalSize,\r\n oldestAge\r\n };\r\n }\r\n\r\n /**\r\n * Revoke blob URLs older than specified age\r\n *\r\n * @param {number} maxAgeMs - Maximum age in milliseconds\r\n * @returns {number} Number of URLs revoked\r\n */\r\n revokeOlderThan(maxAgeMs) {\r\n this._assertNotDisposed();\r\n\r\n const now = Date.now();\r\n const toRevoke = [];\r\n\r\n for (const [url, metadata] of this._urls.entries()) {\r\n const age = now - metadata.createdAt;\r\n if (age > maxAgeMs) {\r\n toRevoke.push(url);\r\n }\r\n }\r\n\r\n for (const url of toRevoke) {\r\n this.revokeBlobUrl(url);\r\n }\r\n\r\n if (toRevoke.length > 0) {\r\n logger.info(`Revoked ${toRevoke.length} blob URLs older than ${maxAgeMs}ms`);\r\n }\r\n\r\n return toRevoke.length;\r\n }\r\n\r\n /**\r\n * Check if a URL is being tracked\r\n *\r\n * @param {string} url - URL to check\r\n * @returns {boolean} True if URL is tracked\r\n */\r\n isTracked(url) {\r\n return this._urls.has(url);\r\n }\r\n\r\n /**\r\n * Dispose manager and revoke all URLs\r\n */\r\n dispose() {\r\n if (this._disposed) {\r\n return;\r\n }\r\n\r\n logger.debug('Disposing BlobUrlManager');\r\n this.revokeAll();\r\n this._disposed = true;\r\n }\r\n}\r\n\r\n/**\r\n * Global blob URL manager instance\r\n * @type {BlobUrlManager}\r\n */\r\nconst globalBlobUrlManager = new BlobUrlManager();\r\n\r\n/**\r\n * Get the global blob URL manager\r\n * @returns {BlobUrlManager} Global manager instance\r\n */\r\nexport function getGlobalBlobUrlManager() {\r\n return globalBlobUrlManager;\r\n}\r\n\r\n/**\r\n * Helper function to create a blob URL with automatic tracking\r\n *\r\n * @param {Blob|ArrayBuffer|Uint8Array} data - Data to create blob from\r\n * @param {string} mimeType - MIME type\r\n * @param {string} [label] - Optional label for debugging\r\n * @returns {string} Blob URL\r\n */\r\nexport function createTrackedBlobUrl(data, mimeType, label) {\r\n return globalBlobUrlManager.createBlobUrl(data, mimeType, label);\r\n}\r\n\r\n/**\r\n * Helper function to revoke a blob URL\r\n *\r\n * @param {string} url - Blob URL to revoke\r\n * @returns {boolean} True if URL was tracked and revoked\r\n */\r\nexport function revokeTrackedBlobUrl(url) {\r\n return globalBlobUrlManager.revokeBlobUrl(url);\r\n}\r\n\r\nexport default BlobUrlManager;\r\n","/**\r\n * RenderLoop - Frame-independent animation loop with budget management\r\n *\r\n * Provides a robust requestAnimationFrame loop with:\r\n * - Delta time calculation for frame-independent updates\r\n * - Frame budget management to prevent frame drops\r\n * - Deferred task execution\r\n * - Performance monitoring\r\n */\r\n\r\nimport { getLogger } from './Logger.js';\r\n\r\nconst logger = getLogger('RenderLoop');\r\n\r\n/**\r\n * RenderLoop - Manages animation frame loop\r\n */\r\nexport class RenderLoop {\r\n /**\r\n * Create a RenderLoop\r\n * @param {Function} updateFn - Update function called each frame with deltaTime\r\n * @param {Function} renderFn - Render function called each frame\r\n * @param {object} [options] - Configuration options\r\n * @param {number} [options.targetFps=60] - Target frames per second\r\n * @param {number} [options.maxDeltaTime=0.1] - Maximum delta time in seconds (prevents spiral of death)\r\n */\r\n constructor(updateFn, renderFn, options = {}) {\r\n this._update = updateFn;\r\n this._render = renderFn;\r\n\r\n this._targetFps = options.targetFps || 60;\r\n this._maxDeltaTime = options.maxDeltaTime || 0.1; // 100ms max\r\n this._frameBudget = 1000 / this._targetFps; // ms per frame\r\n\r\n this._running = false;\r\n this._rafId = null;\r\n this._lastTime = 0;\r\n this._frameCount = 0;\r\n this._deferredTasks = [];\r\n\r\n // Performance tracking\r\n this._fpsHistory = [];\r\n this._fpsHistorySize = 60; // Track last 60 frames\r\n this._lastFpsUpdate = 0;\r\n this._currentFps = 0;\r\n }\r\n\r\n /**\r\n * Start the render loop\r\n */\r\n start() {\r\n if (this._running) {\r\n logger.warn('RenderLoop already running');\r\n return;\r\n }\r\n\r\n this._running = true;\r\n this._lastTime = performance.now();\r\n this._frameCount = 0;\r\n logger.info('RenderLoop started');\r\n\r\n this._tick();\r\n }\r\n\r\n /**\r\n * Stop the render loop\r\n */\r\n stop() {\r\n if (!this._running) {\r\n return;\r\n }\r\n\r\n this._running = false;\r\n\r\n if (this._rafId !== null) {\r\n cancelAnimationFrame(this._rafId);\r\n this._rafId = null;\r\n }\r\n\r\n logger.info(`RenderLoop stopped after ${this._frameCount} frames`);\r\n }\r\n\r\n /**\r\n * Main loop tick\r\n * @private\r\n */\r\n _tick = () => {\r\n if (!this._running) {\r\n return;\r\n }\r\n\r\n const frameStart = performance.now();\r\n const rawDeltaTime = (frameStart - this._lastTime) / 1000; // Convert to seconds\r\n\r\n // Clamp delta time to prevent spiral of death\r\n const deltaTime = Math.min(rawDeltaTime, this._maxDeltaTime);\r\n\r\n this._lastTime = frameStart;\r\n this._frameCount++;\r\n\r\n try {\r\n // Update logic\r\n this._update(deltaTime);\r\n\r\n // Render\r\n this._render();\r\n\r\n // Process deferred tasks if time permits\r\n const frameElapsed = performance.now() - frameStart;\r\n const remainingTime = this._frameBudget - frameElapsed;\r\n\r\n if (remainingTime > 1 && this._deferredTasks.length > 0) {\r\n this._processDeferredTasks(remainingTime - 1); // Leave 1ms margin\r\n }\r\n\r\n // Update FPS tracking\r\n this._updateFpsTracking(performance.now() - frameStart);\r\n\r\n } catch (error) {\r\n logger.error('Error in render loop:', error);\r\n // Continue loop despite error\r\n }\r\n\r\n // Schedule next frame\r\n this._rafId = requestAnimationFrame(this._tick);\r\n };\r\n\r\n /**\r\n * Update FPS tracking\r\n * @private\r\n * @param {number} frameTime - Time taken for this frame in ms\r\n */\r\n _updateFpsTracking(frameTime) {\r\n this._fpsHistory.push(1000 / frameTime);\r\n\r\n if (this._fpsHistory.length > this._fpsHistorySize) {\r\n this._fpsHistory.shift();\r\n }\r\n\r\n // Update FPS every second\r\n const now = performance.now();\r\n if (now - this._lastFpsUpdate > 1000) {\r\n this._currentFps = this._fpsHistory.reduce((a, b) => a + b, 0) / this._fpsHistory.length;\r\n this._lastFpsUpdate = now;\r\n }\r\n }\r\n\r\n /**\r\n * Process deferred tasks within time budget\r\n * @private\r\n * @param {number} maxTime - Maximum time in ms to spend on tasks\r\n */\r\n _processDeferredTasks(maxTime) {\r\n const startTime = performance.now();\r\n\r\n while (this._deferredTasks.length > 0) {\r\n if (performance.now() - startTime >= maxTime) {\r\n break;\r\n }\r\n\r\n const task = this._deferredTasks.shift();\r\n\r\n try {\r\n task.fn();\r\n } catch (error) {\r\n logger.error(`Error in deferred task: ${task.label}`, error);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Execute task if within frame budget, otherwise defer\r\n *\r\n * @param {Function} task - Task function to execute\r\n * @param {number} [priority=0] - Task priority (higher = more important)\r\n * @param {string} [label=''] - Task label for debugging\r\n */\r\n executeOrDefer(task, priority = 0, label = '') {\r\n const frameElapsed = performance.now() - this._lastTime;\r\n\r\n if (frameElapsed < this._frameBudget * 0.8) {\r\n // Within budget, execute now\r\n task();\r\n } else {\r\n // Over budget, defer\r\n this._deferredTasks.push({ fn: task, priority, label });\r\n\r\n // Sort by priority (higher first)\r\n this._deferredTasks.sort((a, b) => b.priority - a.priority);\r\n }\r\n }\r\n\r\n /**\r\n * Get current FPS\r\n * @returns {number} Average FPS over recent frames\r\n */\r\n getFps() {\r\n return Math.round(this._currentFps);\r\n }\r\n\r\n /**\r\n * Get performance stats\r\n * @returns {object} Performance statistics\r\n */\r\n getStats() {\r\n return {\r\n fps: this.getFps(),\r\n frameCount: this._frameCount,\r\n deferredTaskCount: this._deferredTasks.length,\r\n running: this._running\r\n };\r\n }\r\n\r\n /**\r\n * Check if loop is running\r\n * @returns {boolean} True if running\r\n */\r\n isRunning() {\r\n return this._running;\r\n }\r\n\r\n /**\r\n * Get frame count\r\n * @returns {number} Total frames rendered\r\n */\r\n getFrameCount() {\r\n return this._frameCount;\r\n }\r\n\r\n /**\r\n * Clear all deferred tasks\r\n */\r\n clearDeferredTasks() {\r\n this._deferredTasks.length = 0;\r\n logger.debug('Cleared all deferred tasks');\r\n }\r\n}\r\n\r\n/**\r\n * FrameBudgetMonitor - Monitors and alerts on frame budget violations\r\n */\r\nexport class FrameBudgetMonitor {\r\n /**\r\n * Create a FrameBudgetMonitor\r\n * @param {number} [targetFps=60] - Target FPS\r\n * @param {Function} [onViolation] - Callback when budget is violated\r\n */\r\n constructor(targetFps = 60, onViolation = null) {\r\n this._targetFps = targetFps;\r\n this._frameBudget = 1000 / targetFps;\r\n this._onViolation = onViolation;\r\n this._violations = 0;\r\n this._frameStart = 0;\r\n }\r\n\r\n /**\r\n * Mark start of frame\r\n */\r\n startFrame() {\r\n this._frameStart = performance.now();\r\n }\r\n\r\n /**\r\n * Check if frame is within budget\r\n * @param {string} [location] - Location identifier for debugging\r\n * @returns {boolean} True if within budget\r\n */\r\n checkBudget(location = '') {\r\n const elapsed = performance.now() - this._frameStart;\r\n const withinBudget = elapsed < this._frameBudget;\r\n\r\n if (!withinBudget) {\r\n this._violations++;\r\n\r\n if (this._onViolation) {\r\n this._onViolation({\r\n location,\r\n elapsed,\r\n budget: this._frameBudget,\r\n overrun: elapsed - this._frameBudget\r\n });\r\n }\r\n\r\n logger.warn(`Frame budget violation at ${location}: ${elapsed.toFixed(2)}ms / ${this._frameBudget.toFixed(2)}ms`);\r\n }\r\n\r\n return withinBudget;\r\n }\r\n\r\n /**\r\n * Get violation count\r\n * @returns {number} Total violations\r\n */\r\n getViolationCount() {\r\n return this._violations;\r\n }\r\n\r\n /**\r\n * Reset violation count\r\n */\r\n resetViolations() {\r\n this._violations = 0;\r\n }\r\n}\r\n\r\nexport default RenderLoop;\r\n","/**\r\n * EventEmitter - Observer pattern implementation for event-driven communication\r\n *\r\n * Provides decoupled event handling with automatic cleanup to prevent memory leaks.\r\n * Critical for managing state changes and component communication.\r\n */\r\n\r\nimport { getLogger } from './Logger.js';\r\nimport { ValidationError } from '../errors/index.js';\r\n\r\nconst logger = getLogger('EventEmitter');\r\n\r\n/**\r\n * EventEmitter - Pub/sub event system\r\n */\r\nexport class EventEmitter {\r\n constructor() {\r\n /**\r\n * Map of event name to Set of listeners\r\n * @private\r\n */\r\n this._listeners = new Map();\r\n\r\n /**\r\n * Whether emitter has been disposed\r\n * @private\r\n */\r\n this._disposed = false;\r\n\r\n /**\r\n * Event emission history for debugging (last N events)\r\n * @private\r\n */\r\n this._eventHistory = [];\r\n this._maxHistorySize = 50;\r\n }\r\n\r\n /**\r\n * Assert emitter is not disposed\r\n * @private\r\n * @throws {Error} If emitter is disposed\r\n */\r\n _assertNotDisposed() {\r\n if (this._disposed) {\r\n throw new Error('EventEmitter has been disposed');\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to an event\r\n *\r\n * @param {string} event - Event name\r\n * @param {Function} callback - Event handler\r\n * @param {object} [options] - Subscription options\r\n * @param {boolean} [options.once=false] - Auto-unsubscribe after first call\r\n * @returns {Function} Unsubscribe function\r\n * @throws {ValidationError} If parameters are invalid\r\n */\r\n on(event, callback, options = {}) {\r\n this._assertNotDisposed();\r\n\r\n if (typeof event !== 'string' || event.length === 0) {\r\n throw new ValidationError(\r\n 'event must be a non-empty string',\r\n 'event'\r\n );\r\n }\r\n\r\n if (typeof callback !== 'function') {\r\n throw new ValidationError(\r\n 'callback must be a function',\r\n 'callback'\r\n );\r\n }\r\n\r\n // Wrap callback if once option is set\r\n const wrappedCallback = options.once\r\n ? (...args) => {\r\n this.off(event, wrappedCallback);\r\n callback(...args);\r\n }\r\n : callback;\r\n\r\n // Store original callback reference for removal\r\n if (options.once) {\r\n wrappedCallback._originalCallback = callback;\r\n }\r\n\r\n // Add listener\r\n if (!this._listeners.has(event)) {\r\n this._listeners.set(event, new Set());\r\n }\r\n this._listeners.get(event).add(wrappedCallback);\r\n\r\n logger.debug(`Subscribed to event: ${event}`);\r\n\r\n // Return unsubscribe function\r\n return () => this.off(event, wrappedCallback);\r\n }\r\n\r\n /**\r\n * Subscribe to an event (fires once then auto-unsubscribes)\r\n *\r\n * @param {string} event - Event name\r\n * @param {Function} callback - Event handler\r\n * @returns {Function} Unsubscribe function\r\n */\r\n once(event, callback) {\r\n return this.on(event, callback, { once: true });\r\n }\r\n\r\n /**\r\n * Unsubscribe from an event\r\n *\r\n * @param {string} event - Event name\r\n * @param {Function} callback - Event handler to remove\r\n * @returns {boolean} True if callback was found and removed\r\n */\r\n off(event, callback) {\r\n this._assertNotDisposed();\r\n\r\n const listeners = this._listeners.get(event);\r\n if (!listeners) {\r\n return false;\r\n }\r\n\r\n // Try to remove directly\r\n if (listeners.delete(callback)) {\r\n logger.debug(`Unsubscribed from event: ${event}`);\r\n return true;\r\n }\r\n\r\n // Try to find by original callback (for once listeners)\r\n for (const listener of listeners) {\r\n if (listener._originalCallback === callback) {\r\n listeners.delete(listener);\r\n logger.debug(`Unsubscribed from event: ${event} (once listener)`);\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Remove all listeners for an event (or all events if no event specified)\r\n *\r\n * @param {string} [event] - Event name (optional)\r\n */\r\n removeAllListeners(event = null) {\r\n this._assertNotDisposed();\r\n\r\n if (event) {\r\n const count = this._listeners.get(event)?.size || 0;\r\n this._listeners.delete(event);\r\n logger.debug(`Removed ${count} listeners for event: ${event}`);\r\n } else {\r\n const totalCount = Array.from(this._listeners.values())\r\n .reduce((sum, set) => sum + set.size, 0);\r\n this._listeners.clear();\r\n logger.debug(`Removed all ${totalCount} listeners`);\r\n }\r\n }\r\n\r\n /**\r\n * Emit an event to all subscribers\r\n *\r\n * @param {string} event - Event name\r\n * @param {...*} args - Arguments to pass to listeners\r\n * @returns {boolean} True if event had listeners\r\n */\r\n emit(event, ...args) {\r\n this._assertNotDisposed();\r\n\r\n const listeners = this._listeners.get(event);\r\n if (!listeners || listeners.size === 0) {\r\n return false;\r\n }\r\n\r\n // Record in history for debugging\r\n this._recordEvent(event, args);\r\n\r\n // Call all listeners\r\n let callCount = 0;\r\n for (const callback of listeners) {\r\n try {\r\n callback(...args);\r\n callCount++;\r\n } catch (error) {\r\n logger.error(`Error in event listener for '${event}':`, error);\r\n // Continue calling other listeners\r\n }\r\n }\r\n\r\n logger.debug(`Emitted event: ${event} to ${callCount} listeners`);\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Record event in history for debugging\r\n * @private\r\n * @param {string} event - Event name\r\n * @param {Array} args - Event arguments\r\n */\r\n _recordEvent(event, args) {\r\n this._eventHistory.push({\r\n event,\r\n timestamp: Date.now(),\r\n argCount: args.length\r\n });\r\n\r\n // Keep history bounded\r\n if (this._eventHistory.length > this._maxHistorySize) {\r\n this._eventHistory.shift();\r\n }\r\n }\r\n\r\n /**\r\n * Get event emission history\r\n * @returns {Array} Array of event records\r\n */\r\n getEventHistory() {\r\n return [...this._eventHistory];\r\n }\r\n\r\n /**\r\n * Check if event has listeners\r\n *\r\n * @param {string} event - Event name\r\n * @returns {boolean} True if event has listeners\r\n */\r\n hasListeners(event) {\r\n const listeners = this._listeners.get(event);\r\n return listeners ? listeners.size > 0 : false;\r\n }\r\n\r\n /**\r\n * Get listener count for an event\r\n *\r\n * @param {string} event - Event name\r\n * @returns {number} Number of listeners\r\n */\r\n listenerCount(event) {\r\n const listeners = this._listeners.get(event);\r\n return listeners ? listeners.size : 0;\r\n }\r\n\r\n /**\r\n * Get all event names with listeners\r\n *\r\n * @returns {string[]} Array of event names\r\n */\r\n eventNames() {\r\n return Array.from(this._listeners.keys());\r\n }\r\n\r\n /**\r\n * Get statistics about listeners\r\n *\r\n * @returns {object} Statistics\r\n */\r\n getStats() {\r\n const stats = {\r\n totalEvents: this._listeners.size,\r\n totalListeners: 0,\r\n eventBreakdown: {}\r\n };\r\n\r\n for (const [event, listeners] of this._listeners.entries()) {\r\n const count = listeners.size;\r\n stats.totalListeners += count;\r\n stats.eventBreakdown[event] = count;\r\n }\r\n\r\n return stats;\r\n }\r\n\r\n /**\r\n * Dispose emitter and remove all listeners\r\n */\r\n dispose() {\r\n if (this._disposed) {\r\n return;\r\n }\r\n\r\n logger.debug('Disposing EventEmitter');\r\n this.removeAllListeners();\r\n this._eventHistory.length = 0;\r\n this._disposed = true;\r\n }\r\n}\r\n\r\n/**\r\n * TypedEventEmitter - Type-safe event emitter with event registry\r\n *\r\n * Ensures events are pre-registered, preventing typos and providing\r\n * better developer experience.\r\n */\r\nexport class TypedEventEmitter extends EventEmitter {\r\n /**\r\n * Create a TypedEventEmitter\r\n * @param {string[]} allowedEvents - Array of allowed event names\r\n */\r\n constructor(allowedEvents) {\r\n super();\r\n\r\n /**\r\n * Set of allowed event names\r\n * @private\r\n */\r\n this._allowedEvents = new Set(allowedEvents);\r\n }\r\n\r\n /**\r\n * Validate event name is allowed\r\n * @private\r\n * @param {string} event - Event name\r\n * @throws {ValidationError} If event is not allowed\r\n */\r\n _validateEvent(event) {\r\n if (!this._allowedEvents.has(event)) {\r\n throw new ValidationError(\r\n `Event '${event}' is not registered. Allowed events: ${Array.from(this._allowedEvents).join(', ')}`,\r\n 'event'\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to an event (override to add validation)\r\n * @override\r\n */\r\n on(event, callback, options) {\r\n this._validateEvent(event);\r\n return super.on(event, callback, options);\r\n }\r\n\r\n /**\r\n * Emit an event (override to add validation)\r\n * @override\r\n */\r\n emit(event, ...args) {\r\n this._validateEvent(event);\r\n return super.emit(event, ...args);\r\n }\r\n}\r\n\r\nexport default EventEmitter;\r\n","/**\r\n * AppConstants\r\n * \r\n * Derived from gaussian-splat-renderer-for-lam\r\n * Animation state constants and ARKit blendshape mappings.\r\n */\r\n\r\n/**\r\n * Voice chat state enumeration\r\n * Controls the rendering and behavior modes of the avatar\r\n */\r\nexport const TYVoiceChatState = {\r\n Idle: 'Idle', // Idle/waiting state\r\n Listening: 'Listening', // Listening to user input\r\n Responding: 'Responding', // Speaking/responding animation\r\n Thinking: 'Thinking' // Processing/thinking animation\r\n};\r\n\r\n/**\r\n * ARKit blendshape names (52 expressions)\r\n * Used for facial expression mapping from ARKit face tracking\r\n */\r\nexport const ARKitBlendshapes = [\r\n 'browDownLeft',\r\n 'browDownRight',\r\n 'browInnerUp',\r\n 'browOuterUpLeft',\r\n 'browOuterUpRight',\r\n 'cheekPuff',\r\n 'cheekSquintLeft',\r\n 'cheekSquintRight',\r\n 'eyeBlinkLeft',\r\n 'eyeBlinkRight',\r\n 'eyeLookDownLeft',\r\n 'eyeLookDownRight',\r\n 'eyeLookInLeft',\r\n 'eyeLookInRight',\r\n 'eyeLookOutLeft',\r\n 'eyeLookOutRight',\r\n 'eyeLookUpLeft',\r\n 'eyeLookUpRight',\r\n 'eyeSquintLeft',\r\n 'eyeSquintRight',\r\n 'eyeWideLeft',\r\n 'eyeWideRight',\r\n 'jawForward',\r\n 'jawLeft',\r\n 'jawOpen',\r\n 'jawRight',\r\n 'mouthClose',\r\n 'mouthDimpleLeft',\r\n 'mouthDimpleRight',\r\n 'mouthFrownLeft',\r\n 'mouthFrownRight',\r\n 'mouthFunnel',\r\n 'mouthLeft',\r\n 'mouthLowerDownLeft',\r\n 'mouthLowerDownRight',\r\n 'mouthPressLeft',\r\n 'mouthPressRight',\r\n 'mouthPucker',\r\n 'mouthRight',\r\n 'mouthRollLower',\r\n 'mouthRollUpper',\r\n 'mouthShrugLower',\r\n 'mouthShrugUpper',\r\n 'mouthSmileLeft',\r\n 'mouthSmileRight',\r\n 'mouthStretchLeft',\r\n 'mouthStretchRight',\r\n 'mouthUpperUpLeft',\r\n 'mouthUpperUpRight',\r\n 'noseSneerLeft',\r\n 'noseSneerRight',\r\n 'tongueOut'\r\n];\r\n\r\n/**\r\n * FLAME model bone names\r\n */\r\nexport const FlameBoneNames = [\r\n 'root',\r\n 'neck',\r\n 'jaw',\r\n 'leftEye',\r\n 'rightEye'\r\n];\r\n\r\n/**\r\n * Constants derived from the arrays\r\n */\r\nexport const ARKIT_BLENDSHAPES_COUNT = ARKitBlendshapes.length;\r\nexport const FLAME_BONES_COUNT = FlameBoneNames.length;\r\n\r\nexport default {\r\n TYVoiceChatState,\r\n ARKitBlendshapes,\r\n FlameBoneNames,\r\n ARKIT_BLENDSHAPES_COUNT,\r\n FLAME_BONES_COUNT\r\n};\r\n","/**\r\n * AnimationManager\r\n *\r\n * Derived from gaussian-splat-renderer-for-lam\r\n * Manages animation state machine with Three.js AnimationMixer.\r\n */\r\n\r\nimport { LoopOnce, LoopRepeat } from 'three';\r\nimport { TYVoiceChatState } from './AppConstants.js';\r\nimport { getLogger } from '../utils/Logger.js';\r\n\r\nconst logger = getLogger('AnimationManager');\r\n\r\n/**\r\n * Base State class for animation states\r\n */\r\nclass State {\r\n constructor(actions, isGroup) {\r\n this.isPlaying = false;\r\n this.stage = 0;\r\n this.actions = actions || [];\r\n this.blendingTime = 0.5;\r\n this.isGroup = isGroup || false;\r\n }\r\n\r\n dispose() {\r\n this.actions = [];\r\n }\r\n\r\n update(state) {\r\n // Override in subclasses\r\n }\r\n}\r\n\r\n/**\r\n * Hello state - initial greeting animation\r\n */\r\nclass Hello extends State {\r\n constructor(actions, isGroup) {\r\n super(actions, isGroup);\r\n }\r\n\r\n update(state) {\r\n // Safety check: return early if no actions available\r\n if (!this.actions || this.actions.length === 0) return;\r\n \r\n if (AnimationManager.CurPlaying === undefined &&\r\n state === TYVoiceChatState.Idle &&\r\n this.isPlaying === false) {\r\n this.stage = 0;\r\n this.actions[this.stage].time = 0;\r\n AnimationManager.SetWeight(this.actions[this.stage], 1.0);\r\n this.actions[this.stage].loop = LoopRepeat;\r\n this.actions[this.stage].clampWhenFinished = false;\r\n this.actions[this.stage].paused = false;\r\n this.actions[this.stage].play();\r\n if (AnimationManager.LastAction !== undefined) {\r\n AnimationManager.PrepareCrossFade(AnimationManager.LastAction, this.actions[this.stage], this.blendingTime);\r\n }\r\n this.isPlaying = true;\r\n }\r\n\r\n if (AnimationManager.CurPlaying === TYVoiceChatState.Idle &&\r\n state === TYVoiceChatState.Idle &&\r\n this.isPlaying === true) {\r\n if (this.actions[this.stage].time >\r\n this.actions[this.stage].getClip().duration - this.blendingTime) {\r\n let nextStage = this.stage + 1;\r\n if (nextStage >= this.actions.length) nextStage = 0;\r\n this.actions[nextStage].time = 0;\r\n AnimationManager.SetWeight(this.actions[nextStage], 1.0);\r\n this.actions[nextStage].loop = LoopRepeat;\r\n this.actions[nextStage].play();\r\n AnimationManager.PrepareCrossFade(this.actions[this.stage], this.actions[nextStage], this.blendingTime);\r\n this.stage = nextStage;\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Idle state - resting animation\r\n */\r\nclass Idle extends State {\r\n constructor(actions, isGroup) {\r\n super(actions, isGroup);\r\n }\r\n\r\n update(state) {\r\n // Safety check: return early if no actions available\r\n if (!this.actions || this.actions.length === 0) return;\r\n \r\n if (AnimationManager.CurPlaying === undefined &&\r\n state === TYVoiceChatState.Idle &&\r\n this.isPlaying === false) {\r\n this.stage = 0;\r\n this.actions[this.stage].time = 0;\r\n AnimationManager.SetWeight(this.actions[this.stage], 1.0);\r\n this.actions[this.stage].loop = LoopRepeat;\r\n this.actions[this.stage].clampWhenFinished = false;\r\n this.actions[this.stage].paused = false;\r\n this.actions[this.stage].play();\r\n if (AnimationManager.LastAction !== undefined) {\r\n AnimationManager.PrepareCrossFade(AnimationManager.LastAction, this.actions[this.stage], this.blendingTime);\r\n }\r\n this.isPlaying = true;\r\n }\r\n\r\n if (AnimationManager.CurPlaying === TYVoiceChatState.Idle &&\r\n state !== TYVoiceChatState.Idle &&\r\n this.isPlaying === true &&\r\n this.stage === 0) {\r\n this.actions[this.stage].loop = LoopOnce;\r\n this.actions[this.stage].clampWhenFinished = true;\r\n this.isPlaying = false;\r\n AnimationManager.LastAction = this.actions[this.stage];\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Listen state - listening animation\r\n */\r\nclass Listen extends State {\r\n constructor(actions, isGroup) {\r\n super(actions, isGroup);\r\n }\r\n\r\n update(state) {\r\n // Safety check: return early if no actions available\r\n if (!this.actions || this.actions.length === 0) return;\r\n \r\n if (AnimationManager.CurPlaying === undefined &&\r\n state === TYVoiceChatState.Listening &&\r\n this.isPlaying === false) {\r\n this.stage = 0;\r\n this.actions[this.stage].time = 0;\r\n this.actions[this.stage].play();\r\n AnimationManager.SetWeight(this.actions[this.stage], 1.0);\r\n this.actions[this.stage].loop = this.isGroup ? LoopOnce : LoopRepeat;\r\n this.actions[this.stage].clampWhenFinished = this.isGroup ? true : false;\r\n if (AnimationManager.LastAction !== undefined) {\r\n AnimationManager.PrepareCrossFade(AnimationManager.LastAction, this.actions[this.stage], this.blendingTime);\r\n }\r\n this.isPlaying = true;\r\n }\r\n\r\n if (this.isGroup) {\r\n if (AnimationManager.CurPlaying === TYVoiceChatState.Listening &&\r\n state === TYVoiceChatState.Listening &&\r\n this.isPlaying === true &&\r\n this.stage === 0) {\r\n if (this.actions[this.stage].time >\r\n this.actions[this.stage].getClip().duration - this.blendingTime) {\r\n this.actions[this.stage + 1].time = 0;\r\n AnimationManager.SetWeight(this.actions[this.stage + 1], 1.0);\r\n this.actions[this.stage + 1].loop = LoopRepeat;\r\n this.actions[this.stage + 1].play();\r\n AnimationManager.PrepareCrossFade(this.actions[this.stage], this.actions[this.stage + 1], this.blendingTime);\r\n this.stage = 1;\r\n }\r\n }\r\n\r\n if (AnimationManager.CurPlaying === TYVoiceChatState.Listening &&\r\n state !== TYVoiceChatState.Listening &&\r\n this.isPlaying === true &&\r\n (this.stage === 0 || this.stage === 1)) {\r\n this.actions[2].time = 0;\r\n this.actions[2].play();\r\n AnimationManager.SetWeight(this.actions[2], 1.0);\r\n this.actions[2].loop = LoopOnce;\r\n AnimationManager.PrepareCrossFade(this.actions[this.stage], this.actions[2], this.blendingTime);\r\n this.stage = 2;\r\n }\r\n }\r\n\r\n if (AnimationManager.CurPlaying === TYVoiceChatState.Listening &&\r\n state !== TYVoiceChatState.Listening &&\r\n this.isPlaying === true &&\r\n this.stage === (this.isGroup ? this.actions.length - 1 : 0)) {\r\n this.actions[this.stage].loop = LoopOnce;\r\n this.actions[this.stage].clampWhenFinished = true;\r\n this.isPlaying = false;\r\n AnimationManager.LastAction = this.actions[this.stage];\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Think state - thinking animation\r\n */\r\nclass Think extends State {\r\n constructor(actions, isGroup) {\r\n super(actions, isGroup);\r\n }\r\n\r\n update(state) {\r\n // Safety check: return early if no actions available\r\n if (!this.actions || this.actions.length === 0) return;\r\n \r\n if (AnimationManager.CurPlaying === undefined &&\r\n state === TYVoiceChatState.Thinking &&\r\n this.isPlaying === false) {\r\n this.stage = 0;\r\n this.actions[this.stage].time = 0;\r\n this.actions[this.stage].play();\r\n AnimationManager.SetWeight(this.actions[this.stage], 1.0);\r\n this.actions[this.stage].loop = LoopOnce;\r\n if (AnimationManager.LastAction !== undefined) {\r\n AnimationManager.PrepareCrossFade(AnimationManager.LastAction, this.actions[this.stage], this.blendingTime);\r\n }\r\n this.isPlaying = true;\r\n }\r\n\r\n if (this.isGroup) {\r\n if (AnimationManager.CurPlaying === TYVoiceChatState.Thinking &&\r\n state === TYVoiceChatState.Thinking &&\r\n this.isPlaying === true &&\r\n this.stage === 0) {\r\n if (this.actions[this.stage].time >\r\n this.actions[this.stage].getClip().duration - this.blendingTime) {\r\n this.actions[this.stage + 1].time = 0;\r\n AnimationManager.SetWeight(this.actions[this.stage + 1], 1.0);\r\n this.actions[this.stage + 1].loop = LoopRepeat;\r\n this.actions[this.stage + 1].play();\r\n AnimationManager.PrepareCrossFade(this.actions[this.stage], this.actions[this.stage + 1], this.blendingTime);\r\n this.stage = 1;\r\n }\r\n }\r\n\r\n if (AnimationManager.CurPlaying === TYVoiceChatState.Thinking &&\r\n state !== TYVoiceChatState.Thinking &&\r\n this.isPlaying === true &&\r\n (this.stage === 0 || this.stage === 1)) {\r\n this.actions[2].time = 0;\r\n this.actions[2].play();\r\n AnimationManager.SetWeight(this.actions[2], 1.0);\r\n this.actions[2].loop = LoopOnce;\r\n AnimationManager.PrepareCrossFade(this.actions[this.stage], this.actions[2], this.blendingTime);\r\n this.stage = 2;\r\n }\r\n }\r\n\r\n if (AnimationManager.CurPlaying === TYVoiceChatState.Thinking &&\r\n state !== TYVoiceChatState.Thinking &&\r\n this.isPlaying === true &&\r\n this.stage === (this.isGroup ? this.actions.length - 1 : 0)) {\r\n this.actions[this.stage].loop = LoopOnce;\r\n this.actions[this.stage].clampWhenFinished = true;\r\n this.isPlaying = false;\r\n AnimationManager.LastAction = this.actions[this.stage];\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Speak state - speaking animation with random movement selection\r\n */\r\nclass Speak extends State {\r\n constructor(actions, isGroup) {\r\n super(actions, isGroup);\r\n logger.debug('[SPEAK] Initialized with', actions?.length || 0, 'actions, isGroup:', isGroup);\r\n }\r\n\r\n /**\r\n * Get a random number in range [min, max]\r\n */\r\n getRandomNumber(max, min) {\r\n const range = max - min;\r\n return min + Math.round(Math.random() * range);\r\n }\r\n\r\n update(state) {\r\n // Safety check: return early if no actions available\r\n if (!this.actions || this.actions.length === 0) {\r\n if (!this._warnedNoActions) {\r\n logger.warn('[SPEAK] No actions available!');\r\n this._warnedNoActions = true;\r\n }\r\n return;\r\n }\r\n \r\n // Start speaking - pick a random animation\r\n if (AnimationManager.CurPlaying === undefined &&\r\n state === TYVoiceChatState.Responding &&\r\n this.isPlaying === false) {\r\n // Randomly select initial animation\r\n this.stage = Math.ceil(this.getRandomNumber(0, this.actions.length - 1));\r\n logger.debug('[SPEAK] Starting animation, stage:', this.stage, 'of', this.actions.length);\r\n this.actions[this.stage].time = 0;\r\n this.actions[this.stage].play();\r\n AnimationManager.SetWeight(this.actions[this.stage], 1.0);\r\n this.actions[this.stage].loop = LoopOnce;\r\n this.actions[this.stage].clampWhenFinished = true;\r\n if (AnimationManager.LastAction !== undefined) {\r\n AnimationManager.PrepareCrossFade(AnimationManager.LastAction, this.actions[this.stage], this.blendingTime);\r\n }\r\n this.isPlaying = true;\r\n }\r\n\r\n // Continue speaking - cycle through random animations\r\n if (AnimationManager.CurPlaying === TYVoiceChatState.Responding &&\r\n state === TYVoiceChatState.Responding &&\r\n this.isPlaying === true) {\r\n if (this.actions[this.stage].time >=\r\n this.actions[this.stage].getClip().duration - this.blendingTime) {\r\n const lastAction = this.actions[this.stage];\r\n // Pick a different random animation\r\n this.stage = (this.stage + Math.ceil(this.getRandomNumber(1, this.actions.length - 1))) % this.actions.length;\r\n logger.debug('[SPEAK] Cycling to next animation, stage:', this.stage);\r\n this.actions[this.stage].time = 0;\r\n this.actions[this.stage].play();\r\n AnimationManager.SetWeight(this.actions[this.stage], 1.0);\r\n this.actions[this.stage].loop = LoopOnce;\r\n this.actions[this.stage].clampWhenFinished = true;\r\n AnimationManager.PrepareCrossFade(lastAction, this.actions[this.stage], this.blendingTime);\r\n }\r\n }\r\n\r\n // Stop speaking - finish current animation\r\n if (AnimationManager.CurPlaying === TYVoiceChatState.Responding &&\r\n state !== TYVoiceChatState.Responding &&\r\n this.isPlaying === true) {\r\n this.actions[this.stage].loop = LoopOnce;\r\n this.actions[this.stage].clampWhenFinished = true;\r\n this.isPlaying = false;\r\n AnimationManager.LastAction = this.actions[this.stage];\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * AnimationManager - Main animation controller\r\n * Manages state machine with crossfade transitions between animation states\r\n */\r\nexport class AnimationManager {\r\n // Static properties\r\n static IsBlending = false;\r\n static actions = [];\r\n static NeedReset = false;\r\n static NeedFullReset = false;\r\n static LastAction = undefined;\r\n static CurPlaying = undefined;\r\n\r\n /**\r\n * Set animation action weight\r\n */\r\n static SetWeight(action, weight) {\r\n action.enabled = true;\r\n action.setEffectiveTimeScale(1);\r\n action.setEffectiveWeight(weight);\r\n }\r\n\r\n /**\r\n * Prepare crossfade between two actions\r\n */\r\n static PrepareCrossFade(startAction, endAction, defaultDuration) {\r\n const duration = defaultDuration;\r\n AnimationManager.UnPauseAllActions();\r\n AnimationManager.ExecuteCrossFade(startAction, endAction, duration);\r\n AnimationManager.IsBlending = true;\r\n setTimeout(() => {\r\n AnimationManager.IsBlending = false;\r\n }, defaultDuration + 0.1);\r\n }\r\n\r\n /**\r\n * Pause all animation actions\r\n */\r\n static PauseAllActions() {\r\n AnimationManager.actions.forEach(function(action) {\r\n action.paused = true;\r\n });\r\n }\r\n\r\n /**\r\n * Unpause all animation actions\r\n */\r\n static UnPauseAllActions() {\r\n AnimationManager.actions.forEach(function(action) {\r\n action.paused = false;\r\n });\r\n }\r\n\r\n /**\r\n * Execute crossfade between two actions\r\n */\r\n static ExecuteCrossFade(startAction, endAction, duration) {\r\n AnimationManager.SetWeight(endAction, 1);\r\n endAction.time = 0;\r\n startAction.crossFadeTo(endAction, duration, true);\r\n }\r\n\r\n /**\r\n * Constructor\r\n * @param {THREE.AnimationMixer} mixer - Three.js animation mixer\r\n * @param {THREE.AnimationClip[]} animations - Animation clips\r\n * @param {object} animationcfg - Animation configuration\r\n */\r\n constructor(mixer, animations, animationcfg) {\r\n const helloActions = [];\r\n const idleActions = [];\r\n const listenActions = [];\r\n const speakActions = [];\r\n const thinkActions = [];\r\n\r\n this.mixer = mixer;\r\n\r\n // Calculate action indices based on config\r\n const helloIdx = animationcfg?.hello?.size || 0;\r\n const idleIdx = (animationcfg?.idle?.size || 0) + helloIdx;\r\n const listenIdx = (animationcfg?.listen?.size || 0) + idleIdx;\r\n const speakIdx = (animationcfg?.speak?.size || 0) + listenIdx;\r\n const thinkIdx = (animationcfg?.think?.size || 0) + speakIdx;\r\n\r\n // Distribute animation clips to state action arrays\r\n if (animations && animations.length > 0) {\r\n for (let i = 0; i < animations.length; i++) {\r\n const clip = animations[i];\r\n const action = mixer.clipAction(clip);\r\n\r\n if (i < helloIdx) {\r\n helloActions.push(action);\r\n } else if (i < idleIdx) {\r\n idleActions.push(action);\r\n // Duplicate for states that share idle\r\n if (listenIdx === idleIdx) {\r\n listenActions.push(mixer.clipAction(clip.clone()));\r\n }\r\n if (speakIdx === listenIdx) {\r\n speakActions.push(mixer.clipAction(clip.clone()));\r\n }\r\n if (thinkIdx === speakIdx) {\r\n thinkActions.push(mixer.clipAction(clip.clone()));\r\n }\r\n } else if (i < listenIdx) {\r\n listenActions.push(action);\r\n } else if (i < speakIdx) {\r\n speakActions.push(action);\r\n } else if (i < thinkIdx) {\r\n thinkActions.push(action);\r\n }\r\n\r\n AnimationManager.actions.push(action);\r\n AnimationManager.SetWeight(action, 0);\r\n }\r\n }\r\n\r\n // Create state instances\r\n this.hello = new Hello(helloActions, animationcfg?.hello?.isGroup || false);\r\n this.idle = new Idle(idleActions, animationcfg?.idle?.isGroup || false);\r\n this.listen = new Listen(listenActions, animationcfg?.listen?.isGroup || false);\r\n this.think = new Think(thinkActions, animationcfg?.think?.isGroup || false);\r\n this.speak = new Speak(speakActions, animationcfg?.speak?.isGroup || false);\r\n }\r\n\r\n /**\r\n * Get currently playing state\r\n */\r\n curPlaying() {\r\n if (this.hello.isPlaying) return TYVoiceChatState.Idle;\r\n if (this.idle.isPlaying) return TYVoiceChatState.Idle;\r\n if (this.listen.isPlaying) return TYVoiceChatState.Listening;\r\n if (this.think.isPlaying) return TYVoiceChatState.Thinking;\r\n if (this.speak.isPlaying) return TYVoiceChatState.Responding;\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Dispose animation manager\r\n */\r\n dispose() {\r\n this.hello.dispose();\r\n this.idle.dispose();\r\n this.listen.dispose();\r\n this.think.dispose();\r\n this.speak.dispose();\r\n AnimationManager.actions = [];\r\n }\r\n\r\n /**\r\n * Reset all animation actions\r\n */\r\n resetAllActions(ignoreBlending = false) {\r\n const curPlaying = this.curPlaying();\r\n \r\n switch (curPlaying) {\r\n case TYVoiceChatState.Idle:\r\n AnimationManager.LastAction = this.hello.actions[this.hello.stage];\r\n break;\r\n case TYVoiceChatState.Listening:\r\n AnimationManager.LastAction = this.listen.actions[this.listen.stage];\r\n break;\r\n case TYVoiceChatState.Thinking:\r\n AnimationManager.LastAction = this.think.actions[this.think.stage];\r\n break;\r\n case TYVoiceChatState.Responding:\r\n AnimationManager.LastAction = this.speak.actions[this.speak.stage];\r\n break;\r\n default:\r\n AnimationManager.LastAction = undefined;\r\n break;\r\n }\r\n\r\n if (AnimationManager.LastAction) {\r\n AnimationManager.LastAction.loop = LoopOnce;\r\n AnimationManager.LastAction.clampWhenFinished = true;\r\n AnimationManager.SetWeight(AnimationManager.LastAction, 1.0);\r\n }\r\n\r\n if (ignoreBlending) {\r\n AnimationManager.PauseAllActions();\r\n AnimationManager.actions.forEach(function(action) {\r\n action.time = 0;\r\n AnimationManager.SetWeight(action, 0.0);\r\n });\r\n AnimationManager.LastAction = undefined;\r\n }\r\n\r\n this.hello.isPlaying = false;\r\n this.idle.isPlaying = false;\r\n this.listen.isPlaying = false;\r\n this.think.isPlaying = false;\r\n this.speak.isPlaying = false;\r\n }\r\n\r\n /**\r\n * Update animation state\r\n * @param {string} state - Target state (TYVoiceChatState)\r\n */\r\n update(state) {\r\n if (AnimationManager.IsBlending) return;\r\n\r\n AnimationManager.CurPlaying = this.curPlaying();\r\n\r\n if (AnimationManager.CurPlaying === undefined) {\r\n switch (state) {\r\n case TYVoiceChatState.Idle:\r\n this.idle.update(state);\r\n break;\r\n case TYVoiceChatState.Listening:\r\n this.listen.update(state);\r\n break;\r\n case TYVoiceChatState.Thinking:\r\n this.think.update(state);\r\n break;\r\n case TYVoiceChatState.Responding:\r\n this.speak.update(state);\r\n break;\r\n default:\r\n this.idle.update(state);\r\n break;\r\n }\r\n } else {\r\n switch (AnimationManager.CurPlaying) {\r\n case TYVoiceChatState.Idle:\r\n this.idle.update(state);\r\n break;\r\n case TYVoiceChatState.Listening:\r\n this.listen.update(state);\r\n break;\r\n case TYVoiceChatState.Thinking:\r\n this.think.update(state);\r\n break;\r\n case TYVoiceChatState.Responding:\r\n this.speak.update(state);\r\n break;\r\n default:\r\n this.idle.update(state);\r\n break;\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport { State, Hello, Idle, Listen, Think, Speak };\r\nexport default AnimationManager;\r\n","/**\r\n * SplatScene\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * This file is functionally identical to the original.\r\n */\r\n\r\nimport { Matrix4, Object3D, Quaternion, Vector3 } from 'three';\r\n\r\nexport class SplatScene extends Object3D {\r\n\r\n constructor(splatBuffer, position = new Vector3(), quaternion = new Quaternion(),\r\n scale = new Vector3(1, 1, 1), minimumAlpha = 1, opacity = 1.0, visible = true) {\r\n super();\r\n this.splatBuffer = splatBuffer;\r\n this.position.copy(position);\r\n this.quaternion.copy(quaternion);\r\n this.scale.copy(scale);\r\n this.transform = new Matrix4();\r\n this.minimumAlpha = minimumAlpha;\r\n this.opacity = opacity;\r\n this.visible = visible;\r\n }\r\n\r\n copyTransformData(otherScene) {\r\n this.position.copy(otherScene.position);\r\n this.quaternion.copy(otherScene.quaternion);\r\n this.scale.copy(otherScene.scale);\r\n this.transform.copy(otherScene.transform);\r\n }\r\n\r\n updateTransform(dynamicMode) {\r\n if (dynamicMode) {\r\n if (this.matrixWorldAutoUpdate) this.updateWorldMatrix(true, false);\r\n this.transform.copy(this.matrixWorld);\r\n } else {\r\n if (this.matrixAutoUpdate) this.updateMatrix();\r\n this.transform.copy(this.matrix);\r\n }\r\n }\r\n}","/**\r\n * SplatGeometry\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * This file is functionally identical to the original.\r\n */\r\n\r\nimport { BufferAttribute, BufferGeometry, DynamicDrawUsage, InstancedBufferAttribute, InstancedBufferGeometry } from 'three';\r\n\r\nexport class SplatGeometry {\r\n\r\n /**\r\n * Build the Three.js geometry that will be used to render the splats. The geometry is instanced and is made up of\r\n * vertices for a single quad as well as an attribute buffer for the splat indexes.\r\n * @param {number} maxSplatCount The maximum number of splats that the geometry will need to accomodate\r\n * @return {THREE.InstancedBufferGeometry}\r\n */\r\n static build(maxSplatCount) {\r\n\r\n const baseGeometry = new BufferGeometry();\r\n baseGeometry.setIndex([0, 1, 2, 0, 2, 3]);\r\n\r\n // Vertices for the instanced quad\r\n const positionsArray = new Float32Array(4 * 3);\r\n const positions = new BufferAttribute(positionsArray, 3);\r\n baseGeometry.setAttribute('position', positions);\r\n positions.setXYZ(0, -1.0, -1.0, 0.0);\r\n positions.setXYZ(1, -1.0, 1.0, 0.0);\r\n positions.setXYZ(2, 1.0, 1.0, 0.0);\r\n positions.setXYZ(3, 1.0, -1.0, 0.0);\r\n positions.needsUpdate = true;\r\n\r\n const geometry = new InstancedBufferGeometry().copy(baseGeometry);\r\n\r\n // Splat index buffer\r\n const splatIndexArray = new Uint32Array(maxSplatCount);\r\n\r\n const splatIndexes = new InstancedBufferAttribute(splatIndexArray, 1, false);\r\n splatIndexes.setUsage(DynamicDrawUsage);\r\n geometry.setAttribute('splatIndex', splatIndexes);\r\n\r\n geometry.instanceCount = 0;\r\n\r\n return geometry;\r\n }\r\n}","/**\r\n * SplatTree\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * This file is functionally identical to the original.\r\n */\r\n\r\nimport { Vector3 } from 'three';\r\nimport { delayedExecute } from '../utils/Util.js';\r\n\r\n// Worker-related functions (simplified stubs - the actual worker is handled differently)\r\nconst checkAndCreateWorker = () => {\r\n // Worker creation is handled by the build system\r\n return null;\r\n};\r\n\r\nconst workerProcessCenters = (worker, centers, buffers, maxDepth, maxCentersPerNode) => {\r\n // Worker message passing\r\n if (worker) {\r\n worker.postMessage({\r\n 'process': {\r\n 'centers': centers,\r\n 'maxDepth': maxDepth,\r\n 'maxCentersPerNode': maxCentersPerNode\r\n }\r\n }, buffers);\r\n }\r\n};\r\n\r\n// SplatSubTree helper class\r\nclass SplatSubTree {\r\n constructor() {\r\n this.rootNode = null;\r\n this.splatMesh = null;\r\n }\r\n\r\n static convertWorkerSubTree(workerSubTree, splatMesh) {\r\n const subTree = new SplatSubTree();\r\n subTree.rootNode = workerSubTree.rootNode;\r\n subTree.splatMesh = splatMesh;\r\n return subTree;\r\n }\r\n}\r\n\r\nexport class SplatTree {\r\n\r\n constructor(maxDepth, maxCentersPerNode) {\r\n this.maxDepth = maxDepth;\r\n this.maxCentersPerNode = maxCentersPerNode;\r\n this.subTrees = [];\r\n this.splatMesh = null;\r\n }\r\n\r\n\r\n dispose() {\r\n this.diposeSplatTreeWorker();\r\n this.disposed = true;\r\n }\r\n\r\n diposeSplatTreeWorker() {\r\n if (this.splatTreeWorker) this.splatTreeWorker.terminate();\r\n this.splatTreeWorker = null;\r\n };\r\n\r\n /**\r\n * Construct this instance of SplatTree from an instance of SplatMesh.\r\n *\r\n * @param {SplatMesh} splatMesh The instance of SplatMesh from which to construct this splat tree.\r\n * @param {function} filterFunc Optional function to filter out unwanted splats.\r\n * @param {function} onIndexesUpload Function to be called when the upload of splat centers to the splat tree\r\n * builder worker starts and finishes.\r\n * @param {function} onSplatTreeConstruction Function to be called when the conversion of the local splat tree from\r\n * the format produced by the splat tree builder worker starts and ends.\r\n * @return {undefined}\r\n */\r\n processSplatMesh = (splatMesh, filterFunc = () => true, onIndexesUpload, onSplatTreeConstruction) => {\r\n if (!this.splatTreeWorker) this.splatTreeWorker = checkAndCreateWorker();\r\n\r\n this.splatMesh = splatMesh;\r\n this.subTrees = [];\r\n const center = new Vector3();\r\n\r\n const addCentersForScene = (splatOffset, splatCount) => {\r\n const sceneCenters = new Float32Array(splatCount * 4);\r\n let addedCount = 0;\r\n for (let i = 0; i < splatCount; i++) {\r\n const globalSplatIndex = i + splatOffset;\r\n if (filterFunc(globalSplatIndex)) {\r\n splatMesh.getSplatCenter(globalSplatIndex, center);\r\n const addBase = addedCount * 4;\r\n sceneCenters[addBase] = center.x;\r\n sceneCenters[addBase + 1] = center.y;\r\n sceneCenters[addBase + 2] = center.z;\r\n sceneCenters[addBase + 3] = globalSplatIndex;\r\n addedCount++;\r\n }\r\n }\r\n return sceneCenters;\r\n };\r\n\r\n return new Promise((resolve) => {\r\n\r\n const checkForEarlyExit = () => {\r\n if (this.disposed) {\r\n this.diposeSplatTreeWorker();\r\n resolve();\r\n return true;\r\n }\r\n return false;\r\n };\r\n\r\n if (onIndexesUpload) onIndexesUpload(false);\r\n\r\n delayedExecute(() => {\r\n\r\n if (checkForEarlyExit()) return;\r\n\r\n const allCenters = [];\r\n if (splatMesh.dynamicMode) {\r\n let splatOffset = 0;\r\n for (let s = 0; s < splatMesh.scenes.length; s++) {\r\n const scene = splatMesh.getScene(s);\r\n const splatCount = scene.splatBuffer.getSplatCount();\r\n const sceneCenters = addCentersForScene(splatOffset, splatCount);\r\n allCenters.push(sceneCenters);\r\n splatOffset += splatCount;\r\n }\r\n } else {\r\n const sceneCenters = addCentersForScene(0, splatMesh.getSplatCount());\r\n allCenters.push(sceneCenters);\r\n }\r\n\r\n this.splatTreeWorker.onmessage = (e) => {\r\n\r\n if (checkForEarlyExit()) return;\r\n\r\n if (e.data.subTrees) {\r\n\r\n if (onSplatTreeConstruction) onSplatTreeConstruction(false);\r\n\r\n delayedExecute(() => {\r\n\r\n if (checkForEarlyExit()) return;\r\n\r\n for (let workerSubTree of e.data.subTrees) {\r\n const convertedSubTree = SplatSubTree.convertWorkerSubTree(workerSubTree, splatMesh);\r\n this.subTrees.push(convertedSubTree);\r\n }\r\n this.diposeSplatTreeWorker();\r\n\r\n if (onSplatTreeConstruction) onSplatTreeConstruction(true);\r\n\r\n delayedExecute(() => {\r\n resolve();\r\n });\r\n\r\n });\r\n }\r\n };\r\n\r\n delayedExecute(() => {\r\n if (checkForEarlyExit()) return;\r\n if (onIndexesUpload) onIndexesUpload(true);\r\n const transferBuffers = allCenters.map((array) => array.buffer);\r\n workerProcessCenters(this.splatTreeWorker, allCenters, transferBuffers, this.maxDepth, this.maxCentersPerNode);\r\n });\r\n\r\n });\r\n\r\n });\r\n\r\n };\r\n\r\n countLeaves() {\r\n\r\n let leafCount = 0;\r\n this.visitLeaves(() => {\r\n leafCount++;\r\n });\r\n\r\n return leafCount;\r\n }\r\n\r\n visitLeaves(visitFunc) {\r\n\r\n const visitLeavesFromNode = (node, visitFunc) => {\r\n if (node.children.length === 0) visitFunc(node);\r\n for (let child of node.children) {\r\n visitLeavesFromNode(child, visitFunc);\r\n }\r\n };\r\n\r\n for (let subTree of this.subTrees) {\r\n visitLeavesFromNode(subTree.rootNode, visitFunc);\r\n }\r\n }\r\n\r\n}","/**\r\n * SplatMaterial\r\n * \r\n * Based on @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * HEAVILY MODIFIED for FLAME avatar support:\r\n * - Added FLAME bone/pose uniforms and textures\r\n * - Added expression blendshape support\r\n * - Extended vertex shader with GPU skinning\r\n * - Additional ~500 lines of FLAME-specific shader code\r\n */\r\n\r\nimport { Color, DoubleSide, Matrix4, NormalBlending, ShaderMaterial, Vector2, Vector3 } from 'three';\r\nimport { Constants } from '../enums/EngineConstants.js';\r\n\r\nexport class SplatMaterial {\r\n\r\n static buildVertexShaderBase(dynamicMode = false, enableOptionalEffects = false, maxSphericalHarmonicsDegree = 0, customVars = '') {\r\n let vertexShaderSource = `#define USE_SKINNING\r\n\r\n precision highp float;\r\n #include <common>\r\n\r\n attribute uint splatIndex;\r\n uniform highp usampler2D flameModelTexture;\r\n uniform highp usampler2D boneTexture;\r\n uniform highp usampler2D boneWeightTexture;\r\n\r\n\r\n uniform highp usampler2D centersColorsTexture;\r\n uniform highp sampler2D sphericalHarmonicsTexture;\r\n uniform highp sampler2D sphericalHarmonicsTextureR;\r\n uniform highp sampler2D sphericalHarmonicsTextureG;\r\n uniform highp sampler2D sphericalHarmonicsTextureB;\r\n\r\n uniform highp usampler2D sceneIndexesTexture;\r\n uniform vec2 sceneIndexesTextureSize;\r\n uniform int sceneCount;\r\n uniform int gaussianSplatCount;\r\n uniform int bsCount;\r\n uniform float headBoneIndex;\r\n #ifdef USE_SKINNING\r\n attribute vec4 skinIndex;\r\n attribute vec4 skinWeight;\r\n #endif\r\n `;\r\n\r\n if (enableOptionalEffects) {\r\n vertexShaderSource += `\r\n uniform float sceneOpacity[${Constants.MaxScenes}];\r\n uniform int sceneVisibility[${Constants.MaxScenes}];\r\n `;\r\n }\r\n\r\n if (dynamicMode) {\r\n vertexShaderSource += `\r\n uniform highp mat4 transforms[${Constants.MaxScenes}];\r\n `;\r\n }\r\n\r\n vertexShaderSource += `\r\n ${customVars}\r\n uniform vec2 focal;\r\n uniform float orthoZoom;\r\n uniform int orthographicMode;\r\n uniform int pointCloudModeEnabled;\r\n uniform float inverseFocalAdjustment;\r\n uniform vec2 viewport;\r\n uniform vec2 basisViewport;\r\n uniform vec2 centersColorsTextureSize;\r\n uniform vec2 flameModelTextureSize;\r\n uniform vec2 boneWeightTextureSize;\r\n uniform vec2 boneTextureSize;\r\n\r\n uniform int sphericalHarmonicsDegree;\r\n uniform vec2 sphericalHarmonicsTextureSize;\r\n uniform int sphericalHarmonics8BitMode;\r\n uniform int sphericalHarmonicsMultiTextureMode;\r\n uniform float visibleRegionRadius;\r\n uniform float visibleRegionFadeStartRadius;\r\n uniform float firstRenderTime;\r\n uniform float currentTime;\r\n uniform int fadeInComplete;\r\n uniform vec3 sceneCenter;\r\n uniform float splatScale;\r\n uniform float sphericalHarmonics8BitCompressionRangeMin[${Constants.MaxScenes}];\r\n uniform float sphericalHarmonics8BitCompressionRangeMax[${Constants.MaxScenes}];\r\n\r\n varying vec4 vColor;\r\n varying vec2 vUv;\r\n varying vec2 vPosition;\r\n varying vec2 vSplatIndex;\r\n #ifdef USE_SKINNING\r\n uniform mat4 bindMatrix;\r\n uniform mat4 bindMatrixInverse;\r\n uniform highp sampler2D boneTexture0;\r\n mat4 getBoneMatrix0( const in float i ) {\r\n int size = textureSize( boneTexture0, 0 ).x;\r\n int j = int( i ) * 4;\r\n int x = j % size;\r\n int y = j / size;\r\n vec4 v1 = texelFetch( boneTexture0, ivec2( x, y ), 0 );\r\n vec4 v2 = texelFetch( boneTexture0, ivec2( x + 1, y ), 0 );\r\n vec4 v3 = texelFetch( boneTexture0, ivec2( x + 2, y ), 0 );\r\n vec4 v4 = texelFetch( boneTexture0, ivec2( x + 3, y ), 0 );\r\n return mat4( v1, v2, v3, v4 );\r\n }\r\n #endif\r\n\r\n mat3 quaternionToRotationMatrix(float x, float y, float z, float w) {\r\n float s = 1.0 / sqrt(w * w + x * x + y * y + z * z);\r\n \r\n return mat3(\r\n 1. - 2. * (y * y + z * z),\r\n 2. * (x * y + w * z),\r\n 2. * (x * z - w * y),\r\n 2. * (x * y - w * z),\r\n 1. - 2. * (x * x + z * z),\r\n 2. * (y * z + w * x),\r\n 2. * (x * z + w * y),\r\n 2. * (y * z - w * x),\r\n 1. - 2. * (x * x + y * y)\r\n );\r\n }\r\n\r\n const float sqrt8 = sqrt(8.0);\r\n const float minAlpha = 1.0 / 255.0;\r\n\r\n const vec4 encodeNorm4 = vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);\r\n const uvec4 mask4 = uvec4(uint(0x000000FF), uint(0x0000FF00), uint(0x00FF0000), uint(0xFF000000));\r\n const uvec4 shift4 = uvec4(0, 8, 16, 24);\r\n int internal = 1;//show a gaussian splatting point every internal points.\r\n vec4 uintToRGBAVec (uint u) {\r\n uvec4 urgba = mask4 & u;\r\n urgba = urgba >> shift4;\r\n vec4 rgba = vec4(urgba) * encodeNorm4;\r\n return rgba;\r\n }\r\n float getRealIndex(int sIndex, int reducedFactor) {\r\n int remainder = sIndex % reducedFactor;\r\n\r\n if(remainder == int(0)) {\r\n return float(sIndex);\r\n }\r\n else\r\n {\r\n return float(sIndex - remainder);\r\n }\r\n }\r\n\r\n vec2 getDataUV(in int stride, in int offset, in vec2 dimensions) {\r\n vec2 samplerUV = vec2(0.0, 0.0);\r\n float d = float(uint(getRealIndex(int(splatIndex), internal)) * uint(stride) + uint(offset)) / dimensions.x;\r\n samplerUV.y = float(floor(d)) / dimensions.y;\r\n samplerUV.x = fract(d);\r\n return samplerUV;\r\n }\r\n\r\n vec2 getFlameDataUV(in int stride, in int offset, in vec2 dimensions) {\r\n vec2 samplerUV = vec2(0.0, 0.0);\r\n float d = float(uint(int(splatIndex) / internal) * uint(stride) + uint(offset) + uint(gaussianSplatCount * bsCount)) / dimensions.x;\r\n samplerUV.y = float(floor(d)) / dimensions.y;\r\n samplerUV.x = fract(d);\r\n return samplerUV;\r\n }\r\n\r\n vec2 getBoneWeightUV(in int stride, in int offset, in vec2 dimensions) {\r\n vec2 samplerUV = vec2(0.0, 0.0);\r\n float d = float(uint(int(splatIndex) / internal) * uint(stride) + uint(offset)) / dimensions.x;\r\n samplerUV.y = float(floor(d)) / dimensions.y;\r\n samplerUV.x = fract(d);\r\n return samplerUV;\r\n }\r\n\r\n vec2 getBSFlameDataUV(in int bsInedex, in int stride, in int offset, in vec2 dimensions) {\r\n vec2 samplerUV = vec2(0.0, 0.0);\r\n float d = float(uint(int(splatIndex) / internal) * uint(stride) + uint(offset) + uint(gaussianSplatCount * bsInedex)) / dimensions.x;\r\n samplerUV.y = float(floor(d)) / dimensions.y;\r\n samplerUV.x = fract(d);\r\n return samplerUV;\r\n }\r\n\r\n vec2 getDataUVF(in uint sIndex, in float stride, in uint offset, in vec2 dimensions) {\r\n vec2 samplerUV = vec2(0.0, 0.0);\r\n float d = float(uint(float(getRealIndex(int(sIndex), internal)) * stride) + offset) / dimensions.x;\r\n samplerUV.y = float(floor(d)) / dimensions.y;\r\n samplerUV.x = fract(d);\r\n return samplerUV;\r\n }\r\n\r\n const float SH_C1 = 0.4886025119029199f;\r\n const float[5] SH_C2 = float[](1.0925484, -1.0925484, 0.3153916, -1.0925484, 0.5462742);\r\n\r\n mat4 getBoneMatrix( float i ) {\r\n float y = i;\r\n float x = 0.0;\r\n\r\n vec2 samplerUV = vec2(0.0, 0.0);\r\n float d = float(i * 4.0) / boneTextureSize.x;//4\r\n samplerUV.y = float(floor(d)) / boneTextureSize.y;//5\r\n samplerUV.x = fract(d);\r\n\r\n vec4 v1 = uintBitsToFloat(texture( boneTexture, samplerUV ));\r\n vec4 v2 = uintBitsToFloat(texture( boneTexture, vec2(samplerUV.x + 1.0 / boneTextureSize.x, samplerUV.y)));\r\n vec4 v3 = uintBitsToFloat(texture( boneTexture, vec2(samplerUV.x + 2.0 / boneTextureSize.x, samplerUV.y) ));\r\n vec4 v4 = uintBitsToFloat(texture( boneTexture, vec2(samplerUV.x + 3.0 / boneTextureSize.x, samplerUV.y)));\r\n\r\n return mat4( v1, v2, v3, v4 );\r\n }\r\n\r\n void main () {\r\n\r\n uint oddOffset = splatIndex & uint(0x00000001);\r\n uint doubleOddOffset = oddOffset * uint(2);\r\n bool isEven = oddOffset == uint(0);\r\n uint nearestEvenIndex = splatIndex - oddOffset;\r\n float fOddOffset = float(oddOffset);\r\n\r\n uvec4 sampledCenterColor = texture(centersColorsTexture, getDataUV(1, 0, centersColorsTextureSize));\r\n // vec3 splatCenter = uintBitsToFloat(uvec3(sampledCenterColor.gba));\r\n\r\n uvec3 sampledCenter = texture(centersColorsTexture, getDataUV(1, 0, centersColorsTextureSize)).gba;\r\n vec3 splatCenter = uintBitsToFloat(uvec3(sampledCenter));\r\n\r\n vec2 flameTextureUV = getBSFlameDataUV(bsCount, 1, 0, flameModelTextureSize);\r\n uvec3 sampledflamePos = texture(flameModelTexture, flameTextureUV).rgb;\r\n // splatCenter += uintBitsToFloat(uvec3(sampledflamePos.rgb));\r\n\r\n for(int i = 0; i < bsCount; ++i) {\r\n vec2 flameBSTextureUV = getBSFlameDataUV(i, 1, 0, flameModelTextureSize);\r\n uvec3 sampledBSPos = texture(flameModelTexture, flameBSTextureUV).rgb;\r\n\r\n vec2 samplerUV = vec2(0.0, 0.0);\r\n float d = float(i / 4 + 5 * 4) / boneTextureSize.x;//4\r\n samplerUV.y = float(floor(d)) / boneTextureSize.y;//32\r\n samplerUV.x = fract(d);\r\n\r\n vec4 bsWeight = uintBitsToFloat(texture(boneTexture, samplerUV));\r\n float weight = bsWeight.r;\r\n if(i % 4 == 1) {\r\n weight = bsWeight.g;\r\n }\r\n if(i % 4 == 2) {\r\n weight = bsWeight.b;\r\n }\r\n if(i % 4 == 3) {\r\n weight = bsWeight.a;\r\n }\r\n\r\n splatCenter = splatCenter + weight * uintBitsToFloat(sampledBSPos);\r\n }\r\n\r\n\r\n #ifdef USE_SKINNING\r\n mat4 boneMatX = getBoneMatrix0( skinIndex.x );\r\n mat4 boneMatY = getBoneMatrix0( skinIndex.y );\r\n mat4 boneMatZ = getBoneMatrix0( skinIndex.z );\r\n mat4 boneMatW = getBoneMatrix0( skinIndex.w );\r\n #endif\r\n #ifdef USE_SKINNING\r\n mat4 skinMatrix = mat4( 0.0 );\r\n skinMatrix += skinWeight.x * boneMatX;\r\n skinMatrix += skinWeight.y * boneMatY;\r\n skinMatrix += skinWeight.z * boneMatZ;\r\n skinMatrix += skinWeight.w * boneMatW;\r\n // skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\r\n #endif\r\n vec3 transformed = vec3(splatCenter.xyz);\r\n #ifdef USE_SKINNING\r\n // vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\r\n vec4 skinVertex = vec4( transformed, 1.0 );\r\n\r\n vec4 skinned = vec4( 0.0 );\r\n // There is an offset between the Gaussian point and the mesh vertex,\r\n // which will cause defects in the skeletal animation driving the Gaussian point. \r\n //In order to circumvent this problem, only the head bone(index is 110 currently) is used to drive\r\n\r\n if (headBoneIndex >= 0.0)\r\n {\r\n mat4 boneMat = getBoneMatrix0( headBoneIndex );\r\n skinned += boneMat * skinVertex * 1.0;\r\n }\r\n\r\n // skinned += boneMatX * skinVertex * skinWeight.x;\r\n // skinned += boneMatY * skinVertex * skinWeight.y;\r\n // skinned += boneMatZ * skinVertex * skinWeight.z;\r\n // skinned += boneMatW * skinVertex * skinWeight.w;\r\n\r\n // transformed = ( bindMatrixInverse * skinned ).xyz;\r\n transformed = skinned.xyz;\r\n\r\n #endif\r\n splatCenter = transformed.xyz;\r\n\r\n #ifdef USE_FLAME\r\n mat4 boneMatX = getBoneMatrix( 0.0 );\r\n mat4 boneMatY = getBoneMatrix( 1.0 );\r\n mat4 boneMatZ = getBoneMatrix( 2.0 );\r\n mat4 boneMatW = getBoneMatrix( 3.0 ); \r\n mat4 boneMat0 = getBoneMatrix( 4.0 ); \r\n \r\n vec2 boneWeightUV0 = getBoneWeightUV(2, 0, boneWeightTextureSize);\r\n vec2 boneWeightUV1 = getBoneWeightUV(2, 1, boneWeightTextureSize);\r\n\r\n uvec4 sampledBoneMatrixValue = texture(boneWeightTexture, boneWeightUV0);\r\n uvec4 sampledBoneMatrixValue0 = texture(boneWeightTexture, boneWeightUV1);\r\n\r\n vec4 boneMatrixValue = uintBitsToFloat(sampledBoneMatrixValue);\r\n vec4 boneMatrixValue0 = uintBitsToFloat(sampledBoneMatrixValue0);\r\n\r\n vec4 skinVertex = vec4( splatCenter, 1.0 );\r\n vec4 skinned = vec4( 0.0 );\r\n float minWeight = min(boneMatrixValue.x,min(boneMatrixValue.y, min(boneMatrixValue.z, min(boneMatrixValue.w, boneMatrixValue0.x))));\r\n \r\n if(boneMatrixValue.x > 0.0 && boneMatrixValue.x > minWeight)\r\n skinned += boneMatX * skinVertex * boneMatrixValue.x;\r\n \r\n if(boneMatrixValue.y > 0.0 && boneMatrixValue.y > minWeight)\r\n skinned += boneMatY * skinVertex * boneMatrixValue.y;\r\n \r\n if(boneMatrixValue.z > 0.0 && boneMatrixValue.z > minWeight)\r\n skinned += boneMatZ * skinVertex * boneMatrixValue.z;\r\n \r\n if(boneMatrixValue.w > 0.0 && boneMatrixValue.w > minWeight)\r\n skinned += boneMatW * skinVertex * boneMatrixValue.w;\r\n \r\n if(boneMatrixValue0.x > 0.0 && boneMatrixValue0.x > minWeight)\r\n skinned += boneMat0 * skinVertex * boneMatrixValue0.x;\r\n \r\n splatCenter = skinned.xyz;\r\n #endif\r\n\r\n uint sceneIndex = uint(0);\r\n if (sceneCount > 1) {\r\n sceneIndex = texture(sceneIndexesTexture, getDataUV(1, 0, sceneIndexesTextureSize)).r;\r\n }\r\n `;\r\n\r\n if (enableOptionalEffects) {\r\n vertexShaderSource += `\r\n float splatOpacityFromScene = sceneOpacity[sceneIndex];\r\n int sceneVisible = sceneVisibility[sceneIndex];\r\n if (splatOpacityFromScene <= 0.01 || sceneVisible == 0) {\r\n gl_Position = vec4(0.0, 0.0, 2.0, 1.0);\r\n return;\r\n }\r\n `;\r\n }\r\n\r\n if (dynamicMode) {\r\n vertexShaderSource += `\r\n mat4 transform = transforms[sceneIndex];\r\n mat4 transformModelViewMatrix = viewMatrix * transform;\r\n #ifdef USE_SKINNING\r\n transformModelViewMatrix = transformModelViewMatrix * skinMatrix;\r\n #endif\r\n `;\r\n } else {\r\n vertexShaderSource += `mat4 transformModelViewMatrix = modelViewMatrix;`;\r\n }\r\n\r\n vertexShaderSource += `\r\n float sh8BitCompressionRangeMinForScene = sphericalHarmonics8BitCompressionRangeMin[sceneIndex];\r\n float sh8BitCompressionRangeMaxForScene = sphericalHarmonics8BitCompressionRangeMax[sceneIndex];\r\n float sh8BitCompressionRangeForScene = sh8BitCompressionRangeMaxForScene - sh8BitCompressionRangeMinForScene;\r\n float sh8BitCompressionHalfRangeForScene = sh8BitCompressionRangeForScene / 2.0;\r\n vec3 vec8BitSHShift = vec3(sh8BitCompressionRangeMinForScene);\r\n\r\n vec4 viewCenter = transformModelViewMatrix * vec4(splatCenter, 1.0);\r\n\r\n vec4 clipCenter = projectionMatrix * viewCenter;\r\n\r\n float clip = 1.2 * clipCenter.w;\r\n if (clipCenter.z < -clip || clipCenter.x < -clip || clipCenter.x > clip || clipCenter.y < -clip || clipCenter.y > clip) {\r\n gl_Position = vec4(0.0, 0.0, 2.0, 1.0);\r\n return;\r\n }\r\n\r\n vec3 ndcCenter = clipCenter.xyz / clipCenter.w;\r\n\r\n vPosition = position.xy;\r\n vSplatIndex = vec2(splatIndex, splatIndex);\r\n\r\n vColor = uintToRGBAVec(sampledCenterColor.r);\r\n `;\r\n\r\n // Proceed to sampling and rendering 1st degree spherical harmonics\r\n if (maxSphericalHarmonicsDegree >= 1) {\r\n\r\n vertexShaderSource += ` \r\n if (sphericalHarmonicsDegree >= 1) {\r\n `;\r\n\r\n if (dynamicMode) {\r\n vertexShaderSource += `\r\n vec3 worldViewDir = normalize(splatCenter - vec3(inverse(transform) * vec4(cameraPosition, 1.0)));\r\n `;\r\n } else {\r\n vertexShaderSource += `\r\n vec3 worldViewDir = normalize(splatCenter - cameraPosition);\r\n `;\r\n }\r\n\r\n vertexShaderSource += `\r\n vec3 sh1;\r\n vec3 sh2;\r\n vec3 sh3;\r\n `;\r\n\r\n if (maxSphericalHarmonicsDegree >= 2) {\r\n vertexShaderSource += `\r\n vec3 sh4;\r\n vec3 sh5;\r\n vec3 sh6;\r\n vec3 sh7;\r\n vec3 sh8;\r\n `;\r\n }\r\n\r\n // Determining how to sample spherical harmonics textures to get the coefficients for calculations for a given degree\r\n // depends on how many total degrees (maxSphericalHarmonicsDegree) are present in the textures. This is because that\r\n // number affects how they are packed in the textures, and therefore the offset & stride required to access them.\r\n\r\n // Sample spherical harmonics textures with 1 degree worth of data for 1st degree calculations, and store in sh1, sh2, and sh3\r\n if (maxSphericalHarmonicsDegree === 1) {\r\n vertexShaderSource += `\r\n if (sphericalHarmonicsMultiTextureMode == 0) {\r\n vec2 shUV = getDataUVF(nearestEvenIndex, 2.5, doubleOddOffset, sphericalHarmonicsTextureSize);\r\n vec4 sampledSH0123 = texture(sphericalHarmonicsTexture, shUV);\r\n shUV = getDataUVF(nearestEvenIndex, 2.5, doubleOddOffset + uint(1), sphericalHarmonicsTextureSize);\r\n vec4 sampledSH4567 = texture(sphericalHarmonicsTexture, shUV);\r\n shUV = getDataUVF(nearestEvenIndex, 2.5, doubleOddOffset + uint(2), sphericalHarmonicsTextureSize);\r\n vec4 sampledSH891011 = texture(sphericalHarmonicsTexture, shUV);\r\n sh1 = vec3(sampledSH0123.rgb) * (1.0 - fOddOffset) + vec3(sampledSH0123.ba, sampledSH4567.r) * fOddOffset;\r\n sh2 = vec3(sampledSH0123.a, sampledSH4567.rg) * (1.0 - fOddOffset) + vec3(sampledSH4567.gba) * fOddOffset;\r\n sh3 = vec3(sampledSH4567.ba, sampledSH891011.r) * (1.0 - fOddOffset) + vec3(sampledSH891011.rgb) * fOddOffset;\r\n } else {\r\n vec2 sampledSH01R = texture(sphericalHarmonicsTextureR, getDataUV(2, 0, sphericalHarmonicsTextureSize)).rg;\r\n vec2 sampledSH23R = texture(sphericalHarmonicsTextureR, getDataUV(2, 1, sphericalHarmonicsTextureSize)).rg;\r\n vec2 sampledSH01G = texture(sphericalHarmonicsTextureG, getDataUV(2, 0, sphericalHarmonicsTextureSize)).rg;\r\n vec2 sampledSH23G = texture(sphericalHarmonicsTextureG, getDataUV(2, 1, sphericalHarmonicsTextureSize)).rg;\r\n vec2 sampledSH01B = texture(sphericalHarmonicsTextureB, getDataUV(2, 0, sphericalHarmonicsTextureSize)).rg;\r\n vec2 sampledSH23B = texture(sphericalHarmonicsTextureB, getDataUV(2, 1, sphericalHarmonicsTextureSize)).rg;\r\n sh1 = vec3(sampledSH01R.rg, sampledSH23R.r);\r\n sh2 = vec3(sampledSH01G.rg, sampledSH23G.r);\r\n sh3 = vec3(sampledSH01B.rg, sampledSH23B.r);\r\n }\r\n `;\r\n // Sample spherical harmonics textures with 2 degrees worth of data for 1st degree calculations, and store in sh1, sh2, and sh3\r\n } else if (maxSphericalHarmonicsDegree === 2) {\r\n vertexShaderSource += `\r\n vec4 sampledSH0123;\r\n vec4 sampledSH4567;\r\n vec4 sampledSH891011;\r\n\r\n vec4 sampledSH0123R;\r\n vec4 sampledSH0123G;\r\n vec4 sampledSH0123B;\r\n\r\n if (sphericalHarmonicsMultiTextureMode == 0) {\r\n sampledSH0123 = texture(sphericalHarmonicsTexture, getDataUV(6, 0, sphericalHarmonicsTextureSize));\r\n sampledSH4567 = texture(sphericalHarmonicsTexture, getDataUV(6, 1, sphericalHarmonicsTextureSize));\r\n sampledSH891011 = texture(sphericalHarmonicsTexture, getDataUV(6, 2, sphericalHarmonicsTextureSize));\r\n sh1 = sampledSH0123.rgb;\r\n sh2 = vec3(sampledSH0123.a, sampledSH4567.rg);\r\n sh3 = vec3(sampledSH4567.ba, sampledSH891011.r);\r\n } else {\r\n sampledSH0123R = texture(sphericalHarmonicsTextureR, getDataUV(2, 0, sphericalHarmonicsTextureSize));\r\n sampledSH0123G = texture(sphericalHarmonicsTextureG, getDataUV(2, 0, sphericalHarmonicsTextureSize));\r\n sampledSH0123B = texture(sphericalHarmonicsTextureB, getDataUV(2, 0, sphericalHarmonicsTextureSize));\r\n sh1 = vec3(sampledSH0123R.rgb);\r\n sh2 = vec3(sampledSH0123G.rgb);\r\n sh3 = vec3(sampledSH0123B.rgb);\r\n }\r\n `;\r\n }\r\n\r\n // Perform 1st degree spherical harmonics calculations\r\n vertexShaderSource += `\r\n if (sphericalHarmonics8BitMode == 1) {\r\n sh1 = sh1 * sh8BitCompressionRangeForScene + vec8BitSHShift;\r\n sh2 = sh2 * sh8BitCompressionRangeForScene + vec8BitSHShift;\r\n sh3 = sh3 * sh8BitCompressionRangeForScene + vec8BitSHShift;\r\n }\r\n float x = worldViewDir.x;\r\n float y = worldViewDir.y;\r\n float z = worldViewDir.z;\r\n vColor.rgb += SH_C1 * (-sh1 * y + sh2 * z - sh3 * x);\r\n `;\r\n\r\n // Proceed to sampling and rendering 2nd degree spherical harmonics\r\n if (maxSphericalHarmonicsDegree >= 2) {\r\n\r\n vertexShaderSource += `\r\n if (sphericalHarmonicsDegree >= 2) {\r\n float xx = x * x;\r\n float yy = y * y;\r\n float zz = z * z;\r\n float xy = x * y;\r\n float yz = y * z;\r\n float xz = x * z;\r\n `;\r\n\r\n // Sample spherical harmonics textures with 2 degrees worth of data for 2nd degree calculations,\r\n // and store in sh4, sh5, sh6, sh7, and sh8\r\n if (maxSphericalHarmonicsDegree === 2) {\r\n vertexShaderSource += `\r\n if (sphericalHarmonicsMultiTextureMode == 0) {\r\n vec4 sampledSH12131415 = texture(sphericalHarmonicsTexture, getDataUV(6, 3, sphericalHarmonicsTextureSize));\r\n vec4 sampledSH16171819 = texture(sphericalHarmonicsTexture, getDataUV(6, 4, sphericalHarmonicsTextureSize));\r\n vec4 sampledSH20212223 = texture(sphericalHarmonicsTexture, getDataUV(6, 5, sphericalHarmonicsTextureSize));\r\n sh4 = sampledSH891011.gba;\r\n sh5 = sampledSH12131415.rgb;\r\n sh6 = vec3(sampledSH12131415.a, sampledSH16171819.rg);\r\n sh7 = vec3(sampledSH16171819.ba, sampledSH20212223.r);\r\n sh8 = sampledSH20212223.gba;\r\n } else {\r\n vec4 sampledSH4567R = texture(sphericalHarmonicsTextureR, getDataUV(2, 1, sphericalHarmonicsTextureSize));\r\n vec4 sampledSH4567G = texture(sphericalHarmonicsTextureG, getDataUV(2, 1, sphericalHarmonicsTextureSize));\r\n vec4 sampledSH4567B = texture(sphericalHarmonicsTextureB, getDataUV(2, 1, sphericalHarmonicsTextureSize));\r\n sh4 = vec3(sampledSH0123R.a, sampledSH4567R.rg);\r\n sh5 = vec3(sampledSH4567R.ba, sampledSH0123G.a);\r\n sh6 = vec3(sampledSH4567G.rgb);\r\n sh7 = vec3(sampledSH4567G.a, sampledSH0123B.a, sampledSH4567B.r);\r\n sh8 = vec3(sampledSH4567B.gba);\r\n }\r\n `;\r\n }\r\n\r\n // Perform 2nd degree spherical harmonics calculations\r\n vertexShaderSource += `\r\n if (sphericalHarmonics8BitMode == 1) {\r\n sh4 = sh4 * sh8BitCompressionRangeForScene + vec8BitSHShift;\r\n sh5 = sh5 * sh8BitCompressionRangeForScene + vec8BitSHShift;\r\n sh6 = sh6 * sh8BitCompressionRangeForScene + vec8BitSHShift;\r\n sh7 = sh7 * sh8BitCompressionRangeForScene + vec8BitSHShift;\r\n sh8 = sh8 * sh8BitCompressionRangeForScene + vec8BitSHShift;\r\n }\r\n\r\n vColor.rgb +=\r\n (SH_C2[0] * xy) * sh4 +\r\n (SH_C2[1] * yz) * sh5 +\r\n (SH_C2[2] * (2.0 * zz - xx - yy)) * sh6 +\r\n (SH_C2[3] * xz) * sh7 +\r\n (SH_C2[4] * (xx - yy)) * sh8;\r\n }\r\n `;\r\n }\r\n\r\n vertexShaderSource += `\r\n\r\n vColor.rgb = clamp(vColor.rgb, vec3(0.), vec3(1.));\r\n\r\n }\r\n\r\n `;\r\n }\r\n\r\n return vertexShaderSource;\r\n }\r\n\r\n static getVertexShaderFadeIn() {\r\n return `\r\n if (fadeInComplete == 0) {\r\n float opacityAdjust = 1.0;\r\n float centerDist = length(splatCenter - sceneCenter);\r\n float renderTime = max(currentTime - firstRenderTime, 0.0);\r\n\r\n float fadeDistance = 0.75;\r\n float distanceLoadFadeInFactor = step(visibleRegionFadeStartRadius, centerDist);\r\n distanceLoadFadeInFactor = (1.0 - distanceLoadFadeInFactor) +\r\n (1.0 - clamp((centerDist - visibleRegionFadeStartRadius) / fadeDistance, 0.0, 1.0)) *\r\n distanceLoadFadeInFactor;\r\n opacityAdjust *= distanceLoadFadeInFactor;\r\n vColor.a *= opacityAdjust;\r\n }\r\n `;\r\n }\r\n\r\n static getUniforms(dynamicMode = false, enableOptionalEffects = false, maxSphericalHarmonicsDegree = 0,\r\n splatScale = 1.0, pointCloudModeEnabled = false) {\r\n\r\n const uniforms = {\r\n 'sceneCenter': {\r\n 'type': 'v3',\r\n 'value': new Vector3()\r\n },\r\n 'fadeInComplete': {\r\n 'type': 'i',\r\n 'value': 0\r\n },\r\n 'orthographicMode': {\r\n 'type': 'i',\r\n 'value': 0\r\n },\r\n 'visibleRegionFadeStartRadius': {\r\n 'type': 'f',\r\n 'value': 0.0\r\n },\r\n 'visibleRegionRadius': {\r\n 'type': 'f',\r\n 'value': 0.0\r\n },\r\n 'bindMatrix': {\r\n 'type': 'm4',\r\n 'value': new Matrix4()\r\n },\r\n 'bindMatrixInverse': {\r\n 'type': 'm4',\r\n 'value': new Matrix4()\r\n },\r\n 'currentTime': {\r\n 'type': 'f',\r\n 'value': 0.0\r\n },\r\n 'firstRenderTime': {\r\n 'type': 'f',\r\n 'value': 0.0\r\n },\r\n 'centersColorsTexture': {\r\n 'type': 't',\r\n 'value': null\r\n },\r\n 'flameModelTexture': {\r\n 'type': 't',\r\n 'value': null\r\n },\r\n 'boneTexture': {\r\n 'type': 't',\r\n 'value': null\r\n },\r\n 'boneTexture0': {\r\n 'type': 't',\r\n 'value': null\r\n },\r\n 'boneWeightTexture': {\r\n 'type': 't',\r\n 'value': null\r\n },\r\n 'sphericalHarmonicsTexture': {\r\n 'type': 't',\r\n 'value': null\r\n },\r\n 'sphericalHarmonicsTextureR': {\r\n 'type': 't',\r\n 'value': null\r\n },\r\n 'sphericalHarmonicsTextureG': {\r\n 'type': 't',\r\n 'value': null\r\n },\r\n 'sphericalHarmonicsTextureB': {\r\n 'type': 't',\r\n 'value': null\r\n },\r\n 'sphericalHarmonics8BitCompressionRangeMin': {\r\n 'type': 'f',\r\n 'value': []\r\n },\r\n 'sphericalHarmonics8BitCompressionRangeMax': {\r\n 'type': 'f',\r\n 'value': []\r\n },\r\n 'focal': {\r\n 'type': 'v2',\r\n 'value': new Vector2()\r\n },\r\n 'orthoZoom': {\r\n 'type': 'f',\r\n 'value': 1.0\r\n },\r\n 'inverseFocalAdjustment': {\r\n 'type': 'f',\r\n 'value': 1.0\r\n },\r\n 'viewport': {\r\n 'type': 'v2',\r\n 'value': new Vector2()\r\n },\r\n 'basisViewport': {\r\n 'type': 'v2',\r\n 'value': new Vector2()\r\n },\r\n 'debugColor': {\r\n 'type': 'v3',\r\n 'value': new Color()\r\n },\r\n 'centersColorsTextureSize': {\r\n 'type': 'v2',\r\n 'value': new Vector2(1024, 1024)\r\n },\r\n 'flameModelTextureSize': {\r\n 'type': 'v2',\r\n 'value': new Vector2(4096, 2048)\r\n },\r\n 'boneTextureSize': {\r\n 'type': 'v2',\r\n 'value': new Vector2(4, 32)\r\n },\r\n 'boneWeightTextureSize': {\r\n 'type': 'v2',\r\n 'value': new Vector2(512, 512)\r\n },\r\n \r\n 'sphericalHarmonicsDegree': {\r\n 'type': 'i',\r\n 'value': maxSphericalHarmonicsDegree\r\n },\r\n 'sphericalHarmonicsTextureSize': {\r\n 'type': 'v2',\r\n 'value': new Vector2(1024, 1024)\r\n },\r\n 'sphericalHarmonics8BitMode': {\r\n 'type': 'i',\r\n 'value': 0\r\n },\r\n 'sphericalHarmonicsMultiTextureMode': {\r\n 'type': 'i',\r\n 'value': 0\r\n },\r\n 'splatScale': {\r\n 'type': 'f',\r\n 'value': splatScale\r\n },\r\n 'pointCloudModeEnabled': {\r\n 'type': 'i',\r\n 'value': pointCloudModeEnabled ? 1 : 0\r\n },\r\n 'sceneIndexesTexture': {\r\n 'type': 't',\r\n 'value': null\r\n },\r\n 'sceneIndexesTextureSize': {\r\n 'type': 'v2',\r\n 'value': new Vector2(1024, 1024)\r\n },\r\n 'sceneCount': {\r\n 'type': 'i',\r\n 'value': 1\r\n },\r\n 'gaussianSplatCount': {\r\n 'type': 'i',\r\n 'value': 1\r\n },\r\n 'bsCount': {\r\n 'type': 'i',\r\n 'value': 1\r\n },\r\n 'headBoneIndex': {\r\n 'type': 'f',\r\n 'value': -1.0\r\n },\r\n 'eyeBlinkLeft': {\r\n 'type': 'f',\r\n 'value': 0.0\r\n },\r\n 'eyeBlinkRight': {\r\n 'type': 'f',\r\n 'value': 0.0\r\n }\r\n };\r\n for (let i = 0; i < Constants.MaxScenes; i++) {\r\n uniforms.sphericalHarmonics8BitCompressionRangeMin.value.push(-Constants.SphericalHarmonics8BitCompressionRange / 2.0);\r\n uniforms.sphericalHarmonics8BitCompressionRangeMax.value.push(Constants.SphericalHarmonics8BitCompressionRange / 2.0);\r\n }\r\n\r\n if (enableOptionalEffects) {\r\n const sceneOpacity = [];\r\n for (let i = 0; i < Constants.MaxScenes; i++) {\r\n sceneOpacity.push(1.0);\r\n }\r\n uniforms['sceneOpacity'] ={\r\n 'type': 'f',\r\n 'value': sceneOpacity\r\n };\r\n\r\n const sceneVisibility = [];\r\n for (let i = 0; i < Constants.MaxScenes; i++) {\r\n sceneVisibility.push(1);\r\n }\r\n uniforms['sceneVisibility'] ={\r\n 'type': 'i',\r\n 'value': sceneVisibility\r\n };\r\n }\r\n\r\n if (dynamicMode) {\r\n const transformMatrices = [];\r\n for (let i = 0; i < Constants.MaxScenes; i++) {\r\n transformMatrices.push(new Matrix4());\r\n }\r\n uniforms['transforms'] = {\r\n 'type': 'mat4',\r\n 'value': transformMatrices\r\n };\r\n }\r\n\r\n return uniforms;\r\n }\r\n\r\n}\r\n\r\nclass SplatMaterial3D {\r\n\r\n /**\r\n * Build the Three.js material that is used to render the splats.\r\n * @param {number} dynamicMode If true, it means the scene geometry represented by this splat mesh is not stationary or\r\n * that the splat count might change\r\n * @param {boolean} enableOptionalEffects When true, allows for usage of extra properties and attributes in the shader for effects\r\n * such as opacity adjustment. Default is false for performance reasons.\r\n * @param {boolean} antialiased If true, calculate compensation factor to deal with gaussians being rendered at a significantly\r\n * different resolution than that of their training\r\n * @param {number} maxScreenSpaceSplatSize The maximum clip space splat size\r\n * @param {number} splatScale Value by which all splats are scaled in screen-space (default is 1.0)\r\n * @param {number} pointCloudModeEnabled Render all splats as screen-space circles\r\n * @param {number} maxSphericalHarmonicsDegree Degree of spherical harmonics to utilize in rendering splats\r\n * @return {THREE.ShaderMaterial}\r\n */\r\n static build(dynamicMode = false, enableOptionalEffects = false, antialiased = false, maxScreenSpaceSplatSize = 2048,\r\n splatScale = 1.0, pointCloudModeEnabled = false, maxSphericalHarmonicsDegree = 0, kernel2DSize = 0.3) {\r\n\r\n const customVertexVars = `\r\n uniform vec2 covariancesTextureSize;\r\n uniform highp sampler2D covariancesTexture;\r\n uniform highp usampler2D covariancesTextureHalfFloat;\r\n uniform int covariancesAreHalfFloat;\r\n\r\n void fromCovarianceHalfFloatV4(uvec4 val, out vec4 first, out vec4 second) {\r\n vec2 r = unpackHalf2x16(val.r);\r\n vec2 g = unpackHalf2x16(val.g);\r\n vec2 b = unpackHalf2x16(val.b);\r\n\r\n first = vec4(r.x, r.y, g.x, g.y);\r\n second = vec4(b.x, b.y, 0.0, 0.0);\r\n }\r\n `;\r\n\r\n let vertexShaderSource = SplatMaterial.buildVertexShaderBase(dynamicMode, enableOptionalEffects,\r\n maxSphericalHarmonicsDegree, customVertexVars);\r\n vertexShaderSource += SplatMaterial3D.buildVertexShaderProjection(antialiased, enableOptionalEffects,\r\n maxScreenSpaceSplatSize, kernel2DSize);\r\n const fragmentShaderSource = SplatMaterial3D.buildFragmentShader();\r\n\r\n const uniforms = SplatMaterial.getUniforms(dynamicMode, enableOptionalEffects,\r\n maxSphericalHarmonicsDegree, splatScale, pointCloudModeEnabled);\r\n\r\n uniforms['covariancesTextureSize'] = {\r\n 'type': 'v2',\r\n 'value': new Vector2(1024, 1024)\r\n };\r\n uniforms['covariancesTexture'] = {\r\n 'type': 't',\r\n 'value': null\r\n };\r\n uniforms['covariancesTextureHalfFloat'] = {\r\n 'type': 't',\r\n 'value': null\r\n };\r\n uniforms['covariancesAreHalfFloat'] = {\r\n 'type': 'i',\r\n 'value': 0\r\n };\r\n\r\n const material = new ShaderMaterial({\r\n uniforms: uniforms,\r\n vertexShader: vertexShaderSource,\r\n fragmentShader: fragmentShaderSource,\r\n transparent: true,\r\n alphaTest: 1.0,\r\n blending: NormalBlending,\r\n depthTest: true,\r\n depthWrite: false,\r\n side: DoubleSide\r\n });\r\n\r\n return material;\r\n }\r\n\r\n static buildVertexShaderProjection(antialiased, enableOptionalEffects, maxScreenSpaceSplatSize, kernel2DSize) {\r\n let vertexShaderSource = `\r\n\r\n vec4 sampledCovarianceA;\r\n vec4 sampledCovarianceB;\r\n vec3 cov3D_M11_M12_M13;\r\n vec3 cov3D_M22_M23_M33;\r\n if (covariancesAreHalfFloat == 0) {\r\n sampledCovarianceA = texture(covariancesTexture, getDataUVF(nearestEvenIndex, 1.5, oddOffset,\r\n covariancesTextureSize));\r\n sampledCovarianceB = texture(covariancesTexture, getDataUVF(nearestEvenIndex, 1.5, oddOffset + uint(1),\r\n covariancesTextureSize));\r\n\r\n cov3D_M11_M12_M13 = vec3(sampledCovarianceA.rgb) * (1.0 - fOddOffset) +\r\n vec3(sampledCovarianceA.ba, sampledCovarianceB.r) * fOddOffset;\r\n cov3D_M22_M23_M33 = vec3(sampledCovarianceA.a, sampledCovarianceB.rg) * (1.0 - fOddOffset) +\r\n vec3(sampledCovarianceB.gba) * fOddOffset;\r\n } else {\r\n uvec4 sampledCovarianceU = texture(covariancesTextureHalfFloat, getDataUV(1, 0, covariancesTextureSize));\r\n fromCovarianceHalfFloatV4(sampledCovarianceU, sampledCovarianceA, sampledCovarianceB);\r\n cov3D_M11_M12_M13 = sampledCovarianceA.rgb;\r\n cov3D_M22_M23_M33 = vec3(sampledCovarianceA.a, sampledCovarianceB.rg);\r\n }\r\n \r\n // Construct the 3D covariance matrix\r\n mat3 Vrk = mat3(\r\n cov3D_M11_M12_M13.x, cov3D_M11_M12_M13.y, cov3D_M11_M12_M13.z,\r\n cov3D_M11_M12_M13.y, cov3D_M22_M23_M33.x, cov3D_M22_M23_M33.y,\r\n cov3D_M11_M12_M13.z, cov3D_M22_M23_M33.y, cov3D_M22_M23_M33.z\r\n );\r\n\r\n mat3 J;\r\n if (orthographicMode == 1) {\r\n // Since the projection is linear, we don't need an approximation\r\n J = transpose(mat3(orthoZoom, 0.0, 0.0,\r\n 0.0, orthoZoom, 0.0,\r\n 0.0, 0.0, 0.0));\r\n } else {\r\n // Construct the Jacobian of the affine approximation of the projection matrix. It will be used to transform the\r\n // 3D covariance matrix instead of using the actual projection matrix because that transformation would\r\n // require a non-linear component (perspective division) which would yield a non-gaussian result.\r\n float s = 1.0 / (viewCenter.z * viewCenter.z);\r\n J = mat3(\r\n focal.x / viewCenter.z, 0., -(focal.x * viewCenter.x) * s,\r\n 0., focal.y / viewCenter.z, -(focal.y * viewCenter.y) * s,\r\n 0., 0., 0.\r\n );\r\n }\r\n\r\n // Concatenate the projection approximation with the model-view transformation\r\n mat3 W = transpose(mat3(transformModelViewMatrix));\r\n mat3 T = W * J;\r\n\r\n // Transform the 3D covariance matrix (Vrk) to compute the 2D covariance matrix\r\n mat3 cov2Dm = transpose(T) * Vrk * T;\r\n `;\r\n\r\n if (antialiased) {\r\n vertexShaderSource += `\r\n float detOrig = cov2Dm[0][0] * cov2Dm[1][1] - cov2Dm[0][1] * cov2Dm[0][1];\r\n cov2Dm[0][0] += ${kernel2DSize};\r\n cov2Dm[1][1] += ${kernel2DSize};\r\n float detBlur = cov2Dm[0][0] * cov2Dm[1][1] - cov2Dm[0][1] * cov2Dm[0][1];\r\n vColor.a *= sqrt(max(detOrig / detBlur, 0.0));\r\n if (vColor.a < minAlpha) return;\r\n `;\r\n } else {\r\n vertexShaderSource += `\r\n cov2Dm[0][0] += ${kernel2DSize};\r\n cov2Dm[1][1] += ${kernel2DSize};\r\n `;\r\n }\r\n\r\n vertexShaderSource += `\r\n\r\n // We are interested in the upper-left 2x2 portion of the projected 3D covariance matrix because\r\n // we only care about the X and Y values. We want the X-diagonal, cov2Dm[0][0],\r\n // the Y-diagonal, cov2Dm[1][1], and the correlation between the two cov2Dm[0][1]. We don't\r\n // need cov2Dm[1][0] because it is a symetric matrix.\r\n vec3 cov2Dv = vec3(cov2Dm[0][0], cov2Dm[0][1], cov2Dm[1][1]);\r\n\r\n // We now need to solve for the eigen-values and eigen vectors of the 2D covariance matrix\r\n // so that we can determine the 2D basis for the splat. This is done using the method described\r\n // here: https://people.math.harvard.edu/~knill/teaching/math21b2004/exhibits/2dmatrices/index.html\r\n // After calculating the eigen-values and eigen-vectors, we calculate the basis for rendering the splat\r\n // by normalizing the eigen-vectors and then multiplying them by (sqrt(8) * sqrt(eigen-value)), which is\r\n // equal to scaling them by sqrt(8) standard deviations.\r\n //\r\n // This is a different approach than in the original work at INRIA. In that work they compute the\r\n // max extents of the projected splat in screen space to form a screen-space aligned bounding rectangle\r\n // which forms the geometry that is actually rasterized. The dimensions of that bounding box are 3.0\r\n // times the square root of the maximum eigen-value, or 3 standard deviations. They then use the inverse\r\n // 2D covariance matrix (called 'conic') in the CUDA rendering thread to determine fragment opacity by\r\n // calculating the full gaussian: exp(-0.5 * (X - mean) * conic * (X - mean)) * splat opacity\r\n float a = cov2Dv.x;\r\n float d = cov2Dv.z;\r\n float b = cov2Dv.y;\r\n float D = a * d - b * b;\r\n float trace = a + d;\r\n float traceOver2 = 0.5 * trace;\r\n float term2 = sqrt(max(0.1f, traceOver2 * traceOver2 - D));\r\n float eigenValue1 = traceOver2 + term2;\r\n float eigenValue2 = traceOver2 - term2;\r\n\r\n if (pointCloudModeEnabled == 1) {\r\n eigenValue1 = eigenValue2 = 0.2;\r\n }\r\n\r\n if (eigenValue2 <= 0.0) return;\r\n\r\n vec2 eigenVector1 = normalize(vec2(b, eigenValue1 - a));\r\n // since the eigen vectors are orthogonal, we derive the second one from the first\r\n vec2 eigenVector2 = vec2(eigenVector1.y, -eigenVector1.x);\r\n\r\n // We use sqrt(8) standard deviations instead of 3 to eliminate more of the splat with a very low opacity.\r\n vec2 basisVector1 = eigenVector1 * splatScale * min(sqrt8 * sqrt(eigenValue1), ${parseInt(maxScreenSpaceSplatSize)}.0);\r\n vec2 basisVector2 = eigenVector2 * splatScale * min(sqrt8 * sqrt(eigenValue2), ${parseInt(maxScreenSpaceSplatSize)}.0);\r\n `;\r\n\r\n if (enableOptionalEffects) {\r\n vertexShaderSource += `\r\n vColor.a *= splatOpacityFromScene;\r\n `;\r\n }\r\n\r\n vertexShaderSource += `\r\n vec2 ndcOffset = vec2(vPosition.x * basisVector1 + vPosition.y * basisVector2) *\r\n basisViewport * 2.0 * inverseFocalAdjustment;\r\n\r\n vec4 quadPos = vec4(ndcCenter.xy + ndcOffset, ndcCenter.z, 1.0);\r\n gl_Position = quadPos;\r\n\r\n // Scale the position data we send to the fragment shader\r\n vPosition *= sqrt8;\r\n `;\r\n\r\n vertexShaderSource += SplatMaterial.getVertexShaderFadeIn();\r\n vertexShaderSource += `}`;\r\n\r\n return vertexShaderSource;\r\n }\r\n\r\n static buildFragmentShader() {\r\n let fragmentShaderSource = `\r\n precision highp float;\r\n #include <common>\r\n \r\n uniform vec3 debugColor;\r\n\r\n varying vec4 vColor;\r\n varying vec2 vUv;\r\n varying vec2 vPosition;\r\n varying vec2 vSplatIndex;\r\n\r\n `;\r\n\r\n fragmentShaderSource += `\r\n void main () {\r\n // Compute the positional squared distance from the center of the splat to the current fragment.\r\n float A = dot(vPosition, vPosition);\r\n // Since the positional data in vPosition has been scaled by sqrt(8), the squared result will be\r\n // scaled by a factor of 8. If the squared result is larger than 8, it means it is outside the ellipse\r\n // defined by the rectangle formed by vPosition. It also means it's farther\r\n // away than sqrt(8) standard deviations from the mean.\r\n\r\n // if(vSplatIndex.x > 20000.0) discard;\r\n // if (A > 8.0) discard;\r\n vec3 color = vColor.rgb;\r\n\r\n // Since the rendered splat is scaled by sqrt(8), the inverse covariance matrix that is part of\r\n // the gaussian formula becomes the identity matrix. We're then left with (X - mean) * (X - mean),\r\n // and since 'mean' is zero, we have X * X, which is the same as A:\r\n float opacity = exp( -0.5*A) * vColor.a;\r\n if(opacity < 1.0 / 255.0)\r\n discard;\r\n\r\n // uint a = uint(255);\r\n // vec3 c = vec3(vSplatIndex.x / 256.0 / 256.0, float(uint(vSplatIndex.x / 256.0 )% a) / 256.0, float(uint(vSplatIndex.x)% a) / 256.0);\r\n // gl_FragColor = vec4(c, 1.0);\r\n gl_FragColor = vec4(color, opacity);\r\n\r\n\r\n }\r\n `;\r\n\r\n return fragmentShaderSource;\r\n }\r\n\r\n}","/**\r\n * SplatMaterial3D\r\n * \r\n * Based on @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * Modified for FLAME avatar support:\r\n * - Extended vertex shader for FLAME integration\r\n */\r\n\r\nimport { DoubleSide, NormalBlending, ShaderMaterial, Vector2 } from 'three';\r\nimport { SplatMaterial } from './SplatMaterial.js';\r\n\r\nexport class SplatMaterial3D {\r\n\r\n /**\r\n * Build the Three.js material that is used to render the splats.\r\n * @param {number} dynamicMode If true, it means the scene geometry represented by this splat mesh is not stationary or\r\n * that the splat count might change\r\n * @param {boolean} enableOptionalEffects When true, allows for usage of extra properties and attributes in the shader for effects\r\n * such as opacity adjustment. Default is false for performance reasons.\r\n * @param {boolean} antialiased If true, calculate compensation factor to deal with gaussians being rendered at a significantly\r\n * different resolution than that of their training\r\n * @param {number} maxScreenSpaceSplatSize The maximum clip space splat size\r\n * @param {number} splatScale Value by which all splats are scaled in screen-space (default is 1.0)\r\n * @param {number} pointCloudModeEnabled Render all splats as screen-space circles\r\n * @param {number} maxSphericalHarmonicsDegree Degree of spherical harmonics to utilize in rendering splats\r\n * @return {THREE.ShaderMaterial}\r\n */\r\n static build(dynamicMode = false, enableOptionalEffects = false, antialiased = false, maxScreenSpaceSplatSize = 2048,\r\n splatScale = 1.0, pointCloudModeEnabled = false, maxSphericalHarmonicsDegree = 0, kernel2DSize = 0.3, irisOcclusionConfig = null) {\r\n\r\n const customVertexVars = `\r\n uniform vec2 covariancesTextureSize;\r\n uniform highp sampler2D covariancesTexture;\r\n uniform highp usampler2D covariancesTextureHalfFloat;\r\n uniform int covariancesAreHalfFloat;\r\n\r\n void fromCovarianceHalfFloatV4(uvec4 val, out vec4 first, out vec4 second) {\r\n vec2 r = unpackHalf2x16(val.r);\r\n vec2 g = unpackHalf2x16(val.g);\r\n vec2 b = unpackHalf2x16(val.b);\r\n\r\n first = vec4(r.x, r.y, g.x, g.y);\r\n second = vec4(b.x, b.y, 0.0, 0.0);\r\n }\r\n `;\r\n\r\n // Add a varying for iris splats\r\n let vertexShaderSource = SplatMaterial.buildVertexShaderBase(dynamicMode, enableOptionalEffects,\r\n maxSphericalHarmonicsDegree, customVertexVars);\r\n vertexShaderSource += SplatMaterial3D.buildVertexShaderProjection(antialiased, enableOptionalEffects,\r\n maxScreenSpaceSplatSize, kernel2DSize);\r\n const fragmentShaderSource = SplatMaterial3D.buildFragmentShader(irisOcclusionConfig);\r\n\r\n const uniforms = SplatMaterial.getUniforms(dynamicMode, enableOptionalEffects,\r\n maxSphericalHarmonicsDegree, splatScale, pointCloudModeEnabled);\r\n\r\n uniforms['covariancesTextureSize'] = {\r\n 'type': 'v2',\r\n 'value': new Vector2(1024, 1024)\r\n };\r\n uniforms['covariancesTexture'] = {\r\n 'type': 't',\r\n 'value': null\r\n };\r\n uniforms['covariancesTextureHalfFloat'] = {\r\n 'type': 't',\r\n 'value': null\r\n };\r\n uniforms['covariancesAreHalfFloat'] = {\r\n 'type': 'i',\r\n 'value': 0\r\n };\r\n\r\n const material = new ShaderMaterial({\r\n uniforms: uniforms,\r\n vertexShader: vertexShaderSource,\r\n fragmentShader: fragmentShaderSource,\r\n transparent: true,\r\n alphaTest: 1.0,\r\n blending: NormalBlending,\r\n depthTest: true,\r\n depthWrite: false,\r\n side: DoubleSide\r\n });\r\n\r\n return material;\r\n }\r\n\r\n static buildVertexShaderProjection(antialiased, enableOptionalEffects, maxScreenSpaceSplatSize, kernel2DSize) {\r\n let vertexShaderSource = `\r\n\r\n vec4 sampledCovarianceA;\r\n vec4 sampledCovarianceB;\r\n vec3 cov3D_M11_M12_M13;\r\n vec3 cov3D_M22_M23_M33;\r\n if (covariancesAreHalfFloat == 0) {\r\n sampledCovarianceA = texture(covariancesTexture, getDataUVF(nearestEvenIndex, 1.5, oddOffset,\r\n covariancesTextureSize));\r\n sampledCovarianceB = texture(covariancesTexture, getDataUVF(nearestEvenIndex, 1.5, oddOffset + uint(1),\r\n covariancesTextureSize));\r\n\r\n cov3D_M11_M12_M13 = vec3(sampledCovarianceA.rgb) * (1.0 - fOddOffset) +\r\n vec3(sampledCovarianceA.ba, sampledCovarianceB.r) * fOddOffset;\r\n cov3D_M22_M23_M33 = vec3(sampledCovarianceA.a, sampledCovarianceB.rg) * (1.0 - fOddOffset) +\r\n vec3(sampledCovarianceB.gba) * fOddOffset;\r\n } else {\r\n uvec4 sampledCovarianceU = texture(covariancesTextureHalfFloat, getDataUV(1, 0, covariancesTextureSize));\r\n fromCovarianceHalfFloatV4(sampledCovarianceU, sampledCovarianceA, sampledCovarianceB);\r\n cov3D_M11_M12_M13 = sampledCovarianceA.rgb;\r\n cov3D_M22_M23_M33 = vec3(sampledCovarianceA.a, sampledCovarianceB.rg);\r\n }\r\n \r\n // Construct the 3D covariance matrix\r\n mat3 Vrk = mat3(\r\n cov3D_M11_M12_M13.x, cov3D_M11_M12_M13.y, cov3D_M11_M12_M13.z,\r\n cov3D_M11_M12_M13.y, cov3D_M22_M23_M33.x, cov3D_M22_M23_M33.y,\r\n cov3D_M11_M12_M13.z, cov3D_M22_M23_M33.y, cov3D_M22_M23_M33.z\r\n );\r\n\r\n mat3 J;\r\n if (orthographicMode == 1) {\r\n // Since the projection is linear, we don't need an approximation\r\n J = transpose(mat3(orthoZoom, 0.0, 0.0,\r\n 0.0, orthoZoom, 0.0,\r\n 0.0, 0.0, 0.0));\r\n } else {\r\n // Construct the Jacobian of the affine approximation of the projection matrix. It will be used to transform the\r\n // 3D covariance matrix instead of using the actual projection matrix because that transformation would\r\n // require a non-linear component (perspective division) which would yield a non-gaussian result.\r\n float s = 1.0 / (viewCenter.z * viewCenter.z);\r\n J = mat3(\r\n focal.x / viewCenter.z, 0., -(focal.x * viewCenter.x) * s,\r\n 0., focal.y / viewCenter.z, -(focal.y * viewCenter.y) * s,\r\n 0., 0., 0.\r\n );\r\n }\r\n\r\n // Concatenate the projection approximation with the model-view transformation\r\n mat3 W = transpose(mat3(transformModelViewMatrix));\r\n mat3 T = W * J;\r\n\r\n // Transform the 3D covariance matrix (Vrk) to compute the 2D covariance matrix\r\n mat3 cov2Dm = transpose(T) * Vrk * T;\r\n `;\r\n\r\n if (antialiased) {\r\n vertexShaderSource += `\r\n float detOrig = cov2Dm[0][0] * cov2Dm[1][1] - cov2Dm[0][1] * cov2Dm[0][1];\r\n cov2Dm[0][0] += ${kernel2DSize};\r\n cov2Dm[1][1] += ${kernel2DSize};\r\n float detBlur = cov2Dm[0][0] * cov2Dm[1][1] - cov2Dm[0][1] * cov2Dm[0][1];\r\n vColor.a *= sqrt(max(detOrig / detBlur, 0.0));\r\n if (vColor.a < minAlpha) return;\r\n `;\r\n } else {\r\n vertexShaderSource += `\r\n cov2Dm[0][0] += ${kernel2DSize};\r\n cov2Dm[1][1] += ${kernel2DSize};\r\n `;\r\n }\r\n\r\n vertexShaderSource += `\r\n\r\n // We are interested in the upper-left 2x2 portion of the projected 3D covariance matrix because\r\n // we only care about the X and Y values. We want the X-diagonal, cov2Dm[0][0],\r\n // the Y-diagonal, cov2Dm[1][1], and the correlation between the two cov2Dm[0][1]. We don't\r\n // need cov2Dm[1][0] because it is a symetric matrix.\r\n vec3 cov2Dv = vec3(cov2Dm[0][0], cov2Dm[0][1], cov2Dm[1][1]);\r\n\r\n // We now need to solve for the eigen-values and eigen vectors of the 2D covariance matrix\r\n // so that we can determine the 2D basis for the splat. This is done using the method described\r\n // here: https://people.math.harvard.edu/~knill/teaching/math21b2004/exhibits/2dmatrices/index.html\r\n // After calculating the eigen-values and eigen-vectors, we calculate the basis for rendering the splat\r\n // by normalizing the eigen-vectors and then multiplying them by (sqrt(8) * sqrt(eigen-value)), which is\r\n // equal to scaling them by sqrt(8) standard deviations.\r\n //\r\n // This is a different approach than in the original work at INRIA. In that work they compute the\r\n // max extents of the projected splat in screen space to form a screen-space aligned bounding rectangle\r\n // which forms the geometry that is actually rasterized. The dimensions of that bounding box are 3.0\r\n // times the square root of the maximum eigen-value, or 3 standard deviations. They then use the inverse\r\n // 2D covariance matrix (called 'conic') in the CUDA rendering thread to determine fragment opacity by\r\n // calculating the full gaussian: exp(-0.5 * (X - mean) * conic * (X - mean)) * splat opacity\r\n float a = cov2Dv.x;\r\n float d = cov2Dv.z;\r\n float b = cov2Dv.y;\r\n float D = a * d - b * b;\r\n float trace = a + d;\r\n float traceOver2 = 0.5 * trace;\r\n float term2 = sqrt(max(0.1f, traceOver2 * traceOver2 - D));\r\n float eigenValue1 = traceOver2 + term2;\r\n float eigenValue2 = traceOver2 - term2;\r\n\r\n if (pointCloudModeEnabled == 1) {\r\n eigenValue1 = eigenValue2 = 0.2;\r\n }\r\n\r\n if (eigenValue2 <= 0.0) return;\r\n\r\n vec2 eigenVector1 = normalize(vec2(b, eigenValue1 - a));\r\n // since the eigen vectors are orthogonal, we derive the second one from the first\r\n vec2 eigenVector2 = vec2(eigenVector1.y, -eigenVector1.x);\r\n\r\n // We use sqrt(8) standard deviations instead of 3 to eliminate more of the splat with a very low opacity.\r\n vec2 basisVector1 = eigenVector1 * splatScale * min(sqrt8 * sqrt(eigenValue1), ${parseInt(maxScreenSpaceSplatSize)}.0);\r\n vec2 basisVector2 = eigenVector2 * splatScale * min(sqrt8 * sqrt(eigenValue2), ${parseInt(maxScreenSpaceSplatSize)}.0);\r\n `;\r\n\r\n if (enableOptionalEffects) {\r\n vertexShaderSource += `\r\n vColor.a *= splatOpacityFromScene;\r\n `;\r\n }\r\n\r\n vertexShaderSource += `\r\n vec2 ndcOffset = vec2(vPosition.x * basisVector1 + vPosition.y * basisVector2) *\r\n basisViewport * 2.0 * inverseFocalAdjustment;\r\n\r\n vec4 quadPos = vec4(ndcCenter.xy + ndcOffset, ndcCenter.z, 1.0);\r\n gl_Position = quadPos;\r\n\r\n // Scale the position data we send to the fragment shader\r\n vPosition *= sqrt8;\r\n `;\r\n\r\n vertexShaderSource += SplatMaterial.getVertexShaderFadeIn();\r\n vertexShaderSource += `}`;\r\n\r\n return vertexShaderSource;\r\n }\r\n\r\n static buildFragmentShader(irisOcclusionConfig = null) {\r\n let fragmentShaderSource = `\r\n precision highp float;\r\n #include <common>\r\n\r\n uniform float eyeBlinkLeft;\r\n uniform float eyeBlinkRight;\r\n\r\n varying vec4 vColor;\r\n varying vec2 vUv;\r\n varying vec2 vPosition;\r\n varying vec2 vSplatIndex;\r\n `;\r\n\r\n fragmentShaderSource += `\r\n void main () {\r\n float A = dot(vPosition, vPosition);\r\n float opacity = exp(-0.5 * A) * vColor.a;\r\n if (opacity < 1.0 / 255.0)\r\n discard;\r\n `;\r\n\r\n // Generate iris occlusion code only if config exists\r\n if (irisOcclusionConfig && (irisOcclusionConfig.right_iris || irisOcclusionConfig.left_iris)) {\r\n fragmentShaderSource += `\r\n float idx = vSplatIndex.x;\r\n `;\r\n\r\n // Generate right iris checks\r\n if (irisOcclusionConfig.right_iris && irisOcclusionConfig.right_iris.length > 0) {\r\n const rightConditions = irisOcclusionConfig.right_iris\r\n .map(([start, end]) => `(idx >= ${start}.0 && idx <= ${end}.0)`)\r\n .join(' ||\\n ');\r\n\r\n fragmentShaderSource += `\r\n // Check if this splat is part of right iris\r\n bool isRightIris = ${rightConditions};\r\n `;\r\n } else {\r\n fragmentShaderSource += `\r\n bool isRightIris = false;\r\n `;\r\n }\r\n\r\n // Generate left iris checks\r\n if (irisOcclusionConfig.left_iris && irisOcclusionConfig.left_iris.length > 0) {\r\n const leftConditions = irisOcclusionConfig.left_iris\r\n .map(([start, end]) => `(idx >= ${start}.0 && idx <= ${end}.0)`)\r\n .join(' ||\\n ');\r\n\r\n fragmentShaderSource += `\r\n // Check if this splat is part of left iris\r\n bool isLeftIris = ${leftConditions};\r\n `;\r\n } else {\r\n fragmentShaderSource += `\r\n bool isLeftIris = false;\r\n `;\r\n }\r\n\r\n fragmentShaderSource += `\r\n float finalOpacity = opacity;\r\n\r\n // Smooth fade: iris fades out as eye closes (blink increases)\r\n // smoothstep(0.1, 0.5, blink) = 0 when blink<0.1, 1 when blink>0.5\r\n if (isRightIris) {\r\n float fadeFactor = 1.0 - smoothstep(0.1, 0.5, eyeBlinkRight);\r\n finalOpacity = opacity * fadeFactor;\r\n } else if (isLeftIris) {\r\n float fadeFactor = 1.0 - smoothstep(0.1, 0.5, eyeBlinkLeft);\r\n finalOpacity = opacity * fadeFactor;\r\n }\r\n\r\n if (finalOpacity < 1.0 / 255.0)\r\n discard;\r\n\r\n gl_FragColor = vec4(vColor.rgb, finalOpacity);\r\n }\r\n `;\r\n } else {\r\n // No iris occlusion - simple rendering\r\n fragmentShaderSource += `\r\n gl_FragColor = vec4(vColor.rgb, opacity);\r\n }\r\n `;\r\n }\r\n\r\n return fragmentShaderSource;\r\n }\r\n\r\n}\r\n","/**\r\n * SplatMaterial2D\r\n * \r\n * Based on @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * Modified for FLAME avatar support:\r\n * - Extended vertex shader for FLAME integration\r\n */\r\n\r\nimport { DoubleSide, NormalBlending, ShaderMaterial, Vector2 } from 'three';\r\nimport { SplatMaterial } from './SplatMaterial.js';\r\n\r\nexport class SplatMaterial2D {\r\n\r\n /**\r\n * Build the Three.js material that is used to render the splats.\r\n * @param {number} dynamicMode If true, it means the scene geometry represented by this splat mesh is not stationary or\r\n * that the splat count might change\r\n * @param {boolean} enableOptionalEffects When true, allows for usage of extra properties and attributes in the shader for effects\r\n * such as opacity adjustment. Default is false for performance reasons.\r\n * @param {number} splatScale Value by which all splats are scaled in screen-space (default is 1.0)\r\n * @param {number} pointCloudModeEnabled Render all splats as screen-space circles\r\n * @param {number} maxSphericalHarmonicsDegree Degree of spherical harmonics to utilize in rendering splats\r\n * @return {THREE.ShaderMaterial}\r\n */\r\n static build(dynamicMode = false, enableOptionalEffects = false, splatScale = 1.0,\r\n pointCloudModeEnabled = false, maxSphericalHarmonicsDegree = 0) {\r\n\r\n const customVertexVars = `\r\n uniform vec2 scaleRotationsTextureSize;\r\n uniform highp sampler2D scaleRotationsTexture;\r\n varying mat3 vT;\r\n varying vec2 vQuadCenter;\r\n varying vec2 vFragCoord;\r\n `;\r\n\r\n let vertexShaderSource = SplatMaterial.buildVertexShaderBase(dynamicMode, enableOptionalEffects,\r\n maxSphericalHarmonicsDegree, customVertexVars);\r\n vertexShaderSource += SplatMaterial2D.buildVertexShaderProjection();\r\n const fragmentShaderSource = SplatMaterial2D.buildFragmentShader();\r\n\r\n const uniforms = SplatMaterial.getUniforms(dynamicMode, enableOptionalEffects,\r\n maxSphericalHarmonicsDegree, splatScale, pointCloudModeEnabled);\r\n\r\n uniforms['scaleRotationsTexture'] = {\r\n 'type': 't',\r\n 'value': null\r\n };\r\n uniforms['scaleRotationsTextureSize'] = {\r\n 'type': 'v2',\r\n 'value': new Vector2(1024, 1024)\r\n };\r\n\r\n const material = new ShaderMaterial({\r\n uniforms: uniforms,\r\n vertexShader: vertexShaderSource,\r\n fragmentShader: fragmentShaderSource,\r\n transparent: true,\r\n alphaTest: 1.0,\r\n blending: NormalBlending,\r\n depthTest: true,\r\n depthWrite: false,\r\n side: DoubleSide\r\n });\r\n\r\n return material;\r\n }\r\n\r\n static buildVertexShaderProjection() {\r\n\r\n // Original CUDA code for calculating splat-to-screen transformation, for reference\r\n /*\r\n glm::mat3 R = quat_to_rotmat(rot);\r\n glm::mat3 S = scale_to_mat(scale, mod);\r\n glm::mat3 L = R * S;\r\n\r\n // center of Gaussians in the camera coordinate\r\n glm::mat3x4 splat2world = glm::mat3x4(\r\n glm::vec4(L[0], 0.0),\r\n glm::vec4(L[1], 0.0),\r\n glm::vec4(p_orig.x, p_orig.y, p_orig.z, 1)\r\n );\r\n\r\n glm::mat4 world2ndc = glm::mat4(\r\n projmatrix[0], projmatrix[4], projmatrix[8], projmatrix[12],\r\n projmatrix[1], projmatrix[5], projmatrix[9], projmatrix[13],\r\n projmatrix[2], projmatrix[6], projmatrix[10], projmatrix[14],\r\n projmatrix[3], projmatrix[7], projmatrix[11], projmatrix[15]\r\n );\r\n\r\n glm::mat3x4 ndc2pix = glm::mat3x4(\r\n glm::vec4(float(W) / 2.0, 0.0, 0.0, float(W-1) / 2.0),\r\n glm::vec4(0.0, float(H) / 2.0, 0.0, float(H-1) / 2.0),\r\n glm::vec4(0.0, 0.0, 0.0, 1.0)\r\n );\r\n\r\n T = glm::transpose(splat2world) * world2ndc * ndc2pix;\r\n normal = transformVec4x3({L[2].x, L[2].y, L[2].z}, viewmatrix);\r\n */\r\n\r\n // Compute a 2D-to-2D mapping matrix from a tangent plane into a image plane\r\n // given a 2D gaussian parameters. T = WH (from the paper: https://arxiv.org/pdf/2403.17888)\r\n let vertexShaderSource = `\r\n\r\n vec4 scaleRotationA = texture(scaleRotationsTexture, getDataUVF(nearestEvenIndex, 1.5,\r\n oddOffset, scaleRotationsTextureSize));\r\n vec4 scaleRotationB = texture(scaleRotationsTexture, getDataUVF(nearestEvenIndex, 1.5,\r\n oddOffset + uint(1), scaleRotationsTextureSize));\r\n\r\n vec3 scaleRotation123 = vec3(scaleRotationA.rgb) * (1.0 - fOddOffset) +\r\n vec3(scaleRotationA.ba, scaleRotationB.r) * fOddOffset;\r\n vec3 scaleRotation456 = vec3(scaleRotationA.a, scaleRotationB.rg) * (1.0 - fOddOffset) +\r\n vec3(scaleRotationB.gba) * fOddOffset;\r\n\r\n float missingW = sqrt(1.0 - scaleRotation456.x * scaleRotation456.x - scaleRotation456.y *\r\n scaleRotation456.y - scaleRotation456.z * scaleRotation456.z);\r\n mat3 R = quaternionToRotationMatrix(scaleRotation456.r, scaleRotation456.g, scaleRotation456.b, missingW);\r\n mat3 S = mat3(scaleRotation123.r, 0.0, 0.0,\r\n 0.0, scaleRotation123.g, 0.0,\r\n 0.0, 0.0, scaleRotation123.b);\r\n \r\n mat3 L = R * S;\r\n\r\n mat3x4 splat2World = mat3x4(vec4(L[0], 0.0),\r\n vec4(L[1], 0.0),\r\n vec4(splatCenter.x, splatCenter.y, splatCenter.z, 1.0));\r\n\r\n mat4 world2ndc = transpose(projectionMatrix * transformModelViewMatrix);\r\n\r\n mat3x4 ndc2pix = mat3x4(vec4(viewport.x / 2.0, 0.0, 0.0, (viewport.x - 1.0) / 2.0),\r\n vec4(0.0, viewport.y / 2.0, 0.0, (viewport.y - 1.0) / 2.0),\r\n vec4(0.0, 0.0, 0.0, 1.0));\r\n\r\n mat3 T = transpose(splat2World) * world2ndc * ndc2pix;\r\n vec3 normal = vec3(viewMatrix * vec4(L[0][2], L[1][2], L[2][2], 0.0));\r\n `;\r\n\r\n // Original CUDA code for projection to 2D, for reference\r\n /*\r\n float3 T0 = {T[0][0], T[0][1], T[0][2]};\r\n float3 T1 = {T[1][0], T[1][1], T[1][2]};\r\n float3 T3 = {T[2][0], T[2][1], T[2][2]};\r\n\r\n // Compute AABB\r\n float3 temp_point = {1.0f, 1.0f, -1.0f};\r\n float distance = sumf3(T3 * T3 * temp_point);\r\n float3 f = (1 / distance) * temp_point;\r\n if (distance == 0.0) return false;\r\n\r\n point_image = {\r\n sumf3(f * T0 * T3),\r\n sumf3(f * T1 * T3)\r\n };\r\n\r\n float2 temp = {\r\n sumf3(f * T0 * T0),\r\n sumf3(f * T1 * T1)\r\n };\r\n float2 half_extend = point_image * point_image - temp;\r\n extent = sqrtf2(maxf2(1e-4, half_extend));\r\n return true;\r\n */\r\n\r\n // Computing the bounding box of the 2D Gaussian and its center\r\n // The center of the bounding box is used to create a low pass filter.\r\n // This code is based off the reference implementation and creates an AABB aligned\r\n // with the screen for the quad to be rendered.\r\n const referenceQuadGeneration = `\r\n vec3 T0 = vec3(T[0][0], T[0][1], T[0][2]);\r\n vec3 T1 = vec3(T[1][0], T[1][1], T[1][2]);\r\n vec3 T3 = vec3(T[2][0], T[2][1], T[2][2]);\r\n\r\n vec3 tempPoint = vec3(1.0, 1.0, -1.0);\r\n float distance = (T3.x * T3.x * tempPoint.x) + (T3.y * T3.y * tempPoint.y) + (T3.z * T3.z * tempPoint.z);\r\n vec3 f = (1.0 / distance) * tempPoint;\r\n if (abs(distance) < 0.00001) return;\r\n\r\n float pointImageX = (T0.x * T3.x * f.x) + (T0.y * T3.y * f.y) + (T0.z * T3.z * f.z);\r\n float pointImageY = (T1.x * T3.x * f.x) + (T1.y * T3.y * f.y) + (T1.z * T3.z * f.z);\r\n vec2 pointImage = vec2(pointImageX, pointImageY);\r\n\r\n float tempX = (T0.x * T0.x * f.x) + (T0.y * T0.y * f.y) + (T0.z * T0.z * f.z);\r\n float tempY = (T1.x * T1.x * f.x) + (T1.y * T1.y * f.y) + (T1.z * T1.z * f.z);\r\n vec2 temp = vec2(tempX, tempY);\r\n\r\n vec2 halfExtend = pointImage * pointImage - temp;\r\n vec2 extent = sqrt(max(vec2(0.0001), halfExtend));\r\n float radius = max(extent.x, extent.y);\r\n\r\n vec2 ndcOffset = ((position.xy * radius * 3.0) * basisViewport * 2.0);\r\n\r\n vec4 quadPos = vec4(ndcCenter.xy + ndcOffset, ndcCenter.z, 1.0);\r\n gl_Position = quadPos;\r\n\r\n vT = T;\r\n vQuadCenter = pointImage;\r\n vFragCoord = (quadPos.xy * 0.5 + 0.5) * viewport;\r\n `;\r\n\r\n const useRefImplementation = false;\r\n if (useRefImplementation) {\r\n vertexShaderSource += referenceQuadGeneration;\r\n } else {\r\n // Create a quad that is aligned with the eigen vectors of the projected gaussian for rendering.\r\n // This is a different approach than the reference implementation, similar to how the rendering of\r\n // 3D gaussians in this viewer differs from the reference implementation. If the quad is too small\r\n // (smaller than a pixel), then revert to the reference implementation.\r\n vertexShaderSource += `\r\n\r\n mat4 splat2World4 = mat4(vec4(L[0], 0.0),\r\n vec4(L[1], 0.0),\r\n vec4(L[2], 0.0),\r\n vec4(splatCenter.x, splatCenter.y, splatCenter.z, 1.0));\r\n\r\n mat4 Tt = transpose(transpose(splat2World4) * world2ndc);\r\n\r\n vec4 tempPoint1 = Tt * vec4(1.0, 0.0, 0.0, 1.0);\r\n tempPoint1 /= tempPoint1.w;\r\n\r\n vec4 tempPoint2 = Tt * vec4(0.0, 1.0, 0.0, 1.0);\r\n tempPoint2 /= tempPoint2.w;\r\n\r\n vec4 center = Tt * vec4(0.0, 0.0, 0.0, 1.0);\r\n center /= center.w;\r\n\r\n vec2 basisVector1 = tempPoint1.xy - center.xy;\r\n vec2 basisVector2 = tempPoint2.xy - center.xy;\r\n\r\n vec2 basisVector1Screen = basisVector1 * 0.5 * viewport;\r\n vec2 basisVector2Screen = basisVector2 * 0.5 * viewport;\r\n\r\n const float minPix = 1.;\r\n if (length(basisVector1Screen) < minPix || length(basisVector2Screen) < minPix) {\r\n ${referenceQuadGeneration}\r\n } else {\r\n vec2 ndcOffset = vec2(position.x * basisVector1 + position.y * basisVector2) * 3.0 * inverseFocalAdjustment;\r\n vec4 quadPos = vec4(ndcCenter.xy + ndcOffset, ndcCenter.z, 1.0);\r\n gl_Position = quadPos;\r\n\r\n vT = T;\r\n vQuadCenter = center.xy;\r\n vFragCoord = (quadPos.xy * 0.5 + 0.5) * viewport;\r\n }\r\n `;\r\n }\r\n\r\n vertexShaderSource += SplatMaterial.getVertexShaderFadeIn();\r\n vertexShaderSource += `}`;\r\n\r\n return vertexShaderSource;\r\n }\r\n\r\n static buildFragmentShader() {\r\n\r\n // Original CUDA code for splat intersection, for reference\r\n /*\r\n const float2 xy = collected_xy[j];\r\n const float3 Tu = collected_Tu[j];\r\n const float3 Tv = collected_Tv[j];\r\n const float3 Tw = collected_Tw[j];\r\n float3 k = pix.x * Tw - Tu;\r\n float3 l = pix.y * Tw - Tv;\r\n float3 p = cross(k, l);\r\n if (p.z == 0.0) continue;\r\n float2 s = {p.x / p.z, p.y / p.z};\r\n float rho3d = (s.x * s.x + s.y * s.y);\r\n float2 d = {xy.x - pixf.x, xy.y - pixf.y};\r\n float rho2d = FilterInvSquare * (d.x * d.x + d.y * d.y);\r\n\r\n // compute intersection and depth\r\n float rho = min(rho3d, rho2d);\r\n float depth = (rho3d <= rho2d) ? (s.x * Tw.x + s.y * Tw.y) + Tw.z : Tw.z;\r\n if (depth < near_n) continue;\r\n float4 nor_o = collected_normal_opacity[j];\r\n float normal[3] = {nor_o.x, nor_o.y, nor_o.z};\r\n float opa = nor_o.w;\r\n\r\n float power = -0.5f * rho;\r\n if (power > 0.0f)\r\n continue;\r\n\r\n // Eq. (2) from 3D Gaussian splatting paper.\r\n // Obtain alpha by multiplying with Gaussian opacity\r\n // and its exponential falloff from mean.\r\n // Avoid numerical instabilities (see paper appendix).\r\n float alpha = min(0.99f, opa * exp(power));\r\n if (alpha < 1.0f / 255.0f)\r\n continue;\r\n float test_T = T * (1 - alpha);\r\n if (test_T < 0.0001f)\r\n {\r\n done = true;\r\n continue;\r\n }\r\n\r\n float w = alpha * T;\r\n */\r\n let fragmentShaderSource = `\r\n precision highp float;\r\n #include <common>\r\n\r\n uniform vec3 debugColor;\r\n\r\n varying vec4 vColor;\r\n varying vec2 vUv;\r\n varying vec2 vPosition;\r\n varying mat3 vT;\r\n varying vec2 vQuadCenter;\r\n varying vec2 vFragCoord;\r\n\r\n void main () {\r\n\r\n const float FilterInvSquare = 2.0;\r\n const float near_n = 0.2;\r\n const float T = 1.0;\r\n\r\n vec2 xy = vQuadCenter;\r\n vec3 Tu = vT[0];\r\n vec3 Tv = vT[1];\r\n vec3 Tw = vT[2];\r\n vec3 k = vFragCoord.x * Tw - Tu;\r\n vec3 l = vFragCoord.y * Tw - Tv;\r\n vec3 p = cross(k, l);\r\n if (p.z == 0.0) discard;\r\n vec2 s = vec2(p.x / p.z, p.y / p.z);\r\n float rho3d = (s.x * s.x + s.y * s.y); \r\n vec2 d = vec2(xy.x - vFragCoord.x, xy.y - vFragCoord.y);\r\n float rho2d = FilterInvSquare * (d.x * d.x + d.y * d.y); \r\n\r\n // compute intersection and depth\r\n float rho = min(rho3d, rho2d);\r\n float depth = (rho3d <= rho2d) ? (s.x * Tw.x + s.y * Tw.y) + Tw.z : Tw.z; \r\n if (depth < near_n) discard;\r\n // vec4 nor_o = collected_normal_opacity[j];\r\n // float normal[3] = {nor_o.x, nor_o.y, nor_o.z};\r\n float opa = vColor.a;\r\n\r\n float power = -0.5f * rho;\r\n if (power > 0.0f) discard;\r\n\r\n // Eq. (2) from 3D Gaussian splatting paper.\r\n // Obtain alpha by multiplying with Gaussian opacity\r\n // and its exponential falloff from mean.\r\n // Avoid numerical instabilities (see paper appendix). \r\n float alpha = min(0.99f, opa * exp(power));\r\n if (alpha < 1.0f / 255.0f) discard;\r\n float test_T = T * (1.0 - alpha);\r\n if (test_T < 0.0001)discard;\r\n\r\n float w = alpha * T;\r\n gl_FragColor = vec4(vColor.rgb, w);\r\n }\r\n `;\r\n\r\n return fragmentShaderSource;\r\n }\r\n}\r\n","/**\r\n * SplatMesh\r\n * \r\n * Based on @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * HEAVILY MODIFIED for FLAME avatar support:\r\n * - Added FLAME bone texture handling\r\n * - Added expression blendshape support\r\n * - Extended with skinning data management\r\n * - Additional ~800 lines of FLAME-specific code\r\n */\r\n\r\nimport { Box3, BufferGeometry, DataTexture, FloatType, HalfFloatType, Matrix4, Mesh, MeshBasicMaterial, Quaternion, RGBAFormat, RGBAIntegerFormat, RGFormat, RGIntegerFormat, RedFormat, RedIntegerFormat, RGBIntegerFormat, Scene, UnsignedByteType, UnsignedIntType, Vector2, Vector3, Vector4, WebGLRenderer } from 'three';\r\nimport { SplatRenderMode } from '../enums/SplatRenderMode.js';\r\nimport { LogLevel } from '../enums/LogLevel.js';\r\nimport { SceneRevealMode } from '../enums/SceneRevealMode.js';\r\nimport { Constants } from '../enums/EngineConstants.js';\r\nimport { SplatScene } from './SplatScene.js';\r\nimport { SplatGeometry } from './SplatGeometry.js';\r\nimport { SplatTree } from './SplatTree.js';\r\nimport { SplatMaterial3D } from '../materials/SplatMaterial3D.js';\r\nimport { SplatMaterial2D } from '../materials/SplatMaterial2D.js';\r\nimport { getSphericalHarmonicsComponentCountForDegree, uintEncodedFloat, rgbaArrayToInteger, clamp } from '../utils/Util.js';\r\nimport { getLogger } from '../utils/Logger.js';\r\n\r\nconst logger = getLogger('SplatMesh');\r\n\r\n// Dummy geometry and material for initial Mesh construction\r\nconst dummyGeometry = new BufferGeometry();\r\nconst dummyMaterial = new MeshBasicMaterial();\r\n\r\n/**\r\n * WebGL Extensions helper (from Three.js internals)\r\n */\r\nfunction WebGLExtensions$1(gl) {\r\n const extensions = {};\r\n\r\n function getExtension(name) {\r\n if (extensions[name] !== undefined) {\r\n return extensions[name];\r\n }\r\n\r\n let extension;\r\n switch (name) {\r\n case 'WEBGL_depth_texture':\r\n extension = gl.getExtension('WEBGL_depth_texture') || gl.getExtension('MOZ_WEBGL_depth_texture') ||\r\n gl.getExtension('WEBKIT_WEBGL_depth_texture');\r\n break;\r\n case 'EXT_texture_filter_anisotropic':\r\n extension = gl.getExtension('EXT_texture_filter_anisotropic') ||\r\n gl.getExtension('MOZ_EXT_texture_filter_anisotropic') ||\r\n gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic');\r\n break;\r\n case 'WEBGL_compressed_texture_s3tc':\r\n extension = gl.getExtension('WEBGL_compressed_texture_s3tc') ||\r\n gl.getExtension('MOZ_WEBGL_compressed_texture_s3tc') ||\r\n gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc');\r\n break;\r\n case 'WEBGL_compressed_texture_pvrtc':\r\n extension = gl.getExtension('WEBGL_compressed_texture_pvrtc') ||\r\n gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc');\r\n break;\r\n default:\r\n extension = gl.getExtension(name);\r\n }\r\n\r\n extensions[name] = extension;\r\n return extension;\r\n }\r\n\r\n return {\r\n has: function(name) {\r\n return getExtension(name) !== null;\r\n },\r\n init: function(capabilities) {\r\n if (capabilities.isWebGL2) {\r\n getExtension('EXT_color_buffer_float');\r\n getExtension('WEBGL_clip_cull_distance');\r\n } else {\r\n getExtension('WEBGL_depth_texture');\r\n getExtension('OES_texture_float');\r\n getExtension('OES_texture_half_float');\r\n getExtension('OES_texture_half_float_linear');\r\n getExtension('OES_standard_derivatives');\r\n getExtension('OES_element_index_uint');\r\n getExtension('OES_vertex_array_object');\r\n getExtension('ANGLE_instanced_arrays');\r\n }\r\n getExtension('OES_texture_float_linear');\r\n getExtension('EXT_color_buffer_half_float');\r\n getExtension('WEBGL_multisampled_render_to_texture');\r\n },\r\n get: function(name) {\r\n const extension = getExtension(name);\r\n if (extension === null) {\r\n logger.warn('THREE.WebGLRenderer: ' + name + ' extension not supported.');\r\n }\r\n return extension;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * WebGL Capabilities helper (from Three.js internals)\r\n */\r\nfunction WebGLCapabilities$1(gl, extensions, parameters) {\r\n let maxAnisotropy;\r\n\r\n function getMaxAnisotropy() {\r\n if (maxAnisotropy !== undefined) return maxAnisotropy;\r\n if (extensions.has('EXT_texture_filter_anisotropic') === true) {\r\n const extension = extensions.get('EXT_texture_filter_anisotropic');\r\n maxAnisotropy = gl.getParameter(extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT);\r\n } else {\r\n maxAnisotropy = 0;\r\n }\r\n return maxAnisotropy;\r\n }\r\n\r\n function getMaxPrecision(precision) {\r\n if (precision === 'highp') {\r\n if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT).precision > 0 &&\r\n gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT).precision > 0) {\r\n return 'highp';\r\n }\r\n precision = 'mediump';\r\n }\r\n if (precision === 'mediump') {\r\n if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT).precision > 0 &&\r\n gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT).precision > 0) {\r\n return 'mediump';\r\n }\r\n }\r\n return 'lowp';\r\n }\r\n\r\n const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl.constructor.name === 'WebGL2RenderingContext';\r\n\r\n let precision = parameters.precision !== undefined ? parameters.precision : 'highp';\r\n const maxPrecision = getMaxPrecision(precision);\r\n\r\n if (maxPrecision !== precision) {\r\n logger.warn('THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.');\r\n precision = maxPrecision;\r\n }\r\n\r\n const drawBuffers = isWebGL2 || extensions.has('WEBGL_draw_buffers');\r\n const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;\r\n\r\n const maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);\r\n const maxVertexTextures = gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS);\r\n const maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);\r\n const maxCubemapSize = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE);\r\n\r\n const maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);\r\n const maxVertexUniforms = gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS);\r\n const maxVaryings = gl.getParameter(gl.MAX_VARYING_VECTORS);\r\n const maxFragmentUniforms = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);\r\n\r\n const vertexTextures = maxVertexTextures > 0;\r\n const floatFragmentTextures = isWebGL2 || extensions.has('OES_texture_float');\r\n const floatVertexTextures = vertexTextures && floatFragmentTextures;\r\n\r\n const maxSamples = isWebGL2 ? gl.getParameter(gl.MAX_SAMPLES) : 0;\r\n\r\n return {\r\n isWebGL2: isWebGL2,\r\n drawBuffers: drawBuffers,\r\n getMaxAnisotropy: getMaxAnisotropy,\r\n getMaxPrecision: getMaxPrecision,\r\n precision: precision,\r\n logarithmicDepthBuffer: logarithmicDepthBuffer,\r\n maxTextures: maxTextures,\r\n maxVertexTextures: maxVertexTextures,\r\n maxTextureSize: maxTextureSize,\r\n maxCubemapSize: maxCubemapSize,\r\n maxAttributes: maxAttributes,\r\n maxVertexUniforms: maxVertexUniforms,\r\n maxVaryings: maxVaryings,\r\n maxFragmentUniforms: maxFragmentUniforms,\r\n vertexTextures: vertexTextures,\r\n floatFragmentTextures: floatFragmentTextures,\r\n floatVertexTextures: floatVertexTextures,\r\n maxSamples: maxSamples\r\n };\r\n}\r\n\r\n/**\r\n * WebGL Utils helper (from Three.js internals)\r\n */\r\nfunction WebGLUtils$1(gl, extensions, capabilities) {\r\n const isWebGL2 = capabilities.isWebGL2;\r\n\r\n function convert(p, colorSpace) {\r\n let extension;\r\n\r\n if (p === UnsignedByteType) return gl.UNSIGNED_BYTE;\r\n if (p === 1017) return gl.UNSIGNED_SHORT_4_4_4_4;\r\n if (p === 1018) return gl.UNSIGNED_SHORT_5_5_5_1;\r\n if (p === 1010) return gl.BYTE;\r\n if (p === 1011) return gl.SHORT;\r\n if (p === 1012) return gl.UNSIGNED_SHORT;\r\n if (p === 1013) return gl.INT;\r\n if (p === 1014) return gl.UNSIGNED_INT;\r\n if (p === FloatType) return gl.FLOAT;\r\n\r\n if (p === HalfFloatType) {\r\n if (isWebGL2) return gl.HALF_FLOAT;\r\n extension = extensions.get('OES_texture_half_float');\r\n if (extension !== null) {\r\n return extension.HALF_FLOAT_OES;\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n if (p === 1021) return gl.ALPHA;\r\n if (p === 1022) return gl.RGB;\r\n if (p === RGBAFormat) return gl.RGBA;\r\n if (p === 1024) return gl.LUMINANCE;\r\n if (p === 1025) return gl.LUMINANCE_ALPHA;\r\n if (p === 1026) return gl.DEPTH_COMPONENT;\r\n if (p === 1027) return gl.DEPTH_STENCIL;\r\n\r\n // WebGL2 formats\r\n if (p === RedFormat) return gl.RED;\r\n if (p === RedIntegerFormat) return gl.RED_INTEGER;\r\n if (p === RGFormat) return gl.RG;\r\n if (p === RGIntegerFormat) return gl.RG_INTEGER;\r\n if (p === RGBIntegerFormat) return gl.RGB_INTEGER;\r\n if (p === RGBAIntegerFormat) return gl.RGBA_INTEGER;\r\n\r\n // S3TC\r\n if (p === 33776 || p === 33777 || p === 33778 || p === 33779) {\r\n extension = extensions.get('WEBGL_compressed_texture_s3tc');\r\n if (extension !== null) {\r\n if (p === 33776) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;\r\n if (p === 33777) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;\r\n if (p === 33778) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;\r\n if (p === 33779) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n // PVRTC\r\n if (p === 35840 || p === 35841 || p === 35842 || p === 35843) {\r\n extension = extensions.get('WEBGL_compressed_texture_pvrtc');\r\n if (extension !== null) {\r\n if (p === 35840) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;\r\n if (p === 35841) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;\r\n if (p === 35842) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;\r\n if (p === 35843) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n // ETC\r\n if (p === 36196) {\r\n extension = extensions.get('WEBGL_compressed_texture_etc1');\r\n if (extension !== null) {\r\n return extension.COMPRESSED_RGB_ETC1_WEBGL;\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n // ASTC\r\n if (p >= 37808 && p <= 37814 || p >= 37840 && p <= 37846) {\r\n extension = extensions.get('WEBGL_compressed_texture_astc');\r\n if (extension !== null) {\r\n return p;\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n // BPTC\r\n if (p === 36492 || p === 36494 || p === 36495) {\r\n extension = extensions.get('EXT_texture_compression_bptc');\r\n if (extension !== null) {\r\n return p;\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n if (p === 34042) return gl.UNSIGNED_INT_24_8;\r\n\r\n // Internal formats for float/half-float textures\r\n if (isWebGL2) {\r\n if (p === 6407) return gl.RGB;\r\n if (p === 6408) return gl.RGBA;\r\n }\r\n\r\n return (gl[p] !== undefined) ? gl[p] : null;\r\n }\r\n\r\n return {\r\n convert: convert\r\n };\r\n}\r\n\r\n// Constants for texture element counts\r\nconst COVARIANCES_ELEMENTS_PER_SPLAT = 6;\r\nconst CENTER_COLORS_ELEMENTS_PER_SPLAT = 4;\r\n\r\nconst COVARIANCES_ELEMENTS_PER_TEXEL_STORED = 4;\r\nconst COVARIANCES_ELEMENTS_PER_TEXEL_ALLOCATED = 4;\r\nconst COVARIANCES_ELEMENTS_PER_TEXEL_COMPRESSED_STORED = 6;\r\nconst COVARIANCES_ELEMENTS_PER_TEXEL_COMPRESSED_ALLOCATED = 8;\r\nconst SCALES_ROTATIONS_ELEMENTS_PER_TEXEL = 4;\r\nconst CENTER_COLORS_ELEMENTS_PER_TEXEL = 4;\r\nconst SCENE_INDEXES_ELEMENTS_PER_TEXEL = 1;\r\n\r\nconst SCENE_FADEIN_RATE_FAST = 0.012;\r\nconst SCENE_FADEIN_RATE_GRADUAL = 0.003;\r\n\r\nconst VISIBLE_REGION_EXPANSION_DELTA = 1;\r\n\r\nconst MAX_TEXTURE_TEXELS = 16777216;\r\n\r\nexport class SplatMesh extends Mesh {\r\n\r\n constructor(splatRenderMode = SplatRenderMode.ThreeD, dynamicMode = false, enableOptionalEffects = false,\r\n halfPrecisionCovariancesOnGPU = false, devicePixelRatio = 1, enableDistancesComputationOnGPU = true,\r\n integerBasedDistancesComputation = false, antialiased = false, maxScreenSpaceSplatSize = 1024, logLevel = LogLevel.None,\r\n sphericalHarmonicsDegree = 0, sceneFadeInRateMultiplier = 1.0, kernel2DSize = 0.3) {\r\n super(dummyGeometry, dummyMaterial);\r\n\r\n // Reference to a Three.js renderer\r\n this.renderer = undefined;\r\n\r\n // Determine how the splats are rendered\r\n this.splatRenderMode = splatRenderMode;\r\n\r\n // When 'dynamicMode' is true, scenes are assumed to be non-static. Dynamic scenes are handled differently\r\n // and certain optimizations cannot be made for them. Additionally, by default, all splat data retrieved from\r\n // this splat mesh will not have their scene transform applied to them if the splat mesh is dynamic. That\r\n // can be overriden via parameters to the individual functions that are used to retrieve splat data.\r\n this.dynamicMode = dynamicMode;\r\n\r\n // When true, allows for usage of extra properties and attributes during rendering for effects such as opacity adjustment.\r\n // Default is false for performance reasons. These properties are separate from transform properties (scale, rotation, position)\r\n // that are enabled by the 'dynamicScene' parameter.\r\n this.enableOptionalEffects = enableOptionalEffects;\r\n\r\n // Use 16-bit floating point values when storing splat covariance data in textures, instead of 32-bit\r\n this.halfPrecisionCovariancesOnGPU = halfPrecisionCovariancesOnGPU;\r\n\r\n // Ratio of the resolution in physical pixels to the resolution in CSS pixels for the current display device\r\n this.devicePixelRatio = devicePixelRatio;\r\n\r\n // Use a transform feedback to calculate splat distances from the camera\r\n this.enableDistancesComputationOnGPU = enableDistancesComputationOnGPU;\r\n\r\n // Use a faster integer-based approach for calculating splat distances from the camera\r\n this.integerBasedDistancesComputation = integerBasedDistancesComputation;\r\n\r\n // When true, will perform additional steps during rendering to address artifacts caused by the rendering of gaussians at a\r\n // substantially different resolution than that at which they were rendered during training. This will only work correctly\r\n // for models that were trained using a process that utilizes this compensation calculation. For more details:\r\n // https://github.com/nerfstudio-project/gsplat/pull/117\r\n // https://github.com/graphdeco-inria/gaussian-splatting/issues/294#issuecomment-1772688093\r\n this.antialiased = antialiased;\r\n\r\n // The size of the 2D kernel used for splat rendering\r\n // This will adjust the 2D kernel size after the projection\r\n this.kernel2DSize = kernel2DSize;\r\n\r\n // Specify the maximum clip space splat size, can help deal with large splats that get too unwieldy\r\n this.maxScreenSpaceSplatSize = maxScreenSpaceSplatSize;\r\n\r\n // The verbosity of console logging\r\n this.logLevel = logLevel;\r\n\r\n // Degree 0 means no spherical harmonics\r\n this.sphericalHarmonicsDegree = sphericalHarmonicsDegree;\r\n this.minSphericalHarmonicsDegree = 0;\r\n\r\n this.sceneFadeInRateMultiplier = sceneFadeInRateMultiplier;\r\n\r\n // The individual splat scenes stored in this splat mesh, each containing their own transform\r\n this.scenes = [];\r\n\r\n // Special octree tailored to SplatMesh instances\r\n this.splatTree = null;\r\n this.baseSplatTree = null;\r\n\r\n // Cache textures and the intermediate data used to populate them\r\n this.splatDataTextures = {};\r\n this.flameModel = null;\r\n this.expressionBSNum = 0;\r\n this.bsWeight = [];\r\n\r\n this.bonesMatrix = null;\r\n this.bonesNum = null;\r\n this.bonesWeight = null;\r\n this.gaussianSplatCount = null;\r\n\r\n this.morphTargetDictionary = null;\r\n this.distancesTransformFeedback = {\r\n 'id': null,\r\n 'vertexShader': null,\r\n 'fragmentShader': null,\r\n 'program': null,\r\n 'centersBuffer': null,\r\n 'sceneIndexesBuffer': null,\r\n 'outDistancesBuffer': null,\r\n 'centersLoc': -1,\r\n 'modelViewProjLoc': -1,\r\n 'sceneIndexesLoc': -1,\r\n 'transformsLocs': []\r\n };\r\n\r\n this.globalSplatIndexToLocalSplatIndexMap = [];\r\n this.globalSplatIndexToSceneIndexMap = [];\r\n\r\n // Optional iris occlusion configuration from avatar ZIP\r\n this.irisOcclusionConfig = null;\r\n\r\n this.lastBuildSplatCount = 0;\r\n this.lastBuildScenes = [];\r\n this.lastBuildMaxSplatCount = 0;\r\n this.lastBuildSceneCount = 0;\r\n this.firstRenderTime = -1;\r\n this.finalBuild = false;\r\n\r\n this.webGLUtils = null;\r\n\r\n this.boundingBox = new Box3();\r\n this.calculatedSceneCenter = new Vector3();\r\n this.maxSplatDistanceFromSceneCenter = 0;\r\n this.visibleRegionBufferRadius = 0;\r\n this.visibleRegionRadius = 0;\r\n this.visibleRegionFadeStartRadius = 0;\r\n this.visibleRegionChanging = false;\r\n\r\n this.splatScale = 1.0;\r\n this.pointCloudModeEnabled = false;\r\n\r\n this.disposed = false;\r\n this.lastRenderer = null;\r\n this.visible = false;\r\n }\r\n\r\n /**\r\n * Build a container for each scene managed by this splat mesh based on an instance of SplatBuffer, along with optional\r\n * transform data (position, scale, rotation) passed to the splat mesh during the build process.\r\n * @param {Array<THREE.Matrix4>} splatBuffers SplatBuffer instances containing splats for each scene\r\n * @param {Array<object>} sceneOptions Array of options objects: {\r\n *\r\n * position (Array<number>): Position of the scene, acts as an offset from its default position, defaults to [0, 0, 0]\r\n *\r\n * rotation (Array<number>): Rotation of the scene represented as a quaternion, defaults to [0, 0, 0, 1]\r\n *\r\n * scale (Array<number>): Scene's scale, defaults to [1, 1, 1]\r\n * }\r\n * @return {Array<THREE.Matrix4>}\r\n */\r\n static buildScenes(parentObject, splatBuffers, sceneOptions) {\r\n const scenes = [];\r\n scenes.length = splatBuffers.length;\r\n for (let i = 0; i < splatBuffers.length; i++) {\r\n const splatBuffer = splatBuffers[i];\r\n const options = sceneOptions[i] || {};\r\n let positionArray = options['position'] || [0, 0, 0];\r\n let rotationArray = options['rotation'] || [0, 0, 0, 1];\r\n let scaleArray = options['scale'] || [1, 1, 1];\r\n const position = new Vector3().fromArray(positionArray);\r\n const rotation = new Quaternion().fromArray(rotationArray);\r\n const scale = new Vector3().fromArray(scaleArray);\r\n const scene = SplatMesh.createScene(splatBuffer, position, rotation, scale,\r\n options.splatAlphaRemovalThreshold || 1, options.opacity, options.visible);\r\n parentObject.add(scene);\r\n scenes[i] = scene;\r\n }\r\n return scenes;\r\n }\r\n\r\n\r\n\r\n static createScene(splatBuffer, position, rotation, scale, minimumAlpha, opacity = 1.0, visible = true) {\r\n return new SplatScene(splatBuffer, position, rotation, scale, minimumAlpha, opacity, visible);\r\n }\r\n\r\n /**\r\n * Build data structures that map global splat indexes (based on a unified index across all splat buffers) to\r\n * local data within a single scene.\r\n * @param {Array<SplatBuffer>} splatBuffers Instances of SplatBuffer off which to build the maps\r\n * @return {object}\r\n */\r\n static buildSplatIndexMaps(splatBuffers) {\r\n const localSplatIndexMap = [];\r\n const sceneIndexMap = [];\r\n let totalSplatCount = 0;\r\n for (let s = 0; s < splatBuffers.length; s++) {\r\n const splatBuffer = splatBuffers[s];\r\n const maxSplatCount = splatBuffer.getMaxSplatCount();\r\n for (let i = 0; i < maxSplatCount; i++) {\r\n localSplatIndexMap[totalSplatCount] = i;\r\n sceneIndexMap[totalSplatCount] = s;\r\n totalSplatCount++;\r\n }\r\n }\r\n return {\r\n localSplatIndexMap,\r\n sceneIndexMap\r\n };\r\n }\r\n\r\n /**\r\n * Build an instance of SplatTree (a specialized octree) for the given splat mesh.\r\n * @param {Array<number>} minAlphas Array of minimum splat slphas for each scene\r\n * @param {function} onSplatTreeIndexesUpload Function to be called when the upload of splat centers to the splat tree\r\n * builder worker starts and finishes.\r\n * @param {function} onSplatTreeConstruction Function to be called when the conversion of the local splat tree from\r\n * the format produced by the splat tree builder worker starts and ends.\r\n * @return {SplatTree}\r\n */\r\n buildSplatTree = (minAlphas = [], onSplatTreeIndexesUpload, onSplatTreeConstruction) => {\r\n return new Promise((resolve) => {\r\n this.disposeSplatTree();\r\n // TODO: expose SplatTree constructor parameters (maximumDepth and maxCentersPerNode) so that they can\r\n // be configured on a per-scene basis\r\n this.baseSplatTree = new SplatTree(8, 1000);\r\n const buildStartTime = performance.now();\r\n const splatColor = new Vector4();\r\n this.baseSplatTree.processSplatMesh(this, (splatIndex) => {\r\n this.getSplatColor(splatIndex, splatColor);\r\n const sceneIndex = this.getSceneIndexForSplat(splatIndex);\r\n const minAlpha = minAlphas[sceneIndex] || 1;\r\n return splatColor.w >= minAlpha;\r\n }, onSplatTreeIndexesUpload, onSplatTreeConstruction)\r\n .then(() => {\r\n const buildTime = performance.now() - buildStartTime;\r\n if (this.logLevel >= LogLevel.Info) logger.info('SplatTree build: ' + buildTime + ' ms');\r\n if (this.disposed) {\r\n resolve();\r\n } else {\r\n\r\n this.splatTree = this.baseSplatTree;\r\n this.baseSplatTree = null;\r\n\r\n let leavesWithVertices = 0;\r\n let avgSplatCount = 0;\r\n let maxSplatCount = 0;\r\n let nodeCount = 0;\r\n\r\n this.splatTree.visitLeaves((node) => {\r\n const nodeSplatCount = node.data.indexes.length;\r\n if (nodeSplatCount > 0) {\r\n avgSplatCount += nodeSplatCount;\r\n maxSplatCount = Math.max(maxSplatCount, nodeSplatCount);\r\n nodeCount++;\r\n leavesWithVertices++;\r\n }\r\n });\r\n if (this.logLevel >= LogLevel.Info) {\r\n logger.info(`SplatTree leaves: ${this.splatTree.countLeaves()}`);\r\n logger.info(`SplatTree leaves with splats:${leavesWithVertices}`);\r\n avgSplatCount = avgSplatCount / nodeCount;\r\n logger.info(`Avg splat count per node: ${avgSplatCount}`);\r\n logger.info(`Total splat count: ${this.getSplatCount()}`);\r\n }\r\n resolve();\r\n }\r\n });\r\n });\r\n };\r\n\r\n /**\r\n * Construct this instance of SplatMesh.\r\n * @param {Array<SplatBuffer>} splatBuffers The base splat data, instances of SplatBuffer\r\n * @param {Array<object>} sceneOptions Dynamic options for each scene {\r\n *\r\n * splatAlphaRemovalThreshold: Ignore any splats with an alpha less than the specified\r\n * value (valid range: 0 - 255), defaults to 1\r\n *\r\n * position (Array<number>): Position of the scene, acts as an offset from its default position, defaults to [0, 0, 0]\r\n *\r\n * rotation (Array<number>): Rotation of the scene represented as a quaternion, defaults to [0, 0, 0, 1]\r\n *\r\n * scale (Array<number>): Scene's scale, defaults to [1, 1, 1]\r\n *\r\n * }\r\n * @param {boolean} keepSceneTransforms For a scene that already exists and is being overwritten, this flag\r\n * says to keep the transform from the existing scene.\r\n * @param {boolean} finalBuild Will the splat mesh be in its final state after this build?\r\n * @param {function} onSplatTreeIndexesUpload Function to be called when the upload of splat centers to the splat tree\r\n * builder worker starts and finishes.\r\n * @param {function} onSplatTreeConstruction Function to be called when the conversion of the local splat tree from\r\n * the format produced by the splat tree builder worker starts and ends.\r\n * @return {object} Object containing info about the splats that are updated\r\n */\r\n build(splatBuffers, sceneOptions, keepSceneTransforms = true, finalBuild = false,\r\n onSplatTreeIndexesUpload, onSplatTreeConstruction, preserveVisibleRegion = true) {\r\n\r\n this.sceneOptions = sceneOptions;\r\n this.finalBuild = finalBuild;\r\n\r\n const maxSplatCount = SplatMesh.getTotalMaxSplatCountForSplatBuffers(splatBuffers);\r\n\r\n const newScenes = SplatMesh.buildScenes(this, splatBuffers, sceneOptions);\r\n if (keepSceneTransforms) {\r\n for (let i = 0; i < this.scenes.length && i < newScenes.length; i++) {\r\n const newScene = newScenes[i];\r\n const existingScene = this.getScene(i);\r\n newScene.copyTransformData(existingScene);\r\n }\r\n }\r\n this.scenes = newScenes;\r\n\r\n let minSphericalHarmonicsDegree = 3;\r\n for (let splatBuffer of splatBuffers) {\r\n const splatBufferSphericalHarmonicsDegree = splatBuffer.getMinSphericalHarmonicsDegree();\r\n if (splatBufferSphericalHarmonicsDegree < minSphericalHarmonicsDegree) {\r\n minSphericalHarmonicsDegree = splatBufferSphericalHarmonicsDegree;\r\n }\r\n }\r\n this.minSphericalHarmonicsDegree = Math.min(minSphericalHarmonicsDegree, this.sphericalHarmonicsDegree);\r\n\r\n let splatBuffersChanged = false;\r\n if (splatBuffers.length !== this.lastBuildScenes.length) {\r\n splatBuffersChanged = true;\r\n } else {\r\n for (let i = 0; i < splatBuffers.length; i++) {\r\n const splatBuffer = splatBuffers[i];\r\n if (splatBuffer !== this.lastBuildScenes[i].splatBuffer) {\r\n splatBuffersChanged = true;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n let isUpdateBuild = true;\r\n if (this.scenes.length !== 1 ||\r\n this.lastBuildSceneCount !== this.scenes.length ||\r\n this.lastBuildMaxSplatCount !== maxSplatCount ||\r\n splatBuffersChanged) {\r\n isUpdateBuild = false;\r\n }\r\n\r\n if (!isUpdateBuild) {\r\n this.boundingBox = new Box3();\r\n if (!preserveVisibleRegion) {\r\n this.maxSplatDistanceFromSceneCenter = 0;\r\n this.visibleRegionBufferRadius = 0;\r\n this.visibleRegionRadius = 0;\r\n this.visibleRegionFadeStartRadius = 0;\r\n this.firstRenderTime = -1;\r\n }\r\n this.lastBuildScenes = [];\r\n this.lastBuildSplatCount = 0;\r\n this.lastBuildMaxSplatCount = 0;\r\n this.disposeMeshData();\r\n this.geometry = SplatGeometry.build(maxSplatCount);\r\n if (this.splatRenderMode === SplatRenderMode.ThreeD) {\r\n this.material = SplatMaterial3D.build(this.dynamicMode, this.enableOptionalEffects, this.antialiased,\r\n this.maxScreenSpaceSplatSize, this.splatScale, this.pointCloudModeEnabled,\r\n this.minSphericalHarmonicsDegree, this.kernel2DSize, this.irisOcclusionConfig);\r\n } else {\r\n this.material = SplatMaterial2D.build(this.dynamicMode, this.enableOptionalEffects,\r\n this.splatScale, this.pointCloudModeEnabled, this.minSphericalHarmonicsDegree);\r\n }\r\n\r\n const indexMaps = SplatMesh.buildSplatIndexMaps(splatBuffers);\r\n this.globalSplatIndexToLocalSplatIndexMap = indexMaps.localSplatIndexMap;\r\n this.globalSplatIndexToSceneIndexMap = indexMaps.sceneIndexMap;\r\n }\r\n\r\n const splatBufferSplatCount = this.getSplatCount(true);\r\n if (this.enableDistancesComputationOnGPU) this.setupDistancesComputationTransformFeedback();\r\n const dataUpdateResults = this.refreshGPUDataFromSplatBuffers(isUpdateBuild);\r\n\r\n for (let i = 0; i < this.scenes.length; i++) {\r\n this.lastBuildScenes[i] = this.scenes[i];\r\n }\r\n this.lastBuildSplatCount = splatBufferSplatCount;\r\n this.lastBuildMaxSplatCount = this.getMaxSplatCount();\r\n this.lastBuildSceneCount = this.scenes.length;\r\n\r\n // if (finalBuild && this.scenes.length > 0) {\r\n // this.buildSplatTree(sceneOptions.map(options => options.splatAlphaRemovalThreshold || 1),\r\n // onSplatTreeIndexesUpload, onSplatTreeConstruction)\r\n // .then(() => {\r\n // if (this.onSplatTreeReadyCallback) this.onSplatTreeReadyCallback(this.splatTree);\r\n // this.onSplatTreeReadyCallback = null;\r\n // });\r\n // }\r\n\r\n this.visible = (this.scenes.length > 0);\r\n\r\n return dataUpdateResults;\r\n }\r\n\r\n freeIntermediateSplatData() {\r\n\r\n const deleteTextureData = (texture) => {\r\n delete texture.source.data;\r\n delete texture.image;\r\n texture.onUpdate = null;\r\n };\r\n\r\n delete this.splatDataTextures.baseData.covariances;\r\n delete this.splatDataTextures.baseData.centers;\r\n delete this.splatDataTextures.baseData.colors;\r\n delete this.splatDataTextures.baseData.sphericalHarmonics;\r\n\r\n delete this.splatDataTextures.centerColors.data;\r\n delete this.splatDataTextures.covariances.data;\r\n if (this.splatDataTextures.sphericalHarmonics) {\r\n delete this.splatDataTextures.sphericalHarmonics.data;\r\n }\r\n if (this.splatDataTextures.sceneIndexes) {\r\n delete this.splatDataTextures.sceneIndexes.data;\r\n }\r\n\r\n this.splatDataTextures.centerColors.texture.needsUpdate = true;\r\n this.splatDataTextures.centerColors.texture.onUpdate = () => {\r\n deleteTextureData(this.splatDataTextures.centerColors.texture);\r\n };\r\n\r\n this.splatDataTextures.flameModelPosTexture.texture.needsUpdate = true;\r\n this.splatDataTextures.flameModelPosTexture.texture.onUpdate = () => {\r\n deleteTextureData(this.splatDataTextures.flameModelPosTexture.texture);\r\n };\r\n\r\n this.splatDataTextures.covariances.texture.needsUpdate = true;\r\n this.splatDataTextures.covariances.texture.onUpdate = () => {\r\n deleteTextureData(this.splatDataTextures.covariances.texture);\r\n };\r\n\r\n if (this.splatDataTextures.sphericalHarmonics) {\r\n if (this.splatDataTextures.sphericalHarmonics.texture) {\r\n this.splatDataTextures.sphericalHarmonics.texture.needsUpdate = true;\r\n this.splatDataTextures.sphericalHarmonics.texture.onUpdate = () => {\r\n deleteTextureData(this.splatDataTextures.sphericalHarmonics.texture);\r\n };\r\n } else {\r\n this.splatDataTextures.sphericalHarmonics.textures.forEach((texture) => {\r\n texture.needsUpdate = true;\r\n texture.onUpdate = () => {\r\n deleteTextureData(texture);\r\n };\r\n });\r\n }\r\n }\r\n if (this.splatDataTextures.sceneIndexes) {\r\n this.splatDataTextures.sceneIndexes.texture.needsUpdate = true;\r\n this.splatDataTextures.sceneIndexes.texture.onUpdate = () => {\r\n deleteTextureData(this.splatDataTextures.sceneIndexes.texture);\r\n };\r\n }\r\n }\r\n /**\r\n * Dispose all resources held by the splat mesh\r\n */\r\n dispose() {\r\n this.disposeMeshData();\r\n this.disposeTextures();\r\n this.disposeSplatTree();\r\n if (this.enableDistancesComputationOnGPU) {\r\n if (this.computeDistancesOnGPUSyncTimeout) {\r\n clearTimeout(this.computeDistancesOnGPUSyncTimeout);\r\n this.computeDistancesOnGPUSyncTimeout = null;\r\n }\r\n this.disposeDistancesComputationGPUResources();\r\n }\r\n this.scenes = [];\r\n this.distancesTransformFeedback = {\r\n 'id': null,\r\n 'vertexShader': null,\r\n 'fragmentShader': null,\r\n 'program': null,\r\n 'centersBuffer': null,\r\n 'sceneIndexesBuffer': null,\r\n 'outDistancesBuffer': null,\r\n 'centersLoc': -1,\r\n 'modelViewProjLoc': -1,\r\n 'sceneIndexesLoc': -1,\r\n 'transformsLocs': []\r\n };\r\n this.renderer = null;\r\n\r\n this.globalSplatIndexToLocalSplatIndexMap = [];\r\n this.globalSplatIndexToSceneIndexMap = [];\r\n\r\n this.lastBuildSplatCount = 0;\r\n this.lastBuildScenes = [];\r\n this.lastBuildMaxSplatCount = 0;\r\n this.lastBuildSceneCount = 0;\r\n this.firstRenderTime = -1;\r\n this.finalBuild = false;\r\n\r\n this.webGLUtils = null;\r\n\r\n this.boundingBox = new Box3();\r\n this.calculatedSceneCenter = new Vector3();\r\n this.maxSplatDistanceFromSceneCenter = 0;\r\n this.visibleRegionBufferRadius = 0;\r\n this.visibleRegionRadius = 0;\r\n this.visibleRegionFadeStartRadius = 0;\r\n this.visibleRegionChanging = false;\r\n\r\n this.splatScale = 1.0;\r\n this.pointCloudModeEnabled = false;\r\n\r\n this.disposed = true;\r\n this.lastRenderer = null;\r\n this.visible = false;\r\n }\r\n\r\n /**\r\n * Dispose of only the Three.js mesh resources (geometry, material, and texture)\r\n */\r\n disposeMeshData() {\r\n if (this.geometry && this.geometry !== dummyGeometry) {\r\n this.geometry.dispose();\r\n this.geometry = null;\r\n }\r\n if (this.material) {\r\n this.material.dispose();\r\n this.material = null;\r\n }\r\n }\r\n\r\n disposeTextures() {\r\n for (let textureKey in this.splatDataTextures) {\r\n if (Object.hasOwn(this.splatDataTextures, textureKey)) {\r\n const textureContainer = this.splatDataTextures[textureKey];\r\n if (textureContainer.texture) {\r\n textureContainer.texture.dispose();\r\n textureContainer.texture = null;\r\n }\r\n }\r\n }\r\n this.splatDataTextures = null;\r\n }\r\n\r\n disposeSplatTree() {\r\n if (this.splatTree) {\r\n this.splatTree.dispose();\r\n this.splatTree = null;\r\n }\r\n if (this.baseSplatTree) {\r\n this.baseSplatTree.dispose();\r\n this.baseSplatTree = null;\r\n }\r\n }\r\n\r\n getSplatTree() {\r\n return this.splatTree;\r\n }\r\n\r\n onSplatTreeReady(callback) {\r\n this.onSplatTreeReadyCallback = callback;\r\n }\r\n\r\n /**\r\n * Get copies of data that are necessary for splat distance computation: splat center positions and splat\r\n * scene indexes (necessary for applying dynamic scene transformations during distance computation)\r\n * @param {*} start The index at which to start copying data\r\n * @param {*} end The index at which to stop copying data\r\n * @return {object}\r\n */\r\n getDataForDistancesComputation(start, end) {\r\n const centers = this.integerBasedDistancesComputation ?\r\n this.getIntegerCenters(start, end, true) :\r\n this.getFloatCenters(start, end, true);\r\n const sceneIndexes = this.getSceneIndexes(start, end);\r\n return {\r\n centers,\r\n sceneIndexes\r\n };\r\n }\r\n\r\n /**\r\n * Refresh data textures and GPU buffers with splat data from the splat buffers belonging to this mesh.\r\n * @param {boolean} sinceLastBuildOnly Specify whether or not to only update for splats that have been added since the last build.\r\n * @return {object}\r\n */\r\n refreshGPUDataFromSplatBuffers(sinceLastBuildOnly) {\r\n const splatCount = this.getSplatCount(true);\r\n this.refreshDataTexturesFromSplatBuffers(sinceLastBuildOnly);\r\n const updateStart = sinceLastBuildOnly ? this.lastBuildSplatCount : 0;\r\n const { centers, sceneIndexes } = this.getDataForDistancesComputation(updateStart, splatCount - 1);\r\n if (this.enableDistancesComputationOnGPU) {\r\n this.refreshGPUBuffersForDistancesComputation(centers, sceneIndexes, sinceLastBuildOnly);\r\n }\r\n return {\r\n 'from': updateStart,\r\n 'to': splatCount - 1,\r\n 'count': splatCount - updateStart,\r\n 'centers': centers,\r\n 'sceneIndexes': sceneIndexes\r\n };\r\n }\r\n\r\n /**\r\n * Update the GPU buffers that are used for computing splat distances on the GPU.\r\n * @param {Array<number>} centers Splat center positions\r\n * @param {Array<number>} sceneIndexes Indexes of the scene to which each splat belongs\r\n * @param {boolean} sinceLastBuildOnly Specify whether or not to only update for splats that have been added since the last build.\r\n */\r\n refreshGPUBuffersForDistancesComputation(centers, sceneIndexes, sinceLastBuildOnly = false) {\r\n const offset = sinceLastBuildOnly ? this.lastBuildSplatCount : 0;\r\n this.updateGPUCentersBufferForDistancesComputation(sinceLastBuildOnly, centers, offset);\r\n this.updateGPUTransformIndexesBufferForDistancesComputation(sinceLastBuildOnly, sceneIndexes, offset);\r\n }\r\n\r\n /**\r\n * Refresh data textures with data from the splat buffers for this mesh.\r\n * @param {boolean} sinceLastBuildOnly Specify whether or not to only update for splats that have been added since the last build.\r\n */\r\n refreshDataTexturesFromSplatBuffers(sinceLastBuildOnly) {\r\n const splatCount = this.getSplatCount(true);\r\n const fromSplat = this.lastBuildSplatCount;\r\n const toSplat = splatCount - 1;\r\n\r\n if (!sinceLastBuildOnly) {\r\n this.setupDataTextures();\r\n this.updateBaseDataFromSplatBuffers();\r\n } else {\r\n this.updateBaseDataFromSplatBuffers(fromSplat, toSplat);\r\n }\r\n\r\n this.updateDataTexturesFromBaseData(fromSplat, toSplat);\r\n this.updateVisibleRegion(sinceLastBuildOnly);\r\n }\r\n\r\n setupDataTextures() {\r\n const maxSplatCount = this.getMaxSplatCount();\r\n const splatCount = this.getSplatCount(true);\r\n\r\n this.disposeTextures();\r\n\r\n const computeDataTextureSize = (elementsPerTexel, elementsPerSplat) => {\r\n const texSize = new Vector2(4096, 1024);\r\n while (texSize.x * texSize.y * elementsPerTexel < maxSplatCount * elementsPerSplat) texSize.y *= 2;\r\n return texSize;\r\n };\r\n\r\n const getCovariancesElementsPertexelStored = (compressionLevel) => {\r\n return compressionLevel >= 1 ? COVARIANCES_ELEMENTS_PER_TEXEL_COMPRESSED_STORED : COVARIANCES_ELEMENTS_PER_TEXEL_STORED;\r\n };\r\n\r\n const getCovariancesInitialTextureSpecs = (compressionLevel) => {\r\n const elementsPerTexelStored = getCovariancesElementsPertexelStored(compressionLevel);\r\n const texSize = computeDataTextureSize(elementsPerTexelStored, 6);\r\n return {elementsPerTexelStored, texSize};\r\n };\r\n\r\n let covarianceCompressionLevel = this.getTargetCovarianceCompressionLevel();\r\n const scaleRotationCompressionLevel = 0;\r\n const shCompressionLevel = this.getTargetSphericalHarmonicsCompressionLevel();\r\n\r\n let covariances;\r\n let scales;\r\n let rotations;\r\n if (this.splatRenderMode === SplatRenderMode.ThreeD) {\r\n const initialCovTexSpecs = getCovariancesInitialTextureSpecs(covarianceCompressionLevel);\r\n if (initialCovTexSpecs.texSize.x * initialCovTexSpecs.texSize.y > MAX_TEXTURE_TEXELS && covarianceCompressionLevel === 0) {\r\n covarianceCompressionLevel = 1;\r\n }\r\n covariances = new Float32Array(maxSplatCount * COVARIANCES_ELEMENTS_PER_SPLAT);\r\n } else {\r\n scales = new Float32Array(maxSplatCount * 3);\r\n rotations = new Float32Array(maxSplatCount * 4);\r\n }\r\n\r\n const centers = new Float32Array(maxSplatCount * 3);\r\n const colors = new Uint8Array(maxSplatCount * 4);\r\n\r\n let SphericalHarmonicsArrayType = Float32Array;\r\n if (shCompressionLevel === 1) SphericalHarmonicsArrayType = Uint16Array;\r\n else if (shCompressionLevel === 2) SphericalHarmonicsArrayType = Uint8Array;\r\n const shComponentCount = getSphericalHarmonicsComponentCountForDegree(this.minSphericalHarmonicsDegree);\r\n const shData = this.minSphericalHarmonicsDegree ? new SphericalHarmonicsArrayType(maxSplatCount * shComponentCount) : undefined;\r\n\r\n // set up centers/colors data texture\r\n const centersColsTexSize = computeDataTextureSize(CENTER_COLORS_ELEMENTS_PER_TEXEL, 4);\r\n const paddedCentersCols = new Uint32Array(centersColsTexSize.x * centersColsTexSize.y * CENTER_COLORS_ELEMENTS_PER_TEXEL);\r\n SplatMesh.updateCenterColorsPaddedData(0, splatCount - 1, centers, colors, paddedCentersCols);\r\n\r\n const centersColsTex = new DataTexture(paddedCentersCols, centersColsTexSize.x, centersColsTexSize.y,\r\n RGBAIntegerFormat, UnsignedIntType);\r\n centersColsTex.internalFormat = 'RGBA32UI';\r\n centersColsTex.needsUpdate = true;\r\n this.material.uniforms.centersColorsTexture.value = centersColsTex;\r\n this.material.uniforms.centersColorsTextureSize.value.copy(centersColsTexSize);\r\n this.material.uniformsNeedUpdate = true;\r\n\r\n this.splatDataTextures = {\r\n 'baseData': {\r\n 'covariances': covariances,\r\n 'scales': scales,\r\n 'rotations': rotations,\r\n 'centers': centers,\r\n 'colors': colors,\r\n 'sphericalHarmonics': shData\r\n },\r\n 'centerColors': {\r\n 'data': paddedCentersCols,\r\n 'texture': centersColsTex,\r\n 'size': centersColsTexSize\r\n }\r\n };\r\n\r\n if (this.splatRenderMode === SplatRenderMode.ThreeD) {\r\n // set up covariances data texture\r\n\r\n const covTexSpecs = getCovariancesInitialTextureSpecs(covarianceCompressionLevel);\r\n const covariancesElementsPerTexelStored = covTexSpecs.elementsPerTexelStored;\r\n const covTexSize = covTexSpecs.texSize;\r\n\r\n let CovariancesDataType = covarianceCompressionLevel >= 1 ? Uint32Array : Float32Array;\r\n const covariancesElementsPerTexelAllocated = covarianceCompressionLevel >= 1 ?\r\n COVARIANCES_ELEMENTS_PER_TEXEL_COMPRESSED_ALLOCATED :\r\n COVARIANCES_ELEMENTS_PER_TEXEL_ALLOCATED;\r\n const covariancesTextureData = new CovariancesDataType(covTexSize.x * covTexSize.y * covariancesElementsPerTexelAllocated);\r\n\r\n if (covarianceCompressionLevel === 0) {\r\n covariancesTextureData.set(covariances);\r\n } else {\r\n SplatMesh.updatePaddedCompressedCovariancesTextureData(covariances, covariancesTextureData, 0, 0, covariances.length);\r\n }\r\n\r\n let covTex;\r\n if (covarianceCompressionLevel >= 1) {\r\n covTex = new DataTexture(covariancesTextureData, covTexSize.x, covTexSize.y,\r\n RGBAIntegerFormat, UnsignedIntType);\r\n covTex.internalFormat = 'RGBA32UI';\r\n this.material.uniforms.covariancesTextureHalfFloat.value = covTex;\r\n } else {\r\n covTex = new DataTexture(covariancesTextureData, covTexSize.x, covTexSize.y, RGBAFormat, FloatType);\r\n this.material.uniforms.covariancesTexture.value = covTex;\r\n\r\n // For some reason a usampler2D needs to have a valid texture attached or WebGL complains\r\n const dummyTex = new DataTexture(new Uint32Array(32), 2, 2, RGBAIntegerFormat, UnsignedIntType);\r\n dummyTex.internalFormat = 'RGBA32UI';\r\n this.material.uniforms.covariancesTextureHalfFloat.value = dummyTex;\r\n dummyTex.needsUpdate = true;\r\n }\r\n covTex.needsUpdate = true;\r\n\r\n this.material.uniforms.covariancesAreHalfFloat.value = (covarianceCompressionLevel >= 1) ? 1 : 0;\r\n this.material.uniforms.covariancesTextureSize.value.copy(covTexSize);\r\n\r\n this.splatDataTextures['covariances'] = {\r\n 'data': covariancesTextureData,\r\n 'texture': covTex,\r\n 'size': covTexSize,\r\n 'compressionLevel': covarianceCompressionLevel,\r\n 'elementsPerTexelStored': covariancesElementsPerTexelStored,\r\n 'elementsPerTexelAllocated': covariancesElementsPerTexelAllocated\r\n };\r\n } else {\r\n // set up scale & rotations data texture\r\n const elementsPerSplat = 6;\r\n const scaleRotationsTexSize = computeDataTextureSize(SCALES_ROTATIONS_ELEMENTS_PER_TEXEL, elementsPerSplat);\r\n let ScaleRotationsDataType = scaleRotationCompressionLevel >= 1 ? Uint16Array : Float32Array;\r\n let scaleRotationsTextureType = scaleRotationCompressionLevel >= 1 ? HalfFloatType : FloatType;\r\n const paddedScaleRotations = new ScaleRotationsDataType(scaleRotationsTexSize.x * scaleRotationsTexSize.y *\r\n SCALES_ROTATIONS_ELEMENTS_PER_TEXEL);\r\n\r\n SplatMesh.updateScaleRotationsPaddedData(0, splatCount - 1, scales, rotations, paddedScaleRotations);\r\n\r\n const scaleRotationsTex = new DataTexture(paddedScaleRotations, scaleRotationsTexSize.x, scaleRotationsTexSize.y,\r\n RGBAFormat, scaleRotationsTextureType);\r\n scaleRotationsTex.needsUpdate = true;\r\n this.material.uniforms.scaleRotationsTexture.value = scaleRotationsTex;\r\n this.material.uniforms.scaleRotationsTextureSize.value.copy(scaleRotationsTexSize);\r\n\r\n this.splatDataTextures['scaleRotations'] = {\r\n 'data': paddedScaleRotations,\r\n 'texture': scaleRotationsTex,\r\n 'size': scaleRotationsTexSize,\r\n 'compressionLevel': scaleRotationCompressionLevel\r\n };\r\n }\r\n\r\n if (shData) {\r\n const shTextureType = shCompressionLevel === 2 ? UnsignedByteType : HalfFloatType;\r\n\r\n let paddedSHComponentCount = shComponentCount;\r\n if (paddedSHComponentCount % 2 !== 0) paddedSHComponentCount++;\r\n const shElementsPerTexel = this.minSphericalHarmonicsDegree === 2 ? 4 : 2;\r\n const texelFormat = shElementsPerTexel === 4 ? RGBAFormat : RGFormat;\r\n let shTexSize = computeDataTextureSize(shElementsPerTexel, paddedSHComponentCount);\r\n\r\n // Use one texture for all spherical harmonics data\r\n if (shTexSize.x * shTexSize.y <= MAX_TEXTURE_TEXELS) {\r\n const paddedSHArraySize = shTexSize.x * shTexSize.y * shElementsPerTexel;\r\n const paddedSHArray = new SphericalHarmonicsArrayType(paddedSHArraySize);\r\n for (let c = 0; c < splatCount; c++) {\r\n const srcBase = shComponentCount * c;\r\n const destBase = paddedSHComponentCount * c;\r\n for (let i = 0; i < shComponentCount; i++) {\r\n paddedSHArray[destBase + i] = shData[srcBase + i];\r\n }\r\n }\r\n\r\n const shTexture = new DataTexture(paddedSHArray, shTexSize.x, shTexSize.y, texelFormat, shTextureType);\r\n shTexture.needsUpdate = true;\r\n this.material.uniforms.sphericalHarmonicsTexture.value = shTexture;\r\n this.splatDataTextures['sphericalHarmonics'] = {\r\n 'componentCount': shComponentCount,\r\n 'paddedComponentCount': paddedSHComponentCount,\r\n 'data': paddedSHArray,\r\n 'textureCount': 1,\r\n 'texture': shTexture,\r\n 'size': shTexSize,\r\n 'compressionLevel': shCompressionLevel,\r\n 'elementsPerTexel': shElementsPerTexel\r\n };\r\n // Use three textures for spherical harmonics data, one per color channel\r\n } else {\r\n const shComponentCountPerChannel = shComponentCount / 3;\r\n paddedSHComponentCount = shComponentCountPerChannel;\r\n if (paddedSHComponentCount % 2 !== 0) paddedSHComponentCount++;\r\n shTexSize = computeDataTextureSize(shElementsPerTexel, paddedSHComponentCount);\r\n\r\n const paddedSHArraySize = shTexSize.x * shTexSize.y * shElementsPerTexel;\r\n const textureUniforms = [this.material.uniforms.sphericalHarmonicsTextureR,\r\n this.material.uniforms.sphericalHarmonicsTextureG,\r\n this.material.uniforms.sphericalHarmonicsTextureB];\r\n const paddedSHArrays = [];\r\n const shTextures = [];\r\n for (let t = 0; t < 3; t++) {\r\n const paddedSHArray = new SphericalHarmonicsArrayType(paddedSHArraySize);\r\n paddedSHArrays.push(paddedSHArray);\r\n for (let c = 0; c < splatCount; c++) {\r\n const srcBase = shComponentCount * c;\r\n const destBase = paddedSHComponentCount * c;\r\n if (shComponentCountPerChannel >= 3) {\r\n for (let i = 0; i < 3; i++) paddedSHArray[destBase + i] = shData[srcBase + t * 3 + i];\r\n if (shComponentCountPerChannel >= 8) {\r\n for (let i = 0; i < 5; i++) paddedSHArray[destBase + 3 + i] = shData[srcBase + 9 + t * 5 + i];\r\n }\r\n }\r\n }\r\n\r\n const shTexture = new DataTexture(paddedSHArray, shTexSize.x, shTexSize.y, texelFormat, shTextureType);\r\n shTextures.push(shTexture);\r\n shTexture.needsUpdate = true;\r\n textureUniforms[t].value = shTexture;\r\n }\r\n\r\n this.material.uniforms.sphericalHarmonicsMultiTextureMode.value = 1;\r\n this.splatDataTextures['sphericalHarmonics'] = {\r\n 'componentCount': shComponentCount,\r\n 'componentCountPerChannel': shComponentCountPerChannel,\r\n 'paddedComponentCount': paddedSHComponentCount,\r\n 'data': paddedSHArrays,\r\n 'textureCount': 3,\r\n 'textures': shTextures,\r\n 'size': shTexSize,\r\n 'compressionLevel': shCompressionLevel,\r\n 'elementsPerTexel': shElementsPerTexel\r\n };\r\n }\r\n\r\n this.material.uniforms.sphericalHarmonicsTextureSize.value.copy(shTexSize);\r\n this.material.uniforms.sphericalHarmonics8BitMode.value = shCompressionLevel === 2 ? 1 : 0;\r\n for (let s = 0; s < this.scenes.length; s++) {\r\n const splatBuffer = this.scenes[s].splatBuffer;\r\n this.material.uniforms.sphericalHarmonics8BitCompressionRangeMin.value[s] =\r\n splatBuffer.minSphericalHarmonicsCoeff;\r\n this.material.uniforms.sphericalHarmonics8BitCompressionRangeMax.value[s] =\r\n splatBuffer.maxSphericalHarmonicsCoeff;\r\n }\r\n this.material.uniformsNeedUpdate = true;\r\n }\r\n\r\n const sceneIndexesTexSize = computeDataTextureSize(SCENE_INDEXES_ELEMENTS_PER_TEXEL, 4);\r\n const paddedTransformIndexes = new Uint32Array(sceneIndexesTexSize.x *\r\n sceneIndexesTexSize.y * SCENE_INDEXES_ELEMENTS_PER_TEXEL);\r\n for (let c = 0; c < splatCount; c++) paddedTransformIndexes[c] = this.globalSplatIndexToSceneIndexMap[c];\r\n const sceneIndexesTexture = new DataTexture(paddedTransformIndexes, sceneIndexesTexSize.x, sceneIndexesTexSize.y,\r\n RedIntegerFormat, UnsignedIntType);\r\n sceneIndexesTexture.internalFormat = 'R32UI';\r\n sceneIndexesTexture.needsUpdate = true;\r\n this.material.uniforms.sceneIndexesTexture.value = sceneIndexesTexture;\r\n this.material.uniforms.sceneIndexesTextureSize.value.copy(sceneIndexesTexSize);\r\n this.material.uniformsNeedUpdate = true;\r\n this.splatDataTextures['sceneIndexes'] = {\r\n 'data': paddedTransformIndexes,\r\n 'texture': sceneIndexesTexture,\r\n 'size': sceneIndexesTexSize\r\n };\r\n this.material.uniforms.sceneCount.value = this.scenes.length;\r\n\r\n // FLAME-specific setup (only if flameModel has required data)\r\n if (this.flameModel && this.flameModel.geometry && this.flameModel.geometry.morphAttributes && this.flameModel.skeleton) {\r\n this.expressionBSNum = this.flameModel.geometry.morphAttributes.position.length;\r\n this.material.uniforms.bsCount.value = this.expressionBSNum;\r\n\r\n this.flameModel.skeleton.bones.forEach((bone, index) => {\r\n if (bone.name == 'head')\r\n this.material.uniforms.headBoneIndex.value = index;\r\n });\r\n\r\n this.buildModelTexture(this.flameModel);\r\n this.buildBoneMatrixTexture();\r\n this.buildBoneWeightTexture(this.flameModel);\r\n }\r\n }\r\n\r\n buildBoneMatrixTexture() {\r\n if (!this.bsWeight)\r\n return\r\n\r\n // Guard: Requires FLAME model with morphTargetDictionary\r\n if (!this.flameModel || !this.flameModel.morphTargetDictionary) {\r\n return;\r\n }\r\n\r\n //this.bonesNum + this.expressionBSNum / 4 = 30, so 32\r\n const boneTextureSize = new Vector2(4, 32);\r\n let boneMatrixTextureData = new Float32Array(this.bonesMatrix);\r\n let boneMatrixTextureDataInt = new Uint32Array(boneTextureSize.x * boneTextureSize.y * 4);\r\n this.morphTargetDictionary = this.flameModel.morphTargetDictionary;\r\n\r\n for (let c = 0; c < this.bonesNum * 16; c++) {\r\n boneMatrixTextureDataInt[c] = uintEncodedFloat(boneMatrixTextureData[c]);\r\n }\r\n if (this.flameModel && this.flameModel.skeleton) {\r\n this.material.uniforms.boneTexture0.value = this.flameModel.skeleton.boneTexture;\r\n this.material.uniforms.bindMatrix.value = this.flameModel.bindMatrix;\r\n this.material.uniforms.bindMatrixInverse.value = this.flameModel.bindMatrixInverse;\r\n }\r\n for (const key in this.bsWeight) {\r\n if (Object.hasOwn(this.bsWeight, key)) {\r\n const value = this.bsWeight[key];\r\n const idx = this.morphTargetDictionary[key];\r\n boneMatrixTextureDataInt[idx + this.bonesNum * 16] = uintEncodedFloat(value);\r\n }\r\n }\r\n\r\n // for (let c = 0; c < this.bsWeight.length; c++) {\r\n // this.morphTargetDictionary\r\n // boneMatrixTextureDataInt[c + this.bonesNum * 16] = uintEncodedFloat(this.bsWeight[c]);\r\n // }\r\n\r\n const boneMatrixTex = new DataTexture(boneMatrixTextureDataInt, boneTextureSize.x, boneTextureSize.y,\r\n RGBAIntegerFormat, UnsignedIntType);\r\n boneMatrixTex.internalFormat = 'RGBA32UI';\r\n boneMatrixTex.needsUpdate = true;\r\n this.material.uniforms.boneTexture.value = boneMatrixTex;\r\n this.material.uniforms.boneTextureSize.value.copy(boneTextureSize);\r\n\r\n this.material.uniformsNeedUpdate = true;\r\n\r\n this.splatDataTextures['boneMatrix'] = {\r\n 'data': boneMatrixTextureDataInt,\r\n 'texture': boneMatrixTex,\r\n 'size': boneTextureSize,\r\n };\r\n this.splatDataTextures.baseData['boneMatrix'] = boneMatrixTextureDataInt;\r\n }\r\n\r\n updateBoneMatrixTexture() {\r\n if (!this.bsWeight || !this.morphTargetDictionary)\r\n return\r\n\r\n for (const key in this.bsWeight) {\r\n if (Object.hasOwn(this.bsWeight, key)) {\r\n const value = this.bsWeight[key];\r\n const idx = this.morphTargetDictionary[key];\r\n this.splatDataTextures.baseData['boneMatrix'][idx + this.bonesNum * 16] = uintEncodedFloat(value);\r\n }\r\n }\r\n\r\n // for (let c = 0; c < this.bsWeight.length; c++) {\r\n // this.splatDataTextures.baseData['boneMatrix'][c + this.bonesNum * 16] = uintEncodedFloat(this.bsWeight[c]);\r\n // }\r\n this.splatDataTextures['boneMatrix']['texture'].data = this.splatDataTextures.baseData['boneMatrix'];\r\n \r\n this.splatDataTextures['boneMatrix']['texture'].needsUpdate = true;\r\n this.material.uniforms.boneTexture.value = this.splatDataTextures['boneMatrix']['texture'];\r\n\r\n if (this.flameModel.skeleton) {\r\n this.material.uniforms.boneTexture0.value = this.flameModel.skeleton.boneTexture;\r\n this.material.uniforms.bindMatrix.value = this.flameModel.bindMatrix;\r\n this.material.uniforms.bindMatrixInverse.value = this.flameModel.bindMatrixInverse;\r\n }\r\n \r\n this.material.uniformsNeedUpdate = true;\r\n }\r\n\r\n buildBoneWeightTexture(flameModel) {\r\n // Guard: bonesWeight is required for FLAME bone weight texture building\r\n if (!this.bonesWeight) {\r\n return;\r\n }\r\n\r\n let shapedMesh = flameModel.geometry.attributes.position.array;\r\n\r\n let pointNum = shapedMesh.length / 3;\r\n const boneWeightTextureSize = new Vector2(512, 512);\r\n let boneWeightTextureData = new Float32Array(boneWeightTextureSize.x * boneWeightTextureSize.y * 4);\r\n let boneWeightTextureDataInt = new Uint32Array(boneWeightTextureSize.x * boneWeightTextureSize.y * 4);\r\n for (let i = 0; i < pointNum; i++) {\r\n boneWeightTextureData[i * 8 + 0] = this.bonesWeight[i][0];\r\n boneWeightTextureData[i * 8 + 1] = this.bonesWeight[i][1];\r\n boneWeightTextureData[i * 8 + 2] = this.bonesWeight[i][2];\r\n boneWeightTextureData[i * 8 + 3] = this.bonesWeight[i][3];\r\n boneWeightTextureData[i * 8 + 4] = this.bonesWeight[i][4];\r\n\r\n boneWeightTextureDataInt[i * 8 + 0] = uintEncodedFloat(this.bonesWeight[i][0]);\r\n boneWeightTextureDataInt[i * 8 + 1] = uintEncodedFloat(this.bonesWeight[i][1]);\r\n boneWeightTextureDataInt[i * 8 + 2] = uintEncodedFloat(this.bonesWeight[i][2]);\r\n boneWeightTextureDataInt[i * 8 + 3] = uintEncodedFloat(this.bonesWeight[i][3]);\r\n boneWeightTextureDataInt[i * 8 + 4] = uintEncodedFloat(this.bonesWeight[i][4]);\r\n\r\n }\r\n const boneWeightTex = new DataTexture(boneWeightTextureDataInt, boneWeightTextureSize.x, boneWeightTextureSize.y,\r\n RGBAIntegerFormat, UnsignedIntType);\r\n \r\n boneWeightTex.internalFormat = 'RGBA32UI';\r\n boneWeightTex.needsUpdate = true;\r\n this.material.uniforms.boneWeightTexture.value = boneWeightTex;\r\n this.material.uniforms.boneWeightTextureSize.value.copy(boneWeightTextureSize);\r\n this.material.uniformsNeedUpdate = true;\r\n\r\n this.splatDataTextures['boneWeight'] = {\r\n 'data': boneWeightTextureDataInt,\r\n 'texture': boneWeightTex,\r\n 'size': boneWeightTextureSize,\r\n };\r\n this.splatDataTextures.baseData['boneWeight'] = boneWeightTextureDataInt;\r\n }\r\n\r\n\r\n buildModelTexture(flameModel) {\r\n // Guard: Requires FLAME model with morph attributes\r\n if (!flameModel || !flameModel.geometry || !flameModel.geometry.morphAttributes || !flameModel.morphTargetDictionary) {\r\n return;\r\n }\r\n\r\n const flameModelTexSize = new Vector2(4096, 2048);\r\n\r\n var shapedMesh = flameModel.geometry.attributes.position.array;\r\n var shapedMeshArray = [];//Array.from(shapedMesh);\r\n let pointNum = shapedMesh.length / 3;\r\n\r\n let bsLength = flameModel.geometry.morphAttributes.position.length;\r\n\r\n const morphTargetNames = Object.keys(flameModel.morphTargetDictionary);\r\n morphTargetNames.forEach((name, newIndex) => {\r\n const originalIndex = flameModel.morphTargetDictionary[name];\r\n var bsMesh = flameModel.geometry.morphAttributes.position[originalIndex];\r\n shapedMeshArray = shapedMeshArray.concat(Array.from(bsMesh.array));\r\n \r\n });\r\n shapedMeshArray = shapedMeshArray.concat(Array.from(shapedMesh));\r\n\r\n let flameModelData = new Float32Array(flameModelTexSize.x * flameModelTexSize.y * 4);\r\n let flameModelDataInt = new Uint32Array(flameModelTexSize.x * flameModelTexSize.y * 4);\r\n for (let c = 0; c < pointNum * (bsLength + 1); c++) {\r\n flameModelData[c * 4 + 0] = shapedMeshArray[c * 3 + 0];\r\n flameModelData[c * 4 + 1] = shapedMeshArray[c * 3 + 1];\r\n flameModelData[c * 4 + 2] = shapedMeshArray[c * 3 + 2];\r\n\r\n flameModelDataInt[c * 4 + 0] = uintEncodedFloat(flameModelData[c * 4 + 0]);\r\n flameModelDataInt[c * 4 + 1] = uintEncodedFloat(flameModelData[c * 4 + 1]);\r\n flameModelDataInt[c * 4 + 2] = uintEncodedFloat(flameModelData[c * 4 + 2]);\r\n }\r\n\r\n const flameModelTex = new DataTexture(flameModelDataInt, flameModelTexSize.x, flameModelTexSize.y,\r\n RGBAIntegerFormat, UnsignedIntType);\r\n flameModelTex.internalFormat = 'RGBA32UI';\r\n flameModelTex.needsUpdate = true;\r\n this.material.uniforms.flameModelTexture.value = flameModelTex;\r\n this.material.uniforms.flameModelTextureSize.value.copy(flameModelTexSize);\r\n this.material.uniformsNeedUpdate = true;\r\n this.material.uniforms.gaussianSplatCount.value = this.gaussianSplatCount;\r\n\r\n this.splatDataTextures['flameModel'] = {\r\n 'data': flameModelDataInt,\r\n 'texture': flameModelTex,\r\n 'size': flameModelTexSize,\r\n };\r\n this.splatDataTextures.baseData['flameModelPos'] = flameModelData;\r\n }\r\n\r\n updateTetureAfterBSAndSkeleton(fromSplat, toSplat) {\r\n const sceneTransform = new Matrix4();\r\n\r\n this.getSceneTransform(0, sceneTransform);\r\n this.getScene(0).splatBuffer.fillSplatCenterArray(this.morphedMesh, this.splatDataTextures.baseData.centers, sceneTransform, fromSplat, toSplat, 0);\r\n\r\n // Update center & color data texture\r\n const centerColorsTextureDescriptor = this.splatDataTextures['centerColors'];\r\n const paddedCenterColors = centerColorsTextureDescriptor.data;\r\n const centerColorsTexture = centerColorsTextureDescriptor.texture;\r\n SplatMesh.updateCenterColorsPaddedData(fromSplat, toSplat, this.splatDataTextures.baseData.centers,\r\n this.splatDataTextures.baseData.colors, paddedCenterColors);\r\n const centerColorsTextureProps = this.renderer ? this.renderer.properties.get(centerColorsTexture) : null;\r\n if (!centerColorsTextureProps || !centerColorsTextureProps.__webglTexture) {\r\n centerColorsTexture.needsUpdate = true;\r\n } else {\r\n this.updateDataTexture(paddedCenterColors, centerColorsTextureDescriptor.texture, centerColorsTextureDescriptor.size,\r\n centerColorsTextureProps, CENTER_COLORS_ELEMENTS_PER_TEXEL, CENTER_COLORS_ELEMENTS_PER_SPLAT, 4,\r\n fromSplat, toSplat);\r\n }\r\n\r\n this.updateBoneMatrixTexture();\r\n }\r\n\r\n updateBaseDataFromSplatBuffers(fromSplat, toSplat) {\r\n const covarancesTextureDesc = this.splatDataTextures['covariances'];\r\n const covarianceCompressionLevel = covarancesTextureDesc ? covarancesTextureDesc.compressionLevel : undefined;\r\n const scaleRotationsTextureDesc = this.splatDataTextures['scaleRotations'];\r\n const scaleRotationCompressionLevel = scaleRotationsTextureDesc ? scaleRotationsTextureDesc.compressionLevel : undefined;\r\n const shITextureDesc = this.splatDataTextures['sphericalHarmonics'];\r\n const shCompressionLevel = shITextureDesc ? shITextureDesc.compressionLevel : 0;\r\n\r\n this.fillSplatDataArrays(this.splatDataTextures.baseData.covariances, this.splatDataTextures.baseData.scales,\r\n this.splatDataTextures.baseData.rotations, this.splatDataTextures.baseData.centers,\r\n this.splatDataTextures.baseData.colors, this.splatDataTextures.baseData.sphericalHarmonics, \r\n this.splatDataTextures.baseData.flameModelPos,\r\n undefined,\r\n covarianceCompressionLevel, scaleRotationCompressionLevel, shCompressionLevel,\r\n fromSplat, toSplat, fromSplat);\r\n }\r\n\r\n updateDataTexturesFromBaseData(fromSplat, toSplat) {\r\n const covarancesTextureDesc = this.splatDataTextures['covariances'];\r\n const covarianceCompressionLevel = covarancesTextureDesc ? covarancesTextureDesc.compressionLevel : undefined;\r\n const scaleRotationsTextureDesc = this.splatDataTextures['scaleRotations'];\r\n const scaleRotationCompressionLevel = scaleRotationsTextureDesc ? scaleRotationsTextureDesc.compressionLevel : undefined;\r\n const shTextureDesc = this.splatDataTextures['sphericalHarmonics'];\r\n const shCompressionLevel = shTextureDesc ? shTextureDesc.compressionLevel : 0;\r\n\r\n // Update flame data texture\r\n const flameModelTextureDescriptor = this.splatDataTextures['flameModel'];\r\n const flameModelPos = flameModelTextureDescriptor.data;\r\n const flameModelPosTexture = flameModelTextureDescriptor.texture;\r\n\r\n const flameModelPosTextureProps = this.renderer ? this.renderer.properties.get(flameModelPosTexture) : null;\r\n if (!flameModelPosTextureProps || !flameModelPosTextureProps.__webglTexture) {\r\n flameModelPosTexture.needsUpdate = true;\r\n } else {\r\n this.updateDataTexture(flameModelPos, flameModelTextureDescriptor.texture, flameModelTextureDescriptor.size,\r\n flameModelPosTextureProps, CENTER_COLORS_ELEMENTS_PER_TEXEL, CENTER_COLORS_ELEMENTS_PER_SPLAT, 3,\r\n fromSplat, toSplat);\r\n }\r\n\r\n // Update center & color data texture\r\n const centerColorsTextureDescriptor = this.splatDataTextures['centerColors'];\r\n const paddedCenterColors = centerColorsTextureDescriptor.data;\r\n const centerColorsTexture = centerColorsTextureDescriptor.texture;\r\n SplatMesh.updateCenterColorsPaddedData(fromSplat, toSplat, this.splatDataTextures.baseData.centers,\r\n this.splatDataTextures.baseData.colors, paddedCenterColors);\r\n const centerColorsTextureProps = this.renderer ? this.renderer.properties.get(centerColorsTexture) : null;\r\n if (!centerColorsTextureProps || !centerColorsTextureProps.__webglTexture) {\r\n centerColorsTexture.needsUpdate = true;\r\n } else {\r\n this.updateDataTexture(paddedCenterColors, centerColorsTextureDescriptor.texture, centerColorsTextureDescriptor.size,\r\n centerColorsTextureProps, CENTER_COLORS_ELEMENTS_PER_TEXEL, CENTER_COLORS_ELEMENTS_PER_SPLAT, 4,\r\n fromSplat, toSplat);\r\n }\r\n\r\n // update covariance data texture\r\n if (covarancesTextureDesc) {\r\n const covariancesTexture = covarancesTextureDesc.texture;\r\n const covarancesStartElement = fromSplat * COVARIANCES_ELEMENTS_PER_SPLAT;\r\n const covariancesEndElement = toSplat * COVARIANCES_ELEMENTS_PER_SPLAT;\r\n\r\n if (covarianceCompressionLevel === 0) {\r\n for (let i = covarancesStartElement; i <= covariancesEndElement; i++) {\r\n const covariance = this.splatDataTextures.baseData.covariances[i];\r\n covarancesTextureDesc.data[i] = covariance;\r\n }\r\n } else {\r\n SplatMesh.updatePaddedCompressedCovariancesTextureData(this.splatDataTextures.baseData.covariances,\r\n covarancesTextureDesc.data,\r\n fromSplat * covarancesTextureDesc.elementsPerTexelAllocated,\r\n covarancesStartElement, covariancesEndElement);\r\n }\r\n\r\n const covariancesTextureProps = this.renderer ? this.renderer.properties.get(covariancesTexture) : null;\r\n if (!covariancesTextureProps || !covariancesTextureProps.__webglTexture) {\r\n covariancesTexture.needsUpdate = true;\r\n } else {\r\n if (covarianceCompressionLevel === 0) {\r\n this.updateDataTexture(covarancesTextureDesc.data, covarancesTextureDesc.texture, covarancesTextureDesc.size,\r\n covariancesTextureProps, covarancesTextureDesc.elementsPerTexelStored,\r\n COVARIANCES_ELEMENTS_PER_SPLAT, 4, fromSplat, toSplat);\r\n } else {\r\n this.updateDataTexture(covarancesTextureDesc.data, covarancesTextureDesc.texture, covarancesTextureDesc.size,\r\n covariancesTextureProps, covarancesTextureDesc.elementsPerTexelAllocated,\r\n covarancesTextureDesc.elementsPerTexelAllocated, 2, fromSplat, toSplat);\r\n }\r\n }\r\n }\r\n\r\n // update scale and rotation data texture\r\n if (scaleRotationsTextureDesc) {\r\n const paddedScaleRotations = scaleRotationsTextureDesc.data;\r\n const scaleRotationsTexture = scaleRotationsTextureDesc.texture;\r\n const elementsPerSplat = 6;\r\n const bytesPerElement = scaleRotationCompressionLevel === 0 ? 4 : 2;\r\n\r\n SplatMesh.updateScaleRotationsPaddedData(fromSplat, toSplat, this.splatDataTextures.baseData.scales,\r\n this.splatDataTextures.baseData.rotations, paddedScaleRotations);\r\n const scaleRotationsTextureProps = this.renderer ? this.renderer.properties.get(scaleRotationsTexture) : null;\r\n if (!scaleRotationsTextureProps || !scaleRotationsTextureProps.__webglTexture) {\r\n scaleRotationsTexture.needsUpdate = true;\r\n } else {\r\n this.updateDataTexture(paddedScaleRotations, scaleRotationsTextureDesc.texture, scaleRotationsTextureDesc.size,\r\n scaleRotationsTextureProps, SCALES_ROTATIONS_ELEMENTS_PER_TEXEL, elementsPerSplat, bytesPerElement,\r\n fromSplat, toSplat);\r\n }\r\n }\r\n\r\n // update spherical harmonics data texture\r\n const shData = this.splatDataTextures.baseData.sphericalHarmonics;\r\n if (shData) {\r\n let shBytesPerElement = 4;\r\n if (shCompressionLevel === 1) shBytesPerElement = 2;\r\n else if (shCompressionLevel === 2) shBytesPerElement = 1;\r\n\r\n const updateTexture = (shTexture, shTextureSize, elementsPerTexel, paddedSHArray, paddedSHComponentCount) => {\r\n const shTextureProps = this.renderer ? this.renderer.properties.get(shTexture) : null;\r\n if (!shTextureProps || !shTextureProps.__webglTexture) {\r\n shTexture.needsUpdate = true;\r\n } else {\r\n this.updateDataTexture(paddedSHArray, shTexture, shTextureSize, shTextureProps, elementsPerTexel,\r\n paddedSHComponentCount, shBytesPerElement, fromSplat, toSplat);\r\n }\r\n };\r\n\r\n const shComponentCount = shTextureDesc.componentCount;\r\n const paddedSHComponentCount = shTextureDesc.paddedComponentCount;\r\n\r\n // Update for the case of a single texture for all spherical harmonics data\r\n if (shTextureDesc.textureCount === 1) {\r\n const paddedSHArray = shTextureDesc.data;\r\n for (let c = fromSplat; c <= toSplat; c++) {\r\n const srcBase = shComponentCount * c;\r\n const destBase = paddedSHComponentCount * c;\r\n for (let i = 0; i < shComponentCount; i++) {\r\n paddedSHArray[destBase + i] = shData[srcBase + i];\r\n }\r\n }\r\n updateTexture(shTextureDesc.texture, shTextureDesc.size,\r\n shTextureDesc.elementsPerTexel, paddedSHArray, paddedSHComponentCount);\r\n // Update for the case of spherical harmonics data split among three textures, one for each color channel\r\n } else {\r\n const shComponentCountPerChannel = shTextureDesc.componentCountPerChannel;\r\n for (let t = 0; t < 3; t++) {\r\n const paddedSHArray = shTextureDesc.data[t];\r\n for (let c = fromSplat; c <= toSplat; c++) {\r\n const srcBase = shComponentCount * c;\r\n const destBase = paddedSHComponentCount * c;\r\n if (shComponentCountPerChannel >= 3) {\r\n for (let i = 0; i < 3; i++) paddedSHArray[destBase + i] = shData[srcBase + t * 3 + i];\r\n if (shComponentCountPerChannel >= 8) {\r\n for (let i = 0; i < 5; i++) paddedSHArray[destBase + 3 + i] = shData[srcBase + 9 + t * 5 + i];\r\n }\r\n }\r\n }\r\n updateTexture(shTextureDesc.textures[t], shTextureDesc.size,\r\n shTextureDesc.elementsPerTexel, paddedSHArray, paddedSHComponentCount);\r\n }\r\n }\r\n }\r\n\r\n // update scene index & transform data\r\n const sceneIndexesTexDesc = this.splatDataTextures['sceneIndexes'];\r\n const paddedSceneIndexes = sceneIndexesTexDesc.data;\r\n for (let c = this.lastBuildSplatCount; c <= toSplat; c++) {\r\n paddedSceneIndexes[c] = this.globalSplatIndexToSceneIndexMap[c];\r\n }\r\n const sceneIndexesTexture = sceneIndexesTexDesc.texture;\r\n const sceneIndexesTextureProps = this.renderer ? this.renderer.properties.get(sceneIndexesTexture) : null;\r\n if (!sceneIndexesTextureProps || !sceneIndexesTextureProps.__webglTexture) {\r\n sceneIndexesTexture.needsUpdate = true;\r\n } else {\r\n this.updateDataTexture(paddedSceneIndexes, sceneIndexesTexDesc.texture, sceneIndexesTexDesc.size,\r\n sceneIndexesTextureProps, 1, 1, 1, this.lastBuildSplatCount, toSplat);\r\n }\r\n }\r\n\r\n getTargetCovarianceCompressionLevel() {\r\n return this.halfPrecisionCovariancesOnGPU ? 1 : 0;\r\n }\r\n\r\n getTargetSphericalHarmonicsCompressionLevel() {\r\n return Math.max(1, this.getMaximumSplatBufferCompressionLevel());\r\n }\r\n\r\n getMaximumSplatBufferCompressionLevel() {\r\n let maxCompressionLevel;\r\n for (let i = 0; i < this.scenes.length; i++) {\r\n const scene = this.getScene(i);\r\n const splatBuffer = scene.splatBuffer;\r\n if (i === 0 || splatBuffer.compressionLevel > maxCompressionLevel) {\r\n maxCompressionLevel = splatBuffer.compressionLevel;\r\n }\r\n }\r\n return maxCompressionLevel;\r\n }\r\n\r\n getMinimumSplatBufferCompressionLevel() {\r\n let minCompressionLevel;\r\n for (let i = 0; i < this.scenes.length; i++) {\r\n const scene = this.getScene(i);\r\n const splatBuffer = scene.splatBuffer;\r\n if (i === 0 || splatBuffer.compressionLevel < minCompressionLevel) {\r\n minCompressionLevel = splatBuffer.compressionLevel;\r\n }\r\n }\r\n return minCompressionLevel;\r\n }\r\n\r\n static computeTextureUpdateRegion(startSplat, endSplat, textureWidth, elementsPerTexel, elementsPerSplat) {\r\n const texelsPerSplat = elementsPerSplat / elementsPerTexel;\r\n\r\n const startSplatTexels = startSplat * texelsPerSplat;\r\n const startRow = Math.floor(startSplatTexels / textureWidth);\r\n const startRowElement = startRow * textureWidth * elementsPerTexel;\r\n\r\n const endSplatTexels = endSplat * texelsPerSplat;\r\n const endRow = Math.floor(endSplatTexels / textureWidth);\r\n const endRowEndElement = endRow * textureWidth * elementsPerTexel + (textureWidth * elementsPerTexel);\r\n\r\n return {\r\n 'dataStart': startRowElement,\r\n 'dataEnd': endRowEndElement,\r\n 'startRow': startRow,\r\n 'endRow': endRow\r\n };\r\n }\r\n\r\n updateDataTexture(paddedData, texture, textureSize, textureProps, elementsPerTexel, elementsPerSplat, bytesPerElement, from, to) {\r\n const gl = this.renderer.getContext();\r\n const updateRegion = SplatMesh.computeTextureUpdateRegion(from, to, textureSize.x, elementsPerTexel, elementsPerSplat);\r\n const updateElementCount = updateRegion.dataEnd - updateRegion.dataStart;\r\n const updateDataView = new paddedData.constructor(paddedData.buffer,\r\n updateRegion.dataStart * bytesPerElement, updateElementCount);\r\n const updateHeight = updateRegion.endRow - updateRegion.startRow + 1;\r\n const glType = this.webGLUtils.convert(texture.type);\r\n const glFormat = this.webGLUtils.convert(texture.format, texture.colorSpace);\r\n const currentTexture = gl.getParameter(gl.TEXTURE_BINDING_2D);\r\n gl.bindTexture(gl.TEXTURE_2D, textureProps.__webglTexture);\r\n gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, updateRegion.startRow,\r\n textureSize.x, updateHeight, glFormat, glType, updateDataView);\r\n gl.bindTexture(gl.TEXTURE_2D, currentTexture);\r\n }\r\n\r\n static updatePaddedCompressedCovariancesTextureData(sourceData, textureData, textureDataStartIndex, fromElement, toElement) {\r\n let textureDataView = new DataView(textureData.buffer);\r\n let textureDataIndex = textureDataStartIndex;\r\n let sequentialCount = 0;\r\n for (let i = fromElement; i <= toElement; i+=2) {\r\n textureDataView.setUint16(textureDataIndex * 2, sourceData[i], true);\r\n textureDataView.setUint16(textureDataIndex * 2 + 2, sourceData[i + 1], true);\r\n textureDataIndex += 2;\r\n sequentialCount++;\r\n if (sequentialCount >= 3) {\r\n textureDataIndex += 2;\r\n sequentialCount = 0;\r\n }\r\n }\r\n }\r\n\r\n static updateCenterColorsPaddedData(from, to, centers, colors, paddedCenterColors) {\r\n for (let c = from; c <= to; c++) {\r\n const colorsBase = c * 4;\r\n const centersBase = c * 3;\r\n const centerColorsBase = c * 4;\r\n paddedCenterColors[centerColorsBase] = rgbaArrayToInteger(colors, colorsBase);\r\n paddedCenterColors[centerColorsBase + 1] = uintEncodedFloat(centers[centersBase]);\r\n paddedCenterColors[centerColorsBase + 2] = uintEncodedFloat(centers[centersBase + 1]);\r\n paddedCenterColors[centerColorsBase + 3] = uintEncodedFloat(centers[centersBase + 2]);\r\n }\r\n }\r\n\r\n static updateScaleRotationsPaddedData(from, to, scales, rotations, paddedScaleRotations) {\r\n const combinedSize = 6;\r\n for (let c = from; c <= to; c++) {\r\n const scaleBase = c * 3;\r\n const rotationBase = c * 4;\r\n const scaleRotationsBase = c * combinedSize;\r\n\r\n paddedScaleRotations[scaleRotationsBase] = scales[scaleBase];\r\n paddedScaleRotations[scaleRotationsBase + 1] = scales[scaleBase + 1];\r\n paddedScaleRotations[scaleRotationsBase + 2] = scales[scaleBase + 2];\r\n\r\n paddedScaleRotations[scaleRotationsBase + 3] = rotations[rotationBase];\r\n paddedScaleRotations[scaleRotationsBase + 4] = rotations[rotationBase + 1];\r\n paddedScaleRotations[scaleRotationsBase + 5] = rotations[rotationBase + 2];\r\n }\r\n }\r\n\r\n updateVisibleRegion(sinceLastBuildOnly) {\r\n const splatCount = this.getSplatCount(true);\r\n const tempCenter = new Vector3();\r\n if (!sinceLastBuildOnly) {\r\n const avgCenter = new Vector3();\r\n this.scenes.forEach((scene) => {\r\n avgCenter.add(scene.splatBuffer.sceneCenter);\r\n });\r\n avgCenter.multiplyScalar(1.0 / this.scenes.length);\r\n this.calculatedSceneCenter.copy(avgCenter);\r\n this.material.uniforms.sceneCenter.value.copy(this.calculatedSceneCenter);\r\n this.material.uniformsNeedUpdate = true;\r\n }\r\n\r\n const startSplatFormMaxDistanceCalc = sinceLastBuildOnly ? this.lastBuildSplatCount : 0;\r\n for (let i = startSplatFormMaxDistanceCalc; i < splatCount; i++) {\r\n this.getSplatCenter(this.morphedMesh, i, tempCenter, true);\r\n const distFromCSceneCenter = tempCenter.sub(this.calculatedSceneCenter).length();\r\n if (distFromCSceneCenter > this.maxSplatDistanceFromSceneCenter) this.maxSplatDistanceFromSceneCenter = distFromCSceneCenter;\r\n }\r\n\r\n if (this.maxSplatDistanceFromSceneCenter - this.visibleRegionBufferRadius > VISIBLE_REGION_EXPANSION_DELTA) {\r\n this.visibleRegionBufferRadius = this.maxSplatDistanceFromSceneCenter;\r\n this.visibleRegionRadius = Math.max(this.visibleRegionBufferRadius - VISIBLE_REGION_EXPANSION_DELTA, 0.0);\r\n }\r\n if (this.finalBuild) this.visibleRegionRadius = this.visibleRegionBufferRadius = this.maxSplatDistanceFromSceneCenter;\r\n this.updateVisibleRegionFadeDistance();\r\n }\r\n\r\n updateVisibleRegionFadeDistance(sceneRevealMode = SceneRevealMode.Default) {\r\n const fastFadeRate = SCENE_FADEIN_RATE_FAST * this.sceneFadeInRateMultiplier;\r\n const gradualFadeRate = SCENE_FADEIN_RATE_GRADUAL * this.sceneFadeInRateMultiplier;\r\n const defaultFadeInRate = this.finalBuild ? fastFadeRate : gradualFadeRate;\r\n const fadeInRate = sceneRevealMode === SceneRevealMode.Default ? defaultFadeInRate : gradualFadeRate;\r\n this.visibleRegionFadeStartRadius = (this.visibleRegionRadius - this.visibleRegionFadeStartRadius) *\r\n fadeInRate + this.visibleRegionFadeStartRadius;\r\n const fadeInPercentage = (this.visibleRegionBufferRadius > 0) ?\r\n (this.visibleRegionFadeStartRadius / this.visibleRegionBufferRadius) : 0;\r\n const fadeInComplete = fadeInPercentage > 0.99;\r\n const shaderFadeInComplete = (fadeInComplete || sceneRevealMode === SceneRevealMode.Instant) ? 1 : 0;\r\n\r\n this.material.uniforms.visibleRegionFadeStartRadius.value = this.visibleRegionFadeStartRadius;\r\n this.material.uniforms.visibleRegionRadius.value = this.visibleRegionRadius;\r\n this.material.uniforms.firstRenderTime.value = this.firstRenderTime;\r\n this.material.uniforms.currentTime.value = performance.now();\r\n this.material.uniforms.fadeInComplete.value = shaderFadeInComplete;\r\n this.material.uniformsNeedUpdate = true;\r\n this.visibleRegionChanging = !fadeInComplete;\r\n }\r\n\r\n /**\r\n * Set the indexes of splats that should be rendered; should be sorted in desired render order.\r\n * @param {Uint32Array} globalIndexes Sorted index list of splats to be rendered\r\n * @param {number} renderSplatCount Total number of splats to be rendered. Necessary because we may not want to render\r\n * every splat.\r\n */\r\n updateRenderIndexes(globalIndexes, renderSplatCount) {\r\n const geometry = this.geometry;\r\n geometry.attributes.splatIndex.set(globalIndexes);\r\n geometry.attributes.splatIndex.needsUpdate = true;\r\n if (renderSplatCount > 0 && this.firstRenderTime === -1) this.firstRenderTime = performance.now();\r\n geometry.instanceCount = renderSplatCount;\r\n geometry.setDrawRange(0, renderSplatCount);\r\n }\r\n\r\n /**\r\n * Update the transforms for each scene in this splat mesh from their individual components (position,\r\n * quaternion, and scale)\r\n */\r\n updateTransforms() {\r\n for (let i = 0; i < this.scenes.length; i++) {\r\n const scene = this.getScene(i);\r\n scene.updateTransform(this.dynamicMode);\r\n }\r\n }\r\n\r\n updateUniforms = function() {\r\n\r\n const viewport = new Vector2();\r\n\r\n return function(renderDimensions, cameraFocalLengthX, cameraFocalLengthY,\r\n orthographicMode, orthographicZoom, inverseFocalAdjustment) {\r\n const splatCount = this.getSplatCount();\r\n if (splatCount > 0) {\r\n viewport.set(renderDimensions.x * this.devicePixelRatio,\r\n renderDimensions.y * this.devicePixelRatio);\r\n this.material.uniforms.viewport.value.copy(viewport);\r\n this.material.uniforms.basisViewport.value.set(1.0 / viewport.x, 1.0 / viewport.y);\r\n this.material.uniforms.focal.value.set(cameraFocalLengthX, cameraFocalLengthY);\r\n this.material.uniforms.orthographicMode.value = orthographicMode ? 1 : 0;\r\n this.material.uniforms.orthoZoom.value = orthographicZoom;\r\n this.material.uniforms.inverseFocalAdjustment.value = inverseFocalAdjustment;\r\n if (this.dynamicMode) {\r\n for (let i = 0; i < this.scenes.length; i++) {\r\n this.material.uniforms.transforms.value[i].copy(this.getScene(i).transform);\r\n }\r\n }\r\n if (this.enableOptionalEffects) {\r\n for (let i = 0; i < this.scenes.length; i++) {\r\n this.material.uniforms.sceneOpacity.value[i] = clamp(this.getScene(i).opacity, 0.0, 1.0);\r\n this.material.uniforms.sceneVisibility.value[i] = this.getScene(i).visible ? 1 : 0;\r\n this.material.uniformsNeedUpdate = true;\r\n }\r\n }\r\n this.material.uniformsNeedUpdate = true;\r\n }\r\n };\r\n\r\n }();\r\n\r\n setSplatScale(splatScale = 1) {\r\n this.splatScale = splatScale;\r\n this.material.uniforms.splatScale.value = splatScale;\r\n this.material.uniformsNeedUpdate = true;\r\n }\r\n\r\n getSplatScale() {\r\n return this.splatScale;\r\n }\r\n\r\n setPointCloudModeEnabled(enabled) {\r\n this.pointCloudModeEnabled = enabled;\r\n this.material.uniforms.pointCloudModeEnabled.value = enabled ? 1 : 0;\r\n this.material.uniformsNeedUpdate = true;\r\n }\r\n\r\n getPointCloudModeEnabled() {\r\n return this.pointCloudModeEnabled;\r\n }\r\n\r\n getSplatDataTextures() {\r\n return this.splatDataTextures;\r\n }\r\n\r\n getSplatCount(includeSinceLastBuild = false) {\r\n if (!includeSinceLastBuild) return this.lastBuildSplatCount;\r\n else return SplatMesh.getTotalSplatCountForScenes(this.scenes);\r\n }\r\n\r\n static getTotalSplatCountForScenes(scenes) {\r\n let totalSplatCount = 0;\r\n for (let scene of scenes) {\r\n if (scene && scene.splatBuffer) totalSplatCount += scene.splatBuffer.getSplatCount();\r\n }\r\n return totalSplatCount;\r\n }\r\n\r\n static getTotalSplatCountForSplatBuffers(splatBuffers) {\r\n let totalSplatCount = 0;\r\n for (let splatBuffer of splatBuffers) totalSplatCount += splatBuffer.getSplatCount();\r\n return totalSplatCount;\r\n }\r\n\r\n getMaxSplatCount() {\r\n return SplatMesh.getTotalMaxSplatCountForScenes(this.scenes);\r\n }\r\n\r\n static getTotalMaxSplatCountForScenes(scenes) {\r\n let totalSplatCount = 0;\r\n for (let scene of scenes) {\r\n if (scene && scene.splatBuffer) totalSplatCount += scene.splatBuffer.getMaxSplatCount();\r\n }\r\n return totalSplatCount;\r\n }\r\n\r\n static getTotalMaxSplatCountForSplatBuffers(splatBuffers) {\r\n let totalSplatCount = 0;\r\n for (let splatBuffer of splatBuffers) totalSplatCount += splatBuffer.getMaxSplatCount();\r\n return totalSplatCount;\r\n }\r\n\r\n disposeDistancesComputationGPUResources() {\r\n\r\n if (!this.renderer) return;\r\n\r\n const gl = this.renderer.getContext();\r\n\r\n if (this.distancesTransformFeedback.vao) {\r\n gl.deleteVertexArray(this.distancesTransformFeedback.vao);\r\n this.distancesTransformFeedback.vao = null;\r\n }\r\n if (this.distancesTransformFeedback.program) {\r\n gl.deleteProgram(this.distancesTransformFeedback.program);\r\n gl.deleteShader(this.distancesTransformFeedback.vertexShader);\r\n gl.deleteShader(this.distancesTransformFeedback.fragmentShader);\r\n this.distancesTransformFeedback.program = null;\r\n this.distancesTransformFeedback.vertexShader = null;\r\n this.distancesTransformFeedback.fragmentShader = null;\r\n }\r\n this.disposeDistancesComputationGPUBufferResources();\r\n if (this.distancesTransformFeedback.id) {\r\n gl.deleteTransformFeedback(this.distancesTransformFeedback.id);\r\n this.distancesTransformFeedback.id = null;\r\n }\r\n }\r\n\r\n disposeDistancesComputationGPUBufferResources() {\r\n\r\n if (!this.renderer) return;\r\n\r\n const gl = this.renderer.getContext();\r\n\r\n if (this.distancesTransformFeedback.centersBuffer) {\r\n this.distancesTransformFeedback.centersBuffer = null;\r\n gl.deleteBuffer(this.distancesTransformFeedback.centersBuffer);\r\n }\r\n if (this.distancesTransformFeedback.outDistancesBuffer) {\r\n gl.deleteBuffer(this.distancesTransformFeedback.outDistancesBuffer);\r\n this.distancesTransformFeedback.outDistancesBuffer = null;\r\n }\r\n }\r\n\r\n /**\r\n * Set the Three.js renderer used by this splat mesh\r\n * @param {THREE.WebGLRenderer} renderer Instance of THREE.WebGLRenderer\r\n */\r\n setRenderer(renderer) {\r\n if (renderer !== this.renderer) {\r\n this.renderer = renderer;\r\n const gl = this.renderer.getContext();\r\n const extensions = new WebGLExtensions$1(gl);\r\n const capabilities = new WebGLCapabilities$1(gl, extensions, {});\r\n extensions.init(capabilities);\r\n this.webGLUtils = new WebGLUtils$1(gl, extensions, capabilities);\r\n if (this.enableDistancesComputationOnGPU && this.getSplatCount() > 0) {\r\n this.setupDistancesComputationTransformFeedback();\r\n const { centers, sceneIndexes } = this.getDataForDistancesComputation(0, this.getSplatCount() - 1);\r\n this.refreshGPUBuffersForDistancesComputation(centers, sceneIndexes);\r\n }\r\n }\r\n }\r\n\r\n setupDistancesComputationTransformFeedback = function() {\r\n\r\n let currentMaxSplatCount;\r\n\r\n return () => {\r\n const maxSplatCount = this.getMaxSplatCount();\r\n\r\n if (!this.renderer) return;\r\n\r\n const rebuildGPUObjects = (this.lastRenderer !== this.renderer);\r\n const rebuildBuffers = currentMaxSplatCount !== maxSplatCount;\r\n\r\n if (!rebuildGPUObjects && !rebuildBuffers) return;\r\n\r\n if (rebuildGPUObjects) {\r\n this.disposeDistancesComputationGPUResources();\r\n } else if (rebuildBuffers) {\r\n this.disposeDistancesComputationGPUBufferResources();\r\n }\r\n\r\n const gl = this.renderer.getContext();\r\n\r\n const createShader = (gl, type, source) => {\r\n const shader = gl.createShader(type);\r\n if (!shader) {\r\n logger.error('Fatal error: gl could not create a shader object.');\r\n return null;\r\n }\r\n\r\n gl.shaderSource(shader, source);\r\n gl.compileShader(shader);\r\n\r\n const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);\r\n if (!compiled) {\r\n let typeName = 'unknown';\r\n if (type === gl.VERTEX_SHADER) typeName = 'vertex shader';\r\n else if (type === gl.FRAGMENT_SHADER) typeName = 'fragement shader';\r\n const errors = gl.getShaderInfoLog(shader);\r\n logger.error('Failed to compile ' + typeName + ' with these errors:' + errors);\r\n gl.deleteShader(shader);\r\n return null;\r\n }\r\n\r\n return shader;\r\n };\r\n\r\n let vsSource;\r\n if (this.integerBasedDistancesComputation) {\r\n vsSource =\r\n `#version 300 es\r\n in ivec4 center;\r\n flat out int distance;`;\r\n if (this.dynamicMode) {\r\n vsSource += `\r\n in uint sceneIndex;\r\n uniform ivec4 transforms[${Constants.MaxScenes}];\r\n void main(void) {\r\n ivec4 transform = transforms[sceneIndex];\r\n distance = center.x * transform.x + center.y * transform.y + center.z * transform.z + transform.w * center.w;\r\n }\r\n `;\r\n } else {\r\n vsSource += `\r\n uniform ivec3 modelViewProj;\r\n void main(void) {\r\n distance = center.x * modelViewProj.x + center.y * modelViewProj.y + center.z * modelViewProj.z;\r\n }\r\n `;\r\n }\r\n } else {\r\n vsSource =\r\n `#version 300 es\r\n in vec4 center;\r\n flat out float distance;`;\r\n if (this.dynamicMode) {\r\n vsSource += `\r\n in uint sceneIndex;\r\n uniform mat4 transforms[${Constants.MaxScenes}];\r\n void main(void) {\r\n vec4 transformedCenter = transforms[sceneIndex] * vec4(center.xyz, 1.0);\r\n distance = transformedCenter.z;\r\n }\r\n `;\r\n } else {\r\n vsSource += `\r\n uniform vec3 modelViewProj;\r\n void main(void) {\r\n distance = center.x * modelViewProj.x + center.y * modelViewProj.y + center.z * modelViewProj.z;\r\n }\r\n `;\r\n }\r\n }\r\n\r\n const fsSource =\r\n `#version 300 es\r\n precision lowp float;\r\n out vec4 fragColor;\r\n void main(){}\r\n `;\r\n\r\n const currentVao = gl.getParameter(gl.VERTEX_ARRAY_BINDING);\r\n const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM);\r\n const currentProgramDeleted = currentProgram ? gl.getProgramParameter(currentProgram, gl.DELETE_STATUS) : false;\r\n\r\n if (rebuildGPUObjects) {\r\n this.distancesTransformFeedback.vao = gl.createVertexArray();\r\n }\r\n\r\n gl.bindVertexArray(this.distancesTransformFeedback.vao);\r\n\r\n if (rebuildGPUObjects) {\r\n const program = gl.createProgram();\r\n const vertexShader = createShader(gl, gl.VERTEX_SHADER, vsSource);\r\n const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fsSource);\r\n if (!vertexShader || !fragmentShader) {\r\n throw new Error('Could not compile shaders for distances computation on GPU.');\r\n }\r\n gl.attachShader(program, vertexShader);\r\n gl.attachShader(program, fragmentShader);\r\n gl.transformFeedbackVaryings(program, ['distance'], gl.SEPARATE_ATTRIBS);\r\n gl.linkProgram(program);\r\n\r\n const linked = gl.getProgramParameter(program, gl.LINK_STATUS);\r\n if (!linked) {\r\n const error = gl.getProgramInfoLog(program);\r\n logger.error('Fatal error: Failed to link program: ' + error);\r\n gl.deleteProgram(program);\r\n gl.deleteShader(fragmentShader);\r\n gl.deleteShader(vertexShader);\r\n throw new Error('Could not link shaders for distances computation on GPU.');\r\n }\r\n\r\n this.distancesTransformFeedback.program = program;\r\n this.distancesTransformFeedback.vertexShader = vertexShader;\r\n this.distancesTransformFeedback.vertexShader = fragmentShader;\r\n }\r\n\r\n gl.useProgram(this.distancesTransformFeedback.program);\r\n\r\n this.distancesTransformFeedback.centersLoc =\r\n gl.getAttribLocation(this.distancesTransformFeedback.program, 'center');\r\n if (this.dynamicMode) {\r\n this.distancesTransformFeedback.sceneIndexesLoc =\r\n gl.getAttribLocation(this.distancesTransformFeedback.program, 'sceneIndex');\r\n for (let i = 0; i < this.scenes.length; i++) {\r\n this.distancesTransformFeedback.transformsLocs[i] =\r\n gl.getUniformLocation(this.distancesTransformFeedback.program, `transforms[${i}]`);\r\n }\r\n } else {\r\n this.distancesTransformFeedback.modelViewProjLoc =\r\n gl.getUniformLocation(this.distancesTransformFeedback.program, 'modelViewProj');\r\n }\r\n\r\n if (rebuildGPUObjects || rebuildBuffers) {\r\n this.distancesTransformFeedback.centersBuffer = gl.createBuffer();\r\n gl.bindBuffer(gl.ARRAY_BUFFER, this.distancesTransformFeedback.centersBuffer);\r\n gl.enableVertexAttribArray(this.distancesTransformFeedback.centersLoc);\r\n if (this.integerBasedDistancesComputation) {\r\n gl.vertexAttribIPointer(this.distancesTransformFeedback.centersLoc, 4, gl.INT, 0, 0);\r\n } else {\r\n gl.vertexAttribPointer(this.distancesTransformFeedback.centersLoc, 4, gl.FLOAT, false, 0, 0);\r\n }\r\n\r\n if (this.dynamicMode) {\r\n this.distancesTransformFeedback.sceneIndexesBuffer = gl.createBuffer();\r\n gl.bindBuffer(gl.ARRAY_BUFFER, this.distancesTransformFeedback.sceneIndexesBuffer);\r\n gl.enableVertexAttribArray(this.distancesTransformFeedback.sceneIndexesLoc);\r\n gl.vertexAttribIPointer(this.distancesTransformFeedback.sceneIndexesLoc, 1, gl.UNSIGNED_INT, 0, 0);\r\n }\r\n }\r\n\r\n if (rebuildGPUObjects || rebuildBuffers) {\r\n this.distancesTransformFeedback.outDistancesBuffer = gl.createBuffer();\r\n }\r\n gl.bindBuffer(gl.ARRAY_BUFFER, this.distancesTransformFeedback.outDistancesBuffer);\r\n gl.bufferData(gl.ARRAY_BUFFER, maxSplatCount * 4, gl.STATIC_READ);\r\n\r\n if (rebuildGPUObjects) {\r\n this.distancesTransformFeedback.id = gl.createTransformFeedback();\r\n }\r\n gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, this.distancesTransformFeedback.id);\r\n gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, this.distancesTransformFeedback.outDistancesBuffer);\r\n\r\n if (currentProgram && currentProgramDeleted !== true) gl.useProgram(currentProgram);\r\n if (currentVao) gl.bindVertexArray(currentVao);\r\n\r\n this.lastRenderer = this.renderer;\r\n currentMaxSplatCount = maxSplatCount;\r\n };\r\n\r\n }();\r\n\r\n /**\r\n * Refresh GPU buffers used for computing splat distances with centers data from the scenes for this mesh.\r\n * @param {boolean} isUpdate Specify whether or not to update the GPU buffer or to initialize & fill\r\n * @param {Array<number>} centers The splat centers data\r\n * @param {number} offsetSplats Offset in the GPU buffer at which to start updating data, specified in splats\r\n */\r\n updateGPUCentersBufferForDistancesComputation(isUpdate, centers, offsetSplats) {\r\n\r\n if (!this.renderer) return;\r\n\r\n const gl = this.renderer.getContext();\r\n\r\n const currentVao = gl.getParameter(gl.VERTEX_ARRAY_BINDING);\r\n gl.bindVertexArray(this.distancesTransformFeedback.vao);\r\n\r\n const ArrayType = this.integerBasedDistancesComputation ? Uint32Array : Float32Array;\r\n const attributeBytesPerCenter = 16;\r\n const subBufferOffset = offsetSplats * attributeBytesPerCenter;\r\n\r\n gl.bindBuffer(gl.ARRAY_BUFFER, this.distancesTransformFeedback.centersBuffer);\r\n\r\n if (isUpdate) {\r\n gl.bufferSubData(gl.ARRAY_BUFFER, subBufferOffset, centers);\r\n } else {\r\n const maxArray = new ArrayType(this.getMaxSplatCount() * attributeBytesPerCenter);\r\n maxArray.set(centers);\r\n gl.bufferData(gl.ARRAY_BUFFER, maxArray, gl.STATIC_DRAW);\r\n }\r\n\r\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\r\n\r\n if (currentVao) gl.bindVertexArray(currentVao);\r\n }\r\n\r\n /**\r\n * Refresh GPU buffers used for pre-computing splat distances with centers data from the scenes for this mesh.\r\n * @param {boolean} isUpdate Specify whether or not to update the GPU buffer or to initialize & fill\r\n * @param {Array<number>} sceneIndexes The splat scene indexes\r\n * @param {number} offsetSplats Offset in the GPU buffer at which to start updating data, specified in splats\r\n */\r\n updateGPUTransformIndexesBufferForDistancesComputation(isUpdate, sceneIndexes, offsetSplats) {\r\n\r\n if (!this.renderer || !this.dynamicMode) return;\r\n\r\n const gl = this.renderer.getContext();\r\n\r\n const currentVao = gl.getParameter(gl.VERTEX_ARRAY_BINDING);\r\n gl.bindVertexArray(this.distancesTransformFeedback.vao);\r\n\r\n const subBufferOffset = offsetSplats * 4;\r\n\r\n gl.bindBuffer(gl.ARRAY_BUFFER, this.distancesTransformFeedback.sceneIndexesBuffer);\r\n\r\n if (isUpdate) {\r\n gl.bufferSubData(gl.ARRAY_BUFFER, subBufferOffset, sceneIndexes);\r\n } else {\r\n const maxArray = new Uint32Array(this.getMaxSplatCount() * 4);\r\n maxArray.set(sceneIndexes);\r\n gl.bufferData(gl.ARRAY_BUFFER, maxArray, gl.STATIC_DRAW);\r\n }\r\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\r\n\r\n if (currentVao) gl.bindVertexArray(currentVao);\r\n }\r\n\r\n /**\r\n * Get a typed array containing a mapping from global splat indexes to their scene index.\r\n * @param {number} start Starting splat index to store\r\n * @param {number} end Ending splat index to store\r\n * @return {Uint32Array}\r\n */\r\n getSceneIndexes(start, end) {\r\n\r\n let sceneIndexes;\r\n const fillCount = end - start + 1;\r\n sceneIndexes = new Uint32Array(fillCount);\r\n for (let i = start; i <= end; i++) {\r\n sceneIndexes[i] = this.globalSplatIndexToSceneIndexMap[i];\r\n }\r\n\r\n return sceneIndexes;\r\n }\r\n\r\n /**\r\n * Fill 'array' with the transforms for each scene in this splat mesh.\r\n * @param {Array} array Empty array to be filled with scene transforms. If not empty, contents will be overwritten.\r\n */\r\n fillTransformsArray = function() {\r\n\r\n const tempArray = [];\r\n\r\n return function(array) {\r\n if (tempArray.length !== array.length) tempArray.length = array.length;\r\n for (let i = 0; i < this.scenes.length; i++) {\r\n const sceneTransform = this.getScene(i).transform;\r\n const sceneTransformElements = sceneTransform.elements;\r\n for (let j = 0; j < 16; j++) {\r\n tempArray[i * 16 + j] = sceneTransformElements[j];\r\n }\r\n }\r\n array.set(tempArray);\r\n };\r\n\r\n }();\r\n\r\n computeDistancesOnGPU = function() {\r\n\r\n const tempMatrix = new Matrix4();\r\n\r\n return (modelViewProjMatrix, outComputedDistances) => {\r\n if (!this.renderer) return;\r\n\r\n const gl = this.renderer.getContext();\r\n\r\n const currentVao = gl.getParameter(gl.VERTEX_ARRAY_BINDING);\r\n const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM);\r\n const currentProgramDeleted = currentProgram ? gl.getProgramParameter(currentProgram, gl.DELETE_STATUS) : false;\r\n\r\n gl.bindVertexArray(this.distancesTransformFeedback.vao);\r\n gl.useProgram(this.distancesTransformFeedback.program);\r\n\r\n gl.enable(gl.RASTERIZER_DISCARD);\r\n\r\n if (this.dynamicMode) {\r\n for (let i = 0; i < this.scenes.length; i++) {\r\n tempMatrix.copy(this.getScene(i).transform);\r\n tempMatrix.premultiply(modelViewProjMatrix);\r\n\r\n if (this.integerBasedDistancesComputation) {\r\n const iTempMatrix = SplatMesh.getIntegerMatrixArray(tempMatrix);\r\n const iTransform = [iTempMatrix[2], iTempMatrix[6], iTempMatrix[10], iTempMatrix[14]];\r\n gl.uniform4i(this.distancesTransformFeedback.transformsLocs[i], iTransform[0], iTransform[1],\r\n iTransform[2], iTransform[3]);\r\n } else {\r\n gl.uniformMatrix4fv(this.distancesTransformFeedback.transformsLocs[i], false, tempMatrix.elements);\r\n }\r\n }\r\n } else {\r\n if (this.integerBasedDistancesComputation) {\r\n const iViewProjMatrix = SplatMesh.getIntegerMatrixArray(modelViewProjMatrix);\r\n const iViewProj = [iViewProjMatrix[2], iViewProjMatrix[6], iViewProjMatrix[10]];\r\n gl.uniform3i(this.distancesTransformFeedback.modelViewProjLoc, iViewProj[0], iViewProj[1], iViewProj[2]);\r\n } else {\r\n const viewProj = [modelViewProjMatrix.elements[2], modelViewProjMatrix.elements[6], modelViewProjMatrix.elements[10]];\r\n gl.uniform3f(this.distancesTransformFeedback.modelViewProjLoc, viewProj[0], viewProj[1], viewProj[2]);\r\n }\r\n }\r\n\r\n gl.bindBuffer(gl.ARRAY_BUFFER, this.distancesTransformFeedback.centersBuffer);\r\n gl.enableVertexAttribArray(this.distancesTransformFeedback.centersLoc);\r\n if (this.integerBasedDistancesComputation) {\r\n gl.vertexAttribIPointer(this.distancesTransformFeedback.centersLoc, 4, gl.INT, 0, 0);\r\n } else {\r\n gl.vertexAttribPointer(this.distancesTransformFeedback.centersLoc, 4, gl.FLOAT, false, 0, 0);\r\n }\r\n\r\n if (this.dynamicMode) {\r\n gl.bindBuffer(gl.ARRAY_BUFFER, this.distancesTransformFeedback.sceneIndexesBuffer);\r\n gl.enableVertexAttribArray(this.distancesTransformFeedback.sceneIndexesLoc);\r\n gl.vertexAttribIPointer(this.distancesTransformFeedback.sceneIndexesLoc, 1, gl.UNSIGNED_INT, 0, 0);\r\n }\r\n\r\n gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, this.distancesTransformFeedback.id);\r\n gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, this.distancesTransformFeedback.outDistancesBuffer);\r\n\r\n gl.beginTransformFeedback(gl.POINTS);\r\n gl.drawArrays(gl.POINTS, 0, this.getSplatCount());\r\n gl.endTransformFeedback();\r\n\r\n gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);\r\n gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);\r\n\r\n gl.disable(gl.RASTERIZER_DISCARD);\r\n\r\n const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);\r\n gl.flush();\r\n\r\n const promise = new Promise((resolve) => {\r\n const checkSync = () => {\r\n if (this.disposed) {\r\n resolve();\r\n } else {\r\n const timeout = 0;\r\n const bitflags = 0;\r\n const status = gl.clientWaitSync(sync, bitflags, timeout);\r\n switch (status) {\r\n case gl.TIMEOUT_EXPIRED:\r\n this.computeDistancesOnGPUSyncTimeout = setTimeout(checkSync);\r\n return this.computeDistancesOnGPUSyncTimeout;\r\n case gl.WAIT_FAILED:\r\n throw new Error('should never get here');\r\n default: {\r\n this.computeDistancesOnGPUSyncTimeout = null;\r\n gl.deleteSync(sync);\r\n const currentVao = gl.getParameter(gl.VERTEX_ARRAY_BINDING);\r\n gl.bindVertexArray(this.distancesTransformFeedback.vao);\r\n gl.bindBuffer(gl.ARRAY_BUFFER, this.distancesTransformFeedback.outDistancesBuffer);\r\n gl.getBufferSubData(gl.ARRAY_BUFFER, 0, outComputedDistances);\r\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\r\n\r\n if (currentVao) gl.bindVertexArray(currentVao);\r\n\r\n resolve();\r\n }\r\n }\r\n }\r\n };\r\n this.computeDistancesOnGPUSyncTimeout = setTimeout(checkSync);\r\n });\r\n\r\n if (currentProgram && currentProgramDeleted !== true) gl.useProgram(currentProgram);\r\n if (currentVao) gl.bindVertexArray(currentVao);\r\n\r\n return promise;\r\n };\r\n\r\n }();\r\n\r\n /**\r\n * Given a global splat index, return corresponding local data (splat buffer, index of splat in that splat\r\n * buffer, and the corresponding transform)\r\n * @param {number} globalIndex Global splat index\r\n * @param {object} paramsObj Object in which to store local data\r\n * @param {boolean} returnSceneTransform By default, the transform of the scene to which the splat at 'globalIndex' belongs will be\r\n * returned via the 'sceneTransform' property of 'paramsObj' only if the splat mesh is static.\r\n * If 'returnSceneTransform' is true, the 'sceneTransform' property will always contain the scene\r\n * transform, and if 'returnSceneTransform' is false, the 'sceneTransform' property will always\r\n * be null.\r\n */\r\n getLocalSplatParameters(globalIndex, paramsObj, returnSceneTransform) {\r\n if (returnSceneTransform === undefined || returnSceneTransform === null) {\r\n returnSceneTransform = this.dynamicMode ? false : true;\r\n }\r\n paramsObj.splatBuffer = this.getSplatBufferForSplat(globalIndex);\r\n paramsObj.localIndex = this.getSplatLocalIndex(globalIndex);\r\n paramsObj.sceneTransform = returnSceneTransform ? this.getSceneTransformForSplat(globalIndex) : null;\r\n }\r\n\r\n /**\r\n * Fill arrays with splat data and apply transforms if appropriate. Each array is optional.\r\n * @param {Float32Array} covariances Target storage for splat covariances\r\n * @param {Float32Array} scales Target storage for splat scales\r\n * @param {Float32Array} rotations Target storage for splat rotations\r\n * @param {Float32Array} centers Target storage for splat centers\r\n * @param {Uint8Array} colors Target storage for splat colors\r\n * @param {Float32Array} sphericalHarmonics Target storage for spherical harmonics\r\n * @param {boolean} applySceneTransform By default, scene transforms are applied to relevant splat data only if the splat mesh is\r\n * static. If 'applySceneTransform' is true, scene transforms will always be applied and if\r\n * it is false, they will never be applied. If undefined, the default behavior will apply.\r\n * @param {number} covarianceCompressionLevel The compression level for covariances in the destination array\r\n * @param {number} sphericalHarmonicsCompressionLevel The compression level for spherical harmonics in the destination array\r\n * @param {number} srcStart The start location from which to pull source data\r\n * @param {number} srcEnd The end location from which to pull source data\r\n * @param {number} destStart The start location from which to write data\r\n */\r\n fillSplatDataArrays(covariances, scales, rotations, centers, colors, sphericalHarmonics, flameModelPos,\r\n applySceneTransform,\r\n covarianceCompressionLevel = 0, scaleRotationCompressionLevel = 0, sphericalHarmonicsCompressionLevel = 1,\r\n srcStart, srcEnd, destStart = 0, sceneIndex) {\r\n const scaleOverride = new Vector3();\r\n scaleOverride.x = undefined;\r\n scaleOverride.y = undefined;\r\n if (this.splatRenderMode === SplatRenderMode.ThreeD) {\r\n scaleOverride.z = undefined;\r\n } else {\r\n scaleOverride.z = 1;\r\n }\r\n const tempTransform = new Matrix4();\r\n\r\n let startSceneIndex = 0;\r\n let endSceneIndex = this.scenes.length - 1;\r\n if (sceneIndex !== undefined && sceneIndex !== null && sceneIndex >= 0 && sceneIndex <= this.scenes.length) {\r\n startSceneIndex = sceneIndex;\r\n endSceneIndex = sceneIndex;\r\n }\r\n for (let i = startSceneIndex; i <= endSceneIndex; i++) {\r\n if (applySceneTransform === undefined || applySceneTransform === null) {\r\n applySceneTransform = this.dynamicMode ? false : true;\r\n }\r\n\r\n const scene = this.getScene(i);\r\n const splatBuffer = scene.splatBuffer;\r\n let sceneTransform;\r\n if (applySceneTransform) {\r\n this.getSceneTransform(i, tempTransform);\r\n sceneTransform = tempTransform;\r\n }\r\n if (covariances) {\r\n splatBuffer.fillSplatCovarianceArray(covariances, sceneTransform, srcStart, srcEnd, destStart, covarianceCompressionLevel);\r\n }\r\n if (scales || rotations) {\r\n if (!scales || !rotations) {\r\n throw new Error('SplatMesh::fillSplatDataArrays() -> \"scales\" and \"rotations\" must both be valid.');\r\n }\r\n splatBuffer.fillSplatScaleRotationArray(scales, rotations, sceneTransform,\r\n srcStart, srcEnd, destStart, scaleRotationCompressionLevel, scaleOverride);\r\n }\r\n if (centers) splatBuffer.fillSplatCenterArray(this.morphedMesh, centers, sceneTransform, srcStart, srcEnd, destStart);\r\n if (colors) splatBuffer.fillSplatColorArray(colors, scene.minimumAlpha, srcStart, srcEnd, destStart);\r\n if (sphericalHarmonics) {\r\n splatBuffer.fillSphericalHarmonicsArray(sphericalHarmonics, this.minSphericalHarmonicsDegree,\r\n sceneTransform, srcStart, srcEnd, destStart, sphericalHarmonicsCompressionLevel);\r\n }\r\n\r\n destStart += splatBuffer.getSplatCount();\r\n }\r\n }\r\n\r\n morphedMesh;\r\n /**\r\n * Convert splat centers, which are floating point values, to an array of integers and multiply\r\n * each by 1000. Centers will get transformed as appropriate before conversion to integer.\r\n * @param {number} start The index at which to start retrieving data\r\n * @param {number} end The index at which to stop retrieving data\r\n * @param {boolean} padFour Enforce alignment of 4 by inserting a 1 after every 3 values\r\n * @return {Int32Array}\r\n */\r\n getIntegerCenters(start, end, padFour = false) {\r\n const splatCount = end - start + 1;\r\n const floatCenters = new Float32Array(splatCount * 3);\r\n this.fillSplatDataArrays(null, null, null, floatCenters, null, null, undefined, undefined, undefined, undefined, start);\r\n let intCenters;\r\n let componentCount = padFour ? 4 : 3;\r\n intCenters = new Int32Array(splatCount * componentCount);\r\n for (let i = 0; i < splatCount; i++) {\r\n for (let t = 0; t < 3; t++) {\r\n intCenters[i * componentCount + t] = Math.round(floatCenters[i * 3 + t] * 1000.0);\r\n }\r\n if (padFour) intCenters[i * componentCount + 3] = 1000;\r\n }\r\n return intCenters;\r\n }\r\n\r\n /**\r\n * Returns an array of splat centers, transformed as appropriate, optionally padded.\r\n * @param {number} start The index at which to start retrieving data\r\n * @param {number} end The index at which to stop retrieving data\r\n * @param {boolean} padFour Enforce alignment of 4 by inserting a 1 after every 3 values\r\n * @return {Float32Array}\r\n */\r\n getFloatCenters(start, end, padFour = false) {\r\n const splatCount = end - start + 1;\r\n const floatCenters = new Float32Array(splatCount * 3);\r\n this.fillSplatDataArrays(null, null, null, floatCenters, null, null, undefined, undefined, undefined, undefined, start);\r\n if (!padFour) return floatCenters;\r\n let paddedFloatCenters = new Float32Array(splatCount * 4);\r\n for (let i = 0; i < splatCount; i++) {\r\n for (let t = 0; t < 3; t++) {\r\n paddedFloatCenters[i * 4 + t] = floatCenters[i * 3 + t];\r\n }\r\n paddedFloatCenters[i * 4 + 3] = 1.0;\r\n }\r\n return paddedFloatCenters;\r\n }\r\n\r\n /**\r\n * Get the center for a splat, transformed as appropriate.\r\n * @param {number} globalIndex Global index of splat\r\n * @param {THREE.Vector3} outCenter THREE.Vector3 instance in which to store splat center\r\n * @param {boolean} applySceneTransform By default, if the splat mesh is static, the transform of the scene to which the splat at\r\n * 'globalIndex' belongs will be applied to the splat center. If 'applySceneTransform' is true,\r\n * the scene transform will always be applied and if 'applySceneTransform' is false, the\r\n * scene transform will never be applied. If undefined, the default behavior will apply.\r\n */\r\n getSplatCenter = function() {\r\n\r\n const paramsObj = {};\r\n\r\n return function(morphedMesh, globalIndex, outCenter, applySceneTransform) {\r\n this.getLocalSplatParameters(globalIndex, paramsObj, applySceneTransform);\r\n paramsObj.splatBuffer.getSplatCenter(morphedMesh, paramsObj.localIndex, outCenter, paramsObj.sceneTransform);\r\n };\r\n\r\n }();\r\n\r\n /**\r\n * Get the scale and rotation for a splat, transformed as appropriate.\r\n * @param {number} globalIndex Global index of splat\r\n * @param {THREE.Vector3} outScale THREE.Vector3 instance in which to store splat scale\r\n * @param {THREE.Quaternion} outRotation THREE.Quaternion instance in which to store splat rotation\r\n * @param {boolean} applySceneTransform By default, if the splat mesh is static, the transform of the scene to which the splat at\r\n * 'globalIndex' belongs will be applied to the splat scale and rotation. If\r\n * 'applySceneTransform' is true, the scene transform will always be applied and if\r\n * 'applySceneTransform' is false, the scene transform will never be applied. If undefined,\r\n * the default behavior will apply.\r\n */\r\n getSplatScaleAndRotation = function() {\r\n\r\n const paramsObj = {};\r\n const scaleOverride = new Vector3();\r\n\r\n return function(globalIndex, outScale, outRotation, applySceneTransform) {\r\n this.getLocalSplatParameters(globalIndex, paramsObj, applySceneTransform);\r\n scaleOverride.x = undefined;\r\n scaleOverride.y = undefined;\r\n scaleOverride.z = undefined;\r\n if (this.splatRenderMode === SplatRenderMode.TwoD) scaleOverride.z = 0;\r\n paramsObj.splatBuffer.getSplatScaleAndRotation(paramsObj.localIndex, outScale, outRotation,\r\n paramsObj.sceneTransform, scaleOverride);\r\n };\r\n\r\n }();\r\n\r\n /**\r\n * Get the color for a splat.\r\n * @param {number} globalIndex Global index of splat\r\n * @param {THREE.Vector4} outColor THREE.Vector4 instance in which to store splat color\r\n */\r\n getSplatColor = function() {\r\n\r\n const paramsObj = {};\r\n\r\n return function(globalIndex, outColor) {\r\n this.getLocalSplatParameters(globalIndex, paramsObj);\r\n paramsObj.splatBuffer.getSplatColor(paramsObj.localIndex, outColor);\r\n };\r\n\r\n }();\r\n\r\n /**\r\n * Store the transform of the scene at 'sceneIndex' in 'outTransform'.\r\n * @param {number} sceneIndex Index of the desired scene\r\n * @param {THREE.Matrix4} outTransform Instance of THREE.Matrix4 in which to store the scene's transform\r\n */\r\n getSceneTransform(sceneIndex, outTransform) {\r\n const scene = this.getScene(sceneIndex);\r\n scene.updateTransform(this.dynamicMode);\r\n outTransform.copy(scene.transform);\r\n }\r\n\r\n /**\r\n * Get the scene at 'sceneIndex'.\r\n * @param {number} sceneIndex Index of the desired scene\r\n * @return {SplatScene}\r\n */\r\n getScene(sceneIndex) {\r\n if (sceneIndex < 0 || sceneIndex >= this.scenes.length) {\r\n throw new Error('SplatMesh::getScene() -> Invalid scene index.');\r\n }\r\n return this.scenes[sceneIndex];\r\n }\r\n\r\n getSceneCount() {\r\n return this.scenes.length;\r\n }\r\n\r\n getSplatBufferForSplat(globalIndex) {\r\n return this.getScene(this.globalSplatIndexToSceneIndexMap[globalIndex]).splatBuffer;\r\n }\r\n\r\n getSceneIndexForSplat(globalIndex) {\r\n return this.globalSplatIndexToSceneIndexMap[globalIndex];\r\n }\r\n\r\n getSceneTransformForSplat(globalIndex) {\r\n return this.getScene(this.globalSplatIndexToSceneIndexMap[globalIndex]).transform;\r\n }\r\n\r\n getSplatLocalIndex(globalIndex) {\r\n return this.globalSplatIndexToLocalSplatIndexMap[globalIndex];\r\n }\r\n\r\n static getIntegerMatrixArray(matrix) {\r\n const matrixElements = matrix.elements;\r\n const intMatrixArray = [];\r\n for (let i = 0; i < 16; i++) {\r\n intMatrixArray[i] = Math.round(matrixElements[i] * 1000.0);\r\n }\r\n return intMatrixArray;\r\n }\r\n\r\n computeBoundingBox(applySceneTransforms = false, sceneIndex) {\r\n let splatCount = this.getSplatCount();\r\n if (sceneIndex !== undefined && sceneIndex !== null) {\r\n if (sceneIndex < 0 || sceneIndex >= this.scenes.length) {\r\n throw new Error('SplatMesh::computeBoundingBox() -> Invalid scene index.');\r\n }\r\n splatCount = this.scenes[sceneIndex].splatBuffer.getSplatCount();\r\n }\r\n\r\n const floatCenters = new Float32Array(splatCount * 3);\r\n this.fillSplatDataArrays(null, null, null, floatCenters, null, null, applySceneTransforms,\r\n undefined, undefined, undefined, undefined, sceneIndex);\r\n\r\n const min = new Vector3();\r\n const max = new Vector3();\r\n for (let i = 0; i < splatCount; i++) {\r\n const offset = i * 3;\r\n const x = floatCenters[offset];\r\n const y = floatCenters[offset + 1];\r\n const z = floatCenters[offset + 2];\r\n if (i === 0 || x < min.x) min.x = x;\r\n if (i === 0 || y < min.y) min.y = y;\r\n if (i === 0 || z < min.z) min.z = z;\r\n if (i === 0 || x > max.x) max.x = x;\r\n if (i === 0 || y > max.y) max.y = y;\r\n if (i === 0 || z > max.z) max.z = z;\r\n }\r\n\r\n return new Box3(min, max);\r\n }\r\n}","/**\r\n * DirectLoadError\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * Minor enhancement: Added this.name property for better error identification.\r\n */\r\nexport class DirectLoadError extends Error {\r\n constructor(msg) {\r\n super(msg);\r\n this.name = 'DirectLoadError';\r\n }\r\n}\r\n","/**\r\n * UncompressedSplatArray\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * This file is functionally identical to the original.\r\n * Import paths adjusted for gsplat-flame-avatar package structure.\r\n */\r\n\r\nimport { getSphericalHarmonicsComponentCountForDegree } from '../utils/Util.js';\r\n\r\nconst BASE_COMPONENT_COUNT = 14;\r\n\r\nexport class UncompressedSplatArray {\r\n\r\n static OFFSET = {\r\n X: 0,\r\n Y: 1,\r\n Z: 2,\r\n SCALE0: 3,\r\n SCALE1: 4,\r\n SCALE2: 5,\r\n ROTATION0: 6,\r\n ROTATION1: 7,\r\n ROTATION2: 8,\r\n ROTATION3: 9,\r\n FDC0: 10,\r\n FDC1: 11,\r\n FDC2: 12,\r\n OPACITY: 13,\r\n FRC0: 14,\r\n FRC1: 15,\r\n FRC2: 16,\r\n FRC3: 17,\r\n FRC4: 18,\r\n FRC5: 19,\r\n FRC6: 20,\r\n FRC7: 21,\r\n FRC8: 22,\r\n FRC9: 23,\r\n FRC10: 24,\r\n FRC11: 25,\r\n FRC12: 26,\r\n FRC13: 27,\r\n FRC14: 28,\r\n FRC15: 29,\r\n FRC16: 30,\r\n FRC17: 31,\r\n FRC18: 32,\r\n FRC19: 33,\r\n FRC20: 34,\r\n FRC21: 35,\r\n FRC22: 36,\r\n FRC23: 37\r\n };\r\n\r\n constructor(sphericalHarmonicsDegree = 0) {\r\n this.sphericalHarmonicsDegree = sphericalHarmonicsDegree;\r\n this.sphericalHarmonicsCount = getSphericalHarmonicsComponentCountForDegree(this.sphericalHarmonicsDegree);\r\n this.componentCount = this.sphericalHarmonicsCount + BASE_COMPONENT_COUNT;\r\n this.defaultSphericalHarmonics = new Array(this.sphericalHarmonicsCount).fill(0);\r\n this.splats = [];\r\n this.splatCount = 0;\r\n }\r\n\r\n static createSplat(sphericalHarmonicsDegree = 0) {\r\n const baseSplat = [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0];\r\n let shEntries = getSphericalHarmonicsComponentCountForDegree(sphericalHarmonicsDegree);\r\n for (let i = 0; i < shEntries; i++) baseSplat.push(0);\r\n return baseSplat;\r\n }\r\n\r\n addSplat(splat) {\r\n this.splats.push(splat);\r\n this.splatCount++;\r\n }\r\n\r\n getSplat(index) {\r\n return this.splats[index];\r\n }\r\n\r\n addDefaultSplat() {\r\n const newSplat = UncompressedSplatArray.createSplat(this.sphericalHarmonicsDegree);\r\n this.addSplat(newSplat);\r\n return newSplat;\r\n }\r\n\r\n addSplatFromComonents(x, y, z, scale0, scale1, scale2, rot0, rot1, rot2, rot3, r, g, b, opacity, ...rest) {\r\n const newSplat = [x, y, z, scale0, scale1, scale2, rot0, rot1, rot2, rot3, r, g, b, opacity, ...this.defaultSphericalHarmonics];\r\n for (let i = 0; i < rest.length && i < this.sphericalHarmonicsCount; i++) {\r\n newSplat[i] = rest[i];\r\n }\r\n this.addSplat(newSplat);\r\n return newSplat;\r\n }\r\n\r\n addSplatFromArray(src, srcIndex) {\r\n const srcSplat = src.splats[srcIndex];\r\n const newSplat = UncompressedSplatArray.createSplat(this.sphericalHarmonicsDegree);\r\n for (let i = 0; i < this.componentCount && i < srcSplat.length; i++) {\r\n newSplat[i] = srcSplat[i];\r\n }\r\n this.addSplat(newSplat);\r\n }\r\n}","/**\r\n * SplatBuffer\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * This file is functionally identical to the original.\r\n * Import paths adjusted for gsplat-flame-avatar package structure.\r\n */\r\n\r\nimport { DataUtils, Matrix3, Matrix4, Quaternion, Vector3 } from 'three';\r\nimport { UncompressedSplatArray } from './UncompressedSplatArray.js';\r\nimport { clamp, getSphericalHarmonicsComponentCountForDegree, DefaultSphericalHarmonics8BitCompressionHalfRange, convertBetweenCompressionLevels } from '../utils/Util.js';\r\nimport { Constants } from '../enums/EngineConstants.js';\r\n\r\n/**\r\n * Helper function to copy bytes between buffers\r\n */\r\nconst copyBetweenBuffers = (srcBuffer, srcOffset, destBuffer, destOffset, byteCount = 0) => {\r\n const src = new Uint8Array(srcBuffer, srcOffset);\r\n const dest = new Uint8Array(destBuffer, destOffset);\r\n for (let i = 0; i < byteCount; i++) {\r\n dest[i] = src[i];\r\n }\r\n};\r\n\r\n// Compression/decompression helper functions\r\nconst DefaultSphericalHarmonics8BitCompressionRange = Constants.SphericalHarmonics8BitCompressionRange;\r\n\r\nconst toHalfFloat = DataUtils.toHalfFloat.bind(DataUtils);\r\nconst fromHalfFloat = DataUtils.fromHalfFloat.bind(DataUtils);\r\n\r\nconst toUncompressedFloat = (f, compressionLevel, isSH = false, range8BitMin, range8BitMax) => {\r\n if (compressionLevel === 0) {\r\n return f;\r\n } else if (compressionLevel === 1 || compressionLevel === 2 && !isSH) {\r\n return DataUtils.fromHalfFloat(f);\r\n } else if (compressionLevel === 2) {\r\n return fromUint8(f, range8BitMin, range8BitMax);\r\n }\r\n};\r\n\r\nconst toUint8 = (v, rangeMin, rangeMax) => {\r\n v = clamp(v, rangeMin, rangeMax);\r\n const range = (rangeMax - rangeMin);\r\n return clamp(Math.floor((v - rangeMin) / range * 255), 0, 255);\r\n};\r\n\r\nconst fromUint8 = (v, rangeMin, rangeMax) => {\r\n const range = (rangeMax - rangeMin);\r\n return (v / 255 * range + rangeMin);\r\n};\r\n\r\nconst fromHalfFloatToUint8 = (v, rangeMin, rangeMax) => {\r\n return toUint8(fromHalfFloat(v), rangeMin, rangeMax);\r\n};\r\n\r\nconst fromUint8ToHalfFloat = (v, rangeMin, rangeMax) => {\r\n return toHalfFloat(fromUint8(v, rangeMin, rangeMax));\r\n};\r\n\r\nconst dataViewFloatForCompressionLevel = (dataView, floatIndex, compressionLevel, isSH = false) => {\r\n if (compressionLevel === 0) {\r\n return dataView.getFloat32(floatIndex * 4, true);\r\n } else if (compressionLevel === 1 || compressionLevel === 2 && !isSH) {\r\n return dataView.getUint16(floatIndex * 2, true);\r\n } else {\r\n return dataView.getUint8(floatIndex, true);\r\n }\r\n};\r\n\r\nexport class SplatBuffer {\r\n\r\n static CurrentMajorVersion = 0;\r\n static CurrentMinorVersion = 1;\r\n\r\n static CenterComponentCount = 3;\r\n static ScaleComponentCount = 3;\r\n static RotationComponentCount = 4;\r\n static ColorComponentCount = 4;\r\n static CovarianceComponentCount = 6;\r\n\r\n static SplatScaleOffsetFloat = 3;\r\n static SplatRotationOffsetFloat = 6;\r\n\r\n static CompressionLevels = {\r\n 0: {\r\n BytesPerCenter: 12,\r\n BytesPerScale: 12,\r\n BytesPerRotation: 16,\r\n BytesPerColor: 4,\r\n ScaleOffsetBytes: 12,\r\n RotationffsetBytes: 24,\r\n ColorOffsetBytes: 40,\r\n SphericalHarmonicsOffsetBytes: 44,\r\n ScaleRange: 1,\r\n BytesPerSphericalHarmonicsComponent: 4,\r\n SphericalHarmonicsOffsetFloat: 11,\r\n SphericalHarmonicsDegrees: {\r\n 0: { BytesPerSplat: 44 },\r\n 1: { BytesPerSplat: 80 },\r\n 2: { BytesPerSplat: 140 }\r\n },\r\n },\r\n 1: {\r\n BytesPerCenter: 6,\r\n BytesPerScale: 6,\r\n BytesPerRotation: 8,\r\n BytesPerColor: 4,\r\n ScaleOffsetBytes: 6,\r\n RotationffsetBytes: 12,\r\n ColorOffsetBytes: 20,\r\n SphericalHarmonicsOffsetBytes: 24,\r\n ScaleRange: 32767,\r\n BytesPerSphericalHarmonicsComponent: 2,\r\n SphericalHarmonicsOffsetFloat: 12,\r\n SphericalHarmonicsDegrees: {\r\n 0: { BytesPerSplat: 24 },\r\n 1: { BytesPerSplat: 42 },\r\n 2: { BytesPerSplat: 72 }\r\n },\r\n },\r\n 2: {\r\n BytesPerCenter: 6,\r\n BytesPerScale: 6,\r\n BytesPerRotation: 8,\r\n BytesPerColor: 4,\r\n ScaleOffsetBytes: 6,\r\n RotationffsetBytes: 12,\r\n ColorOffsetBytes: 20,\r\n SphericalHarmonicsOffsetBytes: 24,\r\n ScaleRange: 32767,\r\n BytesPerSphericalHarmonicsComponent: 1,\r\n SphericalHarmonicsOffsetFloat: 12,\r\n SphericalHarmonicsDegrees: {\r\n 0: { BytesPerSplat: 24 },\r\n 1: { BytesPerSplat: 33 },\r\n 2: { BytesPerSplat: 48 }\r\n },\r\n }\r\n };\r\n\r\n static CovarianceSizeFloats = 6;\r\n\r\n static HeaderSizeBytes = 4096;\r\n static SectionHeaderSizeBytes = 1024;\r\n\r\n static BucketStorageSizeBytes = 12;\r\n static BucketStorageSizeFloats = 3;\r\n\r\n static BucketBlockSize = 5.0;\r\n static BucketSize = 256;\r\n\r\n constructor(bufferData, secLoadedCountsToMax = true) {\r\n this.constructFromBuffer(bufferData, secLoadedCountsToMax);\r\n }\r\n\r\n getSplatCount() {\r\n return this.splatCount;\r\n }\r\n\r\n getMaxSplatCount() {\r\n return this.maxSplatCount;\r\n }\r\n\r\n getMinSphericalHarmonicsDegree() {\r\n let minSphericalHarmonicsDegree = 0;\r\n for (let i = 0; i < this.sections.length; i++) {\r\n const section = this.sections[i];\r\n if (i === 0 || section.sphericalHarmonicsDegree < minSphericalHarmonicsDegree) {\r\n minSphericalHarmonicsDegree = section.sphericalHarmonicsDegree;\r\n }\r\n }\r\n return minSphericalHarmonicsDegree;\r\n }\r\n\r\n getBucketIndex(section, localSplatIndex) {\r\n let bucketIndex;\r\n const maxSplatIndexInFullBuckets = section.fullBucketCount * section.bucketSize;\r\n if (localSplatIndex < maxSplatIndexInFullBuckets) {\r\n bucketIndex = Math.floor(localSplatIndex / section.bucketSize);\r\n } else {\r\n let bucketSplatIndex = maxSplatIndexInFullBuckets;\r\n bucketIndex = section.fullBucketCount;\r\n let partiallyFullBucketIndex = 0;\r\n while (bucketSplatIndex < section.splatCount) {\r\n let currentPartiallyFilledBucketSize = section.partiallyFilledBucketLengths[partiallyFullBucketIndex];\r\n if (localSplatIndex >= bucketSplatIndex && localSplatIndex < bucketSplatIndex + currentPartiallyFilledBucketSize) {\r\n break;\r\n }\r\n bucketSplatIndex += currentPartiallyFilledBucketSize;\r\n bucketIndex++;\r\n partiallyFullBucketIndex++;\r\n }\r\n }\r\n return bucketIndex;\r\n }\r\n\r\n getSplatCenter(morphedMesh, globalSplatIndex, outCenter, transform) {\r\n const sectionIndex = this.globalSplatIndexToSectionMap[globalSplatIndex];\r\n const section = this.sections[sectionIndex];\r\n const localSplatIndex = globalSplatIndex - section.splatCountOffset;\r\n\r\n const srcSplatCentersBase = section.bytesPerSplat * localSplatIndex;\r\n const dataView = new DataView(this.bufferData, section.dataBase + srcSplatCentersBase);\r\n\r\n const x = dataViewFloatForCompressionLevel(dataView, 0, this.compressionLevel);\r\n const y = dataViewFloatForCompressionLevel(dataView, 1, this.compressionLevel);\r\n const z = dataViewFloatForCompressionLevel(dataView, 2, this.compressionLevel);\r\n if (this.compressionLevel >= 1) {\r\n const bucketIndex = this.getBucketIndex(section, localSplatIndex);\r\n const bucketBase = bucketIndex * SplatBuffer.BucketStorageSizeFloats;\r\n const sf = section.compressionScaleFactor;\r\n const sr = section.compressionScaleRange;\r\n outCenter.x = (x - sr) * sf + section.bucketArray[bucketBase];\r\n outCenter.y = (y - sr) * sf + section.bucketArray[bucketBase + 1];\r\n outCenter.z = (z - sr) * sf + section.bucketArray[bucketBase + 2];\r\n } else {\r\n outCenter.x = x;\r\n outCenter.y = y;\r\n outCenter.z = z;\r\n }\r\n\r\n outCenter.x += morphedMesh[globalSplatIndex * 3 + 0];\r\n outCenter.y += morphedMesh[globalSplatIndex * 3 + 1];\r\n outCenter.z += morphedMesh[globalSplatIndex * 3 + 2];\r\n\r\n\r\n if (transform) outCenter.applyMatrix4(transform);\r\n }\r\n\r\n getSplatScaleAndRotation = function() {\r\n\r\n const scaleMatrix = new Matrix4();\r\n const rotationMatrix = new Matrix4();\r\n const tempMatrix = new Matrix4();\r\n const tempPosition = new Vector3();\r\n const scale = new Vector3();\r\n const rotation = new Quaternion();\r\n\r\n return function(index, outScale, outRotation, transform, scaleOverride) {\r\n const sectionIndex = this.globalSplatIndexToSectionMap[index];\r\n const section = this.sections[sectionIndex];\r\n const localSplatIndex = index - section.splatCountOffset;\r\n\r\n const srcSplatScalesBase = section.bytesPerSplat * localSplatIndex +\r\n SplatBuffer.CompressionLevels[this.compressionLevel].ScaleOffsetBytes;\r\n\r\n const dataView = new DataView(this.bufferData, section.dataBase + srcSplatScalesBase);\r\n\r\n scale.set(toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 0, this.compressionLevel), this.compressionLevel),\r\n toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 1, this.compressionLevel), this.compressionLevel),\r\n toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 2, this.compressionLevel), this.compressionLevel));\r\n if (scaleOverride) {\r\n if (scaleOverride.x !== undefined) scale.x = scaleOverride.x;\r\n if (scaleOverride.y !== undefined) scale.y = scaleOverride.y;\r\n if (scaleOverride.z !== undefined) scale.z = scaleOverride.z;\r\n }\r\n\r\n rotation.set(toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 4, this.compressionLevel), this.compressionLevel),\r\n toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 5, this.compressionLevel), this.compressionLevel),\r\n toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 6, this.compressionLevel), this.compressionLevel),\r\n toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 3, this.compressionLevel), this.compressionLevel));\r\n\r\n if (transform) {\r\n scaleMatrix.makeScale(scale.x, scale.y, scale.z);\r\n rotationMatrix.makeRotationFromQuaternion(rotation);\r\n tempMatrix.copy(scaleMatrix).multiply(rotationMatrix).multiply(transform);\r\n tempMatrix.decompose(tempPosition, outRotation, outScale);\r\n } else {\r\n outScale.copy(scale);\r\n outRotation.copy(rotation);\r\n }\r\n };\r\n\r\n }();\r\n\r\n getSplatColor(globalSplatIndex, outColor) {\r\n const sectionIndex = this.globalSplatIndexToSectionMap[globalSplatIndex];\r\n const section = this.sections[sectionIndex];\r\n const localSplatIndex = globalSplatIndex - section.splatCountOffset;\r\n\r\n const srcSplatColorsBase = section.bytesPerSplat * localSplatIndex +\r\n SplatBuffer.CompressionLevels[this.compressionLevel].ColorOffsetBytes;\r\n const splatColorsArray = new Uint8Array(this.bufferData, section.dataBase + srcSplatColorsBase, 4);\r\n\r\n outColor.set(splatColorsArray[0], splatColorsArray[1],\r\n splatColorsArray[2], splatColorsArray[3]);\r\n }\r\n\r\n fillSplatCenterArray(morphedMesh, outCenterArray, transform, srcFrom, srcTo, destFrom) {\r\n const splatCount = this.splatCount;\r\n\r\n srcFrom = srcFrom || 0;\r\n srcTo = srcTo || splatCount - 1;\r\n if (destFrom === undefined) destFrom = srcFrom;\r\n\r\n const center = new Vector3();\r\n for (let i = srcFrom; i <= srcTo; i++) {\r\n const sectionIndex = this.globalSplatIndexToSectionMap[i];\r\n const section = this.sections[sectionIndex];\r\n const localSplatIndex = i - section.splatCountOffset;\r\n const centerDestBase = (i - srcFrom + destFrom) * SplatBuffer.CenterComponentCount;\r\n\r\n const srcSplatCentersBase = section.bytesPerSplat * localSplatIndex;\r\n const dataView = new DataView(this.bufferData, section.dataBase + srcSplatCentersBase);\r\n\r\n const x = dataViewFloatForCompressionLevel(dataView, 0, this.compressionLevel);\r\n const y = dataViewFloatForCompressionLevel(dataView, 1, this.compressionLevel);\r\n const z = dataViewFloatForCompressionLevel(dataView, 2, this.compressionLevel);\r\n if (this.compressionLevel >= 1) {\r\n const bucketIndex = this.getBucketIndex(section, localSplatIndex);\r\n const bucketBase = bucketIndex * SplatBuffer.BucketStorageSizeFloats;\r\n const sf = section.compressionScaleFactor;\r\n const sr = section.compressionScaleRange;\r\n center.x = (x - sr) * sf + section.bucketArray[bucketBase];\r\n center.y = (y - sr) * sf + section.bucketArray[bucketBase + 1];\r\n center.z = (z - sr) * sf + section.bucketArray[bucketBase + 2];\r\n } else {\r\n center.x = x;\r\n center.y = y;\r\n center.z = z;\r\n }\r\n if (transform) {\r\n center.applyMatrix4(transform);\r\n }\r\n\r\n outCenterArray[centerDestBase] = center.x + morphedMesh[i * 3 + 0];\r\n outCenterArray[centerDestBase + 1] = center.y + morphedMesh[i * 3 + 1];\r\n outCenterArray[centerDestBase + 2] = center.z + morphedMesh[i * 3 + 2];\r\n\r\n // outCenterArray[centerDestBase] = morphedMesh[centerDestBase];\r\n // outCenterArray[centerDestBase + 1] = morphedMesh[centerDestBase + 1];\r\n // outCenterArray[centerDestBase + 2] = morphedMesh[centerDestBase + 2];\r\n\r\n // outCenterArray[centerDestBase] = center.x;\r\n // outCenterArray[centerDestBase + 1] = center.y;\r\n // outCenterArray[centerDestBase + 2] = center.z;\r\n }\r\n }\r\n\r\n fillSplatScaleRotationArray = function() {\r\n\r\n const scaleMatrix = new Matrix4();\r\n const rotationMatrix = new Matrix4();\r\n const tempMatrix = new Matrix4();\r\n const scale = new Vector3();\r\n const rotation = new Quaternion();\r\n const tempPosition = new Vector3();\r\n\r\n const ensurePositiveW = (quaternion) => {\r\n const flip = quaternion.w < 0 ? -1 : 1;\r\n quaternion.x *= flip;\r\n quaternion.y *= flip;\r\n quaternion.z *= flip;\r\n quaternion.w *= flip;\r\n };\r\n\r\n return function(outScaleArray, outRotationArray, transform, srcFrom, srcTo, destFrom,\r\n desiredOutputCompressionLevel, scaleOverride) {\r\n const splatCount = this.splatCount;\r\n\r\n srcFrom = srcFrom || 0;\r\n srcTo = srcTo || splatCount - 1;\r\n if (destFrom === undefined) destFrom = srcFrom;\r\n\r\n const outputConversion = (value, srcCompressionLevel) => {\r\n if (srcCompressionLevel === undefined) srcCompressionLevel = this.compressionLevel;\r\n return convertBetweenCompressionLevels(value, srcCompressionLevel, desiredOutputCompressionLevel);\r\n };\r\n\r\n for (let i = srcFrom; i <= srcTo; i++) {\r\n const sectionIndex = this.globalSplatIndexToSectionMap[i];\r\n const section = this.sections[sectionIndex];\r\n const localSplatIndex = i - section.splatCountOffset;\r\n\r\n const srcSplatScalesBase = section.bytesPerSplat * localSplatIndex +\r\n SplatBuffer.CompressionLevels[this.compressionLevel].ScaleOffsetBytes;\r\n\r\n const scaleDestBase = (i - srcFrom + destFrom) * SplatBuffer.ScaleComponentCount;\r\n const rotationDestBase = (i - srcFrom + destFrom) * SplatBuffer.RotationComponentCount;\r\n const dataView = new DataView(this.bufferData, section.dataBase + srcSplatScalesBase);\r\n\r\n const srcScaleX = (scaleOverride && scaleOverride.x !== undefined) ? scaleOverride.x :\r\n dataViewFloatForCompressionLevel(dataView, 0, this.compressionLevel);\r\n const srcScaleY = (scaleOverride && scaleOverride.y !== undefined) ? scaleOverride.y :\r\n dataViewFloatForCompressionLevel(dataView, 1, this.compressionLevel);\r\n const srcScaleZ = (scaleOverride && scaleOverride.z !== undefined) ? scaleOverride.z :\r\n dataViewFloatForCompressionLevel(dataView, 2, this.compressionLevel);\r\n\r\n const srcRotationW = dataViewFloatForCompressionLevel(dataView, 3, this.compressionLevel);\r\n const srcRotationX = dataViewFloatForCompressionLevel(dataView, 4, this.compressionLevel);\r\n const srcRotationY = dataViewFloatForCompressionLevel(dataView, 5, this.compressionLevel);\r\n const srcRotationZ = dataViewFloatForCompressionLevel(dataView, 6, this.compressionLevel);\r\n\r\n scale.set(toUncompressedFloat(srcScaleX, this.compressionLevel),\r\n toUncompressedFloat(srcScaleY, this.compressionLevel),\r\n toUncompressedFloat(srcScaleZ, this.compressionLevel));\r\n\r\n rotation.set(toUncompressedFloat(srcRotationX, this.compressionLevel),\r\n toUncompressedFloat(srcRotationY, this.compressionLevel),\r\n toUncompressedFloat(srcRotationZ, this.compressionLevel),\r\n toUncompressedFloat(srcRotationW, this.compressionLevel)).normalize();\r\n\r\n if (transform) {\r\n tempPosition.set(0, 0, 0);\r\n scaleMatrix.makeScale(scale.x, scale.y, scale.z);\r\n rotationMatrix.makeRotationFromQuaternion(rotation);\r\n tempMatrix.identity().premultiply(scaleMatrix).premultiply(rotationMatrix);\r\n tempMatrix.premultiply(transform);\r\n tempMatrix.decompose(tempPosition, rotation, scale);\r\n rotation.normalize();\r\n }\r\n\r\n ensurePositiveW(rotation);\r\n\r\n if (outScaleArray) {\r\n outScaleArray[scaleDestBase] = outputConversion(scale.x, 0);\r\n outScaleArray[scaleDestBase + 1] = outputConversion(scale.y, 0);\r\n outScaleArray[scaleDestBase + 2] = outputConversion(scale.z, 0);\r\n }\r\n\r\n if (outRotationArray) {\r\n outRotationArray[rotationDestBase] = outputConversion(rotation.x, 0);\r\n outRotationArray[rotationDestBase + 1] = outputConversion(rotation.y, 0);\r\n outRotationArray[rotationDestBase + 2] = outputConversion(rotation.z, 0);\r\n outRotationArray[rotationDestBase + 3] = outputConversion(rotation.w, 0);\r\n }\r\n }\r\n };\r\n }();\r\n\r\n static computeCovariance = function() {\r\n\r\n const tempMatrix4 = new Matrix4();\r\n const scaleMatrix = new Matrix3();\r\n const rotationMatrix = new Matrix3();\r\n const covarianceMatrix = new Matrix3();\r\n const transformedCovariance = new Matrix3();\r\n const transform3x3 = new Matrix3();\r\n const transform3x3Transpose = new Matrix3();\r\n\r\n return function(scale, rotation, transform, outCovariance, outOffset = 0, desiredOutputCompressionLevel) {\r\n\r\n tempMatrix4.makeScale(scale.x, scale.y, scale.z);\r\n scaleMatrix.setFromMatrix4(tempMatrix4);\r\n\r\n tempMatrix4.makeRotationFromQuaternion(rotation);\r\n rotationMatrix.setFromMatrix4(tempMatrix4);\r\n\r\n covarianceMatrix.copy(rotationMatrix).multiply(scaleMatrix);\r\n transformedCovariance.copy(covarianceMatrix).transpose().premultiply(covarianceMatrix);\r\n\r\n if (transform) {\r\n transform3x3.setFromMatrix4(transform);\r\n transform3x3Transpose.copy(transform3x3).transpose();\r\n transformedCovariance.multiply(transform3x3Transpose);\r\n transformedCovariance.premultiply(transform3x3);\r\n }\r\n\r\n if (desiredOutputCompressionLevel >= 1) {\r\n outCovariance[outOffset] = toHalfFloat(transformedCovariance.elements[0]);\r\n outCovariance[outOffset + 1] = toHalfFloat(transformedCovariance.elements[3]);\r\n outCovariance[outOffset + 2] = toHalfFloat(transformedCovariance.elements[6]);\r\n outCovariance[outOffset + 3] = toHalfFloat(transformedCovariance.elements[4]);\r\n outCovariance[outOffset + 4] = toHalfFloat(transformedCovariance.elements[7]);\r\n outCovariance[outOffset + 5] = toHalfFloat(transformedCovariance.elements[8]);\r\n } else {\r\n outCovariance[outOffset] = transformedCovariance.elements[0];\r\n outCovariance[outOffset + 1] = transformedCovariance.elements[3];\r\n outCovariance[outOffset + 2] = transformedCovariance.elements[6];\r\n outCovariance[outOffset + 3] = transformedCovariance.elements[4];\r\n outCovariance[outOffset + 4] = transformedCovariance.elements[7];\r\n outCovariance[outOffset + 5] = transformedCovariance.elements[8];\r\n }\r\n\r\n };\r\n\r\n }();\r\n\r\n fillSplatCovarianceArray(covarianceArray, transform, srcFrom, srcTo, destFrom, desiredOutputCompressionLevel) {\r\n const splatCount = this.splatCount;\r\n\r\n const scale = new Vector3();\r\n const rotation = new Quaternion();\r\n\r\n srcFrom = srcFrom || 0;\r\n srcTo = srcTo || splatCount - 1;\r\n if (destFrom === undefined) destFrom = srcFrom;\r\n\r\n for (let i = srcFrom; i <= srcTo; i++) {\r\n const sectionIndex = this.globalSplatIndexToSectionMap[i];\r\n const section = this.sections[sectionIndex];\r\n const localSplatIndex = i - section.splatCountOffset;\r\n\r\n const covarianceDestBase = (i - srcFrom + destFrom) * SplatBuffer.CovarianceComponentCount;\r\n const srcSplatScalesBase = section.bytesPerSplat * localSplatIndex +\r\n SplatBuffer.CompressionLevels[this.compressionLevel].ScaleOffsetBytes;\r\n\r\n const dataView = new DataView(this.bufferData, section.dataBase + srcSplatScalesBase);\r\n\r\n scale.set(toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 0, this.compressionLevel), this.compressionLevel),\r\n toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 1, this.compressionLevel), this.compressionLevel),\r\n toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 2, this.compressionLevel), this.compressionLevel));\r\n\r\n rotation.set(toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 4, this.compressionLevel), this.compressionLevel),\r\n toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 5, this.compressionLevel), this.compressionLevel),\r\n toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 6, this.compressionLevel), this.compressionLevel),\r\n toUncompressedFloat(dataViewFloatForCompressionLevel(dataView, 3, this.compressionLevel), this.compressionLevel));\r\n\r\n SplatBuffer.computeCovariance(scale, rotation, transform, covarianceArray, covarianceDestBase, desiredOutputCompressionLevel);\r\n }\r\n }\r\n\r\n fillSplatColorArray(outColorArray, minimumAlpha, srcFrom, srcTo, destFrom) {\r\n const splatCount = this.splatCount;\r\n\r\n srcFrom = srcFrom || 0;\r\n srcTo = srcTo || splatCount - 1;\r\n if (destFrom === undefined) destFrom = srcFrom;\r\n\r\n for (let i = srcFrom; i <= srcTo; i++) {\r\n\r\n const sectionIndex = this.globalSplatIndexToSectionMap[i];\r\n const section = this.sections[sectionIndex];\r\n const localSplatIndex = i - section.splatCountOffset;\r\n\r\n const colorDestBase = (i - srcFrom + destFrom) * SplatBuffer.ColorComponentCount;\r\n const srcSplatColorsBase = section.bytesPerSplat * localSplatIndex +\r\n SplatBuffer.CompressionLevels[this.compressionLevel].ColorOffsetBytes;\r\n\r\n const dataView = new Uint8Array(this.bufferData, section.dataBase + srcSplatColorsBase);\r\n\r\n let alpha = dataView[3];\r\n alpha = (alpha >= minimumAlpha) ? alpha : 0;\r\n\r\n outColorArray[colorDestBase] = dataView[0];\r\n outColorArray[colorDestBase + 1] = dataView[1];\r\n outColorArray[colorDestBase + 2] = dataView[2];\r\n outColorArray[colorDestBase + 3] = alpha;\r\n }\r\n }\r\n\r\n fillSphericalHarmonicsArray = function() {\r\n\r\n const sphericalHarmonicVectors = [];\r\n for (let i = 0; i < 15; i++) {\r\n sphericalHarmonicVectors[i] = new Vector3();\r\n }\r\n\r\n const tempMatrix3 = new Matrix3();\r\n const tempMatrix4 = new Matrix4();\r\n\r\n const tempTranslation = new Vector3();\r\n const tempScale = new Vector3();\r\n const tempRotation = new Quaternion();\r\n\r\n const sh11 = [];\r\n const sh12 = [];\r\n const sh13 = [];\r\n\r\n const sh21 = [];\r\n const sh22 = [];\r\n const sh23 = [];\r\n const sh24 = [];\r\n const sh25 = [];\r\n\r\n const shIn1 = [];\r\n const shIn2 = [];\r\n const shIn3 = [];\r\n const shIn4 = [];\r\n const shIn5 = [];\r\n\r\n const shOut1 = [];\r\n const shOut2 = [];\r\n const shOut3 = [];\r\n const shOut4 = [];\r\n const shOut5 = [];\r\n\r\n const noop = (v) => v;\r\n\r\n const set3 = (array, val1, val2, val3) => {\r\n array[0] = val1;\r\n array[1] = val2;\r\n array[2] = val3;\r\n };\r\n\r\n const set3FromArray = (array, srcDestView, stride, srcBase, compressionLevel) => {\r\n array[0] = dataViewFloatForCompressionLevel(srcDestView, srcBase, compressionLevel, true);\r\n array[1] = dataViewFloatForCompressionLevel(srcDestView, srcBase + stride, compressionLevel, true);\r\n array[2] = dataViewFloatForCompressionLevel(srcDestView, srcBase + stride + stride, compressionLevel, true);\r\n };\r\n\r\n const copy3 = (srcArray, destArray) => {\r\n destArray[0] = srcArray[0];\r\n destArray[1] = srcArray[1];\r\n destArray[2] = srcArray[2];\r\n };\r\n\r\n const setOutput3 = (srcArray, destArray, destBase, conversionFunc) => {\r\n destArray[destBase] = conversionFunc(srcArray[0]);\r\n destArray[destBase + 1] = conversionFunc(srcArray[1]);\r\n destArray[destBase + 2] = conversionFunc(srcArray[2]);\r\n };\r\n\r\n const toUncompressedFloatArray3 = (src, dest, compressionLevel, range8BitMin, range8BitMax) => {\r\n dest[0] = toUncompressedFloat(src[0], compressionLevel, true, range8BitMin, range8BitMax);\r\n dest[1] = toUncompressedFloat(src[1], compressionLevel, true, range8BitMin, range8BitMax);\r\n dest[2] = toUncompressedFloat(src[2], compressionLevel, true, range8BitMin, range8BitMax);\r\n return dest;\r\n };\r\n\r\n return function(outSphericalHarmonicsArray, outSphericalHarmonicsDegree, transform,\r\n srcFrom, srcTo, destFrom, desiredOutputCompressionLevel) {\r\n const splatCount = this.splatCount;\r\n\r\n srcFrom = srcFrom || 0;\r\n srcTo = srcTo || splatCount - 1;\r\n if (destFrom === undefined) destFrom = srcFrom;\r\n\r\n if (transform && outSphericalHarmonicsDegree >= 1) {\r\n tempMatrix4.copy(transform);\r\n tempMatrix4.decompose(tempTranslation, tempRotation, tempScale);\r\n tempRotation.normalize();\r\n tempMatrix4.makeRotationFromQuaternion(tempRotation);\r\n tempMatrix3.setFromMatrix4(tempMatrix4);\r\n set3(sh11, tempMatrix3.elements[4], -tempMatrix3.elements[7], tempMatrix3.elements[1]);\r\n set3(sh12, -tempMatrix3.elements[5], tempMatrix3.elements[8], -tempMatrix3.elements[2]);\r\n set3(sh13, tempMatrix3.elements[3], -tempMatrix3.elements[6], tempMatrix3.elements[0]);\r\n }\r\n\r\n const localFromHalfFloatToUint8 = (v) => {\r\n return fromHalfFloatToUint8(v, this.minSphericalHarmonicsCoeff, this.maxSphericalHarmonicsCoeff);\r\n };\r\n\r\n const localToUint8 = (v) => {\r\n return toUint8(v, this.minSphericalHarmonicsCoeff, this.maxSphericalHarmonicsCoeff);\r\n };\r\n\r\n for (let i = srcFrom; i <= srcTo; i++) {\r\n\r\n const sectionIndex = this.globalSplatIndexToSectionMap[i];\r\n const section = this.sections[sectionIndex];\r\n outSphericalHarmonicsDegree = Math.min(outSphericalHarmonicsDegree, section.sphericalHarmonicsDegree);\r\n const outSphericalHarmonicsComponentsCount = getSphericalHarmonicsComponentCountForDegree(outSphericalHarmonicsDegree);\r\n\r\n const localSplatIndex = i - section.splatCountOffset;\r\n\r\n const srcSplatSHBase = section.bytesPerSplat * localSplatIndex +\r\n SplatBuffer.CompressionLevels[this.compressionLevel].SphericalHarmonicsOffsetBytes;\r\n\r\n const dataView = new DataView(this.bufferData, section.dataBase + srcSplatSHBase);\r\n\r\n const shDestBase = (i - srcFrom + destFrom) * outSphericalHarmonicsComponentsCount;\r\n\r\n let compressionLevelForOutputConversion = transform ? 0 : this.compressionLevel;\r\n let outputConversionFunc = noop;\r\n if (compressionLevelForOutputConversion !== desiredOutputCompressionLevel) {\r\n if (compressionLevelForOutputConversion === 1) {\r\n if (desiredOutputCompressionLevel === 0) outputConversionFunc = fromHalfFloat;\r\n else if (desiredOutputCompressionLevel == 2) outputConversionFunc = localFromHalfFloatToUint8;\r\n } else if (compressionLevelForOutputConversion === 0) {\r\n if (desiredOutputCompressionLevel === 1) outputConversionFunc = toHalfFloat;\r\n else if (desiredOutputCompressionLevel == 2) outputConversionFunc = localToUint8;\r\n }\r\n }\r\n\r\n const minShCoeff = this.minSphericalHarmonicsCoeff;\r\n const maxShCoeff = this.maxSphericalHarmonicsCoeff;\r\n\r\n if (outSphericalHarmonicsDegree >= 1) {\r\n\r\n set3FromArray(shIn1, dataView, 3, 0, this.compressionLevel);\r\n set3FromArray(shIn2, dataView, 3, 1, this.compressionLevel);\r\n set3FromArray(shIn3, dataView, 3, 2, this.compressionLevel);\r\n\r\n if (transform) {\r\n toUncompressedFloatArray3(shIn1, shIn1, this.compressionLevel, minShCoeff, maxShCoeff);\r\n toUncompressedFloatArray3(shIn2, shIn2, this.compressionLevel, minShCoeff, maxShCoeff);\r\n toUncompressedFloatArray3(shIn3, shIn3, this.compressionLevel, minShCoeff, maxShCoeff);\r\n SplatBuffer.rotateSphericalHarmonics3(shIn1, shIn2, shIn3, sh11, sh12, sh13, shOut1, shOut2, shOut3);\r\n } else {\r\n copy3(shIn1, shOut1);\r\n copy3(shIn2, shOut2);\r\n copy3(shIn3, shOut3);\r\n }\r\n\r\n setOutput3(shOut1, outSphericalHarmonicsArray, shDestBase, outputConversionFunc);\r\n setOutput3(shOut2, outSphericalHarmonicsArray, shDestBase + 3, outputConversionFunc);\r\n setOutput3(shOut3, outSphericalHarmonicsArray, shDestBase + 6, outputConversionFunc);\r\n\r\n if (outSphericalHarmonicsDegree >= 2) {\r\n\r\n set3FromArray(shIn1, dataView, 5, 9, this.compressionLevel);\r\n set3FromArray(shIn2, dataView, 5, 10, this.compressionLevel);\r\n set3FromArray(shIn3, dataView, 5, 11, this.compressionLevel);\r\n set3FromArray(shIn4, dataView, 5, 12, this.compressionLevel);\r\n set3FromArray(shIn5, dataView, 5, 13, this.compressionLevel);\r\n\r\n if (transform) {\r\n toUncompressedFloatArray3(shIn1, shIn1, this.compressionLevel, minShCoeff, maxShCoeff);\r\n toUncompressedFloatArray3(shIn2, shIn2, this.compressionLevel, minShCoeff, maxShCoeff);\r\n toUncompressedFloatArray3(shIn3, shIn3, this.compressionLevel, minShCoeff, maxShCoeff);\r\n toUncompressedFloatArray3(shIn4, shIn4, this.compressionLevel, minShCoeff, maxShCoeff);\r\n toUncompressedFloatArray3(shIn5, shIn5, this.compressionLevel, minShCoeff, maxShCoeff);\r\n SplatBuffer.rotateSphericalHarmonics5(shIn1, shIn2, shIn3, shIn4, shIn5,\r\n sh11, sh12, sh13, sh21, sh22, sh23, sh24, sh25,\r\n shOut1, shOut2, shOut3, shOut4, shOut5);\r\n } else {\r\n copy3(shIn1, shOut1);\r\n copy3(shIn2, shOut2);\r\n copy3(shIn3, shOut3);\r\n copy3(shIn4, shOut4);\r\n copy3(shIn5, shOut5);\r\n }\r\n\r\n setOutput3(shOut1, outSphericalHarmonicsArray, shDestBase + 9, outputConversionFunc);\r\n setOutput3(shOut2, outSphericalHarmonicsArray, shDestBase + 12, outputConversionFunc);\r\n setOutput3(shOut3, outSphericalHarmonicsArray, shDestBase + 15, outputConversionFunc);\r\n setOutput3(shOut4, outSphericalHarmonicsArray, shDestBase + 18, outputConversionFunc);\r\n setOutput3(shOut5, outSphericalHarmonicsArray, shDestBase + 21, outputConversionFunc);\r\n }\r\n }\r\n }\r\n };\r\n\r\n }();\r\n\r\n static dot3 = (v1, v2, v3, transformRow, outArray) => {\r\n outArray[0] = outArray[1] = outArray[2] = 0;\r\n const t0 = transformRow[0];\r\n const t1 = transformRow[1];\r\n const t2 = transformRow[2];\r\n SplatBuffer.addInto3(v1[0] * t0, v1[1] * t0, v1[2] * t0, outArray);\r\n SplatBuffer.addInto3(v2[0] * t1, v2[1] * t1, v2[2] * t1, outArray);\r\n SplatBuffer.addInto3(v3[0] * t2, v3[1] * t2, v3[2] * t2, outArray);\r\n };\r\n\r\n static addInto3 = (val1, val2, val3, destArray) => {\r\n destArray[0] = destArray[0] + val1;\r\n destArray[1] = destArray[1] + val2;\r\n destArray[2] = destArray[2] + val3;\r\n };\r\n\r\n static dot5 = (v1, v2, v3, v4, v5, transformRow, outArray) => {\r\n outArray[0] = outArray[1] = outArray[2] = 0;\r\n const t0 = transformRow[0];\r\n const t1 = transformRow[1];\r\n const t2 = transformRow[2];\r\n const t3 = transformRow[3];\r\n const t4 = transformRow[4];\r\n SplatBuffer.addInto3(v1[0] * t0, v1[1] * t0, v1[2] * t0, outArray);\r\n SplatBuffer.addInto3(v2[0] * t1, v2[1] * t1, v2[2] * t1, outArray);\r\n SplatBuffer.addInto3(v3[0] * t2, v3[1] * t2, v3[2] * t2, outArray);\r\n SplatBuffer.addInto3(v4[0] * t3, v4[1] * t3, v4[2] * t3, outArray);\r\n SplatBuffer.addInto3(v5[0] * t4, v5[1] * t4, v5[2] * t4, outArray);\r\n };\r\n\r\n static rotateSphericalHarmonics3 = (in1, in2, in3, tsh11, tsh12, tsh13, out1, out2, out3) => {\r\n SplatBuffer.dot3(in1, in2, in3, tsh11, out1);\r\n SplatBuffer.dot3(in1, in2, in3, tsh12, out2);\r\n SplatBuffer.dot3(in1, in2, in3, tsh13, out3);\r\n };\r\n\r\n static rotateSphericalHarmonics5 = (in1, in2, in3, in4, in5, tsh11, tsh12, tsh13,\r\n tsh21, tsh22, tsh23, tsh24, tsh25, out1, out2, out3, out4, out5) => {\r\n\r\n const kSqrt0104 = Math.sqrt(1.0 / 4.0);\r\n const kSqrt0304 = Math.sqrt(3.0 / 4.0);\r\n const kSqrt0103 = Math.sqrt(1.0 / 3.0);\r\n const kSqrt0403 = Math.sqrt(4.0 / 3.0);\r\n const kSqrt0112 = Math.sqrt(1.0 / 12.0);\r\n\r\n tsh21[0] = kSqrt0104 * ((tsh13[2] * tsh11[0] + tsh13[0] * tsh11[2]) + (tsh11[2] * tsh13[0] + tsh11[0] * tsh13[2]));\r\n tsh21[1] = (tsh13[1] * tsh11[0] + tsh11[1] * tsh13[0]);\r\n tsh21[2] = kSqrt0304 * (tsh13[1] * tsh11[1] + tsh11[1] * tsh13[1]);\r\n tsh21[3] = (tsh13[1] * tsh11[2] + tsh11[1] * tsh13[2]);\r\n tsh21[4] = kSqrt0104 * ((tsh13[2] * tsh11[2] - tsh13[0] * tsh11[0]) + (tsh11[2] * tsh13[2] - tsh11[0] * tsh13[0]));\r\n SplatBuffer.dot5(in1, in2, in3, in4, in5, tsh21, out1);\r\n\r\n tsh22[0] = kSqrt0104 * ((tsh12[2] * tsh11[0] + tsh12[0] * tsh11[2]) + (tsh11[2] * tsh12[0] + tsh11[0] * tsh12[2]));\r\n tsh22[1] = tsh12[1] * tsh11[0] + tsh11[1] * tsh12[0];\r\n tsh22[2] = kSqrt0304 * (tsh12[1] * tsh11[1] + tsh11[1] * tsh12[1]);\r\n tsh22[3] = tsh12[1] * tsh11[2] + tsh11[1] * tsh12[2];\r\n tsh22[4] = kSqrt0104 * ((tsh12[2] * tsh11[2] - tsh12[0] * tsh11[0]) + (tsh11[2] * tsh12[2] - tsh11[0] * tsh12[0]));\r\n SplatBuffer.dot5(in1, in2, in3, in4, in5, tsh22, out2);\r\n\r\n tsh23[0] = kSqrt0103 * (tsh12[2] * tsh12[0] + tsh12[0] * tsh12[2]) + -kSqrt0112 *\r\n ((tsh13[2] * tsh13[0] + tsh13[0] * tsh13[2]) + (tsh11[2] * tsh11[0] + tsh11[0] * tsh11[2]));\r\n tsh23[1] = kSqrt0403 * tsh12[1] * tsh12[0] + -kSqrt0103 * (tsh13[1] * tsh13[0] + tsh11[1] * tsh11[0]);\r\n tsh23[2] = tsh12[1] * tsh12[1] + -kSqrt0104 * (tsh13[1] * tsh13[1] + tsh11[1] * tsh11[1]);\r\n tsh23[3] = kSqrt0403 * tsh12[1] * tsh12[2] + -kSqrt0103 * (tsh13[1] * tsh13[2] + tsh11[1] * tsh11[2]);\r\n tsh23[4] = kSqrt0103 * (tsh12[2] * tsh12[2] - tsh12[0] * tsh12[0]) + -kSqrt0112 *\r\n ((tsh13[2] * tsh13[2] - tsh13[0] * tsh13[0]) + (tsh11[2] * tsh11[2] - tsh11[0] * tsh11[0]));\r\n SplatBuffer.dot5(in1, in2, in3, in4, in5, tsh23, out3);\r\n\r\n tsh24[0] = kSqrt0104 * ((tsh12[2] * tsh13[0] + tsh12[0] * tsh13[2]) + (tsh13[2] * tsh12[0] + tsh13[0] * tsh12[2]));\r\n tsh24[1] = tsh12[1] * tsh13[0] + tsh13[1] * tsh12[0];\r\n tsh24[2] = kSqrt0304 * (tsh12[1] * tsh13[1] + tsh13[1] * tsh12[1]);\r\n tsh24[3] = tsh12[1] * tsh13[2] + tsh13[1] * tsh12[2];\r\n tsh24[4] = kSqrt0104 * ((tsh12[2] * tsh13[2] - tsh12[0] * tsh13[0]) + (tsh13[2] * tsh12[2] - tsh13[0] * tsh12[0]));\r\n SplatBuffer.dot5(in1, in2, in3, in4, in5, tsh24, out4);\r\n\r\n tsh25[0] = kSqrt0104 * ((tsh13[2] * tsh13[0] + tsh13[0] * tsh13[2]) - (tsh11[2] * tsh11[0] + tsh11[0] * tsh11[2]));\r\n tsh25[1] = (tsh13[1] * tsh13[0] - tsh11[1] * tsh11[0]);\r\n tsh25[2] = kSqrt0304 * (tsh13[1] * tsh13[1] - tsh11[1] * tsh11[1]);\r\n tsh25[3] = (tsh13[1] * tsh13[2] - tsh11[1] * tsh11[2]);\r\n tsh25[4] = kSqrt0104 * ((tsh13[2] * tsh13[2] - tsh13[0] * tsh13[0]) - (tsh11[2] * tsh11[2] - tsh11[0] * tsh11[0]));\r\n SplatBuffer.dot5(in1, in2, in3, in4, in5, tsh25, out5);\r\n };\r\n\r\n static parseHeader(buffer) {\r\n const headerArrayUint8 = new Uint8Array(buffer, 0, SplatBuffer.HeaderSizeBytes);\r\n const headerArrayUint16 = new Uint16Array(buffer, 0, SplatBuffer.HeaderSizeBytes / 2);\r\n const headerArrayUint32 = new Uint32Array(buffer, 0, SplatBuffer.HeaderSizeBytes / 4);\r\n const headerArrayFloat32 = new Float32Array(buffer, 0, SplatBuffer.HeaderSizeBytes / 4);\r\n const versionMajor = headerArrayUint8[0];\r\n const versionMinor = headerArrayUint8[1];\r\n const maxSectionCount = headerArrayUint32[1];\r\n const sectionCount = headerArrayUint32[2];\r\n const maxSplatCount = headerArrayUint32[3];\r\n const splatCount = headerArrayUint32[4];\r\n const compressionLevel = headerArrayUint16[10];\r\n const sceneCenter = new Vector3(headerArrayFloat32[6], headerArrayFloat32[7], headerArrayFloat32[8]);\r\n\r\n const minSphericalHarmonicsCoeff = headerArrayFloat32[9] || -DefaultSphericalHarmonics8BitCompressionHalfRange;\r\n const maxSphericalHarmonicsCoeff = headerArrayFloat32[10] || DefaultSphericalHarmonics8BitCompressionHalfRange;\r\n\r\n return {\r\n versionMajor,\r\n versionMinor,\r\n maxSectionCount,\r\n sectionCount,\r\n maxSplatCount,\r\n splatCount,\r\n compressionLevel,\r\n sceneCenter,\r\n minSphericalHarmonicsCoeff,\r\n maxSphericalHarmonicsCoeff\r\n };\r\n }\r\n\r\n static writeHeaderCountsToBuffer(sectionCount, splatCount, buffer) {\r\n const headerArrayUint32 = new Uint32Array(buffer, 0, SplatBuffer.HeaderSizeBytes / 4);\r\n headerArrayUint32[2] = sectionCount;\r\n headerArrayUint32[4] = splatCount;\r\n }\r\n\r\n static writeHeaderToBuffer(header, buffer) {\r\n const headerArrayUint8 = new Uint8Array(buffer, 0, SplatBuffer.HeaderSizeBytes);\r\n const headerArrayUint16 = new Uint16Array(buffer, 0, SplatBuffer.HeaderSizeBytes / 2);\r\n const headerArrayUint32 = new Uint32Array(buffer, 0, SplatBuffer.HeaderSizeBytes / 4);\r\n const headerArrayFloat32 = new Float32Array(buffer, 0, SplatBuffer.HeaderSizeBytes / 4);\r\n headerArrayUint8[0] = header.versionMajor;\r\n headerArrayUint8[1] = header.versionMinor;\r\n headerArrayUint8[2] = 0; // unused for now\r\n headerArrayUint8[3] = 0; // unused for now\r\n headerArrayUint32[1] = header.maxSectionCount;\r\n headerArrayUint32[2] = header.sectionCount;\r\n headerArrayUint32[3] = header.maxSplatCount;\r\n headerArrayUint32[4] = header.splatCount;\r\n headerArrayUint16[10] = header.compressionLevel;\r\n headerArrayFloat32[6] = header.sceneCenter.x;\r\n headerArrayFloat32[7] = header.sceneCenter.y;\r\n headerArrayFloat32[8] = header.sceneCenter.z;\r\n headerArrayFloat32[9] = header.minSphericalHarmonicsCoeff || -DefaultSphericalHarmonics8BitCompressionHalfRange;\r\n headerArrayFloat32[10] = header.maxSphericalHarmonicsCoeff || DefaultSphericalHarmonics8BitCompressionHalfRange;\r\n }\r\n\r\n static parseSectionHeaders(header, buffer, offset = 0, secLoadedCountsToMax) {\r\n const compressionLevel = header.compressionLevel;\r\n\r\n const maxSectionCount = header.maxSectionCount;\r\n const sectionHeaderArrayUint16 = new Uint16Array(buffer, offset, maxSectionCount * SplatBuffer.SectionHeaderSizeBytes / 2);\r\n const sectionHeaderArrayUint32 = new Uint32Array(buffer, offset, maxSectionCount * SplatBuffer.SectionHeaderSizeBytes / 4);\r\n const sectionHeaderArrayFloat32 = new Float32Array(buffer, offset, maxSectionCount * SplatBuffer.SectionHeaderSizeBytes / 4);\r\n\r\n const sectionHeaders = [];\r\n let sectionHeaderBase = 0;\r\n let sectionHeaderBaseUint16 = sectionHeaderBase / 2;\r\n let sectionHeaderBaseUint32 = sectionHeaderBase / 4;\r\n let sectionBase = SplatBuffer.HeaderSizeBytes + header.maxSectionCount * SplatBuffer.SectionHeaderSizeBytes;\r\n let splatCountOffset = 0;\r\n for (let i = 0; i < maxSectionCount; i++) {\r\n const maxSplatCount = sectionHeaderArrayUint32[sectionHeaderBaseUint32 + 1];\r\n const bucketSize = sectionHeaderArrayUint32[sectionHeaderBaseUint32 + 2];\r\n const bucketCount = sectionHeaderArrayUint32[sectionHeaderBaseUint32 + 3];\r\n const bucketBlockSize = sectionHeaderArrayFloat32[sectionHeaderBaseUint32 + 4];\r\n const halfBucketBlockSize = bucketBlockSize / 2.0;\r\n const bucketStorageSizeBytes = sectionHeaderArrayUint16[sectionHeaderBaseUint16 + 10];\r\n const compressionScaleRange = sectionHeaderArrayUint32[sectionHeaderBaseUint32 + 6] ||\r\n SplatBuffer.CompressionLevels[compressionLevel].ScaleRange;\r\n const fullBucketCount = sectionHeaderArrayUint32[sectionHeaderBaseUint32 + 8];\r\n const partiallyFilledBucketCount = sectionHeaderArrayUint32[sectionHeaderBaseUint32 + 9];\r\n const bucketsMetaDataSizeBytes = partiallyFilledBucketCount * 4;\r\n const bucketsStorageSizeBytes = bucketStorageSizeBytes * bucketCount + bucketsMetaDataSizeBytes;\r\n\r\n const sphericalHarmonicsDegree = sectionHeaderArrayUint16[sectionHeaderBaseUint16 + 20];\r\n const { bytesPerSplat } = SplatBuffer.calculateComponentStorage(compressionLevel, sphericalHarmonicsDegree);\r\n\r\n const splatDataStorageSizeBytes = bytesPerSplat * maxSplatCount;\r\n const storageSizeBytes = splatDataStorageSizeBytes + bucketsStorageSizeBytes;\r\n const sectionHeader = {\r\n bytesPerSplat: bytesPerSplat,\r\n splatCountOffset: splatCountOffset,\r\n splatCount: secLoadedCountsToMax ? maxSplatCount : 0,\r\n maxSplatCount: maxSplatCount,\r\n bucketSize: bucketSize,\r\n bucketCount: bucketCount,\r\n bucketBlockSize: bucketBlockSize,\r\n halfBucketBlockSize: halfBucketBlockSize,\r\n bucketStorageSizeBytes: bucketStorageSizeBytes,\r\n bucketsStorageSizeBytes: bucketsStorageSizeBytes,\r\n splatDataStorageSizeBytes: splatDataStorageSizeBytes,\r\n storageSizeBytes: storageSizeBytes,\r\n compressionScaleRange: compressionScaleRange,\r\n compressionScaleFactor: halfBucketBlockSize / compressionScaleRange,\r\n base: sectionBase,\r\n bucketsBase: sectionBase + bucketsMetaDataSizeBytes,\r\n dataBase: sectionBase + bucketsStorageSizeBytes,\r\n fullBucketCount: fullBucketCount,\r\n partiallyFilledBucketCount: partiallyFilledBucketCount,\r\n sphericalHarmonicsDegree: sphericalHarmonicsDegree\r\n };\r\n sectionHeaders[i] = sectionHeader;\r\n sectionBase += storageSizeBytes;\r\n sectionHeaderBase += SplatBuffer.SectionHeaderSizeBytes;\r\n sectionHeaderBaseUint16 = sectionHeaderBase / 2;\r\n sectionHeaderBaseUint32 = sectionHeaderBase / 4;\r\n splatCountOffset += maxSplatCount;\r\n }\r\n\r\n return sectionHeaders;\r\n }\r\n\r\n\r\n static writeSectionHeaderToBuffer(sectionHeader, compressionLevel, buffer, offset = 0) {\r\n const sectionHeadeArrayUint16 = new Uint16Array(buffer, offset, SplatBuffer.SectionHeaderSizeBytes / 2);\r\n const sectionHeadeArrayUint32 = new Uint32Array(buffer, offset, SplatBuffer.SectionHeaderSizeBytes / 4);\r\n const sectionHeadeArrayFloat32 = new Float32Array(buffer, offset, SplatBuffer.SectionHeaderSizeBytes / 4);\r\n\r\n sectionHeadeArrayUint32[0] = sectionHeader.splatCount;\r\n sectionHeadeArrayUint32[1] = sectionHeader.maxSplatCount;\r\n sectionHeadeArrayUint32[2] = compressionLevel >= 1 ? sectionHeader.bucketSize : 0;\r\n sectionHeadeArrayUint32[3] = compressionLevel >= 1 ? sectionHeader.bucketCount : 0;\r\n sectionHeadeArrayFloat32[4] = compressionLevel >= 1 ? sectionHeader.bucketBlockSize : 0.0;\r\n sectionHeadeArrayUint16[10] = compressionLevel >= 1 ? SplatBuffer.BucketStorageSizeBytes : 0;\r\n sectionHeadeArrayUint32[6] = compressionLevel >= 1 ? sectionHeader.compressionScaleRange : 0;\r\n sectionHeadeArrayUint32[7] = sectionHeader.storageSizeBytes;\r\n sectionHeadeArrayUint32[8] = compressionLevel >= 1 ? sectionHeader.fullBucketCount : 0;\r\n sectionHeadeArrayUint32[9] = compressionLevel >= 1 ? sectionHeader.partiallyFilledBucketCount : 0;\r\n sectionHeadeArrayUint16[20] = sectionHeader.sphericalHarmonicsDegree;\r\n\r\n }\r\n\r\n static writeSectionHeaderSplatCountToBuffer(splatCount, buffer, offset = 0) {\r\n const sectionHeadeArrayUint32 = new Uint32Array(buffer, offset, SplatBuffer.SectionHeaderSizeBytes / 4);\r\n sectionHeadeArrayUint32[0] = splatCount;\r\n }\r\n\r\n constructFromBuffer(bufferData, secLoadedCountsToMax) {\r\n this.bufferData = bufferData;\r\n\r\n this.globalSplatIndexToLocalSplatIndexMap = [];\r\n this.globalSplatIndexToSectionMap = [];\r\n\r\n const header = SplatBuffer.parseHeader(this.bufferData);\r\n this.versionMajor = header.versionMajor;\r\n this.versionMinor = header.versionMinor;\r\n this.maxSectionCount = header.maxSectionCount;\r\n this.sectionCount = secLoadedCountsToMax ? header.maxSectionCount : 0;\r\n this.maxSplatCount = header.maxSplatCount;\r\n this.splatCount = secLoadedCountsToMax ? header.maxSplatCount : 0;\r\n this.compressionLevel = header.compressionLevel;\r\n this.sceneCenter = new Vector3().copy(header.sceneCenter);\r\n this.minSphericalHarmonicsCoeff = header.minSphericalHarmonicsCoeff;\r\n this.maxSphericalHarmonicsCoeff = header.maxSphericalHarmonicsCoeff;\r\n\r\n this.sections = SplatBuffer.parseSectionHeaders(header, this.bufferData, SplatBuffer.HeaderSizeBytes, secLoadedCountsToMax);\r\n\r\n this.linkBufferArrays();\r\n this.buildMaps();\r\n }\r\n\r\n static calculateComponentStorage(compressionLevel, sphericalHarmonicsDegree) {\r\n const bytesPerCenter = SplatBuffer.CompressionLevels[compressionLevel].BytesPerCenter;\r\n const bytesPerScale = SplatBuffer.CompressionLevels[compressionLevel].BytesPerScale;\r\n const bytesPerRotation = SplatBuffer.CompressionLevels[compressionLevel].BytesPerRotation;\r\n const bytesPerColor = SplatBuffer.CompressionLevels[compressionLevel].BytesPerColor;\r\n const sphericalHarmonicsComponentsPerSplat = getSphericalHarmonicsComponentCountForDegree(sphericalHarmonicsDegree);\r\n const sphericalHarmonicsBytesPerSplat = SplatBuffer.CompressionLevels[compressionLevel].BytesPerSphericalHarmonicsComponent *\r\n sphericalHarmonicsComponentsPerSplat;\r\n const bytesPerSplat = bytesPerCenter + bytesPerScale + bytesPerRotation +\r\n bytesPerColor + sphericalHarmonicsBytesPerSplat;\r\n return {\r\n bytesPerCenter,\r\n bytesPerScale,\r\n bytesPerRotation,\r\n bytesPerColor,\r\n sphericalHarmonicsComponentsPerSplat,\r\n sphericalHarmonicsBytesPerSplat,\r\n bytesPerSplat\r\n };\r\n }\r\n\r\n linkBufferArrays() {\r\n for (let i = 0; i < this.maxSectionCount; i++) {\r\n const section = this.sections[i];\r\n section.bucketArray = new Float32Array(this.bufferData, section.bucketsBase,\r\n section.bucketCount * SplatBuffer.BucketStorageSizeFloats);\r\n if (section.partiallyFilledBucketCount > 0) {\r\n section.partiallyFilledBucketLengths = new Uint32Array(this.bufferData, section.base,\r\n section.partiallyFilledBucketCount);\r\n }\r\n }\r\n }\r\n\r\n buildMaps() {\r\n let cumulativeSplatCount = 0;\r\n for (let i = 0; i < this.maxSectionCount; i++) {\r\n const section = this.sections[i];\r\n for (let j = 0; j < section.maxSplatCount; j++) {\r\n const globalSplatIndex = cumulativeSplatCount + j;\r\n this.globalSplatIndexToLocalSplatIndexMap[globalSplatIndex] = j;\r\n this.globalSplatIndexToSectionMap[globalSplatIndex] = i;\r\n }\r\n cumulativeSplatCount += section.maxSplatCount;\r\n }\r\n }\r\n\r\n updateLoadedCounts(newSectionCount, newSplatCount) {\r\n SplatBuffer.writeHeaderCountsToBuffer(newSectionCount, newSplatCount, this.bufferData);\r\n this.sectionCount = newSectionCount;\r\n this.splatCount = newSplatCount;\r\n }\r\n\r\n updateSectionLoadedCounts(sectionIndex, newSplatCount) {\r\n const sectionHeaderOffset = SplatBuffer.HeaderSizeBytes + SplatBuffer.SectionHeaderSizeBytes * sectionIndex;\r\n SplatBuffer.writeSectionHeaderSplatCountToBuffer(newSplatCount, this.bufferData, sectionHeaderOffset);\r\n this.sections[sectionIndex].splatCount = newSplatCount;\r\n }\r\n\r\n static writeSplatDataToSectionBuffer = function() {\r\n\r\n const tempCenterBuffer = new ArrayBuffer(12);\r\n const tempScaleBuffer = new ArrayBuffer(12);\r\n const tempRotationBuffer = new ArrayBuffer(16);\r\n const tempColorBuffer = new ArrayBuffer(4);\r\n const tempSHBuffer = new ArrayBuffer(256);\r\n const tempRot = new Quaternion();\r\n const tempScale = new Vector3();\r\n const bucketCenterDelta = new Vector3();\r\n\r\n const {\r\n X: OFFSET_X, Y: OFFSET_Y, Z: OFFSET_Z,\r\n SCALE0: OFFSET_SCALE0, SCALE1: OFFSET_SCALE1, SCALE2: OFFSET_SCALE2,\r\n ROTATION0: OFFSET_ROT0, ROTATION1: OFFSET_ROT1, ROTATION2: OFFSET_ROT2, ROTATION3: OFFSET_ROT3,\r\n FDC0: OFFSET_FDC0, FDC1: OFFSET_FDC1, FDC2: OFFSET_FDC2, OPACITY: OFFSET_OPACITY,\r\n FRC0: OFFSET_FRC0, FRC9: OFFSET_FRC9,\r\n } = UncompressedSplatArray.OFFSET;\r\n\r\n const compressPositionOffset = (v, compressionScaleFactor, compressionScaleRange) => {\r\n const doubleCompressionScaleRange = compressionScaleRange * 2 + 1;\r\n v = Math.round(v * compressionScaleFactor) + compressionScaleRange;\r\n return clamp(v, 0, doubleCompressionScaleRange);\r\n };\r\n\r\n return function(targetSplat, sectionBuffer, bufferOffset, compressionLevel, sphericalHarmonicsDegree,\r\n bucketCenter, compressionScaleFactor, compressionScaleRange,\r\n minSphericalHarmonicsCoeff = -DefaultSphericalHarmonics8BitCompressionHalfRange,\r\n maxSphericalHarmonicsCoeff = DefaultSphericalHarmonics8BitCompressionHalfRange) {\r\n\r\n const sphericalHarmonicsComponentsPerSplat = getSphericalHarmonicsComponentCountForDegree(sphericalHarmonicsDegree);\r\n const bytesPerCenter = SplatBuffer.CompressionLevels[compressionLevel].BytesPerCenter;\r\n const bytesPerScale = SplatBuffer.CompressionLevels[compressionLevel].BytesPerScale;\r\n const bytesPerRotation = SplatBuffer.CompressionLevels[compressionLevel].BytesPerRotation;\r\n const bytesPerColor = SplatBuffer.CompressionLevels[compressionLevel].BytesPerColor;\r\n\r\n const centerBase = bufferOffset;\r\n const scaleBase = centerBase + bytesPerCenter;\r\n const rotationBase = scaleBase + bytesPerScale;\r\n const colorBase = rotationBase + bytesPerRotation;\r\n const sphericalHarmonicsBase = colorBase + bytesPerColor;\r\n\r\n if (targetSplat[OFFSET_ROT0] !== undefined) {\r\n tempRot.set(targetSplat[OFFSET_ROT0], targetSplat[OFFSET_ROT1], targetSplat[OFFSET_ROT2], targetSplat[OFFSET_ROT3]);\r\n tempRot.normalize();\r\n } else {\r\n tempRot.set(1.0, 0.0, 0.0, 0.0);\r\n }\r\n\r\n if (targetSplat[OFFSET_SCALE0] !== undefined) {\r\n tempScale.set(targetSplat[OFFSET_SCALE0] || 0,\r\n targetSplat[OFFSET_SCALE1] || 0,\r\n targetSplat[OFFSET_SCALE2] || 0);\r\n } else {\r\n tempScale.set(0, 0, 0);\r\n }\r\n\r\n if (compressionLevel === 0) {\r\n const center = new Float32Array(sectionBuffer, centerBase, SplatBuffer.CenterComponentCount);\r\n const rot = new Float32Array(sectionBuffer, rotationBase, SplatBuffer.RotationComponentCount);\r\n const scale = new Float32Array(sectionBuffer, scaleBase, SplatBuffer.ScaleComponentCount);\r\n\r\n rot.set([tempRot.x, tempRot.y, tempRot.z, tempRot.w]);\r\n scale.set([tempScale.x, tempScale.y, tempScale.z]);\r\n center.set([targetSplat[OFFSET_X], targetSplat[OFFSET_Y], targetSplat[OFFSET_Z]]);\r\n\r\n if (sphericalHarmonicsDegree > 0) {\r\n const shOut = new Float32Array(sectionBuffer, sphericalHarmonicsBase, sphericalHarmonicsComponentsPerSplat);\r\n if (sphericalHarmonicsDegree >= 1) {\r\n for (let s = 0; s < 9; s++) shOut[s] = targetSplat[OFFSET_FRC0 + s] || 0;\r\n if (sphericalHarmonicsDegree >= 2) {\r\n for (let s = 0; s < 15; s++) shOut[s + 9] = targetSplat[OFFSET_FRC9 + s] || 0;\r\n }\r\n }\r\n }\r\n } else {\r\n const center = new Uint16Array(tempCenterBuffer, 0, SplatBuffer.CenterComponentCount);\r\n const rot = new Uint16Array(tempRotationBuffer, 0, SplatBuffer.RotationComponentCount);\r\n const scale = new Uint16Array(tempScaleBuffer, 0, SplatBuffer.ScaleComponentCount);\r\n\r\n rot.set([toHalfFloat(tempRot.x), toHalfFloat(tempRot.y), toHalfFloat(tempRot.z), toHalfFloat(tempRot.w)]);\r\n scale.set([toHalfFloat(tempScale.x), toHalfFloat(tempScale.y), toHalfFloat(tempScale.z)]);\r\n\r\n bucketCenterDelta.set(targetSplat[OFFSET_X], targetSplat[OFFSET_Y], targetSplat[OFFSET_Z]).sub(bucketCenter);\r\n bucketCenterDelta.x = compressPositionOffset(bucketCenterDelta.x, compressionScaleFactor, compressionScaleRange);\r\n bucketCenterDelta.y = compressPositionOffset(bucketCenterDelta.y, compressionScaleFactor, compressionScaleRange);\r\n bucketCenterDelta.z = compressPositionOffset(bucketCenterDelta.z, compressionScaleFactor, compressionScaleRange);\r\n center.set([bucketCenterDelta.x, bucketCenterDelta.y, bucketCenterDelta.z]);\r\n\r\n if (sphericalHarmonicsDegree > 0) {\r\n const SHArrayType = compressionLevel === 1 ? Uint16Array : Uint8Array;\r\n const bytesPerSHComponent = compressionLevel === 1 ? 2 : 1;\r\n const shOut = new SHArrayType(tempSHBuffer, 0, sphericalHarmonicsComponentsPerSplat);\r\n if (sphericalHarmonicsDegree >= 1) {\r\n for (let s = 0; s < 9; s++) {\r\n const srcVal = targetSplat[OFFSET_FRC0 + s] || 0;\r\n shOut[s] = compressionLevel === 1 ? toHalfFloat(srcVal) :\r\n toUint8(srcVal, minSphericalHarmonicsCoeff, maxSphericalHarmonicsCoeff);\r\n }\r\n const degree1ByteCount = 9 * bytesPerSHComponent;\r\n copyBetweenBuffers(shOut.buffer, 0, sectionBuffer, sphericalHarmonicsBase, degree1ByteCount);\r\n if (sphericalHarmonicsDegree >= 2) {\r\n for (let s = 0; s < 15; s++) {\r\n const srcVal = targetSplat[OFFSET_FRC9 + s] || 0;\r\n shOut[s + 9] = compressionLevel === 1 ? toHalfFloat(srcVal) :\r\n toUint8(srcVal, minSphericalHarmonicsCoeff, maxSphericalHarmonicsCoeff);\r\n }\r\n copyBetweenBuffers(shOut.buffer, degree1ByteCount, sectionBuffer,\r\n sphericalHarmonicsBase + degree1ByteCount, 15 * bytesPerSHComponent);\r\n }\r\n }\r\n }\r\n\r\n copyBetweenBuffers(center.buffer, 0, sectionBuffer, centerBase, 6);\r\n copyBetweenBuffers(scale.buffer, 0, sectionBuffer, scaleBase, 6);\r\n copyBetweenBuffers(rot.buffer, 0, sectionBuffer, rotationBase, 8);\r\n }\r\n\r\n const rgba = new Uint8ClampedArray(tempColorBuffer, 0, 4);\r\n rgba.set([targetSplat[OFFSET_FDC0] || 0, targetSplat[OFFSET_FDC1] || 0, targetSplat[OFFSET_FDC2] || 0]);\r\n rgba[3] = targetSplat[OFFSET_OPACITY] || 0;\r\n\r\n copyBetweenBuffers(rgba.buffer, 0, sectionBuffer, colorBase, 4);\r\n };\r\n\r\n }();\r\n\r\n static generateFromUncompressedSplatArrays(splatArrays, minimumAlpha, compressionLevel,\r\n sceneCenter, blockSize, bucketSize, options = []) {\r\n\r\n let shDegree = 0;\r\n for (let sa = 0; sa < splatArrays.length; sa ++) {\r\n const splatArray = splatArrays[sa];\r\n shDegree = Math.max(splatArray.sphericalHarmonicsDegree, shDegree);\r\n }\r\n\r\n let minSphericalHarmonicsCoeff;\r\n let maxSphericalHarmonicsCoeff;\r\n\r\n for (let sa = 0; sa < splatArrays.length; sa ++) {\r\n const splatArray = splatArrays[sa];\r\n for (let i = 0; i < splatArray.splats.length; i++) {\r\n const splat = splatArray.splats[i];\r\n for (let sc = UncompressedSplatArray.OFFSET.FRC0; sc < UncompressedSplatArray.OFFSET.FRC23 && sc < splat.length; sc++) {\r\n if (!minSphericalHarmonicsCoeff || splat[sc] < minSphericalHarmonicsCoeff) {\r\n minSphericalHarmonicsCoeff = splat[sc];\r\n }\r\n if (!maxSphericalHarmonicsCoeff || splat[sc] > maxSphericalHarmonicsCoeff) {\r\n maxSphericalHarmonicsCoeff = splat[sc];\r\n }\r\n }\r\n }\r\n }\r\n\r\n minSphericalHarmonicsCoeff = minSphericalHarmonicsCoeff || -DefaultSphericalHarmonics8BitCompressionHalfRange;\r\n maxSphericalHarmonicsCoeff = maxSphericalHarmonicsCoeff || DefaultSphericalHarmonics8BitCompressionHalfRange;\r\n\r\n const { bytesPerSplat } = SplatBuffer.calculateComponentStorage(compressionLevel, shDegree);\r\n const compressionScaleRange = SplatBuffer.CompressionLevels[compressionLevel].ScaleRange;\r\n\r\n const sectionBuffers = [];\r\n const sectionHeaderBuffers = [];\r\n let totalSplatCount = 0;\r\n\r\n for (let sa = 0; sa < splatArrays.length; sa ++) {\r\n const splatArray = splatArrays[sa];\r\n const validSplats = new UncompressedSplatArray(shDegree);\r\n for (let i = 0; i < splatArray.splatCount; i++) {\r\n const targetSplat = splatArray.splats[i];\r\n if ((targetSplat[UncompressedSplatArray.OFFSET.OPACITY] || 0) >= minimumAlpha) {\r\n validSplats.addSplat(targetSplat);\r\n }\r\n }\r\n\r\n const sectionOptions = options[sa] || {};\r\n const sectionBlockSize = (sectionOptions.blockSizeFactor || 1) * (blockSize || SplatBuffer.BucketBlockSize);\r\n const sectionBucketSize = Math.ceil((sectionOptions.bucketSizeFactor || 1) * (bucketSize || SplatBuffer.BucketSize));\r\n\r\n const bucketInfo = SplatBuffer.computeBucketsForUncompressedSplatArray(validSplats, sectionBlockSize, sectionBucketSize);\r\n const fullBucketCount = bucketInfo.fullBuckets.length;\r\n const partiallyFullBucketLengths = bucketInfo.partiallyFullBuckets.map((bucket) => bucket.splats.length);\r\n const partiallyFilledBucketCount = partiallyFullBucketLengths.length;\r\n const buckets = [...bucketInfo.fullBuckets, ...bucketInfo.partiallyFullBuckets];\r\n\r\n const sectionDataSizeBytes = validSplats.splats.length * bytesPerSplat;\r\n const bucketMetaDataSizeBytes = partiallyFilledBucketCount * 4;\r\n const bucketDataBytes = compressionLevel >= 1 ? buckets.length *\r\n SplatBuffer.BucketStorageSizeBytes + bucketMetaDataSizeBytes : 0;\r\n const sectionSizeBytes = sectionDataSizeBytes + bucketDataBytes;\r\n const sectionBuffer = new ArrayBuffer(sectionSizeBytes);\r\n\r\n const compressionScaleFactor = compressionScaleRange / (sectionBlockSize * 0.5);\r\n const bucketCenter = new Vector3();\r\n\r\n let outSplatCount = 0;\r\n for (let b = 0; b < buckets.length; b++) {\r\n const bucket = buckets[b];\r\n bucketCenter.fromArray(bucket.center);\r\n for (let i = 0; i < bucket.splats.length; i++) {\r\n let row = bucket.splats[i];\r\n const targetSplat = validSplats.splats[row];\r\n const bufferOffset = bucketDataBytes + outSplatCount * bytesPerSplat;\r\n SplatBuffer.writeSplatDataToSectionBuffer(targetSplat, sectionBuffer, bufferOffset, compressionLevel, shDegree,\r\n bucketCenter, compressionScaleFactor, compressionScaleRange,\r\n minSphericalHarmonicsCoeff, maxSphericalHarmonicsCoeff);\r\n outSplatCount++;\r\n }\r\n }\r\n totalSplatCount += outSplatCount;\r\n\r\n if (compressionLevel >= 1) {\r\n const bucketMetaDataArray = new Uint32Array(sectionBuffer, 0, partiallyFullBucketLengths.length * 4);\r\n for (let pfb = 0; pfb < partiallyFullBucketLengths.length; pfb ++) {\r\n bucketMetaDataArray[pfb] = partiallyFullBucketLengths[pfb];\r\n }\r\n const bucketArray = new Float32Array(sectionBuffer, bucketMetaDataSizeBytes,\r\n buckets.length * SplatBuffer.BucketStorageSizeFloats);\r\n for (let b = 0; b < buckets.length; b++) {\r\n const bucket = buckets[b];\r\n const base = b * 3;\r\n bucketArray[base] = bucket.center[0];\r\n bucketArray[base + 1] = bucket.center[1];\r\n bucketArray[base + 2] = bucket.center[2];\r\n }\r\n }\r\n sectionBuffers.push(sectionBuffer);\r\n\r\n const sectionHeaderBuffer = new ArrayBuffer(SplatBuffer.SectionHeaderSizeBytes);\r\n SplatBuffer.writeSectionHeaderToBuffer({\r\n maxSplatCount: outSplatCount,\r\n splatCount: outSplatCount,\r\n bucketSize: sectionBucketSize,\r\n bucketCount: buckets.length,\r\n bucketBlockSize: sectionBlockSize,\r\n compressionScaleRange: compressionScaleRange,\r\n storageSizeBytes: sectionSizeBytes,\r\n fullBucketCount: fullBucketCount,\r\n partiallyFilledBucketCount: partiallyFilledBucketCount,\r\n sphericalHarmonicsDegree: shDegree\r\n }, compressionLevel, sectionHeaderBuffer, 0);\r\n sectionHeaderBuffers.push(sectionHeaderBuffer);\r\n\r\n }\r\n\r\n let sectionsCumulativeSizeBytes = 0;\r\n for (let sectionBuffer of sectionBuffers) sectionsCumulativeSizeBytes += sectionBuffer.byteLength;\r\n const unifiedBufferSize = SplatBuffer.HeaderSizeBytes +\r\n SplatBuffer.SectionHeaderSizeBytes * sectionBuffers.length + sectionsCumulativeSizeBytes;\r\n const unifiedBuffer = new ArrayBuffer(unifiedBufferSize);\r\n\r\n SplatBuffer.writeHeaderToBuffer({\r\n versionMajor: 0,\r\n versionMinor: 1,\r\n maxSectionCount: sectionBuffers.length,\r\n sectionCount: sectionBuffers.length,\r\n maxSplatCount: totalSplatCount,\r\n splatCount: totalSplatCount,\r\n compressionLevel: compressionLevel,\r\n sceneCenter: sceneCenter,\r\n minSphericalHarmonicsCoeff: minSphericalHarmonicsCoeff,\r\n maxSphericalHarmonicsCoeff: maxSphericalHarmonicsCoeff\r\n }, unifiedBuffer);\r\n\r\n let currentUnifiedBase = SplatBuffer.HeaderSizeBytes;\r\n for (let sectionHeaderBuffer of sectionHeaderBuffers) {\r\n new Uint8Array(unifiedBuffer, currentUnifiedBase, SplatBuffer.SectionHeaderSizeBytes).set(new Uint8Array(sectionHeaderBuffer));\r\n currentUnifiedBase += SplatBuffer.SectionHeaderSizeBytes;\r\n }\r\n\r\n for (let sectionBuffer of sectionBuffers) {\r\n new Uint8Array(unifiedBuffer, currentUnifiedBase, sectionBuffer.byteLength).set(new Uint8Array(sectionBuffer));\r\n currentUnifiedBase += sectionBuffer.byteLength;\r\n }\r\n\r\n const splatBuffer = new SplatBuffer(unifiedBuffer);\r\n return splatBuffer;\r\n }\r\n\r\n static computeBucketsForUncompressedSplatArray(splatArray, blockSize, bucketSize) {\r\n let splatCount = splatArray.splatCount;\r\n const halfBlockSize = blockSize / 2.0;\r\n\r\n const min = new Vector3();\r\n const max = new Vector3();\r\n\r\n for (let i = 0; i < splatCount; i++) {\r\n const targetSplat = splatArray.splats[i];\r\n const center = [targetSplat[UncompressedSplatArray.OFFSET.X],\r\n targetSplat[UncompressedSplatArray.OFFSET.Y],\r\n targetSplat[UncompressedSplatArray.OFFSET.Z]];\r\n if (i === 0 || center[0] < min.x) min.x = center[0];\r\n if (i === 0 || center[0] > max.x) max.x = center[0];\r\n if (i === 0 || center[1] < min.y) min.y = center[1];\r\n if (i === 0 || center[1] > max.y) max.y = center[1];\r\n if (i === 0 || center[2] < min.z) min.z = center[2];\r\n if (i === 0 || center[2] > max.z) max.z = center[2];\r\n }\r\n\r\n const dimensions = new Vector3().copy(max).sub(min);\r\n const yBlocks = Math.ceil(dimensions.y / blockSize);\r\n const zBlocks = Math.ceil(dimensions.z / blockSize);\r\n\r\n const blockCenter = new Vector3();\r\n const fullBuckets = [];\r\n const partiallyFullBuckets = {};\r\n\r\n for (let i = 0; i < splatCount; i++) {\r\n const targetSplat = splatArray.splats[i];\r\n const center = [targetSplat[UncompressedSplatArray.OFFSET.X],\r\n targetSplat[UncompressedSplatArray.OFFSET.Y],\r\n targetSplat[UncompressedSplatArray.OFFSET.Z]];\r\n const xBlock = Math.floor((center[0] - min.x) / blockSize);\r\n const yBlock = Math.floor((center[1] - min.y) / blockSize);\r\n const zBlock = Math.floor((center[2] - min.z) / blockSize);\r\n\r\n blockCenter.x = xBlock * blockSize + min.x + halfBlockSize;\r\n blockCenter.y = yBlock * blockSize + min.y + halfBlockSize;\r\n blockCenter.z = zBlock * blockSize + min.z + halfBlockSize;\r\n\r\n const bucketId = xBlock * (yBlocks * zBlocks) + yBlock * zBlocks + zBlock;\r\n let bucket = partiallyFullBuckets[bucketId];\r\n if (!bucket) {\r\n partiallyFullBuckets[bucketId] = bucket = {\r\n 'splats': [],\r\n 'center': blockCenter.toArray()\r\n };\r\n }\r\n\r\n bucket.splats.push(i);\r\n if (bucket.splats.length >= bucketSize) {\r\n fullBuckets.push(bucket);\r\n partiallyFullBuckets[bucketId] = null;\r\n }\r\n }\r\n\r\n const partiallyFullBucketArray = [];\r\n for (let bucketId in partiallyFullBuckets) {\r\n if (Object.hasOwn(partiallyFullBuckets, bucketId)) {\r\n const bucket = partiallyFullBuckets[bucketId];\r\n if (bucket) {\r\n partiallyFullBucketArray.push(bucket);\r\n }\r\n }\r\n }\r\n\r\n return {\r\n 'fullBuckets': fullBuckets,\r\n 'partiallyFullBuckets': partiallyFullBucketArray,\r\n };\r\n }\r\n\r\n}","/**\r\n * SplatPartitioner\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * This file is functionally identical to the original.\r\n * Import paths adjusted for gsplat-flame-avatar package structure.\r\n */\r\n\r\nimport { Vector3 } from 'three';\r\nimport { SplatBuffer } from './SplatBuffer.js';\r\nimport { UncompressedSplatArray } from './UncompressedSplatArray.js';\r\n\r\nexport class SplatPartitioner {\r\n\r\n constructor(sectionCount, sectionFilters, groupingParameters, partitionGenerator) {\r\n this.sectionCount = sectionCount;\r\n this.sectionFilters = sectionFilters;\r\n this.groupingParameters = groupingParameters;\r\n this.partitionGenerator = partitionGenerator;\r\n }\r\n\r\n partitionUncompressedSplatArray(splatArray) {\r\n let groupingParameters;\r\n let sectionCount;\r\n let sectionFilters;\r\n if (this.partitionGenerator) {\r\n const results = this.partitionGenerator(splatArray);\r\n groupingParameters = results.groupingParameters;\r\n sectionCount = results.sectionCount;\r\n sectionFilters = results.sectionFilters;\r\n } else {\r\n groupingParameters = this.groupingParameters;\r\n sectionCount = this.sectionCount;\r\n sectionFilters = this.sectionFilters;\r\n }\r\n\r\n const newArrays = [];\r\n for (let s = 0; s < sectionCount; s++) {\r\n const sectionSplats = new UncompressedSplatArray(splatArray.sphericalHarmonicsDegree);\r\n const sectionFilter = sectionFilters[s];\r\n for (let i = 0; i < splatArray.splatCount; i++) {\r\n if (sectionFilter(i)) {\r\n sectionSplats.addSplat(splatArray.splats[i]);\r\n }\r\n }\r\n newArrays.push(sectionSplats);\r\n }\r\n return {\r\n splatArrays: newArrays,\r\n parameters: groupingParameters\r\n };\r\n }\r\n\r\n static getStandardPartitioner(partitionSize = 0, sceneCenter = new Vector3(),\r\n blockSize = SplatBuffer.BucketBlockSize, bucketSize = SplatBuffer.BucketSize) {\r\n\r\n const partitionGenerator = (splatArray) => {\r\n\r\n const OFFSET_X = UncompressedSplatArray.OFFSET.X;\r\n const OFFSET_Y = UncompressedSplatArray.OFFSET.Y;\r\n const OFFSET_Z = UncompressedSplatArray.OFFSET.Z;\r\n\r\n if (partitionSize <= 0) partitionSize = splatArray.splatCount;\r\n\r\n const center = new Vector3();\r\n const clampDistance = 0.5;\r\n const clampPoint = (point) => {\r\n point.x = Math.floor(point.x / clampDistance) * clampDistance;\r\n point.y = Math.floor(point.y / clampDistance) * clampDistance;\r\n point.z = Math.floor(point.z / clampDistance) * clampDistance;\r\n };\r\n splatArray.splats.forEach((splat) => {\r\n center.set(splat[OFFSET_X], splat[OFFSET_Y], splat[OFFSET_Z]).sub(sceneCenter);\r\n clampPoint(center);\r\n splat.centerDist = center.lengthSq();\r\n });\r\n splatArray.splats.sort((a, b) => {\r\n let centerADist = a.centerDist;\r\n let centerBDist = b.centerDist;\r\n if (centerADist > centerBDist) return 1;\r\n else return -1;\r\n });\r\n\r\n const sectionFilters = [];\r\n const groupingParameters = [];\r\n partitionSize = Math.min(splatArray.splatCount, partitionSize);\r\n const patitionCount = Math.ceil(splatArray.splatCount / partitionSize);\r\n let currentStartSplat = 0;\r\n for (let i = 0; i < patitionCount; i ++) {\r\n let startSplat = currentStartSplat;\r\n sectionFilters.push((splatIndex) => {\r\n return splatIndex >= startSplat && splatIndex < startSplat + partitionSize;\r\n });\r\n groupingParameters.push({\r\n 'blocksSize': blockSize,\r\n 'bucketSize': bucketSize,\r\n });\r\n currentStartSplat += partitionSize;\r\n }\r\n return {\r\n 'sectionCount': sectionFilters.length,\r\n sectionFilters,\r\n groupingParameters\r\n };\r\n };\r\n return new SplatPartitioner(undefined, undefined, undefined, partitionGenerator);\r\n }\r\n}","/**\r\n * SplatBufferGenerator\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * This file is functionally identical to the original.\r\n * Import paths adjusted for gsplat-flame-avatar package structure.\r\n */\r\n\r\nimport { Vector3 } from 'three';\r\nimport { SplatBuffer } from './SplatBuffer.js';\r\nimport { SplatPartitioner } from './SplatPartitioner.js';\r\n\r\nexport class SplatBufferGenerator {\r\n\r\n constructor(splatPartitioner, alphaRemovalThreshold, compressionLevel, sectionSize, sceneCenter, blockSize, bucketSize) {\r\n this.splatPartitioner = splatPartitioner;\r\n this.alphaRemovalThreshold = alphaRemovalThreshold;\r\n this.compressionLevel = compressionLevel;\r\n this.sectionSize = sectionSize;\r\n this.sceneCenter = sceneCenter ? new Vector3().copy(sceneCenter) : undefined;\r\n this.blockSize = blockSize;\r\n this.bucketSize = bucketSize;\r\n }\r\n\r\n generateFromUncompressedSplatArray(splatArray) {\r\n const partitionResults = this.splatPartitioner.partitionUncompressedSplatArray(splatArray);\r\n return SplatBuffer.generateFromUncompressedSplatArrays(partitionResults.splatArrays,\r\n this.alphaRemovalThreshold, this.compressionLevel,\r\n this.sceneCenter, this.blockSize, this.bucketSize,\r\n partitionResults.parameters);\r\n }\r\n\r\n static getStandardGenerator(alphaRemovalThreshold = 1, compressionLevel = 1, sectionSize = 0, sceneCenter = new Vector3(),\r\n blockSize = SplatBuffer.BucketBlockSize, bucketSize = SplatBuffer.BucketSize) {\r\n const splatPartitioner = SplatPartitioner.getStandardPartitioner(sectionSize, sceneCenter, blockSize, bucketSize);\r\n return new SplatBufferGenerator(splatPartitioner, alphaRemovalThreshold, compressionLevel,\r\n sectionSize, sceneCenter, blockSize, bucketSize);\r\n }\r\n}","/**\r\n * PlyParserUtils and related constants\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * Simplified for FLAME avatar - only supports INRIAV1 format.\r\n */\r\n\r\n// Ply format types (simplified - FLAME uses INRIAV1)\r\nexport const PlyFormat = {\r\n 'INRIAV1': 0\r\n};\r\n\r\n// Field size IDs\r\nexport const FieldSizeIdDouble = 0;\r\nexport const FieldSizeIdInt = 1;\r\nexport const FieldSizeIdUInt = 2;\r\nexport const FieldSizeIdFloat = 3;\r\nexport const FieldSizeIdShort = 4;\r\nexport const FieldSizeIdUShort = 5;\r\nexport const FieldSizeIdUChar = 6;\r\n\r\nexport const FieldSizeStringMap = {\r\n 'double': FieldSizeIdDouble,\r\n 'int': FieldSizeIdInt,\r\n 'uint': FieldSizeIdUInt,\r\n 'float': FieldSizeIdFloat,\r\n 'short': FieldSizeIdShort,\r\n 'ushort': FieldSizeIdUShort,\r\n 'uchar': FieldSizeIdUChar,\r\n};\r\n\r\nexport const FieldSize = {\r\n [FieldSizeIdDouble]: 8,\r\n [FieldSizeIdInt]: 4,\r\n [FieldSizeIdUInt]: 4,\r\n [FieldSizeIdFloat]: 4,\r\n [FieldSizeIdShort]: 2,\r\n [FieldSizeIdUShort]: 2,\r\n [FieldSizeIdUChar]: 1,\r\n};\r\n\r\nexport class PlyParserUtils {\r\n\r\n static HeaderEndToken = 'end_header';\r\n\r\n constructor() {\r\n }\r\n\r\n decodeSectionHeader(headerLines, fieldNameIdMap, headerStartLine = 0) {\r\n\r\n const extractedLines = [];\r\n\r\n let processingSection = false;\r\n let headerEndLine = -1;\r\n let vertexCount = 0;\r\n let endOfHeader = false;\r\n let sectionName = null;\r\n\r\n const fieldIds = [];\r\n const fieldTypes = [];\r\n const allFieldNames = [];\r\n const usedFieldNames = [];\r\n const fieldTypesByName = {};\r\n\r\n for (let i = headerStartLine; i < headerLines.length; i++) {\r\n const line = headerLines[i].trim();\r\n if (line.startsWith('element')) {\r\n if (processingSection) {\r\n headerEndLine--;\r\n break;\r\n } else {\r\n processingSection = true;\r\n headerStartLine = i;\r\n headerEndLine = i;\r\n const lineComponents = line.split(' ');\r\n let validComponents = 0;\r\n for (let lineComponent of lineComponents) {\r\n const trimmedComponent = lineComponent.trim();\r\n if (trimmedComponent.length > 0) {\r\n validComponents++;\r\n if (validComponents === 2) {\r\n sectionName = trimmedComponent;\r\n } else if (validComponents === 3) {\r\n vertexCount = parseInt(trimmedComponent);\r\n }\r\n }\r\n }\r\n }\r\n } else if (line.startsWith('property')) {\r\n const fieldMatch = line.match(/(\\w+)\\s+(\\w+)\\s+(\\w+)/);\r\n if (fieldMatch) {\r\n const fieldTypeStr = fieldMatch[2];\r\n const fieldName = fieldMatch[3];\r\n allFieldNames.push(fieldName);\r\n const fieldId = fieldNameIdMap[fieldName];\r\n fieldTypesByName[fieldName] = fieldTypeStr;\r\n const fieldType = FieldSizeStringMap[fieldTypeStr];\r\n if (fieldId !== undefined) {\r\n usedFieldNames.push(fieldName);\r\n fieldIds.push(fieldId);\r\n fieldTypes[fieldId] = fieldType;\r\n }\r\n }\r\n }\r\n if (line === PlyParserUtils.HeaderEndToken) {\r\n endOfHeader = true;\r\n break;\r\n }\r\n if (processingSection) {\r\n extractedLines.push(line);\r\n headerEndLine++;\r\n }\r\n }\r\n\r\n const fieldOffsets = [];\r\n let bytesPerVertex = 0;\r\n for (let fieldName of allFieldNames) {\r\n const fieldType = fieldTypesByName[fieldName];\r\n if (Object.hasOwn(fieldTypesByName, fieldName)) {\r\n const fieldId = fieldNameIdMap[fieldName];\r\n if (fieldId !== undefined) {\r\n fieldOffsets[fieldId] = bytesPerVertex;\r\n }\r\n }\r\n bytesPerVertex += FieldSize[FieldSizeStringMap[fieldType]];\r\n }\r\n\r\n const sphericalHarmonics = this.decodeSphericalHarmonicsFromSectionHeader(allFieldNames, fieldNameIdMap);\r\n\r\n return {\r\n 'headerLines': extractedLines,\r\n 'headerStartLine': headerStartLine,\r\n 'headerEndLine': headerEndLine,\r\n 'fieldTypes': fieldTypes,\r\n 'fieldIds': fieldIds,\r\n 'fieldOffsets': fieldOffsets,\r\n 'bytesPerVertex': bytesPerVertex,\r\n 'vertexCount': vertexCount,\r\n 'dataSizeBytes': bytesPerVertex * vertexCount,\r\n 'endOfHeader': endOfHeader,\r\n 'sectionName': sectionName,\r\n 'sphericalHarmonicsDegree': sphericalHarmonics.degree,\r\n 'sphericalHarmonicsCoefficientsPerChannel': sphericalHarmonics.coefficientsPerChannel,\r\n 'sphericalHarmonicsDegree1Fields': sphericalHarmonics.degree1Fields,\r\n 'sphericalHarmonicsDegree2Fields': sphericalHarmonics.degree2Fields\r\n };\r\n }\r\n\r\n decodeSphericalHarmonicsFromSectionHeader(fieldNames, fieldNameIdMap) {\r\n let sphericalHarmonicsFieldCount = 0;\r\n let coefficientsPerChannel = 0;\r\n for (let fieldName of fieldNames) {\r\n if (fieldName.startsWith('f_rest')) sphericalHarmonicsFieldCount++;\r\n }\r\n coefficientsPerChannel = sphericalHarmonicsFieldCount / 3;\r\n let degree = 0;\r\n if (coefficientsPerChannel >= 3) degree = 1;\r\n if (coefficientsPerChannel >= 8) degree = 2;\r\n\r\n let degree1Fields = [];\r\n let degree2Fields = [];\r\n\r\n for (let rgb = 0; rgb < 3; rgb++) {\r\n if (degree >= 1) {\r\n for (let i = 0; i < 3; i++) {\r\n degree1Fields.push(fieldNameIdMap['f_rest_' + (i + coefficientsPerChannel * rgb)]);\r\n }\r\n }\r\n if (degree >= 2) {\r\n for (let i = 0; i < 5; i++) {\r\n degree2Fields.push(fieldNameIdMap['f_rest_' + (i + coefficientsPerChannel * rgb + 3)]);\r\n }\r\n }\r\n }\r\n\r\n return {\r\n 'degree': degree,\r\n 'coefficientsPerChannel': coefficientsPerChannel,\r\n 'degree1Fields': degree1Fields,\r\n 'degree2Fields': degree2Fields\r\n };\r\n }\r\n\r\n static getHeaderSectionNames(headerLines) {\r\n const sectionNames = [];\r\n for (let headerLine of headerLines) {\r\n if (headerLine.startsWith('element')) {\r\n const lineComponents = headerLine.split(' ');\r\n let validComponents = 0;\r\n for (let lineComponent of lineComponents) {\r\n const trimmedComponent = lineComponent.trim();\r\n if (trimmedComponent.length > 0) {\r\n validComponents++;\r\n if (validComponents === 2) {\r\n sectionNames.push(trimmedComponent);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n return sectionNames;\r\n }\r\n\r\n static checkTextForEndHeader(endHeaderTestText) {\r\n if (endHeaderTestText.includes(PlyParserUtils.HeaderEndToken)) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n static checkBufferForEndHeader(buffer, searchOfset, chunkSize, decoder) {\r\n const endHeaderTestChunk = new Uint8Array(buffer, Math.max(0, searchOfset - chunkSize), chunkSize);\r\n const endHeaderTestText = decoder.decode(endHeaderTestChunk);\r\n return PlyParserUtils.checkTextForEndHeader(endHeaderTestText);\r\n }\r\n\r\n static extractHeaderFromBufferToText(plyBuffer) {\r\n const decoder = new TextDecoder();\r\n let headerOffset = 0;\r\n let headerText = '';\r\n const readChunkSize = 100;\r\n\r\n while (true) {\r\n if (headerOffset + readChunkSize >= plyBuffer.byteLength) {\r\n throw new Error('End of file reached while searching for end of header');\r\n }\r\n const headerChunk = new Uint8Array(plyBuffer, headerOffset, readChunkSize);\r\n headerText += decoder.decode(headerChunk);\r\n headerOffset += readChunkSize;\r\n\r\n if (PlyParserUtils.checkBufferForEndHeader(plyBuffer, headerOffset, readChunkSize * 2, decoder)) {\r\n break;\r\n }\r\n }\r\n\r\n return headerText;\r\n }\r\n\r\n readHeaderFromBuffer(plyBuffer) {\r\n const decoder = new TextDecoder();\r\n let headerOffset = 0;\r\n let headerText = '';\r\n const readChunkSize = 100;\r\n\r\n while (true) {\r\n if (headerOffset + readChunkSize >= plyBuffer.byteLength) {\r\n throw new Error('End of file reached while searching for end of header');\r\n }\r\n const headerChunk = new Uint8Array(plyBuffer, headerOffset, readChunkSize);\r\n headerText += decoder.decode(headerChunk);\r\n headerOffset += readChunkSize;\r\n\r\n if (PlyParserUtils.checkBufferForEndHeader(plyBuffer, headerOffset, readChunkSize * 2, decoder)) {\r\n break;\r\n }\r\n }\r\n\r\n return headerText;\r\n }\r\n\r\n static convertHeaderTextToLines(headerText) {\r\n const headerLines = headerText.split('\\n');\r\n const prunedLines = [];\r\n for (let i = 0; i < headerLines.length; i++) {\r\n const line = headerLines[i].trim();\r\n prunedLines.push(line);\r\n if (line === PlyParserUtils.HeaderEndToken) {\r\n break;\r\n }\r\n }\r\n return prunedLines;\r\n }\r\n\r\n static determineHeaderFormatFromHeaderText(_headerText) {\r\n // Simplified - FLAME avatars always use INRIAV1 format\r\n return PlyFormat.INRIAV1;\r\n }\r\n\r\n static determineHeaderFormatFromPlyBuffer(plyBuffer) {\r\n const headertText = PlyParserUtils.extractHeaderFromBufferToText(plyBuffer);\r\n return PlyParserUtils.determineHeaderFormatFromHeaderText(headertText);\r\n }\r\n\r\n static readVertex(vertexData, header, row, dataOffset, fieldsToRead, rawVertex, normalize = true) {\r\n const offset = row * header.bytesPerVertex + dataOffset;\r\n const fieldOffsets = header.fieldOffsets;\r\n const fieldTypes = header.fieldTypes;\r\n for (let fieldId of fieldsToRead) {\r\n const fieldType = fieldTypes[fieldId];\r\n if (fieldType === FieldSizeIdFloat) {\r\n rawVertex[fieldId] = vertexData.getFloat32(offset + fieldOffsets[fieldId], true);\r\n } else if (fieldType === FieldSizeIdShort) {\r\n rawVertex[fieldId] = vertexData.getInt16(offset + fieldOffsets[fieldId], true);\r\n } else if (fieldType === FieldSizeIdUShort) {\r\n rawVertex[fieldId] = vertexData.getUint16(offset + fieldOffsets[fieldId], true);\r\n } else if (fieldType === FieldSizeIdInt) {\r\n rawVertex[fieldId] = vertexData.getInt32(offset + fieldOffsets[fieldId], true);\r\n } else if (fieldType === FieldSizeIdUInt) {\r\n rawVertex[fieldId] = vertexData.getUint32(offset + fieldOffsets[fieldId], true);\r\n } else if (fieldType === FieldSizeIdUChar) {\r\n if (normalize) {\r\n rawVertex[fieldId] = vertexData.getUint8(offset + fieldOffsets[fieldId]) / 255.0;\r\n } else {\r\n rawVertex[fieldId] = vertexData.getUint8(offset + fieldOffsets[fieldId]);\r\n }\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * INRIAV1PlyParser\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * Import paths adjusted for gsplat-flame-avatar package structure.\r\n */\r\n\r\nimport { Quaternion } from 'three';\r\nimport { UncompressedSplatArray } from '../buffers/UncompressedSplatArray.js';\r\nimport { SplatBuffer } from '../buffers/SplatBuffer.js';\r\nimport { PlyParserUtils } from './PlyParserUtils.js';\r\nimport { clamp } from '../utils/Util.js';\r\n\r\nconst BaseFieldNamesToRead = ['scale_0', 'scale_1', 'scale_2', 'rot_0', 'rot_1', 'rot_2', 'rot_3', 'x', 'y', 'z',\r\n 'f_dc_0', 'f_dc_1', 'f_dc_2', 'opacity', 'red', 'green', 'blue', 'f_rest_0'];\r\n\r\nconst BaseFieldsToReadIndexes = BaseFieldNamesToRead.map((e, i) => i);\r\n\r\nconst [\r\n SCALE_0, SCALE_1, SCALE_2, ROT_0, ROT_1, ROT_2, ROT_3, X, Y, Z, F_DC_0, F_DC_1, F_DC_2, OPACITY, RED, GREEN, BLUE, F_REST_0\r\n ] = BaseFieldsToReadIndexes;\r\n\r\nexport class INRIAV1PlyParser {\r\n\r\n constructor() {\r\n this.plyParserutils = new PlyParserUtils();\r\n }\r\n\r\n decodeHeaderLines(headerLines) {\r\n\r\n let shLineCount = 0;\r\n headerLines.forEach((line) => {\r\n if (line.includes('f_rest_')) shLineCount++;\r\n });\r\n\r\n let shFieldsToReadCount = 0;\r\n if (shLineCount >= 45) {\r\n shFieldsToReadCount = 45;\r\n } else if (shLineCount >= 24) {\r\n shFieldsToReadCount = 24;\r\n } else if (shLineCount >= 9) {\r\n shFieldsToReadCount = 9;\r\n }\r\n\r\n const shFieldIndexesToMap = Array.from(Array(Math.max(shFieldsToReadCount - 1, 0)));\r\n let shRemainingFieldNamesToRead = shFieldIndexesToMap.map((element, index) => `f_rest_${index + 1}`);\r\n\r\n const fieldNamesToRead = [...BaseFieldNamesToRead, ...shRemainingFieldNamesToRead];\r\n const fieldsToReadIndexes = fieldNamesToRead.map((e, i) => i);\r\n\r\n const fieldNameIdMap = fieldsToReadIndexes.reduce((acc, element) => {\r\n acc[fieldNamesToRead[element]] = element;\r\n return acc;\r\n }, {});\r\n const header = this.plyParserutils.decodeSectionHeader(headerLines, fieldNameIdMap, 0);\r\n header.splatCount = header.vertexCount;\r\n header.bytesPerSplat = header.bytesPerVertex;\r\n header.fieldsToReadIndexes = fieldsToReadIndexes;\r\n return header;\r\n }\r\n\r\n decodeHeaderText(headerText) {\r\n const headerLines = PlyParserUtils.convertHeaderTextToLines(headerText);\r\n const header = this.decodeHeaderLines(headerLines);\r\n header.headerText = headerText;\r\n header.headerSizeBytes = headerText.indexOf(PlyParserUtils.HeaderEndToken) + PlyParserUtils.HeaderEndToken.length + 1;\r\n return header;\r\n }\r\n\r\n decodeHeaderFromBuffer(plyBuffer) {\r\n const headerText = this.plyParserutils.readHeaderFromBuffer(plyBuffer);\r\n return this.decodeHeaderText(headerText);\r\n }\r\n\r\n findSplatData(plyBuffer, header) {\r\n return new DataView(plyBuffer, header.headerSizeBytes);\r\n }\r\n\r\n parseToUncompressedSplatBufferSection(header, fromSplat, toSplat, splatData, splatDataOffset,\r\n toBuffer, toOffset, outSphericalHarmonicsDegree = 0) {\r\n outSphericalHarmonicsDegree = Math.min(outSphericalHarmonicsDegree, header.sphericalHarmonicsDegree);\r\n const outBytesPerSplat = SplatBuffer.CompressionLevels[0].SphericalHarmonicsDegrees[outSphericalHarmonicsDegree].BytesPerSplat;\r\n\r\n for (let i = fromSplat; i <= toSplat; i++) {\r\n const parsedSplat = INRIAV1PlyParser.parseToUncompressedSplat(splatData, i, header,\r\n splatDataOffset, outSphericalHarmonicsDegree);\r\n const outBase = i * outBytesPerSplat + toOffset;\r\n SplatBuffer.writeSplatDataToSectionBuffer(parsedSplat, toBuffer, outBase, 0, outSphericalHarmonicsDegree);\r\n }\r\n }\r\n\r\n parseToUncompressedSplatArraySection(header, fromSplat, toSplat, splatData, splatDataOffset,\r\n splatArray, outSphericalHarmonicsDegree = 0) {\r\n outSphericalHarmonicsDegree = Math.min(outSphericalHarmonicsDegree, header.sphericalHarmonicsDegree);\r\n for (let i = fromSplat; i <= toSplat; i++) {\r\n const parsedSplat = INRIAV1PlyParser.parseToUncompressedSplat(splatData, i, header,\r\n splatDataOffset, outSphericalHarmonicsDegree);\r\n splatArray.addSplat(parsedSplat);\r\n }\r\n }\r\n\r\n decodeSectionSplatData(sectionSplatData, splatCount, sectionHeader, outSphericalHarmonicsDegree) {\r\n outSphericalHarmonicsDegree = Math.min(outSphericalHarmonicsDegree, sectionHeader.sphericalHarmonicsDegree);\r\n const splatArray = new UncompressedSplatArray(outSphericalHarmonicsDegree);\r\n for (let row = 0; row < splatCount; row++) {\r\n const newSplat = INRIAV1PlyParser.parseToUncompressedSplat(sectionSplatData, row, sectionHeader,\r\n 0, outSphericalHarmonicsDegree);\r\n splatArray.addSplat(newSplat);\r\n }\r\n return splatArray;\r\n }\r\n\r\n static parseToUncompressedSplat = function() {\r\n\r\n let rawSplat = [];\r\n const tempRotation = new Quaternion();\r\n\r\n const OFFSET_X = UncompressedSplatArray.OFFSET.X;\r\n const OFFSET_Y = UncompressedSplatArray.OFFSET.Y;\r\n const OFFSET_Z = UncompressedSplatArray.OFFSET.Z;\r\n\r\n const OFFSET_SCALE0 = UncompressedSplatArray.OFFSET.SCALE0;\r\n const OFFSET_SCALE1 = UncompressedSplatArray.OFFSET.SCALE1;\r\n const OFFSET_SCALE2 = UncompressedSplatArray.OFFSET.SCALE2;\r\n\r\n const OFFSET_ROTATION0 = UncompressedSplatArray.OFFSET.ROTATION0;\r\n const OFFSET_ROTATION1 = UncompressedSplatArray.OFFSET.ROTATION1;\r\n const OFFSET_ROTATION2 = UncompressedSplatArray.OFFSET.ROTATION2;\r\n const OFFSET_ROTATION3 = UncompressedSplatArray.OFFSET.ROTATION3;\r\n\r\n const OFFSET_FDC0 = UncompressedSplatArray.OFFSET.FDC0;\r\n const OFFSET_FDC1 = UncompressedSplatArray.OFFSET.FDC1;\r\n const OFFSET_FDC2 = UncompressedSplatArray.OFFSET.FDC2;\r\n const OFFSET_OPACITY = UncompressedSplatArray.OFFSET.OPACITY;\r\n\r\n const OFFSET_FRC = [];\r\n\r\n for (let i = 0; i < 45; i++) {\r\n OFFSET_FRC[i] = UncompressedSplatArray.OFFSET.FRC0 + i;\r\n }\r\n\r\n return function(splatData, row, header, splatDataOffset = 0, outSphericalHarmonicsDegree = 0) {\r\n outSphericalHarmonicsDegree = Math.min(outSphericalHarmonicsDegree, header.sphericalHarmonicsDegree);\r\n INRIAV1PlyParser.readSplat(splatData, header, row, splatDataOffset, rawSplat);\r\n const newSplat = UncompressedSplatArray.createSplat(outSphericalHarmonicsDegree);\r\n if (rawSplat[SCALE_0] !== undefined) {\r\n newSplat[OFFSET_SCALE0] = Math.exp(rawSplat[SCALE_0]);\r\n newSplat[OFFSET_SCALE1] = Math.exp(rawSplat[SCALE_1]);\r\n newSplat[OFFSET_SCALE2] = Math.exp(rawSplat[SCALE_2]);\r\n } else {\r\n newSplat[OFFSET_SCALE0] = 0.01;\r\n newSplat[OFFSET_SCALE1] = 0.01;\r\n newSplat[OFFSET_SCALE2] = 0.01;\r\n }\r\n\r\n if (rawSplat[F_DC_0] !== undefined) {\r\n const SH_C0 = 0.28209479177387814;\r\n newSplat[OFFSET_FDC0] = rawSplat[F_DC_0] * 255;\r\n newSplat[OFFSET_FDC1] = rawSplat[F_DC_1] * 255;\r\n newSplat[OFFSET_FDC2] = rawSplat[F_DC_2] * 255;\r\n } else if (rawSplat[RED] !== undefined) {\r\n newSplat[OFFSET_FDC0] = rawSplat[RED] * 255;\r\n newSplat[OFFSET_FDC1] = rawSplat[GREEN] * 255;\r\n newSplat[OFFSET_FDC2] = rawSplat[BLUE] * 255;\r\n } else {\r\n newSplat[OFFSET_FDC0] = 0;\r\n newSplat[OFFSET_FDC1] = 0;\r\n newSplat[OFFSET_FDC2] = 0;\r\n }\r\n\r\n if (rawSplat[OPACITY] !== undefined) {\r\n newSplat[OFFSET_OPACITY] = (1 / (1 + Math.exp(-rawSplat[OPACITY]))) * 255;\r\n }\r\n\r\n newSplat[OFFSET_FDC0] = clamp(Math.floor(newSplat[OFFSET_FDC0]), 0, 255);\r\n newSplat[OFFSET_FDC1] = clamp(Math.floor(newSplat[OFFSET_FDC1]), 0, 255);\r\n newSplat[OFFSET_FDC2] = clamp(Math.floor(newSplat[OFFSET_FDC2]), 0, 255);\r\n newSplat[OFFSET_OPACITY] = clamp(Math.floor(newSplat[OFFSET_OPACITY]), 0, 255);\r\n\r\n if (outSphericalHarmonicsDegree >= 1) {\r\n if (rawSplat[F_REST_0] !== undefined) {\r\n for (let i = 0; i < 9; i++) {\r\n newSplat[OFFSET_FRC[i]] = rawSplat[header.sphericalHarmonicsDegree1Fields[i]];\r\n }\r\n if (outSphericalHarmonicsDegree >= 2) {\r\n for (let i = 0; i < 15; i++) {\r\n newSplat[OFFSET_FRC[9 + i]] = rawSplat[header.sphericalHarmonicsDegree2Fields[i]];\r\n }\r\n }\r\n }\r\n }\r\n\r\n tempRotation.set(rawSplat[ROT_0], rawSplat[ROT_1], rawSplat[ROT_2], rawSplat[ROT_3]);\r\n tempRotation.normalize();\r\n\r\n newSplat[OFFSET_ROTATION0] = tempRotation.x;\r\n newSplat[OFFSET_ROTATION1] = tempRotation.y;\r\n newSplat[OFFSET_ROTATION2] = tempRotation.z;\r\n newSplat[OFFSET_ROTATION3] = tempRotation.w;\r\n\r\n newSplat[OFFSET_X] = rawSplat[X];\r\n newSplat[OFFSET_Y] = rawSplat[Y];\r\n newSplat[OFFSET_Z] = rawSplat[Z];\r\n\r\n return newSplat;\r\n };\r\n\r\n }();\r\n\r\n static readSplat(splatData, header, row, dataOffset, rawSplat) {\r\n return PlyParserUtils.readVertex(splatData, header, row, dataOffset, header.fieldsToReadIndexes, rawSplat, true);\r\n }\r\n\r\n parseToUncompressedSplatArray(plyBuffer, outSphericalHarmonicsDegree = 0) {\r\n const header = this.decodeHeaderFromBuffer(plyBuffer);\r\n const splatCount = header.splatCount;\r\n const splatData = this.findSplatData(plyBuffer, header);\r\n const splatArray = this.decodeSectionSplatData(splatData, splatCount, header, outSphericalHarmonicsDegree);\r\n return splatArray;\r\n }\r\n}\r\n","/**\r\n * PlyParser\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * Simplified for FLAME avatar - only supports INRIAV1 PLY format.\r\n */\r\n\r\nimport { INRIAV1PlyParser } from './INRIAV1PlyParser.js';\r\n\r\nexport class PlyParser {\r\n\r\n static parseToUncompressedSplatArray(plyBuffer, outSphericalHarmonicsDegree = 0) {\r\n // FLAME avatars use INRIAV1 PLY format\r\n return new INRIAV1PlyParser().parseToUncompressedSplatArray(plyBuffer, outSphericalHarmonicsDegree);\r\n }\r\n\r\n}","/**\r\n * PlyLoader - Loads and parses PLY format Gaussian Splat files\r\n *\r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n *\r\n * Simplified for FLAME avatar - only supports INRIAV1 PLY format.\r\n * Provides both progressive streaming and file-based loading.\r\n */\r\n\r\nimport { Vector3 } from 'three';\r\nimport { SplatBuffer } from '../buffers/SplatBuffer.js';\r\nimport { UncompressedSplatArray } from '../buffers/UncompressedSplatArray.js';\r\nimport { SplatBufferGenerator } from '../buffers/SplatBufferGenerator.js';\r\nimport { PlyParser } from './PlyParser.js';\r\nimport { PlyParserUtils } from './PlyParserUtils.js';\r\nimport { INRIAV1PlyParser } from './INRIAV1PlyParser.js';\r\nimport { Constants, InternalLoadType, LoaderStatus } from '../enums/EngineConstants.js';\r\nimport { fetchWithProgress, delayedExecute, nativePromiseWithExtractedComponents } from '../utils/Util.js';\r\nimport { getLogger } from '../utils/Logger.js';\r\nimport { ValidationError, NetworkError, ParseError, AssetLoadError } from '../errors/index.js';\r\nimport { validateUrl, validateCallback, validateArrayBuffer } from '../utils/ValidationUtils.js';\r\n\r\nconst logger = getLogger('PlyLoader');\r\n\r\n/**\r\n * Store data chunks into a single ArrayBuffer\r\n *\r\n * Combines multiple downloaded chunks into a contiguous buffer for parsing.\r\n * Reallocates buffer if needed to fit all chunks.\r\n *\r\n * @private\r\n * @param {Array<{data: Uint8Array, sizeBytes: number}>} chunks - Array of data chunks\r\n * @param {ArrayBuffer} [buffer] - Existing buffer to reuse (will reallocate if too small)\r\n * @returns {ArrayBuffer} Buffer containing all chunk data\r\n */\r\nfunction storeChunksInBuffer(chunks, buffer) {\r\n let inBytes = 0;\r\n for (let chunk of chunks) {\r\n inBytes += chunk.sizeBytes;\r\n }\r\n\r\n // Reallocate if buffer doesn't exist or is too small\r\n if (!buffer || buffer.byteLength < inBytes) {\r\n buffer = new ArrayBuffer(inBytes);\r\n }\r\n\r\n // Copy all chunks into buffer sequentially\r\n let offset = 0;\r\n for (let chunk of chunks) {\r\n new Uint8Array(buffer, offset, chunk.sizeBytes).set(chunk.data);\r\n offset += chunk.sizeBytes;\r\n }\r\n\r\n return buffer;\r\n}\r\n\r\n/**\r\n * Finalize splat data into a SplatBuffer\r\n *\r\n * Converts UncompressedSplatArray into final optimized SplatBuffer format.\r\n * Applies compression and optimization if requested.\r\n *\r\n * @private\r\n * @param {UncompressedSplatArray} splatData - Parsed splat data\r\n * @param {boolean} optimizeSplatData - Whether to optimize/compress the data\r\n * @param {number} minimumAlpha - Minimum alpha threshold for splat culling\r\n * @param {number} compressionLevel - Compression level (0-2)\r\n * @param {number} sectionSize - Section size for partitioning\r\n * @param {Vector3} sceneCenter - Center point of the scene\r\n * @param {number} blockSize - Block size for spatial partitioning\r\n * @param {number} bucketSize - Bucket size for sorting\r\n * @returns {SplatBuffer} Finalized splat buffer ready for rendering\r\n * @throws {ParseError} If splat data is invalid or finalization fails\r\n */\r\nfunction finalizeSplatData(splatData, optimizeSplatData, minimumAlpha, compressionLevel, sectionSize, sceneCenter, blockSize, bucketSize) {\r\n try {\r\n if (optimizeSplatData) {\r\n const splatBufferGenerator = SplatBufferGenerator.getStandardGenerator(\r\n minimumAlpha,\r\n compressionLevel,\r\n sectionSize,\r\n sceneCenter,\r\n blockSize,\r\n bucketSize\r\n );\r\n return splatBufferGenerator.generateFromUncompressedSplatArray(splatData);\r\n } else {\r\n return SplatBuffer.generateFromUncompressedSplatArrays([splatData], minimumAlpha, 0, new Vector3());\r\n }\r\n } catch (error) {\r\n throw new ParseError(\r\n `Failed to finalize splat data: ${error.message}`,\r\n 'splatData',\r\n error\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * PlyLoader - Loads and parses PLY format Gaussian Splat files\r\n *\r\n * Supports both progressive streaming and complete file loading.\r\n * Optimized for INRIAV1 PLY format used in FLAME avatars.\r\n */\r\nexport class PlyLoader {\r\n\r\n /**\r\n * Load PLY file from URL with progressive streaming support\r\n *\r\n * Downloads and parses PLY data progressively, enabling render during load.\r\n * Supports both direct-to-buffer and array-based loading modes.\r\n *\r\n * @static\r\n * @param {string} fileName - URL to the PLY file\r\n * @param {Function} [onProgress] - Progress callback (percent, percentLabel, status)\r\n * @param {boolean} [loadDirectoToSplatBuffer=false] - Load directly to SplatBuffer (faster but less flexible)\r\n * @param {Function} [onProgressiveLoadSectionProgress] - Callback for progressive section updates\r\n * @param {number} [minimumAlpha=1] - Minimum alpha threshold for splat culling\r\n * @param {number} [compressionLevel=0] - Compression level (0=none, 1=medium, 2=high)\r\n * @param {boolean} [optimizeSplatData=true] - Whether to optimize/compress splat data\r\n * @param {number} [outSphericalHarmonicsDegree=0] - Spherical harmonics degree (0-3)\r\n * @param {Object} [headers] - HTTP headers for fetch request\r\n * @param {number} [sectionSize] - Section size for partitioning\r\n * @param {Vector3} [sceneCenter] - Center point of the scene\r\n * @param {number} [blockSize] - Block size for spatial partitioning\r\n * @param {number} [bucketSize] - Bucket size for sorting\r\n * @returns {Promise<SplatBuffer>} Loaded and parsed splat buffer\r\n * @throws {ValidationError} If parameters are invalid\r\n * @throws {NetworkError} If file download fails\r\n * @throws {ParseError} If PLY parsing fails\r\n * @throws {AssetLoadError} If asset loading fails\r\n */\r\n static loadFromURL(fileName, onProgress, loadDirectoToSplatBuffer, onProgressiveLoadSectionProgress,\r\n minimumAlpha, compressionLevel, optimizeSplatData = true, outSphericalHarmonicsDegree = 0,\r\n headers, sectionSize, sceneCenter, blockSize, bucketSize) {\r\n\r\n // Validate required parameters\r\n try {\r\n validateUrl(fileName);\r\n } catch (error) {\r\n logger.error('Invalid URL provided to loadFromURL', { fileName, error });\r\n throw error;\r\n }\r\n\r\n // Validate optional callbacks\r\n if (onProgress) {\r\n validateCallback(onProgress, 'onProgress', false);\r\n }\r\n if (onProgressiveLoadSectionProgress) {\r\n validateCallback(onProgressiveLoadSectionProgress, 'onProgressiveLoadSectionProgress', false);\r\n }\r\n\r\n logger.info('Loading PLY from URL', { fileName, optimizeSplatData, outSphericalHarmonicsDegree });\r\n\r\n let internalLoadType = loadDirectoToSplatBuffer ? InternalLoadType.DirectToSplatBuffer : InternalLoadType.DirectToSplatArray;\r\n if (optimizeSplatData) internalLoadType = InternalLoadType.DirectToSplatArray;\r\n\r\n const directLoadSectionSizeBytes = Constants.ProgressiveLoadSectionSize;\r\n const splatDataOffsetBytes = SplatBuffer.HeaderSizeBytes + SplatBuffer.SectionHeaderSizeBytes;\r\n const sectionCount = 1;\r\n\r\n let directLoadBufferIn;\r\n let directLoadBufferOut;\r\n let directLoadSplatBuffer;\r\n let maxSplatCount = 0;\r\n let splatCount = 0;\r\n\r\n let headerLoaded = false;\r\n let readyToLoadSplatData = false;\r\n\r\n const loadPromise = nativePromiseWithExtractedComponents();\r\n\r\n let numBytesStreamed = 0;\r\n let numBytesParsed = 0;\r\n let numBytesDownloaded = 0;\r\n let headerText = '';\r\n let header = null;\r\n let chunks = [];\r\n\r\n let standardLoadUncompressedSplatArray;\r\n\r\n const textDecoder = new TextDecoder();\r\n const inriaV1PlyParser = new INRIAV1PlyParser();\r\n\r\n const localOnProgress = (percent, percentLabel, chunkData) => {\r\n const loadComplete = percent >= 100;\r\n\r\n if (chunkData) {\r\n chunks.push({\r\n 'data': chunkData,\r\n 'sizeBytes': chunkData.byteLength,\r\n 'startBytes': numBytesDownloaded,\r\n 'endBytes': numBytesDownloaded + chunkData.byteLength\r\n });\r\n numBytesDownloaded += chunkData.byteLength;\r\n }\r\n\r\n if (internalLoadType === InternalLoadType.DownloadBeforeProcessing) {\r\n if (loadComplete) {\r\n loadPromise.resolve(chunks);\r\n }\r\n } else {\r\n if (!headerLoaded) {\r\n headerText += textDecoder.decode(chunkData);\r\n if (PlyParserUtils.checkTextForEndHeader(headerText)) {\r\n // FLAME avatars use INRIAV1 format - parse header\r\n try {\r\n header = inriaV1PlyParser.decodeHeaderText(headerText);\r\n maxSplatCount = header.splatCount;\r\n readyToLoadSplatData = true;\r\n\r\n logger.debug('PLY header decoded', {\r\n splatCount: maxSplatCount,\r\n sphericalHarmonicsDegree: header.sphericalHarmonicsDegree\r\n });\r\n\r\n outSphericalHarmonicsDegree = Math.min(outSphericalHarmonicsDegree, header.sphericalHarmonicsDegree);\r\n } catch (error) {\r\n const parseError = new ParseError(\r\n `Failed to decode PLY header: ${error.message}`,\r\n 'headerText',\r\n error\r\n );\r\n logger.error('Header parsing failed', parseError);\r\n loadPromise.reject(parseError);\r\n return;\r\n }\r\n\r\n const shDescriptor = SplatBuffer.CompressionLevels[0].SphericalHarmonicsDegrees[outSphericalHarmonicsDegree];\r\n const splatBufferSizeBytes = splatDataOffsetBytes + shDescriptor.BytesPerSplat * maxSplatCount;\r\n\r\n if (internalLoadType === InternalLoadType.DirectToSplatBuffer) {\r\n directLoadBufferOut = new ArrayBuffer(splatBufferSizeBytes);\r\n SplatBuffer.writeHeaderToBuffer({\r\n versionMajor: SplatBuffer.CurrentMajorVersion,\r\n versionMinor: SplatBuffer.CurrentMinorVersion,\r\n maxSectionCount: sectionCount,\r\n sectionCount: sectionCount,\r\n maxSplatCount: maxSplatCount,\r\n splatCount: splatCount,\r\n compressionLevel: 0,\r\n sceneCenter: new Vector3()\r\n }, directLoadBufferOut);\r\n } else {\r\n standardLoadUncompressedSplatArray = new UncompressedSplatArray(outSphericalHarmonicsDegree);\r\n }\r\n\r\n numBytesStreamed = header.headerSizeBytes;\r\n numBytesParsed = header.headerSizeBytes;\r\n headerLoaded = true;\r\n }\r\n }\r\n\r\n if (headerLoaded && readyToLoadSplatData) {\r\n\r\n if (chunks.length > 0) {\r\n\r\n directLoadBufferIn = storeChunksInBuffer(chunks, directLoadBufferIn);\r\n\r\n const bytesLoadedSinceLastStreamedSection = numBytesDownloaded - numBytesStreamed;\r\n if (bytesLoadedSinceLastStreamedSection > directLoadSectionSizeBytes || loadComplete) {\r\n const numBytesToProcess = numBytesDownloaded - numBytesParsed;\r\n const addedSplatCount = Math.floor(numBytesToProcess / header.bytesPerSplat);\r\n const numBytesToParse = addedSplatCount * header.bytesPerSplat;\r\n const numBytesLeftOver = numBytesToProcess - numBytesToParse;\r\n const newSplatCount = splatCount + addedSplatCount;\r\n const parsedDataViewOffset = numBytesParsed - chunks[0].startBytes;\r\n const dataToParse = new DataView(directLoadBufferIn, parsedDataViewOffset, numBytesToParse);\r\n\r\n const shDescriptor = SplatBuffer.CompressionLevels[0].SphericalHarmonicsDegrees[outSphericalHarmonicsDegree];\r\n const outOffset = splatCount * shDescriptor.BytesPerSplat + splatDataOffsetBytes;\r\n\r\n // Parse splat data with error handling\r\n try {\r\n if (internalLoadType === InternalLoadType.DirectToSplatBuffer) {\r\n inriaV1PlyParser.parseToUncompressedSplatBufferSection(\r\n header, 0, addedSplatCount - 1, dataToParse,\r\n 0, directLoadBufferOut, outOffset,\r\n outSphericalHarmonicsDegree\r\n );\r\n } else {\r\n inriaV1PlyParser.parseToUncompressedSplatArraySection(\r\n header, 0, addedSplatCount - 1, dataToParse,\r\n 0, standardLoadUncompressedSplatArray,\r\n outSphericalHarmonicsDegree\r\n );\r\n }\r\n } catch (error) {\r\n const parseError = new ParseError(\r\n `Failed to parse splat data section: ${error.message}`,\r\n 'splatData',\r\n error\r\n );\r\n logger.error('Splat data parsing failed', { splatCount, addedSplatCount, error });\r\n loadPromise.reject(parseError);\r\n return;\r\n }\r\n\r\n splatCount = newSplatCount;\r\n\r\n if (internalLoadType === InternalLoadType.DirectToSplatBuffer) {\r\n if (!directLoadSplatBuffer) {\r\n SplatBuffer.writeSectionHeaderToBuffer({\r\n maxSplatCount: maxSplatCount,\r\n splatCount: splatCount,\r\n bucketSize: 0,\r\n bucketCount: 0,\r\n bucketBlockSize: 0,\r\n compressionScaleRange: 0,\r\n storageSizeBytes: 0,\r\n fullBucketCount: 0,\r\n partiallyFilledBucketCount: 0,\r\n sphericalHarmonicsDegree: outSphericalHarmonicsDegree\r\n }, 0, directLoadBufferOut, SplatBuffer.HeaderSizeBytes);\r\n directLoadSplatBuffer = new SplatBuffer(directLoadBufferOut, false);\r\n }\r\n directLoadSplatBuffer.updateLoadedCounts(1, splatCount);\r\n if (onProgressiveLoadSectionProgress) {\r\n onProgressiveLoadSectionProgress(directLoadSplatBuffer, loadComplete);\r\n }\r\n }\r\n\r\n numBytesStreamed += directLoadSectionSizeBytes;\r\n numBytesParsed += numBytesToParse;\r\n\r\n if (numBytesLeftOver === 0) {\r\n chunks = [];\r\n } else {\r\n let keepChunks = [];\r\n let keepSize = 0;\r\n for (let i = chunks.length - 1; i >= 0; i--) {\r\n const chunk = chunks[i];\r\n keepSize += chunk.sizeBytes;\r\n keepChunks.unshift(chunk);\r\n if (keepSize >= numBytesLeftOver) break;\r\n }\r\n chunks = keepChunks;\r\n }\r\n }\r\n }\r\n\r\n if (loadComplete) {\r\n if (internalLoadType === InternalLoadType.DirectToSplatBuffer) {\r\n loadPromise.resolve(directLoadSplatBuffer);\r\n } else {\r\n loadPromise.resolve(standardLoadUncompressedSplatArray);\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Progress callback with error isolation\r\n if (onProgress) {\r\n try {\r\n onProgress(percent, percentLabel, LoaderStatus.Downloading);\r\n } catch (error) {\r\n logger.warn('Error in onProgress callback', error);\r\n }\r\n }\r\n };\r\n\r\n // Initial progress callback\r\n if (onProgress) {\r\n try {\r\n onProgress(0, '0%', LoaderStatus.Downloading);\r\n } catch (error) {\r\n logger.warn('Error in onProgress callback', error);\r\n }\r\n }\r\n\r\n // Fetch and process the PLY file\r\n return fetchWithProgress(fileName, localOnProgress, false, headers)\r\n .then(() => {\r\n if (onProgress) {\r\n try {\r\n onProgress(0, '0%', LoaderStatus.Processing);\r\n } catch (error) {\r\n logger.warn('Error in onProgress callback', error);\r\n }\r\n }\r\n return loadPromise.promise;\r\n })\r\n .then((splatData) => {\r\n if (onProgress) {\r\n try {\r\n onProgress(100, '100%', LoaderStatus.Done);\r\n } catch (error) {\r\n logger.warn('Error in onProgress callback', error);\r\n }\r\n }\r\n\r\n logger.debug('PLY data loaded successfully', {\r\n internalLoadType,\r\n splatCount: splatData?.splatCount || 'unknown'\r\n });\r\n\r\n // Process based on load type\r\n if (internalLoadType === InternalLoadType.DownloadBeforeProcessing) {\r\n const chunkDatas = chunks.map((chunk) => chunk.data);\r\n return new Blob(chunkDatas).arrayBuffer()\r\n .then((plyFileData) => {\r\n return PlyLoader.loadFromFileData(\r\n plyFileData, minimumAlpha, compressionLevel, optimizeSplatData,\r\n outSphericalHarmonicsDegree, sectionSize, sceneCenter, blockSize, bucketSize\r\n );\r\n })\r\n .catch((error) => {\r\n throw new AssetLoadError(\r\n `Failed to process downloaded PLY data: ${error.message}`,\r\n fileName,\r\n error\r\n );\r\n });\r\n } else if (internalLoadType === InternalLoadType.DirectToSplatBuffer) {\r\n return splatData;\r\n } else {\r\n return delayedExecute(() => {\r\n return finalizeSplatData(\r\n splatData, optimizeSplatData, minimumAlpha, compressionLevel,\r\n sectionSize, sceneCenter, blockSize, bucketSize\r\n );\r\n });\r\n }\r\n })\r\n .catch((error) => {\r\n // Re-throw custom errors as-is\r\n if (error instanceof ValidationError ||\r\n error instanceof NetworkError ||\r\n error instanceof ParseError ||\r\n error instanceof AssetLoadError) {\r\n logger.error('PLY loading failed', { fileName, errorCode: error.code });\r\n throw error;\r\n }\r\n\r\n // Wrap unexpected errors\r\n logger.error('Unexpected error loading PLY', { fileName, error });\r\n throw new AssetLoadError(\r\n `Unexpected error loading PLY file: ${error.message}`,\r\n fileName,\r\n error\r\n );\r\n });\r\n }\r\n\r\n /**\r\n * Load PLY file from raw ArrayBuffer data\r\n *\r\n * Parses PLY data that has already been downloaded. Useful for loading\r\n * from local files or when data is provided directly.\r\n *\r\n * @static\r\n * @param {ArrayBuffer} plyFileData - Raw PLY file data as ArrayBuffer\r\n * @param {number} [minimumAlpha=1] - Minimum alpha threshold for splat culling\r\n * @param {number} [compressionLevel=0] - Compression level (0=none, 1=medium, 2=high)\r\n * @param {boolean} [optimizeSplatData=true] - Whether to optimize/compress splat data\r\n * @param {number} [outSphericalHarmonicsDegree=0] - Spherical harmonics degree (0-3)\r\n * @param {number} [sectionSize] - Section size for partitioning\r\n * @param {Vector3} [sceneCenter] - Center point of the scene\r\n * @param {number} [blockSize] - Block size for spatial partitioning\r\n * @param {number} [bucketSize] - Bucket size for sorting\r\n * @returns {Promise<SplatBuffer>} Parsed and finalized splat buffer\r\n * @throws {ValidationError} If plyFileData is invalid\r\n * @throws {ParseError} If parsing fails\r\n */\r\n static loadFromFileData(plyFileData, minimumAlpha, compressionLevel, optimizeSplatData, outSphericalHarmonicsDegree = 0,\r\n sectionSize, sceneCenter, blockSize, bucketSize) {\r\n // Validate input\r\n try {\r\n validateArrayBuffer(plyFileData, 'plyFileData');\r\n } catch (error) {\r\n logger.error('Invalid PLY file data', error);\r\n return Promise.reject(error);\r\n }\r\n\r\n logger.info('Loading PLY from file data', {\r\n sizeBytes: plyFileData.byteLength,\r\n optimizeSplatData,\r\n outSphericalHarmonicsDegree\r\n });\r\n\r\n return delayedExecute(() => {\r\n try {\r\n return PlyParser.parseToUncompressedSplatArray(plyFileData, outSphericalHarmonicsDegree);\r\n } catch (error) {\r\n throw new ParseError(\r\n `Failed to parse PLY file data: ${error.message}`,\r\n 'plyFileData',\r\n error\r\n );\r\n }\r\n })\r\n .then((splatArray) => {\r\n logger.debug('PLY parsed successfully', {\r\n splatCount: splatArray?.splatCount || 'unknown'\r\n });\r\n\r\n return finalizeSplatData(\r\n splatArray, optimizeSplatData, minimumAlpha, compressionLevel,\r\n sectionSize, sceneCenter, blockSize, bucketSize\r\n );\r\n })\r\n .catch((error) => {\r\n // Re-throw custom errors as-is\r\n if (error instanceof ValidationError || error instanceof ParseError) {\r\n logger.error('PLY file data loading failed', { errorCode: error.code });\r\n throw error;\r\n }\r\n\r\n // Wrap unexpected errors\r\n logger.error('Unexpected error loading PLY from file data', error);\r\n throw new ParseError(\r\n `Unexpected error parsing PLY data: ${error.message}`,\r\n 'plyFileData',\r\n error\r\n );\r\n });\r\n }\r\n}","/**\r\n * Ray\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * This file is functionally identical to the original.\r\n */\r\n\r\nimport * as THREE from 'three';\r\n\r\nconst VectorRight = new THREE.Vector3(1, 0, 0);\r\nconst VectorUp = new THREE.Vector3(0, 1, 0);\r\nconst VectorBackward = new THREE.Vector3(0, 0, 1);\r\n\r\nexport class Ray {\r\n\r\n constructor(origin = new THREE.Vector3(), direction = new THREE.Vector3()) {\r\n this.origin = new THREE.Vector3();\r\n this.direction = new THREE.Vector3();\r\n this.setParameters(origin, direction);\r\n }\r\n\r\n setParameters(origin, direction) {\r\n this.origin.copy(origin);\r\n this.direction.copy(direction).normalize();\r\n }\r\n\r\n boxContainsPoint(box, point, epsilon) {\r\n return point.x < box.min.x - epsilon || point.x > box.max.x + epsilon ||\r\n point.y < box.min.y - epsilon || point.y > box.max.y + epsilon ||\r\n point.z < box.min.z - epsilon || point.z > box.max.z + epsilon ? false : true;\r\n }\r\n\r\n intersectBox = function() {\r\n\r\n const planeIntersectionPoint = new THREE.Vector3();\r\n const planeIntersectionPointArray = [];\r\n const originArray = [];\r\n const directionArray = [];\r\n\r\n return function(box, outHit) {\r\n\r\n originArray[0] = this.origin.x;\r\n originArray[1] = this.origin.y;\r\n originArray[2] = this.origin.z;\r\n directionArray[0] = this.direction.x;\r\n directionArray[1] = this.direction.y;\r\n directionArray[2] = this.direction.z;\r\n\r\n if (this.boxContainsPoint(box, this.origin, 0.0001)) {\r\n if (outHit) {\r\n outHit.origin.copy(this.origin);\r\n outHit.normal.set(0, 0, 0);\r\n outHit.distance = -1;\r\n }\r\n return true;\r\n }\r\n\r\n for (let i = 0; i < 3; i++) {\r\n if (directionArray[i] == 0.0) continue;\r\n\r\n const hitNormal = i == 0 ? VectorRight : i == 1 ? VectorUp : VectorBackward;\r\n const extremeVec = directionArray[i] < 0 ? box.max : box.min;\r\n let multiplier = -Math.sign(directionArray[i]);\r\n planeIntersectionPointArray[0] = i == 0 ? extremeVec.x : i == 1 ? extremeVec.y : extremeVec.z;\r\n let toSide = planeIntersectionPointArray[0] - originArray[i];\r\n\r\n if (toSide * multiplier < 0) {\r\n const idx1 = (i + 1) % 3;\r\n const idx2 = (i + 2) % 3;\r\n planeIntersectionPointArray[2] = directionArray[idx1] / directionArray[i] * toSide + originArray[idx1];\r\n planeIntersectionPointArray[1] = directionArray[idx2] / directionArray[i] * toSide + originArray[idx2];\r\n planeIntersectionPoint.set(planeIntersectionPointArray[i],\r\n planeIntersectionPointArray[idx2],\r\n planeIntersectionPointArray[idx1]);\r\n if (this.boxContainsPoint(box, planeIntersectionPoint, 0.0001)) {\r\n if (outHit) {\r\n outHit.origin.copy(planeIntersectionPoint);\r\n outHit.normal.copy(hitNormal).multiplyScalar(multiplier);\r\n outHit.distance = planeIntersectionPoint.sub(this.origin).length();\r\n }\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n return false;\r\n };\r\n\r\n }();\r\n\r\n intersectSphere = function() {\r\n\r\n const toSphereCenterVec = new THREE.Vector3();\r\n\r\n return function(center, radius, outHit) {\r\n toSphereCenterVec.copy(center).sub(this.origin);\r\n const toClosestApproach = toSphereCenterVec.dot(this.direction);\r\n const toClosestApproachSq = toClosestApproach * toClosestApproach;\r\n const toSphereCenterSq = toSphereCenterVec.dot(toSphereCenterVec);\r\n const diffSq = toSphereCenterSq - toClosestApproachSq;\r\n const radiusSq = radius * radius;\r\n\r\n if (diffSq > radiusSq) return false;\r\n\r\n const thc = Math.sqrt(radiusSq - diffSq);\r\n const t0 = toClosestApproach - thc;\r\n const t1 = toClosestApproach + thc;\r\n\r\n if (t1 < 0) return false;\r\n let t = t0 < 0 ? t1 : t0;\r\n\r\n if (outHit) {\r\n outHit.origin.copy(this.origin).addScaledVector(this.direction, t);\r\n outHit.normal.copy(outHit.origin).sub(center).normalize();\r\n outHit.distance = t;\r\n }\r\n return true;\r\n };\r\n\r\n }();\r\n}\r\n","/**\r\n * Hit\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * This file is functionally identical to the original.\r\n */\r\n\r\nimport * as THREE from 'three';\r\n\r\nexport class Hit {\r\n\r\n constructor() {\r\n this.origin = new THREE.Vector3();\r\n this.normal = new THREE.Vector3();\r\n this.distance = 0;\r\n this.splatIndex = 0;\r\n }\r\n\r\n set(origin, normal, distance, splatIndex) {\r\n this.origin.copy(origin);\r\n this.normal.copy(normal);\r\n this.distance = distance;\r\n this.splatIndex = splatIndex;\r\n }\r\n\r\n clone() {\r\n const hitClone = new Hit();\r\n hitClone.origin.copy(this.origin);\r\n hitClone.normal.copy(this.normal);\r\n hitClone.distance = this.distance;\r\n hitClone.splatIndex = this.splatIndex;\r\n return hitClone;\r\n }\r\n\r\n}\r\n","/**\r\n * Raycaster\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * Import paths adjusted for gsplat-flame-avatar package structure.\r\n */\r\n\r\nimport * as THREE from 'three';\r\nimport { Ray } from './Ray.js';\r\nimport { Hit } from './Hit.js';\r\nimport { SplatRenderMode } from '../enums/index.js';\r\n\r\nexport class Raycaster {\r\n\r\n constructor(origin, direction, raycastAgainstTrueSplatEllipsoid = false) {\r\n this.ray = new Ray(origin, direction);\r\n this.raycastAgainstTrueSplatEllipsoid = raycastAgainstTrueSplatEllipsoid;\r\n }\r\n\r\n setFromCameraAndScreenPosition = function() {\r\n\r\n const ndcCoords = new THREE.Vector2();\r\n\r\n return function(camera, screenPosition, screenDimensions) {\r\n ndcCoords.x = screenPosition.x / screenDimensions.x * 2.0 - 1.0;\r\n ndcCoords.y = (screenDimensions.y - screenPosition.y) / screenDimensions.y * 2.0 - 1.0;\r\n if (camera.isPerspectiveCamera) {\r\n this.ray.origin.setFromMatrixPosition(camera.matrixWorld);\r\n this.ray.direction.set(ndcCoords.x, ndcCoords.y, 0.5 ).unproject(camera).sub(this.ray.origin).normalize();\r\n this.camera = camera;\r\n } else if (camera.isOrthographicCamera) {\r\n this.ray.origin.set(ndcCoords.x, ndcCoords.y,\r\n (camera.near + camera.far) / (camera.near - camera.far)).unproject(camera);\r\n this.ray.direction.set(0, 0, -1).transformDirection(camera.matrixWorld);\r\n this.camera = camera;\r\n } else {\r\n throw new Error('Raycaster::setFromCameraAndScreenPosition() -> Unsupported camera type');\r\n }\r\n };\r\n\r\n }();\r\n\r\n intersectSplatMesh = function() {\r\n\r\n const toLocal = new THREE.Matrix4();\r\n const fromLocal = new THREE.Matrix4();\r\n const sceneTransform = new THREE.Matrix4();\r\n const localRay = new Ray();\r\n const tempPoint = new THREE.Vector3();\r\n\r\n return function(splatMesh, outHits = []) {\r\n const splatTree = splatMesh.getSplatTree();\r\n\r\n if (!splatTree) return;\r\n\r\n for (let s = 0; s < splatTree.subTrees.length; s++) {\r\n const subTree = splatTree.subTrees[s];\r\n\r\n fromLocal.copy(splatMesh.matrixWorld);\r\n if (splatMesh.dynamicMode) {\r\n splatMesh.getSceneTransform(s, sceneTransform);\r\n fromLocal.multiply(sceneTransform);\r\n }\r\n toLocal.copy(fromLocal).invert();\r\n\r\n localRay.origin.copy(this.ray.origin).applyMatrix4(toLocal);\r\n localRay.direction.copy(this.ray.origin).add(this.ray.direction);\r\n localRay.direction.applyMatrix4(toLocal).sub(localRay.origin).normalize();\r\n\r\n const outHitsForSubTree = [];\r\n if (subTree.rootNode) {\r\n this.castRayAtSplatTreeNode(localRay, splatTree, subTree.rootNode, outHitsForSubTree);\r\n }\r\n\r\n outHitsForSubTree.forEach((hit) => {\r\n hit.origin.applyMatrix4(fromLocal);\r\n hit.normal.applyMatrix4(fromLocal).normalize();\r\n hit.distance = tempPoint.copy(hit.origin).sub(this.ray.origin).length();\r\n });\r\n\r\n outHits.push(...outHitsForSubTree);\r\n }\r\n\r\n outHits.sort((a, b) => {\r\n if (a.distance > b.distance) return 1;\r\n else return -1;\r\n });\r\n\r\n return outHits;\r\n };\r\n\r\n }();\r\n\r\n castRayAtSplatTreeNode = function() {\r\n\r\n const tempColor = new THREE.Vector4();\r\n const tempCenter = new THREE.Vector3();\r\n const tempScale = new THREE.Vector3();\r\n const tempRotation = new THREE.Quaternion();\r\n const tempHit = new Hit();\r\n const scaleEpsilon = 0.0000001;\r\n\r\n const origin = new THREE.Vector3(0, 0, 0);\r\n const uniformScaleMatrix = new THREE.Matrix4();\r\n const scaleMatrix = new THREE.Matrix4();\r\n const rotationMatrix = new THREE.Matrix4();\r\n const toSphereSpace = new THREE.Matrix4();\r\n const fromSphereSpace = new THREE.Matrix4();\r\n const tempRay = new Ray();\r\n\r\n return function(ray, splatTree, node, outHits = []) {\r\n if (!ray.intersectBox(node.boundingBox)) {\r\n return;\r\n }\r\n if (node.data && node.data.indexes && node.data.indexes.length > 0) {\r\n for (let i = 0; i < node.data.indexes.length; i++) {\r\n\r\n const splatGlobalIndex = node.data.indexes[i];\r\n const splatSceneIndex = splatTree.splatMesh.getSceneIndexForSplat(splatGlobalIndex);\r\n const splatScene = splatTree.splatMesh.getScene(splatSceneIndex);\r\n if (!splatScene.visible) continue;\r\n\r\n splatTree.splatMesh.getSplatColor(splatGlobalIndex, tempColor);\r\n splatTree.splatMesh.getSplatCenter(splatGlobalIndex, tempCenter);\r\n splatTree.splatMesh.getSplatScaleAndRotation(splatGlobalIndex, tempScale, tempRotation);\r\n\r\n if (tempScale.x <= scaleEpsilon || tempScale.y <= scaleEpsilon ||\r\n splatTree.splatMesh.splatRenderMode === SplatRenderMode.ThreeD && tempScale.z <= scaleEpsilon) {\r\n continue;\r\n }\r\n\r\n if (!this.raycastAgainstTrueSplatEllipsoid) {\r\n let radius = (tempScale.x + tempScale.y);\r\n let componentCount = 2;\r\n if (splatTree.splatMesh.splatRenderMode === SplatRenderMode.ThreeD) {\r\n radius += tempScale.z;\r\n componentCount = 3;\r\n }\r\n radius = radius / componentCount;\r\n if (ray.intersectSphere(tempCenter, radius, tempHit)) {\r\n const hitClone = tempHit.clone();\r\n hitClone.splatIndex = splatGlobalIndex;\r\n outHits.push(hitClone);\r\n }\r\n } else {\r\n scaleMatrix.makeScale(tempScale.x, tempScale.y, tempScale.z);\r\n rotationMatrix.makeRotationFromQuaternion(tempRotation);\r\n const uniformScale = Math.log10(tempColor.w) * 2.0;\r\n uniformScaleMatrix.makeScale(uniformScale, uniformScale, uniformScale);\r\n fromSphereSpace.copy(uniformScaleMatrix).multiply(rotationMatrix).multiply(scaleMatrix);\r\n toSphereSpace.copy(fromSphereSpace).invert();\r\n tempRay.origin.copy(ray.origin).sub(tempCenter).applyMatrix4(toSphereSpace);\r\n tempRay.direction.copy(ray.origin).add(ray.direction).sub(tempCenter);\r\n tempRay.direction.applyMatrix4(toSphereSpace).sub(tempRay.origin).normalize();\r\n if (tempRay.intersectSphere(origin, 1.0, tempHit)) {\r\n const hitClone = tempHit.clone();\r\n hitClone.splatIndex = splatGlobalIndex;\r\n hitClone.origin.applyMatrix4(fromSphereSpace).add(tempCenter);\r\n outHits.push(hitClone);\r\n }\r\n }\r\n }\r\n }\r\n if (node.children && node.children.length > 0) {\r\n for (let child of node.children) {\r\n this.castRayAtSplatTreeNode(ray, splatTree, child, outHits);\r\n }\r\n }\r\n return outHits;\r\n };\r\n\r\n }();\r\n}\r\n","/**\r\n * SortWorker\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * Handles GPU-based sorting using WebAssembly\r\n */\r\n\r\nimport { isIOS, getIOSSemever } from '../utils/Util.js';\r\nimport { Constants } from '../enums/EngineConstants.js';\r\n\r\n// Base64 encoded WASM modules for sorting\r\nconst SorterWasm = \"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\";\r\n\r\nconst SorterWasmNoSIMD = \"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\";\r\n\r\nconst SorterWasmNonShared = \"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\";\r\n\r\nconst SorterWasmNoSIMDNonShared = \"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\";\r\n\r\n/**\r\n * Sort worker function that runs in a Web Worker\r\n * Handles the actual sorting logic using WebAssembly\r\n */\r\nfunction sortWorker(self) {\r\n\r\n let wasmInstance;\r\n let wasmMemory;\r\n let useSharedMemory;\r\n let integerBasedSort;\r\n let dynamicMode;\r\n let splatCount;\r\n let indexesToSortOffset;\r\n let sortedIndexesOffset;\r\n let sceneIndexesOffset;\r\n let transformsOffset;\r\n let precomputedDistancesOffset;\r\n let mappedDistancesOffset;\r\n let frequenciesOffset;\r\n let centersOffset;\r\n let modelViewProjOffset;\r\n let countsZero;\r\n let sortedIndexesOut;\r\n let distanceMapRange;\r\n let uploadedSplatCount;\r\n let Constants;\r\n\r\n function sort(splatSortCount, splatRenderCount, modelViewProj,\r\n usePrecomputedDistances, copyIndexesToSort, copyPrecomputedDistances, copyTransforms) {\r\n const sortStartTime = performance.now();\r\n\r\n if (!useSharedMemory) {\r\n const indexesToSort = new Uint32Array(wasmMemory, indexesToSortOffset, copyIndexesToSort.byteLength / Constants.BytesPerInt);\r\n indexesToSort.set(copyIndexesToSort);\r\n const transforms = new Float32Array(wasmMemory, transformsOffset, copyTransforms.byteLength / Constants.BytesPerFloat);\r\n transforms.set(copyTransforms);\r\n if (usePrecomputedDistances) {\r\n let precomputedDistances;\r\n if (integerBasedSort) {\r\n precomputedDistances = new Int32Array(wasmMemory, precomputedDistancesOffset,\r\n copyPrecomputedDistances.byteLength / Constants.BytesPerInt);\r\n } else {\r\n precomputedDistances = new Float32Array(wasmMemory, precomputedDistancesOffset,\r\n copyPrecomputedDistances.byteLength / Constants.BytesPerFloat);\r\n }\r\n precomputedDistances.set(copyPrecomputedDistances);\r\n }\r\n }\r\n\r\n if (!countsZero) countsZero = new Uint32Array(distanceMapRange);\r\n new Float32Array(wasmMemory, modelViewProjOffset, 16).set(modelViewProj);\r\n new Uint32Array(wasmMemory, frequenciesOffset, distanceMapRange).set(countsZero);\r\n wasmInstance.exports.sortIndexes(indexesToSortOffset, centersOffset, precomputedDistancesOffset,\r\n mappedDistancesOffset, frequenciesOffset, modelViewProjOffset,\r\n sortedIndexesOffset, sceneIndexesOffset, transformsOffset, distanceMapRange,\r\n splatSortCount, splatRenderCount, splatCount, usePrecomputedDistances, integerBasedSort,\r\n dynamicMode);\r\n\r\n const sortMessage = {\r\n 'sortDone': true,\r\n 'splatSortCount': splatSortCount,\r\n 'splatRenderCount': splatRenderCount,\r\n 'sortTime': 0\r\n };\r\n if (!useSharedMemory) {\r\n const sortedIndexes = new Uint32Array(wasmMemory, sortedIndexesOffset, splatRenderCount);\r\n if (!sortedIndexesOut || sortedIndexesOut.length < splatRenderCount) {\r\n sortedIndexesOut = new Uint32Array(splatRenderCount);\r\n }\r\n sortedIndexesOut.set(sortedIndexes);\r\n sortMessage.sortedIndexes = sortedIndexesOut;\r\n }\r\n const sortEndTime = performance.now();\r\n\r\n sortMessage.sortTime = sortEndTime - sortStartTime;\r\n\r\n self.postMessage(sortMessage);\r\n }\r\n\r\n self.onmessage = (e) => {\r\n if (e.data.centers) {\r\n let centers = e.data.centers;\r\n let sceneIndexes = e.data.sceneIndexes;\r\n if (integerBasedSort) {\r\n new Int32Array(wasmMemory, centersOffset + e.data.range.from * Constants.BytesPerInt * 4,\r\n e.data.range.count * 4).set(new Int32Array(centers));\r\n } else {\r\n new Float32Array(wasmMemory, centersOffset + e.data.range.from * Constants.BytesPerFloat * 4,\r\n e.data.range.count * 4).set(new Float32Array(centers));\r\n }\r\n if (dynamicMode) {\r\n new Uint32Array(wasmMemory, sceneIndexesOffset + e.data.range.from * 4,\r\n e.data.range.count).set(new Uint32Array(sceneIndexes));\r\n }\r\n uploadedSplatCount = e.data.range.from + e.data.range.count;\r\n } else if (e.data.sort) {\r\n const renderCount = Math.min(e.data.sort.splatRenderCount || 0, uploadedSplatCount);\r\n const sortCount = Math.min(e.data.sort.splatSortCount || 0, uploadedSplatCount);\r\n const usePrecomputedDistances = e.data.sort.usePrecomputedDistances;\r\n\r\n let copyIndexesToSort;\r\n let copyPrecomputedDistances;\r\n let copyTransforms;\r\n if (!useSharedMemory) {\r\n copyIndexesToSort = e.data.sort.indexesToSort;\r\n copyTransforms = e.data.sort.transforms;\r\n if (usePrecomputedDistances) copyPrecomputedDistances = e.data.sort.precomputedDistances;\r\n }\r\n sort(sortCount, renderCount, e.data.sort.modelViewProj, usePrecomputedDistances,\r\n copyIndexesToSort, copyPrecomputedDistances, copyTransforms);\r\n } else if (e.data.init) {\r\n // Yep, this is super hacky and gross :(\r\n Constants = e.data.init.Constants;\r\n\r\n splatCount = e.data.init.splatCount;\r\n useSharedMemory = e.data.init.useSharedMemory;\r\n integerBasedSort = e.data.init.integerBasedSort;\r\n dynamicMode = e.data.init.dynamicMode;\r\n distanceMapRange = e.data.init.distanceMapRange;\r\n uploadedSplatCount = 0;\r\n\r\n const CENTERS_BYTES_PER_ENTRY = integerBasedSort ? (Constants.BytesPerInt * 4) : (Constants.BytesPerFloat * 4);\r\n\r\n const sorterWasmBytes = new Uint8Array(e.data.init.sorterWasmBytes);\r\n\r\n const matrixSize = 16 * Constants.BytesPerFloat;\r\n const memoryRequiredForIndexesToSort = splatCount * Constants.BytesPerInt;\r\n const memoryRequiredForCenters = splatCount * CENTERS_BYTES_PER_ENTRY;\r\n const memoryRequiredForModelViewProjectionMatrix = matrixSize;\r\n const memoryRequiredForPrecomputedDistances = integerBasedSort ?\r\n (splatCount * Constants.BytesPerInt) : (splatCount * Constants.BytesPerFloat);\r\n const memoryRequiredForMappedDistances = splatCount * Constants.BytesPerInt;\r\n const memoryRequiredForSortedIndexes = splatCount * Constants.BytesPerInt;\r\n const memoryRequiredForIntermediateSortBuffers = integerBasedSort ? (distanceMapRange * Constants.BytesPerInt * 2) :\r\n (distanceMapRange * Constants.BytesPerFloat * 2);\r\n const memoryRequiredforTransformIndexes = dynamicMode ? (splatCount * Constants.BytesPerInt) : 0;\r\n const memoryRequiredforTransforms = dynamicMode ? (Constants.MaxScenes * matrixSize) : 0;\r\n const extraMemory = Constants.MemoryPageSize * 32;\r\n\r\n const totalRequiredMemory = memoryRequiredForIndexesToSort +\r\n memoryRequiredForCenters +\r\n memoryRequiredForModelViewProjectionMatrix +\r\n memoryRequiredForPrecomputedDistances +\r\n memoryRequiredForMappedDistances +\r\n memoryRequiredForIntermediateSortBuffers +\r\n memoryRequiredForSortedIndexes +\r\n memoryRequiredforTransformIndexes +\r\n memoryRequiredforTransforms +\r\n extraMemory;\r\n const totalPagesRequired = Math.floor(totalRequiredMemory / Constants.MemoryPageSize ) + 1;\r\n const sorterWasmImport = {\r\n module: {},\r\n env: {\r\n memory: new WebAssembly.Memory({\r\n initial: totalPagesRequired,\r\n maximum: totalPagesRequired,\r\n shared: true,\r\n }),\r\n }\r\n };\r\n WebAssembly.compile(sorterWasmBytes)\r\n .then((wasmModule) => {\r\n return WebAssembly.instantiate(wasmModule, sorterWasmImport);\r\n })\r\n .then((instance) => {\r\n wasmInstance = instance;\r\n indexesToSortOffset = 0;\r\n centersOffset = indexesToSortOffset + memoryRequiredForIndexesToSort;\r\n modelViewProjOffset = centersOffset + memoryRequiredForCenters;\r\n precomputedDistancesOffset = modelViewProjOffset + memoryRequiredForModelViewProjectionMatrix;\r\n mappedDistancesOffset = precomputedDistancesOffset + memoryRequiredForPrecomputedDistances;\r\n frequenciesOffset = mappedDistancesOffset + memoryRequiredForMappedDistances;\r\n sortedIndexesOffset = frequenciesOffset + memoryRequiredForIntermediateSortBuffers;\r\n sceneIndexesOffset = sortedIndexesOffset + memoryRequiredForSortedIndexes;\r\n transformsOffset = sceneIndexesOffset + memoryRequiredforTransformIndexes;\r\n wasmMemory = sorterWasmImport.env.memory.buffer;\r\n if (useSharedMemory) {\r\n self.postMessage({\r\n 'sortSetupPhase1Complete': true,\r\n 'indexesToSortBuffer': wasmMemory,\r\n 'indexesToSortOffset': indexesToSortOffset,\r\n 'sortedIndexesBuffer': wasmMemory,\r\n 'sortedIndexesOffset': sortedIndexesOffset,\r\n 'precomputedDistancesBuffer': wasmMemory,\r\n 'precomputedDistancesOffset': precomputedDistancesOffset,\r\n 'transformsBuffer': wasmMemory,\r\n 'transformsOffset': transformsOffset\r\n });\r\n } else {\r\n self.postMessage({\r\n 'sortSetupPhase1Complete': true\r\n });\r\n }\r\n });\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Creates a sort worker for GPU-based sorting\r\n * @param {number} splatCount - Number of splats to sort\r\n * @param {boolean} useSharedMemory - Whether to use shared memory\r\n * @param {boolean} enableSIMDInSort - Whether to enable SIMD instructions\r\n * @param {boolean} integerBasedSort - Whether to use integer-based sorting\r\n * @param {boolean} dynamicMode - Whether dynamic mode is enabled\r\n * @param {number} splatSortDistanceMapPrecision - Precision for distance map\r\n * @returns {Worker} The created sort worker\r\n */\r\nexport function createSortWorker(splatCount, useSharedMemory, enableSIMDInSort, integerBasedSort, dynamicMode,\r\n splatSortDistanceMapPrecision = Constants.DefaultSplatSortDistanceMapPrecision) {\r\n const worker = new Worker(\r\n URL.createObjectURL(\r\n new Blob(['(', sortWorker.toString(), ')(self)'], {\r\n type: 'application/javascript',\r\n }),\r\n ),\r\n );\r\n\r\n let sourceWasm = SorterWasm;\r\n\r\n // iOS makes choosing the right WebAssembly configuration tricky :(\r\n const iOSSemVer = isIOS() ? getIOSSemever() : null;\r\n if (!enableSIMDInSort && !useSharedMemory) {\r\n sourceWasm = SorterWasmNoSIMD;\r\n // Testing on various devices has shown that even when shared memory is disabled, the WASM module with shared\r\n // memory can still be used most of the time -- the exception seems to be iOS devices below 16.4\r\n if (iOSSemVer && iOSSemVer.major <= 16 && iOSSemVer.minor < 4) {\r\n sourceWasm = SorterWasmNoSIMDNonShared;\r\n }\r\n } else if (!enableSIMDInSort) {\r\n sourceWasm = SorterWasmNoSIMD;\r\n } else if (!useSharedMemory) {\r\n // Same issue with shared memory as above on iOS devices\r\n if (iOSSemVer && iOSSemVer.major <= 16 && iOSSemVer.minor < 4) {\r\n sourceWasm = SorterWasmNonShared;\r\n }\r\n }\r\n\r\n const sorterWasmBinaryString = atob(sourceWasm);\r\n const sorterWasmBytes = new Uint8Array(sorterWasmBinaryString.length);\r\n for (let i = 0; i < sorterWasmBinaryString.length; i++) {\r\n sorterWasmBytes[i] = sorterWasmBinaryString.charCodeAt(i);\r\n }\r\n\r\n worker.postMessage({\r\n 'init': {\r\n 'sorterWasmBytes': sorterWasmBytes.buffer,\r\n 'splatCount': splatCount,\r\n 'useSharedMemory': useSharedMemory,\r\n 'integerBasedSort': integerBasedSort,\r\n 'dynamicMode': dynamicMode,\r\n 'distanceMapRange': 1 << splatSortDistanceMapPrecision,\r\n // Super hacky\r\n 'Constants': {\r\n 'BytesPerFloat': Constants.BytesPerFloat,\r\n 'BytesPerInt': Constants.BytesPerInt,\r\n 'MemoryPageSize': Constants.MemoryPageSize,\r\n 'MaxScenes': Constants.MaxScenes\r\n }\r\n }\r\n });\r\n return worker;\r\n}\r\n","/**\r\n * Viewer\r\n * \r\n * Based on @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * HEAVILY MODIFIED for FLAME avatar support:\r\n * - Added FLAME head model integration\r\n * - Extended with expression/pose controls\r\n * - Additional rendering pipeline modifications\r\n * - Additional ~900 lines of FLAME-specific code\r\n */\r\n\r\nimport { Bone, DynamicDrawUsage, InstancedBufferAttribute, MathUtils, Matrix4, OrthographicCamera, PerspectiveCamera, Quaternion, Scene, Skeleton, Vector2, Vector3, WebGLRenderer } from 'three';\r\nimport {\r\n getCurrentTime,\r\n clamp,\r\n delayedExecute,\r\n isIOS,\r\n getIOSSemever,\r\n Semver,\r\n fetchWithProgress,\r\n nativePromiseWithExtractedComponents,\r\n abortablePromiseWithExtractedComponents,\r\n disposeAllMeshes,\r\n AbortedPromiseError\r\n} from '../utils/Util.js';\r\nimport { getLogger } from '../utils/Logger.js';\r\n\r\nconst logger = getLogger('Viewer');\r\nimport { RenderMode } from '../enums/RenderMode.js';\r\nimport { LogLevel } from '../enums/LogLevel.js';\r\nimport { SplatRenderMode } from '../enums/SplatRenderMode.js';\r\nimport { SceneFormat, sceneFormatFromPath } from '../enums/SceneFormat.js';\r\nimport { SceneRevealMode } from '../enums/SceneRevealMode.js';\r\nimport { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';\r\nimport { SplatMesh } from './SplatMesh.js';\r\nimport { SplatScene } from './SplatScene.js';\r\nimport { DirectLoadError } from '../loaders/DirectLoadError.js';\r\nimport { PlyLoader } from '../loaders/PlyLoader.js';\r\nimport { Raycaster } from '../raycaster/Raycaster.js';\r\nimport { createSortWorker } from '../worker/SortWorker.js';\r\nimport { \r\n SCENE_FADEIN_RATE_FAST,\r\n SCENE_FADEIN_RATE_GRADUAL,\r\n THREE_CAMERA_FOV,\r\n MINIMUM_DISTANCE_TO_NEW_FOCAL_POINT,\r\n CONSECUTIVE_RENDERED_FRAMES_FOR_FPS_CALCULATION,\r\n MIN_SPLAT_COUNT_TO_SHOW_SPLAT_TREE_LOADING_SPINNER,\r\n FOCUS_MARKER_FADE_IN_SPEED,\r\n FOCUS_MARKER_FADE_OUT_SPEED,\r\n Constants,\r\n LoaderStatus\r\n} from '../enums/EngineConstants.js';\r\n\r\n// UI components - stub implementations for now\r\nclass LoadingSpinner {\r\n constructor(msg, container) { this.tasks = []; }\r\n show() {}\r\n hide() {}\r\n setContainer(c) {}\r\n addTask(msg) { return this.tasks.push(msg); }\r\n removeTask(id) {}\r\n removeAllTasks() { this.tasks = []; }\r\n setMessageForTask(id, msg) {}\r\n}\r\n\r\nclass LoadingProgressBar {\r\n constructor(container) {}\r\n show() {}\r\n hide() {}\r\n setContainer(c) {}\r\n setProgress(p) {}\r\n}\r\n\r\nclass SceneHelper {\r\n constructor(scene) { \r\n this.scene = scene; \r\n this.meshCursor = null;\r\n this.meshCursorVisible = false;\r\n this.focusMarker = null;\r\n this.focusMarkerOpacity = 0;\r\n this.controlPlane = null;\r\n this.controlPlaneVisible = false;\r\n }\r\n setupMeshCursor() {}\r\n setupFocusMarker() {}\r\n setupControlPlane() {}\r\n updateMeshCursor(pos, active) {}\r\n updateFocusMarker(target, camera, renderDimensions) {}\r\n updateControlPlane(cam, ctrl) {}\r\n setFocusMarkerVisibility(v) {}\r\n setFocusMarkerOpacity(o) { this.focusMarkerOpacity = o; }\r\n getFocusMarkerOpacity() { return this.focusMarkerOpacity; }\r\n positionAndOrientFocusMarker(pos, cam) {}\r\n positionAndOrientMeshCursor(pos, cam) {}\r\n setMeshCursorVisibility(visible) { this.meshCursorVisible = visible; }\r\n getMeschCursorVisibility() { return this.meshCursorVisible; }\r\n setControlPlaneVisibility(visible) { this.controlPlaneVisible = visible; }\r\n positionAndOrientControlPlane(pos, quat, scale) {}\r\n updateForRenderMode(mode, mesh) {}\r\n dispose() {}\r\n}\r\n\r\n/**\r\n * Viewer - Core Gaussian Splatting Viewer\r\n * Handles the Three.js scene, camera, controls, and rendering loop.\r\n */\r\nexport class Viewer {\r\n /**\r\n * @param {object} options - Configuration options\r\n * @param {Array<number>} [options.cameraUp=[0, 1, 0]] - Camera up vector\r\n * @param {Array<number>} [options.initialCameraPosition=[0, 10, 15]] - Initial camera position\r\n * @param {Array<number>} [options.initialCameraRotation=[0, 0, 0]] - Initial camera rotation\r\n * @param {Array<number>} [options.initialCameraLookAt=[0, 0, 0]] - Initial camera look-at point\r\n * @param {boolean} [options.dropInMode=false] - If true, viewer is used as a Three.js scene object\r\n * @param {boolean} [options.selfDrivenMode=true] - If true, viewer manages its own render loop\r\n * @param {boolean} [options.useBuiltInControls=true] - If true, uses OrbitControls\r\n * @param {HTMLElement} [options.rootElement] - Parent element for the canvas\r\n * @param {HTMLCanvasElement} [options.threejsCanvas] - Existing canvas to use\r\n * @param {boolean} [options.ignoreDevicePixelRatio=false] - If true, forces DPR to 1\r\n * @param {boolean} [options.halfPrecisionCovariancesOnGPU=false] - Use 16-bit float for covariances\r\n * @param {THREE.Scene} [options.threeScene] - External Three.js scene to render\r\n * @param {THREE.WebGLRenderer} [options.renderer] - External Three.js renderer\r\n * @param {THREE.Camera} [options.camera] - External Three.js camera\r\n * @param {boolean} [options.gpuAcceleratedSort=false] - Use GPU for sorting distances\r\n * @param {boolean} [options.integerBasedSort=true] - Use integer arithmetic for sorting\r\n * @param {boolean} [options.sharedMemoryForWorkers=true] - Use SharedArrayBuffer for workers\r\n * @param {boolean} [options.dynamicScene=false] - Optimize for dynamic scenes\r\n */\r\n constructor(options = {}) {\r\n // The natural 'up' vector for viewing the scene (only has an effect when used with orbit controls and\r\n // when the viewer uses its own camera).\r\n if (!options.cameraUp) options.cameraUp = [0, 1, 0];\r\n this.cameraUp = new Vector3().fromArray(options.cameraUp);\r\n\r\n // The camera's initial position (only used when the viewer uses its own camera).\r\n if (!options.initialCameraPosition)\r\n options.initialCameraPosition = [0, 10, 15];\r\n this.initialCameraPosition = new Vector3().fromArray(\r\n options.initialCameraPosition\r\n );\r\n\r\n if (!options.initialCameraRotation)\r\n options.initialCameraRotation = [0, 0, 0];\r\n this.initialCameraRotation = new Vector3().fromArray(\r\n options.initialCameraRotation\r\n );\r\n this.backgroundColor = options.backgroundColor;\r\n\r\n // The initial focal point of the camera and center of the camera's orbit (only used when the viewer uses its own camera).\r\n if (!options.initialCameraLookAt) options.initialCameraLookAt = [0, 0, 0];\r\n this.initialCameraLookAt = new Vector3().fromArray(\r\n options.initialCameraLookAt\r\n );\r\n\r\n // 'dropInMode' is a flag that is used internally to support the usage of the viewer as a Three.js scene object\r\n this.dropInMode = options.dropInMode || false;\r\n\r\n // If 'selfDrivenMode' is true, the viewer manages its own update/animation loop via requestAnimationFrame()\r\n if (options.selfDrivenMode === undefined || options.selfDrivenMode === null)\r\n options.selfDrivenMode = true;\r\n this.selfDrivenMode = options.selfDrivenMode && !this.dropInMode;\r\n this.selfDrivenUpdateFunc = this.selfDrivenUpdate.bind(this);\r\n\r\n // If 'useBuiltInControls' is true, the viewer will create its own instance of OrbitControls and attach to the camera\r\n if (options.useBuiltInControls === undefined)\r\n options.useBuiltInControls = true;\r\n this.useBuiltInControls = options.useBuiltInControls;\r\n\r\n // parent element of the Three.js renderer canvas\r\n this.rootElement = options.rootElement;\r\n this.canvas = options.threejsCanvas;\r\n // Tells the viewer to pretend the device pixel ratio is 1, which can boost performance on devices where it is larger,\r\n // at a small cost to visual quality\r\n this.ignoreDevicePixelRatio = options.ignoreDevicePixelRatio || false;\r\n this.devicePixelRatio = this.ignoreDevicePixelRatio\r\n ? 1\r\n : window.devicePixelRatio || 1;\r\n\r\n // Tells the viewer to use 16-bit floating point values when storing splat covariance data in textures, instead of 32-bit\r\n this.halfPrecisionCovariancesOnGPU =\r\n options.halfPrecisionCovariancesOnGPU || false;\r\n\r\n // If 'threeScene' is valid, it will be rendered by the viewer along with the splat mesh\r\n this.threeScene = options.threeScene;\r\n // Allows for usage of an external Three.js renderer\r\n this.renderer = options.renderer;\r\n // Allows for usage of an external Three.js camera\r\n this.camera = options.camera;\r\n\r\n // If 'gpuAcceleratedSort' is true, a partially GPU-accelerated approach to sorting splats will be used.\r\n // Currently this means pre-computing splat distances from the camera on the GPU\r\n this.gpuAcceleratedSort = options.gpuAcceleratedSort || false;\r\n\r\n // if 'integerBasedSort' is true, the integer version of splat centers as well as other values used to calculate\r\n // splat distances are used instead of the float version. This speeds up computation, but introduces the possibility of\r\n // overflow in larger scenes.\r\n if (\r\n options.integerBasedSort === undefined ||\r\n options.integerBasedSort === null\r\n ) {\r\n options.integerBasedSort = true;\r\n }\r\n this.integerBasedSort = options.integerBasedSort;\r\n\r\n // If 'sharedMemoryForWorkers' is true, a SharedArrayBuffer will be used to communicate with web workers. This method\r\n // is faster than copying memory to or from web workers, but comes with security implications as outlined here:\r\n // https://web.dev/articles/cross-origin-isolation-guide\r\n // If enabled, it requires specific CORS headers to be present in the response from the server that is sent when\r\n // loading the application. More information is available in the README.\r\n if (\r\n options.sharedMemoryForWorkers === undefined ||\r\n options.sharedMemoryForWorkers === null\r\n )\r\n options.sharedMemoryForWorkers = true;\r\n this.sharedMemoryForWorkers = false; //options.sharedMemoryForWorkers;\r\n\r\n // if 'dynamicScene' is true, it tells the viewer to assume scene elements are not stationary or that the number of splats in the\r\n // scene may change. This prevents optimizations that depend on a static scene from being made. Additionally, if 'dynamicScene' is\r\n // true it tells the splat mesh to not apply scene tranforms to splat data that is returned by functions like\r\n // SplatMesh.getSplatCenter() by default.\r\n this.dynamicScene = !!options.dynamicScene;\r\n\r\n // When true, will perform additional steps during rendering to address artifacts caused by the rendering of gaussians at a\r\n // substantially different resolution than that at which they were rendered during training. This will only work correctly\r\n // for models that were trained using a process that utilizes this compensation calculation. For more details:\r\n // https://github.com/nerfstudio-project/gsplat/pull/117\r\n // https://github.com/graphdeco-inria/gaussian-splatting/issues/294#issuecomment-1772688093\r\n this.antialiased = options.antialiased || false;\r\n\r\n // This constant is added to the projected 2D screen-space splat scales\r\n this.kernel2DSize =\r\n options.kernel2DSize === undefined ? 0.3 : options.kernel2DSize;\r\n\r\n // if 'renderMode' is RenderMode.Always, then the viewer will rrender the scene on every update. If it is RenderMode.OnChange,\r\n // it will only render when something in the scene has changed.\r\n this.renderMode = options.renderMode || RenderMode.Always;\r\n\r\n // SceneRevealMode.Default results in a nice, slow fade-in effect for progressively loaded scenes,\r\n // and a fast fade-in for non progressively loaded scenes.\r\n // SceneRevealMode.Gradual will force a slow fade-in for all scenes.\r\n // SceneRevealMode.Instant will force all loaded scene data to be immediately visible.\r\n this.sceneRevealMode = options.sceneRevealMode || SceneRevealMode.Default;\r\n\r\n // Hacky, experimental, non-scientific parameter for tweaking focal length related calculations. For scenes with very\r\n // small gaussians, small details, and small dimensions -- increasing this value can help improve visual quality.\r\n this.focalAdjustment = options.focalAdjustment || 1.0;\r\n\r\n // Specify the maximum screen-space splat size, can help deal with large splats that get too unwieldy\r\n this.maxScreenSpaceSplatSize = options.maxScreenSpaceSplatSize || 1024;\r\n\r\n // The verbosity of console logging\r\n this.logLevel = options.logLevel || LogLevel.None;\r\n\r\n // Degree of spherical harmonics to utilize in rendering splats (assuming the data is present in the splat scene).\r\n // Valid values are 0 - 2. Default value is 0.\r\n this.sphericalHarmonicsDegree = options.sphericalHarmonicsDegree || 0;\r\n\r\n // When true, allows for usage of extra properties and attributes during rendering for effects such as opacity adjustment.\r\n // Default is false for performance reasons. These properties are separate from transform properties (scale, rotation, position)\r\n // that are enabled by the 'dynamicScene' parameter.\r\n this.enableOptionalEffects = options.enableOptionalEffects || false;\r\n\r\n // Enable the usage of SIMD WebAssembly instructions for the splat sort\r\n if (\r\n options.enableSIMDInSort === undefined ||\r\n options.enableSIMDInSort === null\r\n )\r\n options.enableSIMDInSort = true;\r\n this.enableSIMDInSort = options.enableSIMDInSort;\r\n\r\n // Level to compress non KSPLAT files when loading them for direct rendering\r\n if (\r\n options.inMemoryCompressionLevel === undefined ||\r\n options.inMemoryCompressionLevel === null\r\n ) {\r\n options.inMemoryCompressionLevel = 0;\r\n }\r\n this.inMemoryCompressionLevel = options.inMemoryCompressionLevel;\r\n\r\n // Reorder splat data in memory after loading is complete to optimize cache utilization. Default is true.\r\n // Does not apply if splat scene is progressively loaded.\r\n if (\r\n options.optimizeSplatData === undefined ||\r\n options.optimizeSplatData === null\r\n ) {\r\n options.optimizeSplatData = true;\r\n }\r\n this.optimizeSplatData = options.optimizeSplatData;\r\n\r\n // When true, the intermediate splat data that is the result of decompressing splat bufffer(s) and is used to\r\n // populate the data textures will be freed. This will reduces memory usage, but if that data needs to be modified\r\n // it will need to be re-populated from the splat buffer(s). Default is false.\r\n if (\r\n options.freeIntermediateSplatData === undefined ||\r\n options.freeIntermediateSplatData === null\r\n ) {\r\n options.freeIntermediateSplatData = false;\r\n }\r\n this.freeIntermediateSplatData = options.freeIntermediateSplatData;\r\n\r\n // It appears that for certain iOS versions, special actions need to be taken with the\r\n // usage of SIMD instructions and shared memory\r\n if (isIOS()) {\r\n const semver = getIOSSemever();\r\n if (semver.major < 17) {\r\n this.enableSIMDInSort = false;\r\n }\r\n if (semver.major < 16) {\r\n this.sharedMemoryForWorkers = false;\r\n }\r\n }\r\n\r\n // Tell the viewer how to render the splats\r\n if (\r\n options.splatRenderMode === undefined ||\r\n options.splatRenderMode === null\r\n ) {\r\n options.splatRenderMode = SplatRenderMode.ThreeD;\r\n }\r\n this.splatRenderMode = options.splatRenderMode;\r\n\r\n // Customize the speed at which the scene is revealed\r\n this.sceneFadeInRateMultiplier = options.sceneFadeInRateMultiplier || 1.0;\r\n\r\n // Set the range for the depth map for the counting sort used to sort the splats\r\n this.splatSortDistanceMapPrecision =\r\n options.splatSortDistanceMapPrecision ||\r\n Constants.DefaultSplatSortDistanceMapPrecision;\r\n const maxPrecision = this.integerBasedSort ? 20 : 24;\r\n this.splatSortDistanceMapPrecision = clamp(\r\n this.splatSortDistanceMapPrecision,\r\n 10,\r\n maxPrecision\r\n );\r\n\r\n this.onSplatMeshChangedCallback = null;\r\n this.createSplatMesh();\r\n\r\n this.controls = null;\r\n this.perspectiveControls = null;\r\n this.orthographicControls = null;\r\n\r\n this.orthographicCamera = null;\r\n this.perspectiveCamera = null;\r\n\r\n this.showMeshCursor = false;\r\n this.showControlPlane = false;\r\n this.showInfo = false;\r\n\r\n this.sceneHelper = null;\r\n\r\n this.sortWorker = null;\r\n this.sortRunning = false;\r\n this.splatRenderCount = 0;\r\n this.splatSortCount = 0;\r\n this.lastSplatSortCount = 0;\r\n this.sortWorkerIndexesToSort = null;\r\n this.sortWorkerSortedIndexes = null;\r\n this.sortWorkerPrecomputedDistances = null;\r\n this.sortWorkerTransforms = null;\r\n this.preSortMessages = [];\r\n this.runAfterNextSort = [];\r\n\r\n this.selfDrivenModeRunning = false;\r\n this.splatRenderReady = false;\r\n\r\n this.raycaster = new Raycaster();\r\n\r\n this.infoPanel = null;\r\n\r\n this.startInOrthographicMode = false;\r\n\r\n this.currentFPS = 0;\r\n this.lastSortTime = 0;\r\n this.consecutiveRenderFrames = 0;\r\n\r\n this.previousCameraTarget = new Vector3();\r\n this.nextCameraTarget = new Vector3();\r\n\r\n this.mousePosition = new Vector2();\r\n this.mouseDownPosition = new Vector2();\r\n this.mouseDownTime = null;\r\n\r\n this.resizeObserver = null;\r\n this.mouseMoveListener = null;\r\n this.mouseDownListener = null;\r\n this.mouseUpListener = null;\r\n this.keyDownListener = null;\r\n\r\n this.sortPromise = null;\r\n this.sortPromiseResolver = null;\r\n this.splatSceneDownloadControllers = [];\r\n this.splatSceneDownloadPromises = {};\r\n this.splatSceneDownloadAndBuildPromise = null;\r\n this.splatSceneRemovalPromise = null;\r\n\r\n this.loadingSpinner = new LoadingSpinner(\r\n null,\r\n this.rootElement || document.body\r\n );\r\n this.loadingSpinner.hide();\r\n this.loadingProgressBar = new LoadingProgressBar(\r\n this.rootElement || document.body\r\n );\r\n this.loadingProgressBar.hide();\r\n // this.infoPanel = new InfoPanel(this.rootElement || document.body)\r\n // this.infoPanel.hide()\r\n\r\n this.usingExternalCamera = this.dropInMode || this.camera ? true : false;\r\n this.usingExternalRenderer = this.dropInMode || this.renderer ? true : false;\r\n\r\n this.initialized = false;\r\n this.disposing = false;\r\n this.disposed = false;\r\n this.disposePromise = null;\r\n\r\n this.lastTime = 0;\r\n this.gaussianSplatCount = 0;\r\n this.totalFrames = 0;\r\n this.frame = 0;\r\n this. avatarMesh = null;\r\n this.skinModel = null;\r\n this.boneRoot = null;\r\n this.baseMesh = null;\r\n this.setSkinAttibutes = false;\r\n\r\n if (!this.dropInMode) this.init();\r\n }\r\n\r\n createSplatMesh() {\r\n this.splatMesh = new SplatMesh(\r\n this.splatRenderMode,\r\n this.dynamicScene,\r\n this.enableOptionalEffects,\r\n this.halfPrecisionCovariancesOnGPU,\r\n this.devicePixelRatio,\r\n this.gpuAcceleratedSort,\r\n this.integerBasedSort,\r\n this.antialiased,\r\n this.maxScreenSpaceSplatSize,\r\n this.logLevel,\r\n this.sphericalHarmonicsDegree,\r\n this.sceneFadeInRateMultiplier,\r\n this.kernel2DSize\r\n );\r\n\r\n // Pass iris occlusion config if loaded\r\n this.splatMesh.irisOcclusionConfig = this.irisOcclusionConfig;\r\n this.splatMesh.frustumCulled = false;\r\n if (this.onSplatMeshChangedCallback) this.onSplatMeshChangedCallback();\r\n }\r\n\r\n init() {\r\n if (this.initialized) return\r\n\r\n if (!this.rootElement) {\r\n if (!this.usingExternalRenderer) {\r\n this.rootElement = document.createElement('div');\r\n this.rootElement.style.width = '100%';\r\n this.rootElement.style.height = '100%';\r\n this.rootElement.style.position = 'absolute';\r\n document.body.appendChild(this.rootElement);\r\n } else {\r\n this.rootElement = this.renderer.domElement || document.body;\r\n }\r\n }\r\n\r\n this.setupCamera();\r\n this.setupRenderer();\r\n // 暂时去掉控制器\r\n // this.setupControls()\r\n this.setupEventHandlers();\r\n\r\n this.threeScene = this.threeScene || new Scene();\r\n this.sceneHelper = new SceneHelper(this.threeScene);\r\n this.sceneHelper.setupMeshCursor();\r\n this.sceneHelper.setupFocusMarker();\r\n this.sceneHelper.setupControlPlane();\r\n\r\n this.loadingProgressBar.setContainer(this.rootElement);\r\n this.loadingSpinner.setContainer(this.rootElement);\r\n // this.infoPanel.setContainer(this.rootElement)\r\n\r\n this.initialized = true;\r\n }\r\n\r\n setupCamera() {\r\n if (!this.usingExternalCamera) {\r\n const renderDimensions = new Vector2();\r\n this.getRenderDimensions(renderDimensions);\r\n\r\n this.perspectiveCamera = new PerspectiveCamera(\r\n THREE_CAMERA_FOV,\r\n renderDimensions.x / renderDimensions.y,\r\n 0.1,\r\n 1000\r\n );\r\n this.orthographicCamera = new OrthographicCamera(\r\n renderDimensions.x / -2,\r\n renderDimensions.x / 2,\r\n renderDimensions.y / 2,\r\n renderDimensions.y / -2,\r\n 0.1,\r\n 1000\r\n );\r\n this.camera = this.startInOrthographicMode\r\n ? this.orthographicCamera\r\n : this.perspectiveCamera;\r\n this.camera.position.copy(this.initialCameraPosition);\r\n // this.camera.up.copy(this.cameraUp).normalize()\r\n // this.camera.lookAt(this.initialCameraLookAt)\r\n this.camera.rotateX(MathUtils.degToRad(this.initialCameraRotation.x));\r\n this.camera.rotateY(MathUtils.degToRad(this.initialCameraRotation.y));\r\n this.camera.rotateZ(MathUtils.degToRad(this.initialCameraRotation.z));\r\n }\r\n }\r\n\r\n setupRenderer() {\r\n if (!this.usingExternalRenderer) {\r\n const renderDimensions = new Vector2();\r\n this.getRenderDimensions(renderDimensions);\r\n\r\n this.renderer = new WebGLRenderer({\r\n antialias: false,\r\n precision: 'highp',\r\n canvas: this.canvas\r\n });\r\n this.renderer.setPixelRatio(this.devicePixelRatio);\r\n this.renderer.autoClear = true;\r\n this.renderer.setClearColor(this.backgroundColor, 1.0); // set background color according to the config\r\n\r\n this.renderer.setSize(renderDimensions.x, renderDimensions.y);\r\n\r\n this.resizeObserver = new ResizeObserver(() => {\r\n this.getRenderDimensions(renderDimensions);\r\n this.renderer.setSize(renderDimensions.x, renderDimensions.y);\r\n this.forceRenderNextFrame();\r\n });\r\n this.resizeObserver.observe(this.rootElement);\r\n this.rootElement.appendChild(this.renderer.domElement);\r\n }\r\n }\r\n\r\n setupControls() {\r\n if (this.useBuiltInControls) {\r\n if (!this.usingExternalCamera) {\r\n this.perspectiveControls = new OrbitControls(\r\n this.perspectiveCamera,\r\n this.renderer.domElement\r\n );\r\n this.orthographicControls = new OrbitControls(\r\n this.orthographicCamera,\r\n this.renderer.domElement\r\n );\r\n } else {\r\n if (this.camera.isOrthographicCamera) {\r\n this.orthographicControls = new OrbitControls(\r\n this.camera,\r\n this.renderer.domElement\r\n );\r\n } else {\r\n this.perspectiveControls = new OrbitControls(\r\n this.camera,\r\n this.renderer.domElement\r\n );\r\n }\r\n }\r\n for (let controls of [\r\n this.orthographicControls,\r\n this.perspectiveControls\r\n ]) {\r\n if (controls) {\r\n controls.listenToKeyEvents(window);\r\n controls.rotateSpeed = 0.5;\r\n controls.maxPolarAngle = Math.PI * 0.5;// + Math.PI / 24\r\n controls.minPolarAngle = Math.PI * 0.5;// - Math.PI / 24\r\n controls.minAzimuthAngle = -Math.PI / 72;\r\n controls.maxAzimuthAngle = Math.PI / 72;\r\n controls.enableDamping = true;\r\n controls.dampingFactor = 0.05;\r\n controls.target.copy(this.initialCameraLookAt);\r\n controls.update();\r\n }\r\n }\r\n this.controls = this.camera.isOrthographicCamera\r\n ? this.orthographicControls\r\n : this.perspectiveControls;\r\n this.controls.update();\r\n }\r\n }\r\n\r\n setupEventHandlers() {\r\n if (this.useBuiltInControls) {\r\n this.mouseMoveListener = this.onMouseMove.bind(this);\r\n this.renderer.domElement.addEventListener(\r\n 'pointermove',\r\n this.mouseMoveListener,\r\n false\r\n );\r\n this.mouseDownListener = this.onMouseDown.bind(this);\r\n this.renderer.domElement.addEventListener(\r\n 'pointerdown',\r\n this.mouseDownListener,\r\n false\r\n );\r\n this.mouseUpListener = this.onMouseUp.bind(this);\r\n this.renderer.domElement.addEventListener(\r\n 'pointerup',\r\n this.mouseUpListener,\r\n false\r\n );\r\n this.keyDownListener = this.onKeyDown.bind(this);\r\n }\r\n }\r\n\r\n removeEventHandlers() {\r\n if (this.useBuiltInControls) {\r\n this.renderer.domElement.removeEventListener(\r\n 'pointermove',\r\n this.mouseMoveListener\r\n );\r\n this.mouseMoveListener = null;\r\n this.renderer.domElement.removeEventListener(\r\n 'pointerdown',\r\n this.mouseDownListener\r\n );\r\n this.mouseDownListener = null;\r\n this.renderer.domElement.removeEventListener(\r\n 'pointerup',\r\n this.mouseUpListener\r\n );\r\n this.mouseUpListener = null;\r\n window.removeEventListener('keydown', this.keyDownListener);\r\n this.keyDownListener = null;\r\n }\r\n }\r\n\r\n setRenderMode(renderMode) {\r\n this.renderMode = renderMode;\r\n }\r\n\r\n setActiveSphericalHarmonicsDegrees(activeSphericalHarmonicsDegrees) {\r\n this.splatMesh.material.uniforms.sphericalHarmonicsDegree.value =\r\n activeSphericalHarmonicsDegrees;\r\n this.splatMesh.material.uniformsNeedUpdate = true;\r\n }\r\n\r\n onSplatMeshChanged(callback) {\r\n this.onSplatMeshChangedCallback = callback;\r\n }\r\n\r\n tempForward = new Vector3()\r\n tempMatrixLeft = new Matrix4()\r\n tempMatrixRight = new Matrix4()\r\n onKeyDown = (e) => {\r\n this.tempForward.set(0, 0, -1);\r\n this.tempForward.transformDirection(this.camera.matrixWorld);\r\n this.tempMatrixLeft.makeRotationAxis(this.tempForward, Math.PI / 128);\r\n this.tempMatrixRight.makeRotationAxis(this.tempForward, -Math.PI / 128);\r\n switch (e.code) {\r\n case 'KeyG':\r\n this.focalAdjustment += 0.02;\r\n this.forceRenderNextFrame();\r\n break\r\n case 'KeyF':\r\n this.focalAdjustment -= 0.02;\r\n this.forceRenderNextFrame();\r\n break\r\n case 'ArrowLeft':\r\n this.camera.up.transformDirection(this.tempMatrixLeft);\r\n break\r\n case 'ArrowRight':\r\n this.camera.up.transformDirection(this.tempMatrixRight);\r\n break\r\n case 'KeyC':\r\n this.showMeshCursor = !this.showMeshCursor;\r\n break\r\n case 'KeyU':\r\n this.showControlPlane = !this.showControlPlane;\r\n break\r\n case 'KeyI':\r\n this.showInfo = !this.showInfo;\r\n if (this.showInfo) {\r\n // this.infoPanel.show()\r\n } else {\r\n // this.infoPanel.hide()\r\n }\r\n break\r\n case 'KeyO':\r\n if (!this.usingExternalCamera) {\r\n this.setOrthographicMode(!this.camera.isOrthographicCamera);\r\n }\r\n break\r\n case 'KeyP':\r\n if (!this.usingExternalCamera) {\r\n this.splatMesh.setPointCloudModeEnabled(\r\n !this.splatMesh.getPointCloudModeEnabled()\r\n );\r\n }\r\n break\r\n case 'Equal':\r\n if (!this.usingExternalCamera) {\r\n this.splatMesh.setSplatScale(this.splatMesh.getSplatScale() + 0.05);\r\n }\r\n break\r\n case 'Minus':\r\n if (!this.usingExternalCamera) {\r\n this.splatMesh.setSplatScale(\r\n Math.max(this.splatMesh.getSplatScale() - 0.05, 0.0)\r\n );\r\n }\r\n break\r\n }\r\n }\r\n\r\n onMouseMove(mouse) {\r\n this.mousePosition.set(mouse.offsetX, mouse.offsetY);\r\n }\r\n\r\n onMouseDown() {\r\n this.mouseDownPosition.copy(this.mousePosition);\r\n this.mouseDownTime = getCurrentTime();\r\n }\r\n\r\n onMouseUp = (function () {\r\n const clickOffset = new Vector2();\r\n\r\n return function (mouse) {\r\n clickOffset.copy(this.mousePosition).sub(this.mouseDownPosition);\r\n const mouseUpTime = getCurrentTime();\r\n const wasClick =\r\n mouseUpTime - this.mouseDownTime < 0.5 && clickOffset.length() < 2;\r\n if (wasClick) {\r\n this.onMouseClick(mouse);\r\n }\r\n }\r\n })()\r\n\r\n onMouseClick(mouse) {\r\n this.mousePosition.set(mouse.offsetX, mouse.offsetY);\r\n this.checkForFocalPointChange();\r\n }\r\n\r\n checkPointRenderDimensions = new Vector2()\r\n checkPointToNewFocalPoint = new Vector3()\r\n checkPointOutHits = []\r\n checkForFocalPointChange = () => {\r\n if (!this.transitioningCameraTarget) {\r\n this.getRenderDimensions(this.checkPointRenderDimensions);\r\n this.checkPointOutHits.length = 0;\r\n this.raycaster.setFromCameraAndScreenPosition(\r\n this.camera,\r\n this.mousePosition,\r\n this.checkPointRenderDimensions\r\n );\r\n this.raycaster.intersectSplatMesh(this.splatMesh, this.checkPointOutHits);\r\n if (this.checkPointOutHits.length > 0) {\r\n const hit = this.checkPointOutHits[0];\r\n const intersectionPoint = hit.origin;\r\n this.checkPointToNewFocalPoint\r\n .copy(intersectionPoint)\r\n .sub(this.camera.position);\r\n if (\r\n this.checkPointToNewFocalPoint.length() >\r\n MINIMUM_DISTANCE_TO_NEW_FOCAL_POINT\r\n ) {\r\n this.previousCameraTarget.copy(this.controls.target);\r\n this.nextCameraTarget.copy(intersectionPoint);\r\n this.transitioningCameraTarget = true;\r\n this.transitioningCameraTargetStartTime = getCurrentTime();\r\n }\r\n }\r\n }\r\n }\r\n\r\n getRenderDimensions(outDimensions) {\r\n if (this.rootElement) {\r\n outDimensions.x = this.rootElement.offsetWidth;\r\n outDimensions.y = this.rootElement.offsetHeight;\r\n } else {\r\n this.renderer.getSize(outDimensions);\r\n }\r\n }\r\n\r\n setOrthographicMode(orthographicMode) {\r\n if (orthographicMode === this.camera.isOrthographicCamera) return\r\n const fromCamera = this.camera;\r\n const toCamera = orthographicMode\r\n ? this.orthographicCamera\r\n : this.perspectiveCamera;\r\n toCamera.position.copy(fromCamera.position);\r\n toCamera.up.copy(fromCamera.up);\r\n toCamera.rotation.copy(fromCamera.rotation);\r\n toCamera.quaternion.copy(fromCamera.quaternion);\r\n toCamera.matrix.copy(fromCamera.matrix);\r\n this.camera = toCamera;\r\n\r\n if (this.controls) {\r\n const resetControls = (controls) => {\r\n controls.saveState();\r\n controls.reset();\r\n };\r\n\r\n const fromControls = this.controls;\r\n const toControls = orthographicMode\r\n ? this.orthographicControls\r\n : this.perspectiveControls;\r\n\r\n resetControls(toControls);\r\n resetControls(fromControls);\r\n\r\n toControls.target.copy(fromControls.target);\r\n if (orthographicMode) {\r\n Viewer.setCameraZoomFromPosition(toCamera, fromCamera, fromControls);\r\n } else {\r\n Viewer.setCameraPositionFromZoom(toCamera, fromCamera, toControls);\r\n }\r\n this.controls = toControls;\r\n this.camera.lookAt(this.controls.target);\r\n }\r\n }\r\n\r\n static setCameraPositionFromZoom = (function () {\r\n const tempVector = new Vector3();\r\n\r\n return function (positionCamera, zoomedCamera, controls) {\r\n const toLookAtDistance = 1 / (zoomedCamera.zoom * 0.001);\r\n tempVector\r\n .copy(controls.target)\r\n .sub(positionCamera.position)\r\n .normalize()\r\n .multiplyScalar(toLookAtDistance)\r\n .negate();\r\n positionCamera.position.copy(controls.target).add(tempVector);\r\n }\r\n })()\r\n\r\n static setCameraZoomFromPosition = (function () {\r\n const tempVector = new Vector3();\r\n\r\n return function (zoomCamera, positionZamera, controls) {\r\n const toLookAtDistance = tempVector\r\n .copy(controls.target)\r\n .sub(positionZamera.position)\r\n .length();\r\n zoomCamera.zoom = 1 / (toLookAtDistance * 0.001);\r\n }\r\n })()\r\n\r\n updateSplatMesh = (function () {\r\n const renderDimensions = new Vector2();\r\n\r\n return function () {\r\n if (!this.splatMesh) return\r\n const splatCount = this.splatMesh.getSplatCount();\r\n if (splatCount > 0) {\r\n this.splatMesh.updateVisibleRegionFadeDistance(this.sceneRevealMode);\r\n this.splatMesh.updateTransforms();\r\n this.getRenderDimensions(renderDimensions);\r\n const focalLengthX =\r\n this.camera.projectionMatrix.elements[0] *\r\n 0.5 *\r\n this.devicePixelRatio *\r\n renderDimensions.x;\r\n const focalLengthY =\r\n this.camera.projectionMatrix.elements[5] *\r\n 0.5 *\r\n this.devicePixelRatio *\r\n renderDimensions.y;\r\n\r\n const focalMultiplier = this.camera.isOrthographicCamera\r\n ? 1.0 / this.devicePixelRatio\r\n : 1.0;\r\n const focalAdjustment = this.focalAdjustment * focalMultiplier;\r\n const inverseFocalAdjustment = 1.0 / focalAdjustment;\r\n\r\n this.adjustForWebXRStereo(renderDimensions);\r\n this.splatMesh.updateUniforms(\r\n renderDimensions,\r\n focalLengthX * focalAdjustment,\r\n focalLengthY * focalAdjustment,\r\n this.camera.isOrthographicCamera,\r\n this.camera.zoom || 1.0,\r\n inverseFocalAdjustment\r\n );\r\n }\r\n }\r\n })()\r\n\r\n adjustForWebXRStereo(renderDimensions) {\r\n // TODO: Figure out a less hacky way to determine if stereo rendering is active\r\n if (this.camera && this.webXRActive) {\r\n const xrCamera = this.renderer.xr.getCamera();\r\n const xrCameraProj00 = xrCamera.projectionMatrix.elements[0];\r\n const cameraProj00 = this.camera.projectionMatrix.elements[0];\r\n renderDimensions.x *= cameraProj00 / xrCameraProj00;\r\n }\r\n }\r\n\r\n isLoadingOrUnloading() {\r\n return (\r\n Object.keys(this.splatSceneDownloadPromises).length > 0 ||\r\n this.splatSceneDownloadAndBuildPromise !== null ||\r\n this.splatSceneRemovalPromise !== null\r\n )\r\n }\r\n\r\n isDisposingOrDisposed() {\r\n return this.disposing || this.disposed\r\n }\r\n\r\n addSplatSceneDownloadController(controller) {\r\n this.splatSceneDownloadControllers.push(controller);\r\n }\r\n\r\n removeSplatSceneDownloadController(controller) {\r\n const index = this.splatSceneDownloadControllers.indexOf(controller);\r\n if (index > -1) {\r\n this.splatSceneDownloadControllers.splice(index, 1);\r\n }\r\n }\r\n\r\n addSplatSceneDownloadPromise(promise) {\r\n this.splatSceneDownloadPromises[promise.id] = promise;\r\n }\r\n\r\n removeSplatSceneDownloadPromise(promise) {\r\n delete this.splatSceneDownloadPromises[promise.id];\r\n }\r\n\r\n setSplatSceneDownloadAndBuildPromise(promise) {\r\n this.splatSceneDownloadAndBuildPromise = promise;\r\n }\r\n\r\n clearSplatSceneDownloadAndBuildPromise() {\r\n this.splatSceneDownloadAndBuildPromise = null;\r\n }\r\n\r\n /**\r\n * Add a splat scene to the viewer and display any loading UI if appropriate.\r\n * @param {string} path Path to splat scene to be loaded\r\n * @param {object} options {\r\n *\r\n * splatAlphaRemovalThreshold: Ignore any splats with an alpha less than the specified\r\n * value (valid range: 0 - 255), defaults to 1\r\n *\r\n * showLoadingUI: Display a loading spinner while the scene is loading, defaults to true\r\n *\r\n * position (Array<number>): Position of the scene, acts as an offset from its default position, defaults to [0, 0, 0]\r\n *\r\n * rotation (Array<number>): Rotation of the scene represented as a quaternion, defaults to [0, 0, 0, 1]\r\n *\r\n * scale (Array<number>): Scene's scale, defaults to [1, 1, 1]\r\n *\r\n * onProgress: Function to be called as file data are received, or other processing occurs\r\n *\r\n * headers: Optional HTTP headers to be sent along with splat requests\r\n * }\r\n * @return {Promise}\r\n */\r\n addSplatScene(path, options = {}) {\r\n if (this.isLoadingOrUnloading()) {\r\n throw new Error(\r\n 'Cannot add splat scene while another load or unload is already in progress.'\r\n )\r\n }\r\n\r\n if (this.isDisposingOrDisposed()) {\r\n throw new Error('Cannot add splat scene after dispose() is called.')\r\n }\r\n\r\n if (\r\n options.progressiveLoad &&\r\n this.splatMesh.scenes &&\r\n this.splatMesh.scenes.length > 0\r\n ) {\r\n logger.warn(\r\n 'addSplatScene(): \"progressiveLoad\" option ignore because there are multiple splat scenes'\r\n );\r\n options.progressiveLoad = false;\r\n }\r\n\r\n const format =\r\n options.format !== undefined && options.format !== null\r\n ? options.format\r\n : sceneFormatFromPath(path);\r\n const progressiveLoad =\r\n Viewer.isProgressivelyLoadable(format) && options.progressiveLoad;\r\n const showLoadingUI =\r\n options.showLoadingUI !== undefined && options.showLoadingUI !== null\r\n ? options.showLoadingUI\r\n : true;\r\n\r\n let loadingUITaskId = null;\r\n if (showLoadingUI) {\r\n this.loadingSpinner.removeAllTasks();\r\n loadingUITaskId = this.loadingSpinner.addTask('Downloading...');\r\n }\r\n const hideLoadingUI = () => {\r\n this.loadingProgressBar.hide();\r\n this.loadingSpinner.removeAllTasks();\r\n };\r\n\r\n const onProgressUIUpdate = (\r\n percentComplete,\r\n percentCompleteLabel,\r\n loaderStatus\r\n ) => {\r\n if (showLoadingUI) {\r\n if (loaderStatus === LoaderStatus.Downloading) {\r\n if (percentComplete == 100) {\r\n this.loadingSpinner.setMessageForTask(\r\n loadingUITaskId,\r\n 'Download complete!'\r\n );\r\n } else {\r\n if (progressiveLoad) {\r\n this.loadingSpinner.setMessageForTask(\r\n loadingUITaskId,\r\n 'Downloading splats...'\r\n );\r\n } else {\r\n const suffix = percentCompleteLabel\r\n ? `: ${percentCompleteLabel}`\r\n : `...`;\r\n this.loadingSpinner.setMessageForTask(\r\n loadingUITaskId,\r\n `Downloading${suffix}`\r\n );\r\n }\r\n }\r\n } else if (loaderStatus === LoaderStatus.Processing) {\r\n logger.debug('loaderStatus === LoaderStatus.Processing');\r\n this.loadingSpinner.setMessageForTask(\r\n loadingUITaskId,\r\n 'Processing splats...'\r\n );\r\n }\r\n }\r\n };\r\n\r\n let downloadDone = false;\r\n let downloadedPercentage = 0;\r\n const splatBuffersAddedUIUpdate = (firstBuild, finalBuild) => {\r\n if (showLoadingUI) {\r\n if (\r\n (firstBuild && progressiveLoad) ||\r\n (finalBuild && !progressiveLoad)\r\n ) {\r\n this.loadingSpinner.removeTask(loadingUITaskId);\r\n if (!finalBuild && !downloadDone) this.loadingProgressBar.show();\r\n }\r\n if (progressiveLoad) {\r\n if (finalBuild) {\r\n downloadDone = true;\r\n this.loadingProgressBar.hide();\r\n } else {\r\n this.loadingProgressBar.setProgress(downloadedPercentage);\r\n }\r\n }\r\n }\r\n };\r\n\r\n const onProgress = (\r\n percentComplete,\r\n percentCompleteLabel,\r\n loaderStatus\r\n ) => {\r\n downloadedPercentage = percentComplete;\r\n onProgressUIUpdate(percentComplete, percentCompleteLabel, loaderStatus);\r\n if (options.onProgress)\r\n options.onProgress(percentComplete, percentCompleteLabel, loaderStatus);\r\n };\r\n\r\n const buildSection = (splatBuffer, firstBuild, finalBuild) => {\r\n if (!progressiveLoad && options.onProgress)\r\n options.onProgress(0, '0%', LoaderStatus.Processing);\r\n const addSplatBufferOptions = {\r\n rotation: options.rotation || options.orientation,\r\n position: options.position,\r\n scale: options.scale,\r\n splatAlphaRemovalThreshold: options.splatAlphaRemovalThreshold\r\n };\r\n return this.addSplatBuffers(\r\n [splatBuffer],\r\n [addSplatBufferOptions],\r\n finalBuild,\r\n firstBuild && showLoadingUI,\r\n showLoadingUI,\r\n progressiveLoad,\r\n progressiveLoad\r\n ).then(() => {\r\n if (!progressiveLoad && options.onProgress)\r\n options.onProgress(100, '100%', LoaderStatus.Processing);\r\n splatBuffersAddedUIUpdate(firstBuild, finalBuild);\r\n })\r\n };\r\n\r\n const loadFunc = progressiveLoad\r\n ? this.downloadAndBuildSingleSplatSceneProgressiveLoad.bind(this)\r\n : this.downloadAndBuildSingleSplatSceneStandardLoad.bind(this);\r\n return loadFunc(\r\n path,\r\n format,\r\n options.splatAlphaRemovalThreshold,\r\n buildSection.bind(this),\r\n onProgress,\r\n hideLoadingUI.bind(this),\r\n options.headers\r\n )\r\n }\r\n\r\n /**\r\n * Download a single splat scene, convert to splat buffer and then rebuild the viewer's splat mesh\r\n * by calling 'buildFunc' -- all before displaying the scene. Also sets/clears relevant instance synchronization objects,\r\n * and calls appropriate functions on success or failure.\r\n * @param {string} path Path to splat scene to be loaded\r\n * @param {SceneFormat} format Format of the splat scene file\r\n * @param {number} splatAlphaRemovalThreshold Ignore any splats with an alpha less than the specified value (valid range: 0 - 255)\r\n * @param {function} buildFunc Function to build the viewer's splat mesh with the downloaded splat buffer\r\n * @param {function} onProgress Function to be called as file data are received, or other processing occurs\r\n * @param {function} onException Function to be called when exception occurs\r\n * @param {object} headers Optional HTTP headers to pass to use for downloading splat scene\r\n * @return {Promise}\r\n */\r\n downloadAndBuildSingleSplatSceneStandardLoad(\r\n path,\r\n format,\r\n splatAlphaRemovalThreshold,\r\n buildFunc,\r\n onProgress,\r\n onException,\r\n headers\r\n ) {\r\n const downloadPromise = this.downloadSplatSceneToSplatBuffer(\r\n path,\r\n splatAlphaRemovalThreshold,\r\n onProgress,\r\n false,\r\n undefined,\r\n format,\r\n headers\r\n );\r\n\r\n // Create a promise that can be resolved/rejected externally, with abort capability\r\n const downloadAndBuildPromise = abortablePromiseWithExtractedComponents(\r\n downloadPromise.abort ? downloadPromise.abort.bind(downloadPromise) : undefined\r\n );\r\n\r\n downloadPromise\r\n .then((splatBuffer) => {\r\n this.removeSplatSceneDownloadPromise(downloadPromise);\r\n return buildFunc(splatBuffer, true, true).then(() => {\r\n downloadAndBuildPromise.resolve();\r\n this.clearSplatSceneDownloadAndBuildPromise();\r\n })\r\n })\r\n .catch((e) => {\r\n if (onException) onException();\r\n this.clearSplatSceneDownloadAndBuildPromise();\r\n this.removeSplatSceneDownloadPromise(downloadPromise);\r\n const error =\r\n (e instanceof AbortedPromiseError || e.name === 'AbortError')\r\n ? e\r\n : new Error(`Viewer::addSplatScene -> Could not load file ${path}`);\r\n downloadAndBuildPromise.reject(error);\r\n });\r\n\r\n this.addSplatSceneDownloadPromise(downloadPromise);\r\n this.setSplatSceneDownloadAndBuildPromise(downloadAndBuildPromise.promise);\r\n\r\n return downloadAndBuildPromise.promise\r\n }\r\n\r\n /**\r\n * Download a single splat scene and convert to splat buffer in a progressive manner, allowing rendering as the file downloads.\r\n * As each section is downloaded, the viewer's splat mesh is rebuilt by calling 'buildFunc'\r\n * Also sets/clears relevant instance synchronization objects, and calls appropriate functions on success or failure.\r\n * @param {string} path Path to splat scene to be loaded\r\n * @param {SceneFormat} format Format of the splat scene file\r\n * @param {number} splatAlphaRemovalThreshold Ignore any splats with an alpha less than the specified value (valid range: 0 - 255)\r\n * @param {function} buildFunc Function to rebuild the viewer's splat mesh after a new splat buffer section is downloaded\r\n * @param {function} onDownloadProgress Function to be called as file data are received\r\n * @param {function} onDownloadException Function to be called when exception occurs at any point during the full download\r\n * @param {object} headers Optional HTTP headers to pass to use for downloading splat scene\r\n * @return {Promise}\r\n */\r\n downloadAndBuildSingleSplatSceneProgressiveLoad(\r\n path,\r\n format,\r\n splatAlphaRemovalThreshold,\r\n buildFunc,\r\n onDownloadProgress,\r\n onDownloadException,\r\n headers\r\n ) {\r\n let progressiveLoadedSectionBuildCount = 0;\r\n let progressiveLoadedSectionBuilding = false;\r\n const queuedProgressiveLoadSectionBuilds = [];\r\n\r\n const checkAndBuildProgressiveLoadSections = () => {\r\n if (\r\n queuedProgressiveLoadSectionBuilds.length > 0 &&\r\n !progressiveLoadedSectionBuilding &&\r\n !this.isDisposingOrDisposed()\r\n ) {\r\n progressiveLoadedSectionBuilding = true;\r\n const queuedBuild = queuedProgressiveLoadSectionBuilds.shift();\r\n buildFunc(\r\n queuedBuild.splatBuffer,\r\n queuedBuild.firstBuild,\r\n queuedBuild.finalBuild\r\n ).then(() => {\r\n progressiveLoadedSectionBuilding = false;\r\n if (queuedBuild.firstBuild) {\r\n progressiveLoadFirstSectionBuildPromise.resolve();\r\n } else if (queuedBuild.finalBuild) {\r\n splatSceneDownloadAndBuildPromise.resolve();\r\n this.clearSplatSceneDownloadAndBuildPromise();\r\n }\r\n if (queuedProgressiveLoadSectionBuilds.length > 0) {\r\n delayedExecute(() => checkAndBuildProgressiveLoadSections());\r\n }\r\n });\r\n }\r\n };\r\n\r\n const onProgressiveLoadSectionProgress = (splatBuffer, finalBuild) => {\r\n if (!this.isDisposingOrDisposed()) {\r\n if (\r\n finalBuild ||\r\n queuedProgressiveLoadSectionBuilds.length === 0 ||\r\n splatBuffer.getSplatCount() >\r\n queuedProgressiveLoadSectionBuilds[0].splatBuffer.getSplatCount()\r\n ) {\r\n queuedProgressiveLoadSectionBuilds.push({\r\n splatBuffer,\r\n firstBuild: progressiveLoadedSectionBuildCount === 0,\r\n finalBuild\r\n });\r\n progressiveLoadedSectionBuildCount++;\r\n checkAndBuildProgressiveLoadSections();\r\n }\r\n }\r\n };\r\n\r\n const splatSceneDownloadPromise = this.downloadSplatSceneToSplatBuffer(\r\n path,\r\n splatAlphaRemovalThreshold,\r\n onDownloadProgress,\r\n true,\r\n onProgressiveLoadSectionProgress,\r\n format,\r\n headers\r\n );\r\n\r\n // Get abort handler from download promise\r\n const abortHandler = splatSceneDownloadPromise.abort \r\n ? splatSceneDownloadPromise.abort.bind(splatSceneDownloadPromise) \r\n : undefined;\r\n\r\n const progressiveLoadFirstSectionBuildPromise =\r\n abortablePromiseWithExtractedComponents(abortHandler);\r\n\r\n const splatSceneDownloadAndBuildPromise =\r\n abortablePromiseWithExtractedComponents(abortHandler);\r\n\r\n this.addSplatSceneDownloadPromise(splatSceneDownloadPromise);\r\n this.setSplatSceneDownloadAndBuildPromise(\r\n splatSceneDownloadAndBuildPromise.promise\r\n );\r\n\r\n splatSceneDownloadPromise\r\n .then(() => {\r\n this.removeSplatSceneDownloadPromise(splatSceneDownloadPromise);\r\n })\r\n .catch((e) => {\r\n logger.error('Viewer::addSplatScene actual error:', e);\r\n this.clearSplatSceneDownloadAndBuildPromise();\r\n this.removeSplatSceneDownloadPromise(splatSceneDownloadPromise);\r\n const error =\r\n (e instanceof AbortedPromiseError || e.name === 'AbortError')\r\n ? e\r\n : new Error(\r\n `Viewer::addSplatScene -> Could not load one or more scenes: ${e.message}`\r\n );\r\n progressiveLoadFirstSectionBuildPromise.reject(error);\r\n if (onDownloadException) onDownloadException(error);\r\n });\r\n\r\n return progressiveLoadFirstSectionBuildPromise.promise\r\n }\r\n\r\n /**\r\n * Add multiple splat scenes to the viewer and display any loading UI if appropriate.\r\n * @param {Array<object>} sceneOptions Array of per-scene options: {\r\n *\r\n * path: Path to splat scene to be loaded\r\n *\r\n * splatAlphaRemovalThreshold: Ignore any splats with an alpha less than the specified\r\n * value (valid range: 0 - 255), defaults to 1\r\n *\r\n * position (Array<number>): Position of the scene, acts as an offset from its default position, defaults to [0, 0, 0]\r\n *\r\n * rotation (Array<number>): Rotation of the scene represented as a quaternion, defaults to [0, 0, 0, 1]\r\n *\r\n * scale (Array<number>): Scene's scale, defaults to [1, 1, 1]\r\n *\r\n * headers: Optional HTTP headers to be sent along with splat requests\r\n *\r\n * format (SceneFormat) Optional, the format of the scene data (.ply, .ksplat, .splat). If not present, the\r\n * file extension in 'path' will be used to determine the format (if it is present)\r\n * }\r\n * @param {boolean} showLoadingUI Display a loading spinner while the scene is loading, defaults to true\r\n * @param {function} onProgress Function to be called as file data are received\r\n * @return {Promise}\r\n */\r\n addSplatScenes(sceneOptions, showLoadingUI = true, onProgress = undefined) {\r\n if (this.isLoadingOrUnloading()) {\r\n throw new Error(\r\n 'Cannot add splat scene while another load or unload is already in progress.'\r\n )\r\n }\r\n\r\n if (this.isDisposingOrDisposed()) {\r\n throw new Error('Cannot add splat scene after dispose() is called.')\r\n }\r\n\r\n const fileCount = sceneOptions.length;\r\n const percentComplete = [];\r\n\r\n let loadingUITaskId;\r\n if (showLoadingUI) {\r\n this.loadingSpinner.removeAllTasks();\r\n loadingUITaskId = this.loadingSpinner.addTask('Downloading...');\r\n }\r\n\r\n const onLoadProgress = (fileIndex, percent, percentLabel, loaderStatus) => {\r\n percentComplete[fileIndex] = percent;\r\n let totalPercent = 0;\r\n for (let i = 0; i < fileCount; i++)\r\n totalPercent += percentComplete[i] || 0;\r\n totalPercent = totalPercent / fileCount;\r\n percentLabel = `${totalPercent.toFixed(2)}%`;\r\n if (showLoadingUI) {\r\n if (loaderStatus === LoaderStatus.Downloading) {\r\n this.loadingSpinner.setMessageForTask(\r\n loadingUITaskId,\r\n totalPercent == 100\r\n ? `Download complete!`\r\n : `Downloading: ${percentLabel}`\r\n );\r\n }\r\n }\r\n if (onProgress) onProgress(totalPercent, percentLabel, loaderStatus);\r\n };\r\n\r\n const abortController = new AbortController();\r\n const signal = abortController.signal;\r\n this.addSplatSceneDownloadController(abortController);\r\n\r\n const downloadPromises = [];\r\n for (let i = 0; i < sceneOptions.length; i++) {\r\n const options = sceneOptions[i];\r\n const format =\r\n options.format !== undefined && options.format !== null\r\n ? options.format\r\n : sceneFormatFromPath(options.path);\r\n const downloadPromise = this.downloadSplatSceneToSplatBuffer(\r\n options.path,\r\n options.splatAlphaRemovalThreshold,\r\n onLoadProgress.bind(this, i),\r\n false,\r\n undefined,\r\n format,\r\n options.headers,\r\n signal\r\n );\r\n downloadPromises.push(downloadPromise);\r\n }\r\n\r\n const downloadAndBuildPromise = Promise.all(downloadPromises)\r\n .then((splatBuffers) => {\r\n if (showLoadingUI) this.loadingSpinner.removeTask(loadingUITaskId);\r\n if (onProgress) onProgress(0, '0%', LoaderStatus.Processing);\r\n return this.addSplatBuffers(\r\n splatBuffers,\r\n sceneOptions,\r\n true,\r\n showLoadingUI,\r\n showLoadingUI,\r\n false,\r\n false\r\n ).then(() => {\r\n if (onProgress) onProgress(100, '100%', LoaderStatus.Processing);\r\n this.clearSplatSceneDownloadAndBuildPromise();\r\n });\r\n })\r\n .catch((e) => {\r\n if (showLoadingUI) this.loadingSpinner.removeTask(loadingUITaskId);\r\n this.clearSplatSceneDownloadAndBuildPromise();\r\n const error =\r\n e.name === 'AbortError'\r\n ? e\r\n : new Error(\r\n `Viewer::addSplatScenes -> Could not load one or more splat scenes.`\r\n );\r\n throw error;\r\n })\r\n .finally(() => {\r\n this.removeSplatSceneDownloadController(abortController);\r\n });\r\n\r\n this.setSplatSceneDownloadAndBuildPromise(downloadAndBuildPromise);\r\n return downloadAndBuildPromise\r\n }\r\n\r\n /**\r\n * Download a splat scene and convert to SplatBuffer instance.\r\n * @param {string} path Path to splat scene to be loaded\r\n * @param {number} splatAlphaRemovalThreshold Ignore any splats with an alpha less than the specified\r\n * value (valid range: 0 - 255), defaults to 1\r\n *\r\n * @param {function} onProgress Function to be called as file data are received\r\n * @param {boolean} progressiveBuild Construct file sections into splat buffers as they are downloaded\r\n * @param {function} onSectionBuilt Function to be called when new section is added to the file\r\n * @param {string} format File format of the scene\r\n * @param {object} headers Optional HTTP headers to pass to use for downloading splat scene\r\n * @param {AbortSignal} signal Optional AbortSignal to cancel the download\r\n * @return {AbortablePromise}\r\n */\r\n downloadSplatSceneToSplatBuffer(\r\n path,\r\n splatAlphaRemovalThreshold = 1,\r\n onProgress = undefined,\r\n progressiveBuild = false,\r\n onSectionBuilt = undefined,\r\n format,\r\n headers\r\n ) {\r\n const optimizeSplatData = progressiveBuild ? false : this.optimizeSplatData;\r\n try {\r\n if (format === SceneFormat.Ply) {\r\n return PlyLoader.loadFromURL(\r\n path,\r\n onProgress,\r\n progressiveBuild,\r\n onSectionBuilt,\r\n splatAlphaRemovalThreshold,\r\n this.inMemoryCompressionLevel,\r\n optimizeSplatData,\r\n this.sphericalHarmonicsDegree,\r\n headers\r\n )\r\n }\r\n } catch (e) {\r\n if (e instanceof DirectLoadError) {\r\n throw new Error(\r\n 'File type or server does not support progressive loading.'\r\n )\r\n } else {\r\n throw e\r\n }\r\n }\r\n\r\n throw new Error(\r\n `Viewer::downloadSplatSceneToSplatBuffer -> File format not supported: ${path}`\r\n )\r\n }\r\n\r\n static isProgressivelyLoadable(format) {\r\n return format === SceneFormat.Ply\r\n }\r\n\r\n /**\r\n * Add one or more instances of SplatBuffer to the SplatMesh instance managed by the viewer and set up the sorting web worker.\r\n * This function will terminate the existing sort worker (if there is one).\r\n */\r\n addSplatBuffers = (\r\n splatBuffers,\r\n splatBufferOptions = [],\r\n finalBuild = true,\r\n showLoadingUI = true,\r\n showLoadingUIForSplatTreeBuild = true,\r\n replaceExisting = false,\r\n enableRenderBeforeFirstSort = false,\r\n preserveVisibleRegion = true\r\n ) => {\r\n if (this.isDisposingOrDisposed()) return Promise.resolve()\r\n\r\n let splatProcessingTaskId = null;\r\n const removeSplatProcessingTask = () => {\r\n if (splatProcessingTaskId !== null) {\r\n this.loadingSpinner.removeTask(splatProcessingTaskId);\r\n splatProcessingTaskId = null;\r\n }\r\n };\r\n\r\n this.splatRenderReady = false;\r\n return new Promise((resolve) => {\r\n if (showLoadingUI) {\r\n splatProcessingTaskId = this.loadingSpinner.addTask(\r\n 'Processing splats...'\r\n );\r\n }\r\n delayedExecute(() => {\r\n if (this.isDisposingOrDisposed()) {\r\n resolve();\r\n } else {\r\n const buildResults = this.addSplatBuffersToMesh(\r\n splatBuffers,\r\n splatBufferOptions,\r\n finalBuild,\r\n showLoadingUIForSplatTreeBuild,\r\n replaceExisting,\r\n preserveVisibleRegion\r\n );\r\n\r\n const maxSplatCount = this.splatMesh.getMaxSplatCount();\r\n if (\r\n this.sortWorker &&\r\n this.sortWorker.maxSplatCount !== maxSplatCount\r\n )\r\n this.disposeSortWorker();\r\n // If we aren't calculating the splat distances from the center on the GPU, the sorting worker needs\r\n // splat centers and transform indexes so that it can calculate those distance values.\r\n if (!this.gpuAcceleratedSort) {\r\n this.preSortMessages.push({\r\n centers: buildResults.centers.buffer,\r\n sceneIndexes: buildResults.sceneIndexes.buffer,\r\n range: {\r\n from: buildResults.from,\r\n to: buildResults.to,\r\n count: buildResults.count\r\n }\r\n });\r\n }\r\n const sortWorkerSetupPromise =\r\n !this.sortWorker && maxSplatCount > 0\r\n ? this.setupSortWorker(this.splatMesh)\r\n : Promise.resolve();\r\n sortWorkerSetupPromise.then(() => {\r\n if (this.isDisposingOrDisposed()) return\r\n this.runSplatSort(true, true).then((sortRunning) => {\r\n if (!this.sortWorker || !sortRunning) {\r\n this.splatRenderReady = true;\r\n removeSplatProcessingTask();\r\n resolve();\r\n } else {\r\n if (enableRenderBeforeFirstSort) {\r\n this.splatRenderReady = true;\r\n } else {\r\n this.runAfterNextSort.push(() => {\r\n this.splatRenderReady = true;\r\n });\r\n }\r\n this.runAfterNextSort.push(() => {\r\n removeSplatProcessingTask();\r\n resolve();\r\n });\r\n }\r\n });\r\n });\r\n }\r\n }, true);\r\n })\r\n }\r\n\r\n /**\r\n * Add one or more instances of SplatBuffer to the SplatMesh instance managed by the viewer. By default, this function is additive;\r\n * all splat buffers contained by the viewer's splat mesh before calling this function will be preserved. This behavior can be\r\n * changed by passing 'true' for 'replaceExisting'.\r\n * @param {Array<SplatBuffer>} splatBuffers SplatBuffer instances\r\n * @param {Array<object>} splatBufferOptions Array of options objects: {\r\n *\r\n * splatAlphaRemovalThreshold: Ignore any splats with an alpha less than the specified\r\n * value (valid range: 0 - 255), defaults to 1\r\n *\r\n * position (Array<number>): Position of the scene, acts as an offset from its default position, defaults to [0, 0, 0]\r\n *\r\n * rotation (Array<number>): Rotation of the scene represented as a quaternion, defaults to [0, 0, 0, 1]\r\n *\r\n * scale (Array<number>): Scene's scale, defaults to [1, 1, 1]\r\n * }\r\n * @param {boolean} finalBuild Will the splat mesh be in its final state after this build?\r\n * @param {boolean} showLoadingUIForSplatTreeBuild Whether or not to show the loading spinner during construction of the splat tree.\r\n * @return {object} Object containing info about the splats that are updated\r\n */\r\n addSplatBuffersToMesh = (function () {\r\n let splatOptimizingTaskId;\r\n\r\n return function (\r\n splatBuffers,\r\n splatBufferOptions,\r\n finalBuild = true,\r\n showLoadingUIForSplatTreeBuild = false,\r\n replaceExisting = false,\r\n preserveVisibleRegion = true\r\n ) {\r\n if (this.isDisposingOrDisposed()) return\r\n let allSplatBuffers = [];\r\n let allSplatBufferOptions = [];\r\n if (!replaceExisting) {\r\n allSplatBuffers =\r\n this.splatMesh.scenes.map((scene) => scene.splatBuffer) || [];\r\n allSplatBufferOptions = this.splatMesh.sceneOptions\r\n ? this.splatMesh.sceneOptions.map((sceneOptions) => sceneOptions)\r\n : [];\r\n }\r\n allSplatBuffers.push(...splatBuffers);\r\n allSplatBufferOptions.push(...splatBufferOptions);\r\n if (this.renderer) this.splatMesh.setRenderer(this.renderer);\r\n const onSplatTreeIndexesUpload = (finished) => {\r\n if (this.isDisposingOrDisposed()) return\r\n const splatCount = this.splatMesh.getSplatCount();\r\n if (\r\n showLoadingUIForSplatTreeBuild &&\r\n splatCount >= MIN_SPLAT_COUNT_TO_SHOW_SPLAT_TREE_LOADING_SPINNER\r\n ) {\r\n if (!finished && !splatOptimizingTaskId) {\r\n this.loadingSpinner.setMinimized(true, true);\r\n splatOptimizingTaskId = this.loadingSpinner.addTask(\r\n 'Optimizing data structures...'\r\n );\r\n }\r\n }\r\n };\r\n const onSplatTreeReady = (finished) => {\r\n if (this.isDisposingOrDisposed()) return\r\n if (finished && splatOptimizingTaskId) {\r\n this.loadingSpinner.removeTask(splatOptimizingTaskId);\r\n splatOptimizingTaskId = null;\r\n }\r\n };\r\n const buildResults = this.splatMesh.build(\r\n allSplatBuffers,\r\n allSplatBufferOptions,\r\n true,\r\n finalBuild,\r\n onSplatTreeIndexesUpload,\r\n onSplatTreeReady,\r\n preserveVisibleRegion\r\n );\r\n if (finalBuild && this.freeIntermediateSplatData)\r\n this.splatMesh.freeIntermediateSplatData();\r\n return buildResults\r\n }\r\n })()\r\n\r\n /**\r\n * Set up the splat sorting web worker.\r\n * @param {SplatMesh} splatMesh SplatMesh instance that contains the splats to be sorted\r\n * @return {Promise}\r\n */\r\n async setupSortWorker(splatMesh) {\r\n if (this.isDisposingOrDisposed()) return\r\n const DistancesArrayType = this.integerBasedSort\r\n ? Int32Array\r\n : Float32Array;\r\n const splatCount = splatMesh.getSplatCount();\r\n const maxSplatCount = splatMesh.getMaxSplatCount();\r\n this.sortWorker = await createSortWorker(\r\n maxSplatCount,\r\n this.sharedMemoryForWorkers,\r\n this.enableSIMDInSort,\r\n this.integerBasedSort,\r\n this.splatMesh.dynamicMode,\r\n this.splatSortDistanceMapPrecision\r\n );\r\n return new Promise((resolve) => {\r\n this.sortWorker.onmessage = (e) => {\r\n if (e.data.sortDone) {\r\n this.sortRunning = false;\r\n let numbersArray = Array.from(\r\n { length: this.gaussianSplatCount },\r\n (_, i) => i\r\n );\r\n if (this.sharedMemoryForWorkers) {\r\n this.splatMesh.updateRenderIndexes(\r\n this.sortWorkerSortedIndexes,\r\n e.data.splatRenderCount\r\n );\r\n } else {\r\n const sortedIndexes = new Uint32Array(\r\n e.data.sortedIndexes.buffer,\r\n 0,\r\n e.data.splatRenderCount\r\n );\r\n this.splatMesh.updateRenderIndexes(\r\n sortedIndexes,\r\n e.data.splatRenderCount\r\n );\r\n }\r\n\r\n this.lastSplatSortCount = this.splatSortCount;\r\n\r\n this.lastSortTime = e.data.sortTime;\r\n this.sortPromiseResolver();\r\n this.sortPromiseResolver = null;\r\n this.forceRenderNextFrame();\r\n if (this.runAfterNextSort.length > 0) {\r\n this.runAfterNextSort.forEach((func) => {\r\n func();\r\n });\r\n this.runAfterNextSort.length = 0;\r\n }\r\n } else if (e.data.sortCanceled) {\r\n this.sortRunning = false;\r\n } else if (e.data.sortSetupPhase1Complete) {\r\n if (this.logLevel >= LogLevel.Info)\r\n logger.info('Sorting web worker WASM setup complete.');\r\n if (this.sharedMemoryForWorkers) {\r\n this.sortWorkerSortedIndexes = new Uint32Array(\r\n e.data.sortedIndexesBuffer,\r\n e.data.sortedIndexesOffset,\r\n maxSplatCount\r\n );\r\n this.sortWorkerIndexesToSort = new Uint32Array(\r\n e.data.indexesToSortBuffer,\r\n e.data.indexesToSortOffset,\r\n maxSplatCount\r\n );\r\n this.sortWorkerPrecomputedDistances = new DistancesArrayType(\r\n e.data.precomputedDistancesBuffer,\r\n e.data.precomputedDistancesOffset,\r\n maxSplatCount\r\n );\r\n this.sortWorkerTransforms = new Float32Array(\r\n e.data.transformsBuffer,\r\n e.data.transformsOffset,\r\n Constants.MaxScenes * 16\r\n );\r\n } else {\r\n this.sortWorkerIndexesToSort = new Uint32Array(maxSplatCount);\r\n this.sortWorkerPrecomputedDistances = new DistancesArrayType(\r\n maxSplatCount\r\n );\r\n this.sortWorkerTransforms = new Float32Array(\r\n Constants.MaxScenes * 16\r\n );\r\n }\r\n for (let i = 0; i < splatCount; i++)\r\n this.sortWorkerIndexesToSort[i] = i;\r\n this.sortWorker.maxSplatCount = maxSplatCount;\r\n\r\n if (this.logLevel >= LogLevel.Info) {\r\n logger.info('Sorting web worker ready.');\r\n const splatDataTextures = this.splatMesh.getSplatDataTextures();\r\n const covariancesTextureSize = splatDataTextures.covariances.size;\r\n const centersColorsTextureSize = splatDataTextures.centerColors.size;\r\n logger.info(\r\n 'Covariances texture size: ' +\r\n covariancesTextureSize.x +\r\n ' x ' +\r\n covariancesTextureSize.y\r\n );\r\n logger.info(\r\n 'Centers/colors texture size: ' +\r\n centersColorsTextureSize.x +\r\n ' x ' +\r\n centersColorsTextureSize.y\r\n );\r\n }\r\n\r\n resolve();\r\n }\r\n };\r\n })\r\n }\r\n\r\n disposeSortWorker() {\r\n if (this.sortWorker) this.sortWorker.terminate();\r\n this.sortWorker = null;\r\n this.sortPromise = null;\r\n if (this.sortPromiseResolver) {\r\n this.sortPromiseResolver();\r\n this.sortPromiseResolver = null;\r\n }\r\n this.preSortMessages = [];\r\n this.sortRunning = false;\r\n }\r\n\r\n removeSplatScene(indexToRemove, showLoadingUI = true) {\r\n return this.removeSplatScenes([indexToRemove], showLoadingUI)\r\n }\r\n\r\n removeSplatScenes(indexesToRemove, showLoadingUI = true) {\r\n if (this.isLoadingOrUnloading()) {\r\n throw new Error(\r\n 'Cannot remove splat scene while another load or unload is already in progress.'\r\n )\r\n }\r\n\r\n if (this.isDisposingOrDisposed()) {\r\n throw new Error('Cannot remove splat scene after dispose() is called.')\r\n }\r\n\r\n let sortPromise;\r\n\r\n this.splatSceneRemovalPromise = new Promise((resolve, reject) => {\r\n let revmovalTaskId;\r\n\r\n if (showLoadingUI) {\r\n this.loadingSpinner.removeAllTasks();\r\n this.loadingSpinner.show();\r\n revmovalTaskId = this.loadingSpinner.addTask('Removing splat scene...');\r\n }\r\n\r\n const checkAndHideLoadingUI = () => {\r\n if (showLoadingUI) {\r\n this.loadingSpinner.hide();\r\n this.loadingSpinner.removeTask(revmovalTaskId);\r\n }\r\n };\r\n\r\n const onDone = (error) => {\r\n checkAndHideLoadingUI();\r\n this.splatSceneRemovalPromise = null;\r\n if (!error) resolve();\r\n else reject(error);\r\n };\r\n\r\n const checkForEarlyExit = () => {\r\n if (this.isDisposingOrDisposed()) {\r\n onDone();\r\n return true\r\n }\r\n return false\r\n };\r\n\r\n sortPromise = this.sortPromise || Promise.resolve();\r\n sortPromise.then(() => {\r\n if (checkForEarlyExit()) return\r\n const savedSplatBuffers = [];\r\n const savedSceneOptions = [];\r\n const savedSceneTransformComponents = [];\r\n for (let i = 0; i < this.splatMesh.scenes.length; i++) {\r\n let shouldRemove = false;\r\n for (let indexToRemove of indexesToRemove) {\r\n if (indexToRemove === i) {\r\n shouldRemove = true;\r\n break\r\n }\r\n }\r\n if (!shouldRemove) {\r\n const scene = this.splatMesh.scenes[i];\r\n savedSplatBuffers.push(scene.splatBuffer);\r\n savedSceneOptions.push(this.splatMesh.sceneOptions[i]);\r\n savedSceneTransformComponents.push({\r\n position: scene.position.clone(),\r\n quaternion: scene.quaternion.clone(),\r\n scale: scene.scale.clone()\r\n });\r\n }\r\n }\r\n this.disposeSortWorker();\r\n this.splatMesh.dispose();\r\n this.sceneRevealMode = SceneRevealMode.Instant;\r\n this.createSplatMesh();\r\n this.addSplatBuffers(\r\n savedSplatBuffers,\r\n savedSceneOptions,\r\n true,\r\n false,\r\n true\r\n )\r\n .then(() => {\r\n if (checkForEarlyExit()) return\r\n checkAndHideLoadingUI();\r\n this.splatMesh.scenes.forEach((scene, index) => {\r\n scene.position.copy(savedSceneTransformComponents[index].position);\r\n scene.quaternion.copy(\r\n savedSceneTransformComponents[index].quaternion\r\n );\r\n scene.scale.copy(savedSceneTransformComponents[index].scale);\r\n });\r\n this.splatMesh.updateTransforms();\r\n this.splatRenderReady = false;\r\n\r\n this.runSplatSort(true).then(() => {\r\n if (checkForEarlyExit()) {\r\n this.splatRenderReady = true;\r\n return\r\n }\r\n sortPromise = this.sortPromise || Promise.resolve();\r\n sortPromise.then(() => {\r\n this.splatRenderReady = true;\r\n onDone();\r\n });\r\n });\r\n })\r\n .catch((e) => {\r\n onDone(e);\r\n });\r\n });\r\n });\r\n\r\n return this.splatSceneRemovalPromise\r\n }\r\n\r\n /**\r\n * Start self-driven mode\r\n */\r\n start() {\r\n if (this.selfDrivenMode) {\r\n this.requestFrameId = requestAnimationFrame(this.selfDrivenUpdateFunc);\r\n this.selfDrivenModeRunning = true;\r\n } else {\r\n throw new Error('Cannot start viewer unless it is in self driven mode.')\r\n }\r\n }\r\n\r\n /**\r\n * Stop self-driven mode\r\n */\r\n stop() {\r\n if (this.selfDrivenMode && this.selfDrivenModeRunning) {\r\n cancelAnimationFrame(this.requestFrameId);\r\n this.selfDrivenModeRunning = false;\r\n }\r\n }\r\n\r\n /**\r\n * Dispose of all resources held directly and indirectly by this viewer.\r\n */\r\n async dispose() {\r\n if (this.isDisposingOrDisposed()) return this.disposePromise\r\n\r\n for (let controller of this.splatSceneDownloadControllers) {\r\n controller.abort();\r\n }\r\n\r\n let waitPromises = [];\r\n if (this.sortPromise) {\r\n waitPromises.push(this.sortPromise);\r\n }\r\n\r\n this.disposing = true;\r\n this.disposePromise = Promise.all(waitPromises).finally(() => {\r\n this.stop();\r\n if (this.orthographicControls) {\r\n this.orthographicControls.dispose();\r\n this.orthographicControls = null;\r\n }\r\n if (this.perspectiveControls) {\r\n this.perspectiveControls.dispose();\r\n this.perspectiveControls = null;\r\n }\r\n this.controls = null;\r\n if (this.splatMesh) {\r\n this.splatMesh.dispose();\r\n this.splatMesh = null;\r\n }\r\n if (this.avatarMesh) {\r\n disposeAllMeshes(this.avatarMesh);\r\n this.avatarMesh = null;\r\n }\r\n if (this.sceneHelper) {\r\n this.sceneHelper.dispose();\r\n this.sceneHelper = null;\r\n }\r\n if (this.resizeObserver) {\r\n this.resizeObserver.unobserve(this.rootElement);\r\n this.resizeObserver = null;\r\n }\r\n this.disposeSortWorker();\r\n this.removeEventHandlers();\r\n\r\n this.loadingSpinner.removeAllTasks();\r\n this.loadingSpinner.setContainer(null);\r\n this.loadingProgressBar.hide();\r\n this.loadingProgressBar.setContainer(null);\r\n // this.infoPanel.setContainer(null)\r\n\r\n this.camera = null;\r\n this.threeScene = null;\r\n this.splatRenderReady = false;\r\n this.initialized = false;\r\n if (this.renderer) {\r\n if (!this.usingExternalRenderer) {\r\n this.rootElement.removeChild(this.renderer.domElement);\r\n this.renderer.dispose();\r\n }\r\n this.renderer = null;\r\n }\r\n\r\n if (!this.usingExternalRenderer) {\r\n // document.body.removeChild(this.rootElement);\r\n }\r\n\r\n this.sortWorkerSortedIndexes = null;\r\n this.sortWorkerIndexesToSort = null;\r\n this.sortWorkerPrecomputedDistances = null;\r\n this.sortWorkerTransforms = null;\r\n this.disposed = true;\r\n this.disposing = false;\r\n this.disposePromise = null;\r\n });\r\n return this.disposePromise\r\n }\r\n vsyncNum = 4\r\n selfDrivenUpdate() {\r\n if (this.selfDrivenMode) {\r\n this.requestFrameId = requestAnimationFrame(this.selfDrivenUpdateFunc);\r\n\r\n // const currentTime = getCurrentTime();\r\n // const calcDelta = currentTime - this.lastTime;\r\n // if (calcDelta >= 1.0 / 30.0) {\r\n // this.lastTime = currentTime;\r\n // } else {\r\n // return\r\n // }\r\n }\r\n this.vsyncCount++;\r\n\r\n if (this.vsyncCount < this.vsyncNum) {\r\n return\r\n }\r\n\r\n this.vsyncCount = 0;\r\n\r\n this.update();\r\n if (this.shouldRender()) {\r\n //add expression\r\n\r\n this.render();\r\n this.consecutiveRenderFrames++;\r\n } else {\r\n this.consecutiveRenderFrames = 0;\r\n }\r\n this.renderNextFrame = false;\r\n }\r\n\r\n forceRenderNextFrame() {\r\n this.renderNextFrame = true;\r\n }\r\n\r\n shouldRender = (function () {\r\n let renderCount = 0;\r\n const lastCameraPosition = new Vector3();\r\n const lastCameraOrientation = new Quaternion();\r\n const changeEpsilon = 0.0001;\r\n\r\n return function () {\r\n if (\r\n !this.initialized ||\r\n !this.splatRenderReady ||\r\n this.isDisposingOrDisposed()\r\n )\r\n return false\r\n\r\n let shouldRender = false;\r\n let cameraChanged = false;\r\n if (this.camera) {\r\n const cp = this.camera.position;\r\n const co = this.camera.quaternion;\r\n cameraChanged =\r\n Math.abs(cp.x - lastCameraPosition.x) > changeEpsilon ||\r\n Math.abs(cp.y - lastCameraPosition.y) > changeEpsilon ||\r\n Math.abs(cp.z - lastCameraPosition.z) > changeEpsilon ||\r\n Math.abs(co.x - lastCameraOrientation.x) > changeEpsilon ||\r\n Math.abs(co.y - lastCameraOrientation.y) > changeEpsilon ||\r\n Math.abs(co.z - lastCameraOrientation.z) > changeEpsilon ||\r\n Math.abs(co.w - lastCameraOrientation.w) > changeEpsilon;\r\n }\r\n\r\n shouldRender =\r\n this.renderMode !== RenderMode.Never &&\r\n (renderCount === 0 ||\r\n this.splatMesh.visibleRegionChanging ||\r\n cameraChanged ||\r\n this.renderMode === RenderMode.Always ||\r\n this.dynamicMode === true ||\r\n this.renderNextFrame);\r\n\r\n if (this.camera) {\r\n lastCameraPosition.copy(this.camera.position);\r\n lastCameraOrientation.copy(this.camera.quaternion);\r\n }\r\n\r\n renderCount++;\r\n return shouldRender\r\n }\r\n })()\r\n\r\n render = (function () {\r\n return function () {\r\n if (\r\n !this.initialized ||\r\n !this.splatRenderReady ||\r\n this.isDisposingOrDisposed()\r\n )\r\n return\r\n\r\n const hasRenderables = (threeScene) => {\r\n for (let child of threeScene.children) {\r\n if (child.visible) return true\r\n }\r\n return false\r\n };\r\n\r\n const savedAuoClear = this.renderer.autoClear;\r\n if (hasRenderables(this.threeScene)) {\r\n this.renderer.render(this.threeScene, this.camera);\r\n this.renderer.autoClear = false;\r\n }\r\n this.renderer.render(this.splatMesh, this.camera);\r\n this.renderer.autoClear = false;\r\n if (this.sceneHelper.getFocusMarkerOpacity() > 0.0)\r\n this.renderer.render(this.sceneHelper.focusMarker, this.camera);\r\n if (this.showControlPlane)\r\n this.renderer.render(this.sceneHelper.controlPlane, this.camera);\r\n this.renderer.autoClear = savedAuoClear;\r\n }\r\n })()\r\n\r\n\r\n update(renderer, camera) {\r\n // this.frame++\r\n const fpsDiv = document.getElementById('fps');\r\n if (fpsDiv) {\r\n fpsDiv.textContent = `FPS: ${this.currentFPS}`;\r\n }\r\n\r\n if(this.frame >= this.totalFrames) \r\n this.frame = 0;\r\n \r\n if (this.dropInMode) this.updateForDropInMode(renderer, camera);\r\n\r\n if (\r\n !this.initialized ||\r\n !this.splatRenderReady ||\r\n this.isDisposingOrDisposed()\r\n )\r\n return\r\n\r\n if (this.controls) {\r\n this.controls.update();\r\n if (this.camera.isOrthographicCamera && !this.usingExternalCamera) {\r\n Viewer.setCameraPositionFromZoom(\r\n this.camera,\r\n this.camera,\r\n this.controls\r\n );\r\n }\r\n }\r\n this.runMorphUpdate();\r\n this.runSplatSort(true,true);\r\n\r\n const replaceIndexes = false;\r\n if (replaceIndexes) {\r\n this.splatMesh.updateRenderIndexes(\r\n this.sortedIndexes,\r\n this.sortedIndexes.length\r\n );\r\n }\r\n\r\n this.updateForRendererSizeChanges();\r\n this.updateSplatMesh();\r\n this.updateMeshCursor();\r\n this.updateFPS();\r\n this.timingSensitiveUpdates();\r\n // this.updateInfoPanel()\r\n this.updateControlPlane();\r\n }\r\n\r\n sortedIndexes\r\n updateForDropInMode(renderer, camera) {\r\n this.renderer = renderer;\r\n if (this.splatMesh) this.splatMesh.setRenderer(this.renderer);\r\n this.camera = camera;\r\n if (this.controls) this.controls.object = camera;\r\n this.init();\r\n }\r\n\r\n lastCalcTime = getCurrentTime()\r\n fpsFrameCount = 0\r\n updateFPS = () => {\r\n if (\r\n this.consecutiveRenderFrames >\r\n CONSECUTIVE_RENDERED_FRAMES_FOR_FPS_CALCULATION\r\n ) {\r\n const currentTime = getCurrentTime();\r\n const calcDelta = currentTime - this.lastCalcTime;\r\n if (calcDelta >= 1.0) {\r\n this.currentFPS = this.fpsFrameCount;\r\n this.fpsFrameCount = 0;\r\n this.lastCalcTime = currentTime;\r\n } else {\r\n this.fpsFrameCount++;\r\n }\r\n } else {\r\n this.currentFPS = null;\r\n }\r\n }\r\n\r\n updateForRendererSizeChanges = (function () {\r\n const lastRendererSize = new Vector2();\r\n const currentRendererSize = new Vector2();\r\n let lastCameraOrthographic;\r\n\r\n return function () {\r\n if (!this.usingExternalCamera) {\r\n this.renderer.getSize(currentRendererSize);\r\n if (\r\n lastCameraOrthographic === undefined ||\r\n lastCameraOrthographic !== this.camera.isOrthographicCamera ||\r\n currentRendererSize.x !== lastRendererSize.x ||\r\n currentRendererSize.y !== lastRendererSize.y\r\n ) {\r\n if (this.camera.isOrthographicCamera) {\r\n this.camera.left = -currentRendererSize.x / 2.0;\r\n this.camera.right = currentRendererSize.x / 2.0;\r\n this.camera.top = currentRendererSize.y / 2.0;\r\n this.camera.bottom = -currentRendererSize.y / 2.0;\r\n } else {\r\n this.camera.aspect = currentRendererSize.x / currentRendererSize.y;\r\n }\r\n this.camera.updateProjectionMatrix();\r\n lastRendererSize.copy(currentRendererSize);\r\n lastCameraOrthographic = this.camera.isOrthographicCamera;\r\n }\r\n }\r\n }\r\n })()\r\n\r\n timingSensitiveUpdates = (function () {\r\n let lastUpdateTime;\r\n\r\n return function () {\r\n const currentTime = getCurrentTime();\r\n if (!lastUpdateTime) lastUpdateTime = currentTime;\r\n const timeDelta = currentTime - lastUpdateTime;\r\n\r\n this.updateCameraTransition(currentTime);\r\n this.updateFocusMarker(timeDelta);\r\n\r\n lastUpdateTime = currentTime;\r\n }\r\n })()\r\n\r\n tempCameraTarget = new Vector3()\r\n toPreviousTarget = new Vector3()\r\n toNextTarget = new Vector3()\r\n updateCameraTransition = (currentTime) => {\r\n if (this.transitioningCameraTarget) {\r\n this.toPreviousTarget\r\n .copy(this.previousCameraTarget)\r\n .sub(this.camera.position)\r\n .normalize();\r\n this.toNextTarget\r\n .copy(this.nextCameraTarget)\r\n .sub(this.camera.position)\r\n .normalize();\r\n const rotationAngle = Math.acos(\r\n this.toPreviousTarget.dot(this.toNextTarget)\r\n );\r\n const rotationSpeed = (rotationAngle / (Math.PI / 3)) * 0.65 + 0.3;\r\n const t =\r\n (rotationSpeed / rotationAngle) *\r\n (currentTime - this.transitioningCameraTargetStartTime);\r\n this.tempCameraTarget\r\n .copy(this.previousCameraTarget)\r\n .lerp(this.nextCameraTarget, t);\r\n this.camera.lookAt(this.tempCameraTarget);\r\n this.controls.target.copy(this.tempCameraTarget);\r\n if (t >= 1.0) {\r\n this.transitioningCameraTarget = false;\r\n }\r\n }\r\n }\r\n\r\n updateFocusMarker = (function () {\r\n const renderDimensions = new Vector2();\r\n let wasTransitioning = false;\r\n\r\n return function (timeDelta) {\r\n this.getRenderDimensions(renderDimensions);\r\n if (this.transitioningCameraTarget) {\r\n this.sceneHelper.setFocusMarkerVisibility(true);\r\n const currentFocusMarkerOpacity = Math.max(\r\n this.sceneHelper.getFocusMarkerOpacity(),\r\n 0.0\r\n );\r\n let newFocusMarkerOpacity = Math.min(\r\n currentFocusMarkerOpacity + FOCUS_MARKER_FADE_IN_SPEED * timeDelta,\r\n 1.0\r\n );\r\n this.sceneHelper.setFocusMarkerOpacity(newFocusMarkerOpacity);\r\n this.sceneHelper.updateFocusMarker(\r\n this.nextCameraTarget,\r\n this.camera,\r\n renderDimensions\r\n );\r\n wasTransitioning = true;\r\n this.forceRenderNextFrame();\r\n } else {\r\n let currentFocusMarkerOpacity;\r\n if (wasTransitioning) currentFocusMarkerOpacity = 1.0;\r\n else\r\n currentFocusMarkerOpacity = Math.min(\r\n this.sceneHelper.getFocusMarkerOpacity(),\r\n 1.0\r\n );\r\n if (currentFocusMarkerOpacity > 0) {\r\n this.sceneHelper.updateFocusMarker(\r\n this.nextCameraTarget,\r\n this.camera,\r\n renderDimensions\r\n );\r\n let newFocusMarkerOpacity = Math.max(\r\n currentFocusMarkerOpacity - FOCUS_MARKER_FADE_OUT_SPEED * timeDelta,\r\n 0.0\r\n );\r\n this.sceneHelper.setFocusMarkerOpacity(newFocusMarkerOpacity);\r\n if (newFocusMarkerOpacity === 0.0)\r\n this.sceneHelper.setFocusMarkerVisibility(false);\r\n }\r\n if (currentFocusMarkerOpacity > 0.0) this.forceRenderNextFrame();\r\n wasTransitioning = false;\r\n }\r\n }\r\n })()\r\n\r\n updateMeshCursor = (function () {\r\n const outHits = [];\r\n const renderDimensions = new Vector2();\r\n\r\n return function () {\r\n if (this.showMeshCursor) {\r\n this.forceRenderNextFrame();\r\n this.getRenderDimensions(renderDimensions);\r\n outHits.length = 0;\r\n this.raycaster.setFromCameraAndScreenPosition(\r\n this.camera,\r\n this.mousePosition,\r\n renderDimensions\r\n );\r\n this.raycaster.intersectSplatMesh(this.splatMesh, outHits);\r\n if (outHits.length > 0) {\r\n this.sceneHelper.setMeshCursorVisibility(true);\r\n this.sceneHelper.positionAndOrientMeshCursor(\r\n outHits[0].origin,\r\n this.camera\r\n );\r\n } else {\r\n this.sceneHelper.setMeshCursorVisibility(false);\r\n }\r\n } else {\r\n if (this.sceneHelper.getMeschCursorVisibility())\r\n this.forceRenderNextFrame();\r\n this.sceneHelper.setMeshCursorVisibility(false);\r\n }\r\n }\r\n })()\r\n\r\n updateInfoPanel = (function () {\r\n const renderDimensions = new Vector2();\r\n\r\n return function () {\r\n if (!this.showInfo) return\r\n const splatCount = this.splatMesh.getSplatCount();\r\n this.getRenderDimensions(renderDimensions);\r\n const cameraLookAtPosition = this.controls ? this.controls.target : null;\r\n const meshCursorPosition = this.showMeshCursor\r\n ? this.sceneHelper.meshCursor.position\r\n : null;\r\n const splatRenderCountPct =\r\n splatCount > 0 ? (this.splatRenderCount / splatCount) * 100 : 0;\r\n // this.infoPanel.update(\r\n // renderDimensions,\r\n // this.camera.position,\r\n // cameraLookAtPosition,\r\n // this.camera.up,\r\n // this.camera.isOrthographicCamera,\r\n // meshCursorPosition,\r\n // this.currentFPS || 'N/A',\r\n // splatCount,\r\n // this.splatRenderCount,\r\n // splatRenderCountPct,\r\n // this.lastSortTime,\r\n // this.focalAdjustment,\r\n // this.splatMesh.getSplatScale(),\r\n // this.splatMesh.getPointCloudModeEnabled()\r\n // )\r\n }\r\n })()\r\n\r\n updateControlPlane() {\r\n if (this.showControlPlane) {\r\n this.sceneHelper.setControlPlaneVisibility(true);\r\n this.sceneHelper.positionAndOrientControlPlane(\r\n this.controls.target,\r\n this.camera.up\r\n );\r\n } else {\r\n this.sceneHelper.setControlPlaneVisibility(false);\r\n }\r\n }\r\n\r\n mvpMatrix = new Matrix4()\r\n cameraPositionArray = []\r\n lastSortViewDir = new Vector3(0, 0, -1)\r\n sortViewDir = new Vector3(0, 0, -1)\r\n lastSortViewPos = new Vector3()\r\n sortViewOffset = new Vector3()\r\n queuedSorts = []\r\n\r\n partialSorts = [\r\n {\r\n angleThreshold: 0.55,\r\n sortFractions: [0.125, 0.33333, 0.75]\r\n },\r\n {\r\n angleThreshold: 0.65,\r\n sortFractions: [0.33333, 0.66667]\r\n },\r\n {\r\n angleThreshold: 0.8,\r\n sortFractions: [0.5]\r\n }\r\n ]\r\n runSplatSort = (force = false, forceSortAll = false) => {\r\n if (!this.initialized) return Promise.resolve(false)\r\n if (this.sortRunning) return Promise.resolve(true)\r\n if (this.splatMesh.getSplatCount() <= 0) {\r\n this.splatRenderCount = 0;\r\n return Promise.resolve(false)\r\n }\r\n\r\n let angleDiff = 0;\r\n let positionDiff = 0;\r\n let needsRefreshForRotation = false;\r\n let needsRefreshForPosition = false;\r\n\r\n this.sortViewDir.set(0, 0, -1).applyQuaternion(this.camera.quaternion);\r\n angleDiff = this.sortViewDir.dot(this.lastSortViewDir);\r\n positionDiff = this.sortViewOffset\r\n .copy(this.camera.position)\r\n .sub(this.lastSortViewPos)\r\n .length();\r\n\r\n if (!force) {\r\n if (!this.splatMesh.dynamicMode && this.queuedSorts.length === 0) {\r\n if (angleDiff <= 0.99) needsRefreshForRotation = true;\r\n if (positionDiff >= 1.0) needsRefreshForPosition = true;\r\n if (!needsRefreshForRotation && !needsRefreshForPosition)\r\n return Promise.resolve(false)\r\n }\r\n }\r\n\r\n this.sortRunning = true;\r\n let { splatRenderCount, shouldSortAll } = this.gatherSceneNodesForSort();\r\n shouldSortAll = shouldSortAll || forceSortAll;\r\n this.splatRenderCount = splatRenderCount;\r\n\r\n this.mvpMatrix.copy(this.camera.matrixWorld).invert();\r\n const mvpCamera = this.perspectiveCamera || this.camera;\r\n this.mvpMatrix.premultiply(mvpCamera.projectionMatrix);\r\n if (!this.splatMesh.dynamicMode)\r\n this.mvpMatrix.multiply(this.splatMesh.matrixWorld);\r\n\r\n let gpuAcceleratedSortPromise = Promise.resolve(true);\r\n if (\r\n this.gpuAcceleratedSort &&\r\n (this.queuedSorts.length <= 1 || this.queuedSorts.length % 2 === 0)\r\n ) {\r\n gpuAcceleratedSortPromise = this.splatMesh.computeDistancesOnGPU(\r\n this.mvpMatrix,\r\n this.sortWorkerPrecomputedDistances\r\n );\r\n }\r\n\r\n gpuAcceleratedSortPromise.then(() => {\r\n if (this.queuedSorts.length === 0) {\r\n if (this.splatMesh.dynamicMode || shouldSortAll) {\r\n this.queuedSorts.push(this.splatRenderCount);\r\n } else {\r\n for (let partialSort of this.partialSorts) {\r\n if (angleDiff < partialSort.angleThreshold) {\r\n for (let sortFraction of partialSort.sortFractions) {\r\n this.queuedSorts.push(\r\n Math.floor(this.splatRenderCount * sortFraction)\r\n );\r\n }\r\n break\r\n }\r\n }\r\n this.queuedSorts.push(this.splatRenderCount);\r\n }\r\n }\r\n let sortCount = Math.min(this.queuedSorts.shift(), this.splatRenderCount);\r\n this.splatSortCount = sortCount;\r\n\r\n this.cameraPositionArray[0] = this.camera.position.x;\r\n this.cameraPositionArray[1] = this.camera.position.y;\r\n this.cameraPositionArray[2] = this.camera.position.z;\r\n\r\n const sortMessage = {\r\n modelViewProj: this.mvpMatrix.elements,\r\n cameraPosition: this.cameraPositionArray,\r\n splatRenderCount: this.splatRenderCount,\r\n splatSortCount: sortCount,\r\n usePrecomputedDistances: this.gpuAcceleratedSort\r\n };\r\n if (this.splatMesh.dynamicMode) {\r\n this.splatMesh.fillTransformsArray(this.sortWorkerTransforms);\r\n }\r\n if (!this.sharedMemoryForWorkers) {\r\n sortMessage.indexesToSort = this.sortWorkerIndexesToSort;\r\n sortMessage.transforms = this.sortWorkerTransforms;\r\n if (this.gpuAcceleratedSort) {\r\n sortMessage.precomputedDistances = this.sortWorkerPrecomputedDistances;\r\n }\r\n }\r\n\r\n this.sortPromise = new Promise((resolve) => {\r\n this.sortPromiseResolver = resolve;\r\n });\r\n\r\n if (this.preSortMessages.length > 0) {\r\n this.preSortMessages.forEach((message) => {\r\n this.sortWorker.postMessage(message);\r\n });\r\n this.preSortMessages = [];\r\n }\r\n this.sortWorker.postMessage({\r\n sort: sortMessage\r\n });\r\n\r\n if (this.queuedSorts.length === 0) {\r\n this.lastSortViewPos.copy(this.camera.position);\r\n this.lastSortViewDir.copy(this.sortViewDir);\r\n }\r\n\r\n return true\r\n });\r\n\r\n return gpuAcceleratedSortPromise\r\n }\r\n\r\n /**\r\n * Determine which splats to render by checking which are inside or close to the view frustum\r\n */\r\n gatherSceneNodesForSort = (function () {\r\n const nodeRenderList = [];\r\n let allSplatsSortBuffer = null;\r\n const tempVectorYZ = new Vector3();\r\n const tempVectorXZ = new Vector3();\r\n const tempVector = new Vector3();\r\n const modelView = new Matrix4();\r\n const baseModelView = new Matrix4();\r\n const sceneTransform = new Matrix4();\r\n const renderDimensions = new Vector3();\r\n const forward = new Vector3(0, 0, -1);\r\n\r\n const tempMax = new Vector3();\r\n const nodeSize = (node) => {\r\n return tempMax.copy(node.max).sub(node.min).length()\r\n };\r\n\r\n return function (gatherAllNodes = false) {\r\n this.getRenderDimensions(renderDimensions);\r\n const cameraFocalLength =\r\n renderDimensions.y /\r\n 2.0 /\r\n Math.tan((this.camera.fov / 2.0) * MathUtils.DEG2RAD);\r\n const fovXOver2 = Math.atan(renderDimensions.x / 2.0 / cameraFocalLength);\r\n const fovYOver2 = Math.atan(renderDimensions.y / 2.0 / cameraFocalLength);\r\n const cosFovXOver2 = Math.cos(fovXOver2);\r\n const cosFovYOver2 = Math.cos(fovYOver2);\r\n\r\n const splatTree = this.splatMesh.getSplatTree();\r\n\r\n if (splatTree) {\r\n baseModelView.copy(this.camera.matrixWorld).invert();\r\n if (!this.splatMesh.dynamicMode)\r\n baseModelView.multiply(this.splatMesh.matrixWorld);\r\n\r\n let nodeRenderCount = 0;\r\n let splatRenderCount = 0;\r\n\r\n for (let s = 0; s < splatTree.subTrees.length; s++) {\r\n const subTree = splatTree.subTrees[s];\r\n modelView.copy(baseModelView);\r\n if (this.splatMesh.dynamicMode) {\r\n this.splatMesh.getSceneTransform(s, sceneTransform);\r\n modelView.multiply(sceneTransform);\r\n }\r\n const nodeCount = subTree.nodesWithIndexes.length;\r\n for (let i = 0; i < nodeCount; i++) {\r\n const node = subTree.nodesWithIndexes[i];\r\n if (\r\n !node.data ||\r\n !node.data.indexes ||\r\n node.data.indexes.length === 0\r\n )\r\n continue\r\n tempVector.copy(node.center).applyMatrix4(modelView);\r\n\r\n const distanceToNode = tempVector.length();\r\n tempVector.normalize();\r\n\r\n tempVectorYZ.copy(tempVector).setX(0).normalize();\r\n tempVectorXZ.copy(tempVector).setY(0).normalize();\r\n\r\n const cameraAngleXZDot = forward.dot(tempVectorXZ);\r\n const cameraAngleYZDot = forward.dot(tempVectorYZ);\r\n\r\n const ns = nodeSize(node);\r\n const outOfFovY = cameraAngleYZDot < cosFovYOver2 - 0.6;\r\n const outOfFovX = cameraAngleXZDot < cosFovXOver2 - 0.6;\r\n if (\r\n !gatherAllNodes &&\r\n (outOfFovX || outOfFovY) &&\r\n distanceToNode > ns\r\n ) {\r\n continue\r\n }\r\n splatRenderCount += node.data.indexes.length;\r\n nodeRenderList[nodeRenderCount] = node;\r\n node.data.distanceToNode = distanceToNode;\r\n nodeRenderCount++;\r\n }\r\n }\r\n\r\n nodeRenderList.length = nodeRenderCount;\r\n nodeRenderList.sort((a, b) => {\r\n if (a.data.distanceToNode < b.data.distanceToNode) return -1\r\n else return 1\r\n });\r\n\r\n let currentByteOffset = splatRenderCount * Constants.BytesPerInt;\r\n for (let i = 0; i < nodeRenderCount; i++) {\r\n const node = nodeRenderList[i];\r\n const windowSizeInts = node.data.indexes.length;\r\n const windowSizeBytes = windowSizeInts * Constants.BytesPerInt;\r\n let destView = new Uint32Array(\r\n this.sortWorkerIndexesToSort.buffer,\r\n currentByteOffset - windowSizeBytes,\r\n windowSizeInts\r\n );\r\n destView.set(node.data.indexes);\r\n currentByteOffset -= windowSizeBytes;\r\n }\r\n\r\n return {\r\n splatRenderCount: splatRenderCount,\r\n shouldSortAll: false\r\n }\r\n } else {\r\n const totalSplatCount = this.splatMesh.getSplatCount();\r\n if (\r\n !allSplatsSortBuffer ||\r\n allSplatsSortBuffer.length !== totalSplatCount\r\n ) {\r\n allSplatsSortBuffer = new Uint32Array(totalSplatCount);\r\n for (let i = 0; i < totalSplatCount; i++) {\r\n allSplatsSortBuffer[i] = i;\r\n }\r\n }\r\n this.sortWorkerIndexesToSort.set(allSplatsSortBuffer);\r\n return {\r\n splatRenderCount: totalSplatCount,\r\n shouldSortAll: true\r\n }\r\n }\r\n }\r\n })()\r\n\r\n getSplatMesh() {\r\n return this.splatMesh\r\n }\r\n\r\n /**\r\n * Get a reference to a splat scene.\r\n * @param {number} sceneIndex The index of the scene to which the reference will be returned\r\n * @return {SplatScene}\r\n */\r\n getSplatScene(sceneIndex) {\r\n return this.splatMesh.getScene(sceneIndex)\r\n }\r\n\r\n getSceneCount() {\r\n return this.splatMesh.getSceneCount()\r\n }\r\n\r\n isMobile() {\r\n return navigator.userAgent.includes('Mobi')\r\n }\r\n\r\n updateMorphTarget(inputMesh) {\r\n this.avatarMesh = inputMesh;\r\n this.splatMesh.flameModel = inputMesh;\r\n\r\n this.runMorphUpdate();\r\n this.splatMesh.gaussianSplatCount = this.gaussianSplatCount;\r\n }\r\n\r\n runMorphUpdate() {\r\n this.gaussianSplatCount = this.avatarMesh.geometry.attributes.position.count;\r\n var morphedMesh = new Float32Array(\r\n this.avatarMesh.geometry.attributes.position.array\r\n );\r\n const numBones = 5;\r\n this.splatMesh.bonesNum = numBones;\r\n\r\n this.skinModel.skeleton.update();\r\n this.boneRoot.updateMatrixWorld(true);\r\n if (this.splatMesh.geometry.getAttribute('splatIndex') && this.setSkinAttibutes === false) {\r\n\r\n this.setSkinAttibutes = true;\r\n const geometry = this.splatMesh.geometry;\r\n\r\n const skinIndexSource = this.skinModel.geometry.attributes.skinIndex;\r\n const skinWeightSource = this.skinModel.geometry.attributes.skinWeight;\r\n\r\n const newSkinIndex = new InstancedBufferAttribute(\r\n new skinIndexSource.array.constructor(skinIndexSource.array),\r\n 4,\r\n skinIndexSource.normalized,\r\n 1\r\n );\r\n\r\n const newSkinWeight = new InstancedBufferAttribute(\r\n new skinWeightSource.array.constructor(skinWeightSource.array),\r\n 4,\r\n skinWeightSource.normalized,\r\n 1\r\n );\r\n newSkinIndex.setUsage(DynamicDrawUsage);\r\n newSkinWeight.setUsage(DynamicDrawUsage);\r\n geometry.setAttribute('skinIndex', newSkinIndex);\r\n geometry.setAttribute('skinWeight', newSkinWeight);\r\n }\r\n\r\n this.splatMesh.morphedMesh = morphedMesh;\r\n\r\n let splatNum = this.splatMesh.morphedMesh.length / 3;\r\n if (this.splatMesh.splatDataTextures['flameModel'] != undefined) {\r\n this.splatMesh.updateTetureAfterBSAndSkeleton(0, splatNum - 1, false);\r\n }\r\n }\r\n}","/**\r\n * GaussianSplatRenderer\r\n * \r\n * Derived from gaussian-splat-renderer-for-lam\r\n * \r\n * High-level orchestration class that:\r\n * - Loads ZIP assets via fetch\r\n * - Unpacks with JSZip\r\n * - Creates Viewer instance\r\n * - Loads FLAME/skin models\r\n * - Runs the render loop\r\n */\r\n\r\n/* global NProgress */\r\n\r\nimport {\r\n Vector3,\r\n Bone,\r\n Clock,\r\n AnimationMixer\r\n} from 'three';\r\nimport { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';\r\nimport JSZip from 'jszip';\r\n\r\n// Import internal modules\r\nimport { TYVoiceChatState } from './AppConstants.js';\r\nimport { AnimationManager } from './AnimationManager.js';\r\nimport { Viewer } from '../core/Viewer.js';\r\nimport { SceneFormat } from '../enums/SceneFormat.js';\r\n\r\n// Import new utilities and error classes\r\nimport { getLogger } from '../utils/Logger.js';\r\nimport {\r\n ValidationError,\r\n NetworkError,\r\n AssetLoadError,\r\n InitializationError,\r\n ResourceDisposedError\r\n} from '../errors/index.js';\r\nimport {\r\n validateUrl,\r\n validateDOMElement,\r\n validateHexColor,\r\n validateCallback\r\n} from '../utils/ValidationUtils.js';\r\nimport { BlobUrlManager } from '../utils/BlobUrlManager.js';\r\nimport { tempVector3A } from '../utils/ObjectPool.js';\r\n\r\n// Create logger for this module\r\nconst logger = getLogger('GaussianSplatRenderer');\r\n\r\n// Configuration objects - these would normally be loaded from the ZIP\r\nconst charactorConfig = {\r\n camPos: { x: 0, y: 1.8, z: 1 },\r\n camRot: { x: -10, y: 0, z: 0 },\r\n backgroundColor: 'ffffff'\r\n};\r\n\r\nconst motionConfig = {\r\n offset: {},\r\n scale: {}\r\n};\r\n\r\n// Animation configuration - defines how animation clips are distributed to states\r\n// The animation.glb contains clips in order: hello(2), idle(1), listen(0), speak(6), think(3)\r\nconst animationConfig = {\r\n hello: { size: 2, isGroup: false },\r\n idle: { size: 1, isGroup: false },\r\n listen: { size: 0, isGroup: false },\r\n speak: { size: 6, isGroup: false },\r\n think: { size: 3, isGroup: true },\r\n other: []\r\n};\r\n\r\n/**\r\n * GaussianSplatRenderer - Main rendering class\r\n */\r\nexport class GaussianSplatRenderer {\r\n /**\r\n * Factory method to create a new renderer instance\r\n *\r\n * @param {HTMLElement} container - DOM container for canvas\r\n * @param {string} assetPath - URL to character ZIP file\r\n * @param {object} [options={}] - Configuration options\r\n * @param {Function} [options.downloadProgress] - Download progress callback (0-1)\r\n * @param {Function} [options.loadProgress] - Load progress callback (0-1)\r\n * @param {Function} [options.getChatState] - Chat state provider function\r\n * @param {Function} [options.getExpressionData] - Expression data provider function\r\n * @param {string} [options.backgroundColor] - Background color (hex string)\r\n * @returns {Promise<GaussianSplatRenderer>} Renderer instance\r\n * @throws {ValidationError} If parameters are invalid\r\n * @throws {NetworkError} If asset download fails\r\n * @throws {AssetLoadError} If asset loading/parsing fails\r\n * @throws {InitializationError} If renderer initialization fails\r\n */\r\n static async create(container, assetPath, options = {}) {\r\n\r\n try {\r\n // Validate required parameters\r\n validateDOMElement(container, 'container');\r\n validateUrl(assetPath);\r\n\r\n // Validate optional callbacks\r\n if (options.downloadProgress) {\r\n validateCallback(options.downloadProgress, 'options.downloadProgress', false);\r\n }\r\n if (options.loadProgress) {\r\n validateCallback(options.loadProgress, 'options.loadProgress', false);\r\n }\r\n if (options.getChatState) {\r\n validateCallback(options.getChatState, 'options.getChatState', false);\r\n }\r\n if (options.getExpressionData) {\r\n validateCallback(options.getExpressionData, 'options.getExpressionData', false);\r\n }\r\n if (options.backgroundColor) {\r\n validateHexColor(options.backgroundColor, 'options.backgroundColor');\r\n }\r\n\r\n logger.info('Initializing GaussianSplatRenderer', { assetPath });\r\n\r\n const characterPath = assetPath;\r\n\r\n // Parse character name from path\r\n let characterName;\r\n try {\r\n const url = new URL(characterPath, typeof window !== 'undefined' ? window.location.href : undefined);\r\n const pathname = url.pathname;\r\n const matches = pathname.match(/\\/([^/]+?)\\.zip/);\r\n characterName = matches?.[1];\r\n\r\n if (!characterName) {\r\n throw new ValidationError(\r\n 'Character model name could not be extracted from path. Expected format: /path/name.zip',\r\n 'assetPath'\r\n );\r\n }\r\n } catch (error) {\r\n if (error instanceof ValidationError) {\r\n throw error;\r\n }\r\n throw new ValidationError(\r\n `Invalid asset path format: ${error.message}`,\r\n 'assetPath',\r\n error\r\n );\r\n }\r\n\r\n // Show progress\r\n if (typeof NProgress !== 'undefined') {\r\n NProgress.start();\r\n }\r\n\r\n // Download ZIP file\r\n logger.info('Downloading asset ZIP', { path: characterPath });\r\n let characterZipResponse;\r\n try {\r\n characterZipResponse = await fetch(characterPath);\r\n if (!characterZipResponse.ok) {\r\n throw new NetworkError(\r\n `Failed to download asset: ${characterZipResponse.statusText}`,\r\n characterZipResponse.status\r\n );\r\n }\r\n } catch (error) {\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n throw new NetworkError(\r\n `Network error downloading asset: ${error.message}`,\r\n 0,\r\n error\r\n );\r\n }\r\n\r\n // Report download progress\r\n if (options.downloadProgress) {\r\n try {\r\n options.downloadProgress(1.0);\r\n } catch (error) {\r\n logger.warn('Error in downloadProgress callback', error);\r\n }\r\n }\r\n\r\n if (options.loadProgress) {\r\n try {\r\n options.loadProgress(0.1);\r\n } catch (error) {\r\n logger.warn('Error in loadProgress callback', error);\r\n }\r\n }\r\n\r\n if (typeof NProgress !== 'undefined') {\r\n NProgress.done();\r\n }\r\n\r\n // Parse array buffer\r\n let arrayBuffer;\r\n try {\r\n arrayBuffer = await characterZipResponse.arrayBuffer();\r\n } catch (error) {\r\n throw new NetworkError(\r\n `Failed to read response data: ${error.message}`,\r\n 0,\r\n error\r\n );\r\n }\r\n\r\n // Load ZIP with imported JSZip\r\n logger.debug('Unpacking ZIP archive');\r\n let zipData;\r\n try {\r\n zipData = await JSZip.loadAsync(arrayBuffer);\r\n } catch (error) {\r\n throw new AssetLoadError(\r\n `Failed to unpack ZIP archive: ${error.message}`,\r\n characterPath,\r\n error\r\n );\r\n }\r\n\r\n // Find folder name in ZIP\r\n let fileName = '';\r\n Object.values(zipData.files).forEach(file => {\r\n if (file.dir) {\r\n fileName = file.name?.slice(0, file.name?.length - 1); // Remove trailing '/'\r\n }\r\n });\r\n\r\n if (!fileName) {\r\n throw new AssetLoadError(\r\n 'No folder found in ZIP archive. Expected ZIP to contain a folder with model files.',\r\n characterPath\r\n );\r\n }\r\n\r\n logger.debug('Found model folder in ZIP', { fileName });\r\n\r\n // Create renderer instance\r\n logger.debug('Creating GaussianSplatRenderer instance');\r\n const renderer = new GaussianSplatRenderer(container, zipData);\r\n\r\n // Setup camera position (use object pool for temp vectors)\r\n const cameraPos = tempVector3A.set(\r\n charactorConfig.camPos?.x ?? 0,\r\n charactorConfig.camPos?.y ?? 0,\r\n charactorConfig.camPos?.z ?? 1\r\n );\r\n\r\n const cameraRotation = new Vector3(\r\n charactorConfig.camRot?.x ?? 0,\r\n charactorConfig.camRot?.y ?? 0,\r\n charactorConfig.camRot?.z ?? 0\r\n );\r\n\r\n logger.debug('Camera setup', {\r\n position: { x: cameraPos.x, y: cameraPos.y, z: cameraPos.z },\r\n rotation: { x: cameraRotation.x, y: cameraRotation.y, z: cameraRotation.z }\r\n });\r\n\r\n // Background color with validation\r\n let backgroundColor = 0xffffff;\r\n try {\r\n if (charactorConfig.backgroundColor) {\r\n const parsed = parseInt(charactorConfig.backgroundColor, 16);\r\n if (!isNaN(parsed)) {\r\n backgroundColor = parsed;\r\n } else {\r\n logger.warn('Invalid backgroundColor in config, using default', {\r\n value: charactorConfig.backgroundColor\r\n });\r\n }\r\n }\r\n if (options?.backgroundColor) {\r\n if (renderer.isHexColorStrict(options.backgroundColor)) {\r\n backgroundColor = parseInt(options.backgroundColor, 16);\r\n } else {\r\n logger.warn('Invalid backgroundColor option, using config value', {\r\n value: options.backgroundColor\r\n });\r\n }\r\n }\r\n } catch (error) {\r\n logger.warn('Error parsing backgroundColor, using default', error);\r\n }\r\n\r\n logger.debug('Background color set', { backgroundColor: backgroundColor.toString(16) });\r\n\r\n // Store callbacks\r\n renderer.getChatState = options?.getChatState;\r\n renderer.getExpressionData = options?.getExpressionData;\r\n\r\n // Create Viewer with proper error handling\r\n logger.debug('Creating Viewer instance');\r\n try {\r\n renderer.viewer = new Viewer({\r\n rootElement: container,\r\n threejsCanvas: renderer._canvas,\r\n cameraUp: [0, 1, 0],\r\n initialCameraPosition: [cameraPos.x, cameraPos.y, cameraPos.z],\r\n initialCameraRotation: [cameraRotation.x, cameraRotation.y, cameraRotation.z],\r\n sphericalHarmonicsDegree: 0,\r\n backgroundColor: backgroundColor\r\n });\r\n } catch (error) {\r\n throw new InitializationError(\r\n `Failed to create Viewer instance: ${error.message}`,\r\n error\r\n );\r\n }\r\n\r\n // Load model (non-FLAME mode only)\r\n logger.info('Loading model', { fileName });\r\n try {\r\n await renderer.loadModel(fileName, animationConfig, motionConfig);\r\n } catch (error) {\r\n throw new AssetLoadError(\r\n `Failed to load model: ${error.message}`,\r\n fileName,\r\n error\r\n );\r\n }\r\n\r\n // Progress callback with error isolation\r\n if (options.loadProgress) {\r\n try {\r\n options.loadProgress(0.2);\r\n } catch (error) {\r\n logger.warn('Error in loadProgress callback', error);\r\n }\r\n }\r\n\r\n // Load offset PLY\r\n logger.debug('Loading offset PLY file');\r\n let offsetFileUrl;\r\n try {\r\n offsetFileUrl = await renderer.unpackFileAsBlob(fileName + '/offset.ply');\r\n } catch (error) {\r\n throw new AssetLoadError(\r\n `Failed to load offset.ply: ${error.message}`,\r\n fileName + '/offset.ply',\r\n error\r\n );\r\n }\r\n\r\n // Load iris occlusion configuration (optional)\r\n logger.debug('Checking for iris_occlusion.json');\r\n let irisOcclusionConfig = null;\r\n try {\r\n irisOcclusionConfig = await renderer._loadJsonFromZip(fileName + '/iris_occlusion.json');\r\n if (irisOcclusionConfig) {\r\n logger.info('Iris occlusion configuration loaded', {\r\n rightIrisRanges: irisOcclusionConfig.right_iris?.length ?? 0,\r\n leftIrisRanges: irisOcclusionConfig.left_iris?.length ?? 0\r\n });\r\n renderer.irisOcclusionConfig = irisOcclusionConfig;\r\n // Pass to viewer for material generation\r\n renderer.viewer.irisOcclusionConfig = irisOcclusionConfig;\r\n } else {\r\n logger.debug('No iris_occlusion.json found, iris occlusion will be disabled');\r\n }\r\n } catch (error) {\r\n // Log but don't fail - iris occlusion is optional\r\n logger.warn('Failed to load iris_occlusion.json, continuing without it', { error: error.message });\r\n renderer.irisOcclusionConfig = null;\r\n }\r\n\r\n // Progress callback with error isolation\r\n if (options.loadProgress) {\r\n try {\r\n options.loadProgress(0.3);\r\n } catch (error) {\r\n logger.warn('Error in loadProgress callback', error);\r\n }\r\n }\r\n\r\n // Add splat scene\r\n logger.debug('Adding splat scene');\r\n try {\r\n await renderer.viewer.addSplatScene(offsetFileUrl, {\r\n progressiveLoad: true,\r\n sharedMemoryForWorkers: false,\r\n showLoadingUI: false,\r\n format: SceneFormat.Ply\r\n });\r\n } catch (error) {\r\n throw new InitializationError(\r\n `Failed to add splat scene: ${error.message}`,\r\n error\r\n );\r\n }\r\n\r\n // Initial render\r\n try {\r\n renderer.render();\r\n } catch (error) {\r\n logger.error('Error in initial render', error);\r\n // Don't throw - render errors are non-fatal\r\n }\r\n\r\n // Progress callback with error isolation\r\n if (options.loadProgress) {\r\n try {\r\n options.loadProgress(1);\r\n } catch (error) {\r\n logger.warn('Error in loadProgress callback', error);\r\n }\r\n }\r\n\r\n logger.info('GaussianSplatRenderer initialized successfully');\r\n return renderer;\r\n\r\n } catch (error) {\r\n // Re-throw custom errors as-is\r\n if (error instanceof ValidationError ||\r\n error instanceof NetworkError ||\r\n error instanceof AssetLoadError ||\r\n error instanceof InitializationError) {\r\n logger.error('Initialization failed', { errorCode: error.code, message: error.message });\r\n throw error;\r\n }\r\n\r\n // Wrap unexpected errors\r\n logger.error('Unexpected error during initialization', error);\r\n throw new InitializationError(\r\n `Unexpected error initializing GaussianSplatRenderer: ${error.message}`,\r\n error\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * @deprecated Use create() instead. This method is kept for backwards compatibility.\r\n * @param {HTMLElement} container - DOM container for canvas\r\n * @param {string} assetPath - URL to character ZIP file\r\n * @param {object} [options={}] - Configuration options\r\n * @returns {Promise<GaussianSplatRenderer>} Renderer instance\r\n */\r\n static async getInstance(container, assetPath, options = {}) {\r\n logger.warn('getInstance() is deprecated. Use create() instead. Each call creates a new instance.');\r\n return this.create(container, assetPath, options);\r\n }\r\n\r\n /**\r\n * Constructor - Creates a new GaussianSplatRenderer instance\r\n *\r\n * @param {HTMLElement} _container - DOM container element for the renderer\r\n * @param {JSZip} zipData - Loaded ZIP archive containing model data\r\n * @private - Use create() factory method instead\r\n */\r\n constructor(_container, zipData) {\r\n logger.debug('GaussianSplatRenderer constructor called');\r\n\r\n // Disposal tracking\r\n this._disposed = false;\r\n\r\n // BlobUrlManager for tracking blob URLs\r\n this._blobUrlManager = new BlobUrlManager();\r\n\r\n // ZIP file cache\r\n this.zipUrls = {\r\n urls: new Map(),\r\n zip: zipData\r\n };\r\n\r\n // State\r\n this.lastTime = 0;\r\n this.startTime = 0;\r\n this.expressionData = {};\r\n this.chatState = TYVoiceChatState.Idle;\r\n\r\n // Create instance-specific canvas\r\n this._canvas = null;\r\n if (typeof document !== 'undefined' && _container) {\r\n this._canvas = document.createElement('canvas');\r\n const { width, height } = _container.getBoundingClientRect();\r\n this._canvas.style.visibility = 'visible';\r\n this._canvas.width = width;\r\n this._canvas.height = height;\r\n _container.appendChild(this._canvas);\r\n logger.debug('Canvas setup', { width, height });\r\n }\r\n\r\n // Animation timing\r\n this.clock = new Clock();\r\n this.startTime = performance.now() / 1000.0;\r\n\r\n // These will be set during loading\r\n this.viewer = null;\r\n this.mixer = null;\r\n this.animManager = null;\r\n this.model = null;\r\n this.irisOcclusionConfig = null;\r\n this.motioncfg = null;\r\n this.getChatState = null;\r\n this.getExpressionData = null;\r\n\r\n logger.debug('GaussianSplatRenderer instance created');\r\n }\r\n\r\n /**\r\n * Assert renderer is not disposed\r\n * @private\r\n * @throws {ResourceDisposedError} If renderer has been disposed\r\n */\r\n _assertNotDisposed() {\r\n if (this._disposed) {\r\n throw new ResourceDisposedError('GaussianSplatRenderer has been disposed');\r\n }\r\n }\r\n\r\n /**\r\n * Dispose renderer and free all resources\r\n *\r\n * Properly cleans up:\r\n * - Model resources (mesh, animations, textures)\r\n * - Blob URLs to prevent memory leaks\r\n * - Viewer instance\r\n * - Canvas visibility\r\n *\r\n * @returns {void}\r\n */\r\n dispose() {\r\n if (this._disposed) {\r\n logger.warn('GaussianSplatRenderer.dispose() called on already disposed instance');\r\n return;\r\n }\r\n\r\n logger.info('Disposing GaussianSplatRenderer');\r\n\r\n // Hide and remove canvas\r\n if (this._canvas) {\r\n this._canvas.style.visibility = 'hidden';\r\n if (this._canvas.parentNode) {\r\n this._canvas.parentNode.removeChild(this._canvas);\r\n }\r\n this._canvas = null;\r\n }\r\n\r\n // Dispose model resources\r\n this.disposeModel();\r\n\r\n // Revoke all blob URLs using BlobUrlManager\r\n try {\r\n this._blobUrlManager?.dispose();\r\n } catch (error) {\r\n logger.error('Error disposing BlobUrlManager', error);\r\n }\r\n\r\n // Legacy blob URL cleanup (for URLs created before BlobUrlManager)\r\n if (this.zipUrls?.urls) {\r\n this.zipUrls.urls.forEach((value) => {\r\n try {\r\n URL.revokeObjectURL(value);\r\n } catch (error) {\r\n logger.warn('Error revoking blob URL', { url: value, error });\r\n }\r\n });\r\n this.zipUrls.urls.clear();\r\n }\r\n\r\n // Nullify references to aid GC\r\n this.viewer = null;\r\n this.mixer = null;\r\n this.animManager = null;\r\n this.model = null;\r\n this.motioncfg = null;\r\n this.getChatState = null;\r\n this.getExpressionData = null;\r\n this.zipUrls = null;\r\n\r\n // Mark as disposed\r\n this._disposed = true;\r\n\r\n // Clear singleton instance\r\n GaussianSplatRenderer.instance = undefined;\r\n\r\n logger.debug('GaussianSplatRenderer disposed successfully');\r\n }\r\n\r\n /**\r\n * Dispose model-specific resources\r\n *\r\n * Cleans up:\r\n * - Animation mixer and cached actions\r\n * - Animation manager\r\n * - Viewer instance\r\n *\r\n * @returns {void}\r\n */\r\n disposeModel() {\r\n logger.debug('Disposing model resources');\r\n\r\n // Dispose animation mixer\r\n if (this.mixer) {\r\n try {\r\n this.mixer.stopAllAction();\r\n if (this.viewer?.avatarMesh) {\r\n this.mixer.uncacheRoot(this.viewer.avatarMesh);\r\n }\r\n } catch (error) {\r\n logger.error('Error disposing animation mixer', error);\r\n }\r\n this.mixer = null;\r\n }\r\n\r\n // Dispose animation manager\r\n if (this.animManager) {\r\n try {\r\n this.animManager.dispose();\r\n } catch (error) {\r\n logger.error('Error disposing animation manager', error);\r\n }\r\n this.animManager = null;\r\n }\r\n\r\n // Dispose viewer\r\n if (this.viewer) {\r\n try {\r\n this.viewer.dispose();\r\n } catch (error) {\r\n logger.error('Error disposing viewer', error);\r\n }\r\n this.viewer = null;\r\n }\r\n\r\n logger.debug('Model resources disposed');\r\n }\r\n\r\n /**\r\n * Get the Three.js camera\r\n * @returns {THREE.Camera}\r\n */\r\n getCamera() {\r\n return this.viewer?.camera;\r\n }\r\n\r\n /**\r\n * Update blendshape weights from action data\r\n * @param {object} actionData - Blendshape weights\r\n * @returns {object} Processed influence values\r\n */\r\n updateBS(actionData) {\r\n // Default influence values - all 52 ARKit blendshapes\r\n let influence = {\r\n browDownLeft: 0.0,\r\n browDownRight: 0.0,\r\n browInnerUp: 0.0,\r\n browOuterUpLeft: 0.0,\r\n browOuterUpRight: 0.0,\r\n mouthCheekPuff: 0.0,\r\n cheekSquintLeft: 0.0,\r\n cheekSquintRight: 0.0,\r\n eyeBlinkLeft: 0.0,\r\n eyeBlinkRight: 0.0,\r\n eyeLookDownLeft: 0.0,\r\n eyeLookDownRight: 0.0,\r\n eyeLookInLeft: 0.0,\r\n eyeLookInRight: 0.0,\r\n eyeLookOutLeft: 0.0,\r\n eyeLookOutRight: 0.0,\r\n eyeLookUpLeft: 0.0,\r\n eyeLookUpRight: 0.0,\r\n eyeSquintLeft: 0.0,\r\n eyeSquintRight: 0.0,\r\n eyeWideLeft: 0.0,\r\n eyeWideRight: 0.0,\r\n jawForward: 0.0,\r\n jawLeft: 0.0,\r\n jawOpen: 0.0,\r\n jawRight: 0.0,\r\n mouthClose: 0.0,\r\n mouthDimpleLeft: 0.0,\r\n mouthDimpleRight: 0.0,\r\n mouthFrownLeft: 0.0,\r\n mouthFrownRight: 0.0,\r\n mouthFunnel: 0.0,\r\n mouthLeft: 0.0,\r\n mouthLowerDownLeft: 0.0,\r\n mouthLowerDownRight: 0.0,\r\n mouthPressLeft: 0.0,\r\n mouthPressRight: 0.0,\r\n mouthPucker: 0.0,\r\n mouthRight: 0.0,\r\n mouthRollLower: 0.0,\r\n mouthRollUpper: 0.0,\r\n mouthShrugLower: 0.0,\r\n mouthShrugUpper: 0.0,\r\n mouthSmileLeft: 0.0,\r\n mouthSmileRight: 0.0,\r\n mouthStretchLeft: 0.0,\r\n mouthStretchRight: 0.0,\r\n mouthUpperUpLeft: 0.0,\r\n mouthUpperUpRight: 0.0,\r\n noseSneerLeft: 0.0,\r\n noseSneerRight: 0.0,\r\n tongueOut: 0.0\r\n };\r\n\r\n if (actionData != null) {\r\n influence = actionData;\r\n }\r\n\r\n return influence;\r\n }\r\n\r\n /**\r\n * Main render loop\r\n */\r\n render() {\r\n if (this.viewer && this.viewer.selfDrivenMode) {\r\n this.viewer.requestFrameId = requestAnimationFrame(() => this.render());\r\n\r\n const frameInfoInternal = 1.0 / 30.0;\r\n const currentTime = performance.now() / 1000;\r\n \r\n // Prevent division by zero if totalFrames is 0 or not set\r\n const totalFrames = this.viewer.totalFrames || 1;\r\n const calcDelta = (currentTime - this.startTime) % (totalFrames * frameInfoInternal);\r\n const frameIndex = Math.floor(calcDelta / frameInfoInternal);\r\n this.viewer.frame = frameIndex;\r\n\r\n // Update chat state\r\n if (this.getChatState) {\r\n this.chatState = this.getChatState();\r\n // DEBUG: Log state transitions\r\n if (!this._lastLoggedState || this._lastLoggedState !== this.chatState) {\r\n logger.debug('Chat state changed', {\r\n newState: this.chatState,\r\n hasAnimManager: !!this.animManager\r\n });\r\n this._lastLoggedState = this.chatState;\r\n }\r\n this.animManager?.update(this.chatState);\r\n }\r\n\r\n // Update expression data\r\n if (this.getExpressionData) {\r\n this.expressionData = this.updateBS(this.getExpressionData());\r\n }\r\n\r\n // Animation mixer update\r\n if (!this.mixer || !this.animManager) {\r\n if (!this._warnedOnce) {\r\n logger.warn('Mixer or animManager not initialized, skipping animation update', {\r\n hasMixer: !!this.mixer,\r\n hasAnimManager: !!this.animManager\r\n });\r\n this._warnedOnce = true;\r\n }\r\n // Still update expressions even without mixer/animManager\r\n this.setExpression();\r\n } else {\r\n const mixerUpdateDelta = this.clock.getDelta();\r\n this.mixer.update(mixerUpdateDelta);\r\n\r\n // Apply motion config offsets/scales\r\n if (this.motioncfg) {\r\n for (const morphTarget in this.expressionData) {\r\n const offset = this.motioncfg.offset?.[morphTarget];\r\n const scale = this.motioncfg.scale?.[morphTarget];\r\n if (offset !== undefined && scale !== undefined) {\r\n this.expressionData[morphTarget] =\r\n this.expressionData[morphTarget] * scale + offset;\r\n }\r\n }\r\n }\r\n\r\n this.setExpression();\r\n }\r\n\r\n // Update viewer\r\n this.viewer.update(this.viewer.renderer, this.viewer.camera);\r\n\r\n // Render if needed\r\n const shouldRender = this.viewer.shouldRender();\r\n if (this._renderLogCount <= 3) {\r\n logger.debug('shouldRender check', { shouldRender });\r\n }\r\n if (shouldRender) {\r\n this.viewer.render();\r\n this.viewer.consecutiveRenderFrames++;\r\n } else {\r\n this.viewer.consecutiveRenderFrames = 0;\r\n }\r\n\r\n this.viewer.renderNextFrame = false;\r\n this.viewer.selfDrivenModeRunning = true;\r\n } else {\r\n throw new Error('Cannot start viewer unless it is in self driven mode.');\r\n }\r\n }\r\n\r\n /**\r\n * Validate hex color string\r\n * @param {string} value - Color string to validate\r\n * @returns {boolean}\r\n */\r\n isHexColorStrict(value) {\r\n if (typeof value !== 'string') return false;\r\n const hexColorRegex = /^(#|0x)[0-9A-Fa-f]{6}$/i;\r\n return hexColorRegex.test(value);\r\n }\r\n\r\n /**\r\n * Apply expression data to mesh\r\n */\r\n setExpression() {\r\n // Update splat mesh blendshapes\r\n if (this.viewer?.splatMesh) {\r\n this.viewer.splatMesh.bsWeight = this.expressionData;\r\n \r\n // Update eye blink uniforms for smooth iris fade\r\n const material = this.viewer.splatMesh.material;\r\n if (material?.uniforms) {\r\n const eyeBlinkLeft = this.expressionData.eyeBlinkLeft || 0.0;\r\n const eyeBlinkRight = this.expressionData.eyeBlinkRight || 0.0;\r\n if (material.uniforms.eyeBlinkLeft) {\r\n material.uniforms.eyeBlinkLeft.value = eyeBlinkLeft;\r\n }\r\n if (material.uniforms.eyeBlinkRight) {\r\n material.uniforms.eyeBlinkRight.value = eyeBlinkRight;\r\n }\r\n }\r\n }\r\n\r\n // Update morph targets on avatar model\r\n if (this.model) {\r\n this.model.traverse((object) => {\r\n if (object.isMesh || object.isSkinnedMesh) {\r\n const morphAttributes = object.geometry?.morphAttributes;\r\n const hasMorphTargets = morphAttributes && Object.keys(morphAttributes).length > 0;\r\n \r\n if (hasMorphTargets) {\r\n const morphTargetDictionary = object.morphTargetDictionary;\r\n for (const morphTarget in morphTargetDictionary) {\r\n const target = morphTargetDictionary[morphTarget];\r\n const data = this.expressionData[morphTarget];\r\n if (data !== undefined) {\r\n object.morphTargetInfluences[target] = Math.max(0.0, Math.min(1.0, data));\r\n }\r\n }\r\n }\r\n }\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Load model with animation\r\n * @param {string} pathName - Path within ZIP\r\n * @param {object} animationConfig - Animation configuration\r\n * @param {object} motionConfig - Motion configuration\r\n */\r\n async loadModel(pathName, animationConfig, motionConfig) {\r\n const [skinModel, aniclip, indexes] = await Promise.all([\r\n this.unpackAndLoadGlb(pathName + '/skin.glb'),\r\n this.unpackAndLoadGlb(pathName + '/animation.glb'),\r\n this.unpackAndLoadJson(pathName + '/vertex_order.json')\r\n ]);\r\n\r\n if (!this.viewer) {\r\n throw new Error('render viewer is not initialized');\r\n }\r\n\r\n let skinModelSkinnedMesh;\r\n let boneRoot;\r\n\r\n skinModel.traverse((object) => {\r\n if (object.isSkinnedMesh) {\r\n skinModelSkinnedMesh = object;\r\n }\r\n if (object instanceof Bone && object.name === 'hip') {\r\n boneRoot = object;\r\n }\r\n });\r\n\r\n this.viewer.sortedIndexes = indexes;\r\n\r\n if (skinModelSkinnedMesh) {\r\n this.viewer.gaussianSplatCount = skinModelSkinnedMesh.geometry.attributes.position.count;\r\n }\r\n\r\n this.viewer.avatarMesh = skinModel;\r\n this.viewer.skinModel = skinModelSkinnedMesh;\r\n this.viewer.boneRoot = boneRoot;\r\n\r\n // Setup animation\r\n this.mixer = new AnimationMixer(skinModel);\r\n this.animManager = new AnimationManager(this.mixer, aniclip, animationConfig);\r\n this.motioncfg = motionConfig;\r\n\r\n // Set totalFrames from animation clips or default to 1\r\n if (Array.isArray(aniclip) && aniclip.length > 0 && aniclip[0].duration) {\r\n this.viewer.totalFrames = Math.floor(aniclip[0].duration * 30); // 30 fps\r\n } else {\r\n this.viewer.totalFrames = 1;\r\n }\r\n logger.debug('Total frames calculated', { totalFrames: this.viewer.totalFrames });\r\n\r\n if (skinModelSkinnedMesh) {\r\n this.viewer.updateMorphTarget(skinModelSkinnedMesh);\r\n }\r\n\r\n this.viewer.threeScene.add(skinModel);\r\n skinModel.visible = false;\r\n\r\n if (skinModelSkinnedMesh) {\r\n skinModelSkinnedMesh.skeleton.computeBoneTexture();\r\n }\r\n }\r\n\r\n /**\r\n * Unpack file from ZIP and create a blob URL\r\n *\r\n * Uses BlobUrlManager to track blob URLs for automatic cleanup.\r\n * Caches URLs for repeated access to the same file.\r\n *\r\n * @param {string} path - Path to file within ZIP archive\r\n * @returns {Promise<string>} Blob URL to the file\r\n * @throws {AssetLoadError} If file cannot be unpacked\r\n */\r\n async unpackFileAsBlob(path) {\r\n this._assertNotDisposed();\r\n\r\n // Return cached URL if available\r\n if (this.zipUrls.urls.has(path)) {\r\n logger.debug('Returning cached blob URL', { path });\r\n return this.zipUrls.urls.get(path);\r\n }\r\n\r\n logger.debug('Unpacking file from ZIP', { path });\r\n\r\n // Extract file from ZIP\r\n const fileEntry = this.zipUrls.zip?.file(path);\r\n if (!fileEntry) {\r\n throw new AssetLoadError(\r\n `File not found in ZIP archive: ${path}`,\r\n path\r\n );\r\n }\r\n\r\n let modelFile;\r\n try {\r\n modelFile = await fileEntry.async('blob');\r\n } catch (error) {\r\n throw new AssetLoadError(\r\n `Failed to extract file from ZIP: ${error.message}`,\r\n path,\r\n error\r\n );\r\n }\r\n\r\n if (!modelFile) {\r\n throw new AssetLoadError(\r\n `File extracted but blob is empty: ${path}`,\r\n path\r\n );\r\n }\r\n\r\n // Create blob URL using BlobUrlManager for tracking\r\n const mimeType = this._getMimeType(path);\r\n const modelUrl = this._blobUrlManager.createBlobUrl(\r\n modelFile,\r\n mimeType,\r\n `zip:${path}`\r\n );\r\n\r\n // Cache for future access\r\n this.zipUrls.urls.set(path, modelUrl);\r\n logger.debug('Blob URL created and cached', { path, url: modelUrl.substring(0, 50) });\r\n\r\n return modelUrl;\r\n }\r\n\r\n /**\r\n * Load JSON file from ZIP archive\r\n *\r\n * @param {string} path - Path to JSON file within ZIP archive\r\n * @returns {Promise<Object|null>} Parsed JSON object, or null if file doesn't exist\r\n * @throws {ParseError} If JSON parsing fails\r\n * @private\r\n */\r\n async _loadJsonFromZip(path) {\r\n this._assertNotDisposed();\r\n\r\n logger.debug('Attempting to load JSON from ZIP', { path });\r\n\r\n // Check if file exists in ZIP\r\n const fileEntry = this.zipUrls.zip?.file(path);\r\n if (!fileEntry) {\r\n logger.debug('JSON file not found in ZIP, returning null', { path });\r\n return null;\r\n }\r\n\r\n // Extract file as text\r\n let jsonText;\r\n try {\r\n jsonText = await fileEntry.async('text');\r\n } catch (error) {\r\n throw new ParseError(\r\n `Failed to extract JSON file from ZIP: ${error.message}`,\r\n path,\r\n error\r\n );\r\n }\r\n\r\n // Parse JSON\r\n try {\r\n const jsonData = JSON.parse(jsonText);\r\n logger.debug('JSON file loaded successfully', { path });\r\n return jsonData;\r\n } catch (error) {\r\n throw new ParseError(\r\n `Failed to parse JSON file: ${error.message}`,\r\n path,\r\n error\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Unpack GLB file from ZIP and load it\r\n *\r\n * @param {string} path - Path to GLB file within ZIP archive\r\n * @returns {Promise<THREE.Group|THREE.AnimationClip[]>} Loaded GLTF model\r\n * @throws {AssetLoadError} If file cannot be unpacked or loaded\r\n */\r\n async unpackAndLoadGlb(path) {\r\n this._assertNotDisposed();\r\n\r\n // Return cached URL if available\r\n if (this.zipUrls.urls.has(path)) {\r\n logger.debug('Using cached GLB URL', { path });\r\n return this.LoadGLTF(this.zipUrls.urls.get(path));\r\n }\r\n\r\n logger.debug('Unpacking GLB from ZIP', { path });\r\n\r\n // Extract file from ZIP as ArrayBuffer\r\n const fileEntry = this.zipUrls.zip?.file(path);\r\n if (!fileEntry) {\r\n throw new AssetLoadError(\r\n `GLB file not found in ZIP archive: ${path}`,\r\n path\r\n );\r\n }\r\n\r\n let modelFile;\r\n try {\r\n modelFile = await fileEntry.async('arraybuffer');\r\n } catch (error) {\r\n throw new AssetLoadError(\r\n `Failed to extract GLB from ZIP: ${error.message}`,\r\n path,\r\n error\r\n );\r\n }\r\n\r\n if (!modelFile) {\r\n throw new AssetLoadError(\r\n `GLB extracted but ArrayBuffer is empty: ${path}`,\r\n path\r\n );\r\n }\r\n\r\n // Create blob URL using BlobUrlManager\r\n const blob = new Blob([modelFile], { type: 'model/gltf-binary' });\r\n const modelUrl = this._blobUrlManager.createBlobUrl(\r\n blob,\r\n 'model/gltf-binary',\r\n `zip:${path}`\r\n );\r\n\r\n // Cache for future access\r\n this.zipUrls.urls.set(path, modelUrl);\r\n logger.debug('GLB blob URL created and cached', { path });\r\n\r\n return this.LoadGLTF(modelUrl);\r\n }\r\n\r\n /**\r\n * Get MIME type from file extension\r\n * @private\r\n * @param {string} path - File path\r\n * @returns {string} MIME type\r\n */\r\n _getMimeType(path) {\r\n const extension = path.split('.').pop()?.toLowerCase();\r\n const mimeTypes = {\r\n 'ply': 'model/ply',\r\n 'glb': 'model/gltf-binary',\r\n 'gltf': 'model/gltf+json',\r\n 'json': 'application/json',\r\n 'bin': 'application/octet-stream',\r\n 'png': 'image/png',\r\n 'jpg': 'image/jpeg',\r\n 'jpeg': 'image/jpeg'\r\n };\r\n return mimeTypes[extension] || 'application/octet-stream';\r\n }\r\n\r\n /**\r\n * Unpack and parse JSON file\r\n * @param {string} path - Path within ZIP\r\n * @returns {Promise<object>}\r\n */\r\n async unpackAndLoadJson(path) {\r\n const file = this.zipUrls.zip?.file(path);\r\n if (!file) {\r\n throw new Error(`File not found in ZIP: ${path}`);\r\n }\r\n const jsonFile = await file.async('string');\r\n if (!jsonFile) {\r\n throw new Error(`Failed to read file from ZIP: ${path}`);\r\n }\r\n return JSON.parse(jsonFile);\r\n }\r\n\r\n /**\r\n * Load GLTF file\r\n * @param {string} url - URL to GLTF/GLB file\r\n * @returns {Promise<THREE.Group|THREE.AnimationClip[]>}\r\n */\r\n async LoadGLTF(url) {\r\n return new Promise((resolve, reject) => {\r\n const loader = new GLTFLoader();\r\n loader.load(\r\n url,\r\n (gltf) => {\r\n if (gltf.animations.length > 0) {\r\n resolve(gltf.animations);\r\n } else {\r\n resolve(gltf.scene);\r\n }\r\n },\r\n undefined,\r\n (error) => {\r\n reject(error);\r\n }\r\n );\r\n });\r\n }\r\n}\r\n\r\nexport default GaussianSplatRenderer;\r\n","/**\r\n * FlameConstants\r\n * \r\n * Derived from gaussian-splat-renderer-for-lam\r\n * FLAME-specific constants for parametric head model.\r\n * \r\n * Note: General engine constants (MaxScenes, etc.) are in enums/EngineConstants.js\r\n */\r\n\r\nexport const Constants = {\r\n // FLAME model constants\r\n FlameBonesCount: 5, // root, neck, jaw, leftEye, rightEye\r\n DefaultBlendshapeCount: 52, // ARKit blendshapes\r\n \r\n // Texture sizes for FLAME data\r\n FlameModelTextureSize: { width: 4096, height: 2048 },\r\n BoneTextureSize: { width: 4, height: 32 },\r\n BoneWeightTextureSize: { width: 512, height: 512 }\r\n};\r\n\r\nexport default Constants;\r\n","/**\r\n * FLAME Utility Functions\r\n * \r\n * Derived from gaussian-splat-renderer-for-lam\r\n * Contains encoding functions and helpers for GPU texture data.\r\n */\r\n\r\n/**\r\n * Encode float as uint32 for GPU texture storage\r\n * Uses Float32Array/Int32Array view trick to reinterpret float bits as integer\r\n */\r\nexport const uintEncodedFloat = (function() {\r\n const floatView = new Float32Array(1);\r\n const int32View = new Int32Array(floatView.buffer);\r\n\r\n return function(f) {\r\n floatView[0] = f;\r\n return int32View[0];\r\n };\r\n})();\r\n\r\n/**\r\n * Convert RGBA values to a single integer\r\n */\r\nexport const rgbaToInteger = function(r, g, b, a) {\r\n return r + (g << 8) + (b << 16) + (a << 24);\r\n};\r\n\r\n/**\r\n * Convert RGBA array at offset to a single integer\r\n */\r\nexport const rgbaArrayToInteger = function(arr, offset) {\r\n return arr[offset] + (arr[offset + 1] << 8) + (arr[offset + 2] << 16) + (arr[offset + 3] << 24);\r\n};\r\n\r\n/**\r\n * Constants for texture data layout\r\n */\r\nexport const TextureConstants = {\r\n CENTER_COLORS_ELEMENTS_PER_TEXEL: 4,\r\n CENTER_COLORS_ELEMENTS_PER_SPLAT: 4,\r\n COVARIANCES_ELEMENTS_PER_TEXEL_STORED: 2,\r\n COVARIANCES_ELEMENTS_PER_TEXEL_ALLOCATED: 4,\r\n COVARIANCES_ELEMENTS_PER_TEXEL_COMPRESSED_STORED: 2,\r\n COVARIANCES_ELEMENTS_PER_TEXEL_COMPRESSED_ALLOCATED: 4,\r\n COVARIANCES_ELEMENTS_PER_SPLAT: 6,\r\n SCALES_ROTATIONS_ELEMENTS_PER_TEXEL: 4,\r\n SCENE_INDEXES_ELEMENTS_PER_TEXEL: 1,\r\n MAX_TEXTURE_TEXELS: 4096 * 4096\r\n};\r\n","/**\r\n * FlameTextureManager\r\n * \r\n * Derived from gaussian-splat-renderer-for-lam\r\n * \r\n * Manages GPU textures for FLAME parametric head model:\r\n * - Blendshape morph target data textures\r\n * - Bone matrix textures for skeleton animation\r\n * - LBS weight textures for skinning\r\n */\r\n\r\nimport {\r\n Vector2,\r\n DataTexture,\r\n RGBAIntegerFormat,\r\n UnsignedIntType\r\n} from 'three';\r\n\r\nimport { uintEncodedFloat } from './utils.js';\r\n\r\n/**\r\n * Build the FLAME model texture containing blendshape positions\r\n * @param {THREE.SkinnedMesh} flameModel - The FLAME mesh with morph targets\r\n * @param {THREE.ShaderMaterial} material - The splat material to update uniforms\r\n * @param {number} gaussianSplatCount - Number of gaussian splats\r\n * @returns {object} Texture data object\r\n */\r\nexport function buildModelTexture(flameModel, material, gaussianSplatCount) {\r\n const flameModelTexSize = new Vector2(4096, 2048);\r\n\r\n const shapedMesh = flameModel.geometry.attributes.position.array;\r\n let shapedMeshArray = [];\r\n const pointNum = shapedMesh.length / 3;\r\n const bsLength = flameModel.geometry.morphAttributes.position.length;\r\n\r\n // Sort morph targets by dictionary order\r\n const morphTargetNames = Object.keys(flameModel.morphTargetDictionary);\r\n morphTargetNames.forEach((name) => {\r\n const originalIndex = flameModel.morphTargetDictionary[name];\r\n const bsMesh = flameModel.geometry.morphAttributes.position[originalIndex];\r\n shapedMeshArray = shapedMeshArray.concat(Array.from(bsMesh.array));\r\n });\r\n \r\n // Add base mesh positions\r\n shapedMeshArray = shapedMeshArray.concat(Array.from(shapedMesh));\r\n\r\n // Create texture data\r\n const flameModelData = new Float32Array(flameModelTexSize.x * flameModelTexSize.y * 4);\r\n const flameModelDataInt = new Uint32Array(flameModelTexSize.x * flameModelTexSize.y * 4);\r\n \r\n for (let c = 0; c < pointNum * (bsLength + 1); c++) {\r\n flameModelData[c * 4 + 0] = shapedMeshArray[c * 3 + 0];\r\n flameModelData[c * 4 + 1] = shapedMeshArray[c * 3 + 1];\r\n flameModelData[c * 4 + 2] = shapedMeshArray[c * 3 + 2];\r\n\r\n flameModelDataInt[c * 4 + 0] = uintEncodedFloat(flameModelData[c * 4 + 0]);\r\n flameModelDataInt[c * 4 + 1] = uintEncodedFloat(flameModelData[c * 4 + 1]);\r\n flameModelDataInt[c * 4 + 2] = uintEncodedFloat(flameModelData[c * 4 + 2]);\r\n }\r\n\r\n const flameModelTex = new DataTexture(\r\n flameModelDataInt,\r\n flameModelTexSize.x,\r\n flameModelTexSize.y,\r\n RGBAIntegerFormat,\r\n UnsignedIntType\r\n );\r\n flameModelTex.internalFormat = 'RGBA32UI';\r\n flameModelTex.needsUpdate = true;\r\n\r\n // Update material uniforms\r\n material.uniforms.flameModelTexture.value = flameModelTex;\r\n material.uniforms.flameModelTextureSize.value.copy(flameModelTexSize);\r\n material.uniforms.gaussianSplatCount.value = gaussianSplatCount;\r\n material.uniformsNeedUpdate = true;\r\n\r\n return {\r\n data: flameModelDataInt,\r\n texture: flameModelTex,\r\n size: flameModelTexSize,\r\n baseData: { flameModelPos: flameModelData }\r\n };\r\n}\r\n\r\n/**\r\n * Build bone matrix texture for skeleton animation\r\n * @param {Float32Array} bonesMatrix - Flattened bone matrices\r\n * @param {number} bonesNum - Number of bones\r\n * @param {object} bsWeight - Blendshape weights object\r\n * @param {object} morphTargetDictionary - Maps blendshape names to indices\r\n * @param {THREE.SkinnedMesh} flameModel - The FLAME mesh\r\n * @param {THREE.ShaderMaterial} material - The splat material\r\n * @param {boolean} useFlameModel - Use FLAME mode\r\n * @returns {object} Texture data object\r\n */\r\nexport function buildBoneMatrixTexture(\r\n bonesMatrix,\r\n bonesNum,\r\n bsWeight,\r\n morphTargetDictionary,\r\n flameModel,\r\n material,\r\n useFlameModel\r\n) {\r\n if (!bsWeight) return null;\r\n\r\n // bonesNum + expressionBSNum / 4 = 30, so texture height is 32\r\n const boneTextureSize = new Vector2(4, 32);\r\n const boneMatrixTextureData = new Float32Array(bonesMatrix);\r\n const boneMatrixTextureDataInt = new Uint32Array(boneTextureSize.x * boneTextureSize.y * 4);\r\n\r\n if (useFlameModel) {\r\n // Encode bone matrices\r\n for (let c = 0; c < bonesNum * 16; c++) {\r\n boneMatrixTextureDataInt[c] = uintEncodedFloat(boneMatrixTextureData[c]);\r\n }\r\n \r\n // Set skeleton uniforms\r\n if (flameModel && flameModel.skeleton) {\r\n material.uniforms.boneTexture0.value = flameModel.skeleton.boneTexture;\r\n material.uniforms.bindMatrix.value = flameModel.bindMatrix;\r\n material.uniforms.bindMatrixInverse.value = flameModel.bindMatrixInverse;\r\n }\r\n }\r\n\r\n // Encode blendshape weights\r\n for (const key in bsWeight) {\r\n if (Object.hasOwn(bsWeight, key)) {\r\n const value = bsWeight[key];\r\n const idx = morphTargetDictionary[key];\r\n boneMatrixTextureDataInt[idx + bonesNum * 16] = uintEncodedFloat(value);\r\n }\r\n }\r\n\r\n const boneMatrixTex = new DataTexture(\r\n boneMatrixTextureDataInt,\r\n boneTextureSize.x,\r\n boneTextureSize.y,\r\n RGBAIntegerFormat,\r\n UnsignedIntType\r\n );\r\n boneMatrixTex.internalFormat = 'RGBA32UI';\r\n boneMatrixTex.needsUpdate = true;\r\n\r\n material.uniforms.boneTexture.value = boneMatrixTex;\r\n material.uniforms.boneTextureSize.value.copy(boneTextureSize);\r\n material.uniformsNeedUpdate = true;\r\n\r\n return {\r\n data: boneMatrixTextureDataInt,\r\n texture: boneMatrixTex,\r\n size: boneTextureSize,\r\n baseData: { boneMatrix: boneMatrixTextureDataInt }\r\n };\r\n}\r\n\r\n/**\r\n * Update bone matrix texture with new animation data\r\n * @param {object} splatDataTextures - Texture data storage\r\n * @param {Float32Array} bonesMatrix - Updated bone matrices\r\n * @param {number} bonesNum - Number of bones\r\n * @param {object} bsWeight - Updated blendshape weights\r\n * @param {object} morphTargetDictionary - Blendshape name to index map\r\n * @param {THREE.SkinnedMesh} flameModel - The FLAME mesh\r\n * @param {THREE.ShaderMaterial} material - The splat material\r\n * @param {boolean} updateFlameBoneMatrix - Whether to update bone matrices\r\n */\r\nexport function updateBoneMatrixTexture(\r\n splatDataTextures,\r\n bonesMatrix,\r\n bonesNum,\r\n bsWeight,\r\n morphTargetDictionary,\r\n flameModel,\r\n material,\r\n updateFlameBoneMatrix = false\r\n) {\r\n if (!bsWeight || !morphTargetDictionary) return;\r\n\r\n if (updateFlameBoneMatrix) {\r\n const boneMatrixTextureData = new Float32Array(bonesMatrix);\r\n for (let c = 0; c < bonesNum * 16; c++) {\r\n splatDataTextures.baseData['boneMatrix'][c] = uintEncodedFloat(boneMatrixTextureData[c]);\r\n }\r\n }\r\n\r\n // Update blendshape weights\r\n for (const key in bsWeight) {\r\n if (Object.hasOwn(bsWeight, key)) {\r\n const value = bsWeight[key];\r\n const idx = morphTargetDictionary[key];\r\n splatDataTextures.baseData['boneMatrix'][idx + bonesNum * 16] = uintEncodedFloat(value);\r\n }\r\n }\r\n\r\n // Update texture data\r\n splatDataTextures['boneMatrix']['texture'].data = splatDataTextures.baseData['boneMatrix'];\r\n splatDataTextures['boneMatrix']['texture'].needsUpdate = true;\r\n material.uniforms.boneTexture.value = splatDataTextures['boneMatrix']['texture'];\r\n\r\n // Update skeleton uniforms\r\n if (flameModel.skeleton) {\r\n material.uniforms.boneTexture0.value = flameModel.skeleton.boneTexture;\r\n material.uniforms.bindMatrix.value = flameModel.bindMatrix;\r\n material.uniforms.bindMatrixInverse.value = flameModel.bindMatrixInverse;\r\n }\r\n\r\n material.uniformsNeedUpdate = true;\r\n}\r\n\r\n/**\r\n * Build LBS weight texture for skin deformation\r\n * @param {THREE.SkinnedMesh} flameModel - The FLAME mesh\r\n * @param {Array} bonesWeight - Per-vertex bone weights array\r\n * @param {THREE.ShaderMaterial} material - The splat material\r\n * @returns {object} Texture data object\r\n */\r\nexport function buildBoneWeightTexture(flameModel, bonesWeight, material) {\r\n const shapedMesh = flameModel.geometry.attributes.position.array;\r\n const pointNum = shapedMesh.length / 3;\r\n \r\n const boneWeightTextureSize = new Vector2(512, 512);\r\n const boneWeightTextureData = new Float32Array(boneWeightTextureSize.x * boneWeightTextureSize.y * 4);\r\n const boneWeightTextureDataInt = new Uint32Array(boneWeightTextureSize.x * boneWeightTextureSize.y * 4);\r\n\r\n for (let i = 0; i < pointNum; i++) {\r\n // Store 5 bone weights per vertex (2 texels)\r\n boneWeightTextureData[i * 8 + 0] = bonesWeight[i][0];\r\n boneWeightTextureData[i * 8 + 1] = bonesWeight[i][1];\r\n boneWeightTextureData[i * 8 + 2] = bonesWeight[i][2];\r\n boneWeightTextureData[i * 8 + 3] = bonesWeight[i][3];\r\n boneWeightTextureData[i * 8 + 4] = bonesWeight[i][4];\r\n\r\n boneWeightTextureDataInt[i * 8 + 0] = uintEncodedFloat(bonesWeight[i][0]);\r\n boneWeightTextureDataInt[i * 8 + 1] = uintEncodedFloat(bonesWeight[i][1]);\r\n boneWeightTextureDataInt[i * 8 + 2] = uintEncodedFloat(bonesWeight[i][2]);\r\n boneWeightTextureDataInt[i * 8 + 3] = uintEncodedFloat(bonesWeight[i][3]);\r\n boneWeightTextureDataInt[i * 8 + 4] = uintEncodedFloat(bonesWeight[i][4]);\r\n }\r\n\r\n const boneWeightTex = new DataTexture(\r\n boneWeightTextureDataInt,\r\n boneWeightTextureSize.x,\r\n boneWeightTextureSize.y,\r\n RGBAIntegerFormat,\r\n UnsignedIntType\r\n );\r\n boneWeightTex.internalFormat = 'RGBA32UI';\r\n boneWeightTex.needsUpdate = true;\r\n\r\n material.uniforms.boneWeightTexture.value = boneWeightTex;\r\n material.uniforms.boneWeightTextureSize.value.copy(boneWeightTextureSize);\r\n material.uniformsNeedUpdate = true;\r\n\r\n return {\r\n data: boneWeightTextureDataInt,\r\n texture: boneWeightTex,\r\n size: boneWeightTextureSize,\r\n baseData: { boneWeight: boneWeightTextureDataInt }\r\n };\r\n}\r\n\r\n/**\r\n * Get updated bone matrices from skeleton\r\n * @param {THREE.Skeleton} skeleton - The skeleton to read matrices from\r\n * @param {number} boneNum - Number of bones\r\n * @returns {Float32Array} Flattened bone matrices\r\n */\r\nexport function getUpdatedBoneMatrices(skeleton, boneNum) {\r\n const updatedBoneMatrices = [];\r\n \r\n for (let j = 0; j < boneNum; j++) {\r\n const boneMatrix = skeleton.bones[j].matrixWorld.clone()\r\n .multiply(skeleton.boneInverses[j].clone());\r\n\r\n const elements = boneMatrix.elements;\r\n for (let i = 0; i < elements.length; i++) {\r\n updatedBoneMatrices.push(elements[i]);\r\n }\r\n }\r\n \r\n return new Float32Array(updatedBoneMatrices);\r\n}\r\n\r\nexport const FlameTextureManager = {\r\n buildModelTexture,\r\n buildBoneMatrixTexture,\r\n updateBoneMatrixTexture,\r\n buildBoneWeightTexture,\r\n getUpdatedBoneMatrices\r\n};\r\n\r\nexport default FlameTextureManager;\r\n","/**\r\n * FlameAnimator - FLAME Parametric Head Model Animation Controller\r\n *\r\n * Derived from gaussian-splat-renderer-for-lam\r\n *\r\n * Manages FLAME (Faces Learned with an Articulated Model and Expressions) model animation:\r\n * - Skeletal bone rotation from FLAME parameters\r\n * - Blendshape weight updates for facial expressions\r\n * - Skeleton-mesh synchronization for gaussian splat rendering\r\n * - Linear blend skinning (LBS) with bone weights\r\n *\r\n * FLAME uses 5 bones: root, neck, jaw, left eye, right eye\r\n */\r\n\r\nimport {\r\n Matrix4,\r\n Bone,\r\n Skeleton\r\n} from 'three';\r\n\r\nimport { FlameTextureManager } from './FlameTextureManager.js';\r\nimport { getLogger } from '../utils/Logger.js';\r\nimport { ValidationError, ResourceDisposedError } from '../errors/index.js';\r\nimport { validateRequiredProperties } from '../utils/ValidationUtils.js';\r\nimport { vector3Pool, quaternionPool } from '../utils/ObjectPool.js';\r\n\r\nconst logger = getLogger('FlameAnimator');\r\n\r\n/**\r\n * FlameAnimator - Manages FLAME parametric head model animation\r\n *\r\n * Provides skeletal animation, blendshape morphing, and mesh deformation\r\n * for FLAME-based avatar heads with gaussian splatting rendering.\r\n */\r\nexport class FlameAnimator {\r\n /**\r\n * Create a FlameAnimator instance\r\n *\r\n * @constructor\r\n */\r\n constructor() {\r\n /** @type {THREE.Skeleton|null} FLAME skeleton with 5 bones */\r\n this.skeleton = null;\r\n\r\n /** @type {THREE.Bone[]|null} Array of skeleton bones */\r\n this.bones = null;\r\n\r\n /** @type {Object|null} FLAME animation parameters (rotation, expr, neck_pose, jaw_pose, eyes_pose) */\r\n this.flameParams = null;\r\n\r\n /** @type {Array|null} Linear blend skinning weights */\r\n this.lbsWeight = null;\r\n\r\n /** @type {number} Current animation frame */\r\n this.frame = 0;\r\n\r\n /** @type {number} Total frames in animation sequence */\r\n this.totalFrames = 0;\r\n\r\n /** @type {boolean} Whether FLAME mode is enabled */\r\n this.useFlame = true;\r\n\r\n /** @type {THREE.SkinnedMesh|null} The FLAME avatar mesh */\r\n this.avatarMesh = null;\r\n\r\n /** @type {number} Number of gaussian splats in the mesh */\r\n this.gaussianSplatCount = 0;\r\n\r\n /** @type {boolean} Whether animator has been disposed */\r\n this._disposed = false;\r\n\r\n logger.debug('FlameAnimator instance created');\r\n }\r\n\r\n /**\r\n * Assert animator is not disposed\r\n * @private\r\n * @throws {ResourceDisposedError} If animator has been disposed\r\n */\r\n _assertNotDisposed() {\r\n if (this._disposed) {\r\n throw new ResourceDisposedError('FlameAnimator has been disposed');\r\n }\r\n }\r\n\r\n /**\r\n * Initialize animator with FLAME parameters and skeleton data\r\n *\r\n * Sets up the FLAME animation system with parameters for bone rotations,\r\n * expressions, and linear blend skinning weights.\r\n *\r\n * @param {Object} flameParams - FLAME animation parameters\r\n * @param {Array} flameParams.rotation - Root bone rotations per frame (axis-angle)\r\n * @param {Array} flameParams.expr - Expression blendshape weights per frame\r\n * @param {Array} flameParams.neck_pose - Neck bone rotations per frame\r\n * @param {Array} flameParams.jaw_pose - Jaw bone rotations per frame\r\n * @param {Array} flameParams.eyes_pose - Eye bone rotations per frame (6 values: left 3, right 3)\r\n * @param {Object|Array} boneTree - Skeleton hierarchy definition\r\n * @param {Array} lbsWeight - Linear blend skinning weights for each vertex\r\n * @param {THREE.SkinnedMesh} avatarMesh - The FLAME avatar mesh\r\n * @throws {ValidationError} If required parameters are missing or invalid\r\n * @returns {void}\r\n */\r\n initialize(flameParams, boneTree, lbsWeight, avatarMesh) {\r\n this._assertNotDisposed();\r\n\r\n // Validate required parameters\r\n try {\r\n validateRequiredProperties(flameParams, ['rotation', 'expr', 'neck_pose', 'jaw_pose', 'eyes_pose'], 'flameParams');\r\n } catch (error) {\r\n logger.error('Invalid flameParams', error);\r\n throw error;\r\n }\r\n\r\n if (!avatarMesh || !avatarMesh.geometry || !avatarMesh.geometry.attributes || !avatarMesh.geometry.attributes.position) {\r\n const error = new ValidationError(\r\n 'avatarMesh must have geometry with position attribute',\r\n 'avatarMesh'\r\n );\r\n logger.error('Invalid avatarMesh', error);\r\n throw error;\r\n }\r\n\r\n logger.info('Initializing FlameAnimator', {\r\n frameCount: flameParams.rotation?.length,\r\n splatCount: avatarMesh.geometry.attributes.position.count\r\n });\r\n\r\n this.flameParams = flameParams;\r\n this.lbsWeight = lbsWeight;\r\n this.avatarMesh = avatarMesh;\r\n\r\n // Calculate total frames from rotation data\r\n if (flameParams.rotation && Array.isArray(flameParams.rotation)) {\r\n this.totalFrames = flameParams.rotation.length;\r\n logger.debug('Animation has frames', { totalFrames: this.totalFrames });\r\n } else {\r\n logger.warn('No rotation data found, totalFrames set to 0');\r\n this.totalFrames = 0;\r\n }\r\n\r\n this.gaussianSplatCount = avatarMesh.geometry.attributes.position.count;\r\n\r\n // Build skeleton from bone tree\r\n try {\r\n this.buildSkeleton(boneTree);\r\n logger.debug('Skeleton built successfully', { boneCount: this.bones?.length });\r\n } catch (error) {\r\n logger.error('Failed to build skeleton', error);\r\n throw new ValidationError(\r\n `Failed to build skeleton: ${error.message}`,\r\n 'boneTree',\r\n error\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Build skeleton from bone tree data\r\n * @param {object} boneTree - Skeleton hierarchy definition\r\n */\r\n buildSkeleton(boneTree) {\r\n if (!boneTree) return;\r\n\r\n this.bones = [];\r\n const boneInverses = [];\r\n\r\n // Create bones from tree structure\r\n const createBone = (boneData, parentBone = null) => {\r\n const bone = new Bone();\r\n bone.name = boneData.name || `bone_${this.bones.length}`;\r\n\r\n if (boneData.position) {\r\n bone.position.fromArray(boneData.position);\r\n }\r\n if (boneData.rotation) {\r\n bone.rotation.fromArray(boneData.rotation);\r\n }\r\n if (boneData.scale) {\r\n bone.scale.fromArray(boneData.scale);\r\n }\r\n\r\n if (parentBone) {\r\n parentBone.add(bone);\r\n }\r\n\r\n this.bones.push(bone);\r\n\r\n // Create inverse bind matrix\r\n const inverseMatrix = new Matrix4();\r\n if (boneData.inverseBindMatrix) {\r\n inverseMatrix.fromArray(boneData.inverseBindMatrix);\r\n } else {\r\n bone.updateMatrixWorld(true);\r\n inverseMatrix.copy(bone.matrixWorld).invert();\r\n }\r\n boneInverses.push(inverseMatrix);\r\n\r\n // Process children\r\n if (boneData.children) {\r\n boneData.children.forEach(child => createBone(child, bone));\r\n }\r\n };\r\n\r\n // If boneTree is array, create bones directly\r\n if (Array.isArray(boneTree)) {\r\n boneTree.forEach((boneData, index) => {\r\n const bone = new Bone();\r\n bone.name = boneData.name || `bone_${index}`;\r\n \r\n if (boneData.position) {\r\n bone.position.fromArray(boneData.position);\r\n }\r\n \r\n this.bones.push(bone);\r\n \r\n const inverseMatrix = new Matrix4();\r\n if (boneData.inverseBindMatrix) {\r\n inverseMatrix.fromArray(boneData.inverseBindMatrix);\r\n }\r\n boneInverses.push(inverseMatrix);\r\n });\r\n\r\n // Set up hierarchy (FLAME: root -> neck -> jaw, eyes)\r\n if (this.bones.length >= 5) {\r\n this.bones[0].add(this.bones[1]); // root -> neck\r\n this.bones[1].add(this.bones[2]); // neck -> jaw\r\n this.bones[1].add(this.bones[3]); // neck -> leftEye\r\n this.bones[1].add(this.bones[4]); // neck -> rightEye\r\n }\r\n } else if (boneTree.root) {\r\n createBone(boneTree.root);\r\n }\r\n\r\n // Create skeleton\r\n this.skeleton = new Skeleton(this.bones, boneInverses);\r\n }\r\n\r\n /**\r\n * Set bone rotation from axis-angle or quaternion representation\r\n *\r\n * Converts rotation data to quaternion and applies it to the bone.\r\n * Uses object pooling to avoid allocations in animation loop.\r\n *\r\n * @param {THREE.Bone} bone - Target bone to rotate\r\n * @param {Array<number>} angles - Rotation values (3 for axis-angle, 4 for quaternion)\r\n * @param {boolean} [isQuat=false] - Whether angles are quaternion [x, y, z, w]\r\n * @throws {ValidationError} If bone or angles are invalid\r\n * @returns {void}\r\n */\r\n setBoneRotation(bone, angles, isQuat = false) {\r\n this._assertNotDisposed();\r\n\r\n if (!bone || !angles || !Array.isArray(angles)) {\r\n throw new ValidationError(\r\n 'bone and angles array are required',\r\n 'bone/angles'\r\n );\r\n }\r\n\r\n // Use object pooling for temp objects\r\n const quaternion = quaternionPool.acquire();\r\n\r\n try {\r\n if (isQuat) {\r\n // Direct quaternion (XYZW format)\r\n if (angles.length < 4) {\r\n throw new ValidationError('Quaternion requires 4 values', 'angles');\r\n }\r\n quaternion.set(angles[0], angles[1], angles[2], angles[3]);\r\n } else {\r\n // Axis-angle representation: [x, y, z] where magnitude is angle\r\n if (angles.length < 3) {\r\n throw new ValidationError('Axis-angle requires 3 values', 'angles');\r\n }\r\n\r\n const axis = vector3Pool.acquire();\r\n try {\r\n axis.set(angles[0], angles[1], angles[2]);\r\n const angleInRadians = axis.length();\r\n axis.normalize();\r\n quaternion.setFromAxisAngle(axis, angleInRadians);\r\n } finally {\r\n vector3Pool.release(axis);\r\n }\r\n }\r\n\r\n // Apply rotation to bone\r\n bone.quaternion.copy(quaternion);\r\n bone.updateMatrixWorld(true);\r\n } finally {\r\n quaternionPool.release(quaternion);\r\n }\r\n }\r\n\r\n /**\r\n * Update FLAME bones from current frame parameters\r\n *\r\n * Applies bone rotations for all 5 FLAME bones (root, neck, jaw, left eye, right eye)\r\n * from the current animation frame. Updates skeleton matrices and returns data\r\n * needed for mesh deformation.\r\n *\r\n * @returns {Object} Bone and blendshape data for rendering\r\n * @returns {Array} return.bsWeight - Expression blendshape weights for current frame\r\n * @returns {Float32Array} return.bonesMatrix - Updated bone transformation matrices\r\n * @returns {number} return.bonesNum - Number of bones (always 5 for FLAME)\r\n * @returns {Array} return.bonesWeight - LBS weights for vertices\r\n */\r\n updateFlameBones() {\r\n this._assertNotDisposed();\r\n\r\n if (!this.flameParams || !this.skeleton) {\r\n logger.warn('Cannot update bones: flameParams or skeleton not initialized');\r\n return {};\r\n }\r\n\r\n const frame = this.frame;\r\n\r\n // Get blendshape weights for this frame\r\n const bsWeight = this.flameParams['expr'][frame];\r\n\r\n // Apply bone rotations for current frame\r\n try {\r\n // Root bone rotation (global head orientation)\r\n const rootAngle = this.flameParams['rotation'][frame];\r\n this.setBoneRotation(this.skeleton.bones[0], rootAngle);\r\n\r\n // Neck rotation\r\n const neckAngle = this.flameParams['neck_pose'][frame];\r\n this.setBoneRotation(this.skeleton.bones[1], neckAngle);\r\n\r\n // Jaw rotation\r\n const jawAngle = this.flameParams['jaw_pose'][frame];\r\n this.setBoneRotation(this.skeleton.bones[2], jawAngle);\r\n\r\n // Eyes rotation (6 values: left eye xyz, right eye xyz)\r\n const eyesAngle = this.flameParams['eyes_pose'][frame];\r\n this.setBoneRotation(this.skeleton.bones[3], eyesAngle.slice(0, 3)); // Left eye\r\n this.setBoneRotation(this.skeleton.bones[4], eyesAngle.slice(3, 6)); // Right eye\r\n } catch (error) {\r\n logger.error('Error setting bone rotations', { frame, error });\r\n throw error;\r\n }\r\n\r\n // Update skeleton matrices after all rotations are set\r\n this.skeleton.update();\r\n\r\n // Get updated bone matrices for shader\r\n const numBones = 5;\r\n const bonesMatrix = FlameTextureManager.getUpdatedBoneMatrices(this.skeleton, numBones);\r\n\r\n return {\r\n bsWeight,\r\n bonesMatrix,\r\n bonesNum: numBones,\r\n bonesWeight: this.lbsWeight\r\n };\r\n }\r\n\r\n /**\r\n * Run morph update - main animation loop function\r\n * @param {SplatMesh} splatMesh - The gaussian splat mesh to update\r\n */\r\n runMorphUpdate(splatMesh) {\r\n const morphedMesh = new Float32Array(\r\n this.avatarMesh.geometry.attributes.position.array\r\n );\r\n\r\n splatMesh.gaussianSplatCount = this.gaussianSplatCount;\r\n splatMesh.bonesNum = 5;\r\n\r\n if (this.useFlame) {\r\n const updateData = this.updateFlameBones();\r\n splatMesh.bsWeight = updateData.bsWeight;\r\n splatMesh.bonesMatrix = updateData.bonesMatrix;\r\n splatMesh.bonesNum = updateData.bonesNum;\r\n splatMesh.bonesWeight = updateData.bonesWeight;\r\n }\r\n\r\n splatMesh.morphedMesh = morphedMesh;\r\n\r\n // Update textures\r\n const splatNum = splatMesh.morphedMesh.length / 3;\r\n if (splatMesh.splatDataTextures && splatMesh.splatDataTextures['flameModel']) {\r\n splatMesh.updateTextureAfterBSAndSkeleton(0, splatNum - 1, this.useFlame);\r\n }\r\n }\r\n\r\n /**\r\n * Set current animation frame\r\n *\r\n * @param {number} frame - Frame number to set (will wrap if exceeds totalFrames)\r\n * @throws {ValidationError} If frame is not a valid number\r\n * @returns {void}\r\n */\r\n setFrame(frame) {\r\n this._assertNotDisposed();\r\n\r\n if (typeof frame !== 'number' || isNaN(frame)) {\r\n throw new ValidationError('frame must be a valid number', 'frame');\r\n }\r\n\r\n if (this.totalFrames > 0) {\r\n this.frame = ((frame % this.totalFrames) + this.totalFrames) % this.totalFrames; // Handle negative\r\n } else {\r\n this.frame = 0;\r\n }\r\n }\r\n\r\n /**\r\n * Advance to next frame in animation sequence\r\n *\r\n * Automatically wraps to frame 0 after reaching totalFrames.\r\n *\r\n * @returns {void}\r\n */\r\n nextFrame() {\r\n this._assertNotDisposed();\r\n\r\n if (this.totalFrames > 0) {\r\n this.frame = (this.frame + 1) % this.totalFrames;\r\n }\r\n }\r\n\r\n /**\r\n * Get skeleton for external use\r\n *\r\n * @returns {THREE.Skeleton|null} The FLAME skeleton or null if not initialized\r\n */\r\n getSkeleton() {\r\n this._assertNotDisposed();\r\n return this.skeleton;\r\n }\r\n\r\n /**\r\n * Get current frame number\r\n *\r\n * @returns {number} Current animation frame index\r\n */\r\n getFrame() {\r\n this._assertNotDisposed();\r\n return this.frame;\r\n }\r\n\r\n /**\r\n * Get total frame count\r\n *\r\n * @returns {number} Total number of animation frames\r\n */\r\n getTotalFrames() {\r\n this._assertNotDisposed();\r\n return this.totalFrames;\r\n }\r\n\r\n /**\r\n * Dispose animator and free resources\r\n *\r\n * Properly cleans up:\r\n * - Skeleton and bones\r\n * - References to meshes and parameters\r\n *\r\n * @returns {void}\r\n */\r\n dispose() {\r\n if (this._disposed) {\r\n logger.warn('FlameAnimator.dispose() called on already disposed instance');\r\n return;\r\n }\r\n\r\n logger.info('Disposing FlameAnimator');\r\n\r\n // Dispose skeleton (bones are part of skeleton)\r\n if (this.skeleton) {\r\n this.skeleton.dispose();\r\n this.skeleton = null;\r\n }\r\n\r\n // Nullify all references to aid GC\r\n this.bones = null;\r\n this.flameParams = null;\r\n this.lbsWeight = null;\r\n this.avatarMesh = null;\r\n\r\n // Reset state\r\n this.frame = 0;\r\n this.totalFrames = 0;\r\n this.gaussianSplatCount = 0;\r\n\r\n // Mark as disposed\r\n this._disposed = true;\r\n\r\n logger.debug('FlameAnimator disposed successfully');\r\n }\r\n}\r\n\r\nexport default FlameAnimator;\r\n","/**\r\n * LoaderUtils\r\n * \r\n * Derived from @mkkellogg/gaussian-splats-3d (MIT License)\r\n * https://github.com/mkkellogg/GaussianSplats3D\r\n * \r\n * Loader utilities for decoding text and resolving URLs.\r\n */\r\n\r\nexport class LoaderUtils {\r\n\r\n /**\r\n * @deprecated Use TextDecoder instead\r\n */\r\n static decodeText(array) {\r\n if (typeof TextDecoder !== 'undefined') {\r\n return new TextDecoder().decode(array);\r\n }\r\n\r\n // Fallback for environments without TextDecoder\r\n let s = '';\r\n\r\n for (let i = 0, il = array.length; i < il; i++) {\r\n // Implicitly assumes little-endian.\r\n s += String.fromCharCode(array[i]);\r\n }\r\n\r\n try {\r\n // merges multi-byte utf-8 characters.\r\n return decodeURIComponent(escape(s));\r\n } catch {\r\n // see #16358 - ignore decoding errors\r\n return s;\r\n }\r\n }\r\n\r\n static extractUrlBase(url) {\r\n const index = url.lastIndexOf('/');\r\n\r\n if (index === -1) return './';\r\n\r\n return url.slice(0, index + 1);\r\n }\r\n\r\n static resolveURL(url, path) {\r\n // Invalid URL\r\n if (typeof url !== 'string' || url === '') return '';\r\n\r\n // Host Relative URL\r\n if (/^https?:\\/\\//i.test(path) && /^\\//.test(url)) {\r\n path = path.replace(/(^https?:\\/\\/[^/]+).*/i, '$1');\r\n }\r\n\r\n // Absolute URL http://,https://,//\r\n if (/^(https?:)?\\/\\//i.test(url)) return url;\r\n\r\n // Data URI\r\n if (/^data:.*,.*$/i.test(url)) return url;\r\n\r\n // Blob URL\r\n if (/^blob:.*$/i.test(url)) return url;\r\n\r\n // Relative URL\r\n return path + url;\r\n }\r\n}\r\n"],"names":["LogLevel","None","Error","Warning","Info","Debug","RenderMode","Always","OnChange","Never","SceneFormat","Ply","sceneFormatFromPath","path","endsWith","SceneRevealMode","Default","Gradual","Instant","SplatRenderMode","ThreeD","TwoD","Constants$1","static","DefaultSphericalHarmonics8BitCompressionRange","Constants","SphericalHarmonics8BitCompressionRange","MIN_SPLAT_COUNT_TO_SHOW_SPLAT_TREE_LOADING_SPINNER","InternalLoadType","DirectToSplatBuffer","DirectToSplatArray","DownloadBeforeProcessing","LoaderStatus","Downloading","Processing","Done","ApplicationError","constructor","message","code","cause","super","this","name","captureStackTrace","toJSON","stack","ValidationError","field","NetworkError","statusCode","AssetLoadError","assetPath","ResourceDisposedError","resourceName","InitializationError","component","dataType","LoggerLevel","Object","freeze","DEBUG","INFO","WARN","ERROR","NONE","Logger","namespace","minLevel","setLevel","level","_format","args","Date","toISOString","debug","info","console","warn","error","errorWithTrace","context","contextStr","child","childNamespace","loggers","Map","globalLogLevel","setGlobalLogLevel","logger","values","getLogger","has","set","get","AbortedPromiseError","msg","fetchWithProgress","onProgress","saveChunks","headers","abortController","AbortController","signal","aborted","onProgressCalledAtComplete","localOnProgress","percent","percentLabel","chunk","fileSize","promise","Promise","resolve","reject","fetchOptions","fetch","then","async","data","ok","errorText","text","statusText","status","reader","body","getReader","bytesDownloaded","_fileSize","parseInt","undefined","chunks","value","done","read","buffer","Blob","arrayBuffer","length","toFixed","push","catch","abort","reason","clamp","val","min","max","Math","getCurrentTime","performance","now","disposeAllMeshes","object3D","geometry","dispose","material","children","delayedExecute","func","fast","window","setTimeout","getSphericalHarmonicsComponentCountForDegree","sphericalHarmonicsDegree","nativePromiseWithExtractedComponents","resolver","rejecter","abortablePromiseWithExtractedComponents","abortHandler","Semver","major","minor","patch","toString","isIOS","ua","navigator","userAgent","indexOf","getIOSSemever","extract","match","toHalfFloat","DataUtils","bind","fromHalfFloat","DefaultSphericalHarmonics8BitCompressionHalfRange","toUint8","v","rangeMin","rangeMax","range","floor","fromUint8","fromHalfFloatToUint8","fromUint8ToHalfFloat","convertBetweenCompressionLevels","noop","fromLevel","toLevel","isSH","outputConversionFunc","floatToHalf","floatView","Float32Array","int32View","Int32Array","x","bits","m","e","uintEncodedFloat","f","rgbaArrayToInteger","arr","offset","ALLOWED_PROTOCOLS","validateUrl","url","baseURL","parsed","base","location","href","URL","includes","protocol","join","validateInteger","fieldName","Number","isInteger","validateRequiredProperties","obj","requiredProps","objectName","prop","validateArrayBuffer","minSize","ArrayBuffer","byteLength","validateCallback","callback","required","validateHexColor","test","validateDOMElement","element","HTMLElement","ObjectPool","factory","reset","initialSize","_factory","_reset","_pool","_allocated","_maxSize","i","acquire","pop","release","releaseAll","objects","getStats","available","allocated","maxSize","vector3Pool","Vector3","matrix4Pool","Matrix4","identity","quaternionPool","Quaternion","q","eulerPool","Euler","tempVector3A","tempVector3B","tempVector3C","tempMatrix4A","tempMatrix4B","tempQuaternionA","tempQuaternionB","BlobUrlManager","_urls","_disposed","_assertNotDisposed","createBlobUrl","mimeType","label","blob","Uint8Array","type","createObjectURL","createdAt","size","substring","registerBlobUrl","startsWith","revokeBlobUrl","metadata","revokeObjectURL","delete","revokeAll","keys","clear","getMetadata","getAllTrackedUrls","urls","entries","totalSize","oldestAge","age","count","revokeOlderThan","maxAgeMs","toRevoke","isTracked","globalBlobUrlManager","EventEmitter","_listeners","_eventHistory","_maxHistorySize","on","event","options","wrappedCallback","once","off","_originalCallback","Set","add","listeners","listener","removeAllListeners","totalCount","Array","from","reduce","sum","emit","_recordEvent","callCount","timestamp","argCount","shift","getEventHistory","hasListeners","listenerCount","eventNames","stats","totalEvents","totalListeners","eventBreakdown","TYVoiceChatState","Idle","Listening","Responding","Thinking","ARKitBlendshapes","FlameBoneNames","ARKIT_BLENDSHAPES_COUNT","FLAME_BONES_COUNT","State","actions","isGroup","isPlaying","stage","blendingTime","update","state","Hello","AnimationManager","CurPlaying","time","SetWeight","loop","LoopRepeat","clampWhenFinished","paused","play","LastAction","PrepareCrossFade","getClip","duration","nextStage","LoopOnce","Listen","Think","Speak","getRandomNumber","round","random","ceil","lastAction","_warnedNoActions","action","weight","enabled","setEffectiveTimeScale","setEffectiveWeight","startAction","endAction","defaultDuration","UnPauseAllActions","ExecuteCrossFade","IsBlending","PauseAllActions","forEach","crossFadeTo","mixer","animations","animationcfg","helloActions","idleActions","listenActions","speakActions","thinkActions","helloIdx","hello","idleIdx","idle","listenIdx","listen","speakIdx","speak","thinkIdx","think","clip","clipAction","clone","curPlaying","resetAllActions","ignoreBlending","SplatScene","Object3D","splatBuffer","position","quaternion","scale","minimumAlpha","opacity","visible","copy","transform","copyTransformData","otherScene","updateTransform","dynamicMode","matrixWorldAutoUpdate","updateWorldMatrix","matrixWorld","matrixAutoUpdate","updateMatrix","matrix","SplatGeometry","build","maxSplatCount","baseGeometry","BufferGeometry","setIndex","positionsArray","positions","BufferAttribute","setAttribute","setXYZ","needsUpdate","InstancedBufferGeometry","splatIndexArray","Uint32Array","splatIndexes","InstancedBufferAttribute","setUsage","DynamicDrawUsage","instanceCount","SplatSubTree","rootNode","splatMesh","convertWorkerSubTree","workerSubTree","subTree","SplatTree","maxDepth","maxCentersPerNode","subTrees","diposeSplatTreeWorker","disposed","splatTreeWorker","terminate","processSplatMesh","filterFunc","onIndexesUpload","onSplatTreeConstruction","center","addCentersForScene","splatOffset","splatCount","sceneCenters","addedCount","globalSplatIndex","getSplatCenter","addBase","y","z","checkForEarlyExit","allCenters","s","scenes","getScene","getSplatCount","onmessage","convertedSubTree","transferBuffers","map","array","worker","centers","buffers","postMessage","process","countLeaves","leafCount","visitLeaves","visitFunc","visitLeavesFromNode","node","SplatMaterial","buildVertexShaderBase","enableOptionalEffects","maxSphericalHarmonicsDegree","customVars","vertexShaderSource","MaxScenes","getVertexShaderFadeIn","getUniforms","splatScale","pointCloudModeEnabled","uniforms","sceneCenter","fadeInComplete","orthographicMode","visibleRegionFadeStartRadius","visibleRegionRadius","bindMatrix","bindMatrixInverse","currentTime","firstRenderTime","centersColorsTexture","flameModelTexture","boneTexture","boneTexture0","boneWeightTexture","sphericalHarmonicsTexture","sphericalHarmonicsTextureR","sphericalHarmonicsTextureG","sphericalHarmonicsTextureB","sphericalHarmonics8BitCompressionRangeMin","sphericalHarmonics8BitCompressionRangeMax","focal","Vector2","orthoZoom","inverseFocalAdjustment","viewport","basisViewport","debugColor","Color","centersColorsTextureSize","flameModelTextureSize","boneTextureSize","boneWeightTextureSize","sphericalHarmonicsTextureSize","sphericalHarmonics8BitMode","sphericalHarmonicsMultiTextureMode","sceneIndexesTexture","sceneIndexesTextureSize","sceneCount","gaussianSplatCount","bsCount","headBoneIndex","eyeBlinkLeft","eyeBlinkRight","sceneOpacity","sceneVisibility","transformMatrices","SplatMaterial3D","antialiased","maxScreenSpaceSplatSize","kernel2DSize","irisOcclusionConfig","buildVertexShaderProjection","fragmentShaderSource","buildFragmentShader","ShaderMaterial","vertexShader","fragmentShader","transparent","alphaTest","blending","NormalBlending","depthTest","depthWrite","side","DoubleSide","right_iris","left_iris","start","end","SplatMaterial2D","dummyGeometry","dummyMaterial","MeshBasicMaterial","WebGLExtensions$1","gl","extensions","getExtension","extension","init","capabilities","isWebGL2","WebGLCapabilities$1","parameters","maxAnisotropy","getMaxPrecision","precision","getShaderPrecisionFormat","VERTEX_SHADER","HIGH_FLOAT","FRAGMENT_SHADER","MEDIUM_FLOAT","WebGL2RenderingContext","maxPrecision","drawBuffers","logarithmicDepthBuffer","maxTextures","getParameter","MAX_TEXTURE_IMAGE_UNITS","maxVertexTextures","MAX_VERTEX_TEXTURE_IMAGE_UNITS","maxTextureSize","MAX_TEXTURE_SIZE","maxCubemapSize","MAX_CUBE_MAP_TEXTURE_SIZE","maxAttributes","MAX_VERTEX_ATTRIBS","maxVertexUniforms","MAX_VERTEX_UNIFORM_VECTORS","maxVaryings","MAX_VARYING_VECTORS","maxFragmentUniforms","MAX_FRAGMENT_UNIFORM_VECTORS","vertexTextures","floatFragmentTextures","getMaxAnisotropy","MAX_TEXTURE_MAX_ANISOTROPY_EXT","floatVertexTextures","maxSamples","MAX_SAMPLES","WebGLUtils$1","convert","p","colorSpace","UnsignedByteType","UNSIGNED_BYTE","UNSIGNED_SHORT_4_4_4_4","UNSIGNED_SHORT_5_5_5_1","BYTE","SHORT","UNSIGNED_SHORT","INT","UNSIGNED_INT","FloatType","FLOAT","HalfFloatType","HALF_FLOAT","HALF_FLOAT_OES","ALPHA","RGB","RGBAFormat","RGBA","LUMINANCE","LUMINANCE_ALPHA","DEPTH_COMPONENT","DEPTH_STENCIL","RedFormat","RED","RedIntegerFormat","RED_INTEGER","RGFormat","RG","RGIntegerFormat","RG_INTEGER","RGBIntegerFormat","RGB_INTEGER","RGBAIntegerFormat","RGBA_INTEGER","COMPRESSED_RGB_S3TC_DXT1_EXT","COMPRESSED_RGBA_S3TC_DXT1_EXT","COMPRESSED_RGBA_S3TC_DXT3_EXT","COMPRESSED_RGBA_S3TC_DXT5_EXT","COMPRESSED_RGB_PVRTC_4BPPV1_IMG","COMPRESSED_RGB_PVRTC_2BPPV1_IMG","COMPRESSED_RGBA_PVRTC_4BPPV1_IMG","COMPRESSED_RGBA_PVRTC_2BPPV1_IMG","COMPRESSED_RGB_ETC1_WEBGL","UNSIGNED_INT_24_8","MAX_TEXTURE_TEXELS","SplatMesh","Mesh","splatRenderMode","halfPrecisionCovariancesOnGPU","devicePixelRatio","enableDistancesComputationOnGPU","integerBasedDistancesComputation","logLevel","sceneFadeInRateMultiplier","renderer","minSphericalHarmonicsDegree","splatTree","baseSplatTree","splatDataTextures","flameModel","expressionBSNum","bsWeight","bonesMatrix","bonesNum","bonesWeight","morphTargetDictionary","distancesTransformFeedback","id","program","centersBuffer","sceneIndexesBuffer","outDistancesBuffer","centersLoc","modelViewProjLoc","sceneIndexesLoc","transformsLocs","globalSplatIndexToLocalSplatIndexMap","globalSplatIndexToSceneIndexMap","lastBuildSplatCount","lastBuildScenes","lastBuildMaxSplatCount","lastBuildSceneCount","finalBuild","webGLUtils","boundingBox","Box3","calculatedSceneCenter","maxSplatDistanceFromSceneCenter","visibleRegionBufferRadius","visibleRegionChanging","lastRenderer","buildScenes","parentObject","splatBuffers","sceneOptions","positionArray","rotationArray","scaleArray","fromArray","rotation","scene","createScene","splatAlphaRemovalThreshold","buildSplatIndexMaps","localSplatIndexMap","sceneIndexMap","totalSplatCount","getMaxSplatCount","buildSplatTree","minAlphas","onSplatTreeIndexesUpload","disposeSplatTree","buildStartTime","splatColor","Vector4","splatIndex","getSplatColor","sceneIndex","getSceneIndexForSplat","minAlpha","w","buildTime","leavesWithVertices","avgSplatCount","nodeCount","nodeSplatCount","indexes","keepSceneTransforms","preserveVisibleRegion","getTotalMaxSplatCountForSplatBuffers","newScenes","newScene","existingScene","splatBufferSphericalHarmonicsDegree","getMinSphericalHarmonicsDegree","splatBuffersChanged","isUpdateBuild","disposeMeshData","indexMaps","splatBufferSplatCount","setupDistancesComputationTransformFeedback","dataUpdateResults","refreshGPUDataFromSplatBuffers","freeIntermediateSplatData","deleteTextureData","texture","source","image","onUpdate","baseData","covariances","colors","sphericalHarmonics","centerColors","sceneIndexes","flameModelPosTexture","textures","disposeTextures","computeDistancesOnGPUSyncTimeout","clearTimeout","disposeDistancesComputationGPUResources","textureKey","hasOwn","textureContainer","getSplatTree","onSplatTreeReady","onSplatTreeReadyCallback","getDataForDistancesComputation","getIntegerCenters","getFloatCenters","getSceneIndexes","sinceLastBuildOnly","refreshDataTexturesFromSplatBuffers","updateStart","refreshGPUBuffersForDistancesComputation","to","updateGPUCentersBufferForDistancesComputation","updateGPUTransformIndexesBufferForDistancesComputation","fromSplat","toSplat","updateBaseDataFromSplatBuffers","setupDataTextures","updateDataTexturesFromBaseData","updateVisibleRegion","computeDataTextureSize","elementsPerTexel","elementsPerSplat","texSize","getCovariancesInitialTextureSpecs","compressionLevel","elementsPerTexelStored","getCovariancesElementsPertexelStored","covarianceCompressionLevel","getTargetCovarianceCompressionLevel","shCompressionLevel","getTargetSphericalHarmonicsCompressionLevel","scales","rotations","initialCovTexSpecs","SphericalHarmonicsArrayType","Uint16Array","shComponentCount","shData","centersColsTexSize","paddedCentersCols","updateCenterColorsPaddedData","centersColsTex","DataTexture","UnsignedIntType","internalFormat","uniformsNeedUpdate","covTexSpecs","covariancesElementsPerTexelStored","covTexSize","covariancesElementsPerTexelAllocated","covariancesTextureData","covTex","updatePaddedCompressedCovariancesTextureData","covariancesTextureHalfFloat","covariancesTexture","dummyTex","covariancesAreHalfFloat","covariancesTextureSize","elementsPerTexelAllocated","scaleRotationsTexSize","ScaleRotationsDataType","scaleRotationsTextureType","paddedScaleRotations","updateScaleRotationsPaddedData","scaleRotationsTex","scaleRotationsTexture","scaleRotationsTextureSize","shTextureType","paddedSHComponentCount","shElementsPerTexel","texelFormat","shTexSize","paddedSHArray","c","srcBase","destBase","shTexture","componentCount","paddedComponentCount","textureCount","shComponentCountPerChannel","paddedSHArraySize","textureUniforms","paddedSHArrays","shTextures","t","componentCountPerChannel","minSphericalHarmonicsCoeff","maxSphericalHarmonicsCoeff","sceneIndexesTexSize","paddedTransformIndexes","morphAttributes","skeleton","bones","bone","index","buildModelTexture","buildBoneMatrixTexture","buildBoneWeightTexture","boneMatrixTextureData","boneMatrixTextureDataInt","key","boneMatrixTex","updateBoneMatrixTexture","idx","pointNum","attributes","boneWeightTextureData","boneWeightTextureDataInt","boneWeightTex","flameModelTexSize","shapedMesh","shapedMeshArray","bsLength","newIndex","originalIndex","bsMesh","concat","flameModelData","flameModelDataInt","flameModelTex","updateTetureAfterBSAndSkeleton","sceneTransform","getSceneTransform","fillSplatCenterArray","morphedMesh","centerColorsTextureDescriptor","paddedCenterColors","centerColorsTexture","centerColorsTextureProps","properties","__webglTexture","updateDataTexture","covarancesTextureDesc","scaleRotationsTextureDesc","scaleRotationCompressionLevel","shITextureDesc","fillSplatDataArrays","flameModelPos","shTextureDesc","flameModelTextureDescriptor","flameModelPosTextureProps","covarancesStartElement","covariancesEndElement","covariance","covariancesTextureProps","bytesPerElement","scaleRotationsTextureProps","shBytesPerElement","updateTexture","shTextureSize","shTextureProps","sceneIndexesTexDesc","paddedSceneIndexes","sceneIndexesTextureProps","getMaximumSplatBufferCompressionLevel","maxCompressionLevel","getMinimumSplatBufferCompressionLevel","minCompressionLevel","computeTextureUpdateRegion","startSplat","endSplat","textureWidth","texelsPerSplat","startSplatTexels","startRow","startRowElement","endSplatTexels","endRow","dataStart","dataEnd","paddedData","textureSize","textureProps","getContext","updateRegion","updateElementCount","updateDataView","updateHeight","glType","glFormat","format","currentTexture","TEXTURE_BINDING_2D","bindTexture","TEXTURE_2D","texSubImage2D","sourceData","textureData","textureDataStartIndex","fromElement","toElement","textureDataView","DataView","textureDataIndex","sequentialCount","setUint16","colorsBase","centersBase","centerColorsBase","scaleBase","rotationBase","scaleRotationsBase","tempCenter","avgCenter","multiplyScalar","distFromCSceneCenter","sub","updateVisibleRegionFadeDistance","sceneRevealMode","fastFadeRate","gradualFadeRate","defaultFadeInRate","fadeInRate","shaderFadeInComplete","updateRenderIndexes","globalIndexes","renderSplatCount","setDrawRange","updateTransforms","updateUniforms","renderDimensions","cameraFocalLengthX","cameraFocalLengthY","orthographicZoom","transforms","setSplatScale","getSplatScale","setPointCloudModeEnabled","getPointCloudModeEnabled","getSplatDataTextures","includeSinceLastBuild","getTotalSplatCountForScenes","getTotalSplatCountForSplatBuffers","getTotalMaxSplatCountForScenes","vao","deleteVertexArray","deleteProgram","deleteShader","disposeDistancesComputationGPUBufferResources","deleteTransformFeedback","deleteBuffer","setRenderer","currentMaxSplatCount","rebuildGPUObjects","rebuildBuffers","createShader","shader","shaderSource","compileShader","getShaderParameter","COMPILE_STATUS","typeName","errors","getShaderInfoLog","vsSource","currentVao","VERTEX_ARRAY_BINDING","currentProgram","CURRENT_PROGRAM","currentProgramDeleted","getProgramParameter","DELETE_STATUS","createVertexArray","bindVertexArray","createProgram","attachShader","transformFeedbackVaryings","SEPARATE_ATTRIBS","linkProgram","LINK_STATUS","getProgramInfoLog","useProgram","getAttribLocation","getUniformLocation","createBuffer","bindBuffer","ARRAY_BUFFER","enableVertexAttribArray","vertexAttribIPointer","vertexAttribPointer","bufferData","STATIC_READ","createTransformFeedback","bindTransformFeedback","TRANSFORM_FEEDBACK","bindBufferBase","TRANSFORM_FEEDBACK_BUFFER","isUpdate","offsetSplats","ArrayType","subBufferOffset","bufferSubData","maxArray","STATIC_DRAW","fillTransformsArray","tempArray","sceneTransformElements","elements","j","computeDistancesOnGPU","tempMatrix","modelViewProjMatrix","outComputedDistances","enable","RASTERIZER_DISCARD","premultiply","iTempMatrix","getIntegerMatrixArray","iTransform","uniform4i","uniformMatrix4fv","iViewProjMatrix","iViewProj","uniform3i","viewProj","uniform3f","beginTransformFeedback","POINTS","drawArrays","endTransformFeedback","disable","sync","fenceSync","SYNC_GPU_COMMANDS_COMPLETE","flush","checkSync","timeout","bitflags","clientWaitSync","TIMEOUT_EXPIRED","WAIT_FAILED","deleteSync","getBufferSubData","getLocalSplatParameters","globalIndex","paramsObj","returnSceneTransform","getSplatBufferForSplat","localIndex","getSplatLocalIndex","getSceneTransformForSplat","applySceneTransform","sphericalHarmonicsCompressionLevel","srcStart","srcEnd","destStart","scaleOverride","tempTransform","startSceneIndex","endSceneIndex","fillSplatCovarianceArray","fillSplatScaleRotationArray","fillSplatColorArray","fillSphericalHarmonicsArray","padFour","floatCenters","intCenters","paddedFloatCenters","outCenter","getSplatScaleAndRotation","outScale","outRotation","outColor","outTransform","getSceneCount","matrixElements","intMatrixArray","computeBoundingBox","applySceneTransforms","DirectLoadError","UncompressedSplatArray","X","Y","Z","SCALE0","SCALE1","SCALE2","ROTATION0","ROTATION1","ROTATION2","ROTATION3","FDC0","FDC1","FDC2","OPACITY","FRC0","FRC1","FRC2","FRC3","FRC4","FRC5","FRC6","FRC7","FRC8","FRC9","FRC10","FRC11","FRC12","FRC13","FRC14","FRC15","FRC16","FRC17","FRC18","FRC19","FRC20","FRC21","FRC22","FRC23","sphericalHarmonicsCount","defaultSphericalHarmonics","fill","splats","createSplat","baseSplat","shEntries","addSplat","splat","getSplat","addDefaultSplat","newSplat","addSplatFromComonents","scale0","scale1","scale2","rot0","rot1","rot2","rot3","r","g","b","rest","addSplatFromArray","src","srcIndex","srcSplat","copyBetweenBuffers","srcBuffer","srcOffset","destBuffer","destOffset","byteCount","dest","toUncompressedFloat","range8BitMin","range8BitMax","dataViewFloatForCompressionLevel","dataView","floatIndex","getFloat32","getUint16","getUint8","SplatBuffer","BytesPerCenter","BytesPerScale","BytesPerRotation","BytesPerColor","ScaleOffsetBytes","RotationffsetBytes","ColorOffsetBytes","SphericalHarmonicsOffsetBytes","ScaleRange","BytesPerSphericalHarmonicsComponent","SphericalHarmonicsOffsetFloat","SphericalHarmonicsDegrees","BytesPerSplat","secLoadedCountsToMax","constructFromBuffer","sections","section","getBucketIndex","localSplatIndex","bucketIndex","maxSplatIndexInFullBuckets","fullBucketCount","bucketSize","bucketSplatIndex","partiallyFullBucketIndex","currentPartiallyFilledBucketSize","partiallyFilledBucketLengths","sectionIndex","globalSplatIndexToSectionMap","splatCountOffset","srcSplatCentersBase","bytesPerSplat","dataBase","bucketBase","BucketStorageSizeFloats","sf","compressionScaleFactor","sr","compressionScaleRange","bucketArray","applyMatrix4","scaleMatrix","rotationMatrix","tempPosition","srcSplatScalesBase","CompressionLevels","makeScale","makeRotationFromQuaternion","multiply","decompose","srcSplatColorsBase","splatColorsArray","outCenterArray","srcFrom","srcTo","destFrom","centerDestBase","CenterComponentCount","ensurePositiveW","flip","outScaleArray","outRotationArray","desiredOutputCompressionLevel","outputConversion","srcCompressionLevel","scaleDestBase","ScaleComponentCount","rotationDestBase","RotationComponentCount","srcScaleX","srcScaleY","srcScaleZ","srcRotationW","srcRotationX","srcRotationY","srcRotationZ","normalize","tempMatrix4","Matrix3","covarianceMatrix","transformedCovariance","transform3x3","transform3x3Transpose","outCovariance","outOffset","setFromMatrix4","transpose","covarianceArray","covarianceDestBase","CovarianceComponentCount","computeCovariance","outColorArray","colorDestBase","ColorComponentCount","alpha","tempMatrix3","tempTranslation","tempScale","tempRotation","sh11","sh12","sh13","sh21","sh22","sh23","sh24","sh25","shIn1","shIn2","shIn3","shIn4","shIn5","shOut1","shOut2","shOut3","shOut4","shOut5","set3","val1","val2","val3","set3FromArray","srcDestView","stride","copy3","srcArray","destArray","setOutput3","conversionFunc","toUncompressedFloatArray3","outSphericalHarmonicsArray","outSphericalHarmonicsDegree","localFromHalfFloatToUint8","localToUint8","outSphericalHarmonicsComponentsCount","srcSplatSHBase","shDestBase","compressionLevelForOutputConversion","minShCoeff","maxShCoeff","rotateSphericalHarmonics3","rotateSphericalHarmonics5","v1","v2","v3","transformRow","outArray","t0","t1","t2","addInto3","v4","v5","t3","t4","in1","in2","in3","tsh11","tsh12","tsh13","out1","out2","out3","dot3","in4","in5","tsh21","tsh22","tsh23","tsh24","tsh25","out4","out5","kSqrt0104","sqrt","kSqrt0304","kSqrt0103","kSqrt0403","kSqrt0112","dot5","parseHeader","headerArrayUint8","HeaderSizeBytes","headerArrayUint16","headerArrayUint32","headerArrayFloat32","versionMajor","versionMinor","maxSectionCount","sectionCount","writeHeaderCountsToBuffer","writeHeaderToBuffer","header","parseSectionHeaders","sectionHeaderArrayUint16","SectionHeaderSizeBytes","sectionHeaderArrayUint32","sectionHeaderArrayFloat32","sectionHeaders","sectionHeaderBase","sectionHeaderBaseUint16","sectionHeaderBaseUint32","sectionBase","bucketCount","bucketBlockSize","halfBucketBlockSize","bucketStorageSizeBytes","partiallyFilledBucketCount","bucketsMetaDataSizeBytes","bucketsStorageSizeBytes","calculateComponentStorage","splatDataStorageSizeBytes","storageSizeBytes","sectionHeader","bucketsBase","writeSectionHeaderToBuffer","sectionHeadeArrayUint16","sectionHeadeArrayUint32","sectionHeadeArrayFloat32","BucketStorageSizeBytes","writeSectionHeaderSplatCountToBuffer","linkBufferArrays","buildMaps","bytesPerCenter","bytesPerScale","bytesPerRotation","bytesPerColor","sphericalHarmonicsComponentsPerSplat","sphericalHarmonicsBytesPerSplat","cumulativeSplatCount","updateLoadedCounts","newSectionCount","newSplatCount","updateSectionLoadedCounts","sectionHeaderOffset","tempCenterBuffer","tempScaleBuffer","tempRotationBuffer","tempColorBuffer","tempSHBuffer","tempRot","bucketCenterDelta","OFFSET_X","OFFSET_Y","OFFSET_Z","OFFSET_SCALE0","OFFSET_SCALE1","OFFSET_SCALE2","OFFSET_ROT0","OFFSET_ROT1","OFFSET_ROT2","OFFSET_ROT3","OFFSET_FDC0","OFFSET_FDC1","OFFSET_FDC2","OFFSET_OPACITY","OFFSET_FRC0","OFFSET_FRC9","OFFSET","compressPositionOffset","doubleCompressionScaleRange","targetSplat","sectionBuffer","bufferOffset","bucketCenter","centerBase","colorBase","sphericalHarmonicsBase","rot","shOut","bytesPerSHComponent","srcVal","degree1ByteCount","rgba","Uint8ClampedArray","generateFromUncompressedSplatArrays","splatArrays","blockSize","shDegree","sa","splatArray","sc","sectionBuffers","sectionHeaderBuffers","validSplats","sectionOptions","sectionBlockSize","blockSizeFactor","BucketBlockSize","sectionBucketSize","bucketSizeFactor","BucketSize","bucketInfo","computeBucketsForUncompressedSplatArray","fullBuckets","partiallyFullBucketLengths","partiallyFullBuckets","bucket","buckets","sectionDataSizeBytes","bucketMetaDataSizeBytes","bucketDataBytes","sectionSizeBytes","outSplatCount","row","writeSplatDataToSectionBuffer","bucketMetaDataArray","pfb","sectionHeaderBuffer","sectionsCumulativeSizeBytes","unifiedBufferSize","unifiedBuffer","currentUnifiedBase","halfBlockSize","dimensions","yBlocks","zBlocks","blockCenter","xBlock","yBlock","zBlock","bucketId","toArray","partiallyFullBucketArray","SplatPartitioner","sectionFilters","groupingParameters","partitionGenerator","partitionUncompressedSplatArray","results","newArrays","sectionSplats","sectionFilter","getStandardPartitioner","partitionSize","clampDistance","point","centerDist","lengthSq","sort","a","patitionCount","currentStartSplat","blocksSize","SplatBufferGenerator","splatPartitioner","alphaRemovalThreshold","sectionSize","generateFromUncompressedSplatArray","partitionResults","getStandardGenerator","PlyFormat","INRIAV1","FieldSizeIdDouble","FieldSizeIdInt","FieldSizeIdUInt","FieldSizeIdFloat","FieldSizeIdShort","FieldSizeIdUShort","FieldSizeIdUChar","FieldSizeStringMap","double","int","uint","float","short","ushort","uchar","FieldSize","PlyParserUtils","decodeSectionHeader","headerLines","fieldNameIdMap","headerStartLine","extractedLines","processingSection","headerEndLine","vertexCount","endOfHeader","sectionName","fieldIds","fieldTypes","allFieldNames","fieldTypesByName","line","trim","lineComponents","split","validComponents","lineComponent","trimmedComponent","fieldMatch","fieldTypeStr","fieldId","fieldType","HeaderEndToken","fieldOffsets","bytesPerVertex","decodeSphericalHarmonicsFromSectionHeader","dataSizeBytes","degree","sphericalHarmonicsCoefficientsPerChannel","coefficientsPerChannel","sphericalHarmonicsDegree1Fields","degree1Fields","sphericalHarmonicsDegree2Fields","degree2Fields","fieldNames","sphericalHarmonicsFieldCount","rgb","getHeaderSectionNames","sectionNames","headerLine","checkTextForEndHeader","endHeaderTestText","checkBufferForEndHeader","searchOfset","chunkSize","decoder","endHeaderTestChunk","decode","extractHeaderFromBufferToText","plyBuffer","TextDecoder","headerOffset","headerText","headerChunk","readChunkSize","readHeaderFromBuffer","convertHeaderTextToLines","prunedLines","determineHeaderFormatFromHeaderText","_headerText","determineHeaderFormatFromPlyBuffer","headertText","readVertex","vertexData","dataOffset","fieldsToRead","rawVertex","getInt16","getInt32","getUint32","BaseFieldNamesToRead","BaseFieldsToReadIndexes","SCALE_0","SCALE_1","SCALE_2","ROT_0","ROT_1","ROT_2","ROT_3","F_DC_0","F_DC_1","F_DC_2","GREEN","BLUE","F_REST_0","INRIAV1PlyParser","plyParserutils","decodeHeaderLines","shLineCount","shFieldsToReadCount","shRemainingFieldNamesToRead","fieldNamesToRead","fieldsToReadIndexes","acc","decodeHeaderText","headerSizeBytes","decodeHeaderFromBuffer","findSplatData","parseToUncompressedSplatBufferSection","splatData","splatDataOffset","toBuffer","toOffset","outBytesPerSplat","parsedSplat","parseToUncompressedSplat","outBase","parseToUncompressedSplatArraySection","decodeSectionSplatData","sectionSplatData","rawSplat","OFFSET_ROTATION0","OFFSET_ROTATION1","OFFSET_ROTATION2","OFFSET_ROTATION3","OFFSET_FRC","readSplat","exp","parseToUncompressedSplatArray","PlyParser","finalizeSplatData","optimizeSplatData","ParseError","PlyLoader","loadFromURL","fileName","loadDirectoToSplatBuffer","onProgressiveLoadSectionProgress","internalLoadType","directLoadSectionSizeBytes","ProgressiveLoadSectionSize","splatDataOffsetBytes","directLoadBufferIn","directLoadBufferOut","directLoadSplatBuffer","headerLoaded","readyToLoadSplatData","loadPromise","standardLoadUncompressedSplatArray","numBytesStreamed","numBytesParsed","numBytesDownloaded","textDecoder","inriaV1PlyParser","chunkData","loadComplete","sizeBytes","startBytes","endBytes","parseError","shDescriptor","splatBufferSizeBytes","CurrentMajorVersion","CurrentMinorVersion","inBytes","storeChunksInBuffer","numBytesToProcess","addedSplatCount","numBytesToParse","numBytesLeftOver","parsedDataViewOffset","dataToParse","keepChunks","keepSize","unshift","chunkDatas","plyFileData","loadFromFileData","errorCode","VectorRight","THREE","VectorUp","VectorBackward","Ray","origin","direction","setParameters","boxContainsPoint","box","epsilon","intersectBox","planeIntersectionPoint","planeIntersectionPointArray","originArray","directionArray","outHit","normal","distance","hitNormal","extremeVec","multiplier","sign","toSide","idx1","idx2","intersectSphere","toSphereCenterVec","radius","toClosestApproach","dot","toClosestApproachSq","diffSq","radiusSq","thc","addScaledVector","Hit","hitClone","Raycaster","raycastAgainstTrueSplatEllipsoid","ray","setFromCameraAndScreenPosition","ndcCoords","camera","screenPosition","screenDimensions","isPerspectiveCamera","setFromMatrixPosition","unproject","isOrthographicCamera","near","far","transformDirection","intersectSplatMesh","toLocal","fromLocal","localRay","tempPoint","outHits","invert","outHitsForSubTree","castRayAtSplatTreeNode","hit","tempColor","tempHit","scaleEpsilon","uniformScaleMatrix","toSphereSpace","fromSphereSpace","tempRay","splatGlobalIndex","splatSceneIndex","uniformScale","log10","SorterWasmNoSIMD","sortWorker","self","wasmInstance","wasmMemory","useSharedMemory","integerBasedSort","indexesToSortOffset","sortedIndexesOffset","sceneIndexesOffset","transformsOffset","precomputedDistancesOffset","mappedDistancesOffset","frequenciesOffset","centersOffset","modelViewProjOffset","countsZero","sortedIndexesOut","distanceMapRange","uploadedSplatCount","BytesPerInt","BytesPerFloat","renderCount","splatRenderCount","sortCount","splatSortCount","usePrecomputedDistances","copyIndexesToSort","copyPrecomputedDistances","copyTransforms","indexesToSort","precomputedDistances","modelViewProj","sortStartTime","exports","sortIndexes","sortMessage","sortDone","sortTime","sortedIndexes","sortEndTime","CENTERS_BYTES_PER_ENTRY","sorterWasmBytes","matrixSize","memoryRequiredForIndexesToSort","memoryRequiredForCenters","memoryRequiredForModelViewProjectionMatrix","memoryRequiredForPrecomputedDistances","memoryRequiredForMappedDistances","memoryRequiredForSortedIndexes","memoryRequiredForIntermediateSortBuffers","memoryRequiredforTransformIndexes","memoryRequiredforTransforms","extraMemory","MemoryPageSize","totalRequiredMemory","totalPagesRequired","sorterWasmImport","module","env","memory","WebAssembly","Memory","initial","maximum","shared","compile","wasmModule","instantiate","instance","sortSetupPhase1Complete","indexesToSortBuffer","sortedIndexesBuffer","precomputedDistancesBuffer","transformsBuffer","LoadingSpinner","container","tasks","show","hide","setContainer","addTask","removeTask","removeAllTasks","setMessageForTask","LoadingProgressBar","setProgress","SceneHelper","meshCursor","meshCursorVisible","focusMarker","focusMarkerOpacity","controlPlane","controlPlaneVisible","setupMeshCursor","setupFocusMarker","setupControlPlane","updateMeshCursor","pos","active","updateFocusMarker","target","updateControlPlane","cam","ctrl","setFocusMarkerVisibility","setFocusMarkerOpacity","o","getFocusMarkerOpacity","positionAndOrientFocusMarker","positionAndOrientMeshCursor","setMeshCursorVisibility","getMeschCursorVisibility","setControlPlaneVisibility","positionAndOrientControlPlane","quat","updateForRenderMode","mode","mesh","Viewer","cameraUp","initialCameraPosition","initialCameraRotation","backgroundColor","initialCameraLookAt","dropInMode","selfDrivenMode","selfDrivenUpdateFunc","selfDrivenUpdate","useBuiltInControls","rootElement","canvas","threejsCanvas","ignoreDevicePixelRatio","threeScene","gpuAcceleratedSort","sharedMemoryForWorkers","dynamicScene","renderMode","focalAdjustment","enableSIMDInSort","inMemoryCompressionLevel","semver","splatSortDistanceMapPrecision","DefaultSplatSortDistanceMapPrecision","onSplatMeshChangedCallback","createSplatMesh","controls","perspectiveControls","orthographicControls","orthographicCamera","perspectiveCamera","showMeshCursor","showControlPlane","showInfo","sceneHelper","sortRunning","lastSplatSortCount","sortWorkerIndexesToSort","sortWorkerSortedIndexes","sortWorkerPrecomputedDistances","sortWorkerTransforms","preSortMessages","runAfterNextSort","selfDrivenModeRunning","splatRenderReady","raycaster","infoPanel","startInOrthographicMode","currentFPS","lastSortTime","consecutiveRenderFrames","previousCameraTarget","nextCameraTarget","mousePosition","mouseDownPosition","mouseDownTime","resizeObserver","mouseMoveListener","mouseDownListener","mouseUpListener","keyDownListener","sortPromise","sortPromiseResolver","splatSceneDownloadControllers","splatSceneDownloadPromises","splatSceneDownloadAndBuildPromise","splatSceneRemovalPromise","loadingSpinner","document","loadingProgressBar","usingExternalCamera","usingExternalRenderer","initialized","disposing","disposePromise","lastTime","totalFrames","frame","avatarMesh","skinModel","boneRoot","baseMesh","setSkinAttibutes","frustumCulled","domElement","createElement","style","width","height","appendChild","setupCamera","setupRenderer","setupEventHandlers","Scene","getRenderDimensions","PerspectiveCamera","OrthographicCamera","rotateX","MathUtils","degToRad","rotateY","rotateZ","WebGLRenderer","antialias","setPixelRatio","autoClear","setClearColor","setSize","ResizeObserver","forceRenderNextFrame","observe","setupControls","OrbitControls","listenToKeyEvents","rotateSpeed","maxPolarAngle","PI","minPolarAngle","minAzimuthAngle","maxAzimuthAngle","enableDamping","dampingFactor","onMouseMove","addEventListener","onMouseDown","onMouseUp","onKeyDown","removeEventHandlers","removeEventListener","setRenderMode","setActiveSphericalHarmonicsDegrees","activeSphericalHarmonicsDegrees","onSplatMeshChanged","tempForward","tempMatrixLeft","tempMatrixRight","makeRotationAxis","up","setOrthographicMode","mouse","offsetX","offsetY","clickOffset","onMouseClick","checkForFocalPointChange","checkPointRenderDimensions","checkPointToNewFocalPoint","checkPointOutHits","transitioningCameraTarget","intersectionPoint","transitioningCameraTargetStartTime","outDimensions","offsetWidth","offsetHeight","getSize","fromCamera","toCamera","resetControls","saveState","fromControls","toControls","setCameraZoomFromPosition","setCameraPositionFromZoom","lookAt","tempVector","positionCamera","zoomedCamera","toLookAtDistance","zoom","negate","zoomCamera","positionZamera","updateSplatMesh","focalLengthX","projectionMatrix","focalLengthY","focalMultiplier","adjustForWebXRStereo","webXRActive","xrCameraProj00","xr","getCamera","cameraProj00","isLoadingOrUnloading","isDisposingOrDisposed","addSplatSceneDownloadController","controller","removeSplatSceneDownloadController","splice","addSplatSceneDownloadPromise","removeSplatSceneDownloadPromise","setSplatSceneDownloadAndBuildPromise","clearSplatSceneDownloadAndBuildPromise","addSplatScene","progressiveLoad","isProgressivelyLoadable","showLoadingUI","loadingUITaskId","onProgressUIUpdate","percentComplete","percentCompleteLabel","loaderStatus","suffix","downloadDone","downloadedPercentage","splatBuffersAddedUIUpdate","firstBuild","downloadAndBuildSingleSplatSceneProgressiveLoad","downloadAndBuildSingleSplatSceneStandardLoad","addSplatBufferOptions","orientation","addSplatBuffers","buildFunc","onException","downloadPromise","downloadSplatSceneToSplatBuffer","downloadAndBuildPromise","onDownloadProgress","onDownloadException","progressiveLoadedSectionBuildCount","progressiveLoadedSectionBuilding","queuedProgressiveLoadSectionBuilds","checkAndBuildProgressiveLoadSections","queuedBuild","progressiveLoadFirstSectionBuildPromise","splatSceneDownloadPromise","addSplatScenes","fileCount","onLoadProgress","fileIndex","totalPercent","downloadPromises","all","finally","progressiveBuild","onSectionBuilt","splatBufferOptions","showLoadingUIForSplatTreeBuild","replaceExisting","enableRenderBeforeFirstSort","splatProcessingTaskId","removeSplatProcessingTask","buildResults","addSplatBuffersToMesh","disposeSortWorker","setupSortWorker","runSplatSort","splatOptimizingTaskId","allSplatBuffers","allSplatBufferOptions","finished","setMinimized","DistancesArrayType","Worker","sourceWasm","iOSSemVer","sorterWasmBinaryString","atob","charCodeAt","createSortWorker","_","sortCanceled","removeSplatScene","indexToRemove","removeSplatScenes","indexesToRemove","revmovalTaskId","checkAndHideLoadingUI","onDone","savedSplatBuffers","savedSceneOptions","savedSceneTransformComponents","shouldRemove","requestFrameId","requestAnimationFrame","stop","cancelAnimationFrame","waitPromises","unobserve","removeChild","vsyncNum","vsyncCount","shouldRender","render","renderNextFrame","lastCameraPosition","lastCameraOrientation","changeEpsilon","cameraChanged","cp","co","abs","savedAuoClear","hasRenderables","fpsDiv","getElementById","textContent","updateForDropInMode","runMorphUpdate","updateForRendererSizeChanges","updateFPS","timingSensitiveUpdates","object","lastCalcTime","fpsFrameCount","lastRendererSize","currentRendererSize","lastCameraOrthographic","left","right","top","bottom","aspect","updateProjectionMatrix","lastUpdateTime","timeDelta","updateCameraTransition","tempCameraTarget","toPreviousTarget","toNextTarget","rotationAngle","acos","lerp","wasTransitioning","currentFocusMarkerOpacity","newFocusMarkerOpacity","updateInfoPanel","mvpMatrix","cameraPositionArray","lastSortViewDir","sortViewDir","lastSortViewPos","sortViewOffset","queuedSorts","partialSorts","angleThreshold","sortFractions","force","forceSortAll","angleDiff","positionDiff","needsRefreshForRotation","needsRefreshForPosition","applyQuaternion","shouldSortAll","gatherSceneNodesForSort","mvpCamera","gpuAcceleratedSortPromise","partialSort","sortFraction","cameraPosition","nodeRenderList","allSplatsSortBuffer","tempVectorYZ","tempVectorXZ","modelView","baseModelView","forward","tempMax","nodeSize","gatherAllNodes","cameraFocalLength","tan","fov","DEG2RAD","fovXOver2","atan","fovYOver2","cosFovXOver2","cos","cosFovYOver2","nodeRenderCount","nodesWithIndexes","distanceToNode","setX","setY","cameraAngleXZDot","cameraAngleYZDot","ns","currentByteOffset","windowSizeInts","windowSizeBytes","getSplatMesh","getSplatScene","isMobile","updateMorphTarget","inputMesh","updateMatrixWorld","getAttribute","skinIndexSource","skinIndex","skinWeightSource","skinWeight","newSkinIndex","normalized","newSkinWeight","splatNum","charactorConfig","motionConfig","animationConfig","other","GaussianSplatRenderer","create","downloadProgress","loadProgress","getChatState","getExpressionData","characterPath","characterName","characterZipResponse","zipData","matches","pathname","NProgress","JSZip","loadAsync","files","file","dir","slice","cameraPos","cameraRotation","offsetFileUrl","isNaN","isHexColorStrict","viewer","_canvas","loadModel","unpackFileAsBlob","_loadJsonFromZip","rightIrisRanges","leftIrisRanges","getInstance","_container","_blobUrlManager","zipUrls","zip","startTime","expressionData","chatState","getBoundingClientRect","visibility","clock","Clock","animManager","model","motioncfg","parentNode","disposeModel","stopAllAction","uncacheRoot","updateBS","actionData","influence","browDownLeft","browDownRight","browInnerUp","browOuterUpLeft","browOuterUpRight","mouthCheekPuff","cheekSquintLeft","cheekSquintRight","eyeLookDownLeft","eyeLookDownRight","eyeLookInLeft","eyeLookInRight","eyeLookOutLeft","eyeLookOutRight","eyeLookUpLeft","eyeLookUpRight","eyeSquintLeft","eyeSquintRight","eyeWideLeft","eyeWideRight","jawForward","jawLeft","jawOpen","jawRight","mouthClose","mouthDimpleLeft","mouthDimpleRight","mouthFrownLeft","mouthFrownRight","mouthFunnel","mouthLeft","mouthLowerDownLeft","mouthLowerDownRight","mouthPressLeft","mouthPressRight","mouthPucker","mouthRight","mouthRollLower","mouthRollUpper","mouthShrugLower","mouthShrugUpper","mouthSmileLeft","mouthSmileRight","mouthStretchLeft","mouthStretchRight","mouthUpperUpLeft","mouthUpperUpRight","noseSneerLeft","noseSneerRight","tongueOut","frameInfoInternal","calcDelta","frameIndex","_lastLoggedState","newState","hasAnimManager","mixerUpdateDelta","getDelta","morphTarget","setExpression","_warnedOnce","hasMixer","_renderLogCount","traverse","isMesh","isSkinnedMesh","morphTargetInfluences","pathName","aniclip","unpackAndLoadGlb","unpackAndLoadJson","skinModelSkinnedMesh","Bone","AnimationMixer","isArray","computeBoneTexture","fileEntry","modelFile","_getMimeType","modelUrl","jsonText","jsonData","JSON","parse","LoadGLTF","toLowerCase","ply","glb","gltf","json","bin","png","jpg","jpeg","jsonFile","GLTFLoader","load","useFlameModel","boneMatrix","updateFlameBoneMatrix","boneWeight","getUpdatedBoneMatrices","boneNum","updatedBoneMatrices","boneInverses","FlameTextureManager","flameParams","lbsWeight","useFlame","initialize","boneTree","frameCount","buildSkeleton","boneCount","createBone","boneData","parentBone","inverseMatrix","inverseBindMatrix","root","Skeleton","setBoneRotation","angles","isQuat","axis","angleInRadians","setFromAxisAngle","updateFlameBones","rootAngle","neckAngle","jawAngle","eyesAngle","updateData","updateTextureAfterBSAndSkeleton","setFrame","nextFrame","getSkeleton","getFrame","getTotalFrames","FlameBonesCount","DefaultBlendshapeCount","FlameModelTextureSize","BoneTextureSize","BoneWeightTextureSize","targetFps","onViolation","_targetFps","_frameBudget","_onViolation","_violations","_frameStart","startFrame","checkBudget","elapsed","withinBudget","budget","overrun","getViolationCount","resetViolations","decodeText","il","String","fromCharCode","decodeURIComponent","escape","extractUrlBase","lastIndexOf","resolveURL","replace","vector3","pool","matrix4","euler","getAllocatedCount","updateFn","renderFn","_update","_render","_maxDeltaTime","maxDeltaTime","_running","_rafId","_lastTime","_frameCount","_deferredTasks","_fpsHistory","_fpsHistorySize","_lastFpsUpdate","_currentFps","_tick","frameStart","rawDeltaTime","deltaTime","frameElapsed","remainingTime","_processDeferredTasks","_updateFpsTracking","frameTime","maxTime","task","fn","executeOrDefer","priority","getFps","fps","deferredTaskCount","running","isRunning","getFrameCount","clearDeferredTasks","CENTER_COLORS_ELEMENTS_PER_TEXEL","CENTER_COLORS_ELEMENTS_PER_SPLAT","COVARIANCES_ELEMENTS_PER_TEXEL_STORED","COVARIANCES_ELEMENTS_PER_TEXEL_ALLOCATED","COVARIANCES_ELEMENTS_PER_TEXEL_COMPRESSED_STORED","COVARIANCES_ELEMENTS_PER_TEXEL_COMPRESSED_ALLOCATED","COVARIANCES_ELEMENTS_PER_SPLAT","SCALES_ROTATIONS_ELEMENTS_PER_TEXEL","SCENE_INDEXES_ELEMENTS_PER_TEXEL","allowedEvents","_allowedEvents","_validateEvent","dangerousPatterns","normalizedPath","pattern","allowedValues","filename","allowedExtensions","ext"],"mappings":"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"}