UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

264 lines (261 loc) 7.6 kB
import { LAYERID_WORLD } from '../../../scene/constants.js'; import { GSplatInstance } from '../../../scene/gsplat/gsplat-instance.js'; import { Asset } from '../../asset/asset.js'; import { AssetReference } from '../../asset/asset-reference.js'; import { Component } from '../component.js'; class GSplatComponent extends Component { constructor(system, entity){ super(system, entity), this._layers = [ LAYERID_WORLD ], this._instance = null, this._materialTmp = null, this._highQualitySH = true, this._customAabb = null, this._evtLayersChanged = null, this._evtLayerAdded = null, this._evtLayerRemoved = null, this._castShadows = false; this._assetReference = new AssetReference('asset', this, system.app.assets, { add: this._onGSplatAssetAdded, load: this._onGSplatAssetLoad, remove: this._onGSplatAssetRemove, unload: this._onGSplatAssetUnload }, this); entity.on('remove', this.onRemoveChild, this); entity.on('removehierarchy', this.onRemoveChild, this); entity.on('insert', this.onInsertChild, this); entity.on('inserthierarchy', this.onInsertChild, this); } set customAabb(value) { this._customAabb = value; this._instance?.meshInstance?.setCustomAabb(this._customAabb); } get customAabb() { return this._customAabb; } set instance(value) { this.destroyInstance(); this._instance = value; if (this._instance) { const mi = this._instance.meshInstance; if (!mi.node) { mi.node = this.entity; } mi.castShadow = this._castShadows; mi.setCustomAabb(this._customAabb); if (this.enabled && this.entity.enabled) { this.addToLayers(); } } } get instance() { return this._instance; } set material(value) { if (this._instance) { this._instance.material = value; } else { this._materialTmp = value; } } get material() { return this._instance?.material ?? this._materialTmp ?? null; } set highQualitySH(value) { if (value !== this._highQualitySH) { this._highQualitySH = value; if (this._instance) { this._instance.setHighQualitySH(value); } } } get highQualitySH() { return this._highQualitySH; } set castShadows(value) { if (this._castShadows !== value) { const mi = this.instance?.meshInstance; if (mi) { const layers = this.layers; const scene = this.system.app.scene; if (this._castShadows && !value) { for(let i = 0; i < layers.length; i++){ const layer = scene.layers.getLayerById(this.layers[i]); if (layer) { layer.removeShadowCasters([ mi ]); } } } mi.castShadow = value; if (!this._castShadows && value) { for(let i = 0; i < layers.length; i++){ const layer = scene.layers.getLayerById(layers[i]); if (layer) { layer.addShadowCasters([ mi ]); } } } } this._castShadows = value; } } get castShadows() { return this._castShadows; } set layers(value) { this.removeFromLayers(); this._layers.length = 0; for(let i = 0; i < value.length; i++){ this._layers[i] = value[i]; } if (!this.enabled || !this.entity.enabled) { return; } this.addToLayers(); } get layers() { return this._layers; } set asset(value) { const id = value instanceof Asset ? value.id : value; if (this._assetReference.id === id) return; if (this._assetReference.asset && this._assetReference.asset.resource) { this._onGSplatAssetRemove(); } this._assetReference.id = id; if (this._assetReference.asset) { this._onGSplatAssetAdded(); } } get asset() { return this._assetReference.id; } destroyInstance() { if (this._instance) { this.removeFromLayers(); this._instance?.destroy(); this._instance = null; } } addToLayers() { const meshInstance = this.instance?.meshInstance; if (meshInstance) { const layers = this.system.app.scene.layers; for(let i = 0; i < this._layers.length; i++){ layers.getLayerById(this._layers[i])?.addMeshInstances([ meshInstance ]); } } } removeFromLayers() { const meshInstance = this.instance?.meshInstance; if (meshInstance) { const layers = this.system.app.scene.layers; for(let i = 0; i < this._layers.length; i++){ layers.getLayerById(this._layers[i])?.removeMeshInstances([ meshInstance ]); } } } onRemoveChild() { this.removeFromLayers(); } onInsertChild() { if (this._instance && this.enabled && this.entity.enabled) { this.addToLayers(); } } onRemove() { this.destroyInstance(); this.asset = null; this._assetReference.id = null; this.entity.off('remove', this.onRemoveChild, this); this.entity.off('insert', this.onInsertChild, this); } onLayersChanged(oldComp, newComp) { this.addToLayers(); oldComp.off('add', this.onLayerAdded, this); oldComp.off('remove', this.onLayerRemoved, this); newComp.on('add', this.onLayerAdded, this); newComp.on('remove', this.onLayerRemoved, this); } onLayerAdded(layer) { const index = this.layers.indexOf(layer.id); if (index < 0) return; if (this._instance) { layer.addMeshInstances(this._instance.meshInstance); } } onLayerRemoved(layer) { const index = this.layers.indexOf(layer.id); if (index < 0) return; if (this._instance) { layer.removeMeshInstances(this._instance.meshInstance); } } onEnable() { const scene = this.system.app.scene; const layers = scene.layers; this._evtLayersChanged = scene.on('set:layers', this.onLayersChanged, this); if (layers) { this._evtLayerAdded = layers.on('add', this.onLayerAdded, this); this._evtLayerRemoved = layers.on('remove', this.onLayerRemoved, this); } if (this._instance) { this.addToLayers(); } else if (this.asset) { this._onGSplatAssetAdded(); } } onDisable() { const scene = this.system.app.scene; const layers = scene.layers; this._evtLayersChanged?.off(); this._evtLayersChanged = null; if (layers) { this._evtLayerAdded?.off(); this._evtLayerAdded = null; this._evtLayerRemoved?.off(); this._evtLayerRemoved = null; } this.removeFromLayers(); } hide() { if (this._instance) { this._instance.meshInstance.visible = false; } } show() { if (this._instance) { this._instance.meshInstance.visible = true; } } _onGSplatAssetAdded() { if (!this._assetReference.asset) { return; } if (this._assetReference.asset.resource) { this._onGSplatAssetLoad(); } else if (this.enabled && this.entity.enabled) { this.system.app.assets.load(this._assetReference.asset); } } _onGSplatAssetLoad() { this.destroyInstance(); const asset = this._assetReference.asset; if (asset) { this.instance = new GSplatInstance(asset.resource, { material: this._materialTmp, highQualitySH: this._highQualitySH }); this._materialTmp = null; this.customAabb = this.instance.resource.aabb.clone(); } } _onGSplatAssetUnload() { this.destroyInstance(); } _onGSplatAssetRemove() { this._onGSplatAssetUnload(); } } export { GSplatComponent };