UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

391 lines (390 loc) 11.4 kB
"use strict"; import { ActorsManager } from "./utils/ActorsManager"; import { SceneCamerasController } from "./utils/SceneCamerasController"; import { Cooker } from "./utils/Cooker"; import { SceneCookController } from "./utils/CookController"; import { CoreGraph } from "../../core/graph/CoreGraph"; import { CorePerformance } from "../../core/performance/CorePerformance"; import { DispatchController } from "./utils/DispatchController"; import { SceneExpressionsController } from "./utils/SceneExpressionsController"; import { SceneLifeCycleController } from "./utils/LifeCycleController"; import { LoadingController } from "./utils/LoadingController"; import { MissingReferencesController } from "./utils/missingReferences/MissingReferencesController"; import { GraphNodesController } from "./utils/GraphNodesController"; import { NodesController } from "./utils/NodesController"; import { SceneEventsDispatcher } from "./utils/events/EventsDispatcher"; import { ObjectsController } from "./utils/ObjectsController"; import { ScenePerformanceMonitor } from "./utils/ScenePerformanceMonitor"; import { ReferencesController } from "./utils/ReferencesController"; import { TimeController, TIME_CONTROLLER_UPDATE_TIME_OPTIONS_DEFAULT } from "./utils/TimeController"; import { UniformsController } from "./utils/UniformsController"; import { ViewersRegister } from "./utils/ViewersRegister"; import { SceneWebGLController } from "./utils/WebGLController"; import { WindowController } from "./utils/WindowController"; import { SceneAssetsController } from "./utils/AssetsController"; import { SceneTraverserController } from "./utils/SceneTraverser"; import { CoreString } from "../../core/String"; import { SceneRenderersRegister } from "./utils/SceneRenderersRegister"; import { Poly } from "../Poly"; import { SceneWebXRController } from "./utils/WebXREventsController"; export class PolyScene { // // // constructor // // constructor(options) { this._cooker = new Cooker(this); this.cookController = new SceneCookController(); this._graph = new CoreGraph(); this.lifecycleController = new SceneLifeCycleController(this); this.loadingController = new LoadingController(this); this.missingExpressionReferencesController = new MissingReferencesController(this); this.expressionsController = new SceneExpressionsController(); this.nodesController = new NodesController(this); this.graphNodesController = new GraphNodesController(this); this.renderersRegister = new SceneRenderersRegister(this); this._objectsController = new ObjectsController(this); this._referencesController = new ReferencesController(this); this.perfMonitor = new ScenePerformanceMonitor(this); this.sceneTraverser = new SceneTraverserController(this); // // // time // // this.timeController = new TimeController(this); this._disposed = false; this._graph.setScene(this); this._paramSerializerClass = options == null ? void 0 : options.paramsSerializerClass; this.nodesController.createRoot(options == null ? void 0 : options.root); Poly.scenesRegister.registerScene(this); } /** * Returns the THREE.Scene. * * @remarks * * Read more about how to use a THREE.Scene on [THREE's documentation](https://threejs.org/docs/?q=scene#api/en/scenes/Scene) * */ threejsScene() { return this.root().object; } setUuid(uuid) { return this._uuid = uuid; } get uuid() { return this._uuid; } setName(newName) { return this._name = PolyScene.sanitizeName(newName); } static sanitizeName(newName) { newName = CoreString.sanitizeName(newName); newName = newName.toLowerCase(); return newName; } name() { return this._name; } get camerasController() { return this._camerasController = this._camerasController || new SceneCamerasController(this); } /** * Returns the camera object that has been set as main * */ mainCamera() { return this.camerasController.mainCamera(); } get cooker() { return this._cooker; } get actorsManager() { return this._actorsManager = this._actorsManager || new ActorsManager(this); } get assets() { return this._assetsController = this._assetsController || new SceneAssetsController(); } /** * Returns a promise to wait for all nodes to have cooked when loading a scene. * */ async waitForCooksCompleted() { return await this.cookController.waitForCooksCompleted(); } get dispatchController() { return this._dispatchController = this._dispatchController || new DispatchController(this); } get eventsDispatcher() { return this._eventsDispatcher = this._eventsDispatcher || new SceneEventsDispatcher(this); } get webXR() { return this._webXRController = this._webXRController || new SceneWebXRController(this); } /** * When using Polygonjs viewers, a raycaster is created to use mouse events and detect if there are any object under the cursor. * But if no viewer is created, such as when [importing a scene in react three fiber](/docs/integrations/react_three_fiber), * It is then useful to give a raycaster. * */ setRaycaster(raycaster) { this.eventsDispatcher.setRaycaster(raycaster); } get graph() { return this._graph; } createNode(nodeClass, options) { return this.root().createNode(nodeClass, options); } /** * returns all nodes with a given type * * - polyScene.nodesByType('box'): returns all BoxSopNodes */ nodesByType(type) { return this.nodesController.nodesByType(type); } get objectsController() { return this._objectsController; } /** * returns a THREE.Object3D whose name matches the mask * */ findObjectByMask(mask) { return this._objectsController.findObjectByMask(mask); } /** * returns a list THREE.Object3Ds whose names matche the mask * */ objectsByMask(mask, parent) { return this._objectsController.objectsByMask(mask, parent); } get referencesController() { return this._referencesController; } get performance() { return this._performance = this._performance || new CorePerformance(); } get viewersRegister() { return this._viewersRegister = this._viewersRegister || new ViewersRegister(this); } /** * updates Polygonjs scene internals. This is called automatically when using Polygonjs viewers, * but you would need to call it yourself in the render loop when adding your scene to threejs or react-three-fiber. * See [https://polygonjs.com/docs/integrations](https://polygonjs.com/docs/integrations) * */ update(delta, state) { this.timeController.setDelta(delta); this.timeController.incrementTimeIfPlaying(TIME_CONTROLLER_UPDATE_TIME_OPTIONS_DEFAULT); this.sceneTraverser.traverseScene(state == null ? void 0 : state.scene); } /** * sets the current frame * */ setFrame(frame) { this.timeController.setFrame(frame); } setFrameToStart() { this.timeController.setFrameToStart(); } /** * returns the current frame * */ frame() { return this.timeController.frame(); } /** * returns the current time * */ time() { return this.timeController.time(); } maxFrame() { return this.timeController.maxFrame(); } /** * starts playing the scene * */ play() { this.timeController.play(); } /** * pauses the scene * */ pause() { this.timeController.pause(); } /** * increments the time * */ incrementTime(options) { this.timeController.incrementTime(options); } /** * increments the time if the scene is playing() * */ incrementTimeIfPlaying(options) { this.timeController.incrementTimeIfPlaying(options); } /** * registers a renderer * */ registerRenderer(renderer, options) { return this.renderersRegister.registerRenderer(renderer, options); } get uniformsController() { return this._uniformsController = this._uniformsController || new UniformsController(this); } get webglController() { return this._webglController = this._webglController || new SceneWebGLController(); } get windowController() { return this._windowController = this._windowController || new WindowController(this); } dispose() { if (this._disposed == true) { return; } this._disposed = true; this.batchUpdates(() => { this.nodesController.traverseNodes((node) => { var _a; (_a = node.parent()) == null ? void 0 : _a.removeNode(node); }); }); if (this._windowController) { this._windowController.dispose(); this._windowController = void 0; } this.timeController.dispose(); this.renderersRegister.dispose(); this.camerasController.dispose(); this.root().dispose(); Poly.scenesRegister.deregisterScene(this); } disposed() { return this._disposed; } paramSerializerClass() { return this._paramSerializerClass; } // // // cooker // // /** * batchUpdates can be useful to set multiple parameter values without triggering a recook for each update. * */ async batchUpdates(callback) { this._cooker.block(); await callback(); this._cooker.unblock(); } // // // nodes // // /** * returns a node based on its path * * - polyScene.node('/geo1') * */ node(path) { return this.nodesController.node(path); } /** * returns the root node * */ root() { return this.nodesController.root(); } /** * traverse all nodes and runs a callback for each * */ traverseNodes(callback) { this.nodesController.traverseNodes(callback); } // // // CALLBACKS // // /** * registers a BeforeTick callback. BeforeTick callbacks are run before updating the frame (and therefore before any time dependent node has changed) * */ registerOnBeforeTick(callbackName, callback) { this.timeController.registerOnBeforeTick(callbackName, callback); } /** * unregisters BeforeTick callback * */ unRegisterOnBeforeTick(callbackName) { this.timeController.unRegisterOnBeforeTick(callbackName); } /** * Returns the list registered BeforeTick callback names * */ registeredBeforeTickCallbacks() { return this.timeController.registeredBeforeTickCallbacks(); } /** * return true if a callback is registered with that name * */ hasBeforeTickCallback(callbackName) { return this.timeController.hasBeforeTickCallback(callbackName); } /** * registers AfterTick callback. AfterTick callbacks are run after updating the frame (and therefore after any time dependent node has changed) * */ registerOnAfterTick(callbackName, callback) { this.timeController.registerOnAfterTick(callbackName, callback); } /** * unregisters AfterTick callback * */ unRegisterOnAfterTick(callbackName) { this.timeController.unRegisterOnAfterTick(callbackName); } /** * Returns the list registered AfterTick callback names * */ registeredAfterTickCallbacks() { return this.timeController.registeredAfterTickCallbacks(); } /** * return true if a callback is registered with that name * */ hasAfterTickCallback(callbackName) { return this.timeController.hasAfterTickCallback(callbackName); } }