var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var BABYLON; (function (BABYLON) { var PointerEventTypes = (function () { function PointerEventTypes() { } Object.defineProperty(PointerEventTypes, "POINTERDOWN", { get: function () { return PointerEventTypes._POINTERDOWN; }, enumerable: true, configurable: true }); Object.defineProperty(PointerEventTypes, "POINTERUP", { get: function () { return PointerEventTypes._POINTERUP; }, enumerable: true, configurable: true }); Object.defineProperty(PointerEventTypes, "POINTERMOVE", { get: function () { return PointerEventTypes._POINTERMOVE; }, enumerable: true, configurable: true }); Object.defineProperty(PointerEventTypes, "POINTERWHEEL", { get: function () { return PointerEventTypes._POINTERWHEEL; }, enumerable: true, configurable: true }); Object.defineProperty(PointerEventTypes, "POINTERPICK", { get: function () { return PointerEventTypes._POINTERPICK; }, enumerable: true, configurable: true }); PointerEventTypes._POINTERDOWN = 0x01; PointerEventTypes._POINTERUP = 0x02; PointerEventTypes._POINTERMOVE = 0x04; PointerEventTypes._POINTERWHEEL = 0x08; PointerEventTypes._POINTERPICK = 0x10; return PointerEventTypes; }()); BABYLON.PointerEventTypes = PointerEventTypes; var PointerInfoBase = (function () { function PointerInfoBase(type, event) { this.type = type; this.event = event; } return PointerInfoBase; }()); BABYLON.PointerInfoBase = PointerInfoBase; /** * This class is used to store pointer related info for the onPrePointerObservable event. * Set the skipOnPointerObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onPointerObservable */ var PointerInfoPre = (function (_super) { __extends(PointerInfoPre, _super); function PointerInfoPre(type, event, localX, localY) { _super.call(this, type, event); this.skipOnPointerObservable = false; this.localPosition = new BABYLON.Vector2(localX, localY); } return PointerInfoPre; }(PointerInfoBase)); BABYLON.PointerInfoPre = PointerInfoPre; /** * This type contains all the data related to a pointer event in Babylon.js. * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The different event types can be found in the PointerEventTypes class. */ var PointerInfo = (function (_super) { __extends(PointerInfo, _super); function PointerInfo(type, event, pickInfo) { _super.call(this, type, event); this.pickInfo = pickInfo; } return PointerInfo; }(PointerInfoBase)); BABYLON.PointerInfo = PointerInfo; /** * This class is used by the onRenderingGroupObservable */ var RenderingGroupInfo = (function () { function RenderingGroupInfo() { } /** * Stage corresponding to the very first hook in the renderingGroup phase: before the render buffer may be cleared * This stage will be fired no matter what */ RenderingGroupInfo.STAGE_PRECLEAR = 1; /** * Called before opaque object are rendered. * This stage will be fired only if there's 3D Opaque content to render */ RenderingGroupInfo.STAGE_PREOPAQUE = 2; /** * Called after the opaque objects are rendered and before the transparent ones * This stage will be fired only if there's 3D transparent content to render */ RenderingGroupInfo.STAGE_PRETRANSPARENT = 3; /** * Called after the transparent object are rendered, last hook of the renderingGroup phase * This stage will be fired no matter what */ RenderingGroupInfo.STAGE_POSTTRANSPARENT = 4; return RenderingGroupInfo; }()); BABYLON.RenderingGroupInfo = RenderingGroupInfo; /** * Represents a scene to be rendered by the engine. * @see http://doc.babylonjs.com/page.php?p=21911 */ var Scene = (function () { /** * @constructor * @param {BABYLON.Engine} engine - the engine to be used to render this scene. */ function Scene(engine) { // Members this.autoClear = true; this.clearColor = new BABYLON.Color3(0.2, 0.2, 0.3); this.ambientColor = new BABYLON.Color3(0, 0, 0); this.forceWireframe = false; this.forcePointsCloud = false; this.forceShowBoundingBoxes = false; this.animationsEnabled = true; this.constantlyUpdateMeshUnderPointer = false; this.useRightHandedSystem = false; this.hoverCursor = "pointer"; // Metadata this.metadata = null; // Events /** * An event triggered when the scene is disposed. * @type {BABYLON.Observable} */ this.onDisposeObservable = new BABYLON.Observable(); /** * An event triggered before rendering the scene * @type {BABYLON.Observable} */ this.onBeforeRenderObservable = new BABYLON.Observable(); /** * An event triggered after rendering the scene * @type {BABYLON.Observable} */ this.onAfterRenderObservable = new BABYLON.Observable(); /** * An event triggered when the scene is ready * @type {BABYLON.Observable} */ this.onReadyObservable = new BABYLON.Observable(); /** * An event triggered before rendering a camera * @type {BABYLON.Observable} */ this.onBeforeCameraRenderObservable = new BABYLON.Observable(); /** * An event triggered after rendering a camera * @type {BABYLON.Observable} */ this.onAfterCameraRenderObservable = new BABYLON.Observable(); /** * An event triggered when a camera is created * @type {BABYLON.Observable} */ this.onNewCameraAddedObservable = new BABYLON.Observable(); /** * An event triggered when a camera is removed * @type {BABYLON.Observable} */ this.onCameraRemovedObservable = new BABYLON.Observable(); /** * An event triggered when a light is created * @type {BABYLON.Observable} */ this.onNewLightAddedObservable = new BABYLON.Observable(); /** * An event triggered when a light is removed * @type {BABYLON.Observable} */ this.onLightRemovedObservable = new BABYLON.Observable(); /** * An event triggered when a geometry is created * @type {BABYLON.Observable} */ this.onNewGeometryAddedObservable = new BABYLON.Observable(); /** * An event triggered when a geometry is removed * @type {BABYLON.Observable} */ this.onGeometryRemovedObservable = new BABYLON.Observable(); /** * An event triggered when a mesh is created * @type {BABYLON.Observable} */ this.onNewMeshAddedObservable = new BABYLON.Observable(); /** * An event triggered when a mesh is removed * @type {BABYLON.Observable} */ this.onMeshRemovedObservable = new BABYLON.Observable(); /** * This Observable will be triggered for each stage of each renderingGroup of each rendered camera. * The RenderinGroupInfo class contains all the information about the context in which the observable is called * If you wish to register an Observer only for a given set of renderingGroup, use the mask with a combination of the renderingGroup index elevated to the power of two (1 for renderingGroup 0, 2 for renderingrOup1, 4 for 2 and 8 for 3) */ this.onRenderingGroupObservable = new BABYLON.Observable(); // Animations this.animations = []; /** * This observable event is triggered when any mouse event registered during Scene.attach() is called BEFORE the 3D engine to process anything (mesh/sprite picking for instance). * You have the possibility to skip the 3D Engine process and the call to onPointerObservable by setting PointerInfoBase.skipOnPointerObservable to true */ this.onPrePointerObservable = new BABYLON.Observable(); /** * Observable event triggered each time an input event is received from the rendering canvas */ this.onPointerObservable = new BABYLON.Observable(); this.cameraToUseForPointers = null; // Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position this._startingPointerPosition = new BABYLON.Vector2(0, 0); this._startingPointerTime = 0; // Fog /** * is fog enabled on this scene. * @type {boolean} */ this.fogEnabled = true; this.fogMode = Scene.FOGMODE_NONE; this.fogColor = new BABYLON.Color3(0.2, 0.2, 0.3); this.fogDensity = 0.1; this.fogStart = 0; this.fogEnd = 1000.0; // Lights /** * is shadow enabled on this scene. * @type {boolean} */ this.shadowsEnabled = true; /** * is light enabled on this scene. * @type {boolean} */ this.lightsEnabled = true; /** * All of the lights added to this scene. * @see BABYLON.Light * @type {BABYLON.Light[]} */ this.lights = new Array(); // Cameras /** * All of the cameras added to this scene. * @see BABYLON.Camera * @type {BABYLON.Camera[]} */ this.cameras = new Array(); this.activeCameras = new Array(); // Meshes /** * All of the (abstract) meshes added to this scene. * @see BABYLON.AbstractMesh * @type {BABYLON.AbstractMesh[]} */ this.meshes = new Array(); // Geometries this._geometries = new Array(); this.materials = new Array(); this.multiMaterials = new Array(); // Textures this.texturesEnabled = true; this.textures = new Array(); // Particles this.particlesEnabled = true; this.particleSystems = new Array(); // Sprites this.spritesEnabled = true; this.spriteManagers = new Array(); // Layers this.layers = new Array(); this.highlightLayers = new Array(); // Skeletons this.skeletonsEnabled = true; this.skeletons = new Array(); // Lens flares this.lensFlaresEnabled = true; this.lensFlareSystems = new Array(); // Collisions this.collisionsEnabled = true; this.gravity = new BABYLON.Vector3(0, -9.807, 0); // Postprocesses this.postProcessesEnabled = true; // Customs render targets this.renderTargetsEnabled = true; this.dumpNextRenderTargets = false; this.customRenderTargets = new Array(); // Imported meshes this.importedMeshesFiles = new Array(); // Probes this.probesEnabled = true; this.reflectionProbes = new Array(); this._actionManagers = new Array(); this._meshesForIntersections = new BABYLON.SmartArray(256); // Procedural textures this.proceduralTexturesEnabled = true; this._proceduralTextures = new Array(); this.soundTracks = new Array(); this._audioEnabled = true; this._headphone = false; // Performance counters this._totalMeshesCounter = new BABYLON.PerfCounter(); this._totalLightsCounter = new BABYLON.PerfCounter(); this._totalMaterialsCounter = new BABYLON.PerfCounter(); this._totalTexturesCounter = new BABYLON.PerfCounter(); this._totalVertices = new BABYLON.PerfCounter(); this._activeIndices = new BABYLON.PerfCounter(); this._activeParticles = new BABYLON.PerfCounter(); this._lastFrameDuration = new BABYLON.PerfCounter(); this._evaluateActiveMeshesDuration = new BABYLON.PerfCounter(); this._renderTargetsDuration = new BABYLON.PerfCounter(); this._particlesDuration = new BABYLON.PerfCounter(); this._renderDuration = new BABYLON.PerfCounter(); this._spritesDuration = new BABYLON.PerfCounter(); this._activeBones = new BABYLON.PerfCounter(); this._renderId = 0; this._executeWhenReadyTimeoutId = -1; this._intermediateRendering = false; this._toBeDisposed = new BABYLON.SmartArray(256); this._pendingData = []; //ANY this._activeMeshes = new BABYLON.SmartArray(256); this._processedMaterials = new BABYLON.SmartArray(256); this._renderTargets = new BABYLON.SmartArray(256); this._activeParticleSystems = new BABYLON.SmartArray(256); this._activeSkeletons = new BABYLON.SmartArray(32); this._softwareSkinnedMeshes = new BABYLON.SmartArray(32); this._activeAnimatables = new Array(); this._transformMatrix = BABYLON.Matrix.Zero(); this._edgesRenderers = new BABYLON.SmartArray(16); this._uniqueIdCounter = 0; this._engine = engine; engine.scenes.push(this); this._externalData = new BABYLON.StringDictionary(); this._uid = null; this._renderingManager = new BABYLON.RenderingManager(this); this.postProcessManager = new BABYLON.PostProcessManager(this); this.postProcessRenderPipelineManager = new BABYLON.PostProcessRenderPipelineManager(); this._boundingBoxRenderer = new BABYLON.BoundingBoxRenderer(this); if (BABYLON.OutlineRenderer) { this._outlineRenderer = new BABYLON.OutlineRenderer(this); } this.attachControl(); if (BABYLON.SoundTrack) { this.mainSoundTrack = new BABYLON.SoundTrack(this, { mainTrack: true }); } //simplification queue if (BABYLON.SimplificationQueue) { this.simplificationQueue = new BABYLON.SimplificationQueue(); } //collision coordinator initialization. For now legacy per default. this.workerCollisions = false; //(!!Worker && (!!BABYLON.CollisionWorker || BABYLON.WorkerIncluded)); } Object.defineProperty(Scene, "FOGMODE_NONE", { get: function () { return Scene._FOGMODE_NONE; }, enumerable: true, configurable: true }); Object.defineProperty(Scene, "FOGMODE_EXP", { get: function () { return Scene._FOGMODE_EXP; }, enumerable: true, configurable: true }); Object.defineProperty(Scene, "FOGMODE_EXP2", { get: function () { return Scene._FOGMODE_EXP2; }, enumerable: true, configurable: true }); Object.defineProperty(Scene, "FOGMODE_LINEAR", { get: function () { return Scene._FOGMODE_LINEAR; }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "onDispose", { set: function (callback) { if (this._onDisposeObserver) { this.onDisposeObservable.remove(this._onDisposeObserver); } this._onDisposeObserver = this.onDisposeObservable.add(callback); }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "beforeRender", { set: function (callback) { if (this._onBeforeRenderObserver) { this.onBeforeRenderObservable.remove(this._onBeforeRenderObserver); } this._onBeforeRenderObserver = this.onBeforeRenderObservable.add(callback); }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "afterRender", { set: function (callback) { if (this._onAfterRenderObserver) { this.onAfterRenderObservable.remove(this._onAfterRenderObserver); } this._onAfterRenderObserver = this.onAfterRenderObservable.add(callback); }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "beforeCameraRender", { set: function (callback) { if (this._onBeforeCameraRenderObserver) { this.onBeforeCameraRenderObservable.remove(this._onBeforeCameraRenderObserver); } this._onBeforeCameraRenderObserver = this.onBeforeCameraRenderObservable.add(callback); }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "afterCameraRender", { set: function (callback) { if (this._onAfterCameraRenderObserver) { this.onAfterCameraRenderObservable.remove(this._onAfterCameraRenderObserver); } this._onAfterCameraRenderObserver = this.onAfterCameraRenderObservable.add(callback); }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "unTranslatedPointer", { get: function () { return new BABYLON.Vector2(this._unTranslatedPointerX, this._unTranslatedPointerY); }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "defaultMaterial", { get: function () { if (!this._defaultMaterial) { this._defaultMaterial = new BABYLON.StandardMaterial("default material", this); } return this._defaultMaterial; }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "debugLayer", { // Properties get: function () { if (!this._debugLayer) { this._debugLayer = new BABYLON.DebugLayer(this); } return this._debugLayer; }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "workerCollisions", { get: function () { return this._workerCollisions; }, set: function (enabled) { enabled = (enabled && !!Worker); this._workerCollisions = enabled; if (this.collisionCoordinator) { this.collisionCoordinator.destroy(); } this.collisionCoordinator = enabled ? new BABYLON.CollisionCoordinatorWorker() : new BABYLON.CollisionCoordinatorLegacy(); this.collisionCoordinator.init(this); }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "SelectionOctree", { get: function () { return this._selectionOctree; }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "meshUnderPointer", { /** * The mesh that is currently under the pointer. * @return {BABYLON.AbstractMesh} mesh under the pointer/mouse cursor or null if none. */ get: function () { return this._pointerOverMesh; }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "pointerX", { /** * Current on-screen X position of the pointer * @return {number} X position of the pointer */ get: function () { return this._pointerX; }, enumerable: true, configurable: true }); Object.defineProperty(Scene.prototype, "pointerY", { /** * Current on-screen Y position of the pointer * @return {number} Y position of the pointer */ get: function () { return this._pointerY; }, enumerable: true, configurable: true }); Scene.prototype.getCachedMaterial = function () { return this._cachedMaterial; }; Scene.prototype.getBoundingBoxRenderer = function () { return this._boundingBoxRenderer; }; Scene.prototype.getOutlineRenderer = function () { return this._outlineRenderer; }; Scene.prototype.getEngine = function () { return this._engine; }; Scene.prototype.getTotalVertices = function () { return this._totalVertices.current; }; Object.defineProperty(Scene.prototype, "totalVerticesPerfCounter", { get: function () { return this._totalVertices; }, enumerable: true, configurable: true }); Scene.prototype.getActiveIndices = function () { return this._activeIndices.current; }; Object.defineProperty(Scene.prototype, "totalActiveIndicesPerfCounter", { get: function () { return this._activeIndices; }, enumerable: true, configurable: true }); Scene.prototype.getActiveParticles = function () { return this._activeParticles.current; }; Object.defineProperty(Scene.prototype, "activeParticlesPerfCounter", { get: function () { return this._activeParticles; }, enumerable: true, configurable: true }); Scene.prototype.getActiveBones = function () { return this._activeBones.current; }; Object.defineProperty(Scene.prototype, "activeBonesPerfCounter", { get: function () { return this._activeBones; }, enumerable: true, configurable: true }); // Stats Scene.prototype.getLastFrameDuration = function () { return this._lastFrameDuration.current; }; Object.defineProperty(Scene.prototype, "lastFramePerfCounter", { get: function () { return this._lastFrameDuration; }, enumerable: true, configurable: true }); Scene.prototype.getEvaluateActiveMeshesDuration = function () { return this._evaluateActiveMeshesDuration.current; }; Object.defineProperty(Scene.prototype, "evaluateActiveMeshesDurationPerfCounter", { get: function () { return this._evaluateActiveMeshesDuration; }, enumerable: true, configurable: true }); Scene.prototype.getActiveMeshes = function () { return this._activeMeshes; }; Scene.prototype.getRenderTargetsDuration = function () { return this._renderTargetsDuration.current; }; Scene.prototype.getRenderDuration = function () { return this._renderDuration.current; }; Object.defineProperty(Scene.prototype, "renderDurationPerfCounter", { get: function () { return this._renderDuration; }, enumerable: true, configurable: true }); Scene.prototype.getParticlesDuration = function () { return this._particlesDuration.current; }; Object.defineProperty(Scene.prototype, "particlesDurationPerfCounter", { get: function () { return this._particlesDuration; }, enumerable: true, configurable: true }); Scene.prototype.getSpritesDuration = function () { return this._spritesDuration.current; }; Object.defineProperty(Scene.prototype, "spriteDuractionPerfCounter", { get: function () { return this._spritesDuration; }, enumerable: true, configurable: true }); Scene.prototype.getAnimationRatio = function () { return this._animationRatio; }; Scene.prototype.getRenderId = function () { return this._renderId; }; Scene.prototype.incrementRenderId = function () { this._renderId++; }; Scene.prototype._updatePointerPosition = function (evt) { var canvasRect = this._engine.getRenderingCanvasClientRect(); this._pointerX = evt.clientX - canvasRect.left; this._pointerY = evt.clientY - canvasRect.top; this._unTranslatedPointerX = this._pointerX; this._unTranslatedPointerY = this._pointerY; if (this.cameraToUseForPointers) { this._pointerX = this._pointerX - this.cameraToUseForPointers.viewport.x * this._engine.getRenderWidth(); this._pointerY = this._pointerY - this.cameraToUseForPointers.viewport.y * this._engine.getRenderHeight(); } }; // Pointers handling /** * Attach events to the canvas (To handle actionManagers triggers and raise onPointerMove, onPointerDown and onPointerUp * @param attachUp defines if you want to attach events to pointerup * @param attachDown defines if you want to attach events to pointerdown * @param attachMove defines if you want to attach events to pointermove */ Scene.prototype.attachControl = function (attachUp, attachDown, attachMove) { var _this = this; if (attachUp === void 0) { attachUp = true; } if (attachDown === void 0) { attachDown = true; } if (attachMove === void 0) { attachMove = true; } var spritePredicate = function (sprite) { return sprite.isPickable && sprite.actionManager && sprite.actionManager.hasPointerTriggers; }; this._onPointerMove = function (evt) { _this._updatePointerPosition(evt); // PreObservable support if (_this.onPrePointerObservable.hasObservers()) { var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE; var pi = new PointerInfoPre(type, evt, _this._unTranslatedPointerX, _this._unTranslatedPointerY); _this.onPrePointerObservable.notifyObservers(pi, type); if (pi.skipOnPointerObservable) { return; } } if (!_this.cameraToUseForPointers && !_this.activeCamera) { return; } var canvas = _this._engine.getRenderingCanvas(); if (!_this.pointerMovePredicate) { _this.pointerMovePredicate = function (mesh) { return mesh.isPickable && mesh.isVisible && mesh.isReady() && (_this.constantlyUpdateMeshUnderPointer || mesh.actionManager !== null && mesh.actionManager !== undefined); }; } // Meshes var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this.pointerMovePredicate, false, _this.cameraToUseForPointers); if (pickResult.hit && pickResult.pickedMesh) { _this.setPointerOverSprite(null); _this.setPointerOverMesh(pickResult.pickedMesh); if (_this._pointerOverMesh.actionManager && _this._pointerOverMesh.actionManager.hasPointerTriggers) { if (_this._pointerOverMesh.actionManager.hoverCursor) { canvas.style.cursor = _this._pointerOverMesh.actionManager.hoverCursor; } else { canvas.style.cursor = _this.hoverCursor; } } else { canvas.style.cursor = ""; } } else { _this.setPointerOverMesh(null); // Sprites pickResult = _this.pickSprite(_this._unTranslatedPointerX, _this._unTranslatedPointerY, spritePredicate, false, _this.cameraToUseForPointers); if (pickResult.hit && pickResult.pickedSprite) { _this.setPointerOverSprite(pickResult.pickedSprite); if (_this._pointerOverSprite.actionManager && _this._pointerOverSprite.actionManager.hoverCursor) { canvas.style.cursor = _this._pointerOverSprite.actionManager.hoverCursor; } else { canvas.style.cursor = _this.hoverCursor; } } else { _this.setPointerOverSprite(null); // Restore pointer canvas.style.cursor = ""; } } if (_this.onPointerMove) { _this.onPointerMove(evt, pickResult); } if (_this.onPointerObservable.hasObservers()) { var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE; var pi = new PointerInfo(type, evt, pickResult); _this.onPointerObservable.notifyObservers(pi, type); } }; this._onPointerDown = function (evt) { _this._updatePointerPosition(evt); // PreObservable support if (_this.onPrePointerObservable.hasObservers()) { var type = PointerEventTypes.POINTERDOWN; var pi = new PointerInfoPre(type, evt, _this._unTranslatedPointerX, _this._unTranslatedPointerY); _this.onPrePointerObservable.notifyObservers(pi, type); if (pi.skipOnPointerObservable) { return; } } if (!_this.cameraToUseForPointers && !_this.activeCamera) { return; } _this._startingPointerPosition.x = _this._pointerX; _this._startingPointerPosition.y = _this._pointerY; _this._startingPointerTime = new Date().getTime(); if (!_this.pointerDownPredicate) { _this.pointerDownPredicate = function (mesh) { return mesh.isPickable && mesh.isVisible && mesh.isReady() && (!mesh.actionManager || mesh.actionManager.hasPointerTriggers); }; } // Meshes _this._pickedDownMesh = null; var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this.pointerDownPredicate, false, _this.cameraToUseForPointers); if (pickResult.hit && pickResult.pickedMesh) { if (pickResult.pickedMesh.actionManager) { _this._pickedDownMesh = pickResult.pickedMesh; if (pickResult.pickedMesh.actionManager.hasPickTriggers) { switch (evt.button) { case 0: pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger, BABYLON.ActionEvent.CreateNew(pickResult.pickedMesh, evt)); break; case 1: pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger, BABYLON.ActionEvent.CreateNew(pickResult.pickedMesh, evt)); break; case 2: pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger, BABYLON.ActionEvent.CreateNew(pickResult.pickedMesh, evt)); break; } pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickDownTrigger, BABYLON.ActionEvent.CreateNew(pickResult.pickedMesh, evt)); } if (pickResult.pickedMesh.actionManager.hasSpecificTrigger(BABYLON.ActionManager.OnLongPressTrigger)) { var that = _this; window.setTimeout(function () { var pickResult = that.pick(that._unTranslatedPointerX, that._unTranslatedPointerY, function (mesh) { return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasSpecificTrigger(BABYLON.ActionManager.OnLongPressTrigger); }, false, that.cameraToUseForPointers); if (pickResult.hit && pickResult.pickedMesh) { if (pickResult.pickedMesh.actionManager) { if (that._startingPointerTime !== 0 && ((new Date().getTime() - that._startingPointerTime) > BABYLON.ActionManager.LongPressDelay) && (Math.abs(that._startingPointerPosition.x - that._pointerX) < BABYLON.ActionManager.DragMovementThreshold && Math.abs(that._startingPointerPosition.y - that._pointerY) < BABYLON.ActionManager.DragMovementThreshold)) { that._startingPointerTime = 0; pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnLongPressTrigger, BABYLON.ActionEvent.CreateNew(pickResult.pickedMesh, evt)); } } } }, BABYLON.ActionManager.LongPressDelay); } } } if (_this.onPointerDown) { _this.onPointerDown(evt, pickResult); } if (_this.onPointerObservable.hasObservers()) { var type = PointerEventTypes.POINTERDOWN; var pi = new PointerInfo(type, evt, pickResult); _this.onPointerObservable.notifyObservers(pi, type); } // Sprites _this._pickedDownSprite = null; if (_this.spriteManagers.length > 0) { pickResult = _this.pickSprite(_this._unTranslatedPointerX, _this._unTranslatedPointerY, spritePredicate, false, _this.cameraToUseForPointers); if (pickResult.hit && pickResult.pickedSprite) { if (pickResult.pickedSprite.actionManager) { _this._pickedDownSprite = pickResult.pickedSprite; switch (evt.button) { case 0: pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt)); break; case 1: pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt)); break; case 2: pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt)); break; } pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickDownTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt)); } } } }; this._onPointerUp = function (evt) { _this._updatePointerPosition(evt); // PreObservable support if (_this.onPrePointerObservable.hasObservers()) { var type = PointerEventTypes.POINTERUP; var pi = new PointerInfoPre(type, evt, _this._unTranslatedPointerX, _this._unTranslatedPointerY); _this.onPrePointerObservable.notifyObservers(pi, type); if (pi.skipOnPointerObservable) { return; } } if (!_this.cameraToUseForPointers && !_this.activeCamera) { return; } if (!_this.pointerUpPredicate) { _this.pointerUpPredicate = function (mesh) { return mesh.isPickable && mesh.isVisible && mesh.isReady() && (!mesh.actionManager || (mesh.actionManager.hasPickTriggers || mesh.actionManager.hasSpecificTrigger(BABYLON.ActionManager.OnLongPressTrigger))); }; } // Meshes var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this.pointerUpPredicate, false, _this.cameraToUseForPointers); if (pickResult.hit && pickResult.pickedMesh) { if (_this._pickedDownMesh != null && pickResult.pickedMesh == _this._pickedDownMesh) { if (_this.onPointerPick) { _this.onPointerPick(evt, pickResult); } if (_this.onPointerObservable.hasObservers()) { var type = PointerEventTypes.POINTERPICK; var pi = new PointerInfo(type, evt, pickResult); _this.onPointerObservable.notifyObservers(pi, type); } } if (pickResult.pickedMesh.actionManager) { pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickUpTrigger, BABYLON.ActionEvent.CreateNew(pickResult.pickedMesh, evt)); if (Math.abs(_this._startingPointerPosition.x - _this._pointerX) < BABYLON.ActionManager.DragMovementThreshold && Math.abs(_this._startingPointerPosition.y - _this._pointerY) < BABYLON.ActionManager.DragMovementThreshold) { pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger, BABYLON.ActionEvent.CreateNew(pickResult.pickedMesh, evt)); } } } if (_this._pickedDownMesh && _this._pickedDownMesh !== pickResult.pickedMesh) { _this._pickedDownMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickOutTrigger, BABYLON.ActionEvent.CreateNew(_this._pickedDownMesh, evt)); } if (_this.onPointerUp) { _this.onPointerUp(evt, pickResult); } if (_this.onPointerObservable.hasObservers()) { var type = PointerEventTypes.POINTERUP; var pi = new PointerInfo(type, evt, pickResult); _this.onPointerObservable.notifyObservers(pi, type); } _this._startingPointerTime = 0; // Sprites if (_this.spriteManagers.length > 0) { pickResult = _this.pickSprite(_this._unTranslatedPointerX, _this._unTranslatedPointerY, spritePredicate, false, _this.cameraToUseForPointers); if (pickResult.hit && pickResult.pickedSprite) { if (pickResult.pickedSprite.actionManager) { pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickUpTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt)); if (Math.abs(_this._startingPointerPosition.x - _this._pointerX) < BABYLON.ActionManager.DragMovementThreshold && Math.abs(_this._startingPointerPosition.y - _this._pointerY) < BABYLON.ActionManager.DragMovementThreshold) { pickResult.pickedSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger, BABYLON.ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, _this, evt)); } } } if (_this._pickedDownSprite && _this._pickedDownSprite !== pickResult.pickedSprite) { _this._pickedDownSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPickOutTrigger, BABYLON.ActionEvent.CreateNewFromSprite(_this._pickedDownSprite, _this, evt)); } } }; this._onKeyDown = function (evt) { if (_this.actionManager) { _this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyDownTrigger, BABYLON.ActionEvent.CreateNewFromScene(_this, evt)); } }; this._onKeyUp = function (evt) { if (_this.actionManager) { _this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyUpTrigger, BABYLON.ActionEvent.CreateNewFromScene(_this, evt)); } }; var eventPrefix = BABYLON.Tools.GetPointerPrefix(); var canvas = this._engine.getRenderingCanvas(); if (attachMove) { canvas.addEventListener(eventPrefix + "move", this._onPointerMove, false); // Wheel canvas.addEventListener('mousewheel', this._onPointerMove, false); canvas.addEventListener('DOMMouseScroll', this._onPointerMove, false); } if (attachDown) { canvas.addEventListener(eventPrefix + "down", this._onPointerDown, false); } if (attachUp) { canvas.addEventListener(eventPrefix + "up", this._onPointerUp, false); } canvas.tabIndex = 1; canvas.addEventListener("keydown", this._onKeyDown, false); canvas.addEventListener("keyup", this._onKeyUp, false); }; Scene.prototype.detachControl = function () { var eventPrefix = BABYLON.Tools.GetPointerPrefix(); var canvas = this._engine.getRenderingCanvas(); canvas.removeEventListener(eventPrefix + "move", this._onPointerMove); canvas.removeEventListener(eventPrefix + "down", this._onPointerDown); canvas.removeEventListener(eventPrefix + "up", this._onPointerUp); // Wheel canvas.removeEventListener('mousewheel', this._onPointerMove); canvas.removeEventListener('DOMMouseScroll', this._onPointerMove); canvas.removeEventListener("keydown", this._onKeyDown); canvas.removeEventListener("keyup", this._onKeyUp); }; // Ready Scene.prototype.isReady = function () { if (this._pendingData.length > 0) { return false; } var index; for (index = 0; index < this._geometries.length; index++) { var geometry = this._geometries[index]; if (geometry.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) { return false; } } for (index = 0; index < this.meshes.length; index++) { var mesh = this.meshes[index]; if (!mesh.isReady()) { return false; } var mat = mesh.material; if (mat) { if (!mat.isReady(mesh)) { return false; } } } return true; }; Scene.prototype.resetCachedMaterial = function () { this._cachedMaterial = null; }; Scene.prototype.registerBeforeRender = function (func) { this.onBeforeRenderObservable.add(func); }; Scene.prototype.unregisterBeforeRender = function (func) { this.onBeforeRenderObservable.removeCallback(func); }; Scene.prototype.registerAfterRender = function (func) { this.onAfterRenderObservable.add(func); }; Scene.prototype.unregisterAfterRender = function (func) { this.onAfterRenderObservable.removeCallback(func); }; Scene.prototype._addPendingData = function (data) { this._pendingData.push(data); }; Scene.prototype._removePendingData = function (data) { var index = this._pendingData.indexOf(data); if (index !== -1) { this._pendingData.splice(index, 1); } }; Scene.prototype.getWaitingItemsCount = function () { return this._pendingData.length; }; /** * Registers a function to be executed when the scene is ready. * @param {Function} func - the function to be executed. */ Scene.prototype.executeWhenReady = function (func) { var _this = this; this.onReadyObservable.add(func); if (this._executeWhenReadyTimeoutId !== -1) { return; } this._executeWhenReadyTimeoutId = setTimeout(function () { _this._checkIsReady(); }, 150); }; Scene.prototype._checkIsReady = function () { var _this = this; if (this.isReady()) { this.onReadyObservable.notifyObservers(this); this.onReadyObservable.clear(); this._executeWhenReadyTimeoutId = -1; return; } this._executeWhenReadyTimeoutId = setTimeout(function () { _this._checkIsReady(); }, 150); }; // Animations /** * Will start the animation sequence of a given target * @param target - the target * @param {number} from - from which frame should animation start * @param {number} to - till which frame should animation run. * @param {boolean} [loop] - should the animation loop * @param {number} [speedRatio] - the speed in which to run the animation * @param {Function} [onAnimationEnd] function to be executed when the animation ended. * @param {BABYLON.Animatable} [animatable] an animatable object. If not provided a new one will be created from the given params. * @return {BABYLON.Animatable} the animatable object created for this animation * @see BABYLON.Animatable * @see http://doc.babylonjs.com/page.php?p=22081 */ Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio, onAnimationEnd, animatable) { if (speedRatio === void 0) { speedRatio = 1.0; } this.stopAnimation(target); if (!animatable) { animatable = new BABYLON.Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd); } // Local animations if (target.animations) { animatable.appendAnimations(target, target.animations); } // Children animations if (target.getAnimatables) { var animatables = target.getAnimatables(); for (var index = 0; index < animatables.length; index++) { this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable); } } animatable.reset(); return animatable; }; Scene.prototype.beginDirectAnimation = function (target, animations, from, to, loop, speedRatio, onAnimationEnd) { if (speedRatio === undefined) { speedRatio = 1.0; } var animatable = new BABYLON.Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd, animations); return animatable; }; Scene.prototype.getAnimatableByTarget = function (target) { for (var index = 0; index < this._activeAnimatables.length; index++) { if (this._activeAnimatables[index].target === target) { return this._activeAnimatables[index]; } } return null; }; Object.defineProperty(Scene.prototype, "Animatables", { get: function () { return this._activeAnimatables; }, enumerable: true, configurable: true }); /** * Will stop the animation of the given target * @param target - the target * @param animationName - the name of the animation to stop (all animations will be stopped is empty) * @see beginAnimation */ Scene.prototype.stopAnimation = function (target, animationName) { var animatable = this.getAnimatableByTarget(target); if (animatable) { animatable.stop(animationName); } }; Scene.prototype._animate = function () { if (!this.animationsEnabled || this._activeAnimatables.length === 0) { return; } if (!this._animationStartDate) { if (this._pendingData.length > 0) { return; } this._animationStartDate = BABYLON.Tools.Now; } // Getting time var now = BABYLON.Tools.Now; var delay = now - this._animationStartDate; for (var index = 0; index < this._activeAnimatables.length; index++) { this._activeAnimatables[index]._animate(delay); } }; // Matrix Scene.prototype.getViewMatrix = function () { return this._viewMatrix; }; Scene.prototype.getProjectionMatrix = function () { return this._projectionMatrix; }; Scene.prototype.getTransformMatrix = function () { return this._transformMatrix; }; Scene.prototype.setTransformMatrix = function (view, projection) { this._viewMatrix = view; this._projectionMatrix = projection; this._viewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix); // Update frustum if (!this._frustumPlanes) { this._frustumPlanes = BABYLON.Frustum.GetPlanes(this._transformMatrix); } else { BABYLON.Frustum.GetPlanesToRef(this._transformMatrix, this._frustumPlanes); } }; // Methods Scene.prototype.addMesh = function (newMesh) { newMesh.uniqueId = this._uniqueIdCounter++; var position = this.meshes.push(newMesh); //notify the collision coordinator this.collisionCoordinator.onMeshAdded(newMesh); this.onNewMeshAddedObservable.notifyObservers(newMesh); }; Scene.prototype.removeMesh = function (toRemove) { var index = this.meshes.indexOf(toRemove); if (index !== -1) { // Remove from the scene if mesh found this.meshes.splice(index, 1); } //notify the collision coordinator this.collisionCoordinator.onMeshRemoved(toRemove); this.onMeshRemovedObservable.notifyObservers(toRemove); return index; }; Scene.prototype.removeSkeleton = function (toRemove) { var index = this.skeletons.indexOf(toRemove); if (index !== -1) { // Remove from the scene if mesh found this.skeletons.splice(index, 1); } return index; }; Scene.prototype.removeLight = function (toRemove) { var index = this.lights.indexOf(toRemove); if (index !== -1) { // Remove from the scene if mesh found this.lights.splice(index, 1); } this.onLightRemovedObservable.notifyObservers(toRemove); return index; }; Scene.prototype.removeCamera = function (toRemove) { var index = this.cameras.indexOf(toRemove); if (index !== -1) { // Remove from the scene if mesh found this.cameras.splice(index, 1); } // Remove from activeCameras var index2 = this.activeCameras.indexOf(toRemove); if (index2 !== -1) { // Remove from the scene if mesh found this.activeCameras.splice(index2, 1); } // Reset the activeCamera if (this.activeCamera === toRemove) { if (this.cameras.length > 0) { this.activeCamera = this.cameras[0]; } else { this.activeCamera = null; } } this.onCameraRemovedObservable.notifyObservers(toRemove); return index; }; Scene.prototype.addLight = function (newLight) { newLight.uniqueId = this._uniqueIdCounter++; var position = this.lights.push(newLight); this.onNewLightAddedObservable.notifyObservers(newLight); }; Scene.prototype.addCamera = function (newCamera) { newCamera.uniqueId = this._uniqueIdCounter++; var position = this.cameras.push(newCamera); this.onNewCameraAddedObservable.notifyObservers(newCamera); }; /** * Switch active camera * @param {Camera} newCamera - new active camera * @param {boolean} attachControl - call attachControl for the new active camera (default: true) */ Scene.prototype.switchActiveCamera = function (newCamera, attachControl) { if (attachControl === void 0) { attachControl = true; } var canvas = this._engine.getRenderingCanvas(); this.activeCamera.detachControl(canvas); this.activeCamera = newCamera; if (attachControl) { newCamera.attachControl(canvas); } }; /** * sets the active camera of the scene using its ID * @param {string} id - the camera's ID * @return {BABYLON.Camera|null} the new active camera or null if none found. * @see activeCamera */ Scene.prototype.setActiveCameraByID = function (id) { var camera = this.getCameraByID(id); if (camera) { this.activeCamera = camera; return camera; } return null; }; /** * sets the active camera of the scene using its name * @param {string} name - the camera's name * @return {BABYLON.Camera|null} the new active camera or null if none found. * @see activeCamera */ Scene.prototype.setActiveCameraByName = function (name) { var camera = this.getCameraByName(name); if (camera) { this.activeCamera = camera; return camera; } return null; }; /** * get a material using its id * @param {string} the material's ID * @return {BABYLON.Material|null} the material or null if none found. */ Scene.prototype.getMaterialByID = function (id) { for (var index = 0; index < this.materials.length; index++) { if (this.materials[index].id === id) { return this.materials[index]; } } return null; }; /** * get a material using its name * @param {string} the material's name * @return {BABYLON.Material|null} the material or null if none found. */ Scene.prototype.getMaterialByName = function (name) { for (var index = 0; index < this.materials.length; index++) { if (this.materials[index].name === name) { return this.materials[index]; } } return null; }; Scene.prototype.getLensFlareSystemByName = function (name) { for (var index = 0; index < this.lensFlareSystems.length; index++) { if (this.lensFlareSystems[index].name === name) { return this.lensFlareSystems[index]; } } return null; }; Scene.prototype.getLensFlareSystemByID = function (id) { for (var index = 0; index < this.lensFlareSystems.length; index++) { if (this.lensFlareSystems[index].id === id) { return this.lensFlareSystems[index]; } } return null; }; Scene.prototype.getCameraByID = function (id) { for (var index = 0; index < this.cameras.length; index++) { if (this.cameras[index].id === id) { return this.cameras[index]; } } return null; }; Scene.prototype.getCameraByUniqueID = function (uniqueId) { for (var index = 0; index < this.cameras.length; index++) { if (this.cameras[index].uniqueId === uniqueId) { return this.cameras[index]; } } return null; }; /** * get a camera using its name * @param {string} the camera's name * @return {BABYLON.Camera|null} the camera or null if none found. */ Scene.prototype.getCameraByName = function (name) { for (var index = 0; index < this.cameras.length; index++) { if (this.cameras[index].name === name) { return this.cameras[index]; } } return null; }; /** * get a bone using its id * @param {string} the bone's id * @return {BABYLON.Bone|null} the bone or null if not found */ Scene.prototype.getBoneByID = function (id) { for (var skeletonIndex = 0; skeletonIndex < this.skeletons.length; skeletonIndex++) { var skeleton = this.skeletons[skeletonIndex]; for (var boneIndex = 0; boneIndex < skeleton.bones.length; boneIndex++) { if (skeleton.bones[boneIndex].id === id) { return skeleton.bones[boneIndex]; } } } return null; }; /** * get a bone using its id * @param {string} the bone's name * @return {BABYLON.Bone|null} the bone or null if not found */ Scene.prototype.getBoneByName = function (name) { for (var skeletonIndex = 0; skeletonIndex < this.skeletons.length; skeletonIndex++) { var skeleton = this.skeletons[skeletonIndex]; for (var boneIndex = 0; boneIndex < skeleton.bones.length; boneIndex++) { if (skeleton.bones[boneIndex].name === name) { return skeleton.bones[boneIndex]; } } } return null; }; /** * get a light node using its name * @param {string} the light's name * @return {BABYLON.Light|null} the light or null if none found. */ Scene.prototype.getLightByName = function (name) { for (var index = 0; index < this.lights.length; index++) { if (this.lights[index].name === name) { return this.lights[index]; } } return null; }; /** * get a light node using its ID * @param {string} the light's id * @return {BABYLON.Light|null} the light or null if none found. */ Scene.prototype.getLightByID = function (id) { for (var index = 0; index < this.lights.length; index++) { if (this.lights[index].id === id) { return this.lights[index]; } } return null; }; /** * get a light node using its scene-generated unique ID * @param {number} the light's unique id * @return {BABYLON.Light|null} the light or null if none found. */ Scene.prototype.getLightByUniqueID = function (uniqueId) { for (var index = 0; index < this.lights.length; index++) { if (this.lights[index].uniqueId === uniqueId) { return this.lights[index]; } } return null; }; /** * get a particle system by id * @param id {number} the particle system id * @return {BABYLON.ParticleSystem|null} the corresponding system or null if none found. */ Scene.prototype.getParticleSystemByID = function (id) { for (var index = 0; index < this.particleSystems.length; index++) { if (this.particleSystems[index].id === id) { return this.particleSystems[index]; } } return null; }; /** * get a geometry using its ID * @param {string} the geometry's id * @return {BABYLON.Geometry|null} the geometry or null if none found. */ Scene.prototype.getGeometryByID = function (id) { for (var index = 0; index < this._geometries.length; index++) { if (this._geometries[index].id === id) { return this._geometries[index]; } } return null; }; /** * add a new geometry to this scene. * @param {BABYLON.Geometry} geometry - the geometry to be added to the scene. * @param {boolean} [force] - force addition, even if a geometry with this ID already exists * @return {boolean} was the geometry added or not */ Scene.prototype.pushGeometry = function (geometry, force) { if (!force && this.getGeometryByID(geometry.id)) { return false; } this._geometries.push(geometry); //notify the collision coordinator this.collisionCoordinator.onGeometryAdded(geometry); this.onNewGeometryAddedObservable.notifyObservers(geometry); return true; }; /** * Removes an existing geometry * @param {BABYLON.Geometry} geometry - the geometry to be removed from the scene. * @return {boolean} was the geometry removed or not */ Scene.prototype.removeGeometry = function (geometry) { var index = this._geometries.indexOf(geometry); if (index > -1) { this._geometries.splice(index, 1); //notify the collision coordinator this.collisionCoordinator.onGeometryDeleted(geometry); this.onGeometryRemovedObservable.notifyObservers(geometry); return true; } return false; }; Scene.prototype.getGeometries = function () { return this._geometries; }; /** * Get the first added mesh found of a given ID * @param {string} id - the id to search for * @return {BABYLON.AbstractMesh|null} the mesh found or null if not found at all. */ Scene.prototype.getMeshByID = function (id) { for (var index = 0; index < this.meshes.length; index++) { if (this.meshes[index].id === id) { return this.meshes[index]; } } return null; }; Scene.prototype.getMeshesByID = function (id) { return this.meshes.filter(function (m) { return m.id === id; }); }; /** * Get a mesh with its auto-generated unique id * @param {number} uniqueId - the unique id to search for * @return {BABYLON.AbstractMesh|null} the mesh found or null if not found at all. */ Scene.prototype.getMeshByUniqueID = function (uniqueId) { for (var index = 0; index < this.meshes.length; index++) { if (this.meshes[index].uniqueId === uniqueId) { return this.meshes[index]; } } return null; }; /** * Get a the last added mesh found of a given ID * @param {string} id - the id to search for * @return {BABYLON.AbstractMesh|null} the mesh found or null if not found at all. */ Scene.prototype.getLastMeshByID = function (id) { for (var index = this.meshes.length - 1; index >= 0; index--) { if (this.meshes[index].id === id) { return this.meshes[index]; } } return null; }; /** * Get a the last added node (Mesh, Camera, Light) found of a given ID * @param {string} id - the id to search for * @return {BABYLON.Node|null} the node found or null if not found at all. */ Scene.prototype.getLastEntryByID = function (id) { var index; for (index = this.meshes.length - 1; index >= 0; index--) { if (this.meshes[index].id === id) { return this.meshes[index]; } } for (index = this.cameras.length - 1; index >= 0; index--) { if (this.cameras[index].id === id) { return this.cameras[index]; } } for (index = this.lights.length - 1; index >= 0; index--) { if (this.lights[index].id === id) { return this.lights[index]; } } return null; }; Scene.prototype.getNodeByID = function (id) { var mesh = this.getMeshByID(id); if (mesh) { return mesh; } var light = this.getLightByID(id); if (light) { return light; } var camera = this.getCameraByID(id); if (camera) { return camera; } var bone = this.getBoneByID(id); return bone; }; Scene.prototype.getNodeByName = function (name) { var mesh = this.getMeshByName(name); if (mesh) { return mesh; } var light = this.getLightByName(name); if (light) { return light; } var camera = this.getCameraByName(name); if (camera) { return camera; } var bone = this.getBoneByName(name); return bone; }; Scene.prototype.getMeshByName = function (name) { for (var index = 0; index < this.meshes.length; index++) { if (this.meshes[index].name === name) { return this.meshes[index]; } } return null; }; Scene.prototype.getSoundByName = function (name) { var index; if (BABYLON.AudioEngine) { for (index = 0; index < this.mainSoundTrack.soundCollection.length; index++) { if (this.mainSoundTrack.soundCollection[index].name === name) { return this.mainSoundTrack.soundCollection[index]; } } for (var sdIndex = 0; sdIndex < this.soundTracks.length; sdIndex++) { for (index = 0; index < this.soundTracks[sdIndex].soundCollection.length; index++) { if (this.soundTracks[sdIndex].soundCollection[index].name === name) { return this.soundTracks[sdIndex].soundCollection[index]; } } } } return null; }; Scene.prototype.getLastSkeletonByID = function (id) { for (var index = this.skeletons.length - 1; index >= 0; index--) { if (this.skeletons[index].id === id) { return this.skeletons[index]; } } return null; }; Scene.prototype.getSkeletonById = function (id) { for (var index = 0; index < this.skeletons.length; index++) { if (this.skeletons[index].id === id) { return this.skeletons[index]; } } return null; }; Scene.prototype.getSkeletonByName = function (name) { for (var index = 0; index < this.skeletons.length; index++) { if (this.skeletons[index].name === name) { return this.skeletons[index]; } } return null; }; Scene.prototype.isActiveMesh = function (mesh) { return (this._activeMeshes.indexOf(mesh) !== -1); }; Object.defineProperty(Scene.prototype, "uid", { /** * Return a unique id as a string which can serve as an identifier for the scene */ get: function () { if (!this._uid) { this._uid = BABYLON.Tools.RandomId(); } return this._uid; }, enumerable: true, configurable: true }); /** * Add an externaly attached data from its key. * This method call will fail and return false, if such key already exists. * If you don't care and just want to get the data no matter what, use the more convenient getOrAddExternalDataWithFactory() method. * @param key the unique key that identifies the data * @param data the data object to associate to the key for this Engine instance * @return true if no such key were already present and the data was added successfully, false otherwise */ Scene.prototype.addExternalData = function (key, data) { return this._externalData.add(key, data); }; /** * Get an externaly attached data from its key * @param key the unique key that identifies the data * @return the associated data, if present (can be null), or undefined if not present */ Scene.prototype.getExternalData = function (key) { return this._externalData.get(key); }; /** * Get an externaly attached data from its key, create it using a factory if it's not already present * @param key the unique key that identifies the data * @param factory the factory that will be called to create the instance if and only if it doesn't exists * @return the associated data, can be null if the factory returned null. */ Scene.prototype.getOrAddExternalDataWithFactory = function (key, factory) { return this._externalData.getOrAddWithFactory(key, factory); }; /** * Remove an externaly attached data from the Engine instance * @param key the unique key that identifies the data * @return true if the data was successfully removed, false if it doesn't exist */ Scene.prototype.removeExternalData = function (key) { return this._externalData.remove(key); }; Scene.prototype._evaluateSubMesh = function (subMesh, mesh) { if (mesh.alwaysSelectAsActiveMesh || mesh.subMeshes.length === 1 || subMesh.isInFrustum(this._frustumPlanes)) { var material = subMesh.getMaterial(); if (mesh.showSubMeshesBoundingBox) { this._boundingBoxRenderer.renderList.push(subMesh.getBoundingInfo().boundingBox); } if (material) { // Render targets if (material.getRenderTargetTextures) { if (this._processedMaterials.indexOf(material) === -1) { this._processedMaterials.push(material); this._renderTargets.concatWithNoDuplicate(material.getRenderTargetTextures()); } } // Dispatch this._activeIndices.addCount(subMesh.indexCount, false); this._renderingManager.dispatch(subMesh); } } }; Scene.prototype._isInIntermediateRendering = function () { return this._intermediateRendering; }; Scene.prototype._evaluateActiveMeshes = function () { this.activeCamera._activeMeshes.reset(); this._activeMeshes.reset(); this._renderingManager.reset(); this._processedMaterials.reset(); this._activeParticleSystems.reset(); this._activeSkeletons.reset(); this._softwareSkinnedMeshes.reset(); this._boundingBoxRenderer.reset(); this._edgesRenderers.reset(); // Meshes var meshes; var len; if (this._selectionOctree) { var selection = this._selectionOctree.select(this._frustumPlanes); meshes = selection.data; len = selection.length; } else { len = this.meshes.length; meshes = this.meshes; } for (var meshIndex = 0; meshIndex < len; meshIndex++) { var mesh = meshes[meshIndex]; if (mesh.isBlocked) { continue; } this._totalVertices.addCount(mesh.getTotalVertices(), false); if (!mesh.isReady() || !mesh.isEnabled()) { continue; } mesh.computeWorldMatrix(); // Intersections if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers([BABYLON.ActionManager.OnIntersectionEnterTrigger, BABYLON.ActionManager.OnIntersectionExitTrigger])) { this._meshesForIntersections.pushNoDuplicate(mesh); } // Switch to current LOD var meshLOD = mesh.getLOD(this.activeCamera); if (!meshLOD) { continue; } mesh._preActivate(); if (mesh.alwaysSelectAsActiveMesh || mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && mesh.isInFrustum(this._frustumPlanes)) { this._activeMeshes.push(mesh); this.activeCamera._activeMeshes.push(mesh); mesh._activate(this._renderId); this._activeMesh(mesh, meshLOD); } } // Particle systems this._particlesDuration.beginMonitoring(); var beforeParticlesDate = BABYLON.Tools.Now; if (this.particlesEnabled) { BABYLON.Tools.StartPerformanceCounter("Particles", this.particleSystems.length > 0); for (var particleIndex = 0; particleIndex < this.particleSystems.length; particleIndex++) { var particleSystem = this.particleSystems[particleIndex]; if (!particleSystem.isStarted()) { continue; } if (!particleSystem.emitter.position || (particleSystem.emitter && particleSystem.emitter.isEnabled())) { this._activeParticleSystems.push(particleSystem); particleSystem.animate(); } } BABYLON.Tools.EndPerformanceCounter("Particles", this.particleSystems.length > 0); } this._particlesDuration.endMonitoring(false); }; Scene.prototype._activeMesh = function (sourceMesh, mesh) { if (mesh.skeleton && this.skeletonsEnabled) { if (this._activeSkeletons.pushNoDuplicate(mesh.skeleton)) { mesh.skeleton.prepare(); } if (!mesh.computeBonesUsingShaders) { this._softwareSkinnedMeshes.pushNoDuplicate(mesh); } } if (sourceMesh.showBoundingBox || this.forceShowBoundingBoxes) { this._boundingBoxRenderer.renderList.push(sourceMesh.getBoundingInfo().boundingBox); } if (sourceMesh._edgesRenderer) { this._edgesRenderers.push(sourceMesh._edgesRenderer); } if (mesh && mesh.subMeshes) { // Submeshes Octrees var len; var subMeshes; if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) { var intersections = mesh._submeshesOctree.select(this._frustumPlanes); len = intersections.length; subMeshes = intersections.data; } else { subMeshes = mesh.subMeshes; len = subMeshes.length; } for (var subIndex = 0; subIndex < len; subIndex++) { var subMesh = subMeshes[subIndex]; this._evaluateSubMesh(subMesh, mesh); } } }; Scene.prototype.updateTransformMatrix = function (force) { this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix(force)); }; Scene.prototype._renderForCamera = function (camera) { var engine = this._engine; var startTime = BABYLON.Tools.Now; this.activeCamera = camera; if (!this.activeCamera) throw new Error("Active camera not set"); BABYLON.Tools.StartPerformanceCounter("Rendering camera " + this.activeCamera.name); // Viewport engine.setViewport(this.activeCamera.viewport); // Camera this.resetCachedMaterial(); this._renderId++; this.updateTransformMatrix(); this.onBeforeCameraRenderObservable.notifyObservers(this.activeCamera); // Meshes this._evaluateActiveMeshesDuration.beginMonitoring(); BABYLON.Tools.StartPerformanceCounter("Active meshes evaluation"); this._evaluateActiveMeshes(); this._evaluateActiveMeshesDuration.endMonitoring(false); BABYLON.Tools.EndPerformanceCounter("Active meshes evaluation"); // Software skinning for (var softwareSkinnedMeshIndex = 0; softwareSkinnedMeshIndex < this._softwareSkinnedMeshes.length; softwareSkinnedMeshIndex++) { var mesh = this._softwareSkinnedMeshes.data[softwareSkinnedMeshIndex]; mesh.applySkeleton(mesh.skeleton); } // Render targets this._renderTargetsDuration.beginMonitoring(); var needsRestoreFrameBuffer = false; var beforeRenderTargetDate = BABYLON.Tools.Now; if (this.renderTargetsEnabled && this._renderTargets.length > 0) { this._intermediateRendering = true; BABYLON.Tools.StartPerformanceCounter("Render targets", this._renderTargets.length > 0); for (var renderIndex = 0; renderIndex < this._renderTargets.length; renderIndex++) { var renderTarget = this._renderTargets.data[renderIndex]; if (renderTarget._shouldRender()) { this._renderId++; var hasSpecialRenderTargetCamera = renderTarget.activeCamera && renderTarget.activeCamera !== this.activeCamera; renderTarget.render(hasSpecialRenderTargetCamera, this.dumpNextRenderTargets); } } BABYLON.Tools.EndPerformanceCounter("Render targets", this._renderTargets.length > 0); this._intermediateRendering = false; this._renderId++; needsRestoreFrameBuffer = true; // Restore back buffer } // Render HighlightLayer Texture var stencilState = this._engine.getStencilBuffer(); var renderhighlights = false; if (this.renderTargetsEnabled && this.highlightLayers && this.highlightLayers.length > 0) { this._intermediateRendering = true; for (var i = 0; i < this.highlightLayers.length; i++) { var highlightLayer = this.highlightLayers[i]; if (highlightLayer.shouldRender() && (!highlightLayer.camera || (highlightLayer.camera.cameraRigMode === BABYLON.Camera.RIG_MODE_NONE && camera === highlightLayer.camera) || (highlightLayer.camera.cameraRigMode !== BABYLON.Camera.RIG_MODE_NONE && highlightLayer.camera._rigCameras.indexOf(camera) > -1))) { renderhighlights = true; var renderTarget = highlightLayer._mainTexture; if (renderTarget._shouldRender()) { this._renderId++; renderTarget.render(false, false); needsRestoreFrameBuffer = true; } } } this._intermediateRendering = false; this._renderId++; } if (needsRestoreFrameBuffer) { engine.restoreDefaultFramebuffer(); } this._renderTargetsDuration.endMonitoring(false); // Prepare Frame this.postProcessManager._prepareFrame(); this._renderDuration.beginMonitoring(); // Backgrounds var layerIndex; var layer; if (this.layers.length) { engine.setDepthBuffer(false); for (layerIndex = 0; layerIndex < this.layers.length; layerIndex++) { layer = this.layers[layerIndex]; if (layer.isBackground) { layer.render(); } } engine.setDepthBuffer(true); } // Render BABYLON.Tools.StartPerformanceCounter("Main render"); // Activate HighlightLayer stencil if (renderhighlights) { this._engine.setStencilBuffer(true); } this._renderingManager.render(null, null, true, true); // Restore HighlightLayer stencil if (renderhighlights) { this._engine.setStencilBuffer(stencilState); } BABYLON.Tools.EndPerformanceCounter("Main render"); // Bounding boxes this._boundingBoxRenderer.render(); // Edges for (var edgesRendererIndex = 0; edgesRendererIndex < this._edgesRenderers.length; edgesRendererIndex++) { this._edgesRenderers.data[edgesRendererIndex].render(); } // Lens flares if (this.lensFlaresEnabled) { BABYLON.Tools.StartPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0); for (var lensFlareSystemIndex = 0; lensFlareSystemIndex < this.lensFlareSystems.length; lensFlareSystemIndex++) { var lensFlareSystem = this.lensFlareSystems[lensFlareSystemIndex]; if ((camera.layerMask & lensFlareSystem.layerMask) !== 0) { lensFlareSystem.render(); } } BABYLON.Tools.EndPerformanceCounter("Lens flares", this.lensFlareSystems.length > 0); } // Foregrounds if (this.layers.length) { engine.setDepthBuffer(false); for (layerIndex = 0; layerIndex < this.layers.length; layerIndex++) { layer = this.layers[layerIndex]; if (!layer.isBackground) { layer.render(); } } engine.setDepthBuffer(true); } // Highlight Layer if (renderhighlights) { engine.setDepthBuffer(false); for (var i = 0; i < this.highlightLayers.length; i++) { if (this.highlightLayers[i].shouldRender()) { this.highlightLayers[i].render(); } } engine.setDepthBuffer(true); } this._renderDuration.endMonitoring(false); // Finalize frame this.postProcessManager._finalizeFrame(camera.isIntermediate); // Update camera this.activeCamera._updateFromScene(); // Reset some special arrays this._renderTargets.reset(); this.onAfterCameraRenderObservable.notifyObservers(this.activeCamera); BABYLON.Tools.EndPerformanceCounter("Rendering camera " + this.activeCamera.name); }; Scene.prototype._processSubCameras = function (camera) { if (camera.cameraRigMode === BABYLON.Camera.RIG_MODE_NONE) { this._renderForCamera(camera); return; } // rig cameras for (var index = 0; index < camera._rigCameras.length; index++) { this._renderForCamera(camera._rigCameras[index]); } this.activeCamera = camera; this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix()); // Update camera this.activeCamera._updateFromScene(); }; Scene.prototype._checkIntersections = function () { for (var index = 0; index < this._meshesForIntersections.length; index++) { var sourceMesh = this._meshesForIntersections.data[index]; for (var actionIndex = 0; actionIndex < sourceMesh.actionManager.actions.length; actionIndex++) { var action = sourceMesh.actionManager.actions[actionIndex]; if (action.trigger === BABYLON.ActionManager.OnIntersectionEnterTrigger || action.trigger === BABYLON.ActionManager.OnIntersectionExitTrigger) { var parameters = action.getTriggerParameter(); var otherMesh = parameters instanceof BABYLON.AbstractMesh ? parameters : parameters.mesh; var areIntersecting = otherMesh.intersectsMesh(sourceMesh, parameters.usePreciseIntersection); var currentIntersectionInProgress = sourceMesh._intersectionsInProgress.indexOf(otherMesh); if (areIntersecting && currentIntersectionInProgress === -1) { if (action.trigger === BABYLON.ActionManager.OnIntersectionEnterTrigger) { action._executeCurrent(BABYLON.ActionEvent.CreateNew(sourceMesh, null, otherMesh)); sourceMesh._intersectionsInProgress.push(otherMesh); } else if (action.trigger === BABYLON.ActionManager.OnIntersectionExitTrigger) { sourceMesh._intersectionsInProgress.push(otherMesh); } } else if (!areIntersecting && currentIntersectionInProgress > -1) { //They intersected, and now they don't. //is this trigger an exit trigger? execute an event. if (action.trigger === BABYLON.ActionManager.OnIntersectionExitTrigger) { action._executeCurrent(BABYLON.ActionEvent.CreateNew(sourceMesh, null, otherMesh)); } //if this is an exit trigger, or no exit trigger exists, remove the id from the intersection in progress array. if (!sourceMesh.actionManager.hasSpecificTrigger(BABYLON.ActionManager.OnIntersectionExitTrigger) || action.trigger === BABYLON.ActionManager.OnIntersectionExitTrigger) { sourceMesh._intersectionsInProgress.splice(currentIntersectionInProgress, 1); } } } } } }; Scene.prototype.render = function () { this._lastFrameDuration.beginMonitoring(); this._particlesDuration.fetchNewFrame(); this._spritesDuration.fetchNewFrame(); this._activeParticles.fetchNewFrame(); this._renderDuration.fetchNewFrame(); this._renderTargetsDuration.fetchNewFrame(); this._evaluateActiveMeshesDuration.fetchNewFrame(); this._totalVertices.fetchNewFrame(); this._activeIndices.fetchNewFrame(); this._activeBones.fetchNewFrame(); this.getEngine().drawCallsPerfCounter.fetchNewFrame(); this._meshesForIntersections.reset(); this.resetCachedMaterial(); BABYLON.Tools.StartPerformanceCounter("Scene rendering"); // Actions if (this.actionManager) { this.actionManager.processTrigger(BABYLON.ActionManager.OnEveryFrameTrigger, null); } //Simplification Queue if (this.simplificationQueue && !this.simplificationQueue.running) { this.simplificationQueue.executeNext(); } // Animations var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime)); this._animationRatio = deltaTime * (60.0 / 1000.0); this._animate(); // Physics if (this._physicsEngine) { BABYLON.Tools.StartPerformanceCounter("Physics"); this._physicsEngine._step(deltaTime / 1000.0); BABYLON.Tools.EndPerformanceCounter("Physics"); } // Before render this.onBeforeRenderObservable.notifyObservers(this); // Customs render targets this._renderTargetsDuration.beginMonitoring(); var beforeRenderTargetDate = BABYLON.Tools.Now; var engine = this.getEngine(); var currentActiveCamera = this.activeCamera; if (this.renderTargetsEnabled) { BABYLON.Tools.StartPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0); for (var customIndex = 0; customIndex < this.customRenderTargets.length; customIndex++) { var renderTarget = this.customRenderTargets[customIndex]; if (renderTarget._shouldRender()) { this._renderId++; this.activeCamera = renderTarget.activeCamera || this.activeCamera; if (!this.activeCamera) throw new Error("Active camera not set"); // Viewport engine.setViewport(this.activeCamera.viewport); // Camera this.updateTransformMatrix(); renderTarget.render(currentActiveCamera !== this.activeCamera, this.dumpNextRenderTargets); } } BABYLON.Tools.EndPerformanceCounter("Custom render targets", this.customRenderTargets.length > 0); this._renderId++; } if (this.customRenderTargets.length > 0) { engine.restoreDefaultFramebuffer(); } this._renderTargetsDuration.endMonitoring(); this.activeCamera = currentActiveCamera; // Procedural textures if (this.proceduralTexturesEnabled) { BABYLON.Tools.StartPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0); for (var proceduralIndex = 0; proceduralIndex < this._proceduralTextures.length; proceduralIndex++) { var proceduralTexture = this._proceduralTextures[proceduralIndex]; if (proceduralTexture._shouldRender()) { proceduralTexture.render(); } } BABYLON.Tools.EndPerformanceCounter("Procedural textures", this._proceduralTextures.length > 0); } // Clear this._engine.clear(this.clearColor, this.autoClear || this.forceWireframe || this.forcePointsCloud, true, true); // Shadows if (this.shadowsEnabled) { for (var lightIndex = 0; lightIndex < this.lights.length; lightIndex++) { var light = this.lights[lightIndex]; var shadowGenerator = light.getShadowGenerator(); if (light.isEnabled() && shadowGenerator && shadowGenerator.getShadowMap().getScene().textures.indexOf(shadowGenerator.getShadowMap()) !== -1) { this._renderTargets.push(shadowGenerator.getShadowMap()); } } } // Depth renderer if (this._depthRenderer) { this._renderTargets.push(this._depthRenderer.getDepthMap()); } // RenderPipeline this.postProcessRenderPipelineManager.update(); // Multi-cameras? if (this.activeCameras.length > 0) { for (var cameraIndex = 0; cameraIndex < this.activeCameras.length; cameraIndex++) { if (cameraIndex > 0) { this._engine.clear(0, false, true, true); } this._processSubCameras(this.activeCameras[cameraIndex]); } } else { if (!this.activeCamera) { throw new Error("No camera defined"); } this._processSubCameras(this.activeCamera); } // Intersection checks this._checkIntersections(); // Update the audio listener attached to the camera if (BABYLON.AudioEngine) { this._updateAudioParameters(); } // After render if (this.afterRender) { this.afterRender(); } this.onAfterRenderObservable.notifyObservers(this); // Cleaning for (var index = 0; index < this._toBeDisposed.length; index++) { this._toBeDisposed.data[index].dispose(); this._toBeDisposed[index] = null; } this._toBeDisposed.reset(); if (this.dumpNextRenderTargets) { this.dumpNextRenderTargets = false; } BABYLON.Tools.EndPerformanceCounter("Scene rendering"); this._lastFrameDuration.endMonitoring(); this._totalMeshesCounter.addCount(this.meshes.length, true); this._totalLightsCounter.addCount(this.lights.length, true); this._totalMaterialsCounter.addCount(this.materials.length, true); this._totalTexturesCounter.addCount(this.textures.length, true); this._activeBones.addCount(0, true); this._activeIndices.addCount(0, true); this._activeParticles.addCount(0, true); }; Scene.prototype._updateAudioParameters = function () { if (!this.audioEnabled || (this.mainSoundTrack.soundCollection.length === 0 && this.soundTracks.length === 1)) { return; } var listeningCamera; var audioEngine = BABYLON.Engine.audioEngine; if (this.activeCameras.length > 0) { listeningCamera = this.activeCameras[0]; } else { listeningCamera = this.activeCamera; } if (listeningCamera && audioEngine.canUseWebAudio) { audioEngine.audioContext.listener.setPosition(listeningCamera.position.x, listeningCamera.position.y, listeningCamera.position.z); var mat = BABYLON.Matrix.Invert(listeningCamera.getViewMatrix()); var cameraDirection = BABYLON.Vector3.TransformNormal(new BABYLON.Vector3(0, 0, -1), mat); cameraDirection.normalize(); audioEngine.audioContext.listener.setOrientation(cameraDirection.x, cameraDirection.y, cameraDirection.z, 0, 1, 0); var i; for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) { var sound = this.mainSoundTrack.soundCollection[i]; if (sound.useCustomAttenuation) { sound.updateDistanceFromListener(); } } for (i = 0; i < this.soundTracks.length; i++) { for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) { sound = this.soundTracks[i].soundCollection[j]; if (sound.useCustomAttenuation) { sound.updateDistanceFromListener(); } } } } }; Object.defineProperty(Scene.prototype, "audioEnabled", { // Audio get: function () { return this._audioEnabled; }, set: function (value) { this._audioEnabled = value; if (BABYLON.AudioEngine) { if (this._audioEnabled) { this._enableAudio(); } else { this._disableAudio(); } } }, enumerable: true, configurable: true }); Scene.prototype._disableAudio = function () { var i; for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) { this.mainSoundTrack.soundCollection[i].pause(); } for (i = 0; i < this.soundTracks.length; i++) { for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) { this.soundTracks[i].soundCollection[j].pause(); } } }; Scene.prototype._enableAudio = function () { var i; for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) { if (this.mainSoundTrack.soundCollection[i].isPaused) { this.mainSoundTrack.soundCollection[i].play(); } } for (i = 0; i < this.soundTracks.length; i++) { for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) { if (this.soundTracks[i].soundCollection[j].isPaused) { this.soundTracks[i].soundCollection[j].play(); } } } }; Object.defineProperty(Scene.prototype, "headphone", { get: function () { return this._headphone; }, set: function (value) { this._headphone = value; if (BABYLON.AudioEngine) { if (this._headphone) { this._switchAudioModeForHeadphones(); } else { this._switchAudioModeForNormalSpeakers(); } } }, enumerable: true, configurable: true }); Scene.prototype._switchAudioModeForHeadphones = function () { this.mainSoundTrack.switchPanningModelToHRTF(); for (var i = 0; i < this.soundTracks.length; i++) { this.soundTracks[i].switchPanningModelToHRTF(); } }; Scene.prototype._switchAudioModeForNormalSpeakers = function () { this.mainSoundTrack.switchPanningModelToEqualPower(); for (var i = 0; i < this.soundTracks.length; i++) { this.soundTracks[i].switchPanningModelToEqualPower(); } }; Scene.prototype.enableDepthRenderer = function () { if (this._depthRenderer) { return this._depthRenderer; } this._depthRenderer = new BABYLON.DepthRenderer(this); return this._depthRenderer; }; Scene.prototype.disableDepthRenderer = function () { if (!this._depthRenderer) { return; } this._depthRenderer.dispose(); this._depthRenderer = null; }; Scene.prototype.freezeMaterials = function () { for (var i = 0; i < this.materials.length; i++) { this.materials[i].freeze(); } }; Scene.prototype.unfreezeMaterials = function () { for (var i = 0; i < this.materials.length; i++) { this.materials[i].unfreeze(); } }; Scene.prototype.dispose = function () { this.beforeRender = null; this.afterRender = null; this.skeletons = []; this._boundingBoxRenderer.dispose(); if (this._depthRenderer) { this._depthRenderer.dispose(); } // Debug layer if (this._debugLayer) { this._debugLayer.hide(); } // Events this.onDisposeObservable.notifyObservers(this); this.onDisposeObservable.clear(); this.onBeforeRenderObservable.clear(); this.onAfterRenderObservable.clear(); this.detachControl(); // Release sounds & sounds tracks if (BABYLON.AudioEngine) { this.disposeSounds(); } // Detach cameras var canvas = this._engine.getRenderingCanvas(); var index; for (index = 0; index < this.cameras.length; index++) { this.cameras[index].detachControl(canvas); } // Release lights while (this.lights.length) { this.lights[0].dispose(); } // Release meshes while (this.meshes.length) { this.meshes[0].dispose(true); } // Release cameras while (this.cameras.length) { this.cameras[0].dispose(); } // Release materials while (this.materials.length) { this.materials[0].dispose(); } // Release particles while (this.particleSystems.length) { this.particleSystems[0].dispose(); } // Release sprites while (this.spriteManagers.length) { this.spriteManagers[0].dispose(); } // Release layers while (this.layers.length) { this.layers[0].dispose(); } while (this.highlightLayers.length) { this.highlightLayers[0].dispose(); } // Release textures while (this.textures.length) { this.textures[0].dispose(); } // Post-processes this.postProcessManager.dispose(); // Physics if (this._physicsEngine) { this.disablePhysicsEngine(); } // Remove from engine index = this._engine.scenes.indexOf(this); if (index > -1) { this._engine.scenes.splice(index, 1); } this._engine.wipeCaches(); }; // Release sounds & sounds tracks Scene.prototype.disposeSounds = function () { this.mainSoundTrack.dispose(); for (var scIndex = 0; scIndex < this.soundTracks.length; scIndex++) { this.soundTracks[scIndex].dispose(); } }; // Octrees Scene.prototype.getWorldExtends = function () { var min = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); var max = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); for (var index = 0; index < this.meshes.length; index++) { var mesh = this.meshes[index]; mesh.computeWorldMatrix(true); var minBox = mesh.getBoundingInfo().boundingBox.minimumWorld; var maxBox = mesh.getBoundingInfo().boundingBox.maximumWorld; BABYLON.Tools.CheckExtends(minBox, min, max); BABYLON.Tools.CheckExtends(maxBox, min, max); } return { min: min, max: max }; }; Scene.prototype.createOrUpdateSelectionOctree = function (maxCapacity, maxDepth) { if (maxCapacity === void 0) { maxCapacity = 64; } if (maxDepth === void 0) { maxDepth = 2; } if (!this._selectionOctree) { this._selectionOctree = new BABYLON.Octree(BABYLON.Octree.CreationFuncForMeshes, maxCapacity, maxDepth); } var worldExtends = this.getWorldExtends(); // Update octree this._selectionOctree.update(worldExtends.min, worldExtends.max, this.meshes); return this._selectionOctree; }; // Picking Scene.prototype.createPickingRay = function (x, y, world, camera, cameraViewSpace) { if (cameraViewSpace === void 0) { cameraViewSpace = false; } var engine = this._engine; if (!camera) { if (!this.activeCamera) throw new Error("Active camera not set"); camera = this.activeCamera; } var cameraViewport = camera.viewport; var viewport = cameraViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight()); // Moving coordinates to local viewport world x = x / this._engine.getHardwareScalingLevel() - viewport.x; y = y / this._engine.getHardwareScalingLevel() - (this._engine.getRenderHeight() - viewport.y - viewport.height); return BABYLON.Ray.CreateNew(x, y, viewport.width, viewport.height, world ? world : BABYLON.Matrix.Identity(), cameraViewSpace ? BABYLON.Matrix.Identity() : camera.getViewMatrix(), camera.getProjectionMatrix()); // return BABYLON.Ray.CreateNew(x / window.devicePixelRatio, y / window.devicePixelRatio, viewport.width, viewport.height, world ? world : BABYLON.Matrix.Identity(), camera.getViewMatrix(), camera.getProjectionMatrix()); }; Scene.prototype.createPickingRayInCameraSpace = function (x, y, camera) { var engine = this._engine; if (!camera) { if (!this.activeCamera) throw new Error("Active camera not set"); camera = this.activeCamera; } var cameraViewport = camera.viewport; var viewport = cameraViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight()); var identity = BABYLON.Matrix.Identity(); // Moving coordinates to local viewport world x = x / this._engine.getHardwareScalingLevel() - viewport.x; y = y / this._engine.getHardwareScalingLevel() - (this._engine.getRenderHeight() - viewport.y - viewport.height); return BABYLON.Ray.CreateNew(x, y, viewport.width, viewport.height, identity, identity, camera.getProjectionMatrix()); }; Scene.prototype._internalPick = function (rayFunction, predicate, fastCheck) { var pickingInfo = null; for (var meshIndex = 0; meshIndex < this.meshes.length; meshIndex++) { var mesh = this.meshes[meshIndex]; if (predicate) { if (!predicate(mesh)) { continue; } } else if (!mesh.isEnabled() || !mesh.isVisible || !mesh.isPickable) { continue; } var world = mesh.getWorldMatrix(); var ray = rayFunction(world); var result = mesh.intersects(ray, fastCheck); if (!result || !result.hit) continue; if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance) continue; pickingInfo = result; if (fastCheck) { break; } } return pickingInfo || new BABYLON.PickingInfo(); }; Scene.prototype._internalMultiPick = function (rayFunction, predicate) { var pickingInfos = new Array(); for (var meshIndex = 0; meshIndex < this.meshes.length; meshIndex++) { var mesh = this.meshes[meshIndex]; if (predicate) { if (!predicate(mesh)) { continue; } } else if (!mesh.isEnabled() || !mesh.isVisible || !mesh.isPickable) { continue; } var world = mesh.getWorldMatrix(); var ray = rayFunction(world); var result = mesh.intersects(ray, false); if (!result || !result.hit) continue; pickingInfos.push(result); } return pickingInfos; }; Scene.prototype._internalPickSprites = function (ray, predicate, fastCheck, camera) { var pickingInfo = null; camera = camera || this.activeCamera; if (this.spriteManagers.length > 0) { for (var spriteIndex = 0; spriteIndex < this.spriteManagers.length; spriteIndex++) { var spriteManager = this.spriteManagers[spriteIndex]; if (!spriteManager.isPickable) { continue; } var result = spriteManager.intersects(ray, camera, predicate, fastCheck); if (!result || !result.hit) continue; if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance) continue; pickingInfo = result; if (fastCheck) { break; } } } return pickingInfo || new BABYLON.PickingInfo(); }; /// Launch a ray to try to pick a mesh in the scene /// X position on screen /// Y position on screen /// Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true /// Launch a fast check only using the bounding boxes. Can be set to null. /// camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used Scene.prototype.pick = function (x, y, predicate, fastCheck, camera) { var _this = this; return this._internalPick(function (world) { return _this.createPickingRay(x, y, world, camera); }, predicate, fastCheck); }; /// Launch a ray to try to pick a mesh in the scene /// X position on screen /// Y position on screen /// Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true /// Launch a fast check only using the bounding boxes. Can be set to null. /// camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used Scene.prototype.pickSprite = function (x, y, predicate, fastCheck, camera) { return this._internalPickSprites(this.createPickingRayInCameraSpace(x, y, camera), predicate, fastCheck, camera); }; Scene.prototype.pickWithRay = function (ray, predicate, fastCheck) { var _this = this; return this._internalPick(function (world) { if (!_this._pickWithRayInverseMatrix) { _this._pickWithRayInverseMatrix = BABYLON.Matrix.Identity(); } world.invertToRef(_this._pickWithRayInverseMatrix); return BABYLON.Ray.Transform(ray, _this._pickWithRayInverseMatrix); }, predicate, fastCheck); }; /// Launch a ray to try to pick a mesh in the scene /// X position on screen /// Y position on screen /// Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true /// camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used Scene.prototype.multiPick = function (x, y, predicate, camera) { var _this = this; return this._internalMultiPick(function (world) { return _this.createPickingRay(x, y, world, camera); }, predicate); }; /// Launch a ray to try to pick a mesh in the scene /// Ray to use /// Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true Scene.prototype.multiPickWithRay = function (ray, predicate) { var _this = this; return this._internalMultiPick(function (world) { if (!_this._pickWithRayInverseMatrix) { _this._pickWithRayInverseMatrix = BABYLON.Matrix.Identity(); } world.invertToRef(_this._pickWithRayInverseMatrix); return BABYLON.Ray.Transform(ray, _this._pickWithRayInverseMatrix); }, predicate); }; Scene.prototype.setPointerOverMesh = function (mesh) { if (this._pointerOverMesh === mesh) { return; } if (this._pointerOverMesh && this._pointerOverMesh.actionManager) { this._pointerOverMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOutTrigger, BABYLON.ActionEvent.CreateNew(this._pointerOverMesh)); } this._pointerOverMesh = mesh; if (this._pointerOverMesh && this._pointerOverMesh.actionManager) { this._pointerOverMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOverTrigger, BABYLON.ActionEvent.CreateNew(this._pointerOverMesh)); } }; Scene.prototype.getPointerOverMesh = function () { return this._pointerOverMesh; }; Scene.prototype.setPointerOverSprite = function (sprite) { if (this._pointerOverSprite === sprite) { return; } if (this._pointerOverSprite && this._pointerOverSprite.actionManager) { this._pointerOverSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOutTrigger, BABYLON.ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this)); } this._pointerOverSprite = sprite; if (this._pointerOverSprite && this._pointerOverSprite.actionManager) { this._pointerOverSprite.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOverTrigger, BABYLON.ActionEvent.CreateNewFromSprite(this._pointerOverSprite, this)); } }; Scene.prototype.getPointerOverSprite = function () { return this._pointerOverSprite; }; // Physics Scene.prototype.getPhysicsEngine = function () { return this._physicsEngine; }; /** * Enables physics to the current scene * @param {BABYLON.Vector3} [gravity] - the scene's gravity for the physics engine * @param {BABYLON.IPhysicsEnginePlugin} [plugin] - The physics engine to be used. defaults to OimoJS. * @return {boolean} was the physics engine initialized */ Scene.prototype.enablePhysics = function (gravity, plugin) { if (this._physicsEngine) { return true; } try { this._physicsEngine = new BABYLON.PhysicsEngine(gravity, plugin); return true; } catch (e) { BABYLON.Tools.Error(e.message); return false; } }; Scene.prototype.disablePhysicsEngine = function () { if (!this._physicsEngine) { return; } this._physicsEngine.dispose(); this._physicsEngine = undefined; }; Scene.prototype.isPhysicsEnabled = function () { return this._physicsEngine !== undefined; }; /** * * Sets the gravity of the physics engine (and NOT of the scene) * @param {BABYLON.Vector3} [gravity] - the new gravity to be used */ Scene.prototype.setGravity = function (gravity) { BABYLON.Tools.Warn("Deprecated, please use 'scene.getPhysicsEngine().setGravity()'"); if (!this._physicsEngine) { return; } this._physicsEngine.setGravity(gravity); }; /** * Legacy support, using the new API * @Deprecated */ Scene.prototype.createCompoundImpostor = function (parts, options) { BABYLON.Tools.Warn("Scene.createCompoundImpostor is deprecated. Please use PhysicsImpostor parent/child"); if (parts.parts) { options = parts; parts = parts.parts; } var mainMesh = parts[0].mesh; mainMesh.physicsImpostor = new BABYLON.PhysicsImpostor(mainMesh, parts[0].impostor, options, this); for (var index = 1; index < parts.length; index++) { var mesh = parts[index].mesh; if (mesh.parent !== mainMesh) { mesh.position = mesh.position.subtract(mainMesh.position); mesh.parent = mainMesh; } mesh.physicsImpostor = new BABYLON.PhysicsImpostor(mesh, parts[index].impostor, options, this); } mainMesh.physicsImpostor.forceUpdate(); }; Scene.prototype.deleteCompoundImpostor = function (compound) { var mesh = compound.parts[0].mesh; mesh.physicsImpostor.dispose(); mesh.physicsImpostor = null; }; // Misc. Scene.prototype.createDefaultCameraOrLight = function () { // Light if (this.lights.length === 0) { new BABYLON.HemisphericLight("default light", BABYLON.Vector3.Up(), this); } // Camera if (!this.activeCamera) { var camera = new BABYLON.FreeCamera("default camera", BABYLON.Vector3.Zero(), this); // Compute position var worldExtends = this.getWorldExtends(); var worldCenter = worldExtends.min.add(worldExtends.max.subtract(worldExtends.min).scale(0.5)); camera.position = new BABYLON.Vector3(worldCenter.x, worldCenter.y, worldExtends.min.z - (worldExtends.max.z - worldExtends.min.z)); camera.setTarget(worldCenter); this.activeCamera = camera; } }; // Tags Scene.prototype._getByTags = function (list, tagsQuery, forEach) { if (tagsQuery === undefined) { // returns the complete list (could be done with BABYLON.Tags.MatchesQuery but no need to have a for-loop here) return list; } var listByTags = []; forEach = forEach || (function (item) { return; }); for (var i in list) { var item = list[i]; if (BABYLON.Tags.MatchesQuery(item, tagsQuery)) { listByTags.push(item); forEach(item); } } return listByTags; }; Scene.prototype.getMeshesByTags = function (tagsQuery, forEach) { return this._getByTags(this.meshes, tagsQuery, forEach); }; Scene.prototype.getCamerasByTags = function (tagsQuery, forEach) { return this._getByTags(this.cameras, tagsQuery, forEach); }; Scene.prototype.getLightsByTags = function (tagsQuery, forEach) { return this._getByTags(this.lights, tagsQuery, forEach); }; Scene.prototype.getMaterialByTags = function (tagsQuery, forEach) { return this._getByTags(this.materials, tagsQuery, forEach).concat(this._getByTags(this.multiMaterials, tagsQuery, forEach)); }; /** * Overrides the default sort function applied in the renderging group to prepare the meshes. * This allowed control for front to back rendering or reversly depending of the special needs. * * @param renderingGroupId The rendering group id corresponding to its index * @param opaqueSortCompareFn The opaque queue comparison function use to sort. * @param alphaTestSortCompareFn The alpha test queue comparison function use to sort. * @param transparentSortCompareFn The transparent queue comparison function use to sort. */ Scene.prototype.setRenderingOrder = function (renderingGroupId, opaqueSortCompareFn, alphaTestSortCompareFn, transparentSortCompareFn) { if (opaqueSortCompareFn === void 0) { opaqueSortCompareFn = null; } if (alphaTestSortCompareFn === void 0) { alphaTestSortCompareFn = null; } if (transparentSortCompareFn === void 0) { transparentSortCompareFn = null; } this._renderingManager.setRenderingOrder(renderingGroupId, opaqueSortCompareFn, alphaTestSortCompareFn, transparentSortCompareFn); }; /** * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups. * * @param renderingGroupId The rendering group id corresponding to its index * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true. */ Scene.prototype.setRenderingAutoClearDepthStencil = function (renderingGroupId, autoClearDepthStencil) { this._renderingManager.setRenderingAutoClearDepthStencil(renderingGroupId, autoClearDepthStencil); }; // Statics Scene._FOGMODE_NONE = 0; Scene._FOGMODE_EXP = 1; Scene._FOGMODE_EXP2 = 2; Scene._FOGMODE_LINEAR = 3; Scene.MinDeltaTime = 1.0; Scene.MaxDeltaTime = 1000.0; return Scene; }()); BABYLON.Scene = Scene; })(BABYLON || (BABYLON = {}));