playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
96 lines (95 loc) • 3.33 kB
JavaScript
import { Vec3 } from "../../../core/math/vec3.js";
import { BoundingBox } from "../../../core/shape/bounding-box.js";
import { GSplatDirector } from "../../../scene/gsplat-unified/gsplat-director.js";
import { ComponentSystem } from "../system.js";
import { GSplatComponent } from "./component.js";
import { gsplatChunksGLSL } from "../../../scene/shader-lib/glsl/collections/gsplat-chunks-glsl.js";
import { gsplatChunksWGSL } from "../../../scene/shader-lib/wgsl/collections/gsplat-chunks-wgsl.js";
import { SHADERLANGUAGE_GLSL, SHADERLANGUAGE_WGSL } from "../../../platform/graphics/constants.js";
import { ShaderChunks } from "../../../scene/shader-lib/shader-chunks.js";
const _properties = [
"unified",
"lodBaseDistance",
"lodMultiplier",
"lodRangeMin",
"lodRangeMax",
"castShadows",
"material",
"asset",
"resource",
"layers"
];
class GSplatComponentSystem extends ComponentSystem {
static EVENT_MATERIALCREATED = "material:created";
static EVENT_FRAMEREADY = "frame:ready";
static EVENT_FRAMEREQUEST = "frame:request";
constructor(app) {
super(app);
this.id = "gsplat";
this.ComponentType = GSplatComponent;
this.extraDataProperties = ["aabbCenter", "aabbHalfExtents"];
app.renderer.gsplatDirector = new GSplatDirector(app.graphicsDevice, app.renderer, app.scene, this);
ShaderChunks.get(app.graphicsDevice, SHADERLANGUAGE_GLSL).add(gsplatChunksGLSL);
ShaderChunks.get(app.graphicsDevice, SHADERLANGUAGE_WGSL).add(gsplatChunksWGSL);
this.on("beforeremove", this.onBeforeRemove, this);
this.app.on("framerender", this.onFrameRender, this);
}
onFrameRender() {
this.app.renderer.gsplatDirector?.updateStreaming();
}
initializeComponentData(component, _data, properties) {
if (_data.layers && _data.layers.length) {
_data.layers = _data.layers.slice(0);
}
for (let i = 0; i < _properties.length; i++) {
if (_data.hasOwnProperty(_properties[i])) {
component[_properties[i]] = _data[_properties[i]];
}
}
if (_data.aabbCenter && _data.aabbHalfExtents) {
component.customAabb = new BoundingBox(new Vec3(_data.aabbCenter), new Vec3(_data.aabbHalfExtents));
}
super.initializeComponentData(component, _data);
}
cloneComponent(entity, clone) {
const gSplatComponent = entity.gsplat;
const data = {};
_properties.forEach((prop) => {
if (prop === "material") {
if (!gSplatComponent.unified) {
const srcMaterial = gSplatComponent[prop];
if (srcMaterial) {
data[prop] = srcMaterial.clone();
}
}
} else {
data[prop] = gSplatComponent[prop];
}
});
data.enabled = gSplatComponent.enabled;
const component = this.addComponent(clone, data);
component.customAabb = gSplatComponent.customAabb?.clone() ?? null;
return component;
}
onBeforeRemove(entity, component) {
component.onBeforeRemove();
}
getMaterial(camera, layer) {
const director = this.app.renderer.gsplatDirector;
if (!director) return null;
const cameraData = director.camerasMap.get(camera);
if (!cameraData) return null;
const layerData = cameraData.layersMap.get(layer);
return layerData?.gsplatManager?.material ?? null;
}
getGSplatMaterial(camera, layer) {
return this.getMaterial(camera, layer);
}
destroy() {
super.destroy();
this.app.off("framerender", this.onFrameRender, this);
}
}
export {
GSplatComponentSystem
};