UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

162 lines (159 loc) 6.11 kB
import { GSplatManager } from './gsplat-manager.js'; /** * @import { LayerComposition } from '../composition/layer-composition.js' * @import { Camera } from '../camera.js' * @import { Layer } from '../layer.js' * @import { GraphicsDevice } from '../../platform/graphics/graphics-device.js' * @import { GraphNode } from '../graph-node.js' * @import { GSplatAssetLoaderBase } from './gsplat-asset-loader-base.js' * @import { Scene } from '../scene.js' * @import { Renderer } from '../renderer/renderer.js' */ /** * Per layer data the director keeps track of. * * @ignore */ class GSplatLayerData { /** * @param {GraphicsDevice} device - The graphics device. * @param {GSplatDirector} director - The director. * @param {Layer} layer - The layer. * @param {GraphNode} cameraNode - The camera node. */ constructor(device, director, layer, cameraNode){ this.gsplatManager = new GSplatManager(device, director, layer, cameraNode); } destroy() { this.gsplatManager.destroy(); } } /** * Per camera data the director keeps track of. * * @ignore */ class GSplatCameraData { destroy() { this.layersMap.forEach((layerData)=>layerData.destroy()); this.layersMap.clear(); } removeLayerData(layer) { const layerData = this.layersMap.get(layer); if (layerData) { layerData.destroy(); this.layersMap.delete(layer); } } getLayerData(device, director, layer, cameraNode) { let layerData = this.layersMap.get(layer); if (!layerData) { layerData = new GSplatLayerData(device, director, layer, cameraNode); this.layersMap.set(layer, layerData); } return layerData; } constructor(){ /** * @type {Map<Layer, GSplatLayerData>} */ this.layersMap = new Map(); } } /** * Class responsible for managing {@link GSplatManager} instances for Cameras and their Layers. * * @ignore */ class GSplatDirector { /** * @param {GraphicsDevice} device - The graphics device. * @param {Renderer} renderer - The renderer. * @param {Scene} scene - The scene. * @param {GSplatAssetLoaderBase} assetLoader - The asset loader. */ constructor(device, renderer, scene, assetLoader){ /** * Per camera data. * * @type {Map<Camera, GSplatCameraData>} */ this.camerasMap = new Map(); this.device = device; this.renderer = renderer; this.assetLoader = assetLoader; this.scene = scene; } destroy() { // destroy all gsplat managers this.camerasMap.forEach((cameraData)=>cameraData.destroy()); this.camerasMap.clear(); } getCameraData(camera) { let cameraData = this.camerasMap.get(camera); if (!cameraData) { cameraData = new GSplatCameraData(); this.camerasMap.set(camera, cameraData); } return cameraData; } /** * Updates the director for the given layer composition cameras and layers. * * @param {LayerComposition} comp - The layer composition. */ update(comp) { // remove camera / layer entires for cameras / layers no longer in the composition this.camerasMap.forEach((cameraData, camera)=>{ // camera is no longer in the composition if (!comp.camerasSet.has(camera)) { cameraData.destroy(); this.camerasMap.delete(camera); } else { // remove all layerdata for removed / disabled layers of this camera cameraData.layersMap.forEach((layerData, layer)=>{ if (!camera.layersSet.has(layer.id) || !layer.enabled) { layerData.destroy(); cameraData.layersMap.delete(layer); } }); } }); let gsplatCount = 0; // for all cameras in the composition const camerasComponents = comp.cameras; for(let i = 0; i < camerasComponents.length; i++){ const camera = camerasComponents[i].camera; let cameraData = this.camerasMap.get(camera); // for all of its layers const layerIds = camera.layers; for(let j = 0; j < layerIds.length; j++){ const layer = comp.getLayerById(layerIds[j]); if (layer?.enabled) { // if layer's splat placements were modified, or new camera if (layer.gsplatPlacementsDirty || !cameraData) { // no splats on layer const placements = layer.gsplatPlacements; if (placements.length === 0) { // remove gsplat manager if it exists if (cameraData) { cameraData.removeLayerData(layer); } } else { // update gsplat manager with modified placements cameraData ??= this.getCameraData(camera); const layerData = cameraData.getLayerData(this.device, this, layer, camera.node); layerData.gsplatManager.reconcile(placements); } } } } // update gsplat managers if (cameraData) { for (const layerData of cameraData.layersMap.values()){ gsplatCount += layerData.gsplatManager.update(); } } } // update stats this.renderer._gsplatCount = gsplatCount; // clear global gsplat params dirty flag after all updates for this camera this.scene.gsplat.dirty = false; // clear dirty flags on all layers of the composition for(let i = 0; i < comp.layerList.length; i++){ comp.layerList[i].gsplatPlacementsDirty = false; } } } export { GSplatDirector };