scene.onPointerDown = function() { camera.attachControl(canvas); }* * @param element html element to attach the vrDevice to * @param noPreventDefault prevent the default html element operation when attaching the vrDevice */ WebVRFreeCamera.prototype.attachControl = function (element, noPreventDefault) { _super.prototype.attachControl.call(this, element, noPreventDefault); this._attached = true; noPreventDefault = BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault; if (this._vrDevice) { this.getEngine().enableVR(); } }; /** * Detaches the camera from the html element and disables VR * * @param element html element to detach from */ WebVRFreeCamera.prototype.detachControl = function (element) { this.getScene().gamepadManager.onGamepadConnectedObservable.remove(this._onGamepadConnectedObserver); this.getScene().gamepadManager.onGamepadDisconnectedObservable.remove(this._onGamepadDisconnectedObserver); _super.prototype.detachControl.call(this, element); this._attached = false; this.getEngine().disableVR(); }; /** * @returns the name of this class */ WebVRFreeCamera.prototype.getClassName = function () { return "WebVRFreeCamera"; }; /** * Calls resetPose on the vrDisplay * See: https://developer.mozilla.org/en-US/docs/Web/API/VRDisplay/resetPose */ WebVRFreeCamera.prototype.resetToCurrentRotation = function () { //uses the vrDisplay's "resetPose()". //pitch and roll won't be affected. this._vrDevice.resetPose(); }; /** * Updates the rig cameras (left and right eye) */ WebVRFreeCamera.prototype._updateRigCameras = function () { var camLeft = this._rigCameras[0]; var camRight = this._rigCameras[1]; camLeft.rotationQuaternion.copyFrom(this._deviceRoomRotationQuaternion); camRight.rotationQuaternion.copyFrom(this._deviceRoomRotationQuaternion); camLeft.position.copyFrom(this._deviceRoomPosition); camRight.position.copyFrom(this._deviceRoomPosition); }; /** * Updates the cached values of the camera * @param ignoreParentClass ignores updating the parent class's cache (default: false) */ WebVRFreeCamera.prototype._updateCache = function (ignoreParentClass) { var _this = this; if (!this.rotationQuaternion.equals(this._cache.rotationQuaternion) || !this.position.equals(this._cache.position)) { // Update to ensure devicePosition is up to date with most recent _deviceRoomPosition if (!this.updateCacheCalled) { // make sure it is only called once per loop. this.update() might cause an infinite loop. this.updateCacheCalled = true; this.update(); } // Set working vector to the device position in room space rotated by the new rotation this.rotationQuaternion.toRotationMatrix(this._workingMatrix); BABYLON.Vector3.TransformCoordinatesToRef(this._deviceRoomPosition, this._workingMatrix, this._workingVector); // Subtract this vector from the current device position in world to get the translation for the device world matrix this.devicePosition.subtractToRef(this._workingVector, this._workingVector); BABYLON.Matrix.ComposeToRef(this._oneVector, this.rotationQuaternion, this._workingVector, this._deviceToWorld); // Add translation from anchor position this._deviceToWorld.getTranslationToRef(this._workingVector); this._workingVector.addInPlace(this.position); this._workingVector.subtractInPlace(this._cache.position); this._deviceToWorld.setTranslation(this._workingVector); // Set an inverted matrix to be used when updating the camera this._deviceToWorld.invertToRef(this._worldToDevice); // Update the gamepad to ensure the mesh is updated on the same frame as camera this.controllers.forEach(function (controller) { controller._deviceToWorld.copyFrom(_this._deviceToWorld); controller.update(); }); } if (!ignoreParentClass) { _super.prototype._updateCache.call(this); } this.updateCacheCalled = false; }; /** * Updates the current device position and rotation in the babylon world */ WebVRFreeCamera.prototype.update = function () { // Get current device position in babylon world BABYLON.Vector3.TransformCoordinatesToRef(this._deviceRoomPosition, this._deviceToWorld, this.devicePosition); // Get current device rotation in babylon world BABYLON.Matrix.FromQuaternionToRef(this._deviceRoomRotationQuaternion, this._workingMatrix); this._workingMatrix.multiplyToRef(this._deviceToWorld, this._workingMatrix); BABYLON.Quaternion.FromRotationMatrixToRef(this._workingMatrix, this.deviceRotationQuaternion); _super.prototype.update.call(this); }; /** * Gets the view matrix of this camera (Always set to identity as left and right eye cameras contain the actual view matrix) * @returns an identity matrix */ WebVRFreeCamera.prototype._getViewMatrix = function () { return BABYLON.Matrix.Identity(); }; /** * This function is called by the two RIG cameras. * 'this' is the left or right camera (and NOT (!!!) the WebVRFreeCamera instance) */ WebVRFreeCamera.prototype._getWebVRViewMatrix = function () { var _this = this; // Update the parent camera prior to using a child camera to avoid desynchronization var parentCamera = this._cameraRigParams["parentCamera"]; parentCamera._updateCache(); //WebVR 1.1 var viewArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftViewMatrix : this._cameraRigParams["frameData"].rightViewMatrix; BABYLON.Matrix.FromArrayToRef(viewArray, 0, this._webvrViewMatrix); if (!this.getScene().useRightHandedSystem) { [2, 6, 8, 9, 14].forEach(function (num) { _this._webvrViewMatrix.m[num] *= -1; }); } // update the camera rotation matrix this._webvrViewMatrix.getRotationMatrixToRef(this._cameraRotationMatrix); BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint); // Computing target and final matrix this.position.addToRef(this._transformedReferencePoint, this._currentTarget); // should the view matrix be updated with scale and position offset? if (parentCamera.deviceScaleFactor !== 1) { this._webvrViewMatrix.invert(); // scale the position, if set if (parentCamera.deviceScaleFactor) { this._webvrViewMatrix.m[12] *= parentCamera.deviceScaleFactor; this._webvrViewMatrix.m[13] *= parentCamera.deviceScaleFactor; this._webvrViewMatrix.m[14] *= parentCamera.deviceScaleFactor; } this._webvrViewMatrix.invert(); } parentCamera._worldToDevice.multiplyToRef(this._webvrViewMatrix, this._webvrViewMatrix); return this._webvrViewMatrix; }; WebVRFreeCamera.prototype._getWebVRProjectionMatrix = function () { var _this = this; var parentCamera = this.parent; parentCamera._vrDevice.depthNear = parentCamera.minZ; parentCamera._vrDevice.depthFar = parentCamera.maxZ; var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftProjectionMatrix : this._cameraRigParams["frameData"].rightProjectionMatrix; BABYLON.Matrix.FromArrayToRef(projectionArray, 0, this._projectionMatrix); //babylon compatible matrix if (!this.getScene().useRightHandedSystem) { [8, 9, 10, 11].forEach(function (num) { _this._projectionMatrix.m[num] *= -1; }); } return this._projectionMatrix; }; /** * Initializes the controllers and their meshes */ WebVRFreeCamera.prototype.initControllers = function () { var _this = this; this.controllers = []; var manager = this.getScene().gamepadManager; this._onGamepadDisconnectedObserver = manager.onGamepadDisconnectedObservable.add(function (gamepad) { if (gamepad.type === BABYLON.Gamepad.POSE_ENABLED) { var webVrController = gamepad; if (webVrController.defaultModel) { webVrController.defaultModel.setEnabled(false); } if (webVrController.hand === "right") { _this._rightController = null; } if (webVrController.hand === "left") { _this._leftController = null; } var controllerIndex = _this.controllers.indexOf(webVrController); if (controllerIndex !== -1) { _this.controllers.splice(controllerIndex, 1); } } }); this._onGamepadConnectedObserver = manager.onGamepadConnectedObservable.add(function (gamepad) { if (gamepad.type === BABYLON.Gamepad.POSE_ENABLED) { var webVrController_1 = gamepad; webVrController_1.deviceScaleFactor = _this.deviceScaleFactor; webVrController_1._deviceToWorld.copyFrom(_this._deviceToWorld); if (_this.webVROptions.controllerMeshes) { if (webVrController_1.defaultModel) { webVrController_1.defaultModel.setEnabled(true); } else { // Load the meshes webVrController_1.initControllerMesh(_this.getScene(), function (loadedMesh) { loadedMesh.scaling.scaleInPlace(_this.deviceScaleFactor); _this.onControllerMeshLoadedObservable.notifyObservers(webVrController_1); if (_this.webVROptions.defaultLightingOnControllers) { if (!_this._lightOnControllers) { _this._lightOnControllers = new BABYLON.HemisphericLight("vrControllersLight", new BABYLON.Vector3(0, 1, 0), _this.getScene()); } var activateLightOnSubMeshes_1 = function (mesh, light) { var children = mesh.getChildren(); if (children.length !== 0) { children.forEach(function (mesh) { light.includedOnlyMeshes.push(mesh); activateLightOnSubMeshes_1(mesh, light); }); } }; _this._lightOnControllers.includedOnlyMeshes.push(loadedMesh); activateLightOnSubMeshes_1(loadedMesh, _this._lightOnControllers); } }); } } webVrController_1.attachToPoseControlledCamera(_this); // since this is async - sanity check. Is the controller already stored? if (_this.controllers.indexOf(webVrController_1) === -1) { //add to the controllers array _this.controllers.push(webVrController_1); // Forced to add some control code for Vive as it doesn't always fill properly the "hand" property // Sometimes, both controllers are set correctly (left and right), sometimes none, sometimes only one of them... // So we're overriding setting left & right manually to be sure var firstViveWandDetected = false; for (var i = 0; i < _this.controllers.length; i++) { if (_this.controllers[i].controllerType === BABYLON.PoseEnabledControllerType.VIVE) { if (!firstViveWandDetected) { firstViveWandDetected = true; _this.controllers[i].hand = "left"; } else { _this.controllers[i].hand = "right"; } } } //did we find enough controllers? Great! let the developer know. if (_this.controllers.length >= 2) { _this.onControllersAttachedObservable.notifyObservers(_this.controllers); } } } }); }; return WebVRFreeCamera; }(BABYLON.FreeCamera)); BABYLON.WebVRFreeCamera = WebVRFreeCamera; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.webVRCamera.js.map var BABYLON; (function (BABYLON) { // We're mainly based on the logic defined into the FreeCamera code /** * This is a camera specifically designed to react to device orientation events such as a modern mobile device * being tilted forward or back and left or right. */ var DeviceOrientationCamera = /** @class */ (function (_super) { __extends(DeviceOrientationCamera, _super); /** * Creates a new device orientation camera * @param name The name of the camera * @param position The start position camera * @param scene The scene the camera belongs to */ function DeviceOrientationCamera(name, position, scene) { var _this = _super.call(this, name, position, scene) || this; _this._quaternionCache = new BABYLON.Quaternion(); _this.inputs.addDeviceOrientation(); return _this; } /** * Gets the current instance class name ("DeviceOrientationCamera"). * This helps avoiding instanceof at run time. * @returns the class name */ DeviceOrientationCamera.prototype.getClassName = function () { return "DeviceOrientationCamera"; }; /** * Checks and applies the current values of the inputs to the camera. (Internal use only) */ DeviceOrientationCamera.prototype._checkInputs = function () { _super.prototype._checkInputs.call(this); this._quaternionCache.copyFrom(this.rotationQuaternion); if (this._initialQuaternion) { this._initialQuaternion.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion); } }; /** * Reset the camera to its default orientation on the specified axis only. * @param axis The axis to reset */ DeviceOrientationCamera.prototype.resetToCurrentRotation = function (axis) { var _this = this; if (axis === void 0) { axis = BABYLON.Axis.Y; } //can only work if this camera has a rotation quaternion already. if (!this.rotationQuaternion) return; if (!this._initialQuaternion) { this._initialQuaternion = new BABYLON.Quaternion(); } this._initialQuaternion.copyFrom(this._quaternionCache || this.rotationQuaternion); ['x', 'y', 'z'].forEach(function (axisName) { if (!axis[axisName]) { _this._initialQuaternion[axisName] = 0; } else { _this._initialQuaternion[axisName] *= -1; } }); this._initialQuaternion.normalize(); //force rotation update this._initialQuaternion.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion); }; return DeviceOrientationCamera; }(BABYLON.FreeCamera)); BABYLON.DeviceOrientationCamera = DeviceOrientationCamera; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.deviceOrientationCamera.js.map var BABYLON; (function (BABYLON) { var VRDeviceOrientationFreeCamera = /** @class */ (function (_super) { __extends(VRDeviceOrientationFreeCamera, _super); function VRDeviceOrientationFreeCamera(name, position, scene, compensateDistortion, vrCameraMetrics) { if (compensateDistortion === void 0) { compensateDistortion = true; } if (vrCameraMetrics === void 0) { vrCameraMetrics = BABYLON.VRCameraMetrics.GetDefault(); } var _this = _super.call(this, name, position, scene) || this; vrCameraMetrics.compensateDistortion = compensateDistortion; _this.setCameraRigMode(BABYLON.Camera.RIG_MODE_VR, { vrCameraMetrics: vrCameraMetrics }); return _this; } VRDeviceOrientationFreeCamera.prototype.getClassName = function () { return "VRDeviceOrientationFreeCamera"; }; return VRDeviceOrientationFreeCamera; }(BABYLON.DeviceOrientationCamera)); BABYLON.VRDeviceOrientationFreeCamera = VRDeviceOrientationFreeCamera; var VRDeviceOrientationGamepadCamera = /** @class */ (function (_super) { __extends(VRDeviceOrientationGamepadCamera, _super); function VRDeviceOrientationGamepadCamera(name, position, scene, compensateDistortion, vrCameraMetrics) { if (compensateDistortion === void 0) { compensateDistortion = true; } if (vrCameraMetrics === void 0) { vrCameraMetrics = BABYLON.VRCameraMetrics.GetDefault(); } var _this = _super.call(this, name, position, scene, compensateDistortion, vrCameraMetrics) || this; _this.inputs.addGamepad(); return _this; } VRDeviceOrientationGamepadCamera.prototype.getClassName = function () { return "VRDeviceOrientationGamepadCamera"; }; return VRDeviceOrientationGamepadCamera; }(VRDeviceOrientationFreeCamera)); BABYLON.VRDeviceOrientationGamepadCamera = VRDeviceOrientationGamepadCamera; var VRDeviceOrientationArcRotateCamera = /** @class */ (function (_super) { __extends(VRDeviceOrientationArcRotateCamera, _super); function VRDeviceOrientationArcRotateCamera(name, alpha, beta, radius, target, scene, compensateDistortion, vrCameraMetrics) { if (compensateDistortion === void 0) { compensateDistortion = true; } if (vrCameraMetrics === void 0) { vrCameraMetrics = BABYLON.VRCameraMetrics.GetDefault(); } var _this = _super.call(this, name, alpha, beta, radius, target, scene) || this; vrCameraMetrics.compensateDistortion = compensateDistortion; _this.setCameraRigMode(BABYLON.Camera.RIG_MODE_VR, { vrCameraMetrics: vrCameraMetrics }); _this.inputs.addVRDeviceOrientation(); return _this; } VRDeviceOrientationArcRotateCamera.prototype.getClassName = function () { return "VRDeviceOrientationArcRotateCamera"; }; return VRDeviceOrientationArcRotateCamera; }(BABYLON.ArcRotateCamera)); BABYLON.VRDeviceOrientationArcRotateCamera = VRDeviceOrientationArcRotateCamera; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.vrDeviceOrientationCamera.js.map var BABYLON; (function (BABYLON) { var AnaglyphFreeCamera = /** @class */ (function (_super) { __extends(AnaglyphFreeCamera, _super); function AnaglyphFreeCamera(name, position, interaxialDistance, scene) { var _this = _super.call(this, name, position, scene) || this; _this.interaxialDistance = interaxialDistance; _this.setCameraRigMode(BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance }); return _this; } AnaglyphFreeCamera.prototype.getClassName = function () { return "AnaglyphFreeCamera"; }; return AnaglyphFreeCamera; }(BABYLON.FreeCamera)); BABYLON.AnaglyphFreeCamera = AnaglyphFreeCamera; var AnaglyphArcRotateCamera = /** @class */ (function (_super) { __extends(AnaglyphArcRotateCamera, _super); function AnaglyphArcRotateCamera(name, alpha, beta, radius, target, interaxialDistance, scene) { var _this = _super.call(this, name, alpha, beta, radius, target, scene) || this; _this.interaxialDistance = interaxialDistance; _this.setCameraRigMode(BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance }); return _this; } AnaglyphArcRotateCamera.prototype.getClassName = function () { return "AnaglyphArcRotateCamera"; }; return AnaglyphArcRotateCamera; }(BABYLON.ArcRotateCamera)); BABYLON.AnaglyphArcRotateCamera = AnaglyphArcRotateCamera; var AnaglyphGamepadCamera = /** @class */ (function (_super) { __extends(AnaglyphGamepadCamera, _super); function AnaglyphGamepadCamera(name, position, interaxialDistance, scene) { var _this = _super.call(this, name, position, scene) || this; _this.interaxialDistance = interaxialDistance; _this.setCameraRigMode(BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance }); return _this; } AnaglyphGamepadCamera.prototype.getClassName = function () { return "AnaglyphGamepadCamera"; }; return AnaglyphGamepadCamera; }(BABYLON.GamepadCamera)); BABYLON.AnaglyphGamepadCamera = AnaglyphGamepadCamera; var AnaglyphUniversalCamera = /** @class */ (function (_super) { __extends(AnaglyphUniversalCamera, _super); function AnaglyphUniversalCamera(name, position, interaxialDistance, scene) { var _this = _super.call(this, name, position, scene) || this; _this.interaxialDistance = interaxialDistance; _this.setCameraRigMode(BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance }); return _this; } AnaglyphUniversalCamera.prototype.getClassName = function () { return "AnaglyphUniversalCamera"; }; return AnaglyphUniversalCamera; }(BABYLON.UniversalCamera)); BABYLON.AnaglyphUniversalCamera = AnaglyphUniversalCamera; var StereoscopicFreeCamera = /** @class */ (function (_super) { __extends(StereoscopicFreeCamera, _super); function StereoscopicFreeCamera(name, position, interaxialDistance, isStereoscopicSideBySide, scene) { var _this = _super.call(this, name, position, scene) || this; _this.interaxialDistance = interaxialDistance; _this.isStereoscopicSideBySide = isStereoscopicSideBySide; _this.setCameraRigMode(isStereoscopicSideBySide ? BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance }); return _this; } StereoscopicFreeCamera.prototype.getClassName = function () { return "StereoscopicFreeCamera"; }; return StereoscopicFreeCamera; }(BABYLON.FreeCamera)); BABYLON.StereoscopicFreeCamera = StereoscopicFreeCamera; var StereoscopicArcRotateCamera = /** @class */ (function (_super) { __extends(StereoscopicArcRotateCamera, _super); function StereoscopicArcRotateCamera(name, alpha, beta, radius, target, interaxialDistance, isStereoscopicSideBySide, scene) { var _this = _super.call(this, name, alpha, beta, radius, target, scene) || this; _this.interaxialDistance = interaxialDistance; _this.isStereoscopicSideBySide = isStereoscopicSideBySide; _this.setCameraRigMode(isStereoscopicSideBySide ? BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance }); return _this; } StereoscopicArcRotateCamera.prototype.getClassName = function () { return "StereoscopicArcRotateCamera"; }; return StereoscopicArcRotateCamera; }(BABYLON.ArcRotateCamera)); BABYLON.StereoscopicArcRotateCamera = StereoscopicArcRotateCamera; var StereoscopicGamepadCamera = /** @class */ (function (_super) { __extends(StereoscopicGamepadCamera, _super); function StereoscopicGamepadCamera(name, position, interaxialDistance, isStereoscopicSideBySide, scene) { var _this = _super.call(this, name, position, scene) || this; _this.interaxialDistance = interaxialDistance; _this.isStereoscopicSideBySide = isStereoscopicSideBySide; _this.setCameraRigMode(isStereoscopicSideBySide ? BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance }); return _this; } StereoscopicGamepadCamera.prototype.getClassName = function () { return "StereoscopicGamepadCamera"; }; return StereoscopicGamepadCamera; }(BABYLON.GamepadCamera)); BABYLON.StereoscopicGamepadCamera = StereoscopicGamepadCamera; var StereoscopicUniversalCamera = /** @class */ (function (_super) { __extends(StereoscopicUniversalCamera, _super); function StereoscopicUniversalCamera(name, position, interaxialDistance, isStereoscopicSideBySide, scene) { var _this = _super.call(this, name, position, scene) || this; _this.interaxialDistance = interaxialDistance; _this.isStereoscopicSideBySide = isStereoscopicSideBySide; _this.setCameraRigMode(isStereoscopicSideBySide ? BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance }); return _this; } StereoscopicUniversalCamera.prototype.getClassName = function () { return "StereoscopicUniversalCamera"; }; return StereoscopicUniversalCamera; }(BABYLON.UniversalCamera)); BABYLON.StereoscopicUniversalCamera = StereoscopicUniversalCamera; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.stereoscopicCameras.js.map var BABYLON; (function (BABYLON) { var VRExperienceHelperGazer = /** @class */ (function () { function VRExperienceHelperGazer(scene, gazeTrackerToClone) { if (gazeTrackerToClone === void 0) { gazeTrackerToClone = null; } this.scene = scene; this._pointerDownOnMeshAsked = false; this._isActionableMesh = false; this._teleportationRequestInitiated = false; this._teleportationBackRequestInitiated = false; this._dpadPressed = true; this._activePointer = false; this._id = VRExperienceHelperGazer._idCounter++; // Gaze tracker if (!gazeTrackerToClone) { this._gazeTracker = BABYLON.Mesh.CreateTorus("gazeTracker", 0.0035, 0.0025, 20, scene, false); this._gazeTracker.bakeCurrentTransformIntoVertices(); this._gazeTracker.isPickable = false; this._gazeTracker.isVisible = false; var targetMat = new BABYLON.StandardMaterial("targetMat", scene); targetMat.specularColor = BABYLON.Color3.Black(); targetMat.emissiveColor = new BABYLON.Color3(0.7, 0.7, 0.7); targetMat.backFaceCulling = false; this._gazeTracker.material = targetMat; } else { this._gazeTracker = gazeTrackerToClone.clone("gazeTracker"); } } VRExperienceHelperGazer.prototype._getForwardRay = function (length) { return new BABYLON.Ray(BABYLON.Vector3.Zero(), new BABYLON.Vector3(0, 0, length)); }; VRExperienceHelperGazer.prototype._selectionPointerDown = function () { this._pointerDownOnMeshAsked = true; if (this._currentMeshSelected && this._currentHit) { this.scene.simulatePointerDown(this._currentHit, { pointerId: this._id }); } }; VRExperienceHelperGazer.prototype._selectionPointerUp = function () { if (this._currentMeshSelected && this._currentHit) { this.scene.simulatePointerUp(this._currentHit, { pointerId: this._id }); } this._pointerDownOnMeshAsked = false; }; VRExperienceHelperGazer.prototype._activatePointer = function () { this._activePointer = true; }; VRExperienceHelperGazer.prototype._deactivatePointer = function () { this._activePointer = false; }; VRExperienceHelperGazer.prototype._updatePointerDistance = function (distance) { }; VRExperienceHelperGazer.prototype.dispose = function () { this._interactionsEnabled = false; this._teleportationEnabled = false; }; VRExperienceHelperGazer._idCounter = 0; return VRExperienceHelperGazer; }()); var VRExperienceHelperControllerGazer = /** @class */ (function (_super) { __extends(VRExperienceHelperControllerGazer, _super); function VRExperienceHelperControllerGazer(webVRController, scene, gazeTrackerToClone) { var _this = _super.call(this, scene, gazeTrackerToClone) || this; _this.webVRController = webVRController; // Laser pointer _this._laserPointer = BABYLON.Mesh.CreateCylinder("laserPointer", 1, 0.004, 0.0002, 20, 1, scene, false); var laserPointerMaterial = new BABYLON.StandardMaterial("laserPointerMat", scene); laserPointerMaterial.emissiveColor = new BABYLON.Color3(0.7, 0.7, 0.7); laserPointerMaterial.alpha = 0.6; _this._laserPointer.material = laserPointerMaterial; _this._laserPointer.rotation.x = Math.PI / 2; _this._laserPointer.position.z = -0.5; _this._laserPointer.isVisible = false; if (!webVRController.mesh) { // Create an empty mesh that is used prior to loading the high quality model var preloadMesh = new BABYLON.Mesh("preloadControllerMesh", scene); var preloadPointerPose = new BABYLON.Mesh(BABYLON.PoseEnabledController.POINTING_POSE, scene); preloadPointerPose.rotation.x = -0.7; preloadMesh.addChild(preloadPointerPose); webVRController.attachToMesh(preloadMesh); } _this._setLaserPointerParent(webVRController.mesh); return _this; } VRExperienceHelperControllerGazer.prototype._getForwardRay = function (length) { return this.webVRController.getForwardRay(length); }; VRExperienceHelperControllerGazer.prototype._activatePointer = function () { _super.prototype._activatePointer.call(this); this._laserPointer.isVisible = true; }; VRExperienceHelperControllerGazer.prototype._deactivatePointer = function () { _super.prototype._deactivatePointer.call(this); this._laserPointer.isVisible = false; }; VRExperienceHelperControllerGazer.prototype._setLaserPointerColor = function (color) { this._laserPointer.material.emissiveColor = color; }; VRExperienceHelperControllerGazer.prototype._setLaserPointerParent = function (mesh) { var makeNotPick = function (root) { root.name += " laserPointer"; root.getChildMeshes().forEach(function (c) { makeNotPick(c); }); }; makeNotPick(mesh); var childMeshes = mesh.getChildMeshes(); this.webVRController._pointingPoseNode = null; for (var i = 0; i < childMeshes.length; i++) { if (childMeshes[i].name && childMeshes[i].name.indexOf(BABYLON.PoseEnabledController.POINTING_POSE) >= 0) { mesh = childMeshes[i]; this.webVRController._pointingPoseNode = mesh; break; } } this._laserPointer.parent = mesh; }; VRExperienceHelperControllerGazer.prototype._updatePointerDistance = function (distance) { this._laserPointer.scaling.y = distance; this._laserPointer.position.z = -distance / 2; }; VRExperienceHelperControllerGazer.prototype.dispose = function () { _super.prototype.dispose.call(this); this._laserPointer.dispose(); }; return VRExperienceHelperControllerGazer; }(VRExperienceHelperGazer)); var VRExperienceHelperCameraGazer = /** @class */ (function (_super) { __extends(VRExperienceHelperCameraGazer, _super); function VRExperienceHelperCameraGazer(getCamera, scene) { var _this = _super.call(this, scene) || this; _this.getCamera = getCamera; return _this; } VRExperienceHelperCameraGazer.prototype._getForwardRay = function (length) { var camera = this.getCamera(); if (camera) { return camera.getForwardRay(length); } else { return new BABYLON.Ray(BABYLON.Vector3.Zero(), BABYLON.Vector3.Forward()); } }; return VRExperienceHelperCameraGazer; }(VRExperienceHelperGazer)); /** * Helps to quickly add VR support to an existing scene. * See http://doc.babylonjs.com/how_to/webvr_helper */ var VRExperienceHelper = /** @class */ (function () { /** * Instantiates a VRExperienceHelper. * Helps to quickly add VR support to an existing scene. * @param scene The scene the VRExperienceHelper belongs to. * @param webVROptions Options to modify the vr experience helper's behavior. */ function VRExperienceHelper(scene, /** Options to modify the vr experience helper's behavior. */ webVROptions) { if (webVROptions === void 0) { webVROptions = {}; } var _this = this; this.webVROptions = webVROptions; // Can the system support WebVR, even if a headset isn't plugged in? this._webVRsupported = false; // If WebVR is supported, is a headset plugged in and are we ready to present? this._webVRready = false; // Are we waiting for the requestPresent callback to complete? this._webVRrequesting = false; // Are we presenting to the headset right now? this._webVRpresenting = false; // Are we presenting in the fullscreen fallback? this._fullscreenVRpresenting = false; /** * Observable raised when entering VR. */ this.onEnteringVRObservable = new BABYLON.Observable(); /** * Observable raised when exiting VR. */ this.onExitingVRObservable = new BABYLON.Observable(); /** * Observable raised when controller mesh is loaded. */ this.onControllerMeshLoadedObservable = new BABYLON.Observable(); this._useCustomVRButton = false; this._teleportationRequested = false; this._teleportActive = false; this._floorMeshesCollection = []; this._rotationAllowed = true; this._teleportBackwardsVector = new BABYLON.Vector3(0, -1, -1); this._rotationRightAsked = false; this._rotationLeftAsked = false; this._isDefaultTeleportationTarget = true; this._teleportationFillColor = "#444444"; this._teleportationBorderColor = "#FFFFFF"; this._rotationAngle = 0; this._haloCenter = new BABYLON.Vector3(0, 0, 0); this._padSensibilityUp = 0.65; this._padSensibilityDown = 0.35; this.leftController = null; this.rightController = null; /** * Observable raised when a new mesh is selected based on meshSelectionPredicate */ this.onNewMeshSelected = new BABYLON.Observable(); /** * Observable raised when a new mesh is picked based on meshSelectionPredicate */ this.onNewMeshPicked = new BABYLON.Observable(); /** * Observable raised before camera teleportation */ this.onBeforeCameraTeleport = new BABYLON.Observable(); /** * Observable raised after camera teleportation */ this.onAfterCameraTeleport = new BABYLON.Observable(); /** * Observable raised when current selected mesh gets unselected */ this.onSelectedMeshUnselected = new BABYLON.Observable(); /** * Set teleportation enabled. If set to false camera teleportation will be disabled but camera rotation will be kept. */ this.teleportationEnabled = true; this._teleportationInitialized = false; this._interactionsEnabled = false; this._interactionsRequested = false; this._displayGaze = true; this._displayLaserPointer = true; this._onResize = function () { _this.moveButtonToBottomRight(); if (_this._fullscreenVRpresenting && _this._webVRready) { _this.exitVR(); } }; this._onFullscreenChange = function () { if (document.fullscreen !== undefined) { _this._fullscreenVRpresenting = document.fullscreen; } else if (document.mozFullScreen !== undefined) { _this._fullscreenVRpresenting = document.mozFullScreen; } else if (document.webkitIsFullScreen !== undefined) { _this._fullscreenVRpresenting = document.webkitIsFullScreen; } else if (document.msIsFullScreen !== undefined) { _this._fullscreenVRpresenting = document.msIsFullScreen; } if (!_this._fullscreenVRpresenting && _this._canvas) { _this.exitVR(); if (!_this._useCustomVRButton) { _this._btnVR.style.top = _this._canvas.offsetTop + _this._canvas.offsetHeight - 70 + "px"; _this._btnVR.style.left = _this._canvas.offsetLeft + _this._canvas.offsetWidth - 100 + "px"; } } }; this.beforeRender = function () { if (_this.leftController && _this.leftController._activePointer) { _this._castRayAndSelectObject(_this.leftController); } if (_this.rightController && _this.rightController._activePointer) { _this._castRayAndSelectObject(_this.rightController); } if (!(_this.leftController && _this.leftController._activePointer) && !(_this.rightController && _this.rightController._activePointer)) { _this._castRayAndSelectObject(_this._cameraGazer); } else { _this._cameraGazer._gazeTracker.isVisible = false; } }; this._onNewGamepadConnected = function (gamepad) { if (gamepad.type !== BABYLON.Gamepad.POSE_ENABLED) { if (gamepad.leftStick) { gamepad.onleftstickchanged(function (stickValues) { if (_this._teleportationInitialized && _this.teleportationEnabled) { // Listening to classic/xbox gamepad only if no VR controller is active if ((!_this.leftController && !_this.rightController) || ((_this.leftController && !_this.leftController._activePointer) && (_this.rightController && !_this.rightController._activePointer))) { _this._checkTeleportWithRay(stickValues, _this._cameraGazer); _this._checkTeleportBackwards(stickValues, _this._cameraGazer); } } }); } if (gamepad.rightStick) { gamepad.onrightstickchanged(function (stickValues) { if (_this._teleportationInitialized) { _this._checkRotate(stickValues, _this._cameraGazer); } }); } if (gamepad.type === BABYLON.Gamepad.XBOX) { gamepad.onbuttondown(function (buttonPressed) { if (_this._interactionsEnabled && buttonPressed === BABYLON.Xbox360Button.A) { _this._cameraGazer._selectionPointerDown(); } }); gamepad.onbuttonup(function (buttonPressed) { if (_this._interactionsEnabled && buttonPressed === BABYLON.Xbox360Button.A) { _this._cameraGazer._selectionPointerUp(); } }); } } else { var webVRController = gamepad; var controller = new VRExperienceHelperControllerGazer(webVRController, _this._scene, _this._cameraGazer._gazeTracker); if (webVRController.hand === "right" || (_this.leftController && _this.leftController.webVRController != webVRController)) { _this.rightController = controller; } else { _this.leftController = controller; } _this._tryEnableInteractionOnController(controller); } }; // This only succeeds if the controller's mesh exists for the controller so this must be called whenever new controller is connected or when mesh is loaded this._tryEnableInteractionOnController = function (controller) { if (_this._interactionsRequested && !controller._interactionsEnabled) { _this._enableInteractionOnController(controller); } if (_this._teleportationRequested && !controller._teleportationEnabled) { _this._enableTeleportationOnController(controller); } }; this._onNewGamepadDisconnected = function (gamepad) { if (gamepad instanceof BABYLON.WebVRController) { if (gamepad.hand === "left" && _this.leftController != null) { _this.leftController.dispose(); _this.leftController = null; } if (gamepad.hand === "right" && _this.rightController != null) { _this.rightController.dispose(); _this.rightController = null; } } }; this._workingVector = BABYLON.Vector3.Zero(); this._workingQuaternion = BABYLON.Quaternion.Identity(); this._workingMatrix = BABYLON.Matrix.Identity(); this._scene = scene; this._canvas = scene.getEngine().getRenderingCanvas(); // Parse options if (webVROptions.createFallbackVRDeviceOrientationFreeCamera === undefined) { webVROptions.createFallbackVRDeviceOrientationFreeCamera = true; } if (webVROptions.createDeviceOrientationCamera === undefined) { webVROptions.createDeviceOrientationCamera = true; } if (webVROptions.defaultHeight === undefined) { webVROptions.defaultHeight = 1.7; } if (webVROptions.useCustomVRButton) { this._useCustomVRButton = true; if (webVROptions.customVRButton) { this._btnVR = webVROptions.customVRButton; } } if (webVROptions.rayLength) { this._rayLength = webVROptions.rayLength; } this._defaultHeight = webVROptions.defaultHeight; if (webVROptions.positionScale) { this._rayLength *= webVROptions.positionScale; this._defaultHeight *= webVROptions.positionScale; } // Set position if (this._scene.activeCamera) { this._position = this._scene.activeCamera.position.clone(); } else { this._position = new BABYLON.Vector3(0, this._defaultHeight, 0); } // Set non-vr camera if (webVROptions.createDeviceOrientationCamera || !this._scene.activeCamera) { this._deviceOrientationCamera = new BABYLON.DeviceOrientationCamera("deviceOrientationVRHelper", this._position.clone(), scene); // Copy data from existing camera if (this._scene.activeCamera) { this._deviceOrientationCamera.minZ = this._scene.activeCamera.minZ; this._deviceOrientationCamera.maxZ = this._scene.activeCamera.maxZ; // Set rotation from previous camera if (this._scene.activeCamera instanceof BABYLON.TargetCamera && this._scene.activeCamera.rotation) { var targetCamera = this._scene.activeCamera; if (targetCamera.rotationQuaternion) { this._deviceOrientationCamera.rotationQuaternion.copyFrom(targetCamera.rotationQuaternion); } else { this._deviceOrientationCamera.rotationQuaternion.copyFrom(BABYLON.Quaternion.RotationYawPitchRoll(targetCamera.rotation.y, targetCamera.rotation.x, targetCamera.rotation.z)); } this._deviceOrientationCamera.rotation = targetCamera.rotation.clone(); } } this._scene.activeCamera = this._deviceOrientationCamera; if (this._canvas) { this._scene.activeCamera.attachControl(this._canvas); } } else { this._existingCamera = this._scene.activeCamera; } // Create VR cameras if (webVROptions.createFallbackVRDeviceOrientationFreeCamera) { this._vrDeviceOrientationCamera = new BABYLON.VRDeviceOrientationFreeCamera("VRDeviceOrientationVRHelper", this._position, this._scene); } this._webVRCamera = new BABYLON.WebVRFreeCamera("WebVRHelper", this._position, this._scene, webVROptions); this._webVRCamera.useStandingMatrix(); this._cameraGazer = new VRExperienceHelperCameraGazer(function () { return _this.currentVRCamera; }, scene); // Create default button if (!this._useCustomVRButton) { this._btnVR = document.createElement("BUTTON"); this._btnVR.className = "babylonVRicon"; this._btnVR.id = "babylonVRiconbtn"; this._btnVR.title = "Click to switch to VR"; var css = ".babylonVRicon { position: absolute; right: 20px; height: 50px; width: 80px; background-color: rgba(51,51,51,0.7); background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%222048%22%20height%3D%221152%22%20viewBox%3D%220%200%202048%201152%22%20version%3D%221.1%22%3E%3Cpath%20transform%3D%22rotate%28180%201024%2C576.0000000000001%29%22%20d%3D%22m1109%2C896q17%2C0%2030%2C-12t13%2C-30t-12.5%2C-30.5t-30.5%2C-12.5l-170%2C0q-18%2C0%20-30.5%2C12.5t-12.5%2C30.5t13%2C30t30%2C12l170%2C0zm-85%2C256q59%2C0%20132.5%2C-1.5t154.5%2C-5.5t164.5%2C-11.5t163%2C-20t150%2C-30t124.5%2C-41.5q23%2C-11%2042%2C-24t38%2C-30q27%2C-25%2041%2C-61.5t14%2C-72.5l0%2C-257q0%2C-123%20-47%2C-232t-128%2C-190t-190%2C-128t-232%2C-47l-81%2C0q-37%2C0%20-68.5%2C14t-60.5%2C34.5t-55.5%2C45t-53%2C45t-53%2C34.5t-55.5%2C14t-55.5%2C-14t-53%2C-34.5t-53%2C-45t-55.5%2C-45t-60.5%2C-34.5t-68.5%2C-14l-81%2C0q-123%2C0%20-232%2C47t-190%2C128t-128%2C190t-47%2C232l0%2C257q0%2C68%2038%2C115t97%2C73q54%2C24%20124.5%2C41.5t150%2C30t163%2C20t164.5%2C11.5t154.5%2C5.5t132.5%2C1.5zm939%2C-298q0%2C39%20-24.5%2C67t-58.5%2C42q-54%2C23%20-122%2C39.5t-143.5%2C28t-155.5%2C19t-157%2C11t-148.5%2C5t-129.5%2C1.5q-59%2C0%20-130%2C-1.5t-148%2C-5t-157%2C-11t-155.5%2C-19t-143.5%2C-28t-122%2C-39.5q-34%2C-14%20-58.5%2C-42t-24.5%2C-67l0%2C-257q0%2C-106%2040.5%2C-199t110%2C-162.5t162.5%2C-109.5t199%2C-40l81%2C0q27%2C0%2052%2C14t50%2C34.5t51%2C44.5t55.5%2C44.5t63.5%2C34.5t74%2C14t74%2C-14t63.5%2C-34.5t55.5%2C-44.5t51%2C-44.5t50%2C-34.5t52%2C-14l14%2C0q37%2C0%2070%2C0.5t64.5%2C4.5t63.5%2C12t68%2C23q71%2C30%20128.5%2C78.5t98.5%2C110t63.5%2C133.5t22.5%2C149l0%2C257z%22%20fill%3D%22white%22%20/%3E%3C/svg%3E%0A); background-size: 80%; background-repeat:no-repeat; background-position: center; border: none; outline: none; transition: transform 0.125s ease-out } .babylonVRicon:hover { transform: scale(1.05) } .babylonVRicon:active {background-color: rgba(51,51,51,1) } .babylonVRicon:focus {background-color: rgba(51,51,51,1) }"; css += ".babylonVRicon.vrdisplaypresenting { display: none; }"; // TODO: Add user feedback so that they know what state the VRDisplay is in (disconnected, connected, entering-VR) // css += ".babylonVRicon.vrdisplaysupported { }"; // css += ".babylonVRicon.vrdisplayready { }"; // css += ".babylonVRicon.vrdisplayrequesting { }"; var style = document.createElement('style'); style.appendChild(document.createTextNode(css)); document.getElementsByTagName('head')[0].appendChild(style); this.moveButtonToBottomRight(); } // VR button click event if (this._btnVR) { this._btnVR.addEventListener("click", function () { if (!_this.isInVRMode) { _this.enterVR(); } else { _this.exitVR(); } }); } // Window events window.addEventListener("resize", this._onResize); document.addEventListener("fullscreenchange", this._onFullscreenChange, false); document.addEventListener("mozfullscreenchange", this._onFullscreenChange, false); document.addEventListener("webkitfullscreenchange", this._onFullscreenChange, false); document.addEventListener("msfullscreenchange", this._onFullscreenChange, false); // Display vr button when headset is connected if (webVROptions.createFallbackVRDeviceOrientationFreeCamera) { this.displayVRButton(); } else { this._scene.getEngine().onVRDisplayChangedObservable.add(function (e) { if (e.vrDisplay) { _this.displayVRButton(); } }); } // Exiting VR mode using 'ESC' key on desktop this._onKeyDown = function (event) { if (event.keyCode === 27 && _this.isInVRMode) { _this.exitVR(); } }; document.addEventListener("keydown", this._onKeyDown); // Exiting VR mode double tapping the touch screen this._scene.onPrePointerObservable.add(function (pointerInfo, eventState) { if (_this.isInVRMode) { _this.exitVR(); if (_this._fullscreenVRpresenting) { _this._scene.getEngine().switchFullscreen(true); } } }, BABYLON.PointerEventTypes.POINTERDOUBLETAP, false); // Listen for WebVR display changes this._onVRDisplayChanged = function (eventArgs) { return _this.onVRDisplayChanged(eventArgs); }; this._onVrDisplayPresentChange = function () { return _this.onVrDisplayPresentChange(); }; this._onVRRequestPresentStart = function () { _this._webVRrequesting = true; _this.updateButtonVisibility(); }; this._onVRRequestPresentComplete = function (success) { _this._webVRrequesting = false; _this.updateButtonVisibility(); }; scene.getEngine().onVRDisplayChangedObservable.add(this._onVRDisplayChanged); scene.getEngine().onVRRequestPresentStart.add(this._onVRRequestPresentStart); scene.getEngine().onVRRequestPresentComplete.add(this._onVRRequestPresentComplete); window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange); scene.onDisposeObservable.add(function () { _this.dispose(); }); // Gamepad connection events this._webVRCamera.onControllerMeshLoadedObservable.add(function (webVRController) { return _this._onDefaultMeshLoaded(webVRController); }); this._scene.gamepadManager.onGamepadConnectedObservable.add(this._onNewGamepadConnected); this._scene.gamepadManager.onGamepadDisconnectedObservable.add(this._onNewGamepadDisconnected); this.updateButtonVisibility(); //create easing functions this._circleEase = new BABYLON.CircleEase(); this._circleEase.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT); } Object.defineProperty(VRExperienceHelper.prototype, "onEnteringVR", { /** Return this.onEnteringVRObservable * Note: This one is for backward compatibility. Please use onEnteringVRObservable directly */ get: function () { return this.onEnteringVRObservable; }, enumerable: true, configurable: true }); Object.defineProperty(VRExperienceHelper.prototype, "onExitingVR", { /** Return this.onExitingVRObservable * Note: This one is for backward compatibility. Please use onExitingVRObservable directly */ get: function () { return this.onExitingVRObservable; }, enumerable: true, configurable: true }); Object.defineProperty(VRExperienceHelper.prototype, "onControllerMeshLoaded", { /** Return this.onControllerMeshLoadedObservable * Note: This one is for backward compatibility. Please use onControllerMeshLoadedObservable directly */ get: function () { return this.onControllerMeshLoadedObservable; }, enumerable: true, configurable: true }); Object.defineProperty(VRExperienceHelper.prototype, "teleportationTarget", { /** * The mesh used to display where the user is going to teleport. */ get: function () { return this._teleportationTarget; }, /** * Sets the mesh to be used to display where the user is going to teleport. */ set: function (value) { if (value) { value.name = "teleportationTarget"; this._isDefaultTeleportationTarget = false; this._teleportationTarget = value; } }, enumerable: true, configurable: true }); Object.defineProperty(VRExperienceHelper.prototype, "gazeTrackerMesh", { /** * The mesh used to display where the user is selecting, * when set bakeCurrentTransformIntoVertices will be called on the mesh. * See http://doc.babylonjs.com/resources/baking_transformations */ get: function () { return this._cameraGazer._gazeTracker; }, set: function (value) { if (value) { this._cameraGazer._gazeTracker = value; this._cameraGazer._gazeTracker.bakeCurrentTransformIntoVertices(); this._cameraGazer._gazeTracker.isPickable = false; this._cameraGazer._gazeTracker.isVisible = false; this._cameraGazer._gazeTracker.name = "gazeTracker"; if (this.leftController) { this.leftController._gazeTracker = this._cameraGazer._gazeTracker.clone("gazeTracker"); } if (this.rightController) { this.rightController._gazeTracker = this._cameraGazer._gazeTracker.clone("gazeTracker"); } } }, enumerable: true, configurable: true }); Object.defineProperty(VRExperienceHelper.prototype, "displayGaze", { /** * If the ray of the gaze should be displayed. */ get: function () { return this._displayGaze; }, /** * Sets if the ray of the gaze should be displayed. */ set: function (value) { this._displayGaze = value; if (!value) { this._cameraGazer._gazeTracker.isVisible = false; if (this.leftController) { this.leftController._gazeTracker.isVisible = false; } if (this.rightController) { this.rightController._gazeTracker.isVisible = false; } } }, enumerable: true, configurable: true }); Object.defineProperty(VRExperienceHelper.prototype, "displayLaserPointer", { /** * If the ray of the LaserPointer should be displayed. */ get: function () { return this._displayLaserPointer; }, /** * Sets if the ray of the LaserPointer should be displayed. */ set: function (value) { this._displayLaserPointer = value; if (!value) { if (this.rightController) { this.rightController._deactivatePointer(); this.rightController._gazeTracker.isVisible = false; } if (this.leftController) { this.leftController._deactivatePointer(); this.leftController._gazeTracker.isVisible = false; } } else { if (this.rightController) { this.rightController._activatePointer(); } else if (this.leftController) { this.leftController._activatePointer(); } } }, enumerable: true, configurable: true }); Object.defineProperty(VRExperienceHelper.prototype, "deviceOrientationCamera", { /** * The deviceOrientationCamera used as the camera when not in VR. */ get: function () { return this._deviceOrientationCamera; }, enumerable: true, configurable: true }); Object.defineProperty(VRExperienceHelper.prototype, "currentVRCamera", { /** * Based on the current WebVR support, returns the current VR camera used. */ get: function () { if (this._webVRready) { return this._webVRCamera; } else { return this._scene.activeCamera; } }, enumerable: true, configurable: true }); Object.defineProperty(VRExperienceHelper.prototype, "webVRCamera", { /** * The webVRCamera which is used when in VR. */ get: function () { return this._webVRCamera; }, enumerable: true, configurable: true }); Object.defineProperty(VRExperienceHelper.prototype, "vrDeviceOrientationCamera", { /** * The deviceOrientationCamera that is used as a fallback when vr device is not connected. */ get: function () { return this._vrDeviceOrientationCamera; }, enumerable: true, configurable: true }); Object.defineProperty(VRExperienceHelper.prototype, "_teleportationRequestInitiated", { get: function () { var result = this._cameraGazer._teleportationRequestInitiated || (this.leftController !== null && this.leftController._teleportationRequestInitiated) || (this.rightController !== null && this.rightController._teleportationRequestInitiated); return result; }, enumerable: true, configurable: true }); // Raised when one of the controller has loaded successfully its associated default mesh VRExperienceHelper.prototype._onDefaultMeshLoaded = function (webVRController) { if (this.leftController && this.leftController.webVRController == webVRController) { if (webVRController.mesh) { this.leftController._setLaserPointerParent(webVRController.mesh); } } if (this.rightController && this.rightController.webVRController == webVRController) { if (webVRController.mesh) { this.rightController._setLaserPointerParent(webVRController.mesh); } } try { this.onControllerMeshLoadedObservable.notifyObservers(webVRController); } catch (err) { BABYLON.Tools.Warn("Error in your custom logic onControllerMeshLoaded: " + err); } }; Object.defineProperty(VRExperienceHelper.prototype, "isInVRMode", { /** * Gets a value indicating if we are currently in VR mode. */ get: function () { return this._webVRpresenting || this._fullscreenVRpresenting; }, enumerable: true, configurable: true }); VRExperienceHelper.prototype.onVrDisplayPresentChange = function () { var vrDisplay = this._scene.getEngine().getVRDevice(); if (vrDisplay) { var wasPresenting = this._webVRpresenting; // A VR display is connected this._webVRpresenting = vrDisplay.isPresenting; if (wasPresenting && !this._webVRpresenting) this.exitVR(); } else { BABYLON.Tools.Warn('Detected VRDisplayPresentChange on an unknown VRDisplay. Did you can enterVR on the vrExperienceHelper?'); } this.updateButtonVisibility(); }; VRExperienceHelper.prototype.onVRDisplayChanged = function (eventArgs) { this._webVRsupported = eventArgs.vrSupported; this._webVRready = !!eventArgs.vrDisplay; this._webVRpresenting = eventArgs.vrDisplay && eventArgs.vrDisplay.isPresenting; this.updateButtonVisibility(); }; VRExperienceHelper.prototype.moveButtonToBottomRight = function () { if (this._canvas && !this._useCustomVRButton) { this._btnVR.style.top = this._canvas.offsetTop + this._canvas.offsetHeight - 70 + "px"; this._btnVR.style.left = this._canvas.offsetLeft + this._canvas.offsetWidth - 100 + "px"; } }; VRExperienceHelper.prototype.displayVRButton = function () { if (!this._useCustomVRButton && !this._btnVRDisplayed) { document.body.appendChild(this._btnVR); this._btnVRDisplayed = true; } }; VRExperienceHelper.prototype.updateButtonVisibility = function () { if (!this._btnVR || this._useCustomVRButton) { return; } this._btnVR.className = "babylonVRicon"; if (this.isInVRMode) { this._btnVR.className += " vrdisplaypresenting"; } else { if (this._webVRready) this._btnVR.className += " vrdisplayready"; if (this._webVRsupported) this._btnVR.className += " vrdisplaysupported"; if (this._webVRrequesting) this._btnVR.className += " vrdisplayrequesting"; } }; /** * Attempt to enter VR. If a headset is connected and ready, will request present on that. * Otherwise, will use the fullscreen API. */ VRExperienceHelper.prototype.enterVR = function () { if (this.onEnteringVRObservable) { try { this.onEnteringVRObservable.notifyObservers(this); } catch (err) { BABYLON.Tools.Warn("Error in your custom logic onEnteringVR: " + err); } } if (this._scene.activeCamera) { this._position = this._scene.activeCamera.position.clone(); // make sure that we return to the last active camera this._existingCamera = this._scene.activeCamera; } if (this._webVRrequesting) return; // If WebVR is supported and a headset is connected if (this._webVRready) { if (!this._webVRpresenting) { this._webVRCamera.position = this._position; this._scene.activeCamera = this._webVRCamera; } } else if (this._vrDeviceOrientationCamera) { this._vrDeviceOrientationCamera.position = this._position; this._scene.activeCamera = this._vrDeviceOrientationCamera; this._scene.getEngine().switchFullscreen(true); this.updateButtonVisibility(); } if (this._scene.activeCamera && this._canvas) { this._scene.activeCamera.attachControl(this._canvas); } if (this._interactionsEnabled) { this._scene.registerBeforeRender(this.beforeRender); } }; /** * Attempt to exit VR, or fullscreen. */ VRExperienceHelper.prototype.exitVR = function () { if (this.onExitingVRObservable) { try { this.onExitingVRObservable.notifyObservers(this); } catch (err) { BABYLON.Tools.Warn("Error in your custom logic onExitingVR: " + err); } } if (this._webVRpresenting) { this._scene.getEngine().disableVR(); } if (this._scene.activeCamera) { this._position = this._scene.activeCamera.position.clone(); } if (this._deviceOrientationCamera) { this._deviceOrientationCamera.position = this._position; this._scene.activeCamera = this._deviceOrientationCamera; if (this._canvas) { this._scene.activeCamera.attachControl(this._canvas); } } else if (this._existingCamera) { this._existingCamera.position = this._position; this._scene.activeCamera = this._existingCamera; } this.updateButtonVisibility(); if (this._interactionsEnabled) { this._scene.unregisterBeforeRender(this.beforeRender); } }; Object.defineProperty(VRExperienceHelper.prototype, "position", { /** * The position of the vr experience helper. */ get: function () { return this._position; }, /** * Sets the position of the vr experience helper. */ set: function (value) { this._position = value; if (this._scene.activeCamera) { this._scene.activeCamera.position = value; } }, enumerable: true, configurable: true }); /** * Enables controllers and user interactions suck as selecting and object or clicking on an object. */ VRExperienceHelper.prototype.enableInteractions = function () { var _this = this; if (!this._interactionsEnabled) { this._interactionsRequested = true; if (this.leftController) { this._enableInteractionOnController(this.leftController); } if (this.rightController) { this._enableInteractionOnController(this.rightController); } this.raySelectionPredicate = function (mesh) { return mesh.isVisible; }; this.meshSelectionPredicate = function (mesh) { return true; }; this._raySelectionPredicate = function (mesh) { if (_this._isTeleportationFloor(mesh) || (mesh.name.indexOf("gazeTracker") === -1 && mesh.name.indexOf("teleportationTarget") === -1 && mesh.name.indexOf("torusTeleportation") === -1 && mesh.name.indexOf("laserPointer") === -1)) { return _this.raySelectionPredicate(mesh); } return false; }; this._interactionsEnabled = true; } }; VRExperienceHelper.prototype._isTeleportationFloor = function (mesh) { for (var i = 0; i < this._floorMeshesCollection.length; i++) { if (this._floorMeshesCollection[i].id === mesh.id) { return true; } } if (this._floorMeshName && mesh.name === this._floorMeshName) { return true; } return false; }; /** * Adds a floor mesh to be used for teleportation. * @param floorMesh the mesh to be used for teleportation. */ VRExperienceHelper.prototype.addFloorMesh = function (floorMesh) { if (!this._floorMeshesCollection) { return; } if (this._floorMeshesCollection.indexOf(floorMesh) > -1) { return; } this._floorMeshesCollection.push(floorMesh); }; /** * Removes a floor mesh from being used for teleportation. * @param floorMesh the mesh to be removed. */ VRExperienceHelper.prototype.removeFloorMesh = function (floorMesh) { if (!this._floorMeshesCollection) { return; } var meshIndex = this._floorMeshesCollection.indexOf(floorMesh); if (meshIndex !== -1) { this._floorMeshesCollection.splice(meshIndex, 1); } }; /** * Enables interactions and teleportation using the VR controllers and gaze. * @param vrTeleportationOptions options to modify teleportation behavior. */ VRExperienceHelper.prototype.enableTeleportation = function (vrTeleportationOptions) { if (vrTeleportationOptions === void 0) { vrTeleportationOptions = {}; } if (!this._teleportationInitialized) { this._teleportationRequested = true; this.enableInteractions(); if (vrTeleportationOptions.floorMeshName) { this._floorMeshName = vrTeleportationOptions.floorMeshName; } if (vrTeleportationOptions.floorMeshes) { this._floorMeshesCollection = vrTeleportationOptions.floorMeshes; } if (this.leftController != null) { this._enableTeleportationOnController(this.leftController); } if (this.rightController != null) { this._enableTeleportationOnController(this.rightController); } // Creates an image processing post process for the vignette not relying // on the main scene configuration for image processing to reduce setup and spaces // (gamma/linear) conflicts. var imageProcessingConfiguration = new BABYLON.ImageProcessingConfiguration(); imageProcessingConfiguration.vignetteColor = new BABYLON.Color4(0, 0, 0, 0); imageProcessingConfiguration.vignetteEnabled = true; this._postProcessMove = new BABYLON.ImageProcessingPostProcess("postProcessMove", 1.0, this._webVRCamera, undefined, undefined, undefined, undefined, imageProcessingConfiguration); this._webVRCamera.detachPostProcess(this._postProcessMove); this._teleportationInitialized = true; if (this._isDefaultTeleportationTarget) { this._createTeleportationCircles(); this._teleportationTarget.scaling.scaleInPlace(this._webVRCamera.deviceScaleFactor); } } }; VRExperienceHelper.prototype._enableInteractionOnController = function (controller) { var _this = this; var controllerMesh = controller.webVRController.mesh; if (controllerMesh) { controller._interactionsEnabled = true; controller._activatePointer(); controller.webVRController.onMainButtonStateChangedObservable.add(function (stateObject) { // Enabling / disabling laserPointer if (_this._displayLaserPointer && stateObject.value === 1) { if (controller._activePointer) { controller._deactivatePointer(); } else { controller._activatePointer(); } if (_this.displayGaze) { controller._gazeTracker.isVisible = controller._activePointer; } } }); controller.webVRController.onTriggerStateChangedObservable.add(function (stateObject) { if (!controller._pointerDownOnMeshAsked) { if (stateObject.value > _this._padSensibilityUp) { controller._selectionPointerDown(); } } else if (stateObject.value < _this._padSensibilityDown) { controller._selectionPointerUp(); } }); } }; VRExperienceHelper.prototype._checkTeleportWithRay = function (stateObject, gazer) { // Dont teleport if another gaze already requested teleportation if (this._teleportationRequestInitiated && !gazer._teleportationRequestInitiated) { return; } if (!gazer._teleportationRequestInitiated) { if (stateObject.y < -this._padSensibilityUp && gazer._dpadPressed) { gazer._activatePointer(); gazer._teleportationRequestInitiated = true; } } else { // Listening to the proper controller values changes to confirm teleportation if (Math.sqrt(stateObject.y * stateObject.y + stateObject.x * stateObject.x) < this._padSensibilityDown) { if (this._teleportActive) { this._teleportCamera(this._haloCenter); } gazer._teleportationRequestInitiated = false; } } }; VRExperienceHelper.prototype._checkRotate = function (stateObject, gazer) { // Only rotate when user is not currently selecting a teleportation location if (gazer._teleportationRequestInitiated) { return; } if (!this._rotationLeftAsked) { if (stateObject.x < -this._padSensibilityUp && gazer._dpadPressed) { this._rotationLeftAsked = true; if (this._rotationAllowed) { this._rotateCamera(false); } } } else { if (stateObject.x > -this._padSensibilityDown) { this._rotationLeftAsked = false; } } if (!this._rotationRightAsked) { if (stateObject.x > this._padSensibilityUp && gazer._dpadPressed) { this._rotationRightAsked = true; if (this._rotationAllowed) { this._rotateCamera(true); } } } else { if (stateObject.x < this._padSensibilityDown) { this._rotationRightAsked = false; } } }; VRExperienceHelper.prototype._checkTeleportBackwards = function (stateObject, gazer) { // Only teleport backwards when user is not currently selecting a teleportation location if (gazer._teleportationRequestInitiated) { return; } // Teleport backwards if (stateObject.y > this._padSensibilityUp && gazer._dpadPressed) { if (!gazer._teleportationBackRequestInitiated) { if (!this.currentVRCamera) { return; } // Get rotation and position of the current camera var rotation = BABYLON.Quaternion.FromRotationMatrix(this.currentVRCamera.getWorldMatrix().getRotationMatrix()); var position = this.currentVRCamera.position; // If the camera has device position, use that instead if (this.currentVRCamera.devicePosition && this.currentVRCamera.deviceRotationQuaternion) { rotation = this.currentVRCamera.deviceRotationQuaternion; position = this.currentVRCamera.devicePosition; } // Get matrix with only the y rotation of the device rotation rotation.toEulerAnglesToRef(this._workingVector); this._workingVector.z = 0; this._workingVector.x = 0; BABYLON.Quaternion.RotationYawPitchRollToRef(this._workingVector.y, this._workingVector.x, this._workingVector.z, this._workingQuaternion); this._workingQuaternion.toRotationMatrix(this._workingMatrix); // Rotate backwards ray by device rotation to cast at the ground behind the user BABYLON.Vector3.TransformCoordinatesToRef(this._teleportBackwardsVector, this._workingMatrix, this._workingVector); // Teleport if ray hit the ground and is not to far away eg. backwards off a cliff var ray = new BABYLON.Ray(position, this._workingVector); var hit = this._scene.pickWithRay(ray, this._raySelectionPredicate); if (hit && hit.pickedPoint && hit.pickedMesh && this._isTeleportationFloor(hit.pickedMesh) && hit.distance < 5) { this._teleportCamera(hit.pickedPoint); } gazer._teleportationBackRequestInitiated = true; } } else { gazer._teleportationBackRequestInitiated = false; } }; VRExperienceHelper.prototype._enableTeleportationOnController = function (controller) { var _this = this; var controllerMesh = controller.webVRController.mesh; if (controllerMesh) { if (!controller._interactionsEnabled) { this._enableInteractionOnController(controller); } controller._interactionsEnabled = true; controller._teleportationEnabled = true; if (controller.webVRController.controllerType === BABYLON.PoseEnabledControllerType.VIVE) { controller._dpadPressed = false; controller.webVRController.onPadStateChangedObservable.add(function (stateObject) { controller._dpadPressed = stateObject.pressed; if (!controller._dpadPressed) { _this._rotationLeftAsked = false; _this._rotationRightAsked = false; controller._teleportationBackRequestInitiated = false; } }); } controller.webVRController.onPadValuesChangedObservable.add(function (stateObject) { if (_this.teleportationEnabled) { _this._checkTeleportBackwards(stateObject, controller); _this._checkTeleportWithRay(stateObject, controller); } _this._checkRotate(stateObject, controller); }); } }; VRExperienceHelper.prototype._createTeleportationCircles = function () { this._teleportationTarget = BABYLON.Mesh.CreateGround("teleportationTarget", 2, 2, 2, this._scene); this._teleportationTarget.isPickable = false; var length = 512; var dynamicTexture = new BABYLON.DynamicTexture("DynamicTexture", length, this._scene, true); dynamicTexture.hasAlpha = true; var context = dynamicTexture.getContext(); var centerX = length / 2; var centerY = length / 2; var radius = 200; context.beginPath(); context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false); context.fillStyle = this._teleportationFillColor; context.fill(); context.lineWidth = 10; context.strokeStyle = this._teleportationBorderColor; context.stroke(); context.closePath(); dynamicTexture.update(); var teleportationCircleMaterial = new BABYLON.StandardMaterial("TextPlaneMaterial", this._scene); teleportationCircleMaterial.diffuseTexture = dynamicTexture; this._teleportationTarget.material = teleportationCircleMaterial; var torus = BABYLON.Mesh.CreateTorus("torusTeleportation", 0.75, 0.1, 25, this._scene, false); torus.isPickable = false; torus.parent = this._teleportationTarget; var animationInnerCircle = new BABYLON.Animation("animationInnerCircle", "position.y", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE); var keys = []; keys.push({ frame: 0, value: 0 }); keys.push({ frame: 30, value: 0.4 }); keys.push({ frame: 60, value: 0 }); animationInnerCircle.setKeys(keys); var easingFunction = new BABYLON.SineEase(); easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT); animationInnerCircle.setEasingFunction(easingFunction); torus.animations = []; torus.animations.push(animationInnerCircle); this._scene.beginAnimation(torus, 0, 60, true); this._hideTeleportationTarget(); }; VRExperienceHelper.prototype._displayTeleportationTarget = function () { this._teleportActive = true; if (this._teleportationInitialized) { this._teleportationTarget.isVisible = true; if (this._isDefaultTeleportationTarget) { this._teleportationTarget.getChildren()[0].isVisible = true; } } }; VRExperienceHelper.prototype._hideTeleportationTarget = function () { this._teleportActive = false; if (this._teleportationInitialized) { this._teleportationTarget.isVisible = false; if (this._isDefaultTeleportationTarget) { this._teleportationTarget.getChildren()[0].isVisible = false; } } }; VRExperienceHelper.prototype._rotateCamera = function (right) { var _this = this; if (!(this.currentVRCamera instanceof BABYLON.FreeCamera)) { return; } if (right) { this._rotationAngle++; } else { this._rotationAngle--; } this.currentVRCamera.animations = []; var target = BABYLON.Quaternion.FromRotationMatrix(BABYLON.Matrix.RotationY(Math.PI / 4 * this._rotationAngle)); var animationRotation = new BABYLON.Animation("animationRotation", "rotationQuaternion", 90, BABYLON.Animation.ANIMATIONTYPE_QUATERNION, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT); var animationRotationKeys = []; animationRotationKeys.push({ frame: 0, value: this.currentVRCamera.rotationQuaternion }); animationRotationKeys.push({ frame: 6, value: target }); animationRotation.setKeys(animationRotationKeys); animationRotation.setEasingFunction(this._circleEase); this.currentVRCamera.animations.push(animationRotation); this._postProcessMove.animations = []; var animationPP = new BABYLON.Animation("animationPP", "vignetteWeight", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT); var vignetteWeightKeys = []; vignetteWeightKeys.push({ frame: 0, value: 0 }); vignetteWeightKeys.push({ frame: 3, value: 4 }); vignetteWeightKeys.push({ frame: 6, value: 0 }); animationPP.setKeys(vignetteWeightKeys); animationPP.setEasingFunction(this._circleEase); this._postProcessMove.animations.push(animationPP); var animationPP2 = new BABYLON.Animation("animationPP2", "vignetteStretch", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT); var vignetteStretchKeys = []; vignetteStretchKeys.push({ frame: 0, value: 0 }); vignetteStretchKeys.push({ frame: 3, value: 10 }); vignetteStretchKeys.push({ frame: 6, value: 0 }); animationPP2.setKeys(vignetteStretchKeys); animationPP2.setEasingFunction(this._circleEase); this._postProcessMove.animations.push(animationPP2); this._postProcessMove.imageProcessingConfiguration.vignetteWeight = 0; this._postProcessMove.imageProcessingConfiguration.vignetteStretch = 0; this._postProcessMove.samples = 4; this._webVRCamera.attachPostProcess(this._postProcessMove); this._scene.beginAnimation(this._postProcessMove, 0, 6, false, 1, function () { _this._webVRCamera.detachPostProcess(_this._postProcessMove); }); this._scene.beginAnimation(this.currentVRCamera, 0, 6, false, 1); }; VRExperienceHelper.prototype._moveTeleportationSelectorTo = function (hit, gazer) { if (hit.pickedPoint) { if (gazer._teleportationRequestInitiated) { this._displayTeleportationTarget(); this._haloCenter.copyFrom(hit.pickedPoint); this._teleportationTarget.position.copyFrom(hit.pickedPoint); } var pickNormal = hit.getNormal(true, false); if (pickNormal) { var axis1 = BABYLON.Vector3.Cross(BABYLON.Axis.Y, pickNormal); var axis2 = BABYLON.Vector3.Cross(pickNormal, axis1); BABYLON.Vector3.RotationFromAxisToRef(axis2, pickNormal, axis1, this._teleportationTarget.rotation); } this._teleportationTarget.position.y += 0.1; } }; VRExperienceHelper.prototype._teleportCamera = function (location) { var _this = this; if (!(this.currentVRCamera instanceof BABYLON.FreeCamera)) { return; } // Teleport the hmd to where the user is looking by moving the anchor to where they are looking minus the // offset of the headset from the anchor. if (this.webVRCamera.leftCamera) { this._workingVector.copyFrom(this.webVRCamera.leftCamera.globalPosition); this._workingVector.subtractInPlace(this.webVRCamera.position); location.subtractToRef(this._workingVector, this._workingVector); } else { this._workingVector.copyFrom(location); } // Add height to account for user's height offset if (this.isInVRMode) { this._workingVector.y += this.webVRCamera.deviceDistanceToRoomGround() * this._webVRCamera.deviceScaleFactor; } else { this._workingVector.y += this._defaultHeight; } this.onBeforeCameraTeleport.notifyObservers(this._workingVector); // Create animation from the camera's position to the new location this.currentVRCamera.animations = []; var animationCameraTeleportation = new BABYLON.Animation("animationCameraTeleportation", "position", 90, BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT); var animationCameraTeleportationKeys = [{ frame: 0, value: this.currentVRCamera.position }, { frame: 11, value: this._workingVector } ]; animationCameraTeleportation.setKeys(animationCameraTeleportationKeys); animationCameraTeleportation.setEasingFunction(this._circleEase); this.currentVRCamera.animations.push(animationCameraTeleportation); this._postProcessMove.animations = []; var animationPP = new BABYLON.Animation("animationPP", "vignetteWeight", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT); var vignetteWeightKeys = []; vignetteWeightKeys.push({ frame: 0, value: 0 }); vignetteWeightKeys.push({ frame: 5, value: 8 }); vignetteWeightKeys.push({ frame: 11, value: 0 }); animationPP.setKeys(vignetteWeightKeys); this._postProcessMove.animations.push(animationPP); var animationPP2 = new BABYLON.Animation("animationPP2", "vignetteStretch", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT); var vignetteStretchKeys = []; vignetteStretchKeys.push({ frame: 0, value: 0 }); vignetteStretchKeys.push({ frame: 5, value: 10 }); vignetteStretchKeys.push({ frame: 11, value: 0 }); animationPP2.setKeys(vignetteStretchKeys); this._postProcessMove.animations.push(animationPP2); this._postProcessMove.imageProcessingConfiguration.vignetteWeight = 0; this._postProcessMove.imageProcessingConfiguration.vignetteStretch = 0; this._webVRCamera.attachPostProcess(this._postProcessMove); this._scene.beginAnimation(this._postProcessMove, 0, 11, false, 1, function () { _this._webVRCamera.detachPostProcess(_this._postProcessMove); }); this._scene.beginAnimation(this.currentVRCamera, 0, 11, false, 1, function () { _this.onAfterCameraTeleport.notifyObservers(_this._workingVector); }); this._hideTeleportationTarget(); }; VRExperienceHelper.prototype._castRayAndSelectObject = function (gazer) { if (!(this.currentVRCamera instanceof BABYLON.FreeCamera)) { return; } var hit = this._scene.pickWithRay(gazer._getForwardRay(this._rayLength), this._raySelectionPredicate); // Moving the gazeTracker on the mesh face targetted if (hit && hit.pickedPoint) { if (this._displayGaze) { var multiplier = 1; gazer._gazeTracker.isVisible = true; if (gazer._isActionableMesh) { multiplier = 3; } gazer._gazeTracker.scaling.x = hit.distance * multiplier; gazer._gazeTracker.scaling.y = hit.distance * multiplier; gazer._gazeTracker.scaling.z = hit.distance * multiplier; var pickNormal = hit.getNormal(); // To avoid z-fighting var deltaFighting = 0.002; if (pickNormal) { var axis1 = BABYLON.Vector3.Cross(BABYLON.Axis.Y, pickNormal); var axis2 = BABYLON.Vector3.Cross(pickNormal, axis1); BABYLON.Vector3.RotationFromAxisToRef(axis2, pickNormal, axis1, gazer._gazeTracker.rotation); } gazer._gazeTracker.position.copyFrom(hit.pickedPoint); if (gazer._gazeTracker.position.x < 0) { gazer._gazeTracker.position.x += deltaFighting; } else { gazer._gazeTracker.position.x -= deltaFighting; } if (gazer._gazeTracker.position.y < 0) { gazer._gazeTracker.position.y += deltaFighting; } else { gazer._gazeTracker.position.y -= deltaFighting; } if (gazer._gazeTracker.position.z < 0) { gazer._gazeTracker.position.z += deltaFighting; } else { gazer._gazeTracker.position.z -= deltaFighting; } } // Changing the size of the laser pointer based on the distance from the targetted point gazer._updatePointerDistance(hit.distance); } else { gazer._gazeTracker.isVisible = false; } if (hit && hit.pickedMesh) { gazer._currentHit = hit; if (gazer._pointerDownOnMeshAsked) { this._scene.simulatePointerMove(gazer._currentHit, { pointerId: gazer._id }); } // The object selected is the floor, we're in a teleportation scenario if (this._teleportationInitialized && this._isTeleportationFloor(hit.pickedMesh) && hit.pickedPoint) { // Moving the teleportation area to this targetted point //Raise onSelectedMeshUnselected observable if ray collided floor mesh/meshes and a non floor mesh was previously selected if (gazer._currentMeshSelected && !this._isTeleportationFloor(gazer._currentMeshSelected)) { this._notifySelectedMeshUnselected(gazer._currentMeshSelected); } gazer._currentMeshSelected = null; if (gazer._teleportationRequestInitiated) { this._moveTeleportationSelectorTo(hit, gazer); } return; } // If not, we're in a selection scenario //this._teleportationAllowed = false; if (hit.pickedMesh !== gazer._currentMeshSelected) { if (this.meshSelectionPredicate(hit.pickedMesh)) { this.onNewMeshPicked.notifyObservers(hit); gazer._currentMeshSelected = hit.pickedMesh; if (hit.pickedMesh.isPickable && hit.pickedMesh.actionManager) { this.changeGazeColor(new BABYLON.Color3(0, 0, 1)); this.changeLaserColor(new BABYLON.Color3(0.2, 0.2, 1)); gazer._isActionableMesh = true; } else { this.changeGazeColor(new BABYLON.Color3(0.7, 0.7, 0.7)); this.changeLaserColor(new BABYLON.Color3(0.7, 0.7, 0.7)); gazer._isActionableMesh = false; } try { this.onNewMeshSelected.notifyObservers(hit.pickedMesh); } catch (err) { BABYLON.Tools.Warn("Error in your custom logic onNewMeshSelected: " + err); } } else { this._notifySelectedMeshUnselected(gazer._currentMeshSelected); gazer._currentMeshSelected = null; this.changeGazeColor(new BABYLON.Color3(0.7, 0.7, 0.7)); this.changeLaserColor(new BABYLON.Color3(0.7, 0.7, 0.7)); } } } else { gazer._currentHit = null; this._notifySelectedMeshUnselected(gazer._currentMeshSelected); gazer._currentMeshSelected = null; //this._teleportationAllowed = false; this.changeGazeColor(new BABYLON.Color3(0.7, 0.7, 0.7)); this.changeLaserColor(new BABYLON.Color3(0.7, 0.7, 0.7)); } }; VRExperienceHelper.prototype._notifySelectedMeshUnselected = function (mesh) { if (mesh) { this.onSelectedMeshUnselected.notifyObservers(mesh); } }; /** * Sets the color of the laser ray from the vr controllers. * @param color new color for the ray. */ VRExperienceHelper.prototype.changeLaserColor = function (color) { if (this.leftController) { this.leftController._setLaserPointerColor(color); } if (this.rightController) { this.rightController._setLaserPointerColor(color); } }; /** * Sets the color of the ray from the vr headsets gaze. * @param color new color for the ray. */ VRExperienceHelper.prototype.changeGazeColor = function (color) { if (!this._cameraGazer._gazeTracker.material) { return; } this._cameraGazer._gazeTracker.material.emissiveColor = color; if (this.leftController) { this.leftController._gazeTracker.material.emissiveColor = color; } if (this.rightController) { this.rightController._gazeTracker.material.emissiveColor = color; } }; /** * Exits VR and disposes of the vr experience helper */ VRExperienceHelper.prototype.dispose = function () { if (this.isInVRMode) { this.exitVR(); } if (this._postProcessMove) { this._postProcessMove.dispose(); } if (this._webVRCamera) { this._webVRCamera.dispose(); } if (this._vrDeviceOrientationCamera) { this._vrDeviceOrientationCamera.dispose(); } if (!this._useCustomVRButton && this._btnVR.parentNode) { document.body.removeChild(this._btnVR); } if (this._deviceOrientationCamera && (this._scene.activeCamera != this._deviceOrientationCamera)) { this._deviceOrientationCamera.dispose(); } if (this._cameraGazer) { this._cameraGazer.dispose(); } if (this.leftController) { this.leftController.dispose(); } if (this.rightController) { this.rightController.dispose(); } if (this._teleportationTarget) { this._teleportationTarget.dispose(); } this._floorMeshesCollection = []; document.removeEventListener("keydown", this._onKeyDown); window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange); window.removeEventListener("resize", this._onResize); document.removeEventListener("fullscreenchange", this._onFullscreenChange); document.removeEventListener("mozfullscreenchange", this._onFullscreenChange); document.removeEventListener("webkitfullscreenchange", this._onFullscreenChange); document.removeEventListener("msfullscreenchange", this._onFullscreenChange); this._scene.getEngine().onVRDisplayChangedObservable.removeCallback(this._onVRDisplayChanged); this._scene.getEngine().onVRRequestPresentStart.removeCallback(this._onVRRequestPresentStart); this._scene.getEngine().onVRRequestPresentComplete.removeCallback(this._onVRRequestPresentComplete); window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange); this._scene.gamepadManager.onGamepadConnectedObservable.removeCallback(this._onNewGamepadConnected); this._scene.gamepadManager.onGamepadDisconnectedObservable.removeCallback(this._onNewGamepadDisconnected); this._scene.unregisterBeforeRender(this.beforeRender); }; /** * Gets the name of the VRExperienceHelper class * @returns "VRExperienceHelper" */ VRExperienceHelper.prototype.getClassName = function () { return "VRExperienceHelper"; }; return VRExperienceHelper; }()); BABYLON.VRExperienceHelper = VRExperienceHelper; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.vrExperienceHelper.js.map // Mainly based on these 2 articles : // Creating an universal virtual touch joystick working for all Touch models thanks to Hand.JS : http://blogs.msdn.com/b/davrous/archive/2013/02/22/creating-an-universal-virtual-touch-joystick-working-for-all-touch-models-thanks-to-hand-js.aspx // & on Seb Lee-Delisle original work: http://seb.ly/2011/04/multi-touch-game-controller-in-javascripthtml5-for-ipad/ var BABYLON; (function (BABYLON) { var JoystickAxis; (function (JoystickAxis) { JoystickAxis[JoystickAxis["X"] = 0] = "X"; JoystickAxis[JoystickAxis["Y"] = 1] = "Y"; JoystickAxis[JoystickAxis["Z"] = 2] = "Z"; })(JoystickAxis = BABYLON.JoystickAxis || (BABYLON.JoystickAxis = {})); var VirtualJoystick = /** @class */ (function () { function VirtualJoystick(leftJoystick) { var _this = this; if (leftJoystick) { this._leftJoystick = true; } else { this._leftJoystick = false; } VirtualJoystick._globalJoystickIndex++; // By default left & right arrow keys are moving the X // and up & down keys are moving the Y this._axisTargetedByLeftAndRight = JoystickAxis.X; this._axisTargetedByUpAndDown = JoystickAxis.Y; this.reverseLeftRight = false; this.reverseUpDown = false; // collections of pointers this._touches = new BABYLON.StringDictionary(); this.deltaPosition = BABYLON.Vector3.Zero(); this._joystickSensibility = 25; this._inversedSensibility = 1 / (this._joystickSensibility / 1000); this._onResize = function (evt) { VirtualJoystick.vjCanvasWidth = window.innerWidth; VirtualJoystick.vjCanvasHeight = window.innerHeight; if (VirtualJoystick.vjCanvas) { VirtualJoystick.vjCanvas.width = VirtualJoystick.vjCanvasWidth; VirtualJoystick.vjCanvas.height = VirtualJoystick.vjCanvasHeight; } VirtualJoystick.halfWidth = VirtualJoystick.vjCanvasWidth / 2; }; // injecting a canvas element on top of the canvas 3D game if (!VirtualJoystick.vjCanvas) { window.addEventListener("resize", this._onResize, false); VirtualJoystick.vjCanvas = document.createElement("canvas"); VirtualJoystick.vjCanvasWidth = window.innerWidth; VirtualJoystick.vjCanvasHeight = window.innerHeight; VirtualJoystick.vjCanvas.width = window.innerWidth; VirtualJoystick.vjCanvas.height = window.innerHeight; VirtualJoystick.vjCanvas.style.width = "100%"; VirtualJoystick.vjCanvas.style.height = "100%"; VirtualJoystick.vjCanvas.style.position = "absolute"; VirtualJoystick.vjCanvas.style.backgroundColor = "transparent"; VirtualJoystick.vjCanvas.style.top = "0px"; VirtualJoystick.vjCanvas.style.left = "0px"; VirtualJoystick.vjCanvas.style.zIndex = "5"; VirtualJoystick.vjCanvas.style.msTouchAction = "none"; // Support for jQuery PEP polyfill VirtualJoystick.vjCanvas.setAttribute("touch-action", "none"); var context = VirtualJoystick.vjCanvas.getContext('2d'); if (!context) { throw new Error("Unable to create canvas for virtual joystick"); } VirtualJoystick.vjCanvasContext = context; VirtualJoystick.vjCanvasContext.strokeStyle = "#ffffff"; VirtualJoystick.vjCanvasContext.lineWidth = 2; document.body.appendChild(VirtualJoystick.vjCanvas); } VirtualJoystick.halfWidth = VirtualJoystick.vjCanvas.width / 2; this.pressed = false; // default joystick color this._joystickColor = "cyan"; this._joystickPointerID = -1; // current joystick position this._joystickPointerPos = new BABYLON.Vector2(0, 0); this._joystickPreviousPointerPos = new BABYLON.Vector2(0, 0); // origin joystick position this._joystickPointerStartPos = new BABYLON.Vector2(0, 0); this._deltaJoystickVector = new BABYLON.Vector2(0, 0); this._onPointerDownHandlerRef = function (evt) { _this._onPointerDown(evt); }; this._onPointerMoveHandlerRef = function (evt) { _this._onPointerMove(evt); }; this._onPointerUpHandlerRef = function (evt) { _this._onPointerUp(evt); }; VirtualJoystick.vjCanvas.addEventListener('pointerdown', this._onPointerDownHandlerRef, false); VirtualJoystick.vjCanvas.addEventListener('pointermove', this._onPointerMoveHandlerRef, false); VirtualJoystick.vjCanvas.addEventListener('pointerup', this._onPointerUpHandlerRef, false); VirtualJoystick.vjCanvas.addEventListener('pointerout', this._onPointerUpHandlerRef, false); VirtualJoystick.vjCanvas.addEventListener("contextmenu", function (evt) { evt.preventDefault(); // Disables system menu }, false); requestAnimationFrame(function () { _this._drawVirtualJoystick(); }); } VirtualJoystick.prototype.setJoystickSensibility = function (newJoystickSensibility) { this._joystickSensibility = newJoystickSensibility; this._inversedSensibility = 1 / (this._joystickSensibility / 1000); }; VirtualJoystick.prototype._onPointerDown = function (e) { var positionOnScreenCondition; e.preventDefault(); if (this._leftJoystick === true) { positionOnScreenCondition = (e.clientX < VirtualJoystick.halfWidth); } else { positionOnScreenCondition = (e.clientX > VirtualJoystick.halfWidth); } if (positionOnScreenCondition && this._joystickPointerID < 0) { // First contact will be dedicated to the virtual joystick this._joystickPointerID = e.pointerId; this._joystickPointerStartPos.x = e.clientX; this._joystickPointerStartPos.y = e.clientY; this._joystickPointerPos = this._joystickPointerStartPos.clone(); this._joystickPreviousPointerPos = this._joystickPointerStartPos.clone(); this._deltaJoystickVector.x = 0; this._deltaJoystickVector.y = 0; this.pressed = true; this._touches.add(e.pointerId.toString(), e); } else { // You can only trigger the action buttons with a joystick declared if (VirtualJoystick._globalJoystickIndex < 2 && this._action) { this._action(); this._touches.add(e.pointerId.toString(), { x: e.clientX, y: e.clientY, prevX: e.clientX, prevY: e.clientY }); } } }; VirtualJoystick.prototype._onPointerMove = function (e) { // If the current pointer is the one associated to the joystick (first touch contact) if (this._joystickPointerID == e.pointerId) { this._joystickPointerPos.x = e.clientX; this._joystickPointerPos.y = e.clientY; this._deltaJoystickVector = this._joystickPointerPos.clone(); this._deltaJoystickVector = this._deltaJoystickVector.subtract(this._joystickPointerStartPos); var directionLeftRight = this.reverseLeftRight ? -1 : 1; var deltaJoystickX = directionLeftRight * this._deltaJoystickVector.x / this._inversedSensibility; switch (this._axisTargetedByLeftAndRight) { case JoystickAxis.X: this.deltaPosition.x = Math.min(1, Math.max(-1, deltaJoystickX)); break; case JoystickAxis.Y: this.deltaPosition.y = Math.min(1, Math.max(-1, deltaJoystickX)); break; case JoystickAxis.Z: this.deltaPosition.z = Math.min(1, Math.max(-1, deltaJoystickX)); break; } var directionUpDown = this.reverseUpDown ? 1 : -1; var deltaJoystickY = directionUpDown * this._deltaJoystickVector.y / this._inversedSensibility; switch (this._axisTargetedByUpAndDown) { case JoystickAxis.X: this.deltaPosition.x = Math.min(1, Math.max(-1, deltaJoystickY)); break; case JoystickAxis.Y: this.deltaPosition.y = Math.min(1, Math.max(-1, deltaJoystickY)); break; case JoystickAxis.Z: this.deltaPosition.z = Math.min(1, Math.max(-1, deltaJoystickY)); break; } } else { var data = this._touches.get(e.pointerId.toString()); if (data) { data.x = e.clientX; data.y = e.clientY; } } }; VirtualJoystick.prototype._onPointerUp = function (e) { if (this._joystickPointerID == e.pointerId) { VirtualJoystick.vjCanvasContext.clearRect(this._joystickPointerStartPos.x - 64, this._joystickPointerStartPos.y - 64, 128, 128); VirtualJoystick.vjCanvasContext.clearRect(this._joystickPreviousPointerPos.x - 42, this._joystickPreviousPointerPos.y - 42, 84, 84); this._joystickPointerID = -1; this.pressed = false; } else { var touch = this._touches.get(e.pointerId.toString()); if (touch) { VirtualJoystick.vjCanvasContext.clearRect(touch.prevX - 44, touch.prevY - 44, 88, 88); } } this._deltaJoystickVector.x = 0; this._deltaJoystickVector.y = 0; this._touches.remove(e.pointerId.toString()); }; /** * Change the color of the virtual joystick * @param newColor a string that must be a CSS color value (like "red") or the hexa value (like "#FF0000") */ VirtualJoystick.prototype.setJoystickColor = function (newColor) { this._joystickColor = newColor; }; VirtualJoystick.prototype.setActionOnTouch = function (action) { this._action = action; }; // Define which axis you'd like to control for left & right VirtualJoystick.prototype.setAxisForLeftRight = function (axis) { switch (axis) { case JoystickAxis.X: case JoystickAxis.Y: case JoystickAxis.Z: this._axisTargetedByLeftAndRight = axis; break; default: this._axisTargetedByLeftAndRight = JoystickAxis.X; break; } }; // Define which axis you'd like to control for up & down VirtualJoystick.prototype.setAxisForUpDown = function (axis) { switch (axis) { case JoystickAxis.X: case JoystickAxis.Y: case JoystickAxis.Z: this._axisTargetedByUpAndDown = axis; break; default: this._axisTargetedByUpAndDown = JoystickAxis.Y; break; } }; VirtualJoystick.prototype._drawVirtualJoystick = function () { var _this = this; if (this.pressed) { this._touches.forEach(function (key, touch) { if (touch.pointerId === _this._joystickPointerID) { VirtualJoystick.vjCanvasContext.clearRect(_this._joystickPointerStartPos.x - 64, _this._joystickPointerStartPos.y - 64, 128, 128); VirtualJoystick.vjCanvasContext.clearRect(_this._joystickPreviousPointerPos.x - 42, _this._joystickPreviousPointerPos.y - 42, 84, 84); VirtualJoystick.vjCanvasContext.beginPath(); VirtualJoystick.vjCanvasContext.lineWidth = 6; VirtualJoystick.vjCanvasContext.strokeStyle = _this._joystickColor; VirtualJoystick.vjCanvasContext.arc(_this._joystickPointerStartPos.x, _this._joystickPointerStartPos.y, 40, 0, Math.PI * 2, true); VirtualJoystick.vjCanvasContext.stroke(); VirtualJoystick.vjCanvasContext.closePath(); VirtualJoystick.vjCanvasContext.beginPath(); VirtualJoystick.vjCanvasContext.strokeStyle = _this._joystickColor; VirtualJoystick.vjCanvasContext.lineWidth = 2; VirtualJoystick.vjCanvasContext.arc(_this._joystickPointerStartPos.x, _this._joystickPointerStartPos.y, 60, 0, Math.PI * 2, true); VirtualJoystick.vjCanvasContext.stroke(); VirtualJoystick.vjCanvasContext.closePath(); VirtualJoystick.vjCanvasContext.beginPath(); VirtualJoystick.vjCanvasContext.strokeStyle = _this._joystickColor; VirtualJoystick.vjCanvasContext.arc(_this._joystickPointerPos.x, _this._joystickPointerPos.y, 40, 0, Math.PI * 2, true); VirtualJoystick.vjCanvasContext.stroke(); VirtualJoystick.vjCanvasContext.closePath(); _this._joystickPreviousPointerPos = _this._joystickPointerPos.clone(); } else { VirtualJoystick.vjCanvasContext.clearRect(touch.prevX - 44, touch.prevY - 44, 88, 88); VirtualJoystick.vjCanvasContext.beginPath(); VirtualJoystick.vjCanvasContext.fillStyle = "white"; VirtualJoystick.vjCanvasContext.beginPath(); VirtualJoystick.vjCanvasContext.strokeStyle = "red"; VirtualJoystick.vjCanvasContext.lineWidth = 6; VirtualJoystick.vjCanvasContext.arc(touch.x, touch.y, 40, 0, Math.PI * 2, true); VirtualJoystick.vjCanvasContext.stroke(); VirtualJoystick.vjCanvasContext.closePath(); touch.prevX = touch.x; touch.prevY = touch.y; } ; }); } requestAnimationFrame(function () { _this._drawVirtualJoystick(); }); }; VirtualJoystick.prototype.releaseCanvas = function () { if (VirtualJoystick.vjCanvas) { VirtualJoystick.vjCanvas.removeEventListener('pointerdown', this._onPointerDownHandlerRef); VirtualJoystick.vjCanvas.removeEventListener('pointermove', this._onPointerMoveHandlerRef); VirtualJoystick.vjCanvas.removeEventListener('pointerup', this._onPointerUpHandlerRef); VirtualJoystick.vjCanvas.removeEventListener('pointerout', this._onPointerUpHandlerRef); window.removeEventListener("resize", this._onResize); document.body.removeChild(VirtualJoystick.vjCanvas); VirtualJoystick.vjCanvas = null; } }; // Used to draw the virtual joystick inside a 2D canvas on top of the WebGL rendering canvas VirtualJoystick._globalJoystickIndex = 0; return VirtualJoystick; }()); BABYLON.VirtualJoystick = VirtualJoystick; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.virtualJoystick.js.map var BABYLON; (function (BABYLON) { // We're mainly based on the logic defined into the FreeCamera code var VirtualJoysticksCamera = /** @class */ (function (_super) { __extends(VirtualJoysticksCamera, _super); function VirtualJoysticksCamera(name, position, scene) { var _this = _super.call(this, name, position, scene) || this; _this.inputs.addVirtualJoystick(); return _this; } VirtualJoysticksCamera.prototype.getClassName = function () { return "VirtualJoysticksCamera"; }; return VirtualJoysticksCamera; }(BABYLON.FreeCamera)); BABYLON.VirtualJoysticksCamera = VirtualJoysticksCamera; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.virtualJoysticksCamera.js.map var BABYLON; (function (BABYLON) { var FreeCameraVirtualJoystickInput = /** @class */ (function () { function FreeCameraVirtualJoystickInput() { } FreeCameraVirtualJoystickInput.prototype.getLeftJoystick = function () { return this._leftjoystick; }; FreeCameraVirtualJoystickInput.prototype.getRightJoystick = function () { return this._rightjoystick; }; FreeCameraVirtualJoystickInput.prototype.checkInputs = function () { if (this._leftjoystick) { var camera = this.camera; var speed = camera._computeLocalCameraSpeed() * 50; var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(camera.rotation.y, camera.rotation.x, 0); var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(this._leftjoystick.deltaPosition.x * speed, this._leftjoystick.deltaPosition.y * speed, this._leftjoystick.deltaPosition.z * speed), cameraTransform); camera.cameraDirection = camera.cameraDirection.add(deltaTransform); camera.cameraRotation = camera.cameraRotation.addVector3(this._rightjoystick.deltaPosition); if (!this._leftjoystick.pressed) { this._leftjoystick.deltaPosition = this._leftjoystick.deltaPosition.scale(0.9); } if (!this._rightjoystick.pressed) { this._rightjoystick.deltaPosition = this._rightjoystick.deltaPosition.scale(0.9); } } }; FreeCameraVirtualJoystickInput.prototype.attachControl = function (element, noPreventDefault) { this._leftjoystick = new BABYLON.VirtualJoystick(true); this._leftjoystick.setAxisForUpDown(BABYLON.JoystickAxis.Z); this._leftjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.X); this._leftjoystick.setJoystickSensibility(0.15); this._rightjoystick = new BABYLON.VirtualJoystick(false); this._rightjoystick.setAxisForUpDown(BABYLON.JoystickAxis.X); this._rightjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.Y); this._rightjoystick.reverseUpDown = true; this._rightjoystick.setJoystickSensibility(0.05); this._rightjoystick.setJoystickColor("yellow"); }; FreeCameraVirtualJoystickInput.prototype.detachControl = function (element) { this._leftjoystick.releaseCanvas(); this._rightjoystick.releaseCanvas(); }; FreeCameraVirtualJoystickInput.prototype.getClassName = function () { return "FreeCameraVirtualJoystickInput"; }; FreeCameraVirtualJoystickInput.prototype.getSimpleName = function () { return "virtualJoystick"; }; return FreeCameraVirtualJoystickInput; }()); BABYLON.FreeCameraVirtualJoystickInput = FreeCameraVirtualJoystickInput; BABYLON.CameraInputTypes["FreeCameraVirtualJoystickInput"] = FreeCameraVirtualJoystickInput; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.freeCameraVirtualJoystickInput.js.map var BABYLON; (function (BABYLON) { var SimplificationSettings = /** @class */ (function () { function SimplificationSettings(quality, distance, optimizeMesh) { this.quality = quality; this.distance = distance; this.optimizeMesh = optimizeMesh; } return SimplificationSettings; }()); BABYLON.SimplificationSettings = SimplificationSettings; var SimplificationQueue = /** @class */ (function () { function SimplificationQueue() { this.running = false; this._simplificationArray = []; } SimplificationQueue.prototype.addTask = function (task) { this._simplificationArray.push(task); }; SimplificationQueue.prototype.executeNext = function () { var task = this._simplificationArray.pop(); if (task) { this.running = true; this.runSimplification(task); } else { this.running = false; } }; SimplificationQueue.prototype.runSimplification = function (task) { var _this = this; if (task.parallelProcessing) { //parallel simplifier task.settings.forEach(function (setting) { var simplifier = _this.getSimplifier(task); simplifier.simplify(setting, function (newMesh) { task.mesh.addLODLevel(setting.distance, newMesh); newMesh.isVisible = true; //check if it is the last if (setting.quality === task.settings[task.settings.length - 1].quality && task.successCallback) { //all done, run the success callback. task.successCallback(); } _this.executeNext(); }); }); } else { //single simplifier. var simplifier = this.getSimplifier(task); var runDecimation = function (setting, callback) { simplifier.simplify(setting, function (newMesh) { task.mesh.addLODLevel(setting.distance, newMesh); newMesh.isVisible = true; //run the next quality level callback(); }); }; BABYLON.AsyncLoop.Run(task.settings.length, function (loop) { runDecimation(task.settings[loop.index], function () { loop.executeNext(); }); }, function () { //execution ended, run the success callback. if (task.successCallback) { task.successCallback(); } _this.executeNext(); }); } }; SimplificationQueue.prototype.getSimplifier = function (task) { switch (task.simplificationType) { case SimplificationType.QUADRATIC: default: return new QuadraticErrorSimplification(task.mesh); } }; return SimplificationQueue; }()); BABYLON.SimplificationQueue = SimplificationQueue; /** * The implemented types of simplification. * At the moment only Quadratic Error Decimation is implemented. */ var SimplificationType; (function (SimplificationType) { SimplificationType[SimplificationType["QUADRATIC"] = 0] = "QUADRATIC"; })(SimplificationType = BABYLON.SimplificationType || (BABYLON.SimplificationType = {})); var DecimationTriangle = /** @class */ (function () { function DecimationTriangle(vertices) { this.vertices = vertices; this.error = new Array(4); this.deleted = false; this.isDirty = false; this.deletePending = false; this.borderFactor = 0; } return DecimationTriangle; }()); BABYLON.DecimationTriangle = DecimationTriangle; var DecimationVertex = /** @class */ (function () { function DecimationVertex(position, id) { this.position = position; this.id = id; this.isBorder = true; this.q = new QuadraticMatrix(); this.triangleCount = 0; this.triangleStart = 0; this.originalOffsets = []; } DecimationVertex.prototype.updatePosition = function (newPosition) { this.position.copyFrom(newPosition); }; return DecimationVertex; }()); BABYLON.DecimationVertex = DecimationVertex; var QuadraticMatrix = /** @class */ (function () { function QuadraticMatrix(data) { this.data = new Array(10); for (var i = 0; i < 10; ++i) { if (data && data[i]) { this.data[i] = data[i]; } else { this.data[i] = 0; } } } QuadraticMatrix.prototype.det = function (a11, a12, a13, a21, a22, a23, a31, a32, a33) { var det = this.data[a11] * this.data[a22] * this.data[a33] + this.data[a13] * this.data[a21] * this.data[a32] + this.data[a12] * this.data[a23] * this.data[a31] - this.data[a13] * this.data[a22] * this.data[a31] - this.data[a11] * this.data[a23] * this.data[a32] - this.data[a12] * this.data[a21] * this.data[a33]; return det; }; QuadraticMatrix.prototype.addInPlace = function (matrix) { for (var i = 0; i < 10; ++i) { this.data[i] += matrix.data[i]; } }; QuadraticMatrix.prototype.addArrayInPlace = function (data) { for (var i = 0; i < 10; ++i) { this.data[i] += data[i]; } }; QuadraticMatrix.prototype.add = function (matrix) { var m = new QuadraticMatrix(); for (var i = 0; i < 10; ++i) { m.data[i] = this.data[i] + matrix.data[i]; } return m; }; QuadraticMatrix.FromData = function (a, b, c, d) { return new QuadraticMatrix(QuadraticMatrix.DataFromNumbers(a, b, c, d)); }; //returning an array to avoid garbage collection QuadraticMatrix.DataFromNumbers = function (a, b, c, d) { return [a * a, a * b, a * c, a * d, b * b, b * c, b * d, c * c, c * d, d * d]; }; return QuadraticMatrix; }()); BABYLON.QuadraticMatrix = QuadraticMatrix; var Reference = /** @class */ (function () { function Reference(vertexId, triangleId) { this.vertexId = vertexId; this.triangleId = triangleId; } return Reference; }()); BABYLON.Reference = Reference; /** * An implementation of the Quadratic Error simplification algorithm. * Original paper : http://www1.cs.columbia.edu/~cs4162/html05s/garland97.pdf * Ported mostly from QSlim and http://voxels.blogspot.de/2014/05/quadric-mesh-simplification-with-source.html to babylon JS * @author RaananW */ var QuadraticErrorSimplification = /** @class */ (function () { function QuadraticErrorSimplification(_mesh) { this._mesh = _mesh; this.syncIterations = 5000; this.aggressiveness = 7; this.decimationIterations = 100; this.boundingBoxEpsilon = BABYLON.Epsilon; } QuadraticErrorSimplification.prototype.simplify = function (settings, successCallback) { var _this = this; this.initDecimatedMesh(); //iterating through the submeshes array, one after the other. BABYLON.AsyncLoop.Run(this._mesh.subMeshes.length, function (loop) { _this.initWithMesh(loop.index, function () { _this.runDecimation(settings, loop.index, function () { loop.executeNext(); }); }, settings.optimizeMesh); }, function () { setTimeout(function () { successCallback(_this._reconstructedMesh); }, 0); }); }; QuadraticErrorSimplification.prototype.runDecimation = function (settings, submeshIndex, successCallback) { var _this = this; var targetCount = ~~(this.triangles.length * settings.quality); var deletedTriangles = 0; var triangleCount = this.triangles.length; var iterationFunction = function (iteration, callback) { setTimeout(function () { if (iteration % 5 === 0) { _this.updateMesh(iteration === 0); } for (var i = 0; i < _this.triangles.length; ++i) { _this.triangles[i].isDirty = false; } var threshold = 0.000000001 * Math.pow((iteration + 3), _this.aggressiveness); var trianglesIterator = function (i) { var tIdx = ~~(((_this.triangles.length / 2) + i) % _this.triangles.length); var t = _this.triangles[tIdx]; if (!t) return; if (t.error[3] > threshold || t.deleted || t.isDirty) { return; } for (var j = 0; j < 3; ++j) { if (t.error[j] < threshold) { var deleted0 = []; var deleted1 = []; var v0 = t.vertices[j]; var v1 = t.vertices[(j + 1) % 3]; if (v0.isBorder || v1.isBorder) continue; var p = BABYLON.Vector3.Zero(); var n = BABYLON.Vector3.Zero(); var uv = BABYLON.Vector2.Zero(); var color = new BABYLON.Color4(0, 0, 0, 1); _this.calculateError(v0, v1, p, n, uv, color); var delTr = new Array(); if (_this.isFlipped(v0, v1, p, deleted0, t.borderFactor, delTr)) continue; if (_this.isFlipped(v1, v0, p, deleted1, t.borderFactor, delTr)) continue; if (deleted0.indexOf(true) < 0 || deleted1.indexOf(true) < 0) continue; var uniqueArray = new Array(); delTr.forEach(function (deletedT) { if (uniqueArray.indexOf(deletedT) === -1) { deletedT.deletePending = true; uniqueArray.push(deletedT); } }); if (uniqueArray.length % 2 !== 0) { continue; } v0.q = v1.q.add(v0.q); v0.updatePosition(p); var tStart = _this.references.length; deletedTriangles = _this.updateTriangles(v0, v0, deleted0, deletedTriangles); deletedTriangles = _this.updateTriangles(v0, v1, deleted1, deletedTriangles); var tCount = _this.references.length - tStart; if (tCount <= v0.triangleCount) { if (tCount) { for (var c = 0; c < tCount; c++) { _this.references[v0.triangleStart + c] = _this.references[tStart + c]; } } } else { v0.triangleStart = tStart; } v0.triangleCount = tCount; break; } } }; BABYLON.AsyncLoop.SyncAsyncForLoop(_this.triangles.length, _this.syncIterations, trianglesIterator, callback, function () { return (triangleCount - deletedTriangles <= targetCount); }); }, 0); }; BABYLON.AsyncLoop.Run(this.decimationIterations, function (loop) { if (triangleCount - deletedTriangles <= targetCount) loop.breakLoop(); else { iterationFunction(loop.index, function () { loop.executeNext(); }); } }, function () { setTimeout(function () { //reconstruct this part of the mesh _this.reconstructMesh(submeshIndex); successCallback(); }, 0); }); }; QuadraticErrorSimplification.prototype.initWithMesh = function (submeshIndex, callback, optimizeMesh) { var _this = this; this.vertices = []; this.triangles = []; var positionData = this._mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind); var indices = this._mesh.getIndices(); var submesh = this._mesh.subMeshes[submeshIndex]; var findInVertices = function (positionToSearch) { if (optimizeMesh) { for (var ii = 0; ii < _this.vertices.length; ++ii) { if (_this.vertices[ii].position.equals(positionToSearch)) { return _this.vertices[ii]; } } } return null; }; var vertexReferences = []; var vertexInit = function (i) { if (!positionData) { return; } var offset = i + submesh.verticesStart; var position = BABYLON.Vector3.FromArray(positionData, offset * 3); var vertex = findInVertices(position) || new DecimationVertex(position, _this.vertices.length); vertex.originalOffsets.push(offset); if (vertex.id === _this.vertices.length) { _this.vertices.push(vertex); } vertexReferences.push(vertex.id); }; //var totalVertices = mesh.getTotalVertices(); var totalVertices = submesh.verticesCount; BABYLON.AsyncLoop.SyncAsyncForLoop(totalVertices, (this.syncIterations / 4) >> 0, vertexInit, function () { var indicesInit = function (i) { if (!indices) { return; } var offset = (submesh.indexStart / 3) + i; var pos = (offset * 3); var i0 = indices[pos + 0]; var i1 = indices[pos + 1]; var i2 = indices[pos + 2]; var v0 = _this.vertices[vertexReferences[i0 - submesh.verticesStart]]; var v1 = _this.vertices[vertexReferences[i1 - submesh.verticesStart]]; var v2 = _this.vertices[vertexReferences[i2 - submesh.verticesStart]]; var triangle = new DecimationTriangle([v0, v1, v2]); triangle.originalOffset = pos; _this.triangles.push(triangle); }; BABYLON.AsyncLoop.SyncAsyncForLoop(submesh.indexCount / 3, _this.syncIterations, indicesInit, function () { _this.init(callback); }); }); }; QuadraticErrorSimplification.prototype.init = function (callback) { var _this = this; var triangleInit1 = function (i) { var t = _this.triangles[i]; t.normal = BABYLON.Vector3.Cross(t.vertices[1].position.subtract(t.vertices[0].position), t.vertices[2].position.subtract(t.vertices[0].position)).normalize(); for (var j = 0; j < 3; j++) { t.vertices[j].q.addArrayInPlace(QuadraticMatrix.DataFromNumbers(t.normal.x, t.normal.y, t.normal.z, -(BABYLON.Vector3.Dot(t.normal, t.vertices[0].position)))); } }; BABYLON.AsyncLoop.SyncAsyncForLoop(this.triangles.length, this.syncIterations, triangleInit1, function () { var triangleInit2 = function (i) { var t = _this.triangles[i]; for (var j = 0; j < 3; ++j) { t.error[j] = _this.calculateError(t.vertices[j], t.vertices[(j + 1) % 3]); } t.error[3] = Math.min(t.error[0], t.error[1], t.error[2]); }; BABYLON.AsyncLoop.SyncAsyncForLoop(_this.triangles.length, _this.syncIterations, triangleInit2, function () { callback(); }); }); }; QuadraticErrorSimplification.prototype.reconstructMesh = function (submeshIndex) { var newTriangles = []; var i; for (i = 0; i < this.vertices.length; ++i) { this.vertices[i].triangleCount = 0; } var t; var j; for (i = 0; i < this.triangles.length; ++i) { if (!this.triangles[i].deleted) { t = this.triangles[i]; for (j = 0; j < 3; ++j) { t.vertices[j].triangleCount = 1; } newTriangles.push(t); } } var newPositionData = (this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.PositionKind) || []); var newNormalData = (this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.NormalKind) || []); var newUVsData = (this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.UVKind) || []); var newColorsData = (this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.ColorKind) || []); var normalData = this._mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind); var uvs = this._mesh.getVerticesData(BABYLON.VertexBuffer.UVKind); var colorsData = this._mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind); var vertexCount = 0; for (i = 0; i < this.vertices.length; ++i) { var vertex = this.vertices[i]; vertex.id = vertexCount; if (vertex.triangleCount) { vertex.originalOffsets.forEach(function (originalOffset) { if (!normalData) { return; } newPositionData.push(vertex.position.x); newPositionData.push(vertex.position.y); newPositionData.push(vertex.position.z); newNormalData.push(normalData[originalOffset * 3]); newNormalData.push(normalData[(originalOffset * 3) + 1]); newNormalData.push(normalData[(originalOffset * 3) + 2]); if (uvs && uvs.length) { newUVsData.push(uvs[(originalOffset * 2)]); newUVsData.push(uvs[(originalOffset * 2) + 1]); } else if (colorsData && colorsData.length) { newColorsData.push(colorsData[(originalOffset * 4)]); newColorsData.push(colorsData[(originalOffset * 4) + 1]); newColorsData.push(colorsData[(originalOffset * 4) + 2]); newColorsData.push(colorsData[(originalOffset * 4) + 3]); } ++vertexCount; }); } } var startingIndex = this._reconstructedMesh.getTotalIndices(); var startingVertex = this._reconstructedMesh.getTotalVertices(); var submeshesArray = this._reconstructedMesh.subMeshes; this._reconstructedMesh.subMeshes = []; var newIndicesArray = this._reconstructedMesh.getIndices(); //[]; var originalIndices = this._mesh.getIndices(); for (i = 0; i < newTriangles.length; ++i) { t = newTriangles[i]; //now get the new referencing point for each vertex [0, 1, 2].forEach(function (idx) { var id = originalIndices[t.originalOffset + idx]; var offset = t.vertices[idx].originalOffsets.indexOf(id); if (offset < 0) offset = 0; newIndicesArray.push(t.vertices[idx].id + offset + startingVertex); }); } //overwriting the old vertex buffers and indices. this._reconstructedMesh.setIndices(newIndicesArray); this._reconstructedMesh.setVerticesData(BABYLON.VertexBuffer.PositionKind, newPositionData); this._reconstructedMesh.setVerticesData(BABYLON.VertexBuffer.NormalKind, newNormalData); if (newUVsData.length > 0) this._reconstructedMesh.setVerticesData(BABYLON.VertexBuffer.UVKind, newUVsData); if (newColorsData.length > 0) this._reconstructedMesh.setVerticesData(BABYLON.VertexBuffer.ColorKind, newColorsData); //create submesh var originalSubmesh = this._mesh.subMeshes[submeshIndex]; if (submeshIndex > 0) { this._reconstructedMesh.subMeshes = []; submeshesArray.forEach(function (submesh) { BABYLON.SubMesh.AddToMesh(submesh.materialIndex, submesh.verticesStart, submesh.verticesCount, /* 0, newPositionData.length/3, */ submesh.indexStart, submesh.indexCount, submesh.getMesh()); }); BABYLON.SubMesh.AddToMesh(originalSubmesh.materialIndex, startingVertex, vertexCount, /* 0, newPositionData.length / 3, */ startingIndex, newTriangles.length * 3, this._reconstructedMesh); } }; QuadraticErrorSimplification.prototype.initDecimatedMesh = function () { this._reconstructedMesh = new BABYLON.Mesh(this._mesh.name + "Decimated", this._mesh.getScene()); this._reconstructedMesh.material = this._mesh.material; this._reconstructedMesh.parent = this._mesh.parent; this._reconstructedMesh.isVisible = false; this._reconstructedMesh.renderingGroupId = this._mesh.renderingGroupId; }; QuadraticErrorSimplification.prototype.isFlipped = function (vertex1, vertex2, point, deletedArray, borderFactor, delTr) { for (var i = 0; i < vertex1.triangleCount; ++i) { var t = this.triangles[this.references[vertex1.triangleStart + i].triangleId]; if (t.deleted) continue; var s = this.references[vertex1.triangleStart + i].vertexId; var v1 = t.vertices[(s + 1) % 3]; var v2 = t.vertices[(s + 2) % 3]; if ((v1 === vertex2 || v2 === vertex2)) { deletedArray[i] = true; delTr.push(t); continue; } var d1 = v1.position.subtract(point); d1 = d1.normalize(); var d2 = v2.position.subtract(point); d2 = d2.normalize(); if (Math.abs(BABYLON.Vector3.Dot(d1, d2)) > 0.999) return true; var normal = BABYLON.Vector3.Cross(d1, d2).normalize(); deletedArray[i] = false; if (BABYLON.Vector3.Dot(normal, t.normal) < 0.2) return true; } return false; }; QuadraticErrorSimplification.prototype.updateTriangles = function (origVertex, vertex, deletedArray, deletedTriangles) { var newDeleted = deletedTriangles; for (var i = 0; i < vertex.triangleCount; ++i) { var ref = this.references[vertex.triangleStart + i]; var t = this.triangles[ref.triangleId]; if (t.deleted) continue; if (deletedArray[i] && t.deletePending) { t.deleted = true; newDeleted++; continue; } t.vertices[ref.vertexId] = origVertex; t.isDirty = true; t.error[0] = this.calculateError(t.vertices[0], t.vertices[1]) + (t.borderFactor / 2); t.error[1] = this.calculateError(t.vertices[1], t.vertices[2]) + (t.borderFactor / 2); t.error[2] = this.calculateError(t.vertices[2], t.vertices[0]) + (t.borderFactor / 2); t.error[3] = Math.min(t.error[0], t.error[1], t.error[2]); this.references.push(ref); } return newDeleted; }; QuadraticErrorSimplification.prototype.identifyBorder = function () { for (var i = 0; i < this.vertices.length; ++i) { var vCount = []; var vId = []; var v = this.vertices[i]; var j; for (j = 0; j < v.triangleCount; ++j) { var triangle = this.triangles[this.references[v.triangleStart + j].triangleId]; for (var ii = 0; ii < 3; ii++) { var ofs = 0; var vv = triangle.vertices[ii]; while (ofs < vCount.length) { if (vId[ofs] === vv.id) break; ++ofs; } if (ofs === vCount.length) { vCount.push(1); vId.push(vv.id); } else { vCount[ofs]++; } } } for (j = 0; j < vCount.length; ++j) { if (vCount[j] === 1) { this.vertices[vId[j]].isBorder = true; } else { this.vertices[vId[j]].isBorder = false; } } } }; QuadraticErrorSimplification.prototype.updateMesh = function (identifyBorders) { if (identifyBorders === void 0) { identifyBorders = false; } var i; if (!identifyBorders) { var newTrianglesVector = []; for (i = 0; i < this.triangles.length; ++i) { if (!this.triangles[i].deleted) { newTrianglesVector.push(this.triangles[i]); } } this.triangles = newTrianglesVector; } for (i = 0; i < this.vertices.length; ++i) { this.vertices[i].triangleCount = 0; this.vertices[i].triangleStart = 0; } var t; var j; var v; for (i = 0; i < this.triangles.length; ++i) { t = this.triangles[i]; for (j = 0; j < 3; ++j) { v = t.vertices[j]; v.triangleCount++; } } var tStart = 0; for (i = 0; i < this.vertices.length; ++i) { this.vertices[i].triangleStart = tStart; tStart += this.vertices[i].triangleCount; this.vertices[i].triangleCount = 0; } var newReferences = new Array(this.triangles.length * 3); for (i = 0; i < this.triangles.length; ++i) { t = this.triangles[i]; for (j = 0; j < 3; ++j) { v = t.vertices[j]; newReferences[v.triangleStart + v.triangleCount] = new Reference(j, i); v.triangleCount++; } } this.references = newReferences; if (identifyBorders) { this.identifyBorder(); } }; QuadraticErrorSimplification.prototype.vertexError = function (q, point) { var x = point.x; var y = point.y; var z = point.z; return q.data[0] * x * x + 2 * q.data[1] * x * y + 2 * q.data[2] * x * z + 2 * q.data[3] * x + q.data[4] * y * y + 2 * q.data[5] * y * z + 2 * q.data[6] * y + q.data[7] * z * z + 2 * q.data[8] * z + q.data[9]; }; QuadraticErrorSimplification.prototype.calculateError = function (vertex1, vertex2, pointResult, normalResult, uvResult, colorResult) { var q = vertex1.q.add(vertex2.q); var border = vertex1.isBorder && vertex2.isBorder; var error = 0; var qDet = q.det(0, 1, 2, 1, 4, 5, 2, 5, 7); if (qDet !== 0 && !border) { if (!pointResult) { pointResult = BABYLON.Vector3.Zero(); } pointResult.x = -1 / qDet * (q.det(1, 2, 3, 4, 5, 6, 5, 7, 8)); pointResult.y = 1 / qDet * (q.det(0, 2, 3, 1, 5, 6, 2, 7, 8)); pointResult.z = -1 / qDet * (q.det(0, 1, 3, 1, 4, 6, 2, 5, 8)); error = this.vertexError(q, pointResult); } else { var p3 = (vertex1.position.add(vertex2.position)).divide(new BABYLON.Vector3(2, 2, 2)); //var norm3 = (vertex1.normal.add(vertex2.normal)).divide(new Vector3(2, 2, 2)).normalize(); var error1 = this.vertexError(q, vertex1.position); var error2 = this.vertexError(q, vertex2.position); var error3 = this.vertexError(q, p3); error = Math.min(error1, error2, error3); if (error === error1) { if (pointResult) { pointResult.copyFrom(vertex1.position); } } else if (error === error2) { if (pointResult) { pointResult.copyFrom(vertex2.position); } } else { if (pointResult) { pointResult.copyFrom(p3); } } } return error; }; return QuadraticErrorSimplification; }()); BABYLON.QuadraticErrorSimplification = QuadraticErrorSimplification; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.meshSimplification.js.map var BABYLON; (function (BABYLON) { var MeshLODLevel = /** @class */ (function () { function MeshLODLevel(distance, mesh) { this.distance = distance; this.mesh = mesh; } return MeshLODLevel; }()); BABYLON.MeshLODLevel = MeshLODLevel; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.meshLODLevel.js.map var BABYLON; (function (BABYLON) { /** * Defines the root class used to create scene optimization to use with SceneOptimizer * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var SceneOptimization = /** @class */ (function () { /** * Creates the SceneOptimization object * @param priority defines the priority of this optimization (0 by default which means first in the list) * @param desc defines the description associated with the optimization */ function SceneOptimization( /** * Defines the priority of this optimization (0 by default which means first in the list) */ priority) { if (priority === void 0) { priority = 0; } this.priority = priority; } /** * Gets a string describing the action executed by the current optimization * @returns description string */ SceneOptimization.prototype.getDescription = function () { return ""; }; /** * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization * @param scene defines the current scene where to apply this optimization * @param optimizer defines the current optimizer * @returns true if everything that can be done was applied */ SceneOptimization.prototype.apply = function (scene, optimizer) { return true; }; ; return SceneOptimization; }()); BABYLON.SceneOptimization = SceneOptimization; /** * Defines an optimization used to reduce the size of render target textures * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var TextureOptimization = /** @class */ (function (_super) { __extends(TextureOptimization, _super); /** * Creates the TextureOptimization object * @param priority defines the priority of this optimization (0 by default which means first in the list) * @param maximumSize defines the maximum sized allowed for textures (1024 is the default value). If a texture is bigger, it will be scaled down using a factor defined by the step parameter * @param step defines the factor (0.5 by default) used to scale down textures bigger than maximum sized allowed. */ function TextureOptimization( /** * Defines the priority of this optimization (0 by default which means first in the list) */ priority, /** * Defines the maximum sized allowed for textures (1024 is the default value). If a texture is bigger, it will be scaled down using a factor defined by the step parameter */ maximumSize, /** * Defines the factor (0.5 by default) used to scale down textures bigger than maximum sized allowed. */ step) { if (priority === void 0) { priority = 0; } if (maximumSize === void 0) { maximumSize = 1024; } if (step === void 0) { step = 0.5; } var _this = _super.call(this, priority) || this; _this.priority = priority; _this.maximumSize = maximumSize; _this.step = step; return _this; } /** * Gets a string describing the action executed by the current optimization * @returns description string */ TextureOptimization.prototype.getDescription = function () { return "Reducing render target texture size to " + this.maximumSize; }; /** * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization * @param scene defines the current scene where to apply this optimization * @param optimizer defines the current optimizer * @returns true if everything that can be done was applied */ TextureOptimization.prototype.apply = function (scene, optimizer) { var allDone = true; for (var index = 0; index < scene.textures.length; index++) { var texture = scene.textures[index]; if (!texture.canRescale || texture.getContext) { continue; } var currentSize = texture.getSize(); var maxDimension = Math.max(currentSize.width, currentSize.height); if (maxDimension > this.maximumSize) { texture.scale(this.step); allDone = false; } } return allDone; }; return TextureOptimization; }(SceneOptimization)); BABYLON.TextureOptimization = TextureOptimization; /** * Defines an optimization used to increase or decrease the rendering resolution * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var HardwareScalingOptimization = /** @class */ (function (_super) { __extends(HardwareScalingOptimization, _super); /** * Creates the HardwareScalingOptimization object * @param priority defines the priority of this optimization (0 by default which means first in the list) * @param maximumScale defines the maximum scale to use (2 by default) * @param step defines the step to use between two passes (0.5 by default) */ function HardwareScalingOptimization( /** * Defines the priority of this optimization (0 by default which means first in the list) */ priority, /** * Defines the maximum scale to use (2 by default) */ maximumScale, /** * Defines the step to use between two passes (0.5 by default) */ step) { if (priority === void 0) { priority = 0; } if (maximumScale === void 0) { maximumScale = 2; } if (step === void 0) { step = 0.25; } var _this = _super.call(this, priority) || this; _this.priority = priority; _this.maximumScale = maximumScale; _this.step = step; _this._currentScale = -1; _this._directionOffset = 1; return _this; } /** * Gets a string describing the action executed by the current optimization * @return description string */ HardwareScalingOptimization.prototype.getDescription = function () { return "Setting hardware scaling level to " + this._currentScale; }; /** * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization * @param scene defines the current scene where to apply this optimization * @param optimizer defines the current optimizer * @returns true if everything that can be done was applied */ HardwareScalingOptimization.prototype.apply = function (scene, optimizer) { if (this._currentScale === -1) { this._currentScale = scene.getEngine().getHardwareScalingLevel(); if (this._currentScale > this.maximumScale) { this._directionOffset = -1; } } this._currentScale += this._directionOffset * this.step; scene.getEngine().setHardwareScalingLevel(this._currentScale); return this._directionOffset === 1 ? this._currentScale >= this.maximumScale : this._currentScale <= this.maximumScale; }; ; return HardwareScalingOptimization; }(SceneOptimization)); BABYLON.HardwareScalingOptimization = HardwareScalingOptimization; /** * Defines an optimization used to remove shadows * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var ShadowsOptimization = /** @class */ (function (_super) { __extends(ShadowsOptimization, _super); function ShadowsOptimization() { return _super !== null && _super.apply(this, arguments) || this; } /** * Gets a string describing the action executed by the current optimization * @return description string */ ShadowsOptimization.prototype.getDescription = function () { return "Turning shadows on/off"; }; /** * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization * @param scene defines the current scene where to apply this optimization * @param optimizer defines the current optimizer * @returns true if everything that can be done was applied */ ShadowsOptimization.prototype.apply = function (scene, optimizer) { scene.shadowsEnabled = optimizer.isInImprovementMode; return true; }; ; return ShadowsOptimization; }(SceneOptimization)); BABYLON.ShadowsOptimization = ShadowsOptimization; /** * Defines an optimization used to turn post-processes off * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var PostProcessesOptimization = /** @class */ (function (_super) { __extends(PostProcessesOptimization, _super); function PostProcessesOptimization() { return _super !== null && _super.apply(this, arguments) || this; } /** * Gets a string describing the action executed by the current optimization * @return description string */ PostProcessesOptimization.prototype.getDescription = function () { return "Turning post-processes on/off"; }; /** * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization * @param scene defines the current scene where to apply this optimization * @param optimizer defines the current optimizer * @returns true if everything that can be done was applied */ PostProcessesOptimization.prototype.apply = function (scene, optimizer) { scene.postProcessesEnabled = optimizer.isInImprovementMode; return true; }; ; return PostProcessesOptimization; }(SceneOptimization)); BABYLON.PostProcessesOptimization = PostProcessesOptimization; /** * Defines an optimization used to turn lens flares off * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var LensFlaresOptimization = /** @class */ (function (_super) { __extends(LensFlaresOptimization, _super); function LensFlaresOptimization() { return _super !== null && _super.apply(this, arguments) || this; } /** * Gets a string describing the action executed by the current optimization * @return description string */ LensFlaresOptimization.prototype.getDescription = function () { return "Turning lens flares on/off"; }; /** * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization * @param scene defines the current scene where to apply this optimization * @param optimizer defines the current optimizer * @returns true if everything that can be done was applied */ LensFlaresOptimization.prototype.apply = function (scene, optimizer) { scene.lensFlaresEnabled = optimizer.isInImprovementMode; return true; }; ; return LensFlaresOptimization; }(SceneOptimization)); BABYLON.LensFlaresOptimization = LensFlaresOptimization; /** * Defines an optimization based on user defined callback. * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var CustomOptimization = /** @class */ (function (_super) { __extends(CustomOptimization, _super); function CustomOptimization() { return _super !== null && _super.apply(this, arguments) || this; } /** * Gets a string describing the action executed by the current optimization * @returns description string */ CustomOptimization.prototype.getDescription = function () { if (this.onGetDescription) { return this.onGetDescription(); } return "Running user defined callback"; }; /** * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization * @param scene defines the current scene where to apply this optimization * @param optimizer defines the current optimizer * @returns true if everything that can be done was applied */ CustomOptimization.prototype.apply = function (scene, optimizer) { if (this.onApply) { return this.onApply(scene, optimizer); } return true; }; ; return CustomOptimization; }(SceneOptimization)); BABYLON.CustomOptimization = CustomOptimization; /** * Defines an optimization used to turn particles off * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var ParticlesOptimization = /** @class */ (function (_super) { __extends(ParticlesOptimization, _super); function ParticlesOptimization() { return _super !== null && _super.apply(this, arguments) || this; } /** * Gets a string describing the action executed by the current optimization * @return description string */ ParticlesOptimization.prototype.getDescription = function () { return "Turning particles on/off"; }; /** * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization * @param scene defines the current scene where to apply this optimization * @param optimizer defines the current optimizer * @returns true if everything that can be done was applied */ ParticlesOptimization.prototype.apply = function (scene, optimizer) { scene.particlesEnabled = optimizer.isInImprovementMode; return true; }; ; return ParticlesOptimization; }(SceneOptimization)); BABYLON.ParticlesOptimization = ParticlesOptimization; /** * Defines an optimization used to turn render targets off * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var RenderTargetsOptimization = /** @class */ (function (_super) { __extends(RenderTargetsOptimization, _super); function RenderTargetsOptimization() { return _super !== null && _super.apply(this, arguments) || this; } /** * Gets a string describing the action executed by the current optimization * @return description string */ RenderTargetsOptimization.prototype.getDescription = function () { return "Turning render targets off"; }; /** * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization * @param scene defines the current scene where to apply this optimization * @param optimizer defines the current optimizer * @returns true if everything that can be done was applied */ RenderTargetsOptimization.prototype.apply = function (scene, optimizer) { scene.renderTargetsEnabled = optimizer.isInImprovementMode; return true; }; ; return RenderTargetsOptimization; }(SceneOptimization)); BABYLON.RenderTargetsOptimization = RenderTargetsOptimization; /** * Defines an optimization used to merge meshes with compatible materials * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var MergeMeshesOptimization = /** @class */ (function (_super) { __extends(MergeMeshesOptimization, _super); function MergeMeshesOptimization() { var _this = _super !== null && _super.apply(this, arguments) || this; _this._canBeMerged = function (abstractMesh) { if (!(abstractMesh instanceof BABYLON.Mesh)) { return false; } var mesh = abstractMesh; if (!mesh.isVisible || !mesh.isEnabled()) { return false; } if (mesh.instances.length > 0) { return false; } if (mesh.skeleton || mesh.hasLODLevels) { return false; } if (mesh.parent) { return false; } return true; }; return _this; } Object.defineProperty(MergeMeshesOptimization, "UpdateSelectionTree", { /** * Gets or sets a boolean which defines if optimization octree has to be updated */ get: function () { return MergeMeshesOptimization._UpdateSelectionTree; }, /** * Gets or sets a boolean which defines if optimization octree has to be updated */ set: function (value) { MergeMeshesOptimization._UpdateSelectionTree = value; }, enumerable: true, configurable: true }); /** * Gets a string describing the action executed by the current optimization * @return description string */ MergeMeshesOptimization.prototype.getDescription = function () { return "Merging similar meshes together"; }; /** * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization * @param scene defines the current scene where to apply this optimization * @param optimizer defines the current optimizer * @param updateSelectionTree defines that the selection octree has to be updated (false by default) * @returns true if everything that can be done was applied */ MergeMeshesOptimization.prototype.apply = function (scene, optimizer, updateSelectionTree) { var globalPool = scene.meshes.slice(0); var globalLength = globalPool.length; for (var index = 0; index < globalLength; index++) { var currentPool = new Array(); var current = globalPool[index]; // Checks if (!this._canBeMerged(current)) { continue; } currentPool.push(current); // Find compatible meshes for (var subIndex = index + 1; subIndex < globalLength; subIndex++) { var otherMesh = globalPool[subIndex]; if (!this._canBeMerged(otherMesh)) { continue; } if (otherMesh.material !== current.material) { continue; } if (otherMesh.checkCollisions !== current.checkCollisions) { continue; } currentPool.push(otherMesh); globalLength--; globalPool.splice(subIndex, 1); subIndex--; } if (currentPool.length < 2) { continue; } // Merge meshes BABYLON.Mesh.MergeMeshes(currentPool); } if (updateSelectionTree != undefined) { if (updateSelectionTree) { scene.createOrUpdateSelectionOctree(); } } else if (MergeMeshesOptimization.UpdateSelectionTree) { scene.createOrUpdateSelectionOctree(); } return true; }; ; MergeMeshesOptimization._UpdateSelectionTree = false; return MergeMeshesOptimization; }(SceneOptimization)); BABYLON.MergeMeshesOptimization = MergeMeshesOptimization; /** * Defines a list of options used by SceneOptimizer * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var SceneOptimizerOptions = /** @class */ (function () { /** * Creates a new list of options used by SceneOptimizer * @param targetFrameRate defines the target frame rate to reach (60 by default) * @param trackerDuration defines the interval between two checkes (2000ms by default) */ function SceneOptimizerOptions( /** * Defines the target frame rate to reach (60 by default) */ targetFrameRate, /** * Defines the interval between two checkes (2000ms by default) */ trackerDuration) { if (targetFrameRate === void 0) { targetFrameRate = 60; } if (trackerDuration === void 0) { trackerDuration = 2000; } this.targetFrameRate = targetFrameRate; this.trackerDuration = trackerDuration; /** * Gets the list of optimizations to apply */ this.optimizations = new Array(); } /** * Add a new optimization * @param optimization defines the SceneOptimization to add to the list of active optimizations * @returns the current SceneOptimizerOptions */ SceneOptimizerOptions.prototype.addOptimization = function (optimization) { this.optimizations.push(optimization); return this; }; /** * Add a new custom optimization * @param onApply defines the callback called to apply the custom optimization (true if everything that can be done was applied) * @param onGetDescription defines the callback called to get the description attached with the optimization. * @param priority defines the priority of this optimization (0 by default which means first in the list) * @returns the current SceneOptimizerOptions */ SceneOptimizerOptions.prototype.addCustomOptimization = function (onApply, onGetDescription, priority) { if (priority === void 0) { priority = 0; } var optimization = new CustomOptimization(priority); optimization.onApply = onApply; optimization.onGetDescription = onGetDescription; this.optimizations.push(optimization); return this; }; /** * Creates a list of pre-defined optimizations aimed to reduce the visual impact on the scene * @param targetFrameRate defines the target frame rate (60 by default) * @returns a SceneOptimizerOptions object */ SceneOptimizerOptions.LowDegradationAllowed = function (targetFrameRate) { var result = new SceneOptimizerOptions(targetFrameRate); var priority = 0; result.addOptimization(new MergeMeshesOptimization(priority)); result.addOptimization(new ShadowsOptimization(priority)); result.addOptimization(new LensFlaresOptimization(priority)); // Next priority priority++; result.addOptimization(new PostProcessesOptimization(priority)); result.addOptimization(new ParticlesOptimization(priority)); // Next priority priority++; result.addOptimization(new TextureOptimization(priority, 1024)); return result; }; /** * Creates a list of pre-defined optimizations aimed to have a moderate impact on the scene visual * @param targetFrameRate defines the target frame rate (60 by default) * @returns a SceneOptimizerOptions object */ SceneOptimizerOptions.ModerateDegradationAllowed = function (targetFrameRate) { var result = new SceneOptimizerOptions(targetFrameRate); var priority = 0; result.addOptimization(new MergeMeshesOptimization(priority)); result.addOptimization(new ShadowsOptimization(priority)); result.addOptimization(new LensFlaresOptimization(priority)); // Next priority priority++; result.addOptimization(new PostProcessesOptimization(priority)); result.addOptimization(new ParticlesOptimization(priority)); // Next priority priority++; result.addOptimization(new TextureOptimization(priority, 512)); // Next priority priority++; result.addOptimization(new RenderTargetsOptimization(priority)); // Next priority priority++; result.addOptimization(new HardwareScalingOptimization(priority, 2)); return result; }; /** * Creates a list of pre-defined optimizations aimed to have a big impact on the scene visual * @param targetFrameRate defines the target frame rate (60 by default) * @returns a SceneOptimizerOptions object */ SceneOptimizerOptions.HighDegradationAllowed = function (targetFrameRate) { var result = new SceneOptimizerOptions(targetFrameRate); var priority = 0; result.addOptimization(new MergeMeshesOptimization(priority)); result.addOptimization(new ShadowsOptimization(priority)); result.addOptimization(new LensFlaresOptimization(priority)); // Next priority priority++; result.addOptimization(new PostProcessesOptimization(priority)); result.addOptimization(new ParticlesOptimization(priority)); // Next priority priority++; result.addOptimization(new TextureOptimization(priority, 256)); // Next priority priority++; result.addOptimization(new RenderTargetsOptimization(priority)); // Next priority priority++; result.addOptimization(new HardwareScalingOptimization(priority, 4)); return result; }; return SceneOptimizerOptions; }()); BABYLON.SceneOptimizerOptions = SceneOptimizerOptions; /** * Class used to run optimizations in order to reach a target frame rate * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer */ var SceneOptimizer = /** @class */ (function () { /** * Creates a new SceneOptimizer * @param scene defines the scene to work on * @param options defines the options to use with the SceneOptimizer * @param autoGeneratePriorities defines if priorities must be generated and not read from SceneOptimization property (true by default) * @param improvementMode defines if the scene optimizer must run the maximum optimization while staying over a target frame instead of trying to reach the target framerate (false by default) */ function SceneOptimizer(scene, options, autoGeneratePriorities, improvementMode) { if (autoGeneratePriorities === void 0) { autoGeneratePriorities = true; } if (improvementMode === void 0) { improvementMode = false; } var _this = this; this._isRunning = false; this._currentPriorityLevel = 0; this._targetFrameRate = 60; this._trackerDuration = 2000; this._currentFrameRate = 0; this._improvementMode = false; /** * Defines an observable called when the optimizer reaches the target frame rate */ this.onSuccessObservable = new BABYLON.Observable(); /** * Defines an observable called when the optimizer enables an optimization */ this.onNewOptimizationAppliedObservable = new BABYLON.Observable(); /** * Defines an observable called when the optimizer is not able to reach the target frame rate */ this.onFailureObservable = new BABYLON.Observable(); if (!options) { this._options = new SceneOptimizerOptions(); } else { this._options = options; } if (this._options.targetFrameRate) { this._targetFrameRate = this._options.targetFrameRate; } if (this._options.trackerDuration) { this._trackerDuration = this._options.trackerDuration; } if (autoGeneratePriorities) { var priority = 0; for (var _i = 0, _a = this._options.optimizations; _i < _a.length; _i++) { var optim = _a[_i]; optim.priority = priority++; } } this._improvementMode = improvementMode; this._scene = scene || BABYLON.Engine.LastCreatedScene; this._sceneDisposeObserver = this._scene.onDisposeObservable.add(function () { _this._sceneDisposeObserver = null; _this.dispose(); }); } Object.defineProperty(SceneOptimizer.prototype, "isInImprovementMode", { /** * Gets a boolean indicating if the optimizer is in improvement mode */ get: function () { return this._improvementMode; }, enumerable: true, configurable: true }); Object.defineProperty(SceneOptimizer.prototype, "currentPriorityLevel", { /** * Gets the current priority level (0 at start) */ get: function () { return this._currentPriorityLevel; }, enumerable: true, configurable: true }); Object.defineProperty(SceneOptimizer.prototype, "currentFrameRate", { /** * Gets the current frame rate checked by the SceneOptimizer */ get: function () { return this._currentFrameRate; }, enumerable: true, configurable: true }); Object.defineProperty(SceneOptimizer.prototype, "targetFrameRate", { /** * Gets or sets the current target frame rate (60 by default) */ get: function () { return this._targetFrameRate; }, /** * Gets or sets the current target frame rate (60 by default) */ set: function (value) { this._targetFrameRate = value; }, enumerable: true, configurable: true }); Object.defineProperty(SceneOptimizer.prototype, "trackerDuration", { /** * Gets or sets the current interval between two checks (every 2000ms by default) */ get: function () { return this._trackerDuration; }, /** * Gets or sets the current interval between two checks (every 2000ms by default) */ set: function (value) { this._trackerDuration = value; }, enumerable: true, configurable: true }); Object.defineProperty(SceneOptimizer.prototype, "optimizations", { /** * Gets the list of active optimizations */ get: function () { return this._options.optimizations; }, enumerable: true, configurable: true }); /** * Stops the current optimizer */ SceneOptimizer.prototype.stop = function () { this._isRunning = false; }; /** * Reset the optimizer to initial step (current priority level = 0) */ SceneOptimizer.prototype.reset = function () { this._currentPriorityLevel = 0; }; /** * Start the optimizer. By default it will try to reach a specific framerate * but if the optimizer is set with improvementMode === true then it will run all optimiatiation while frame rate is above the target frame rate */ SceneOptimizer.prototype.start = function () { var _this = this; if (this._isRunning) { return; } this._isRunning = true; // Let's wait for the scene to be ready before running our check this._scene.executeWhenReady(function () { setTimeout(function () { _this._checkCurrentState(); }, _this._trackerDuration); }); }; SceneOptimizer.prototype._checkCurrentState = function () { var _this = this; if (!this._isRunning) { return; } var scene = this._scene; var options = this._options; this._currentFrameRate = Math.round(scene.getEngine().getFps()); if (this._improvementMode && this._currentFrameRate <= this._targetFrameRate || !this._improvementMode && this._currentFrameRate >= this._targetFrameRate) { this._isRunning = false; this.onSuccessObservable.notifyObservers(this); return; } // Apply current level of optimizations var allDone = true; var noOptimizationApplied = true; for (var index = 0; index < options.optimizations.length; index++) { var optimization = options.optimizations[index]; if (optimization.priority === this._currentPriorityLevel) { noOptimizationApplied = false; allDone = allDone && optimization.apply(scene, this); this.onNewOptimizationAppliedObservable.notifyObservers(optimization); } } // If no optimization was applied, this is a failure :( if (noOptimizationApplied) { this._isRunning = false; this.onFailureObservable.notifyObservers(this); return; } // If all optimizations were done, move to next level if (allDone) { this._currentPriorityLevel++; } // Let's the system running for a specific amount of time before checking FPS scene.executeWhenReady(function () { setTimeout(function () { _this._checkCurrentState(); }, _this._trackerDuration); }); }; /** * Release all resources */ SceneOptimizer.prototype.dispose = function () { this.stop(); this.onSuccessObservable.clear(); this.onFailureObservable.clear(); this.onNewOptimizationAppliedObservable.clear(); if (this._sceneDisposeObserver) { this._scene.onDisposeObservable.remove(this._sceneDisposeObserver); } }; /** * Helper function to create a SceneOptimizer with one single line of code * @param scene defines the scene to work on * @param options defines the options to use with the SceneOptimizer * @param onSuccess defines a callback to call on success * @param onFailure defines a callback to call on failure * @returns the new SceneOptimizer object */ SceneOptimizer.OptimizeAsync = function (scene, options, onSuccess, onFailure) { var optimizer = new SceneOptimizer(scene, options || SceneOptimizerOptions.ModerateDegradationAllowed(), false); if (onSuccess) { optimizer.onSuccessObservable.add(function () { onSuccess(); }); } if (onFailure) { optimizer.onFailureObservable.add(function () { onFailure(); }); } optimizer.start(); return optimizer; }; return SceneOptimizer; }()); BABYLON.SceneOptimizer = SceneOptimizer; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.sceneOptimizer.js.map var BABYLON; (function (BABYLON) { var OutlineRenderer = /** @class */ (function () { function OutlineRenderer(scene) { this.zOffset = 1; this._scene = scene; } OutlineRenderer.prototype.render = function (subMesh, batch, useOverlay) { var _this = this; if (useOverlay === void 0) { useOverlay = false; } var scene = this._scene; var engine = this._scene.getEngine(); var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined); if (!this.isReady(subMesh, hardwareInstancedRendering)) { return; } var mesh = subMesh.getRenderingMesh(); var material = subMesh.getMaterial(); if (!material || !scene.activeCamera) { return; } engine.enableEffect(this._effect); // Logarithmic depth if (material.useLogarithmicDepth) { this._effect.setFloat("logarithmicDepthConstant", 2.0 / (Math.log(scene.activeCamera.maxZ + 1.0) / Math.LN2)); } this._effect.setFloat("offset", useOverlay ? 0 : mesh.outlineWidth); this._effect.setColor4("color", useOverlay ? mesh.overlayColor : mesh.outlineColor, useOverlay ? mesh.overlayAlpha : material.alpha); this._effect.setMatrix("viewProjection", scene.getTransformMatrix()); // Bones if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) { this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh)); } mesh._bind(subMesh, this._effect, BABYLON.Material.TriangleFillMode); // Alpha test if (material && material.needAlphaTesting()) { var alphaTexture = material.getAlphaTestTexture(); if (alphaTexture) { this._effect.setTexture("diffuseSampler", alphaTexture); this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix()); } } engine.setZOffset(-this.zOffset); mesh._processRendering(subMesh, this._effect, BABYLON.Material.TriangleFillMode, batch, hardwareInstancedRendering, function (isInstance, world) { _this._effect.setMatrix("world", world); }); engine.setZOffset(0); }; OutlineRenderer.prototype.isReady = function (subMesh, useInstances) { var defines = []; var attribs = [BABYLON.VertexBuffer.PositionKind, BABYLON.VertexBuffer.NormalKind]; var mesh = subMesh.getMesh(); var material = subMesh.getMaterial(); if (material) { // Alpha test if (material.needAlphaTesting()) { defines.push("#define ALPHATEST"); if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) { attribs.push(BABYLON.VertexBuffer.UVKind); defines.push("#define UV1"); } if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) { attribs.push(BABYLON.VertexBuffer.UV2Kind); defines.push("#define UV2"); } } //Logarithmic depth if (material.useLogarithmicDepth) { defines.push("#define LOGARITHMICDEPTH"); } } // Bones if (mesh.useBones && mesh.computeBonesUsingShaders) { attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind); attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind); if (mesh.numBoneInfluencers > 4) { attribs.push(BABYLON.VertexBuffer.MatricesIndicesExtraKind); attribs.push(BABYLON.VertexBuffer.MatricesWeightsExtraKind); } defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers); defines.push("#define BonesPerMesh " + (mesh.skeleton ? mesh.skeleton.bones.length + 1 : 0)); } else { defines.push("#define NUM_BONE_INFLUENCERS 0"); } // Instances if (useInstances) { defines.push("#define INSTANCES"); attribs.push("world0"); attribs.push("world1"); attribs.push("world2"); attribs.push("world3"); } // Get correct effect var join = defines.join("\n"); if (this._cachedDefines !== join) { this._cachedDefines = join; this._effect = this._scene.getEngine().createEffect("outline", attribs, ["world", "mBones", "viewProjection", "diffuseMatrix", "offset", "color", "logarithmicDepthConstant"], ["diffuseSampler"], join); } return this._effect.isReady(); }; return OutlineRenderer; }()); BABYLON.OutlineRenderer = OutlineRenderer; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.outlineRenderer.js.map var BABYLON; (function (BABYLON) { var FaceAdjacencies = /** @class */ (function () { function FaceAdjacencies() { this.edges = new Array(); this.edgesConnectedCount = 0; } return FaceAdjacencies; }()); var EdgesRenderer = /** @class */ (function () { // Beware when you use this class with complex objects as the adjacencies computation can be really long function EdgesRenderer(source, epsilon, checkVerticesInsteadOfIndices) { if (epsilon === void 0) { epsilon = 0.95; } if (checkVerticesInsteadOfIndices === void 0) { checkVerticesInsteadOfIndices = false; } this.edgesWidthScalerForOrthographic = 1000.0; this.edgesWidthScalerForPerspective = 50.0; this._linesPositions = new Array(); this._linesNormals = new Array(); this._linesIndices = new Array(); this._buffers = {}; this._checkVerticesInsteadOfIndices = false; this._source = source; this._checkVerticesInsteadOfIndices = checkVerticesInsteadOfIndices; this._epsilon = epsilon; this._prepareRessources(); this._generateEdgesLines(); } EdgesRenderer.prototype._prepareRessources = function () { if (this._lineShader) { return; } this._lineShader = new BABYLON.ShaderMaterial("lineShader", this._source.getScene(), "line", { attributes: ["position", "normal"], uniforms: ["worldViewProjection", "color", "width", "aspectRatio"] }); this._lineShader.disableDepthWrite = true; this._lineShader.backFaceCulling = false; }; EdgesRenderer.prototype._rebuild = function () { var buffer = this._buffers[BABYLON.VertexBuffer.PositionKind]; if (buffer) { buffer._rebuild(); } buffer = this._buffers[BABYLON.VertexBuffer.NormalKind]; if (buffer) { buffer._rebuild(); } var scene = this._source.getScene(); var engine = scene.getEngine(); this._ib = engine.createIndexBuffer(this._linesIndices); }; EdgesRenderer.prototype.dispose = function () { var buffer = this._buffers[BABYLON.VertexBuffer.PositionKind]; if (buffer) { buffer.dispose(); this._buffers[BABYLON.VertexBuffer.PositionKind] = null; } buffer = this._buffers[BABYLON.VertexBuffer.NormalKind]; if (buffer) { buffer.dispose(); this._buffers[BABYLON.VertexBuffer.NormalKind] = null; } this._source.getScene().getEngine()._releaseBuffer(this._ib); this._lineShader.dispose(); }; EdgesRenderer.prototype._processEdgeForAdjacencies = function (pa, pb, p0, p1, p2) { if (pa === p0 && pb === p1 || pa === p1 && pb === p0) { return 0; } if (pa === p1 && pb === p2 || pa === p2 && pb === p1) { return 1; } if (pa === p2 && pb === p0 || pa === p0 && pb === p2) { return 2; } return -1; }; EdgesRenderer.prototype._processEdgeForAdjacenciesWithVertices = function (pa, pb, p0, p1, p2) { if (pa.equalsWithEpsilon(p0) && pb.equalsWithEpsilon(p1) || pa.equalsWithEpsilon(p1) && pb.equalsWithEpsilon(p0)) { return 0; } if (pa.equalsWithEpsilon(p1) && pb.equalsWithEpsilon(p2) || pa.equalsWithEpsilon(p2) && pb.equalsWithEpsilon(p1)) { return 1; } if (pa.equalsWithEpsilon(p2) && pb.equalsWithEpsilon(p0) || pa.equalsWithEpsilon(p0) && pb.equalsWithEpsilon(p2)) { return 2; } return -1; }; EdgesRenderer.prototype._checkEdge = function (faceIndex, edge, faceNormals, p0, p1) { var needToCreateLine; if (edge === undefined) { needToCreateLine = true; } else { var dotProduct = BABYLON.Vector3.Dot(faceNormals[faceIndex], faceNormals[edge]); needToCreateLine = dotProduct < this._epsilon; } if (needToCreateLine) { var offset = this._linesPositions.length / 3; var normal = p0.subtract(p1); normal.normalize(); // Positions this._linesPositions.push(p0.x); this._linesPositions.push(p0.y); this._linesPositions.push(p0.z); this._linesPositions.push(p0.x); this._linesPositions.push(p0.y); this._linesPositions.push(p0.z); this._linesPositions.push(p1.x); this._linesPositions.push(p1.y); this._linesPositions.push(p1.z); this._linesPositions.push(p1.x); this._linesPositions.push(p1.y); this._linesPositions.push(p1.z); // Normals this._linesNormals.push(p1.x); this._linesNormals.push(p1.y); this._linesNormals.push(p1.z); this._linesNormals.push(-1); this._linesNormals.push(p1.x); this._linesNormals.push(p1.y); this._linesNormals.push(p1.z); this._linesNormals.push(1); this._linesNormals.push(p0.x); this._linesNormals.push(p0.y); this._linesNormals.push(p0.z); this._linesNormals.push(-1); this._linesNormals.push(p0.x); this._linesNormals.push(p0.y); this._linesNormals.push(p0.z); this._linesNormals.push(1); // Indices this._linesIndices.push(offset); this._linesIndices.push(offset + 1); this._linesIndices.push(offset + 2); this._linesIndices.push(offset); this._linesIndices.push(offset + 2); this._linesIndices.push(offset + 3); } }; EdgesRenderer.prototype._generateEdgesLines = function () { var positions = this._source.getVerticesData(BABYLON.VertexBuffer.PositionKind); var indices = this._source.getIndices(); if (!indices || !positions) { return; } // First let's find adjacencies var adjacencies = new Array(); var faceNormals = new Array(); var index; var faceAdjacencies; // Prepare faces for (index = 0; index < indices.length; index += 3) { faceAdjacencies = new FaceAdjacencies(); var p0Index = indices[index]; var p1Index = indices[index + 1]; var p2Index = indices[index + 2]; faceAdjacencies.p0 = new BABYLON.Vector3(positions[p0Index * 3], positions[p0Index * 3 + 1], positions[p0Index * 3 + 2]); faceAdjacencies.p1 = new BABYLON.Vector3(positions[p1Index * 3], positions[p1Index * 3 + 1], positions[p1Index * 3 + 2]); faceAdjacencies.p2 = new BABYLON.Vector3(positions[p2Index * 3], positions[p2Index * 3 + 1], positions[p2Index * 3 + 2]); var faceNormal = BABYLON.Vector3.Cross(faceAdjacencies.p1.subtract(faceAdjacencies.p0), faceAdjacencies.p2.subtract(faceAdjacencies.p1)); faceNormal.normalize(); faceNormals.push(faceNormal); adjacencies.push(faceAdjacencies); } // Scan for (index = 0; index < adjacencies.length; index++) { faceAdjacencies = adjacencies[index]; for (var otherIndex = index + 1; otherIndex < adjacencies.length; otherIndex++) { var otherFaceAdjacencies = adjacencies[otherIndex]; if (faceAdjacencies.edgesConnectedCount === 3) { // Full break; } if (otherFaceAdjacencies.edgesConnectedCount === 3) { // Full continue; } var otherP0 = indices[otherIndex * 3]; var otherP1 = indices[otherIndex * 3 + 1]; var otherP2 = indices[otherIndex * 3 + 2]; for (var edgeIndex = 0; edgeIndex < 3; edgeIndex++) { var otherEdgeIndex = 0; if (faceAdjacencies.edges[edgeIndex] !== undefined) { continue; } switch (edgeIndex) { case 0: if (this._checkVerticesInsteadOfIndices) { otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p0, faceAdjacencies.p1, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2); } else { otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3], indices[index * 3 + 1], otherP0, otherP1, otherP2); } break; case 1: if (this._checkVerticesInsteadOfIndices) { otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p1, faceAdjacencies.p2, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2); } else { otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 1], indices[index * 3 + 2], otherP0, otherP1, otherP2); } break; case 2: if (this._checkVerticesInsteadOfIndices) { otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p2, faceAdjacencies.p0, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2); } else { otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 2], indices[index * 3], otherP0, otherP1, otherP2); } break; } if (otherEdgeIndex === -1) { continue; } faceAdjacencies.edges[edgeIndex] = otherIndex; otherFaceAdjacencies.edges[otherEdgeIndex] = index; faceAdjacencies.edgesConnectedCount++; otherFaceAdjacencies.edgesConnectedCount++; if (faceAdjacencies.edgesConnectedCount === 3) { break; } } } } // Create lines for (index = 0; index < adjacencies.length; index++) { // We need a line when a face has no adjacency on a specific edge or if all the adjacencies has an angle greater than epsilon var current = adjacencies[index]; this._checkEdge(index, current.edges[0], faceNormals, current.p0, current.p1); this._checkEdge(index, current.edges[1], faceNormals, current.p1, current.p2); this._checkEdge(index, current.edges[2], faceNormals, current.p2, current.p0); } // Merge into a single mesh var engine = this._source.getScene().getEngine(); this._buffers[BABYLON.VertexBuffer.PositionKind] = new BABYLON.VertexBuffer(engine, this._linesPositions, BABYLON.VertexBuffer.PositionKind, false); this._buffers[BABYLON.VertexBuffer.NormalKind] = new BABYLON.VertexBuffer(engine, this._linesNormals, BABYLON.VertexBuffer.NormalKind, false, false, 4); this._ib = engine.createIndexBuffer(this._linesIndices); this._indicesCount = this._linesIndices.length; }; EdgesRenderer.prototype.render = function () { var scene = this._source.getScene(); if (!this._lineShader.isReady() || !scene.activeCamera) { return; } var engine = scene.getEngine(); this._lineShader._preBind(); // VBOs engine.bindBuffers(this._buffers, this._ib, this._lineShader.getEffect()); scene.resetCachedMaterial(); this._lineShader.setColor4("color", this._source.edgesColor); if (scene.activeCamera.mode === BABYLON.Camera.ORTHOGRAPHIC_CAMERA) { this._lineShader.setFloat("width", this._source.edgesWidth / this.edgesWidthScalerForOrthographic); } else { this._lineShader.setFloat("width", this._source.edgesWidth / this.edgesWidthScalerForPerspective); } this._lineShader.setFloat("aspectRatio", engine.getAspectRatio(scene.activeCamera)); this._lineShader.bind(this._source.getWorldMatrix()); // Draw order engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, this._indicesCount); this._lineShader.unbind(); engine.setDepthWrite(true); }; return EdgesRenderer; }()); BABYLON.EdgesRenderer = EdgesRenderer; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.edgesRenderer.js.map var __assign = (this && this.__assign) || Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; var BABYLON; (function (BABYLON) { /** * The effect layer Helps adding post process effect blended with the main pass. * * This can be for instance use to generate glow or higlight effects on the scene. * * The effect layer class can not be used directly and is intented to inherited from to be * customized per effects. */ var EffectLayer = /** @class */ (function () { /** * Instantiates a new effect Layer and references it in the scene. * @param name The name of the layer * @param scene The scene to use the layer in */ function EffectLayer( /** The Friendly of the effect in the scene */ name, scene) { this._vertexBuffers = {}; this._maxSize = 0; this._mainTextureDesiredSize = { width: 0, height: 0 }; this._shouldRender = true; this._postProcesses = []; this._textures = []; this._emissiveTextureAndColor = { texture: null, color: new BABYLON.Color4() }; /** * The clear color of the texture used to generate the glow map. */ this.neutralColor = new BABYLON.Color4(); /** * Specifies wether the highlight layer is enabled or not. */ this.isEnabled = true; /** * An event triggered when the effect layer has been disposed. */ this.onDisposeObservable = new BABYLON.Observable(); /** * An event triggered when the effect layer is about rendering the main texture with the glowy parts. */ this.onBeforeRenderMainTextureObservable = new BABYLON.Observable(); /** * An event triggered when the generated texture is being merged in the scene. */ this.onBeforeComposeObservable = new BABYLON.Observable(); /** * An event triggered when the generated texture has been merged in the scene. */ this.onAfterComposeObservable = new BABYLON.Observable(); /** * An event triggered when the efffect layer changes its size. */ this.onSizeChangedObservable = new BABYLON.Observable(); this.name = name; this._scene = scene || BABYLON.Engine.LastCreatedScene; this._engine = scene.getEngine(); this._maxSize = this._engine.getCaps().maxTextureSize; this._scene.effectLayers.push(this); // Generate Buffers this._generateIndexBuffer(); this._genrateVertexBuffer(); } Object.defineProperty(EffectLayer.prototype, "camera", { /** * Gets the camera attached to the layer. */ get: function () { return this._effectLayerOptions.camera; }, enumerable: true, configurable: true }); /** * Initializes the effect layer with the required options. * @param options Sets of none mandatory options to use with the layer (see IEffectLayerOptions for more information) */ EffectLayer.prototype._init = function (options) { // Adapt options this._effectLayerOptions = __assign({ mainTextureRatio: 0.5, alphaBlendingMode: BABYLON.Engine.ALPHA_COMBINE, camera: null }, options); this._setMainTextureSize(); this._createMainTexture(); this._createTextureAndPostProcesses(); this._mergeEffect = this._createMergeEffect(); }; /** * Generates the index buffer of the full screen quad blending to the main canvas. */ EffectLayer.prototype._generateIndexBuffer = function () { // Indices var indices = []; indices.push(0); indices.push(1); indices.push(2); indices.push(0); indices.push(2); indices.push(3); this._indexBuffer = this._engine.createIndexBuffer(indices); }; /** * Generates the vertex buffer of the full screen quad blending to the main canvas. */ EffectLayer.prototype._genrateVertexBuffer = function () { // VBO var vertices = []; vertices.push(1, 1); vertices.push(-1, 1); vertices.push(-1, -1); vertices.push(1, -1); var vertexBuffer = new BABYLON.VertexBuffer(this._engine, vertices, BABYLON.VertexBuffer.PositionKind, false, false, 2); this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = vertexBuffer; }; /** * Sets the main texture desired size which is the closest power of two * of the engine canvas size. */ EffectLayer.prototype._setMainTextureSize = function () { if (this._effectLayerOptions.mainTextureFixedSize) { this._mainTextureDesiredSize.width = this._effectLayerOptions.mainTextureFixedSize; this._mainTextureDesiredSize.height = this._effectLayerOptions.mainTextureFixedSize; } else { this._mainTextureDesiredSize.width = this._engine.getRenderWidth() * this._effectLayerOptions.mainTextureRatio; this._mainTextureDesiredSize.height = this._engine.getRenderHeight() * this._effectLayerOptions.mainTextureRatio; this._mainTextureDesiredSize.width = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(this._mainTextureDesiredSize.width, this._maxSize) : this._mainTextureDesiredSize.width; this._mainTextureDesiredSize.height = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(this._mainTextureDesiredSize.height, this._maxSize) : this._mainTextureDesiredSize.height; } this._mainTextureDesiredSize.width = Math.floor(this._mainTextureDesiredSize.width); this._mainTextureDesiredSize.height = Math.floor(this._mainTextureDesiredSize.height); }; /** * Creates the main texture for the effect layer. */ EffectLayer.prototype._createMainTexture = function () { var _this = this; this._mainTexture = new BABYLON.RenderTargetTexture("HighlightLayerMainRTT", { width: this._mainTextureDesiredSize.width, height: this._mainTextureDesiredSize.height }, this._scene, false, true, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT); this._mainTexture.activeCamera = this._effectLayerOptions.camera; this._mainTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE; this._mainTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE; this._mainTexture.anisotropicFilteringLevel = 1; this._mainTexture.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE); this._mainTexture.renderParticles = false; this._mainTexture.renderList = null; this._mainTexture.ignoreCameraViewport = true; // Custom render function this._mainTexture.customRenderFunction = function (opaqueSubMeshes, alphaTestSubMeshes, transparentSubMeshes, depthOnlySubMeshes) { _this.onBeforeRenderMainTextureObservable.notifyObservers(_this); var index; var engine = _this._scene.getEngine(); if (depthOnlySubMeshes.length) { engine.setColorWrite(false); for (index = 0; index < depthOnlySubMeshes.length; index++) { _this._renderSubMesh(depthOnlySubMeshes.data[index]); } engine.setColorWrite(true); } for (index = 0; index < opaqueSubMeshes.length; index++) { _this._renderSubMesh(opaqueSubMeshes.data[index]); } for (index = 0; index < alphaTestSubMeshes.length; index++) { _this._renderSubMesh(alphaTestSubMeshes.data[index]); } for (index = 0; index < transparentSubMeshes.length; index++) { _this._renderSubMesh(transparentSubMeshes.data[index]); } }; this._mainTexture.onClearObservable.add(function (engine) { engine.clear(_this.neutralColor, true, true, true); }); }; /** * Checks for the readiness of the element composing the layer. * @param subMesh the mesh to check for * @param useInstances specify wether or not to use instances to render the mesh * @param emissiveTexture the associated emissive texture used to generate the glow * @return true if ready otherwise, false */ EffectLayer.prototype._isReady = function (subMesh, useInstances, emissiveTexture) { var material = subMesh.getMaterial(); if (!material) { return false; } if (!material.isReady(subMesh.getMesh(), useInstances)) { return false; } var defines = []; var attribs = [BABYLON.VertexBuffer.PositionKind]; var mesh = subMesh.getMesh(); var uv1 = false; var uv2 = false; // Alpha test if (material && material.needAlphaTesting()) { var alphaTexture = material.getAlphaTestTexture(); if (alphaTexture) { defines.push("#define ALPHATEST"); if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind) && alphaTexture.coordinatesIndex === 1) { defines.push("#define DIFFUSEUV2"); uv2 = true; } else if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) { defines.push("#define DIFFUSEUV1"); uv1 = true; } } } // Emissive if (emissiveTexture) { defines.push("#define EMISSIVE"); if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind) && emissiveTexture.coordinatesIndex === 1) { defines.push("#define EMISSIVEUV2"); uv2 = true; } else if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) { defines.push("#define EMISSIVEUV1"); uv1 = true; } } if (uv1) { attribs.push(BABYLON.VertexBuffer.UVKind); defines.push("#define UV1"); } if (uv2) { attribs.push(BABYLON.VertexBuffer.UV2Kind); defines.push("#define UV2"); } // Bones if (mesh.useBones && mesh.computeBonesUsingShaders) { attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind); attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind); if (mesh.numBoneInfluencers > 4) { attribs.push(BABYLON.VertexBuffer.MatricesIndicesExtraKind); attribs.push(BABYLON.VertexBuffer.MatricesWeightsExtraKind); } defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers); defines.push("#define BonesPerMesh " + (mesh.skeleton ? (mesh.skeleton.bones.length + 1) : 0)); } else { defines.push("#define NUM_BONE_INFLUENCERS 0"); } // Morph targets var manager = mesh.morphTargetManager; var morphInfluencers = 0; if (manager) { if (manager.numInfluencers > 0) { defines.push("#define MORPHTARGETS"); morphInfluencers = manager.numInfluencers; defines.push("#define NUM_MORPH_INFLUENCERS " + morphInfluencers); BABYLON.MaterialHelper.PrepareAttributesForMorphTargets(attribs, mesh, { "NUM_MORPH_INFLUENCERS": morphInfluencers }); } } // Instances if (useInstances) { defines.push("#define INSTANCES"); attribs.push("world0"); attribs.push("world1"); attribs.push("world2"); attribs.push("world3"); } // Get correct effect var join = defines.join("\n"); if (this._cachedDefines !== join) { this._cachedDefines = join; this._effectLayerMapGenerationEffect = this._scene.getEngine().createEffect("glowMapGeneration", attribs, ["world", "mBones", "viewProjection", "diffuseMatrix", "color", "emissiveMatrix", "morphTargetInfluences"], ["diffuseSampler", "emissiveSampler"], join, undefined, undefined, undefined, { maxSimultaneousMorphTargets: morphInfluencers }); } return this._effectLayerMapGenerationEffect.isReady(); }; /** * Renders the glowing part of the scene by blending the blurred glowing meshes on top of the rendered scene. */ EffectLayer.prototype.render = function () { var currentEffect = this._mergeEffect; // Check if (!currentEffect.isReady()) return; for (var i = 0; i < this._postProcesses.length; i++) { if (!this._postProcesses[i].isReady()) { return; } } var engine = this._scene.getEngine(); this.onBeforeComposeObservable.notifyObservers(this); // Render engine.enableEffect(currentEffect); engine.setState(false); // VBOs engine.bindBuffers(this._vertexBuffers, this._indexBuffer, currentEffect); // Cache var previousAlphaMode = engine.getAlphaMode(); // Go Blend. engine.setAlphaMode(this._effectLayerOptions.alphaBlendingMode); // Blends the map on the main canvas. this._internalRender(currentEffect); // Restore Alpha engine.setAlphaMode(previousAlphaMode); this.onAfterComposeObservable.notifyObservers(this); // Handle size changes. var size = this._mainTexture.getSize(); this._setMainTextureSize(); if (size.width !== this._mainTextureDesiredSize.width || size.height !== this._mainTextureDesiredSize.height) { // Recreate RTT and post processes on size change. this.onSizeChangedObservable.notifyObservers(this); this._disposeTextureAndPostProcesses(); this._createMainTexture(); this._createTextureAndPostProcesses(); } }; /** * Determine if a given mesh will be used in the current effect. * @param mesh mesh to test * @returns true if the mesh will be used */ EffectLayer.prototype.hasMesh = function (mesh) { return true; }; /** * Returns true if the layer contains information to display, otherwise false. * @returns true if the glow layer should be rendered */ EffectLayer.prototype.shouldRender = function () { return this.isEnabled && this._shouldRender; }; /** * Returns true if the mesh should render, otherwise false. * @param mesh The mesh to render * @returns true if it should render otherwise false */ EffectLayer.prototype._shouldRenderMesh = function (mesh) { return true; }; /** * Returns true if the mesh should render, otherwise false. * @param mesh The mesh to render * @returns true if it should render otherwise false */ EffectLayer.prototype._shouldRenderEmissiveTextureForMesh = function (mesh) { return true; }; /** * Renders the submesh passed in parameter to the generation map. */ EffectLayer.prototype._renderSubMesh = function (subMesh) { var _this = this; if (!this.shouldRender()) { return; } var material = subMesh.getMaterial(); var mesh = subMesh.getRenderingMesh(); var scene = this._scene; var engine = scene.getEngine(); if (!material) { return; } // Do not block in blend mode. if (material.needAlphaBlendingForMesh(mesh)) { return; } // Culling engine.setState(material.backFaceCulling); // Managing instances var batch = mesh._getInstancesRenderList(subMesh._id); if (batch.mustReturn) { return; } // Early Exit per mesh if (!this._shouldRenderMesh(mesh)) { return; } var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined); this._setEmissiveTextureAndColor(mesh, subMesh, material); if (this._isReady(subMesh, hardwareInstancedRendering, this._emissiveTextureAndColor.texture)) { engine.enableEffect(this._effectLayerMapGenerationEffect); mesh._bind(subMesh, this._effectLayerMapGenerationEffect, BABYLON.Material.TriangleFillMode); this._effectLayerMapGenerationEffect.setMatrix("viewProjection", scene.getTransformMatrix()); this._effectLayerMapGenerationEffect.setFloat4("color", this._emissiveTextureAndColor.color.r, this._emissiveTextureAndColor.color.g, this._emissiveTextureAndColor.color.b, this._emissiveTextureAndColor.color.a); // Alpha test if (material && material.needAlphaTesting()) { var alphaTexture = material.getAlphaTestTexture(); if (alphaTexture) { this._effectLayerMapGenerationEffect.setTexture("diffuseSampler", alphaTexture); var textureMatrix = alphaTexture.getTextureMatrix(); if (textureMatrix) { this._effectLayerMapGenerationEffect.setMatrix("diffuseMatrix", textureMatrix); } } } // Glow emissive only if (this._emissiveTextureAndColor.texture) { this._effectLayerMapGenerationEffect.setTexture("emissiveSampler", this._emissiveTextureAndColor.texture); this._effectLayerMapGenerationEffect.setMatrix("emissiveMatrix", this._emissiveTextureAndColor.texture.getTextureMatrix()); } // Bones if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) { this._effectLayerMapGenerationEffect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh)); } // Morph targets BABYLON.MaterialHelper.BindMorphTargetParameters(mesh, this._effectLayerMapGenerationEffect); // Draw mesh._processRendering(subMesh, this._effectLayerMapGenerationEffect, BABYLON.Material.TriangleFillMode, batch, hardwareInstancedRendering, function (isInstance, world) { return _this._effectLayerMapGenerationEffect.setMatrix("world", world); }); } else { // Need to reset refresh rate of the shadowMap this._mainTexture.resetRefreshCounter(); } }; /** * Rebuild the required buffers. * @ignore Internal use only. */ EffectLayer.prototype._rebuild = function () { var vb = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind]; if (vb) { vb._rebuild(); } this._generateIndexBuffer(); }; /** * Dispose only the render target textures and post process. */ EffectLayer.prototype._disposeTextureAndPostProcesses = function () { this._mainTexture.dispose(); for (var i = 0; i < this._postProcesses.length; i++) { if (this._postProcesses[i]) { this._postProcesses[i].dispose(); } } this._postProcesses = []; for (var i = 0; i < this._textures.length; i++) { if (this._textures[i]) { this._textures[i].dispose(); } } this._textures = []; }; /** * Dispose the highlight layer and free resources. */ EffectLayer.prototype.dispose = function () { var vertexBuffer = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind]; if (vertexBuffer) { vertexBuffer.dispose(); this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = null; } if (this._indexBuffer) { this._scene.getEngine()._releaseBuffer(this._indexBuffer); this._indexBuffer = null; } // Clean textures and post processes this._disposeTextureAndPostProcesses(); // Remove from scene var index = this._scene.effectLayers.indexOf(this, 0); if (index > -1) { this._scene.effectLayers.splice(index, 1); } // Callback this.onDisposeObservable.notifyObservers(this); this.onDisposeObservable.clear(); this.onBeforeRenderMainTextureObservable.clear(); this.onBeforeComposeObservable.clear(); this.onAfterComposeObservable.clear(); this.onSizeChangedObservable.clear(); }; /** * Gets the class name of the effect layer * @returns the string with the class name of the effect layer */ EffectLayer.prototype.getClassName = function () { return "EffectLayer"; }; /** * Creates an effect layer from parsed effect layer data * @param parsedEffectLayer defines effect layer data * @param scene defines the current scene * @param rootUrl defines the root URL containing the effect layer information * @returns a parsed effect Layer */ EffectLayer.Parse = function (parsedEffectLayer, scene, rootUrl) { var effectLayerType = BABYLON.Tools.Instantiate(parsedEffectLayer.customType); return effectLayerType.Parse(parsedEffectLayer, scene, rootUrl); }; __decorate([ BABYLON.serialize() ], EffectLayer.prototype, "name", void 0); __decorate([ BABYLON.serializeAsColor4() ], EffectLayer.prototype, "neutralColor", void 0); __decorate([ BABYLON.serialize() ], EffectLayer.prototype, "isEnabled", void 0); __decorate([ BABYLON.serializeAsCameraReference() ], EffectLayer.prototype, "camera", null); return EffectLayer; }()); BABYLON.EffectLayer = EffectLayer; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.effectLayer.js.map var BABYLON; (function (BABYLON) { /** * Special Glow Blur post process only blurring the alpha channel * It enforces keeping the most luminous color in the color channel. */ var GlowBlurPostProcess = /** @class */ (function (_super) { __extends(GlowBlurPostProcess, _super); function GlowBlurPostProcess(name, direction, kernel, options, camera, samplingMode, engine, reusable) { if (samplingMode === void 0) { samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE; } var _this = _super.call(this, name, "glowBlurPostProcess", ["screenSize", "direction", "blurWidth"], null, options, camera, samplingMode, engine, reusable) || this; _this.direction = direction; _this.kernel = kernel; _this.onApplyObservable.add(function (effect) { effect.setFloat2("screenSize", _this.width, _this.height); effect.setVector2("direction", _this.direction); effect.setFloat("blurWidth", _this.kernel); }); return _this; } return GlowBlurPostProcess; }(BABYLON.PostProcess)); /** * The highlight layer Helps adding a glow effect around a mesh. * * Once instantiated in a scene, simply use the pushMesh or removeMesh method to add or remove * glowy meshes to your scene. * * !!! THIS REQUIRES AN ACTIVE STENCIL BUFFER ON THE CANVAS !!! */ var HighlightLayer = /** @class */ (function (_super) { __extends(HighlightLayer, _super); /** * Instantiates a new highlight Layer and references it to the scene.. * @param name The name of the layer * @param scene The scene to use the layer in * @param options Sets of none mandatory options to use with the layer (see IHighlightLayerOptions for more information) */ function HighlightLayer(name, scene, options) { var _this = _super.call(this, name, scene) || this; _this.name = name; /** * Specifies whether or not the inner glow is ACTIVE in the layer. */ _this.innerGlow = true; /** * Specifies whether or not the outer glow is ACTIVE in the layer. */ _this.outerGlow = true; /** * An event triggered when the highlight layer is being blurred. */ _this.onBeforeBlurObservable = new BABYLON.Observable(); /** * An event triggered when the highlight layer has been blurred. */ _this.onAfterBlurObservable = new BABYLON.Observable(); _this._instanceGlowingMeshStencilReference = HighlightLayer.GlowingMeshStencilReference++; _this._meshes = {}; _this._excludedMeshes = {}; _this.neutralColor = HighlightLayer.NeutralColor; // Warn on stencil if (!_this._engine.isStencilEnable) { BABYLON.Tools.Warn("Rendering the Highlight Layer requires the stencil to be active on the canvas. var engine = new BABYLON.Engine(canvas, antialias, { stencil: true }"); } // Adapt options _this._options = __assign({ mainTextureRatio: 0.5, blurTextureSizeRatio: 0.5, blurHorizontalSize: 1.0, blurVerticalSize: 1.0, alphaBlendingMode: BABYLON.Engine.ALPHA_COMBINE, camera: null }, options); // Initialize the layer _this._init({ alphaBlendingMode: _this._options.alphaBlendingMode, camera: _this._options.camera, mainTextureFixedSize: _this._options.mainTextureFixedSize, mainTextureRatio: _this._options.mainTextureRatio }); // Do not render as long as no meshes have been added _this._shouldRender = false; return _this; } Object.defineProperty(HighlightLayer.prototype, "blurHorizontalSize", { /** * Gets the horizontal size of the blur. */ get: function () { return this._horizontalBlurPostprocess.kernel; }, /** * Specifies the horizontal size of the blur. */ set: function (value) { this._horizontalBlurPostprocess.kernel = value; }, enumerable: true, configurable: true }); Object.defineProperty(HighlightLayer.prototype, "blurVerticalSize", { /** * Gets the vertical size of the blur. */ get: function () { return this._verticalBlurPostprocess.kernel; }, /** * Specifies the vertical size of the blur. */ set: function (value) { this._verticalBlurPostprocess.kernel = value; }, enumerable: true, configurable: true }); /** * Get the effect name of the layer. * @return The effect name */ HighlightLayer.prototype.getEffectName = function () { return HighlightLayer.EffectName; }; /** * Create the merge effect. This is the shader use to blit the information back * to the main canvas at the end of the scene rendering. */ HighlightLayer.prototype._createMergeEffect = function () { // Effect return this._engine.createEffect("glowMapMerge", [BABYLON.VertexBuffer.PositionKind], ["offset"], ["textureSampler"], this._options.isStroke ? "#define STROKE \n" : undefined); }; /** * Creates the render target textures and post processes used in the highlight layer. */ HighlightLayer.prototype._createTextureAndPostProcesses = function () { var _this = this; var blurTextureWidth = this._mainTextureDesiredSize.width * this._options.blurTextureSizeRatio; var blurTextureHeight = this._mainTextureDesiredSize.height * this._options.blurTextureSizeRatio; blurTextureWidth = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth; blurTextureHeight = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight; this._blurTexture = new BABYLON.RenderTargetTexture("HighlightLayerBlurRTT", { width: blurTextureWidth, height: blurTextureHeight }, this._scene, false, true, BABYLON.Engine.TEXTURETYPE_HALF_FLOAT); this._blurTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE; this._blurTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE; this._blurTexture.anisotropicFilteringLevel = 16; this._blurTexture.updateSamplingMode(BABYLON.Texture.TRILINEAR_SAMPLINGMODE); this._blurTexture.renderParticles = false; this._blurTexture.ignoreCameraViewport = true; this._textures = [this._blurTexture]; if (this._options.alphaBlendingMode === BABYLON.Engine.ALPHA_COMBINE) { this._downSamplePostprocess = new BABYLON.PassPostProcess("HighlightLayerPPP", this._options.blurTextureSizeRatio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine()); this._downSamplePostprocess.onApplyObservable.add(function (effect) { effect.setTexture("textureSampler", _this._mainTexture); }); this._horizontalBlurPostprocess = new GlowBlurPostProcess("HighlightLayerHBP", new BABYLON.Vector2(1.0, 0), this._options.blurHorizontalSize, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine()); this._horizontalBlurPostprocess.onApplyObservable.add(function (effect) { effect.setFloat2("screenSize", blurTextureWidth, blurTextureHeight); }); this._verticalBlurPostprocess = new GlowBlurPostProcess("HighlightLayerVBP", new BABYLON.Vector2(0, 1.0), this._options.blurVerticalSize, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine()); this._verticalBlurPostprocess.onApplyObservable.add(function (effect) { effect.setFloat2("screenSize", blurTextureWidth, blurTextureHeight); }); this._postProcesses = [this._downSamplePostprocess, this._horizontalBlurPostprocess, this._verticalBlurPostprocess]; } else { this._horizontalBlurPostprocess = new BABYLON.BlurPostProcess("HighlightLayerHBP", new BABYLON.Vector2(1.0, 0), this._options.blurHorizontalSize / 2, { width: blurTextureWidth, height: blurTextureHeight }, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, BABYLON.Engine.TEXTURETYPE_HALF_FLOAT); this._horizontalBlurPostprocess.width = blurTextureWidth; this._horizontalBlurPostprocess.height = blurTextureHeight; this._horizontalBlurPostprocess.onApplyObservable.add(function (effect) { effect.setTexture("textureSampler", _this._mainTexture); }); this._verticalBlurPostprocess = new BABYLON.BlurPostProcess("HighlightLayerVBP", new BABYLON.Vector2(0, 1.0), this._options.blurVerticalSize / 2, { width: blurTextureWidth, height: blurTextureHeight }, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, BABYLON.Engine.TEXTURETYPE_HALF_FLOAT); this._postProcesses = [this._horizontalBlurPostprocess, this._verticalBlurPostprocess]; } this._mainTexture.onAfterUnbindObservable.add(function () { _this.onBeforeBlurObservable.notifyObservers(_this); var internalTexture = _this._blurTexture.getInternalTexture(); if (internalTexture) { _this._scene.postProcessManager.directRender(_this._postProcesses, internalTexture, true); } _this.onAfterBlurObservable.notifyObservers(_this); }); // Prevent autoClear. this._postProcesses.map(function (pp) { pp.autoClear = false; }); }; /** * Returns wether or nood the layer needs stencil enabled during the mesh rendering. */ HighlightLayer.prototype.needStencil = function () { return true; }; /** * Checks for the readiness of the element composing the layer. * @param subMesh the mesh to check for * @param useInstances specify wether or not to use instances to render the mesh * @param emissiveTexture the associated emissive texture used to generate the glow * @return true if ready otherwise, false */ HighlightLayer.prototype.isReady = function (subMesh, useInstances) { var material = subMesh.getMaterial(); var mesh = subMesh.getRenderingMesh(); if (!material || !mesh || !this._meshes) { return false; } var emissiveTexture = null; var highlightLayerMesh = this._meshes[mesh.uniqueId]; if (highlightLayerMesh && highlightLayerMesh.glowEmissiveOnly && material) { emissiveTexture = material.emissiveTexture; } return _super.prototype._isReady.call(this, subMesh, useInstances, emissiveTexture); }; /** * Implementation specific of rendering the generating effect on the main canvas. * @param effect The effect used to render through */ HighlightLayer.prototype._internalRender = function (effect) { // Texture effect.setTexture("textureSampler", this._blurTexture); // Cache var engine = this._engine; var previousStencilBuffer = engine.getStencilBuffer(); var previousStencilFunction = engine.getStencilFunction(); var previousStencilMask = engine.getStencilMask(); var previousStencilOperationPass = engine.getStencilOperationPass(); var previousStencilOperationFail = engine.getStencilOperationFail(); var previousStencilOperationDepthFail = engine.getStencilOperationDepthFail(); var previousStencilReference = engine.getStencilFunctionReference(); // Stencil operations engine.setStencilOperationPass(BABYLON.Engine.REPLACE); engine.setStencilOperationFail(BABYLON.Engine.KEEP); engine.setStencilOperationDepthFail(BABYLON.Engine.KEEP); // Draw order engine.setStencilMask(0x00); engine.setStencilBuffer(true); engine.setStencilFunctionReference(this._instanceGlowingMeshStencilReference); // 2 passes inner outer if (this.outerGlow) { effect.setFloat("offset", 0); engine.setStencilFunction(BABYLON.Engine.NOTEQUAL); engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 6); } if (this.innerGlow) { effect.setFloat("offset", 1); engine.setStencilFunction(BABYLON.Engine.EQUAL); engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 6); } // Restore Cache engine.setStencilFunction(previousStencilFunction); engine.setStencilMask(previousStencilMask); engine.setStencilBuffer(previousStencilBuffer); engine.setStencilOperationPass(previousStencilOperationPass); engine.setStencilOperationFail(previousStencilOperationFail); engine.setStencilOperationDepthFail(previousStencilOperationDepthFail); engine.setStencilFunctionReference(previousStencilReference); }; /** * Returns true if the layer contains information to display, otherwise false. */ HighlightLayer.prototype.shouldRender = function () { if (_super.prototype.shouldRender.call(this)) { return this._meshes ? true : false; } return false; }; /** * Returns true if the mesh should render, otherwise false. * @param mesh The mesh to render * @returns true if it should render otherwise false */ HighlightLayer.prototype._shouldRenderMesh = function (mesh) { // Excluded Mesh if (this._excludedMeshes && this._excludedMeshes[mesh.uniqueId]) { return false; } ; return true; }; /** * Sets the required values for both the emissive texture and and the main color. */ HighlightLayer.prototype._setEmissiveTextureAndColor = function (mesh, subMesh, material) { var highlightLayerMesh = this._meshes[mesh.uniqueId]; if (highlightLayerMesh) { this._emissiveTextureAndColor.color.set(highlightLayerMesh.color.r, highlightLayerMesh.color.g, highlightLayerMesh.color.b, 1.0); } else { this._emissiveTextureAndColor.color.set(this.neutralColor.r, this.neutralColor.g, this.neutralColor.b, this.neutralColor.a); } if (highlightLayerMesh && highlightLayerMesh.glowEmissiveOnly && material) { this._emissiveTextureAndColor.texture = material.emissiveTexture; this._emissiveTextureAndColor.color.set(1.0, 1.0, 1.0, 1.0); } else { this._emissiveTextureAndColor.texture = null; } }; /** * Add a mesh in the exclusion list to prevent it to impact or being impacted by the highlight layer. * @param mesh The mesh to exclude from the highlight layer */ HighlightLayer.prototype.addExcludedMesh = function (mesh) { if (!this._excludedMeshes) { return; } var meshExcluded = this._excludedMeshes[mesh.uniqueId]; if (!meshExcluded) { this._excludedMeshes[mesh.uniqueId] = { mesh: mesh, beforeRender: mesh.onBeforeRenderObservable.add(function (mesh) { mesh.getEngine().setStencilBuffer(false); }), afterRender: mesh.onAfterRenderObservable.add(function (mesh) { mesh.getEngine().setStencilBuffer(true); }), }; } }; /** * Remove a mesh from the exclusion list to let it impact or being impacted by the highlight layer. * @param mesh The mesh to highlight */ HighlightLayer.prototype.removeExcludedMesh = function (mesh) { if (!this._excludedMeshes) { return; } var meshExcluded = this._excludedMeshes[mesh.uniqueId]; if (meshExcluded) { if (meshExcluded.beforeRender) { mesh.onBeforeRenderObservable.remove(meshExcluded.beforeRender); } if (meshExcluded.afterRender) { mesh.onAfterRenderObservable.remove(meshExcluded.afterRender); } } this._excludedMeshes[mesh.uniqueId] = null; }; /** * Determine if a given mesh will be highlighted by the current HighlightLayer * @param mesh mesh to test * @returns true if the mesh will be highlighted by the current HighlightLayer */ HighlightLayer.prototype.hasMesh = function (mesh) { if (!this._meshes) { return false; } return this._meshes[mesh.uniqueId] !== undefined && this._meshes[mesh.uniqueId] !== null; }; /** * Add a mesh in the highlight layer in order to make it glow with the chosen color. * @param mesh The mesh to highlight * @param color The color of the highlight * @param glowEmissiveOnly Extract the glow from the emissive texture */ HighlightLayer.prototype.addMesh = function (mesh, color, glowEmissiveOnly) { var _this = this; if (glowEmissiveOnly === void 0) { glowEmissiveOnly = false; } if (!this._meshes) { return; } var meshHighlight = this._meshes[mesh.uniqueId]; if (meshHighlight) { meshHighlight.color = color; } else { this._meshes[mesh.uniqueId] = { mesh: mesh, color: color, // Lambda required for capture due to Observable this context observerHighlight: mesh.onBeforeRenderObservable.add(function (mesh) { if (_this._excludedMeshes && _this._excludedMeshes[mesh.uniqueId]) { _this._defaultStencilReference(mesh); } else { mesh.getScene().getEngine().setStencilFunctionReference(_this._instanceGlowingMeshStencilReference); } }), observerDefault: mesh.onAfterRenderObservable.add(this._defaultStencilReference), glowEmissiveOnly: glowEmissiveOnly }; } this._shouldRender = true; }; /** * Remove a mesh from the highlight layer in order to make it stop glowing. * @param mesh The mesh to highlight */ HighlightLayer.prototype.removeMesh = function (mesh) { if (!this._meshes) { return; } var meshHighlight = this._meshes[mesh.uniqueId]; if (meshHighlight) { if (meshHighlight.observerHighlight) { mesh.onBeforeRenderObservable.remove(meshHighlight.observerHighlight); } if (meshHighlight.observerDefault) { mesh.onAfterRenderObservable.remove(meshHighlight.observerDefault); } delete this._meshes[mesh.uniqueId]; } this._shouldRender = false; for (var meshHighlightToCheck in this._meshes) { if (this._meshes[meshHighlightToCheck]) { this._shouldRender = true; break; } } }; /** * Force the stencil to the normal expected value for none glowing parts */ HighlightLayer.prototype._defaultStencilReference = function (mesh) { mesh.getScene().getEngine().setStencilFunctionReference(HighlightLayer.NormalMeshStencilReference); }; /** * Free any resources and references associated to a mesh. * Internal use * @param mesh The mesh to free. */ HighlightLayer.prototype._disposeMesh = function (mesh) { this.removeMesh(mesh); this.removeExcludedMesh(mesh); }; /** * Dispose the highlight layer and free resources. */ HighlightLayer.prototype.dispose = function () { if (this._meshes) { // Clean mesh references for (var id in this._meshes) { var meshHighlight = this._meshes[id]; if (meshHighlight && meshHighlight.mesh) { if (meshHighlight.observerHighlight) { meshHighlight.mesh.onBeforeRenderObservable.remove(meshHighlight.observerHighlight); } if (meshHighlight.observerDefault) { meshHighlight.mesh.onAfterRenderObservable.remove(meshHighlight.observerDefault); } } } this._meshes = null; } if (this._excludedMeshes) { for (var id in this._excludedMeshes) { var meshHighlight = this._excludedMeshes[id]; if (meshHighlight) { if (meshHighlight.beforeRender) { meshHighlight.mesh.onBeforeRenderObservable.remove(meshHighlight.beforeRender); } if (meshHighlight.afterRender) { meshHighlight.mesh.onAfterRenderObservable.remove(meshHighlight.afterRender); } } } this._excludedMeshes = null; } _super.prototype.dispose.call(this); }; /** * Gets the class name of the effect layer * @returns the string with the class name of the effect layer */ HighlightLayer.prototype.getClassName = function () { return "HighlightLayer"; }; /** * Serializes this Highlight layer * @returns a serialized Highlight layer object */ HighlightLayer.prototype.serialize = function () { var serializationObject = BABYLON.SerializationHelper.Serialize(this); serializationObject.customType = "BABYLON.HighlightLayer"; // Highlighted meshes serializationObject.meshes = []; if (this._meshes) { for (var m in this._meshes) { var mesh = this._meshes[m]; if (mesh) { serializationObject.meshes.push({ glowEmissiveOnly: mesh.glowEmissiveOnly, color: mesh.color.asArray(), meshId: mesh.mesh.id }); } } } // Excluded meshes serializationObject.excludedMeshes = []; if (this._excludedMeshes) { for (var e in this._excludedMeshes) { var excludedMesh = this._excludedMeshes[e]; if (excludedMesh) { serializationObject.excludedMeshes.push(excludedMesh.mesh.id); } } } return serializationObject; }; /** * Creates a Highlight layer from parsed Highlight layer data * @param parsedHightlightLayer defines the Highlight layer data * @param scene defines the current scene * @param rootUrl defines the root URL containing the Highlight layer information * @returns a parsed Highlight layer */ HighlightLayer.Parse = function (parsedHightlightLayer, scene, rootUrl) { var hl = BABYLON.SerializationHelper.Parse(function () { return new HighlightLayer(parsedHightlightLayer.name, scene, parsedHightlightLayer.options); }, parsedHightlightLayer, scene, rootUrl); var index; // Excluded meshes for (index = 0; index < parsedHightlightLayer.excludedMeshes.length; index++) { var mesh = scene.getMeshByID(parsedHightlightLayer.excludedMeshes[index]); if (mesh) { hl.addExcludedMesh(mesh); } } // Included meshes for (index = 0; index < parsedHightlightLayer.meshes.length; index++) { var highlightedMesh = parsedHightlightLayer.meshes[index]; var mesh = scene.getMeshByID(highlightedMesh.meshId); if (mesh) { hl.addMesh(mesh, BABYLON.Color3.FromArray(highlightedMesh.color), highlightedMesh.glowEmissiveOnly); } } return hl; }; /** * Effect Name of the highlight layer. */ HighlightLayer.EffectName = "HighlightLayer"; /** * The neutral color used during the preparation of the glow effect. * This is black by default as the blend operation is a blend operation. */ HighlightLayer.NeutralColor = new BABYLON.Color4(0, 0, 0, 0); /** * Stencil value used for glowing meshes. */ HighlightLayer.GlowingMeshStencilReference = 0x02; /** * Stencil value used for the other meshes in the scene. */ HighlightLayer.NormalMeshStencilReference = 0x01; __decorate([ BABYLON.serialize() ], HighlightLayer.prototype, "innerGlow", void 0); __decorate([ BABYLON.serialize() ], HighlightLayer.prototype, "outerGlow", void 0); __decorate([ BABYLON.serialize() ], HighlightLayer.prototype, "blurHorizontalSize", null); __decorate([ BABYLON.serialize() ], HighlightLayer.prototype, "blurVerticalSize", null); __decorate([ BABYLON.serialize("options") ], HighlightLayer.prototype, "_options", void 0); return HighlightLayer; }(BABYLON.EffectLayer)); BABYLON.HighlightLayer = HighlightLayer; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.highlightLayer.js.map var BABYLON; (function (BABYLON) { /** * The glow layer Helps adding a glow effect around the emissive parts of a mesh. * * Once instantiated in a scene, simply use the pushMesh or removeMesh method to add or remove * glowy meshes to your scene. * * Documentation: https://doc.babylonjs.com/how_to/glow_layer */ var GlowLayer = /** @class */ (function (_super) { __extends(GlowLayer, _super); /** * Instantiates a new glow Layer and references it to the scene. * @param name The name of the layer * @param scene The scene to use the layer in * @param options Sets of none mandatory options to use with the layer (see IGlowLayerOptions for more information) */ function GlowLayer(name, scene, options) { var _this = _super.call(this, name, scene) || this; _this._intensity = 1.0; _this._includedOnlyMeshes = []; _this._excludedMeshes = []; _this.neutralColor = new BABYLON.Color4(0, 0, 0, 1); // Adapt options _this._options = __assign({ mainTextureRatio: GlowLayer.DefaultTextureRatio, blurKernelSize: 32, mainTextureFixedSize: undefined, camera: null, mainTextureSamples: 1 }, options); // Initialize the layer _this._init({ alphaBlendingMode: BABYLON.Engine.ALPHA_ADD, camera: _this._options.camera, mainTextureFixedSize: _this._options.mainTextureFixedSize, mainTextureRatio: _this._options.mainTextureRatio }); return _this; } Object.defineProperty(GlowLayer.prototype, "blurKernelSize", { /** * Gets the kernel size of the blur. */ get: function () { return this._horizontalBlurPostprocess1.kernel; }, /** * Sets the kernel size of the blur. */ set: function (value) { this._horizontalBlurPostprocess1.kernel = value; this._verticalBlurPostprocess1.kernel = value; this._horizontalBlurPostprocess2.kernel = value; this._verticalBlurPostprocess2.kernel = value; }, enumerable: true, configurable: true }); Object.defineProperty(GlowLayer.prototype, "intensity", { /** * Gets the glow intensity. */ get: function () { return this._intensity; }, /** * Sets the glow intensity. */ set: function (value) { this._intensity = value; }, enumerable: true, configurable: true }); /** * Get the effect name of the layer. * @return The effect name */ GlowLayer.prototype.getEffectName = function () { return GlowLayer.EffectName; }; /** * Create the merge effect. This is the shader use to blit the information back * to the main canvas at the end of the scene rendering. */ GlowLayer.prototype._createMergeEffect = function () { // Effect return this._engine.createEffect("glowMapMerge", [BABYLON.VertexBuffer.PositionKind], ["offset"], ["textureSampler", "textureSampler2"], "#define EMISSIVE \n"); }; /** * Creates the render target textures and post processes used in the glow layer. */ GlowLayer.prototype._createTextureAndPostProcesses = function () { var _this = this; var blurTextureWidth = this._mainTextureDesiredSize.width; var blurTextureHeight = this._mainTextureDesiredSize.height; blurTextureWidth = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth; blurTextureHeight = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight; var textureType = 0; if (this._engine.getCaps().textureHalfFloatRender) { textureType = BABYLON.Engine.TEXTURETYPE_HALF_FLOAT; } else { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; } this._blurTexture1 = new BABYLON.RenderTargetTexture("GlowLayerBlurRTT", { width: blurTextureWidth, height: blurTextureHeight }, this._scene, false, true, textureType); this._blurTexture1.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE; this._blurTexture1.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE; this._blurTexture1.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE); this._blurTexture1.renderParticles = false; this._blurTexture1.ignoreCameraViewport = true; var blurTextureWidth2 = Math.floor(blurTextureWidth / 2); var blurTextureHeight2 = Math.floor(blurTextureHeight / 2); this._blurTexture2 = new BABYLON.RenderTargetTexture("GlowLayerBlurRTT2", { width: blurTextureWidth2, height: blurTextureHeight2 }, this._scene, false, true, textureType); this._blurTexture2.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE; this._blurTexture2.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE; this._blurTexture2.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE); this._blurTexture2.renderParticles = false; this._blurTexture2.ignoreCameraViewport = true; this._textures = [this._blurTexture1, this._blurTexture2]; this._horizontalBlurPostprocess1 = new BABYLON.BlurPostProcess("GlowLayerHBP1", new BABYLON.Vector2(1.0, 0), this._options.blurKernelSize / 2, { width: blurTextureWidth, height: blurTextureHeight }, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType); this._horizontalBlurPostprocess1.width = blurTextureWidth; this._horizontalBlurPostprocess1.height = blurTextureHeight; this._horizontalBlurPostprocess1.onApplyObservable.add(function (effect) { effect.setTexture("textureSampler", _this._mainTexture); }); this._verticalBlurPostprocess1 = new BABYLON.BlurPostProcess("GlowLayerVBP1", new BABYLON.Vector2(0, 1.0), this._options.blurKernelSize / 2, { width: blurTextureWidth, height: blurTextureHeight }, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType); this._horizontalBlurPostprocess2 = new BABYLON.BlurPostProcess("GlowLayerHBP2", new BABYLON.Vector2(1.0, 0), this._options.blurKernelSize / 2, { width: blurTextureWidth2, height: blurTextureHeight2 }, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType); this._horizontalBlurPostprocess2.width = blurTextureWidth2; this._horizontalBlurPostprocess2.height = blurTextureHeight2; this._horizontalBlurPostprocess2.onApplyObservable.add(function (effect) { effect.setTexture("textureSampler", _this._blurTexture1); }); this._verticalBlurPostprocess2 = new BABYLON.BlurPostProcess("GlowLayerVBP2", new BABYLON.Vector2(0, 1.0), this._options.blurKernelSize / 2, { width: blurTextureWidth2, height: blurTextureHeight2 }, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType); this._postProcesses = [this._horizontalBlurPostprocess1, this._verticalBlurPostprocess1, this._horizontalBlurPostprocess2, this._verticalBlurPostprocess2]; this._postProcesses1 = [this._horizontalBlurPostprocess1, this._verticalBlurPostprocess1]; this._postProcesses2 = [this._horizontalBlurPostprocess2, this._verticalBlurPostprocess2]; this._mainTexture.samples = this._options.mainTextureSamples; this._mainTexture.onAfterUnbindObservable.add(function () { var internalTexture = _this._blurTexture1.getInternalTexture(); if (internalTexture) { _this._scene.postProcessManager.directRender(_this._postProcesses1, internalTexture, true); internalTexture = _this._blurTexture2.getInternalTexture(); if (internalTexture) { _this._scene.postProcessManager.directRender(_this._postProcesses2, internalTexture, true); } } }); // Prevent autoClear. this._postProcesses.map(function (pp) { pp.autoClear = false; }); }; /** * Checks for the readiness of the element composing the layer. * @param subMesh the mesh to check for * @param useInstances specify wether or not to use instances to render the mesh * @param emissiveTexture the associated emissive texture used to generate the glow * @return true if ready otherwise, false */ GlowLayer.prototype.isReady = function (subMesh, useInstances) { var material = subMesh.getMaterial(); var mesh = subMesh.getRenderingMesh(); if (!material || !mesh) { return false; } var emissiveTexture = material.emissiveTexture; return _super.prototype._isReady.call(this, subMesh, useInstances, emissiveTexture); }; /** * Returns wether or nood the layer needs stencil enabled during the mesh rendering. */ GlowLayer.prototype.needStencil = function () { return false; }; /** * Implementation specific of rendering the generating effect on the main canvas. * @param effect The effect used to render through */ GlowLayer.prototype._internalRender = function (effect) { // Texture effect.setTexture("textureSampler", this._blurTexture1); effect.setTexture("textureSampler2", this._blurTexture2); effect.setFloat("offset", this._intensity); // Cache var engine = this._engine; var previousStencilBuffer = engine.getStencilBuffer(); // Draw order engine.setStencilBuffer(false); engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 6); // Draw order engine.setStencilBuffer(previousStencilBuffer); }; /** * Sets the required values for both the emissive texture and and the main color. */ GlowLayer.prototype._setEmissiveTextureAndColor = function (mesh, subMesh, material) { var textureLevel = 1.0; if (this.customEmissiveTextureSelector) { this._emissiveTextureAndColor.texture = this.customEmissiveTextureSelector(mesh, subMesh, material); } else { if (material) { this._emissiveTextureAndColor.texture = material.emissiveTexture; if (this._emissiveTextureAndColor.texture) { textureLevel = this._emissiveTextureAndColor.texture.level; } } else { this._emissiveTextureAndColor.texture = null; } } if (this.customEmissiveColorSelector) { this.customEmissiveColorSelector(mesh, subMesh, material, this._emissiveTextureAndColor.color); } else { if (material.emissiveColor) { this._emissiveTextureAndColor.color.set(material.emissiveColor.r * textureLevel, material.emissiveColor.g * textureLevel, material.emissiveColor.b * textureLevel, 1.0); } else { this._emissiveTextureAndColor.color.set(this.neutralColor.r, this.neutralColor.g, this.neutralColor.b, this.neutralColor.a); } } }; /** * Returns true if the mesh should render, otherwise false. * @param mesh The mesh to render * @returns true if it should render otherwise false */ GlowLayer.prototype._shouldRenderMesh = function (mesh) { return this.hasMesh(mesh); }; /** * Add a mesh in the exclusion list to prevent it to impact or being impacted by the glow layer. * @param mesh The mesh to exclude from the glow layer */ GlowLayer.prototype.addExcludedMesh = function (mesh) { if (this._excludedMeshes.indexOf(mesh.uniqueId) === -1) { this._excludedMeshes.push(mesh.uniqueId); } }; /** * Remove a mesh from the exclusion list to let it impact or being impacted by the glow layer. * @param mesh The mesh to remove */ GlowLayer.prototype.removeExcludedMesh = function (mesh) { var index = this._excludedMeshes.indexOf(mesh.uniqueId); if (index !== -1) { this._excludedMeshes.splice(index, 1); } }; /** * Add a mesh in the inclusion list to impact or being impacted by the glow layer. * @param mesh The mesh to include in the glow layer */ GlowLayer.prototype.addIncludedOnlyMesh = function (mesh) { if (this._includedOnlyMeshes.indexOf(mesh.uniqueId) === -1) { this._includedOnlyMeshes.push(mesh.uniqueId); } }; /** * Remove a mesh from the Inclusion list to prevent it to impact or being impacted by the glow layer. * @param mesh The mesh to remove */ GlowLayer.prototype.removeIncludedOnlyMesh = function (mesh) { var index = this._includedOnlyMeshes.indexOf(mesh.uniqueId); if (index !== -1) { this._includedOnlyMeshes.splice(index, 1); } }; /** * Determine if a given mesh will be used in the glow layer * @param mesh The mesh to test * @returns true if the mesh will be highlighted by the current glow layer */ GlowLayer.prototype.hasMesh = function (mesh) { // Included Mesh if (this._includedOnlyMeshes.length) { return this._includedOnlyMeshes.indexOf(mesh.uniqueId) !== -1; } ; // Excluded Mesh if (this._excludedMeshes.length) { return this._excludedMeshes.indexOf(mesh.uniqueId) === -1; } ; return true; }; /** * Free any resources and references associated to a mesh. * Internal use * @param mesh The mesh to free. */ GlowLayer.prototype._disposeMesh = function (mesh) { this.removeIncludedOnlyMesh(mesh); this.removeExcludedMesh(mesh); }; /** * Gets the class name of the effect layer * @returns the string with the class name of the effect layer */ GlowLayer.prototype.getClassName = function () { return "GlowLayer"; }; /** * Serializes this glow layer * @returns a serialized glow layer object */ GlowLayer.prototype.serialize = function () { var serializationObject = BABYLON.SerializationHelper.Serialize(this); serializationObject.customType = "BABYLON.GlowLayer"; var index; // Included meshes serializationObject.includedMeshes = []; if (this._includedOnlyMeshes.length) { for (index = 0; index < this._includedOnlyMeshes.length; index++) { var mesh = this._scene.getMeshByUniqueID(this._includedOnlyMeshes[index]); if (mesh) { serializationObject.includedMeshes.push(mesh.id); } } } // Excluded meshes serializationObject.excludedMeshes = []; if (this._excludedMeshes.length) { for (index = 0; index < this._excludedMeshes.length; index++) { var mesh = this._scene.getMeshByUniqueID(this._excludedMeshes[index]); if (mesh) { serializationObject.excludedMeshes.push(mesh.id); } } } return serializationObject; }; /** * Creates a Glow Layer from parsed glow layer data * @param parsedGlowLayer defines glow layer data * @param scene defines the current scene * @param rootUrl defines the root URL containing the glow layer information * @returns a parsed Glow Layer */ GlowLayer.Parse = function (parsedGlowLayer, scene, rootUrl) { var gl = BABYLON.SerializationHelper.Parse(function () { return new GlowLayer(parsedGlowLayer.name, scene, parsedGlowLayer.options); }, parsedGlowLayer, scene, rootUrl); var index; // Excluded meshes for (index = 0; index < parsedGlowLayer.excludedMeshes.length; index++) { var mesh = scene.getMeshByID(parsedGlowLayer.excludedMeshes[index]); if (mesh) { gl.addExcludedMesh(mesh); } } // Included meshes for (index = 0; index < parsedGlowLayer.includedMeshes.length; index++) { var mesh = scene.getMeshByID(parsedGlowLayer.includedMeshes[index]); if (mesh) { gl.addIncludedOnlyMesh(mesh); } } return gl; }; /** * Effect Name of the layer. */ GlowLayer.EffectName = "GlowLayer"; /** * The default blur kernel size used for the glow. */ GlowLayer.DefaultBlurKernelSize = 32; /** * The default texture size ratio used for the glow. */ GlowLayer.DefaultTextureRatio = 0.5; __decorate([ BABYLON.serialize() ], GlowLayer.prototype, "blurKernelSize", null); __decorate([ BABYLON.serialize() ], GlowLayer.prototype, "intensity", null); __decorate([ BABYLON.serialize("options") ], GlowLayer.prototype, "_options", void 0); return GlowLayer; }(BABYLON.EffectLayer)); BABYLON.GlowLayer = GlowLayer; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.glowLayer.js.map var BABYLON; (function (BABYLON) { /** * Defines the list of states available for a task inside a {BABYLON.AssetsManager} */ var AssetTaskState; (function (AssetTaskState) { /** * Initialization */ AssetTaskState[AssetTaskState["INIT"] = 0] = "INIT"; /** * Running */ AssetTaskState[AssetTaskState["RUNNING"] = 1] = "RUNNING"; /** * Done */ AssetTaskState[AssetTaskState["DONE"] = 2] = "DONE"; /** * Error */ AssetTaskState[AssetTaskState["ERROR"] = 3] = "ERROR"; })(AssetTaskState = BABYLON.AssetTaskState || (BABYLON.AssetTaskState = {})); /** * Define an abstract asset task used with a {BABYLON.AssetsManager} class to load assets into a scene */ var AbstractAssetTask = /** @class */ (function () { /** * Creates a new {BABYLON.AssetsManager} * @param name defines the name of the task */ function AbstractAssetTask( /** * Task name */ name) { this.name = name; this._isCompleted = false; this._taskState = AssetTaskState.INIT; } Object.defineProperty(AbstractAssetTask.prototype, "isCompleted", { /** * Get if the task is completed */ get: function () { return this._isCompleted; }, enumerable: true, configurable: true }); Object.defineProperty(AbstractAssetTask.prototype, "taskState", { /** * Gets the current state of the task */ get: function () { return this._taskState; }, enumerable: true, configurable: true }); Object.defineProperty(AbstractAssetTask.prototype, "errorObject", { /** * Gets the current error object (if task is in error) */ get: function () { return this._errorObject; }, enumerable: true, configurable: true }); /** * Internal only * @ignore */ AbstractAssetTask.prototype._setErrorObject = function (message, exception) { if (this._errorObject) { return; } this._errorObject = { message: message, exception: exception }; }; /** * Execute the current task * @param scene defines the scene where you want your assets to be loaded * @param onSuccess is a callback called when the task is successfully executed * @param onError is a callback called if an error occurs */ AbstractAssetTask.prototype.run = function (scene, onSuccess, onError) { var _this = this; this._taskState = AssetTaskState.RUNNING; this.runTask(scene, function () { _this.onDoneCallback(onSuccess, onError); }, function (msg, exception) { _this.onErrorCallback(onError, msg, exception); }); }; /** * Execute the current task * @param scene defines the scene where you want your assets to be loaded * @param onSuccess is a callback called when the task is successfully executed * @param onError is a callback called if an error occurs */ AbstractAssetTask.prototype.runTask = function (scene, onSuccess, onError) { throw new Error("runTask is not implemented"); }; AbstractAssetTask.prototype.onErrorCallback = function (onError, message, exception) { this._taskState = AssetTaskState.ERROR; this._errorObject = { message: message, exception: exception }; if (this.onError) { this.onError(this, message, exception); } onError(); }; AbstractAssetTask.prototype.onDoneCallback = function (onSuccess, onError) { try { this._taskState = AssetTaskState.DONE; this._isCompleted = true; if (this.onSuccess) { this.onSuccess(this); } onSuccess(); } catch (e) { this.onErrorCallback(onError, "Task is done, error executing success callback(s)", e); } }; return AbstractAssetTask; }()); BABYLON.AbstractAssetTask = AbstractAssetTask; /** * Class used to share progress information about assets loading */ var AssetsProgressEvent = /** @class */ (function () { /** * Creates a {BABYLON.AssetsProgressEvent} * @param remainingCount defines the number of remaining tasks to process * @param totalCount defines the total number of tasks * @param task defines the task that was just processed */ function AssetsProgressEvent(remainingCount, totalCount, task) { this.remainingCount = remainingCount; this.totalCount = totalCount; this.task = task; } return AssetsProgressEvent; }()); BABYLON.AssetsProgressEvent = AssetsProgressEvent; /** * Define a task used by {BABYLON.AssetsManager} to load meshes */ var MeshAssetTask = /** @class */ (function (_super) { __extends(MeshAssetTask, _super); /** * Creates a new {BABYLON.MeshAssetTask} * @param name defines the name of the task * @param meshesNames defines the list of mesh's names you want to load * @param rootUrl defines the root url to use as a base to load your meshes and associated resources * @param sceneFilename defines the filename of the scene to load from */ function MeshAssetTask( /** * Defines the name of the task */ name, /** * Defines the list of mesh's names you want to load */ meshesNames, /** * Defines the root url to use as a base to load your meshes and associated resources */ rootUrl, /** * Defines the filename of the scene to load from */ sceneFilename) { var _this = _super.call(this, name) || this; _this.name = name; _this.meshesNames = meshesNames; _this.rootUrl = rootUrl; _this.sceneFilename = sceneFilename; return _this; } /** * Execute the current task * @param scene defines the scene where you want your assets to be loaded * @param onSuccess is a callback called when the task is successfully executed * @param onError is a callback called if an error occurs */ MeshAssetTask.prototype.runTask = function (scene, onSuccess, onError) { var _this = this; BABYLON.SceneLoader.ImportMesh(this.meshesNames, this.rootUrl, this.sceneFilename, scene, function (meshes, particleSystems, skeletons) { _this.loadedMeshes = meshes; _this.loadedParticleSystems = particleSystems; _this.loadedSkeletons = skeletons; onSuccess(); }, null, function (scene, message, exception) { onError(message, exception); }); }; return MeshAssetTask; }(AbstractAssetTask)); BABYLON.MeshAssetTask = MeshAssetTask; /** * Define a task used by {BABYLON.AssetsManager} to load text content */ var TextFileAssetTask = /** @class */ (function (_super) { __extends(TextFileAssetTask, _super); /** * Creates a new TextFileAssetTask object * @param name defines the name of the task * @param url defines the location of the file to load */ function TextFileAssetTask( /** * Defines the name of the task */ name, /** * Defines the location of the file to load */ url) { var _this = _super.call(this, name) || this; _this.name = name; _this.url = url; return _this; } /** * Execute the current task * @param scene defines the scene where you want your assets to be loaded * @param onSuccess is a callback called when the task is successfully executed * @param onError is a callback called if an error occurs */ TextFileAssetTask.prototype.runTask = function (scene, onSuccess, onError) { var _this = this; scene._loadFile(this.url, function (data) { _this.text = data; onSuccess(); }, undefined, false, false, function (request, exception) { if (request) { onError(request.status + " " + request.statusText, exception); } }); }; return TextFileAssetTask; }(AbstractAssetTask)); BABYLON.TextFileAssetTask = TextFileAssetTask; /** * Define a task used by {BABYLON.AssetsManager} to load binary data */ var BinaryFileAssetTask = /** @class */ (function (_super) { __extends(BinaryFileAssetTask, _super); /** * Creates a new BinaryFileAssetTask object * @param name defines the name of the new task * @param url defines the location of the file to load */ function BinaryFileAssetTask( /** * Defines the name of the task */ name, /** * Defines the location of the file to load */ url) { var _this = _super.call(this, name) || this; _this.name = name; _this.url = url; return _this; } /** * Execute the current task * @param scene defines the scene where you want your assets to be loaded * @param onSuccess is a callback called when the task is successfully executed * @param onError is a callback called if an error occurs */ BinaryFileAssetTask.prototype.runTask = function (scene, onSuccess, onError) { var _this = this; scene._loadFile(this.url, function (data) { _this.data = data; onSuccess(); }, undefined, true, true, function (request, exception) { if (request) { onError(request.status + " " + request.statusText, exception); } }); }; return BinaryFileAssetTask; }(AbstractAssetTask)); BABYLON.BinaryFileAssetTask = BinaryFileAssetTask; /** * Define a task used by {BABYLON.AssetsManager} to load images */ var ImageAssetTask = /** @class */ (function (_super) { __extends(ImageAssetTask, _super); /** * Creates a new ImageAssetTask * @param name defines the name of the task * @param url defines the location of the image to load */ function ImageAssetTask( /** * Defines the name of the task */ name, /** * Defines the location of the image to load */ url) { var _this = _super.call(this, name) || this; _this.name = name; _this.url = url; return _this; } /** * Execute the current task * @param scene defines the scene where you want your assets to be loaded * @param onSuccess is a callback called when the task is successfully executed * @param onError is a callback called if an error occurs */ ImageAssetTask.prototype.runTask = function (scene, onSuccess, onError) { var _this = this; var img = new Image(); BABYLON.Tools.SetCorsBehavior(this.url, img); img.onload = function () { _this.image = img; onSuccess(); }; img.onerror = function (err) { onError("Error loading image", err); }; img.src = this.url; }; return ImageAssetTask; }(AbstractAssetTask)); BABYLON.ImageAssetTask = ImageAssetTask; /** * Define a task used by {BABYLON.AssetsManager} to load 2D textures */ var TextureAssetTask = /** @class */ (function (_super) { __extends(TextureAssetTask, _super); /** * Creates a new TextureAssetTask object * @param name defines the name of the task * @param url defines the location of the file to load * @param noMipmap defines if mipmap should not be generated (default is false) * @param invertY defines if texture must be inverted on Y axis (default is false) * @param samplingMode defines the sampling mode to use (default is BABYLON.Texture.TRILINEAR_SAMPLINGMODE) */ function TextureAssetTask( /** * Defines the name of the task */ name, /** * Defines the location of the file to load */ url, /** * Defines if mipmap should not be generated (default is false) */ noMipmap, /** * Defines if texture must be inverted on Y axis (default is false) */ invertY, /** * Defines the sampling mode to use (default is BABYLON.Texture.TRILINEAR_SAMPLINGMODE) */ samplingMode) { if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; } var _this = _super.call(this, name) || this; _this.name = name; _this.url = url; _this.noMipmap = noMipmap; _this.invertY = invertY; _this.samplingMode = samplingMode; return _this; } /** * Execute the current task * @param scene defines the scene where you want your assets to be loaded * @param onSuccess is a callback called when the task is successfully executed * @param onError is a callback called if an error occurs */ TextureAssetTask.prototype.runTask = function (scene, onSuccess, onError) { var onload = function () { onSuccess(); }; var onerror = function (message, exception) { onError(message, exception); }; this.texture = new BABYLON.Texture(this.url, scene, this.noMipmap, this.invertY, this.samplingMode, onload, onerror); }; return TextureAssetTask; }(AbstractAssetTask)); BABYLON.TextureAssetTask = TextureAssetTask; /** * Define a task used by {BABYLON.AssetsManager} to load cube textures */ var CubeTextureAssetTask = /** @class */ (function (_super) { __extends(CubeTextureAssetTask, _super); /** * Creates a new CubeTextureAssetTask * @param name defines the name of the task * @param url defines the location of the files to load (You have to specify the folder where the files are + filename with no extension) * @param extensions defines the extensions to use to load files (["_px", "_py", "_pz", "_nx", "_ny", "_nz"] by default) * @param noMipmap defines if mipmaps should not be generated (default is false) * @param files defines the explicit list of files (undefined by default) */ function CubeTextureAssetTask( /** * Defines the name of the task */ name, /** * Defines the location of the files to load (You have to specify the folder where the files are + filename with no extension) */ url, /** * Defines the extensions to use to load files (["_px", "_py", "_pz", "_nx", "_ny", "_nz"] by default) */ extensions, /** * Defines if mipmaps should not be generated (default is false) */ noMipmap, /** * Defines the explicit list of files (undefined by default) */ files) { var _this = _super.call(this, name) || this; _this.name = name; _this.url = url; _this.extensions = extensions; _this.noMipmap = noMipmap; _this.files = files; return _this; } /** * Execute the current task * @param scene defines the scene where you want your assets to be loaded * @param onSuccess is a callback called when the task is successfully executed * @param onError is a callback called if an error occurs */ CubeTextureAssetTask.prototype.runTask = function (scene, onSuccess, onError) { var onload = function () { onSuccess(); }; var onerror = function (message, exception) { onError(message, exception); }; this.texture = new BABYLON.CubeTexture(this.url, scene, this.extensions, this.noMipmap, this.files, onload, onerror); }; return CubeTextureAssetTask; }(AbstractAssetTask)); BABYLON.CubeTextureAssetTask = CubeTextureAssetTask; /** * Define a task used by {BABYLON.AssetsManager} to load HDR cube textures */ var HDRCubeTextureAssetTask = /** @class */ (function (_super) { __extends(HDRCubeTextureAssetTask, _super); /** * Creates a new HDRCubeTextureAssetTask object * @param name defines the name of the task * @param url defines the location of the file to load * @param size defines the desired size (the more it increases the longer the generation will be) If the size is omitted this implies you are using a preprocessed cubemap. * @param noMipmap defines if mipmaps should not be generated (default is false) * @param generateHarmonics specifies whether you want to extract the polynomial harmonics during the generation process (default is true) * @param useInGammaSpace specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space) (default is false) * @param usePMREMGenerator specifies whether or not to generate the CubeMap through CubeMapGen to avoid seams issue at run time (default is false) */ function HDRCubeTextureAssetTask( /** * Defines the name of the task */ name, /** * Defines the location of the file to load */ url, /** * Defines the desired size (the more it increases the longer the generation will be) If the size is omitted this implies you are using a preprocessed cubemap. */ size, /** * Defines if mipmaps should not be generated (default is false) */ noMipmap, /** * Specifies whether you want to extract the polynomial harmonics during the generation process (default is true) */ generateHarmonics, /** * Specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space) (default is false) */ useInGammaSpace, /** * Specifies whether or not to generate the CubeMap through CubeMapGen to avoid seams issue at run time (default is false) */ usePMREMGenerator) { if (noMipmap === void 0) { noMipmap = false; } if (generateHarmonics === void 0) { generateHarmonics = true; } if (useInGammaSpace === void 0) { useInGammaSpace = false; } if (usePMREMGenerator === void 0) { usePMREMGenerator = false; } var _this = _super.call(this, name) || this; _this.name = name; _this.url = url; _this.size = size; _this.noMipmap = noMipmap; _this.generateHarmonics = generateHarmonics; _this.useInGammaSpace = useInGammaSpace; _this.usePMREMGenerator = usePMREMGenerator; return _this; } /** * Execute the current task * @param scene defines the scene where you want your assets to be loaded * @param onSuccess is a callback called when the task is successfully executed * @param onError is a callback called if an error occurs */ HDRCubeTextureAssetTask.prototype.run = function (scene, onSuccess, onError) { var onload = function () { onSuccess(); }; var onerror = function (message, exception) { onError(message, exception); }; this.texture = new BABYLON.HDRCubeTexture(this.url, scene, this.size, this.noMipmap, this.generateHarmonics, this.useInGammaSpace, this.usePMREMGenerator, onload, onerror); }; return HDRCubeTextureAssetTask; }(AbstractAssetTask)); BABYLON.HDRCubeTextureAssetTask = HDRCubeTextureAssetTask; /** * This class can be used to easily import assets into a scene * @see http://doc.babylonjs.com/how_to/how_to_use_assetsmanager */ var AssetsManager = /** @class */ (function () { /** * Creates a new AssetsManager * @param scene defines the scene to work on */ function AssetsManager(scene) { this._isLoading = false; this._tasks = new Array(); this._waitingTasksCount = 0; this._totalTasksCount = 0; /** * Observable called when all tasks are processed */ this.onTaskSuccessObservable = new BABYLON.Observable(); /** * Observable called when a task had an error */ this.onTaskErrorObservable = new BABYLON.Observable(); /** * Observable called when a task is successful */ this.onTasksDoneObservable = new BABYLON.Observable(); /** * Observable called when a task is done (whatever the result is) */ this.onProgressObservable = new BABYLON.Observable(); /** * Gets or sets a boolean defining if the {BABYLON.AssetsManager} should use the default loading screen * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen */ this.useDefaultLoadingScreen = true; this._scene = scene; } /** * Add a {BABYLON.MeshAssetTask} to the list of active tasks * @param taskName defines the name of the new task * @param meshesNames defines the name of meshes to load * @param rootUrl defines the root url to use to locate files * @param sceneFilename defines the filename of the scene file * @returns a new {BABYLON.MeshAssetTask} object */ AssetsManager.prototype.addMeshTask = function (taskName, meshesNames, rootUrl, sceneFilename) { var task = new MeshAssetTask(taskName, meshesNames, rootUrl, sceneFilename); this._tasks.push(task); return task; }; /** * Add a {BABYLON.TextFileAssetTask} to the list of active tasks * @param taskName defines the name of the new task * @param url defines the url of the file to load * @returns a new {BABYLON.TextFileAssetTask} object */ AssetsManager.prototype.addTextFileTask = function (taskName, url) { var task = new TextFileAssetTask(taskName, url); this._tasks.push(task); return task; }; /** * Add a {BABYLON.BinaryFileAssetTask} to the list of active tasks * @param taskName defines the name of the new task * @param url defines the url of the file to load * @returns a new {BABYLON.BinaryFileAssetTask} object */ AssetsManager.prototype.addBinaryFileTask = function (taskName, url) { var task = new BinaryFileAssetTask(taskName, url); this._tasks.push(task); return task; }; /** * Add a {BABYLON.ImageAssetTask} to the list of active tasks * @param taskName defines the name of the new task * @param url defines the url of the file to load * @returns a new {BABYLON.ImageAssetTask} object */ AssetsManager.prototype.addImageTask = function (taskName, url) { var task = new ImageAssetTask(taskName, url); this._tasks.push(task); return task; }; /** * Add a {BABYLON.TextureAssetTask} to the list of active tasks * @param taskName defines the name of the new task * @param url defines the url of the file to load * @param noMipmap defines if the texture must not receive mipmaps (false by default) * @param invertY defines if you want to invert Y axis of the loaded texture (false by default) * @param samplingMode defines the sampling mode to use (BABYLON.Texture.TRILINEAR_SAMPLINGMODE by default) * @returns a new {BABYLON.TextureAssetTask} object */ AssetsManager.prototype.addTextureTask = function (taskName, url, noMipmap, invertY, samplingMode) { if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; } var task = new TextureAssetTask(taskName, url, noMipmap, invertY, samplingMode); this._tasks.push(task); return task; }; /** * Add a {BABYLON.CubeTextureAssetTask} to the list of active tasks * @param taskName defines the name of the new task * @param url defines the url of the file to load * @param extensions defines the extension to use to load the cube map (can be null) * @param noMipmap defines if the texture must not receive mipmaps (false by default) * @param files defines the list of files to load (can be null) * @returns a new {BABYLON.CubeTextureAssetTask} object */ AssetsManager.prototype.addCubeTextureTask = function (taskName, url, extensions, noMipmap, files) { var task = new CubeTextureAssetTask(taskName, url, extensions, noMipmap, files); this._tasks.push(task); return task; }; /** * * Add a {BABYLON.HDRCubeTextureAssetTask} to the list of active tasks * @param taskName defines the name of the new task * @param url defines the url of the file to load * @param size defines the size you want for the cubemap (can be null) * @param noMipmap defines if the texture must not receive mipmaps (false by default) * @param generateHarmonics defines if you want to automatically generate (true by default) * @param useInGammaSpace defines if the texture must be considered in gamma space (false by default) * @param usePMREMGenerator is a reserved parameter and must be set to false or ignored * @returns a new {BABYLON.HDRCubeTextureAssetTask} object */ AssetsManager.prototype.addHDRCubeTextureTask = function (taskName, url, size, noMipmap, generateHarmonics, useInGammaSpace, usePMREMGenerator) { if (noMipmap === void 0) { noMipmap = false; } if (generateHarmonics === void 0) { generateHarmonics = true; } if (useInGammaSpace === void 0) { useInGammaSpace = false; } if (usePMREMGenerator === void 0) { usePMREMGenerator = false; } var task = new HDRCubeTextureAssetTask(taskName, url, size, noMipmap, generateHarmonics, useInGammaSpace, usePMREMGenerator); this._tasks.push(task); return task; }; AssetsManager.prototype._decreaseWaitingTasksCount = function (task) { var _this = this; this._waitingTasksCount--; try { if (task.taskState === AssetTaskState.DONE) { // Let's remove successfull tasks BABYLON.Tools.SetImmediate(function () { var index = _this._tasks.indexOf(task); if (index > -1) { _this._tasks.splice(index, 1); } }); } if (this.onProgress) { this.onProgress(this._waitingTasksCount, this._totalTasksCount, task); } this.onProgressObservable.notifyObservers(new AssetsProgressEvent(this._waitingTasksCount, this._totalTasksCount, task)); } catch (e) { BABYLON.Tools.Error("Error running progress callbacks."); console.log(e); } if (this._waitingTasksCount === 0) { try { if (this.onFinish) { this.onFinish(this._tasks); } this.onTasksDoneObservable.notifyObservers(this._tasks); } catch (e) { BABYLON.Tools.Error("Error running tasks-done callbacks."); console.log(e); } this._isLoading = false; this._scene.getEngine().hideLoadingUI(); } }; AssetsManager.prototype._runTask = function (task) { var _this = this; var done = function () { try { if (_this.onTaskSuccess) { _this.onTaskSuccess(task); } _this.onTaskSuccessObservable.notifyObservers(task); _this._decreaseWaitingTasksCount(task); } catch (e) { error("Error executing task success callbacks", e); } }; var error = function (message, exception) { task._setErrorObject(message, exception); if (_this.onTaskError) { _this.onTaskError(task); } _this.onTaskErrorObservable.notifyObservers(task); _this._decreaseWaitingTasksCount(task); }; task.run(this._scene, done, error); }; /** * Reset the {BABYLON.AssetsManager} and remove all tasks * @return the current instance of the {BABYLON.AssetsManager} */ AssetsManager.prototype.reset = function () { this._isLoading = false; this._tasks = new Array(); return this; }; /** * Start the loading process * @return the current instance of the {BABYLON.AssetsManager} */ AssetsManager.prototype.load = function () { if (this._isLoading) { return this; } this._isLoading = true; this._waitingTasksCount = this._tasks.length; this._totalTasksCount = this._tasks.length; if (this._waitingTasksCount === 0) { this._isLoading = false; if (this.onFinish) { this.onFinish(this._tasks); } this.onTasksDoneObservable.notifyObservers(this._tasks); return this; } if (this.useDefaultLoadingScreen) { this._scene.getEngine().displayLoadingUI(); } for (var index = 0; index < this._tasks.length; index++) { var task = this._tasks[index]; this._runTask(task); } return this; }; return AssetsManager; }()); BABYLON.AssetsManager = AssetsManager; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.assetsManager.js.map var BABYLON; (function (BABYLON) { var serializedGeometries = []; var serializeGeometry = function (geometry, serializationGeometries) { if (serializedGeometries[geometry.id]) { return; } if (geometry.doNotSerialize) { return; } if (geometry instanceof BABYLON.BoxGeometry) { serializationGeometries.boxes.push(geometry.serialize()); } else if (geometry instanceof BABYLON.SphereGeometry) { serializationGeometries.spheres.push(geometry.serialize()); } else if (geometry instanceof BABYLON.CylinderGeometry) { serializationGeometries.cylinders.push(geometry.serialize()); } else if (geometry instanceof BABYLON.TorusGeometry) { serializationGeometries.toruses.push(geometry.serialize()); } else if (geometry instanceof BABYLON.GroundGeometry) { serializationGeometries.grounds.push(geometry.serialize()); } else if (geometry instanceof BABYLON.Plane) { serializationGeometries.planes.push(geometry.serialize()); } else if (geometry instanceof BABYLON.TorusKnotGeometry) { serializationGeometries.torusKnots.push(geometry.serialize()); } else if (geometry instanceof BABYLON._PrimitiveGeometry) { throw new Error("Unknown primitive type"); } else { serializationGeometries.vertexData.push(geometry.serializeVerticeData()); } serializedGeometries[geometry.id] = true; }; var serializeMesh = function (mesh, serializationScene) { var serializationObject = {}; // Geometry var geometry = mesh._geometry; if (geometry) { if (!mesh.getScene().getGeometryByID(geometry.id)) { // Geometry was in the memory but not added to the scene, nevertheless it's better to serialize to be able to reload the mesh with its geometry serializeGeometry(geometry, serializationScene.geometries); } } // Custom if (mesh.serialize) { mesh.serialize(serializationObject); } return serializationObject; }; var finalizeSingleMesh = function (mesh, serializationObject) { //only works if the mesh is already loaded if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE) { //serialize material if (mesh.material) { if (mesh.material instanceof BABYLON.StandardMaterial) { serializationObject.materials = serializationObject.materials || []; if (!serializationObject.materials.some(function (mat) { return (mat.id === mesh.material.id); })) { serializationObject.materials.push(mesh.material.serialize()); } } else if (mesh.material instanceof BABYLON.MultiMaterial) { serializationObject.multiMaterials = serializationObject.multiMaterials || []; if (!serializationObject.multiMaterials.some(function (mat) { return (mat.id === mesh.material.id); })) { serializationObject.multiMaterials.push(mesh.material.serialize()); } } } //serialize geometry var geometry = mesh._geometry; if (geometry) { if (!serializationObject.geometries) { serializationObject.geometries = {}; serializationObject.geometries.boxes = []; serializationObject.geometries.spheres = []; serializationObject.geometries.cylinders = []; serializationObject.geometries.toruses = []; serializationObject.geometries.grounds = []; serializationObject.geometries.planes = []; serializationObject.geometries.torusKnots = []; serializationObject.geometries.vertexData = []; } serializeGeometry(geometry, serializationObject.geometries); } // Skeletons if (mesh.skeleton) { serializationObject.skeletons = serializationObject.skeletons || []; serializationObject.skeletons.push(mesh.skeleton.serialize()); } //serialize the actual mesh serializationObject.meshes = serializationObject.meshes || []; serializationObject.meshes.push(serializeMesh(mesh, serializationObject)); } }; var SceneSerializer = /** @class */ (function () { function SceneSerializer() { } SceneSerializer.ClearCache = function () { serializedGeometries = []; }; SceneSerializer.Serialize = function (scene) { var serializationObject = {}; SceneSerializer.ClearCache(); // Scene serializationObject.useDelayedTextureLoading = scene.useDelayedTextureLoading; serializationObject.autoClear = scene.autoClear; serializationObject.clearColor = scene.clearColor.asArray(); serializationObject.ambientColor = scene.ambientColor.asArray(); serializationObject.gravity = scene.gravity.asArray(); serializationObject.collisionsEnabled = scene.collisionsEnabled; serializationObject.workerCollisions = scene.workerCollisions; // Fog if (scene.fogMode && scene.fogMode !== 0) { serializationObject.fogMode = scene.fogMode; serializationObject.fogColor = scene.fogColor.asArray(); serializationObject.fogStart = scene.fogStart; serializationObject.fogEnd = scene.fogEnd; serializationObject.fogDensity = scene.fogDensity; } //Physics if (scene.isPhysicsEnabled()) { var physicEngine = scene.getPhysicsEngine(); if (physicEngine) { serializationObject.physicsEnabled = true; serializationObject.physicsGravity = physicEngine.gravity.asArray(); serializationObject.physicsEngine = physicEngine.getPhysicsPluginName(); } } // Metadata if (scene.metadata) { serializationObject.metadata = scene.metadata; } // Morph targets serializationObject.morphTargetManagers = []; for (var _i = 0, _a = scene.meshes; _i < _a.length; _i++) { var abstractMesh = _a[_i]; var manager = abstractMesh.morphTargetManager; if (manager) { serializationObject.morphTargetManagers.push(manager.serialize()); } } // Lights serializationObject.lights = []; var index; var light; for (index = 0; index < scene.lights.length; index++) { light = scene.lights[index]; if (!light.doNotSerialize) { serializationObject.lights.push(light.serialize()); } } // Cameras serializationObject.cameras = []; for (index = 0; index < scene.cameras.length; index++) { var camera = scene.cameras[index]; if (!camera.doNotSerialize) { serializationObject.cameras.push(camera.serialize()); } } if (scene.activeCamera) { serializationObject.activeCameraID = scene.activeCamera.id; } // Animations BABYLON.Animation.AppendSerializedAnimations(scene, serializationObject); // Materials serializationObject.materials = []; serializationObject.multiMaterials = []; var material; for (index = 0; index < scene.materials.length; index++) { material = scene.materials[index]; if (!material.doNotSerialize) { serializationObject.materials.push(material.serialize()); } } // MultiMaterials serializationObject.multiMaterials = []; for (index = 0; index < scene.multiMaterials.length; index++) { var multiMaterial = scene.multiMaterials[index]; serializationObject.multiMaterials.push(multiMaterial.serialize()); } // Environment texture if (scene.environmentTexture) { serializationObject.environmentTexture = scene.environmentTexture.name; } // Skeletons serializationObject.skeletons = []; for (index = 0; index < scene.skeletons.length; index++) { var skeleton = scene.skeletons[index]; if (!skeleton.doNotSerialize) { serializationObject.skeletons.push(skeleton.serialize()); } } // Transform nodes serializationObject.transformNodes = []; for (index = 0; index < scene.transformNodes.length; index++) { serializationObject.transformNodes.push(scene.transformNodes[index].serialize()); } // Geometries serializationObject.geometries = {}; serializationObject.geometries.boxes = []; serializationObject.geometries.spheres = []; serializationObject.geometries.cylinders = []; serializationObject.geometries.toruses = []; serializationObject.geometries.grounds = []; serializationObject.geometries.planes = []; serializationObject.geometries.torusKnots = []; serializationObject.geometries.vertexData = []; serializedGeometries = []; var geometries = scene.getGeometries(); for (index = 0; index < geometries.length; index++) { var geometry = geometries[index]; if (geometry.isReady()) { serializeGeometry(geometry, serializationObject.geometries); } } // Meshes serializationObject.meshes = []; for (index = 0; index < scene.meshes.length; index++) { var abstractMesh = scene.meshes[index]; if (abstractMesh instanceof BABYLON.Mesh) { var mesh = abstractMesh; if (!mesh.doNotSerialize) { if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE) { serializationObject.meshes.push(serializeMesh(mesh, serializationObject)); } } } } // Particles Systems serializationObject.particleSystems = []; for (index = 0; index < scene.particleSystems.length; index++) { serializationObject.particleSystems.push(scene.particleSystems[index].serialize()); } // Lens flares serializationObject.lensFlareSystems = []; for (index = 0; index < scene.lensFlareSystems.length; index++) { serializationObject.lensFlareSystems.push(scene.lensFlareSystems[index].serialize()); } // Shadows serializationObject.shadowGenerators = []; for (index = 0; index < scene.lights.length; index++) { light = scene.lights[index]; var shadowGenerator = light.getShadowGenerator(); if (shadowGenerator) { serializationObject.shadowGenerators.push(shadowGenerator.serialize()); } } // Action Manager if (scene.actionManager) { serializationObject.actions = scene.actionManager.serialize("scene"); } // Audio serializationObject.sounds = []; for (index = 0; index < scene.soundTracks.length; index++) { var soundtrack = scene.soundTracks[index]; for (var soundId = 0; soundId < soundtrack.soundCollection.length; soundId++) { serializationObject.sounds.push(soundtrack.soundCollection[soundId].serialize()); } } // Effect layers serializationObject.effectLayers = []; for (index = 0; index < scene.effectLayers.length; index++) { var layer = scene.effectLayers[index]; if (layer.serialize) { serializationObject.effectLayers.push(layer.serialize()); } } return serializationObject; }; SceneSerializer.SerializeMesh = function (toSerialize /* Mesh || Mesh[] */, withParents, withChildren) { if (withParents === void 0) { withParents = false; } if (withChildren === void 0) { withChildren = false; } var serializationObject = {}; SceneSerializer.ClearCache(); toSerialize = (toSerialize instanceof Array) ? toSerialize : [toSerialize]; if (withParents || withChildren) { //deliberate for loop! not for each, appended should be processed as well. for (var i = 0; i < toSerialize.length; ++i) { if (withChildren) { toSerialize[i].getDescendants().forEach(function (node) { if (node instanceof BABYLON.Mesh && (toSerialize.indexOf(node) < 0)) { toSerialize.push(node); } }); } //make sure the array doesn't contain the object already if (withParents && toSerialize[i].parent && (toSerialize.indexOf(toSerialize[i].parent) < 0)) { toSerialize.push(toSerialize[i].parent); } } } toSerialize.forEach(function (mesh) { finalizeSingleMesh(mesh, serializationObject); }); return serializationObject; }; return SceneSerializer; }()); BABYLON.SceneSerializer = SceneSerializer; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.sceneSerializer.js.map var BABYLON; (function (BABYLON) { var ReflectionProbe = /** @class */ (function () { function ReflectionProbe(name, size, scene, generateMipMaps) { if (generateMipMaps === void 0) { generateMipMaps = true; } var _this = this; this.name = name; this._viewMatrix = BABYLON.Matrix.Identity(); this._target = BABYLON.Vector3.Zero(); this._add = BABYLON.Vector3.Zero(); this._invertYAxis = false; this.position = BABYLON.Vector3.Zero(); this._scene = scene; this._scene.reflectionProbes.push(this); this._renderTargetTexture = new BABYLON.RenderTargetTexture(name, size, scene, generateMipMaps, true, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, true); this._renderTargetTexture.onBeforeRenderObservable.add(function (faceIndex) { switch (faceIndex) { case 0: _this._add.copyFromFloats(1, 0, 0); break; case 1: _this._add.copyFromFloats(-1, 0, 0); break; case 2: _this._add.copyFromFloats(0, _this._invertYAxis ? 1 : -1, 0); break; case 3: _this._add.copyFromFloats(0, _this._invertYAxis ? -1 : 1, 0); break; case 4: _this._add.copyFromFloats(0, 0, 1); break; case 5: _this._add.copyFromFloats(0, 0, -1); break; } if (_this._attachedMesh) { _this.position.copyFrom(_this._attachedMesh.getAbsolutePosition()); } _this.position.addToRef(_this._add, _this._target); BABYLON.Matrix.LookAtLHToRef(_this.position, _this._target, BABYLON.Vector3.Up(), _this._viewMatrix); scene.setTransformMatrix(_this._viewMatrix, _this._projectionMatrix); scene._forcedViewPosition = _this.position; }); this._renderTargetTexture.onAfterUnbindObservable.add(function () { scene._forcedViewPosition = null; scene.updateTransformMatrix(true); }); if (scene.activeCamera) { this._projectionMatrix = BABYLON.Matrix.PerspectiveFovLH(Math.PI / 2, 1, scene.activeCamera.minZ, scene.activeCamera.maxZ); } } Object.defineProperty(ReflectionProbe.prototype, "samples", { get: function () { return this._renderTargetTexture.samples; }, set: function (value) { this._renderTargetTexture.samples = value; }, enumerable: true, configurable: true }); Object.defineProperty(ReflectionProbe.prototype, "refreshRate", { get: function () { return this._renderTargetTexture.refreshRate; }, set: function (value) { this._renderTargetTexture.refreshRate = value; }, enumerable: true, configurable: true }); ReflectionProbe.prototype.getScene = function () { return this._scene; }; Object.defineProperty(ReflectionProbe.prototype, "cubeTexture", { get: function () { return this._renderTargetTexture; }, enumerable: true, configurable: true }); Object.defineProperty(ReflectionProbe.prototype, "renderList", { get: function () { return this._renderTargetTexture.renderList; }, enumerable: true, configurable: true }); ReflectionProbe.prototype.attachToMesh = function (mesh) { this._attachedMesh = mesh; }; /** * 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. */ ReflectionProbe.prototype.setRenderingAutoClearDepthStencil = function (renderingGroupId, autoClearDepthStencil) { this._renderTargetTexture.setRenderingAutoClearDepthStencil(renderingGroupId, autoClearDepthStencil); }; ReflectionProbe.prototype.dispose = function () { var index = this._scene.reflectionProbes.indexOf(this); if (index !== -1) { // Remove from the scene if found this._scene.reflectionProbes.splice(index, 1); } if (this._renderTargetTexture) { this._renderTargetTexture.dispose(); this._renderTargetTexture = null; } }; return ReflectionProbe; }()); BABYLON.ReflectionProbe = ReflectionProbe; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.reflectionProbe.js.map var BABYLON; (function (BABYLON) { var Layer = /** @class */ (function () { function Layer(name, imgUrl, scene, isBackground, color) { this.name = name; this.scale = new BABYLON.Vector2(1, 1); this.offset = new BABYLON.Vector2(0, 0); this.alphaBlendingMode = BABYLON.Engine.ALPHA_COMBINE; this.layerMask = 0x0FFFFFFF; this._vertexBuffers = {}; // Events /** * An event triggered when the layer is disposed. */ this.onDisposeObservable = new BABYLON.Observable(); /** * An event triggered before rendering the scene */ this.onBeforeRenderObservable = new BABYLON.Observable(); /** * An event triggered after rendering the scene */ this.onAfterRenderObservable = new BABYLON.Observable(); this.texture = imgUrl ? new BABYLON.Texture(imgUrl, scene, true) : null; this.isBackground = isBackground === undefined ? true : isBackground; this.color = color === undefined ? new BABYLON.Color4(1, 1, 1, 1) : color; this._scene = (scene || BABYLON.Engine.LastCreatedScene); this._scene.layers.push(this); var engine = this._scene.getEngine(); // VBO var vertices = []; vertices.push(1, 1); vertices.push(-1, 1); vertices.push(-1, -1); vertices.push(1, -1); var vertexBuffer = new BABYLON.VertexBuffer(engine, vertices, BABYLON.VertexBuffer.PositionKind, false, false, 2); this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = vertexBuffer; this._createIndexBuffer(); // Effects this._effect = engine.createEffect("layer", [BABYLON.VertexBuffer.PositionKind], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], ""); this._alphaTestEffect = engine.createEffect("layer", [BABYLON.VertexBuffer.PositionKind], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "#define ALPHATEST"); } Object.defineProperty(Layer.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(Layer.prototype, "onBeforeRender", { set: function (callback) { if (this._onBeforeRenderObserver) { this.onBeforeRenderObservable.remove(this._onBeforeRenderObserver); } this._onBeforeRenderObserver = this.onBeforeRenderObservable.add(callback); }, enumerable: true, configurable: true }); Object.defineProperty(Layer.prototype, "onAfterRender", { set: function (callback) { if (this._onAfterRenderObserver) { this.onAfterRenderObservable.remove(this._onAfterRenderObserver); } this._onAfterRenderObserver = this.onAfterRenderObservable.add(callback); }, enumerable: true, configurable: true }); Layer.prototype._createIndexBuffer = function () { var engine = this._scene.getEngine(); // Indices var indices = []; indices.push(0); indices.push(1); indices.push(2); indices.push(0); indices.push(2); indices.push(3); this._indexBuffer = engine.createIndexBuffer(indices); }; Layer.prototype._rebuild = function () { var vb = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind]; if (vb) { vb._rebuild(); } this._createIndexBuffer(); }; Layer.prototype.render = function () { var currentEffect = this.alphaTest ? this._alphaTestEffect : this._effect; // Check if (!currentEffect.isReady() || !this.texture || !this.texture.isReady()) return; var engine = this._scene.getEngine(); this.onBeforeRenderObservable.notifyObservers(this); // Render engine.enableEffect(currentEffect); engine.setState(false); // Texture currentEffect.setTexture("textureSampler", this.texture); currentEffect.setMatrix("textureMatrix", this.texture.getTextureMatrix()); // Color currentEffect.setFloat4("color", this.color.r, this.color.g, this.color.b, this.color.a); // Scale / offset currentEffect.setVector2("offset", this.offset); currentEffect.setVector2("scale", this.scale); // VBOs engine.bindBuffers(this._vertexBuffers, this._indexBuffer, currentEffect); // Draw order if (!this.alphaTest) { engine.setAlphaMode(this.alphaBlendingMode); engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 6); engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE); } else { engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 6); } this.onAfterRenderObservable.notifyObservers(this); }; Layer.prototype.dispose = function () { var vertexBuffer = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind]; if (vertexBuffer) { vertexBuffer.dispose(); this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = null; } if (this._indexBuffer) { this._scene.getEngine()._releaseBuffer(this._indexBuffer); this._indexBuffer = null; } if (this.texture) { this.texture.dispose(); this.texture = null; } // Remove from scene var index = this._scene.layers.indexOf(this); this._scene.layers.splice(index, 1); // Callback this.onDisposeObservable.notifyObservers(this); this.onDisposeObservable.clear(); this.onAfterRenderObservable.clear(); this.onBeforeRenderObservable.clear(); }; return Layer; }()); BABYLON.Layer = Layer; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.layer.js.map var BABYLON; (function (BABYLON) { var TextureTools = /** @class */ (function () { function TextureTools() { } /** * Uses the GPU to create a copy texture rescaled at a given size * @param texture Texture to copy from * @param width Desired width * @param height Desired height * @return Generated texture */ TextureTools.CreateResizedCopy = function (texture, width, height, useBilinearMode) { if (useBilinearMode === void 0) { useBilinearMode = true; } var scene = texture.getScene(); var engine = scene.getEngine(); var rtt = new BABYLON.RenderTargetTexture('resized' + texture.name, { width: width, height: height }, scene, !texture.noMipmap, true, texture._texture.type, false, texture._samplingMode, false); rtt.wrapU = texture.wrapU; rtt.wrapV = texture.wrapV; rtt.uOffset = texture.uOffset; rtt.vOffset = texture.vOffset; rtt.uScale = texture.uScale; rtt.vScale = texture.vScale; rtt.uAng = texture.uAng; rtt.vAng = texture.vAng; rtt.wAng = texture.wAng; rtt.coordinatesIndex = texture.coordinatesIndex; rtt.level = texture.level; rtt.anisotropicFilteringLevel = texture.anisotropicFilteringLevel; rtt._texture.isReady = false; texture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE; texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE; var passPostProcess = new BABYLON.PassPostProcess("pass", 1, null, useBilinearMode ? BABYLON.Texture.BILINEAR_SAMPLINGMODE : BABYLON.Texture.NEAREST_SAMPLINGMODE, engine, false, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT); passPostProcess.getEffect().executeWhenCompiled(function () { passPostProcess.onApply = function (effect) { effect.setTexture("textureSampler", texture); }; var internalTexture = rtt.getInternalTexture(); if (internalTexture) { scene.postProcessManager.directRender([passPostProcess], internalTexture); engine.unBindFramebuffer(internalTexture); rtt.disposeFramebufferObjects(); passPostProcess.dispose(); internalTexture.isReady = true; } }); return rtt; }; TextureTools.GetEnvironmentBRDFTexture = function (scene) { if (!scene._environmentBRDFTexture) { var texture = BABYLON.Texture.CreateFromBase64String(this._environmentBRDFBase64Texture, "EnvironmentBRDFTexture", scene, true, false, BABYLON.Texture.BILINEAR_SAMPLINGMODE); texture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE; texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE; scene._environmentBRDFTexture = texture; } return scene._environmentBRDFTexture; }; TextureTools._environmentBRDFBase64Texture = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAgAElEQVR4Xu19Z7PtTHbW1g3jMMbGmGDAZAMm5xxMLDAU0WSKWOQcCoqccw6eGdtgk4yNbZxnvvAL+Af8Af6AsQl+06ako9X36dXPSi3pnPu+cz/cOntL3S1pq5+w1mrpLs/eud9fvn27rf9evPPwFz+v22S7fGZ/n7/70G79J5/Xv/qzbLP+Pnvvoc/6Tz7jX/15/c62LfeH7fofbpfP3l/ct36Wf+u4+D37+XYb++G26LPsr/zFttnPuh37bm1bt0f7MvtlnOx4uv0H4fty8UUsz77rfn/57u32cgXvDv72eQf0tl0+G38b0Nf9K4Dl704MEfA16KsE8Gw9JgD+DQE8EA0DT2b7GwK4GHnF4a8iguXZt9/vL5/dbisJbEq/uwD5vIK/fbbAv4N9U/8nJIDNCazKvBLBGwdwu62OhajxmQSAx6gqNp5HCg9wPan2nwSNjhLD8ux/3u8vP3y7vbwDAYjtR8AzFyDqLu1Q+YEINnew23rPCYiKb+q/K7o4AVT4tg0t/h4ydJZfkQASQ/d5b9fZ/Z1ENmuPn/cwYCYEELBguKC3nRkCnE0AFOwOKCOAR/sH/L4hgFMpbSWP5dn/uN9ffs7t9mJ5cAHoBLTyszBAFJ/F/xIKdASw5wgaEWDMLySxAk4svf6L+4QAGPiJCziNAPb4f3UZ2dh/m+z7BK4SAPYrxf5FB6ABPgCUAfANAZwKyscc7IEA/vv9/uLzbreXzx9cQCMACAl00m8jAlF7ov6SCMQ8gJsMFFBnCECSg5H6TxJAU3vPAbwhgFfz9AABeOEDBcIbB3AqPzwQwH+731/8sNvt5Ydut5e3B2C/fG9P+jESgGz/RgxG9r9VAwTUUh0goQDafUz+DYnAnSha5l99Z1l/yQVswAZSGIAugNd/9xBgCw9E8aECkHUB22QPHIAVDlQdQAMWAibhBgZAasAVHUAI8Cqg96Tm0bj3VBS9jwd7IIBvuN9ffMHt9vLTbreXy+32QlwAhgMIeuNzKwOqCoB2Aa00KHE+EsIeDuj4H2N+Hf/TfAC6A4nhgQCQDDwiaKDXiq9KgBEJNPArAtCk0AEd2mpAizW3/lYIoANpBPg3BPA+hjs/9eXZV+0E8Bm32wsJA9aEoBCAuAABPiEAC/yDC4gSgRgKRHkAlgsI6v7iEFqJEMgBwb4BGkEfEEDnDlReoAP/SQRgOYIB+IYDMEE/SQBbXoLNr0jhq4qOZc0PHBSf5oKW519xvz//kbfby8+83V68ABfwniIBgwgQ/HoRUMv8w5qAoQqgk4DWQiCw+63eD8k/XAPQgK5s/5a5xzAAqgR6wY9k+ZEMtCOoJABb230hEHMFWQdgAl0Ap/+uc6tKBrrP/n0AuwfiNwTwNKguHHV5/qX3+/M1B/Ddb7cXax7g2e324vaQB3hhkMAW92tHoFb96cVAbimwkgQ0Vv7R+D8iACfuxzKfLvnNlAAjAsBwwP2MwLQAD9sbYJME0AFcg5uBPSAA0x0AobhtcDKDA0j3KYDhk7Hp8uKj9/vzH3C7vfget9uLT9nDgDUZuOYCLBJA8MNKPyGGIftPrL+4gy3eh5p/lwRUYYAs9Fn7tM/E9lvJwCH2DxJ/mPTr4nyyLiDtBgTAGCrgNuPzNuETgN+suEEAFhng9lkCoICMLH7V0isCeEMCxylrefkl9/uzz90J4NNUGLDmAnYXINUBrf5dCCAuQCcCvYVAYPk3G++VAveVfkIAFRLolgbr2F9ifP33pAqAV/fHRF4HcAS7AKlAAEIYFNwITOszs/wMsB6II4BXFZ0QwBsSOEYCDwTw2TsBfPrt9uLlqzCgcwFABI0EVCiANl8Uvq0JWNsi2JPZ/0YKsOiHxftsW4v51ZqAaBWgZf91PsBL/jFHwEqBR1cCiuJ3gAfCmCEA3cf8rmz8AMZHIoA3JDBPAsuHVgL4jNvt+UoCH34ggK0asIYBGArsAB7AD+reQgCl+GwZ8LaNlP3MEEDaSg4ACMGr/+ulwV4JsAEfLH42/vdKgWElAJ4QpBl+LAlKErHwt+oGMgTA2ngE4IUIOH3dGr/hAKT/m/UBdSJYPuVL7vflU26352sScCWAD+0EsCcDVxewKjfmAzAsENVn4EfgdySgnYB81yEAgL4RA8T8mTUASAAYBgylQAkL8K/+zL6rsl8qF6ArAeS7WRGoAB8Sf7isN/VZqTs6jQ5wXlweWfyqpQ8I4I0TmCCAT/3I/b48u92ef9bt9nwNAdZE4FoOFALYXcAGegkDMByAzzQEgJh+cAIs/legH0IA5QTCPADE+7ISkD0TgA/8sBIgLQfOgF/F9kPcr+J8fIYguyCILQRKgV4DNviOzoKqeJS0u4AA3pBAjQSWT//I/b5OmC0MWB3ASgBrGLA+IryvDNxCgRXo+wKhjgwk8bcTwUACsJ09ANRVAALwCxmEoFcrAUsuAJ4M1E8BDuHABAHomJ8RgACrZfQLyT9dBWi2OOEG9NJd/TDQ8HAQuBE97ZhjGKy6o+imnU+4gDckkCeB5cMfud/v6zr9Dz84gOdCAM/3JwQhF9CAD25gBWWz/8wNgMpj3K9Lfy0foMMBVffXyT4r+cceC9bvCcDFP0311QrATPkvWgosYQFLAuoqQEcQuw3v2si25F+M1RkZXLUU+CgBmCBOEsCbvECOBJbP+Oj9fv+u2+3Zp91uz9cy4Kfebs/3ROD6iPD2b10YJCXB+0PyrgsHdtBuRACfBeTN+uM+suJPSEDbfh3/oxPoHgwiC3/06j8Eutj69sAQqj++I0CUfvIpwCEvYCT90O4Pn1XsT5Ve1/+dcp9FBh3woqXBSEJkvjHHEOUPqJPAjUUCeOMGfCJYPvOj9/t7//d2e7YmAlcS2B3A8xcPYcBm/7ULEDIQew+5gS0EIEA31R8Uf6gAoBsgKwBd9ddvBBJAs6XARgLQXQ2o7T8+IETe+9eRACg7rhCMVgCiE8D4O9wOCb2ubOht1/vYd2ubzLlgKbBHEDSnAMfL6durVm8qBPwXWz7rY/f7/X/fbsvL2+3Zqv4QAjzfw4COAMAJbEC3wC8koBJ9lAhgxZ+4hi3Oh/f8dU8EqtV/JhHgWn9cC4CJQZXZp6GAk/1nawMkrrcqAiwPIIA2FwOB2oaAF5UkcX+GADBs0I5gsNbBQqCorJcFJjqWKvhNMjky0Aek7/LZH7vf3/vO2215vruAD91uz/dSYCOAPQzYkoD7vw34sFIQw4LNymNSUKk8Wv0hCYhkoJ74Q6BboO9eDKoWAHXvBiCvAdPZf4nt3QqA924AbfXV8t8uN4Bt2We029WkoErWpSoCSm11TM8AOYA5uRS4RAITIQDDavaYHxCcm5exfM7H7vd3v2N9McDt9uxDD//WKsAG/ue32/M1DEACuO3g1jkBsf57fqCL/7UbIISAio85AAG0VQEYiIC9DJTYfy/+Dx8HlpeDRK8G90IBHQbgWgD2WT8LoOJ7NyeA5JEkAwwxmuqzur5X6y+sBEwDMggrqoBNH7c68Puk/fI9Vwfwvx4e6H724oEA1iSg5AAaAewlweeyLmAnAHQCTfU1CTAH4GyTMt+QDMRFQFEYQB71lXUAOjHYlvTqh4N2xe5yASoh2PpaJUGDBDrLr9cGIDlY1l+vDlQOAQHckYMiA68KMFsGtOy65RCGsMIDT+QqJoD3yUwCy/f+6P3+7koAt50AXrwigM0FrIuEoBrwHMMAUhmQUKAlAwHo7VmAPURo9h/r//ozLv1V7/5v6wGMV4B3rwYPXEBqIZAQwp4TYDE+LQlqtQfw6my/LgsyZaeLg7wVgmDnWQ5AA5ZWCDRx7ECzyn3udgFptFCIgTlyFRMEUCKgA+O/jl2Xz/3o/f7Otz88QvpszQOsLmAPARoBSDVgud02AthdwPZ5BSxUBVr8L3kAVHrvs076KSLQi3/M9QCJ7H/G/rf4n8X41XIgcwHecuBMDgAe+BHA6uQgqnvbF5DB5hwUQM3vQgIWkKOVftH+gAC6cz0RXZ9MjmD5fh/ZCWCd1CsB7CSwhgArAUgIIC5AQoDOCewJwab+CH79WR4C0mQAZT4hEQS9DgfEztNkoEECDfi6FAhZflb6Q1XXqwHDEECpvZX4a0qP1l7bfAS98cQfzQUo9a4mASMC0CsIm6JGK/2i/QkCuFK9PxmIYPm8nQDu795uy3K7LTvwVyJAB7ARwJoAVLkA7QIkJ9A5AQS95Ad2YmgvAJWwQFcBpB38pUuB9wVKbAWgCXwV86Mz2ICKTwUWFgOxMEBicr0eoBwCGBUADfxsDsAiA+zflNay31ZcfnAdAAXgDGkcdAcfZCJYfuCX3O9vf/vtthHAmgcQF7ATwOoAtn9IACsRSDkQ/wqIIUGoXYEQQ/sL5IDJP539776DwodVAGlr5QBgP8sDdApP3gSUXQa8/rZsRaBeHmy+HwDyCI1MUNlZzX9iJSBO9igJGJYCo4RdIqMfJQ4Ztq8C7FXjHuSnQ92XH/yvdwJ4Z68ErOXAlQRW0O9/JRG42v9GBHsuAImAqv+uzDo30C3yAfVHoHeg9xyAp/7wlp+WFCSWv1sOTBb+0EoAZP5DImBrApAUMFHolQG19c+EAkbpjyUEdQ6gm/QEsCzZFxKDlWNwprJVWfBm/1WAvWrcQ0ie7Lz80H91v7/9v263+9sPI2zrAZAEdvXvXMBKBJIIFDcgyUAEvHICg/o7wA/Bvyt35wCc2F9Cg03RvRyAA34N8hD0xsIfXP7bQgDMFSgyYO8GsF4N/hQ5ALak1yUGRQDZZJ5VWXgKEsie8yQuH63b8vn/8oEA3lsJYJ2EQgD73xX4z9bs/74gaHMBQgA7+DsXAJWBBniHCLTtNx2AUnkG/LYNiUCpvX7wp6sIOHF/lwgkNf8UGagwYMgLMBdgLQCyVgOyciCGCs5nz/Jr8EXOQOcQZEbrfjjTU8qaCBseMyx4vxPB8iP+RU8A24Kg9R8Qgaj/av8lDBgcwApQ+QdVgW0bKr3+jsk//AztzBKgtv4K+Kj08rl7JFgt9BnCAIsQcD2AsQAolQj0CAGAqhOFCK5u3cA+84dyIJLCPm6buAgoBa5qDoDF6wzUkZ13iSDKKwTamSKZSf29cuzJUwq7LV/wz18RwH2Nl9dKABLArv6bC5B/+9OBGxmsIIR1AQ3w2gk4RECTfwBulgC0rP96/FYJUOv9SzkAB/xuKTBY/qsTgZ0LILF/s/RW9v81ywEwhbeAwUIH6hRwGp+wEOhqoF49fojqQoPlR/+z+/3t77jd3n3rdru999CzEYAQAYJfXACEAqL8W5lQgA5uoJUK9zxBB3ii9ALiYT2AjvuN72wFILP+XdlP8gLKFeg6f5QM3AC+VlMMZ9ABGuN+VePHWL6tHVD23or3tQPo2iWfBRgShDp0ELcBjmIAbwTWqEzIJvLM6kEDEFcD9erxCzg3my4/9p/e7299x+323lu32+oAtjwAhgE7Cazqv7mAvRLQcgG7A9B5AAwHus87CWBYsIKFfe+eCSBgt2J+7QBQ+VsogOU/9fIPBvLhASEF8AHwlhPQ2wVYFhmo/Wby74QyYLcmQAEbbbue2FcnAb28QTmHQKBwNVCvHv8IESw//h/f7299pyIA7QIE/LsTeIbqL59hPUADvHIBG8jBIWgn0L4rsKMj2Noomz8QgZELsCoAAnh0Caj8lup7ib9tX+ZBoKgUmFkWTGJ8S/UHZa/kAHT+QGaeoeQmMUC/CoAzVYAjYDvSNwPCq8fPnINus/zEfwQE8O7tdt8dwGZjIQQQ9Y9cwAB+RQIC4I4MdvvdLL+O//E7LgLykn6q3Efjf6X8bOUfkoNYcQZ8z/KzBUBYCqT/YQgjBuOBHxPs7JHh7JoAy/IzWz+xEtBKBEYg8fIGw+SeQQQ+CzHZP+oWXWPU/8z9y0/+h/f729/5kAN4791X/6/cpl4SCsDfLRQwHEBLCmJFYH92vssNgBPo7D8qv4CekIHpAjKgx1iffGbKb5UAQwdguIAtz2KsEWj7vIQggNON91lYoIFN2mznYKj9UBmwQgXLLcDstRTdBchEFWAWcLP9MgC9cuzM8aXN8lP//v3+9v/uCUDyAM0FIBFADqAjAsgFiAvYwK3/MfAL8InSd/Yfy37Qpyv3OSTgxf8C5vZXPfF3aB2AA3hJGg5LghMOgCUBo8SgEAyC3Irvh5xAwhW0cT1iQBKYWds/QQLdeVUQcrEjeGoiWH7633sggHfWJOAaAkglYL/wLQyQf3tYsCp9CwmgFIgOgIJ/JwMdBuB3cQTDX4z9wR2whN+WE9idh67761p/F/8bpb8O/OotQCsJDhZfji0qT9p0LsCI83X9H8E9KH8iCSiTrQO29bwAAbvlCipPAw4T/oRKQAVElbaMJ472t7jnqnEjrlt+1t+539/6P4oAxLquawIkF7Bb/40M9hAAHcD2GVzABmBYKSgxfyMGAbROCipl1w6gs/8ZF0Cy/UIOOr7vHAIu9iHP/2v77yX9ROUt29+AHVUCnDJgtvSn8wXsnQGzIUAW3F27qFS4z2CrD07wCogqbR8LtGecUwR4vX/5OX/7FQFsOYC9FCiToBGAEAH83ZwA5AM06BspiPKrNQIt/kcg69iffBegNqVXb/wdQgIMC0DltUuQ+L+Bmz0OrNTdK/91+4JVf15SEPMCYRkwEfc3stBxurMS0AoTMKRocaV8cKw6jpcFsdUn2/8qRT8buGeP55HC8vP+5v3+1v99cADvvfNQBZB4dO24Kv5GAntSUOz/+n1wAis4wAnoMAC/N9svSUKsBABgmwPAbQTwWzsW/2vAI6j14h+1CEjnBYZFQWSxj+sEVFyPjgBBrhf+aOtPY39vRaBVJlQ2vyOGIATQsb6etBguDMSQyAF4IMhUAmZANNNnUNSqBDvtzzif6HSWL/wbuwN4eycA4gDEBQgRYPzfSGC3/BYBdOCHxKBHBAJoAbdWfIz1I9XXsf5g9y0yAJB7iUDPCaC6e2EA2ngMGyIHwAgBldncf4ID0EDXVp1NYmbnrclOtyfDhiPOoCO4CEXB/rOBfOZ4yy/8a7sDAALY1gKAfWMEgOovoNdk0IArKr+7gwH02gWQ2L4t/sEEoLL2IQnoFX96HYC4CIz/jcSgAJSVAtu2RPZ/SPRBHkC7AkYEqceC2fqBfdKaCcHAAeAkpKVBCANcElBVgBQRTC4HngHOTJ+rQo2jhEbP6xf/VU4AmBza7L+EAZgLgGSgxP8dGQDwmQOQbS2xp6oEWAnQn1seIEMCJO4fsv8Q2w/JQU0IJMvPiCCT/NPuQP/noJ0rAFBa23VSr1N/vQhIgxzzB9odMMIAkGvFZPF6JkyIlJeFFl6IcRYYX0ciOOOcll/6l+/3t/7fngPYy4BSCmyT0SGAlgvY4/+BAET10fZjUhAWCg2AV8nBEPQ6D6DJgSUAoQ/G+Dr+T9l/pfg0HxAs/e3WBUhbsihIgHKkHGiGCQHYO/UHomDgdd0BcRkZlYtyAFlgZNtlzqkSJcwc1xr/6FjLL/tLPQG8t+YA3tuXBKPiqISgAB//bjZdkoNE/Rs5EAIYXIAKCwYHYJADlvhalp8RgS4PogNwFN8jgo1A2LoALxRw1gA09TbCAjckQHBZlQEFwEoS0Iv1S3mAYFGPlwOIJn+0v+ocPohEsHzRX9gJYM0BvPvwTyoB2gGsP6iEAowANsBJWAAVgRYeAPCb/WdkAKEAttNJwRbzM+UPQI8K36k9Kf3RagBTe2vhj3o8uAFXLxUGxTdXBrK1AIltTZ2JzUe7Lp/Ralvxvrb5kcWP9nv2fwBzIRF4FRFkx/XcwRljHCGm5Vf++fv9re+63d4xCABVRhOAJoOtRCguQKoCmghwv7L/mBPQwB/KfMQhCEF0ym8RAUkIToUAxrP/gxOwSoDGmn9WCjTzASw3kHQA5poA7Q4g3n+MEMAChiadiopXwHZV26usvB43e/7Lr/pznADakmBdDcB8AFj+5ggcF4AhgAlwwyUM6m+pPgF8U3BS6jOdAAkJ3HUAO5C7ZKBT99/IVDsGhwyY3e8qNfhCERXDa5BrlW/ftaoqe265Ar0U+PIQQCUzqwqYBYfnSK4AcuW8sjmHaMzl1/zZnQDeud3eXRcCrfH/ngNYbyxzAKL8nQNAMiC5gI0gBNz42XIBAnAkBACwqDyWByPlp2BPWP7WD0Crs/5ewq+1JaBnWX8rEajbDiVAlbNpwHRyAJ4D6EqECQcQWfxo/0wI4E3wcPJnUbSLXqH5A26qHaD9kb7ssKaj+nV/ZiSALRG4rwhsJLBfUKt/k3yAJMGwEtCFBGD/PTIY4n6d8ANyaEk/Q/nPUv8h+WeRgXYCVgIwSwbK3osKi4PonEGUC2C2Pngc2LL73Xanlj9bBTg7BIgAFe2vuoxZS14B7wy/DCT8xX/qfn/rrYccwLtrElA7AJkgkrDSJUHJfO/Z/wZ4Kx8g4IXyYKfm0i9QfkoSJK5HghALr51Ce2Jwv0ad9BvAj1WCidKfZf1x3UDnvPQ90HYf7o1WfSQMGbOpU1D3H6oCynpjPE7VfSccpoalMEHNdAxFKkDLgDzTRo5ZaXukz1E34f1Gy2/8kzEB6MUlsjCoCwWMEAAdgOcGTECrnECn+JYTgPyABn0U82vwt7hfJft0rK9DAlHooTSolH94GxBUAnTSL/reAbz6UBADt344SDkIJBIT5E62HgnEAwgFmjq3ChFkAJUFd7Zd9fwsdZ89nnX85Tf/8Z0A1hwAOgDJAxBbuU1usboYCoiCKvWX+L/lAUDlNUG0bD8Bt7dviP9Vf0v9LbV3XQCz/3qbZf2d0h8D+JAPYDb/RAfArL1l92W7Z/OjEICpOZvkw7bES0EisET7M0RxRNkzx78qJGj37rf+MUUA+zoAnQjs1gTAhJNyFy4X7kBtkYHKB0ifDMgrLiADfJMESGa/Cwe0/a+CHsmA5QQ8N6ByAzJZh1IhEobOAegsvwaVDhEKDkCre0cielYbau4SQfIZggyIM0DMtMkc6ywnMHMsduzlt/+R+/2tt2+3d8QBiAtQSUBaEVDxPyYB22cEuiYDQgJtLUFk7539ke1vgAeAR05gC3ekbAclwuaEjEVA3XoAAnLpT6sBCuStrUrIpqsBHhkwcBOVTecFJAteCAFSyk/GzapwBOJofwV0mbEQkNX2p/X9HX9IEcB7eyLw3q8IlPgSbV/LBThEIMreQJkhAeYOIsDrsELV8VmIgHX9ITGo1L+BnxGB5wQY6IvKLzZZCKD7nsj8m+sADjoAVHk9ga19tF1CzSk5GO8T9MCUAdpZbSqEUW17lpNYfucfvN/fBgfwLlQBcEnwdkA9cdGiCjCgGrCpZhACDMSA6wL28dewgKl6GzuI963EXwtf1Nr/wQ0YMb+bCJwAPgKc5gPIPeiImeUC4B5J2zbZnGXBQjI4Mdk2HFNPYqv9MNlJCJByAzPPEezIiUAe7a8ANjPWGYpePc52Db/799/vb7/zKgQQAnhvDwH0cwFWLqBluwkRYJ7AqgoMTiHjApTqR9ZfbLxbCbCUX1wOKQGiO8ASn7XdKgMimL2SoG4nkxGVnqk+OoeBDHR4AN87EmCWnlULBGiBuiNJMFC5RJB8HsACRgYwZ7WpEEY2pNEuYOoYv/f37Q7g3dvtnT3+39YC6BBAv3IK1wVA9p8SAYC5gRDBqz53QDasvag/dQboGMCy0zBA7e/CgoTyszX/VeA35QeH1YGc2Hwr2YchGn5mJNGVd8FdoEOIHEBo9VkeQc3cqFJgEkPhxSBHwoIMCVTAlx1vlggq4y+/7/fe72+tDuDdV2XARgD7isDtd95BpZWjKRUov4Acwa6BT5OEsEjICg1aBUAl8DpwA2kgQeCYbHsjL0zygfKbll9XC5xk3zYGgM1yA0IKERGgI2PJQJ20M13CAQfgWv1kEjBj+Yc2zlqAGdWPgBPtrwI2O16FXMrn8Ad+z04AaxVgTwDiasAtBNgnrK4E6HBgSApichCBBHkBCnQNbmb1iTPoSEXlDXCfTv6x0EAA2OUDtCPA70bMT6sAXjVAlf4sIhieC8BYXy0CYk5gIPKCA8CJGzoAI5QYJqoRzx8NAZ6KCLLgzra7igSWP/i79hzA6gCAAMQFrBMNSUCrFypUm+x78k/cQRffY45AqatOGDJy0CDHkh5dDERielFhWvrTIYHO+icy/jK+qe6sCkCAH70erLsXylXMWv5GFowQrLyACISU6HZ0W+RALX0Qz2ug4NgYUWScRNQ+q6IZ8GbaVMCdHS99jX/4dwIBCAmsoNd5AHAB1sRDArByAV1YgLkBnfRDF6AtPbP4LNY32lkOgMX/tPynSKFzC466Y2JP+mT+mk8BOiVAVP2MA9COgH4nQGcgHxyCAe5uMicqARTcJ+QBIlB5+6O+V4E7c9wMCSx/9HfkCEDyAMPDJiQZ2AABqtZUVwG7s+ZWMlCDO/F9iPFZso9l/IkDaMRgxPqe4g8JQa30yg14pdaM7TddgWHxXcUPVgLqvnqyWw6AqrlT0jPV33AekYJb4IlAdfX+6LwR0BVi8Yhg+WO//X5/e68AyLMAawlwCAEwF2BkpTfgqwlu5QU6G45KrdYNsNi9qwAQMgjBnyEDI77XYGcxfjXut1wAhlfSptsGoNHJPab6XkLwTAeAk1MIidp+mJlRJYCqPxCABwizr0aUDl3I/ogEMsDMjJEZp0oYjECWP/HbSA4ACEDWAbA8gJ6MjADWbYP6i5LqvyRROBBABHgjXEAV14k963s7d0koOkm/s+J+FiaERADqbjkAHKNNrsRCoE7lmYsQ0HjlPm+dgMzKRLmQkkgyBJhR/SPWPwPyTJuriWD5U78FHMB7eyJQ5QDaYiBhXL0mgGWumRNQAO/KbieTASMOL8bvVgUSq2/lAvAaOvDiwiEjs6/BThdZ6bUBJNvfuQN0Z+pzVzI09nXqrT3UMRMAACAASURBVJcKg+J6xKAnLao7Tvruc6ZcyBS6EDpUXUIEvgyAz2oTnQuqe+aYzT386d98v69rALZ1AEIAazVgz/4zBzC8aorlAdS2rkIgC4e8v2TxkOsGMLeA45I6vgZ7ygFg4g8JQhOdl+FPZv+ZnRey0CQhE4PtH1TfCBmkXQd+S+1ZXkCTiQZq0gG4sb6qMHSAKFYQHpsIMoDMtKla/syYy5/9Tb0DWGP/7R8QgOUA2NtnzEw3LhRS6hjlA9CK6/gfS4XU5rOk427p9bg02cfATtS9CwGcSsB6/taTf9Zvx0ItvQ2JgH7WgEYyMMA+5AwmHMBMDsAjAhrPTz5M9H4mggy4M65g+XO/YSeAXf1lLYAsBca/24D7MwKdakBIYOUBxKYyJ0BDAeIOTOW2QI75AgVkXNVH7b+VBFTgDisAQda/gd5LrCrlZpa/WXJrEVBk+cGxNWAkqwDMQWiFNq2/zNKgDOi6A2NFICULRAV8rrSN7HgEzmh/NH4G2MZlDi8qXf78Fz8QgNj/thjIcADtvw9HNcgQwGxIwPIGLHTQVj8BfszWmzkAlZsQwFrlPbcCYOUCjBwKKwl6pUBRWyFhukxY7LmO7414X8f61BVY4YLY9iDBhy6BTX6LPJCoPHtcAXelbQRUD+gZEojGZyCvjrv8hV/fOwArBGBLgnFpcGdJYUJ0gNknxLDNCwm8xKEV6xtqPwt4DWpm92kIQICN7bSNF2Xv/pLfUgNd5wxoCEAA34GbqL0VAmhSuMIBuIqv8wGJRUQWmCzAfNIQwV/8tff7O+9BEhBKgEMiUIUAXjLQinMbAAAcCIruFWMVgBPFX28iLhW2Yvzu+JCo06A21wAQm69XRVJwk+RpaiEQCxeQKEDlaWhgtEWQWEqvt7vhwoQDKAFfjR+5hytdgjf20X1HLH/kIpa//GtUCLATgE4CogOQz628IwzslKx0gosuG1bWnuUGotJhyzUYYUIjBSsnoJKVXZnPCAeYo3EBH1UDDIA38CniiBR/CA1I1r5VEQBUg/1XVt8jjG7iWZUD5WEz5UIK8sRagIhYquQQgfqI/a/aeBYKZMOD5a/86r0MCGsApAqQcQDbgTQBMNuqJ70GE/nuOgMSGjDFj7ZZhNABnxBTIxon459Vfa9yYpUEEfRU5RXounEUkJEgGJlEYNb9O2IQ16hsO07y9nk2ETjzJKG4JIKUSlgQKqyDzgzQM22ic/AcxPLXflXSAew30no8eDsJvBGWyhmJsKojQOAOi3R0yRFtPcvuqxo/tf7qeryYv2T/mZqT0IARgfzmG9Eg6erP8Jvr+4Tk4Sk6IwnWfgA/IxsCPhmfKWuk3ugcqENIgLwC+hl1j4Ac7c+CPDNOd4/++q/ccwCRA1iFHkqAtBrA3ICh/J46Yp7AjM+DHIK27t1aA0YIbKGPIisrw59NAOqSH/0NEKyMCBS4qwnAtNpnk4JGnN8pfKYKoIgiA2R2DEYglW1XE8FZQI6AHu1vv8nf+BUPBNDKgFYOgDkAsHdmQhAnkhP74kNDg72OwgMP0CRuN90GW+CTdCwWoVluQKv3EAYQ1cZjuOpv9JXJNyT49KIgliMwlByVu7kJUFwvPBjcQuaxYSuUOBAGZMjGIxEP1BEQn3z/3/oi4gA0CQD4uxAACMBLCKLNjFSPJd3Q7rtJOWu1oZNcHMgmE+8H5T3P3Xj7OlCzCgEeN+sEVDs8Rpu4Ol9ggd1ScuYWkAQIsDv1lrYqB+BZ/2FfsBqQAe3sbZG6Xwn2aGzr3Ja//cuJA8CnAXfr314SajgBkwBwAs6EAwmwWWFChThY0s8iI297B3DDPYRtCLi3Psb2AdRAHrKvqb9BCEyNtaKXS4OkoqAnomXjKUEo9e/GSjqAs0HvAS8C5WzfaNwKES1/95cZDmAlAbIacPudIRcgi4H0oqBuUirgU6WDSVtJsHnJw8gtZNyGWeJLEJNn61vZzYjzo/3dQ0Ea1DgmUXMWAqTAbil9UOaLynttQj+iAzibCCLQRfstUM+ShJiqqP/y937p7gDuex5gBz5bByD23woDMA9ACeCAG8jkCLTis+8ZUhjCAisZOKvwySw/OoWONFWMrmv4ZsWAqX+wrXMGbLkwnMvgIowEIWuHTsV1CTKz978WeViA88IKDzRnA/Ts8TyCcUng7/+SngC2twFZJLBPljIB4IQ1wgA9waPM+rCfJApN9Tae1beOGZ1LO06CEKj7UbF9A7CVB7AShIa9R3Uf1gOwhF9V6S1iEEQFDqFN3my14IJEYNYRTANNERd+PZMMIsXXp7H8g198v68VgHf2uP9dBX5xAtvbgaUUqEqCg/1HKweAlx9vsLeGIlqxchWojCyqY1RCgXK5jxGHofIsD9B+V92nSAgIxCEkgLEGBU8mAaO4PgoVmEJbOQQG1CzIs+08Msg6kAwRzJBOlgiWf/SLRgewksCq8l0YAKBveQAgBGb/t4vDhJQmAwf4a9dQeZPWnJbiHMfgOYeNlAKlx3BFOxs3L6B+LySS8EUg6rzwuEgQ3luBGugDqx/lCzyCGPbtCBBi05M9Io2OFB4hEXgmGLMgzZDEjIvYruUf/0I7BGgkAJWAbY46SUArGThMyAIZVADH2ppEkiCBir2n5xmpu5ME1I5pUH+LYEnFICKEDpiFEADPSSu0JhQX/MphTBFBIYnI3MRjgLviLs48H9OR/JNf4IcAK9bxPwoV9TerAXgj4T0BOJk9MhAQDZOfACUCNgIy0zbTJpPZpyGAQwTiKug7AYkr0L+N991Vf00gpGyHINbK3yZVMQQwVT2xEMh1BEZ/Nvk1EKsKmgXyGeOeTQQdEf/TL3wggNX2b/H//jqwLRGo1gC0HMCeD9AlQPw+WDqZJEZIoCdaNY6OgOmFAVq5u7ae3Y9AHam7sd8kApUsZHaekclAvrv86eoBcwkZkFvrA1hf1wU4Cu4Btu1T/c8G/hWgrxDEmSFDc0D//OdDCEAqADoPIMnA7a8wrv6LpSEFfJlkoQtAdfKShEmAWlUDN7xgOYYE6DPuBY+Lv0W0HRXdK/cN2X6l0jqcsICubbx2AVeFAK7Sy+zV1YDiasAjgH6MvqZth+vXH6sksfyLn/eKAFaw6yoA5gEE9FYScDsZZfsR8CwhSJNb2Tq5UVLsQO0lE5Pk4bqRiBDU/oEcHFVn9X1T4dFZ6TKhYfWZcltqbm6HsZm6D07QKuGRcqQGgEUKSF5N2QySYPutbZkw4SmJwCIIJIXIYSz/8uf2BEDXAWAosN/w7gUhAHwhge7GY2wGBKFtf5oMGKgcl1Cx/wKwKKQY2hWB3oHbqver7ab6J8t/2L9VbaR6sM8auk4gArlRNbBchQnSaBw5RyV7lRCAgSYCerS/otRZwqiMmSECc7x/9XNUDkCvAyB5AAwDtrlBQgG8KegCOsvolQgrgPKcQKTQSReBhOCquBP3a8LTToXF/vpY8ls2J6AdBFH/rNJfov4YDoL6UzVP5gDc8MBJBFbBnwHrWW08EEcqrvhw+5oNBZZ//bMLBCDqb7kAcAJtUQeyOuQDcGIPnzFeJQClSbJqngBULW3xIzKpkBYe3wGxkISn/u5zASwccLbh5NHhht43ELsFcGeFXwfmA1UAdBsZ9YxU/ej+zDkwJ+RtO5Mkmhh9yc+637cKwJ79lxyAlP/kKcC1IqBzAJgL0K4AQwC0m7hgyAsBrAVEaL0HJU6SQKeiyT6dWictOwsTsqW+9ttosAax/pA3AKJBEqEhQLX+T+J2PG9GEIxEPPC6ag/SNzhOtm/fZo3JABYpfLT/KBFU+leUvxHNR37mSAAC/lYBUDkA76EgIYWOAHASKnXHm4/hwaB8pIxIV8oFFpxlziNws/0diSgF91bwuQQmE7QQ+2fUvwO+pf7KkXRA9db6W6QB1+KCHu1qMgTQE70DoTOG24/Y5qMuIEMOFYBXQ4FM++WjP2MnAFUClGTg5gCEAMhy4M4F7JNou/eZ0qBWELD7qO6D0uNkZXmEwKqb4HXI4wzAa8ejLTYSjb5mfXz8jgCvlP86YrhC/ZH4lfpSFU4SgAfMo88TZFxAlRgyY1aI4Iy2zQF87KfbBLCVAAP199YCaBJAV9AlnAxX0NqwnIBSrHSSziAPa/VeJt/ACMp0AY6l1+CNvofqb6h6NikoJMMUHN2apayZNt3YxRwAPa6Tb2iTXj4cVP2MwkdkUQFz5njsGt1tX/rTHghArwHY7P++DBhdwDanYCWgzgPIfh2TtfUB+6QcJhcBedfGUXoGwAaOyXhdKy4rC1rxPAtlymqfjP0x5h6ArVSdARJdiQa6BWC8t3h8RhQ616AnY+cEigRQdREWUZ1NDBnFz4I5Y+OroMf2y5f9VE4ACH50AS4B7OD28gDtxyEVgW6yOIQwWGlg/Uz8bQLXcBoa/AM56Dq8FcMbCTyx/o3ISF3fsvaMWPRv7JLEPht08nC4TyTDb5UNI1VnwO3coaHQFPBKxa0QwAO/G1LAucwA+2oHkDkny2Vs27/8pygCANUXF9D+h2CdC1CA334rcQf7Z7yxsp8qiFpBOKhPQAiW6jIlN9UdzllAKQBjdtxT9eF8HJLQ5xNae6Lska1nSu+pfyMjb3GOlxwEYrHANwA6sO/abdBxyRiPAf4ZoGf6WOA9y0Es/+YnAwHs4JfsP4v/JSEoTgD/is1veYFZEsB+xAp7gDEX0yRU2asQaHX2wD8QjEEsCDKt0pZqM2LpSqaiiNpteCW7mQSgukc4UTWxsH0Z8EaKT/erRGIW/E/pAo6AOdt35+Pxvwf/t0gA8BKQFfzZMiDmAYakoJ4oUB2gE4UtHDLiYQSa9bnsDEhJj4HfdBYHF/V4Vn8gvh3sh9Rfk60ot7c9Uf+Xc80AkDnCNGng+RrnzCa/RS6Z8zXBJDv0ORnf9bHY96Pbov7LV/ykMQfQrQMgVQABvP67//60BKgXA7UTU9Z/mDgk+TeAndjrBtpCBcEF9Wz23on7j1p9TW74mzaH4jgC/Vtri20uDdakzvIDbTL0y1I9Gx+V8CJHgNeTBfIMEXhjz5LDU5HB8pU/ccwByBOAXQ6AxP9sQVBL5EJGF8uByPYDCehJE1UGAuB7JKD3MadA22iFx9DCiPPpeZAFOZWyH46Jk2cDPiZFRX1IvI7XrMdg2fsOvCRsYGMM25QadgC8KAeQIg5BblAajOL26v5Z4DPrb6m95wKWf/cTxhwAPgJskQAu/aUhAIB5+22J9aelQa0uOuFFQoRBCY2Soc4PNBDBMQVAGJ50amqVI8kYOH4F3FTZsyU9EvuLMs4q/NBP3SNT1Y2FPQyQcs0RYYT7JxYTZQgiAmoE/Ki/8E80DgO+RQYe8Nvx/v2P3wng9updALgAyEoEYrY/ejS4katyBegG2OfOEqpSX7s4K0QohgVUpSft+5VgR7BFsb/nEkxScByD/s31pB2IIOMSIETRE9YLF0wiOGMtwcUu4EoyyIAe79uyEsDwIhAsBSrrT6sAuyJ0i4KU6p9CAkpl9boBNuHT7iCw9vThJBJfe8erKrt2IZZjoWSIcTkLCTwVt6oC6nojwLKYvuoWIsUf1DsZRljn7m3PAPcMBY/GqIK8YU/IHTYs/+HHKQLYAd+tBCQkMIQA7L0AQAxo8bbjI1MXPiOIqMJNOgIEly4HmvsUIaUA7oQ0tD/LuBsAzTqC7XosUnAy/MwBZADtKTl1fjhB2aT19j9RCHAGOWTGyII/Gyos//HHAgEo5c8kAbv4X6m+lRDEmy73EtViSEA5pcFOIVTSMHIEAgTLVuvVceXVeFWwO3F+ByIW5zuxv1ZRRqL6d2TK64E1Y/9dIiDWfVB3veqPEcEThAARcDNgPKtNdC6Dw/lPP+Z+fxcWAOHbgM2FQKDsQ/wP+7TSo+qzsiAqk1apLmGoVUor4kTpcCCDALzZen1EQpbNp+QEjgNdiZWxN8t4pCKQUXeLOChZOFacEoFxTmzsYRIjEZwQAnjjRwCL7Hu0PxofLnVc1IM7gzxGE96vWgkAHwUWF8AWAuGDQOyhIAQ/KwPu+9t5KmVvJwXtMHSgE9BQfU0g7oMy2g4byb9ZMFtkwUCMhNDtJ2VDDVoNLBoSEBLpQBYB18kPpElkv9HM1XRzwFB85gzw2BaArX4uoRRAFYG7up+RQYYgKm5i+aof/RACiPK39wAAEbB3ArSq3v4Bl//qpcAa8Nt3QhAM7N0FE7DTSWc4goEUAAwm8Ky1CNYCG69syWr/BJBWLkArvWflL1H/iDwE2I6dH0hKJkeyYtCRFYCThSdZYLuEwo6hCGwGlE9FBsNx//OP2gkAwwBJBBoVgK4SsE8KyQWwuJ8RAoIdCQJvpMXqVnlQA3z4TpRdjsHA1IEo6hss7JFzQQDQYwaE0AHAUmMrSWgAmJKomuRH7D8DmOVWGMAjgHb7T8oBeORR2XcFOcyMyfps2776C/ocwPr7df8rkEMC23xS/0uQLgVm3IBOAHYni1ldneHVcSMJKdbJEYYOQU7BDR+M8VMZeQZUY1tHVNYxlQJnQgJNKNbk9tzGAFovx0CWDXurDkPF1+MVcgBZhzDbbgaoVWdQsftNaIHcNwLQIYCQgCh9SwaC2jfgQ/lPg92qAnQnokIB6gCUcrlVAqNsZqqco+xMtTM2/FTwVxyBofAsvGGgNe25UxqskgxV+ETIkCaCAgFEzkLmqdXuqZ1ARBam6gMAl6/5kSoEUPYfwa/fBNSeBQBi2MZW7wRox8skBgnYTUfgKLeA11O4KDk3gJ0pWzI00BOYxuhOeU9fhwXWqdg/Io7MfuJKKNhBfRrAJisAFJgH1wF4oPYAF4HxyP6oLwN6xhls/f7Lj7jf5dHf9hdeBNoRgJH5L4UB+2TSpBDmBADsCG5U9izYq+Sg25uKqqsJhnJ64JdrcC13Mfan14tAdDL76MhM0qmOFdh2fRxGJBZQoycKI7BkQZ5tFx0v2h+BPw30BrhXH7bweCOA/eWf+kUgFvjxKcChGqAAbuYADCLQ4N5O14j9I/DjftcGe1UDpn7Ogh2LhCrHfyzw098Hwews/aVkkMzkD8qd7JciggNJQItUjoC0CuAjxMLOMzz3r/3h4ADgLcDM+ktOwKwC4HJg9ZmV/RoXWaGBUv1TiYABO8ofWLHwRDLPBd8JCn8quLMWPeMkiPozK5/dNpBCkAPIgnwWiLP9QqAqBc8of6rN1/3wh4VA8gRg9AxARwI7iFgJUCcAKwlBFg50lQIdDoCbMC1rpYKQrBygW+kUMcjkR+CsxvHus/sReCPQRvsR0A74rPCBnXtK6ZVTsdzgYwK+ovaVthE5zCi/8MnydZ+vQgC1AIiFARveINHnJQMbNlHlAbDbiTj7NBmUiYCoNqsiDBNUT+YjoHaSh3Lz3BDBcivedkaSjvqa8X2ypBe+QEQBVl9vBHrmCCi4H7EKcJban00GFcJYvv6H9UlA+i4AXAuAZT/1WWf/LdXv8G6VAQkxlMHPMsJFJ3CJylugstTaU2FPdT3wZpQ9UZ4LiYvU/TswJ1xDRsWZ88v0a0oIFjtDNt7YEQCPEEc0dnX/AwGQ2P9oDkDCAvld9XdP9dEV4I3tbpaenMZ3V2lIn0yCSlv0wyTh1Nkz9p6ppxVGoFU2VV/UOqn+6NKiMbtzdQgmcgRv1P/hJlXdw/C7/dcfajsAifeFDESU27MB+wa5jzoUaOB3LD4SA4v9NVF4LgAnd3ehgeozAHugHianEx6wCR+FG2YeA294whVQYtjvWQRUMw9BlDIkG7b6j4VmVrusOp9s/y0ncJX6R+POAD4kiI0A4L8BQ+Uf3gfg2H/2MBBTfdP+C7vAzdaPAFfIwLSERHVoIoqUBjNKm3EDGVIwx8kAOFLuaL86hkkkxcU/jDgrSh8CUhG9B6iMzc+0iUB7xO6H4EWszLqBb/ghJARgTwKytwI7OYAhBHBcQDYckOtlTmFYABIA3XILbCEJ3QaE1ampsRItHTbsF+mqqpUryCzZzYA/QzJJN+ICPLFqLwPCI/F/aXy5N4YjiRT6akB7BGmd2/INP/ghBGjJPwL+1QnIfGf2X8CuQ4GGEZXoO9UFEOdwhAxYDiCtXE79ngKh2t7LFWTAHwAbSTEKEby2kaqznEHUJ6XmCUJJjaPUdFbFK4CvtI2IprJ/+caVAHQSkD0ObL0MxCgJbnNNqb7+XlX+KATYLlwdky4NZVaRxY/ZcMGLZwNHkCaXCPwZ1bbOBZXNyS0wkJruSKmll1w9CsrHdACzZOBdYwWwYj7CcAhcijf+8o0/KHYAkgzs/u4Trqm+/g7gKYUDRNG7F4jKhTlAbz+SbgNjdz+g0S5yA0wFO5AQAnHVzwOoZ/vPAn8yMeclKSMlPwOspm1nhO2oeRZEM+0qgH8q9d/O8ZtWAig4AMGQuRDIWQ48JAUBkO3eRcDWuQSi+pETQOBSdpxQ/kjJI7IYljkrVXaBlajpZxbqeGrOQEDzGqA8OoywfvdqHP5+IICznEKFSDJOYhjvm35g0QEkFwIh2Bm4w3AgcAJ6MrV5R+y9BpcmCFQl+oOz8MByE0qNu/EK4UDkJBihWHF7Bvz4m5jAJct+I8Wn+6+I1a8YE0k4+OwBtaLwlbYZwIfjrQQwrP4jK/82+6+2y8q/IQmolR2SiNvvqFUc3x/A9jOwESfAgB6BnxGJFR6E9tWbhJ499ey9FUbIhDT6ejadAjwKMbSVtkgxY7kvAOuZjwFn1fvq0CACeAhucGPycejzzT9gdABYERheCLqDUQhh+0qeC2iYNcBvWf4wMWgQhE7+CdHoC04TAlFy0zkY6+41udAJkyANar8JKVIHEBFEspYfOZLIxofkmSEOr82B+H9WvWcIoALaStuILNj+bdtKAF4JUKu+uQpQx/5AFKj6NBwQeiLOYCCxKEegCELb++GHcCoCA2taYHXU0IrtXTJhjsd5kKcDpziDBEEgQZkkg+MBWVigiYjA/T3gZofjGI4kC+azwTszXgTaqwlgHX/5ls97tRRYVL2tADRCgUH1yYKgDofE4nc4VqDG/EGbE0ZiziMIF/yGYlCHYJEKKzviJLaOEWTbQ5CQpN9AAhcoP5JWGaBA8lmyKYHZI+FgldwMeLNhgncNlX0RWczufyAAWQqcjP2tCgACV+Z+t0RYAUmIpAOxEdtHTmDbTybBsHaAnIMmiuHmatcBk9m8iexcEgrqVgP2c6cxvFL+LMii2HkYJ5Er8H6TaeL4ANj/CKSPofiIowcH8P23COBGnwHQhOBVALxHg1l4kCED0mbIEVjqTIhk+4GT26dJIXAF0yGBQR4U6MR5ZNsNTkIRS0mVsa8ir+o4LnF4ZKvPYXKV3xWK/1o4gG/9/ioJKC8E9dyAAXaM75sDANDp+N8LA7p3CyjF1Y5B3xxKEsZ6AVo5SIDYZHMvGRUlqqLseLCSbzunpBVGMsy6hTA0icAWXf9sIjC45irZyPzKuJUjIH4KxR8cwLd+v50A1PMAmOzTnwXTYvkld7Bth5uM+9uBo3yAodKR8uP4HUEQ5dFtGYEM25QCDwQQqVAEzAgcQdx/JvipC4jICX50Cpxk/wzoorCkAsrM8WbHM0WCEGXU9qr9y0oAWwiglH8LCYz1/w3wqvznqr5BDhqsUwuEqg5BkUwHdgOI2yGsx02tHIHcaGd/pMQIbArMRF7hCGAwFMqAxWwTEdys+sO9zJzfjBuoKPVVba8lgGISsFsApElivyE45wdXADdNhwUdlkm8nnYCCeWXY+l439tecgvG5OxuZqSMjnPoJnwWYJETYUoenWOkaBP9M2C2yDML8my72fg/Am2FLKKxZvZvfb7t+77KAWxOwEj8NXUHp7DNb3QBCvwSAnSCq0MAQhiitugOcCzcbsX71qrAri9OXEY21nMGHUu9GnG4oQVncMg2Z8FPSDEFNMcVHemf6ssIidw3a6wsyM9oVwXhUQLwznkQMVIKbQRAV/45RKDJoAHcIQMhiwjUQwjQscer3hYh0BWBxhhCNCzej/ZZx9FuIsolHLbMFUWfAXIUviAY2ecKOUVjMTIoXH8EmAwhRSA/Cuoj/c255pHot33uQw6A5QFku5cLQGAjMSDmLCcw4BImixUaCDCZkntuwGtPCcABCx6nHBJkVDg7qSuvwEoAcQDIBPi9MTIAKyt59rcKyGWWHCr9IvJ4kv2NAII8gIC1Wwqs1wUAoi0yEABrx82UP+sGziCFDsgkHLDyBN1N80gjqCLg+CkQJOPqdn4BUOhEniENVJtE/2x8TduRa/IAmT1WBMSzxomO8yj7P/65r1YCotIPn0m8j28BFpVvwGdkoCRf2/gOd1k3MNgImIEEyBZZYEKJugVrHYEoi3EsTSzu5HEIZCCFyuQPnMIl4If7kgVMtt0hUkOCMj5XgVex7VM2XU3IlEAQxyPDdP0//n3GlYAh+FWs370OXBbbqWSfblNxAlbbsuUPyMLLBeA9YLafTZruB8+AO2vps+32650Flqem4b4T1d881oyreWICqJLL1e2XjQDkjUDkmX+d5WffEVeWE0CBNJU/qfq6f0eQBdVv/Qw1tdyCBWzGsDJGqBIZgiCAzjqK0kQ6A1hnjOGBNUEwIUmd5AAqxyndB0PFw7nkOAY9R5ePf+9XSUBGBAJudAVt234Ttn37xi4ESGyTE0rnAIBtBqwfAD/+Zl68r8nGdA3RykEsy2TtfJYkKsfWk+wM4GavJwnA2fj/CDCPgqzSPwoLov1HSOUVAeBKwGgtgJH80+AfbL8OC9A66Od0gFy0UiuCa+Sjt0cKboYQRGmHsR0w4vmGE0GRltk+AapuIlTbG9dcDh8mxpkCauL6wt/eUcojfY8AUiv0Wd+tc3ogAA/8xsKfDuykTVP2/YO1GlCLNnUCiii0Cpu7LUfgjUf2WTG/JgXLORwFtbkE2VLQRNKPTgiHjNKASBw7PZZ2J0Vnc+Q4ugsk6gAAG0BJREFUVVKKQH/muZxKCp/4Xv3DQGLn0fI3sEerAPVTghAaaFyllgcDi1Asq43t6yzwI2IIKgHiOFKWjZyjZ3XZBMuAOJqYbTJVwwuDfIb/l8FR2cy5VX6Ts0HmZdunz90i7eClJZnjZdoMv1EjAMcFbLiYAT+x8TpX0DCeAHPXxAA5XTug7YiW7on9NPYPwgLtEEKiSNjcTg2y4YSehCeBv+xUZid98ne5khCmwHaQDGeOGfVZVgKwqgAiiBH4U2XAfTCco1qxNcAZxiOAm+J/kSvwEoYU4Anl325ath0hr5BYNPDYq9Sr4LzY+reJfBZZVa/vhPYRGGf2Z/p4bZZPfM++CmCFAF4YIETR/upnApw3AqUJAQ4ShQPD/ovA3wjdANDwwxvKZbVjN45uSwI427eqnIywpsbIKOT7iAAy4Ix+p5kxMn2kzSsCCKoA+AiwJoOOAJTtF8vPSAK3NSFLhAJdPwLuTKiwHc8jhsx+1YaGBSRxJdeadQgWETBVTJNG0mVEE3TbXww9yg6lmPzL/gapawNSitpXgIdcF40783tlzmUd94EAEiVAuc8m+HWOoCH61fxAy19R/mplAElHicqrryeD3wM1fVkpm1gBkOgxHEV0gZA4VnpiFlQ5MzHNNoXjpM+9APBozKuI59BvpgAwJgE/B0KA6CWgrP7vZP4bWcBJZJYEI1FYQuzlAtw8gTFg2jXs12I+diz7gQA9tu/2GaRkOQvrfYapiZgNR6znyMn1zQCkpG7GOZfG0PenQAAZIM6cS2bcq9osnxAC0C6AgH14+Ie9EIQQwoY5FRo0HAbbKY5In3Yf2QtHEGVWiGEAVhHow1cHPHgeJnAZqAIll3GrSUdKBkdyBmQF41WTsxv3LMK6mAAe5bdwSKt6/AcCMEIAmevrbz88A7Dv1CofVQQ66w9ftAJrMdSuAHD46ucIiEGDeRDcKCwgB43KgZYa47l4biIav0QyybjfOufhWGcRiQHK7nivKQFUATcQ+Ylgnhl7+cT3sEOARgDO038dATjZ/w74AKTM9q05AScjBY8YEHRVy4/Kr4mEKZXbRnaSa/IAvR3HISk3CZkkr3AMOPeM3c2SiTtWAfyzgDyz3+xYZ/6e6XPoCMBZ9tuAboB8cALKIbT5x54H2CeVBrkGOHUFHjFQNlBJ6wnVZ+AWgogA3Fg6cVymuJ1zME/kYQdT0CwgXTUpEFdmUodtCgQQjrVf2NXtMuNn2lTu18x4rxyACgO8sp+n+ts+A+Rs+a+0Z1jFfXS/ASLLGQxjJEAYlgpn1FwdN0UazloDD6wR4aQVH4GTPP+ZCUkn/MmhxtWgsu7H7O9x5fkun/hsFQKw5B+AGsGfjfc9UrDIYjukmmjatlv4taoAFduvyccFWYJIvOSdFvIo7s8Avps0ScBaE606VoVUdFvL9byO4Inc2PvhnEcC2CfL+mf7p+P//ar1dgTsEA7AmJ1gFrZ36k36tXEjV8CshFwT3tEsqBPt2rDQNqX68GNl2kfEUQGmpcQR+VSOkQJIQf2vUMorxkxdd1R+hbl6aLzmAMhCnuEZAKPmrxW+EYAFcGtpsLM9dATgUrSiMvLQbSruYArQCaKIAJxyCjgxnGN6hGLuyy55npicFuEcJZSjAD7aPwvOK46TGfPBAej4nz3959T8B8VXYMR5aK4HIACOLD8DLZvzlp2nZiAB1G1+J9pVbD8jrdR6Awts5PymQL+Pf6j6EBCCNVHN/7iV/lgq6XkWCcn1k2NmwX2UxLLHyQBeLkPGXD7x3cccQGbdP1P9UPmt5CAAqiMLOVvD8re2XkjggHXASALUWfAzl4BzKLT0wblk+kdt0vuNc6lMbBPkhtU9tMpRgfUogGaApfmi8lsdPd9S/44ASLyPQEelZwlATQqIPU/56ctB1MtEGI61slP1NybvU4LfELBXmxMZfzZGxnGkQY8HgB9rxkVM9XkK0imqfYUYqgRYAnHBEelxXzkAJwcg4EOFz9p+5hSasBPlZuGCMgIPIkwmiN50RjWg+22zDsFxHRnwR21cEKtzjADvTUx0OzMgjsY2VbEI/iq4ps+L3JiKslfPszJ2pS2exwMBZHMA+8Re709HAGxxELTtnACgWZNIa5ew/APY9c0xngno+qlBXHxfDP7tBlaOwSZjsn+GFLZJciAMOUQYRQI4dKxHBvWVJDAz9vKJz4rXAYjidiHA/sPRtQDWE4LGOwIt1e+2KxvgEsD7DPyotNPqXwQNO84ApIkxI3IJwXryMcPjnUAAVeCd1f6MaxsJgNX9WXjgKbzlCIwyX7vn3jJhpZCUAGBjRBCKTzjukoraOlfbp04iooTk04mFic4I6QiwvQkvp+XlL44cewYkZwF0uDZ1D2Ztu76VR8ZZPv5ZDxpOwwDr+X9P4ZV9b66B2HodRmgXnHEGrc8Tgz98B4GF4wJp0Bud7B+BqDu9fcxMn6hNaT+5llL/IsnNkMNMn9eZUDYC0M/5I2jXzxqowzaw9l1bZzsCl1p9I1zQJCHkhffeVH+HJBgA9HwysZYE4TA/Z/sZziECi+clPAXOKg62y5xLFHJMjZFU2ciVnA30GRJ4jD7Lxz/zVQ5AwFVa/rt3osAv5gIQ3A+25OFuenbefV6AlBLZeBb4U/hMNSLQC8gonPyzx7Xq7gapyObwfKJx4SfIOJmzjveYQM78VlW7PktU2eseCSCI9wegW5Y/SQwakDpksPYLM1juofVTQHFxE71NKGkJQmyGDTyt9qsFGeCYo8N5ZcfJtnMnsvo9smNm2mWBUHU50bFnjvvYY67H6wiAvvLLyQPgk3xWqKCFRZSdAbdti5KBilws8YrcAd70cgxfJYtAYQPI97uPEog62DbxCmNGE7UKJjx2duwz2kVjXLl/hiAihzEz5isCCFYByhzRCj0A37H92xjE1neuwtmP/V1nQBYKWfMbQ40MCKvtD5EMO6ErgBqMGQGBnWa6z37sdPujoUYUipy4f9a+R0A/c9zl277bXgXYRQABjsDUIK0Anym7DiW0m2CCaS0ZHsggafuzYO6GSwCQNkn0CwnojDESYUwFjDjcTL9osVHZTTwigCMgvu77txCAEkCy7s9IAcHI3IIGNoJwIAV0ppmwYD+4xgn9HoCpAuIQl0aDsF9nH0J6KDWo2v5DKk86zxy/QjCZtq9Tm+hcrtq/EUCn9M4LQIYwYL+x5mpABUgK8H0jgmH47IC/U38Sl1fBnwV+GryzuYILwd+GTl5ENPmyzNONkzx2xg7PklP2ujLtHqtNdJxov3YljQBEibW1t7Y34CVW/Wngt3vv9MXxB4sPd5w5CBY+6PESTvihCUzU7JzF68uCwzrnSnKudCx1MZmJUxo/itWTP+bMeWX7PEW7s46ZGSdq00IA+uYfou4DkEG9vX2W7Weqz8gBccjcAQNPRfnNuUjcCQPB6a7BZIMqBI32SfBVjhZNtm6sxPFL48HglX5XtM2OeWa7zFhWm+VbP6NPAgrYXOX3VH8fwFT9qEqg+rvq76izRxQZfEVlQXcOJ4nDBdgZY6TZKoZ6ZpLFo4iq8JZHj1Htf1X7K8bNjDnTZiCAyPLPxvs4LnUEiaW/HaifCPyReEXEkSGfM22/nO82OaKTTyP4QMOLQo/M5NdnfXWf6viZ9pk263Vm2m0hwOoAUK3NxUCBsrvEkFH9YI1AN3+zFYHki0M6UBog8bCDYcth0SUHOgW3pwxyAPiJ9wvMjp6Z7Gzsx+pXPU62/RntGgFYyt/IQVnS9au3DwHL6vc6RIjWASDIBntvOMvsSkAPwBZuuu0HQBuNUwUFPd+LwZ+diFc4kPSxyQ/52H2rx6u0z7bV7ZZvkRyAEddr694BP3IFmXyAE/NHlt8iAv2fjXju1wJ/Cvhq4AzOzDZO58y4mXxClUxObX/4IvqzyU547xqOjnGkf7VvpX2p7bd8eCIJKIpLXAFTfq322jl0feCOee00qC2HYIHfUt408GFgb26n5v0JawVmiOVUgHuDpX6E+GwqEzseLRcnXz3OzDVV+3jtl5UAEKAIOhO40WO+mZifOA5KBEG7DuCJhUADIcDkZPPUJIQDil21/dP4KXYsNs9g46HNgYGrkz1/UucRwHrMo+c527/abwwBdgLoSIAou1bjSNU98jD/81Ct/t7/IyAuRPocAH9F9be2pEM0x+l+tTEag03u11H55Zy2yTZzURUUH2xbBVDmcEfGfOy+yzfrEMBaCrzfTAbsiBwyYcGg/oSEAOu9sKi2oe2fUP3WJQnacN4XbH84lp6VB9xJZoKn25RPPD3yaQ2PAC5zEkfHP9I/03cjAAbgAegHFv9YBMEsPyqsPgcNbNaWgb+bh4QsNLHgjWV9Q4IxZoZFIubxghmWcRWZSVrgj/xwb8Df/VYZMEY/7hVjPBAAgIIqvKHGkfJ3Y0UEsl99+L4AaQcoxLmm593Z4Gfz2pvrw76kg5giBXIiV+EwHDdsEE336/efAaiZszzzuEfHWr7508k7ARXIEMjMGZhKnnkpKGnDxhu2ESWfAX8K0Jn/ZwBmgjn3E7Y/i5uIWDITM3uszFgdYV01cPVEgvZHwXP0dK46fmXc5Zs+nZcBN8BFqn10v7H8V5NMZ7kTVYHBoicBTMkgqaqhC3AaRHiJ9m8TccJZeBM4dUw2wIHrjABVmdjkJ2nDV8eJzuus/VeelzX2RgCDwnuLghxV74CbedQ3Uy5MvBQkUn53P7odreIJUFnzvdueGKdq+b3xLwF2NqE/zRxnweiDNc6VpLD+Uo0AGnjBWg92f6dVur2yNFhA59h4nEfb5+T6fw2MCPxU9ZV8mG3UXKNzn1yjnqIRZtz9RXIpinaIplkiCgd+08D9Bc4ihuUbMQRQkzXrDBAv4UNBcllR+IDK/Ejgb5MZZnVEIJ7V9J4M9EAdEUI7ZqZhVrkzZJawFslTegPvR/gFMiSxEYBW2PX7oPIROWTe+JsIHzoygS/6fDTwjiq/Bv8s8BmJAOfR2x6BxnMW1dDBIyxrTkbnt/VzGqX6PwIgjhxCX0MGXEeO9xh912t4IIAo5nfAj2o0kAaqeDLb341hHNcDf/QEoAvsI8lCA4nW5D/iAE5558ABxR/O/SDCD3a/DCuZ83q/E8HyDZ/mVAF2pCEoKcizdj5DJEIaVfAnlgJXwT/lApxS3wzoM2DLTNSK8mfHE+UvtS/A9apxM6fwlMeW81vJ5WrnsREAA/W2LQHsVMyfGKez/gr8Q1ignEXm8V8PzFXXYIHJUmY2mWbIwPq/EvWEzkzeTJuQNMgg2XEzIJwJb6rjHgp7zjrYI43D3MryX8EBWHZ+VvUtEmGAbseAGUSPWwT/2apvglntOAv0bRwDWRnAXdYmM/BkEvKpgZm8tEeC7nWH6QhgRvVdkColt9rKcT1ioC4gsP0V8LttjUnMwFkBvjXJhu2EFGcBEk3saL8cN5uHmD3PaMpnzzMax9v/GMc4cn5n9N0IANXXBWnmPQCi0Enwb8AO2mbAXwFw1fJXiKQBxLg7FYJAR8aGiyboZfvVwNFxMhN1ZoyZPplzie5hZYzXve3y9RICEBAOZJAEdQnQxpiuG3DWBWA//RnJhu5TdyskFTIDKwBPtU2qfwQGb3/Ut/utEo0TTUxczPSd6ZMF5pVjZ88hanfkHDcCiAC7HSAqFQJthi4icAlU8YMyImPtAcAOmLBtCHzCHikwR6GEvtMnVxQY6ZFD2vMt8TDTjFN5yj5Xgisa29t/BNSV4y5f/6nj04ADABNZfI8kqJor5XcVPwF+D7RybimSgF/PHDNQ5YhAPCC2vkl3EYF6VvlpP7VxZpJW+lTasntbAYLVduYcKse9evzoXJav+9RX6wBkMnUKfgH4U+VFDcTkcmANCAR/SBIF8M+CPOUUCDnijZwB9UyfDlSJmZpo0s3HTPtMm7McRMkNRcgK9s9e18HDDt03AugArx7qMfftQ0XKP+MmvD4U4HguhDi8PpV9mfUGTJFToJdrMGaGNWHO2u46iYCQjgAwC4RsuyxRZoA0c8xo3CvGjI7p3dvla4kD2Dqom06JIOsOEs8A4A9jOZCzwV9yBKpxBtSZNt01JY5h3cwzicA7p84VZGZech1AFhjZdjPneYTIop+iet7ReGed60YAFuBc9T8R/IPiF2N+Rh6RWtM+xEmIw/EmlEckacA6KnsGuL0JaO5LJv2ykztqF+2fBXV23LNApcc5cnyPCM4Yd/kv6ACyoM62q7wSTD+BaDiQlAuYLBNSIBeAGRGBSQbkTlZAf0bb4dySbqQ62TOTNtPGDVkIarJjnkkCR45Z/V1nHMPa5xUBwEQ/TfnhF3DHJC8TYa7gKPhLqg8Hi4Bd3W9ZbDZhzgB3ZYx2bs7szUzsqM3R/Y/pBqJzPZM0HgP4eD0bAaTi/WxeoBDvD6SQIAzG/K1bslJgEUF3o48+XUhi32EiFev8WYKYAjzOPBCDSFkicHj7o75Zlc+MQy4vurS2vzp+9ryvtveZ81i+5lPGMiBT3zRJ7J3Tig9UHvVxHYC6SxmQm22csVwC2q8lcgTbGGRWHQF4tq83KbYxjNkegWAW6NG4mUk84wYyx50Zt3K+FgFUzu2o+9gIIALeVeBHuxmdQxb8VeAP48IAEZCn9zvHsCZQFuDZdvQ4CeWPJudTE0F0fjNOoDLmEQKoHmfmWjRhLF8dOQA1KVygFpKDrwP4B7IwgDkNdOYIDJBlgXt2O7wPenJEE3IG7DN9qhM9Ou8rx5slgMo5zzoT5hY2AjBBfTL48cfZhs6+OhzOvANtArBpR5AA5mEiIHc5GjPrCLLEcIXyW5O3uj07sTNgybTJgjU7Vna8KtEebe/1X/6z5QAmwT+AnL1g9CD4hTzcsMAiDba9mPCLQEv3G2RlTfoMoDNtvEnZ+quBZlR6Buwzx7lCvTMAz7SZIYDsuFlyZCrvnddGAIMDCMDfgbxCFIkKgUcg2q6m1X3/VWj7yTUD7Ec1iSHhLrJEcAT0dLIVKxHRRKwSQQSAq/dH15PdX2030z76LRj4oz7LV2kHQJRqIAgB1GOD31DRChF0bR3lM8GcKO91fYvuwmJr73y8yeQSRlL5zwL1rOJHk/jo/oxyR8e4GtDZ41fPoyeAQhKvVBk4Q/kD8FdIYLvhCTLxQozIAWzDBwCLQB3tj87BnQwTyl8hgkrbzKSNAHD1/gxJZNtkrhfVPLo2rfyV9hsBlMH8RMpfBjn8MpbyZ8asEEEbT/1GFZWOgB/tD13EBcpfBfwVbiCa+FfvrwA7OpfKWLNksZ7D8p8+lFwI9AS2H1U0A1Rp47YlwLTaTwF/7xSB9Oj+I+pfeX15SCYGyWYm5etGAhlQPmabqxwFjrsRgAaO+f0k5ccTcI+dBGuaHJLjReByCSNQ16PAj/qHgIUBKqrN2h7tH6ncFQQRgSoCeLQ/Gj+65gxxasufPSZrt/zHrAN4jcCfBjyG4RPPCZQdgAOuCLgeqUSEFIIeZt0VQD46pjeBryCBCMRX788CNjqPCplYx9wIIHQAB8GfVvwT3gNAgTQBflflme0l7qJCIDMgzwCvtQmcSZpECi82rTiECBTVsWbHi/pl9kdtzgT20bGW/xA5gNcc/K4bOAh8D8DdD3/kPygplhVLoL9Q+TPnESlUFdTV9rPOIgLw0f1HQRv9rjpE8I63EYDpAF5D8LuAP2j5o7GpSkMn/UNXvlfaZtxCa3Oh8lcAWWk7C9yzjpEFmAes2X3ZY2dIKNNm+feWA3hC8FeASNuS9QxZNbeOTfur38i6edkxI2BnVFc7kyPWPnO8yvhntI0m9WOSwBGQRy7g6P4skWwEMDiASfDjzTFdxX5m3f4CYCNyyCzwicZIkQUBv6fiFYWvtDVB9cjKnyWLqrqfBehZsM4CcbZfFrjR+BFRynGWf6cdwCT4GahSJBCAPwJrtx++6GOnQK3icVO5T3p+oAL0qG13fYScvImVAW/p+CoIzYxfPb8qkUSAuIIgZseMzjWzP9NmPb+NABpYXgPwlwAPE02vZjwT8BHJsMn7ZG6AzLoMAM9qU7H5Z6j7GWNkVLd6nCwAFVe2r5HCn7V/+crVAVSeAUALbyjhrPJ7LsIC9NaHKN4lDsBQVtMpOI7CIyg2ebxjzKr/DOgzfSok8NhtI2CeCfQjID3SN7pG3L985cvEOgAE/ZFXfSceCio7AMO1uIShriflFhySqQL2DMKgx0yofwbAnnupALYCpsx5PUaY8H4ILSoAjxzG8hUvi88C7Ee3VB5PjrZJuA02BgVp4EBSwM7E/cn1BBVV90A2tQ86RQCOCCuz/ygRZAF/lETOBLSnypXz9Igssy8igIp7WP7tTgAhcCfVuyOBE8DfLq4A/shVuERhAGsKpBeFBNH/gmRNqogoov2PRQJHj/MYJDBDDkeAPHs8fcxGAJaiVwHMwLZtS4Df7Kst+8HKgQX44fj7hizYz24XKbH8rmjzItAe3R+dU9WmZ53AB5UEZoE8228ggH+TdQAFADMgpQhGAZ0SAlHkSOGj/VZ4MRNCZPvMtuv6JQgqA9gqKWTBmAV3tl32uGcpvgWy6vZZpT8L5CgQlAA85a2qtwZ6RflDB5AEfwT4aL+21Fb7LIhn+kfAzfzHIhVgR22j8zmq/BVQZc61SgKV41fH9n6bWXI4q9/y5SoJiAMfBb9Xm7ccwXB8cQVE7QayIW8groI0s5KwOmYEHm9Cm/suUP+MEp/V5oiaV8B6VdsZEphR9Jk+FXLYCMAE0oTtb2OpCZoBq+kAjLFMsgDP4x33TOsfugohMnJuEUEM56lmRaSIV+/PnP8RwGfHrxzjyrZnksPlBPBlRhlwxrpnwW8CnWXJC0RymBCS5b4zwV5Wf+hwBNhH+lqW9rHdwVF1P9r/dQZ6ljiWlQC0SjIbPLRRilYFv0cC7Yc9WOrLAFWf94y9n+ljnZurdie8YnzquMS9PAUJHAVshqCs63oMsFeuzzvPaB8eZ/lS7QCU4jJVNckgUGurH1XuiVJfilSYFTdUtUIgR0nA67/tU7OjouBll2GEKVnQZ4EWXUPFps8es3KM15EEskoPt3T7KP02AojUO0UCk+CnoCWAzII7Au2w3yG8o6COzoUBioKCnKPrFBjJqRlQcQLVY2WJIjNuBaCvIwlUVX0G0NVjdATwMXEAAYBdEnhC8Ecgc/efGPNH5xFNdhOQRdt/ptpHCh3tj675CFE8JTFUjv2UriFz7GUlgOp/DNKRwUHwdxPfUeMjDoCCq5BfOOoEZvpr2x+BLavolXEyAM6obnTMzHEqoMuc09HxKv2rbTPAVYZO/ydUbXfkKP4/BnecprBuissAAAAASUVORK5CYII="; return TextureTools; }()); BABYLON.TextureTools = TextureTools; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.textureTools.js.map var BABYLON; (function (BABYLON) { var FramingBehavior = /** @class */ (function () { function FramingBehavior() { this._mode = FramingBehavior.FitFrustumSidesMode; this._radiusScale = 1.0; this._positionScale = 0.5; this._defaultElevation = 0.3; this._elevationReturnTime = 1500; this._elevationReturnWaitTime = 1000; this._zoomStopsAnimation = false; this._framingTime = 1500; this._isPointerDown = false; this._lastInteractionTime = -Infinity; // Framing control this._animatables = new Array(); this._betaIsAnimating = false; } Object.defineProperty(FramingBehavior.prototype, "name", { get: function () { return "Framing"; }, enumerable: true, configurable: true }); Object.defineProperty(FramingBehavior.prototype, "mode", { /** * Gets current mode used by the behavior. */ get: function () { return this._mode; }, /** * Sets the current mode used by the behavior */ set: function (mode) { this._mode = mode; }, enumerable: true, configurable: true }); Object.defineProperty(FramingBehavior.prototype, "radiusScale", { /** * Gets the scale applied to the radius */ get: function () { return this._radiusScale; }, /** * Sets the scale applied to the radius (1 by default) */ set: function (radius) { this._radiusScale = radius; }, enumerable: true, configurable: true }); Object.defineProperty(FramingBehavior.prototype, "positionScale", { /** * Gets the scale to apply on Y axis to position camera focus. 0.5 by default which means the center of the bounding box. */ get: function () { return this._positionScale; }, /** * Sets the scale to apply on Y axis to position camera focus. 0.5 by default which means the center of the bounding box. */ set: function (scale) { this._positionScale = scale; }, enumerable: true, configurable: true }); Object.defineProperty(FramingBehavior.prototype, "defaultElevation", { /** * Gets the angle above/below the horizontal plane to return to when the return to default elevation idle * behaviour is triggered, in radians. */ get: function () { return this._defaultElevation; }, /** * Sets the angle above/below the horizontal plane to return to when the return to default elevation idle * behaviour is triggered, in radians. */ set: function (elevation) { this._defaultElevation = elevation; }, enumerable: true, configurable: true }); Object.defineProperty(FramingBehavior.prototype, "elevationReturnTime", { /** * Gets the time (in milliseconds) taken to return to the default beta position. * Negative value indicates camera should not return to default. */ get: function () { return this._elevationReturnTime; }, /** * Sets the time (in milliseconds) taken to return to the default beta position. * Negative value indicates camera should not return to default. */ set: function (speed) { this._elevationReturnTime = speed; }, enumerable: true, configurable: true }); Object.defineProperty(FramingBehavior.prototype, "elevationReturnWaitTime", { /** * Gets the delay (in milliseconds) taken before the camera returns to the default beta position. */ get: function () { return this._elevationReturnWaitTime; }, /** * Sets the delay (in milliseconds) taken before the camera returns to the default beta position. */ set: function (time) { this._elevationReturnWaitTime = time; }, enumerable: true, configurable: true }); Object.defineProperty(FramingBehavior.prototype, "zoomStopsAnimation", { /** * Gets the flag that indicates if user zooming should stop animation. */ get: function () { return this._zoomStopsAnimation; }, /** * Sets the flag that indicates if user zooming should stop animation. */ set: function (flag) { this._zoomStopsAnimation = flag; }, enumerable: true, configurable: true }); Object.defineProperty(FramingBehavior.prototype, "framingTime", { /** * Gets the transition time when framing the mesh, in milliseconds */ get: function () { return this._framingTime; }, /** * Sets the transition time when framing the mesh, in milliseconds */ set: function (time) { this._framingTime = time; }, enumerable: true, configurable: true }); FramingBehavior.prototype.init = function () { // Do notihng }; FramingBehavior.prototype.attach = function (camera) { var _this = this; this._attachedCamera = camera; var scene = this._attachedCamera.getScene(); FramingBehavior.EasingFunction.setEasingMode(FramingBehavior.EasingMode); this._onPrePointerObservableObserver = scene.onPrePointerObservable.add(function (pointerInfoPre) { if (pointerInfoPre.type === BABYLON.PointerEventTypes.POINTERDOWN) { _this._isPointerDown = true; return; } if (pointerInfoPre.type === BABYLON.PointerEventTypes.POINTERUP) { _this._isPointerDown = false; } }); this._onMeshTargetChangedObserver = camera.onMeshTargetChangedObservable.add(function (mesh) { if (mesh) { _this.zoomOnMesh(mesh); } }); this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(function () { // Stop the animation if there is user interaction and the animation should stop for this interaction _this._applyUserInteraction(); // Maintain the camera above the ground. If the user pulls the camera beneath the ground plane, lift it // back to the default position after a given timeout _this._maintainCameraAboveGround(); }); }; FramingBehavior.prototype.detach = function () { if (!this._attachedCamera) { return; } var scene = this._attachedCamera.getScene(); if (this._onPrePointerObservableObserver) { scene.onPrePointerObservable.remove(this._onPrePointerObservableObserver); } if (this._onAfterCheckInputsObserver) { this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver); } if (this._onMeshTargetChangedObserver) { this._attachedCamera.onMeshTargetChangedObservable.remove(this._onMeshTargetChangedObserver); } this._attachedCamera = null; }; /** * Targets the given mesh and updates zoom level accordingly. * @param mesh The mesh to target. * @param radius Optional. If a cached radius position already exists, overrides default. * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh * @param onAnimationEnd Callback triggered at the end of the framing animation */ FramingBehavior.prototype.zoomOnMesh = function (mesh, focusOnOriginXZ, onAnimationEnd) { if (focusOnOriginXZ === void 0) { focusOnOriginXZ = false; } if (onAnimationEnd === void 0) { onAnimationEnd = null; } mesh.computeWorldMatrix(true); var boundingBox = mesh.getBoundingInfo().boundingBox; this.zoomOnBoundingInfo(boundingBox.minimumWorld, boundingBox.maximumWorld, focusOnOriginXZ, onAnimationEnd); }; /** * Targets the given mesh with its children and updates zoom level accordingly. * @param mesh The mesh to target. * @param radius Optional. If a cached radius position already exists, overrides default. * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh * @param onAnimationEnd Callback triggered at the end of the framing animation */ FramingBehavior.prototype.zoomOnMeshHierarchy = function (mesh, focusOnOriginXZ, onAnimationEnd) { if (focusOnOriginXZ === void 0) { focusOnOriginXZ = false; } if (onAnimationEnd === void 0) { onAnimationEnd = null; } mesh.computeWorldMatrix(true); var boundingBox = mesh.getHierarchyBoundingVectors(true); this.zoomOnBoundingInfo(boundingBox.min, boundingBox.max, focusOnOriginXZ, onAnimationEnd); }; /** * Targets the given meshes with their children and updates zoom level accordingly. * @param meshes The mesh to target. * @param radius Optional. If a cached radius position already exists, overrides default. * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh * @param onAnimationEnd Callback triggered at the end of the framing animation */ FramingBehavior.prototype.zoomOnMeshesHierarchy = function (meshes, focusOnOriginXZ, onAnimationEnd) { if (focusOnOriginXZ === void 0) { focusOnOriginXZ = false; } if (onAnimationEnd === void 0) { onAnimationEnd = null; } 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 i = 0; i < meshes.length; i++) { var boundingInfo = meshes[i].getHierarchyBoundingVectors(true); BABYLON.Tools.CheckExtends(boundingInfo.min, min, max); BABYLON.Tools.CheckExtends(boundingInfo.max, min, max); } this.zoomOnBoundingInfo(min, max, focusOnOriginXZ, onAnimationEnd); }; /** * Targets the given mesh and updates zoom level accordingly. * @param mesh The mesh to target. * @param radius Optional. If a cached radius position already exists, overrides default. * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh * @param onAnimationEnd Callback triggered at the end of the framing animation */ FramingBehavior.prototype.zoomOnBoundingInfo = function (minimumWorld, maximumWorld, focusOnOriginXZ, onAnimationEnd) { var _this = this; if (focusOnOriginXZ === void 0) { focusOnOriginXZ = false; } if (onAnimationEnd === void 0) { onAnimationEnd = null; } var zoomTarget; if (!this._attachedCamera) { return; } // Find target by interpolating from bottom of bounding box in world-space to top via framingPositionY var bottom = minimumWorld.y; var top = maximumWorld.y; var zoomTargetY = bottom + (top - bottom) * this._positionScale; var radiusWorld = maximumWorld.subtract(minimumWorld).scale(0.5); if (focusOnOriginXZ) { zoomTarget = new BABYLON.Vector3(0, zoomTargetY, 0); } else { var centerWorld = minimumWorld.add(radiusWorld); zoomTarget = new BABYLON.Vector3(centerWorld.x, zoomTargetY, centerWorld.z); } if (!this._vectorTransition) { this._vectorTransition = BABYLON.Animation.CreateAnimation("target", BABYLON.Animation.ANIMATIONTYPE_VECTOR3, 60, FramingBehavior.EasingFunction); } this._betaIsAnimating = true; var animatable = BABYLON.Animation.TransitionTo("target", zoomTarget, this._attachedCamera, this._attachedCamera.getScene(), 60, this._vectorTransition, this._framingTime); if (animatable) { this._animatables.push(animatable); } // sets the radius and lower radius bounds // Small delta ensures camera is not always at lower zoom limit. var radius = 0; if (this._mode === FramingBehavior.FitFrustumSidesMode) { var position = this._calculateLowerRadiusFromModelBoundingSphere(minimumWorld, maximumWorld); this._attachedCamera.lowerRadiusLimit = radiusWorld.length() + this._attachedCamera.minZ; radius = position; } else if (this._mode === FramingBehavior.IgnoreBoundsSizeMode) { radius = this._calculateLowerRadiusFromModelBoundingSphere(minimumWorld, maximumWorld); if (this._attachedCamera.lowerRadiusLimit === null) { this._attachedCamera.lowerRadiusLimit = this._attachedCamera.minZ; } } // Set sensibilities var extend = maximumWorld.subtract(minimumWorld).length(); this._attachedCamera.panningSensibility = 5000 / extend; this._attachedCamera.wheelPrecision = 100 / radius; // transition to new radius if (!this._radiusTransition) { this._radiusTransition = BABYLON.Animation.CreateAnimation("radius", BABYLON.Animation.ANIMATIONTYPE_FLOAT, 60, FramingBehavior.EasingFunction); } animatable = BABYLON.Animation.TransitionTo("radius", radius, this._attachedCamera, this._attachedCamera.getScene(), 60, this._radiusTransition, this._framingTime, function () { _this.stopAllAnimations(); if (onAnimationEnd) { onAnimationEnd(); } if (_this._attachedCamera) { _this._attachedCamera.storeState(); } }); if (animatable) { this._animatables.push(animatable); } }; /** * Calculates the lowest radius for the camera based on the bounding box of the mesh. * @param mesh The mesh on which to base the calculation. mesh boundingInfo used to estimate necessary * frustum width. * @return The minimum distance from the primary mesh's center point at which the camera must be kept in order * to fully enclose the mesh in the viewing frustum. */ FramingBehavior.prototype._calculateLowerRadiusFromModelBoundingSphere = function (minimumWorld, maximumWorld) { var size = maximumWorld.subtract(minimumWorld); var boxVectorGlobalDiagonal = size.length(); var frustumSlope = this._getFrustumSlope(); // Formula for setting distance // (Good explanation: http://stackoverflow.com/questions/2866350/move-camera-to-fit-3d-scene) var radiusWithoutFraming = boxVectorGlobalDiagonal * 0.5; // Horizon distance var radius = radiusWithoutFraming * this._radiusScale; var distanceForHorizontalFrustum = radius * Math.sqrt(1.0 + 1.0 / (frustumSlope.x * frustumSlope.x)); var distanceForVerticalFrustum = radius * Math.sqrt(1.0 + 1.0 / (frustumSlope.y * frustumSlope.y)); var distance = Math.max(distanceForHorizontalFrustum, distanceForVerticalFrustum); var camera = this._attachedCamera; if (!camera) { return 0; } if (camera.lowerRadiusLimit && this._mode === FramingBehavior.IgnoreBoundsSizeMode) { // Don't exceed the requested limit distance = distance < camera.lowerRadiusLimit ? camera.lowerRadiusLimit : distance; } // Don't exceed the upper radius limit if (camera.upperRadiusLimit) { distance = distance > camera.upperRadiusLimit ? camera.upperRadiusLimit : distance; } return distance; }; /** * Keeps the camera above the ground plane. If the user pulls the camera below the ground plane, the camera * is automatically returned to its default position (expected to be above ground plane). */ FramingBehavior.prototype._maintainCameraAboveGround = function () { var _this = this; if (this._elevationReturnTime < 0) { return; } var timeSinceInteraction = BABYLON.Tools.Now - this._lastInteractionTime; var defaultBeta = Math.PI * 0.5 - this._defaultElevation; var limitBeta = Math.PI * 0.5; // Bring the camera back up if below the ground plane if (this._attachedCamera && !this._betaIsAnimating && this._attachedCamera.beta > limitBeta && timeSinceInteraction >= this._elevationReturnWaitTime) { this._betaIsAnimating = true; //Transition to new position this.stopAllAnimations(); if (!this._betaTransition) { this._betaTransition = BABYLON.Animation.CreateAnimation("beta", BABYLON.Animation.ANIMATIONTYPE_FLOAT, 60, FramingBehavior.EasingFunction); } var animatabe = BABYLON.Animation.TransitionTo("beta", defaultBeta, this._attachedCamera, this._attachedCamera.getScene(), 60, this._betaTransition, this._elevationReturnTime, function () { _this._clearAnimationLocks(); _this.stopAllAnimations(); }); if (animatabe) { this._animatables.push(animatabe); } } }; /** * Returns the frustum slope based on the canvas ratio and camera FOV * @returns The frustum slope represented as a Vector2 with X and Y slopes */ FramingBehavior.prototype._getFrustumSlope = function () { // Calculate the viewport ratio // Aspect Ratio is Height/Width. var camera = this._attachedCamera; if (!camera) { return BABYLON.Vector2.Zero(); } var engine = camera.getScene().getEngine(); var aspectRatio = engine.getAspectRatio(camera); // Camera FOV is the vertical field of view (top-bottom) in radians. // Slope of the frustum top/bottom planes in view space, relative to the forward vector. var frustumSlopeY = Math.tan(camera.fov / 2); // Slope of the frustum left/right planes in view space, relative to the forward vector. // Provides the amount that one side (e.g. left) of the frustum gets wider for every unit // along the forward vector. var frustumSlopeX = frustumSlopeY * aspectRatio; return new BABYLON.Vector2(frustumSlopeX, frustumSlopeY); }; /** * Removes all animation locks. Allows new animations to be added to any of the arcCamera properties. */ FramingBehavior.prototype._clearAnimationLocks = function () { this._betaIsAnimating = false; }; /** * Applies any current user interaction to the camera. Takes into account maximum alpha rotation. */ FramingBehavior.prototype._applyUserInteraction = function () { if (this.isUserIsMoving) { this._lastInteractionTime = BABYLON.Tools.Now; this.stopAllAnimations(); this._clearAnimationLocks(); } }; /** * Stops and removes all animations that have been applied to the camera */ FramingBehavior.prototype.stopAllAnimations = function () { if (this._attachedCamera) { this._attachedCamera.animations = []; } while (this._animatables.length) { if (this._animatables[0]) { this._animatables[0].onAnimationEnd = null; this._animatables[0].stop(); } this._animatables.shift(); } }; Object.defineProperty(FramingBehavior.prototype, "isUserIsMoving", { /** * Gets a value indicating if the user is moving the camera */ get: function () { if (!this._attachedCamera) { return false; } return this._attachedCamera.inertialAlphaOffset !== 0 || this._attachedCamera.inertialBetaOffset !== 0 || this._attachedCamera.inertialRadiusOffset !== 0 || this._attachedCamera.inertialPanningX !== 0 || this._attachedCamera.inertialPanningY !== 0 || this._isPointerDown; }, enumerable: true, configurable: true }); /** * The easing function used by animations */ FramingBehavior.EasingFunction = new BABYLON.ExponentialEase(); /** * The easing mode used by animations */ FramingBehavior.EasingMode = BABYLON.EasingFunction.EASINGMODE_EASEINOUT; // Statics /** * The camera can move all the way towards the mesh. */ FramingBehavior.IgnoreBoundsSizeMode = 0; /** * The camera is not allowed to zoom closer to the mesh than the point at which the adjusted bounding sphere touches the frustum sides */ FramingBehavior.FitFrustumSidesMode = 1; return FramingBehavior; }()); BABYLON.FramingBehavior = FramingBehavior; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.framingBehavior.js.map var BABYLON; (function (BABYLON) { /** * Add a bouncing effect to an ArcRotateCamera when reaching a specified minimum and maximum radius */ var BouncingBehavior = /** @class */ (function () { function BouncingBehavior() { /** * The duration of the animation, in milliseconds */ this.transitionDuration = 450; /** * Length of the distance animated by the transition when lower radius is reached */ this.lowerRadiusTransitionRange = 2; /** * Length of the distance animated by the transition when upper radius is reached */ this.upperRadiusTransitionRange = -2; this._autoTransitionRange = false; // Animations this._radiusIsAnimating = false; this._radiusBounceTransition = null; this._animatables = new Array(); } Object.defineProperty(BouncingBehavior.prototype, "name", { get: function () { return "Bouncing"; }, enumerable: true, configurable: true }); Object.defineProperty(BouncingBehavior.prototype, "autoTransitionRange", { /** * Gets a value indicating if the lowerRadiusTransitionRange and upperRadiusTransitionRange are defined automatically */ get: function () { return this._autoTransitionRange; }, /** * Sets a value indicating if the lowerRadiusTransitionRange and upperRadiusTransitionRange are defined automatically * Transition ranges will be set to 5% of the bounding box diagonal in world space */ set: function (value) { var _this = this; if (this._autoTransitionRange === value) { return; } this._autoTransitionRange = value; var camera = this._attachedCamera; if (!camera) { return; } if (value) { this._onMeshTargetChangedObserver = camera.onMeshTargetChangedObservable.add(function (mesh) { if (!mesh) { return; } mesh.computeWorldMatrix(true); var diagonal = mesh.getBoundingInfo().diagonalLength; _this.lowerRadiusTransitionRange = diagonal * 0.05; _this.upperRadiusTransitionRange = diagonal * 0.05; }); } else if (this._onMeshTargetChangedObserver) { camera.onMeshTargetChangedObservable.remove(this._onMeshTargetChangedObserver); } }, enumerable: true, configurable: true }); BouncingBehavior.prototype.init = function () { // Do notihng }; BouncingBehavior.prototype.attach = function (camera) { var _this = this; this._attachedCamera = camera; this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(function () { if (!_this._attachedCamera) { return; } // Add the bounce animation to the lower radius limit if (_this._isRadiusAtLimit(_this._attachedCamera.lowerRadiusLimit)) { _this._applyBoundRadiusAnimation(_this.lowerRadiusTransitionRange); } // Add the bounce animation to the upper radius limit if (_this._isRadiusAtLimit(_this._attachedCamera.upperRadiusLimit)) { _this._applyBoundRadiusAnimation(_this.upperRadiusTransitionRange); } }); }; BouncingBehavior.prototype.detach = function () { if (!this._attachedCamera) { return; } if (this._onAfterCheckInputsObserver) { this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver); } if (this._onMeshTargetChangedObserver) { this._attachedCamera.onMeshTargetChangedObservable.remove(this._onMeshTargetChangedObserver); } this._attachedCamera = null; }; /** * Checks if the camera radius is at the specified limit. Takes into account animation locks. * @param radiusLimit The limit to check against. * @return Bool to indicate if at limit. */ BouncingBehavior.prototype._isRadiusAtLimit = function (radiusLimit) { if (!this._attachedCamera) { return false; } if (this._attachedCamera.radius === radiusLimit && !this._radiusIsAnimating) { return true; } return false; }; /** * Applies an animation to the radius of the camera, extending by the radiusDelta. * @param radiusDelta The delta by which to animate to. Can be negative. */ BouncingBehavior.prototype._applyBoundRadiusAnimation = function (radiusDelta) { var _this = this; if (!this._attachedCamera) { return; } if (!this._radiusBounceTransition) { BouncingBehavior.EasingFunction.setEasingMode(BouncingBehavior.EasingMode); this._radiusBounceTransition = BABYLON.Animation.CreateAnimation("radius", BABYLON.Animation.ANIMATIONTYPE_FLOAT, 60, BouncingBehavior.EasingFunction); } // Prevent zoom until bounce has completed this._cachedWheelPrecision = this._attachedCamera.wheelPrecision; this._attachedCamera.wheelPrecision = Infinity; this._attachedCamera.inertialRadiusOffset = 0; // Animate to the radius limit this.stopAllAnimations(); this._radiusIsAnimating = true; var animatable = BABYLON.Animation.TransitionTo("radius", this._attachedCamera.radius + radiusDelta, this._attachedCamera, this._attachedCamera.getScene(), 60, this._radiusBounceTransition, this.transitionDuration, function () { return _this._clearAnimationLocks(); }); if (animatable) { this._animatables.push(animatable); } }; /** * Removes all animation locks. Allows new animations to be added to any of the camera properties. */ BouncingBehavior.prototype._clearAnimationLocks = function () { this._radiusIsAnimating = false; if (this._attachedCamera) { this._attachedCamera.wheelPrecision = this._cachedWheelPrecision; } }; /** * Stops and removes all animations that have been applied to the camera */ BouncingBehavior.prototype.stopAllAnimations = function () { if (this._attachedCamera) { this._attachedCamera.animations = []; } while (this._animatables.length) { this._animatables[0].onAnimationEnd = null; this._animatables[0].stop(); this._animatables.shift(); } }; /** * The easing function used by animations */ BouncingBehavior.EasingFunction = new BABYLON.BackEase(0.3); /** * The easing mode used by animations */ BouncingBehavior.EasingMode = BABYLON.EasingFunction.EASINGMODE_EASEOUT; return BouncingBehavior; }()); BABYLON.BouncingBehavior = BouncingBehavior; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.bouncingBehavior.js.map var BABYLON; (function (BABYLON) { var AutoRotationBehavior = /** @class */ (function () { function AutoRotationBehavior() { this._zoomStopsAnimation = false; this._idleRotationSpeed = 0.05; this._idleRotationWaitTime = 2000; this._idleRotationSpinupTime = 2000; this._isPointerDown = false; this._lastFrameTime = null; this._lastInteractionTime = -Infinity; this._cameraRotationSpeed = 0; this._lastFrameRadius = 0; } Object.defineProperty(AutoRotationBehavior.prototype, "name", { get: function () { return "AutoRotation"; }, enumerable: true, configurable: true }); Object.defineProperty(AutoRotationBehavior.prototype, "zoomStopsAnimation", { /** * Gets the flag that indicates if user zooming should stop animation. */ get: function () { return this._zoomStopsAnimation; }, /** * Sets the flag that indicates if user zooming should stop animation. */ set: function (flag) { this._zoomStopsAnimation = flag; }, enumerable: true, configurable: true }); Object.defineProperty(AutoRotationBehavior.prototype, "idleRotationSpeed", { /** * Gets the default speed at which the camera rotates around the model. */ get: function () { return this._idleRotationSpeed; }, /** * Sets the default speed at which the camera rotates around the model. */ set: function (speed) { this._idleRotationSpeed = speed; }, enumerable: true, configurable: true }); Object.defineProperty(AutoRotationBehavior.prototype, "idleRotationWaitTime", { /** * Gets the time (milliseconds) to wait after user interaction before the camera starts rotating. */ get: function () { return this._idleRotationWaitTime; }, /** * Sets the time (in milliseconds) to wait after user interaction before the camera starts rotating. */ set: function (time) { this._idleRotationWaitTime = time; }, enumerable: true, configurable: true }); Object.defineProperty(AutoRotationBehavior.prototype, "idleRotationSpinupTime", { /** * Gets the time (milliseconds) to take to spin up to the full idle rotation speed. */ get: function () { return this._idleRotationSpinupTime; }, /** * Sets the time (milliseconds) to take to spin up to the full idle rotation speed. */ set: function (time) { this._idleRotationSpinupTime = time; }, enumerable: true, configurable: true }); Object.defineProperty(AutoRotationBehavior.prototype, "rotationInProgress", { /** * Gets a value indicating if the camera is currently rotating because of this behavior */ get: function () { return Math.abs(this._cameraRotationSpeed) > 0; }, enumerable: true, configurable: true }); AutoRotationBehavior.prototype.init = function () { // Do notihng }; AutoRotationBehavior.prototype.attach = function (camera) { var _this = this; this._attachedCamera = camera; var scene = this._attachedCamera.getScene(); this._onPrePointerObservableObserver = scene.onPrePointerObservable.add(function (pointerInfoPre) { if (pointerInfoPre.type === BABYLON.PointerEventTypes.POINTERDOWN) { _this._isPointerDown = true; return; } if (pointerInfoPre.type === BABYLON.PointerEventTypes.POINTERUP) { _this._isPointerDown = false; } }); this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(function () { var now = BABYLON.Tools.Now; var dt = 0; if (_this._lastFrameTime != null) { dt = now - _this._lastFrameTime; } _this._lastFrameTime = now; // Stop the animation if there is user interaction and the animation should stop for this interaction _this._applyUserInteraction(); var timeToRotation = now - _this._lastInteractionTime - _this._idleRotationWaitTime; var scale = Math.max(Math.min(timeToRotation / (_this._idleRotationSpinupTime), 1), 0); _this._cameraRotationSpeed = _this._idleRotationSpeed * scale; // Step camera rotation by rotation speed if (_this._attachedCamera) { _this._attachedCamera.alpha -= _this._cameraRotationSpeed * (dt / 1000); } }); }; AutoRotationBehavior.prototype.detach = function () { if (!this._attachedCamera) { return; } var scene = this._attachedCamera.getScene(); if (this._onPrePointerObservableObserver) { scene.onPrePointerObservable.remove(this._onPrePointerObservableObserver); } this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver); this._attachedCamera = null; }; /** * Returns true if user is scrolling. * @return true if user is scrolling. */ AutoRotationBehavior.prototype._userIsZooming = function () { if (!this._attachedCamera) { return false; } return this._attachedCamera.inertialRadiusOffset !== 0; }; AutoRotationBehavior.prototype._shouldAnimationStopForInteraction = function () { if (!this._attachedCamera) { return false; } var zoomHasHitLimit = false; if (this._lastFrameRadius === this._attachedCamera.radius && this._attachedCamera.inertialRadiusOffset !== 0) { zoomHasHitLimit = true; } // Update the record of previous radius - works as an approx. indicator of hitting radius limits this._lastFrameRadius = this._attachedCamera.radius; return this._zoomStopsAnimation ? zoomHasHitLimit : this._userIsZooming(); }; /** * Applies any current user interaction to the camera. Takes into account maximum alpha rotation. */ AutoRotationBehavior.prototype._applyUserInteraction = function () { if (this._userIsMoving() && !this._shouldAnimationStopForInteraction()) { this._lastInteractionTime = BABYLON.Tools.Now; } }; // Tools AutoRotationBehavior.prototype._userIsMoving = function () { if (!this._attachedCamera) { return false; } return this._attachedCamera.inertialAlphaOffset !== 0 || this._attachedCamera.inertialBetaOffset !== 0 || this._attachedCamera.inertialRadiusOffset !== 0 || this._attachedCamera.inertialPanningX !== 0 || this._attachedCamera.inertialPanningY !== 0 || this._isPointerDown; }; return AutoRotationBehavior; }()); BABYLON.AutoRotationBehavior = AutoRotationBehavior; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.autoRotationBehavior.js.map var BABYLON; (function (BABYLON) { var NullEngineOptions = /** @class */ (function () { function NullEngineOptions() { this.renderWidth = 512; this.renderHeight = 256; this.textureSize = 512; this.deterministicLockstep = false; this.lockstepMaxSteps = 4; } return NullEngineOptions; }()); BABYLON.NullEngineOptions = NullEngineOptions; /** * The null engine class provides support for headless version of babylon.js. * This can be used in server side scenario or for testing purposes */ var NullEngine = /** @class */ (function (_super) { __extends(NullEngine, _super); function NullEngine(options) { if (options === void 0) { options = new NullEngineOptions(); } var _this = _super.call(this, null) || this; if (options.deterministicLockstep === undefined) { options.deterministicLockstep = false; } if (options.lockstepMaxSteps === undefined) { options.lockstepMaxSteps = 4; } _this._options = options; // Init caps // We consider we are on a webgl1 capable device _this._caps = new BABYLON.EngineCapabilities(); _this._caps.maxTexturesImageUnits = 16; _this._caps.maxVertexTextureImageUnits = 16; _this._caps.maxTextureSize = 512; _this._caps.maxCubemapTextureSize = 512; _this._caps.maxRenderTextureSize = 512; _this._caps.maxVertexAttribs = 16; _this._caps.maxVaryingVectors = 16; _this._caps.maxFragmentUniformVectors = 16; _this._caps.maxVertexUniformVectors = 16; // Extensions _this._caps.standardDerivatives = false; _this._caps.astc = null; _this._caps.s3tc = null; _this._caps.pvrtc = null; _this._caps.etc1 = null; _this._caps.etc2 = null; _this._caps.textureAnisotropicFilterExtension = null; _this._caps.maxAnisotropy = 0; _this._caps.uintIndices = false; _this._caps.fragmentDepthSupported = false; _this._caps.highPrecisionShaderSupported = true; _this._caps.colorBufferFloat = false; _this._caps.textureFloat = false; _this._caps.textureFloatLinearFiltering = false; _this._caps.textureFloatRender = false; _this._caps.textureHalfFloat = false; _this._caps.textureHalfFloatLinearFiltering = false; _this._caps.textureHalfFloatRender = false; _this._caps.textureLOD = false; _this._caps.drawBuffersExtension = false; _this._caps.depthTextureExtension = false; _this._caps.vertexArrayObject = false; _this._caps.instancedArrays = false; BABYLON.Tools.Log("Babylon.js null engine (v" + BABYLON.Engine.Version + ") launched"); // Wrappers if (typeof URL === "undefined") { URL = { createObjectURL: function () { }, revokeObjectURL: function () { } }; } if (typeof Blob === "undefined") { Blob = function () { }; } return _this; } NullEngine.prototype.isDeterministicLockStep = function () { return this._options.deterministicLockstep; }; NullEngine.prototype.getLockstepMaxSteps = function () { return this._options.lockstepMaxSteps; }; NullEngine.prototype.getHardwareScalingLevel = function () { return 1.0; }; NullEngine.prototype.createVertexBuffer = function (vertices) { return { capacity: 0, references: 1, is32Bits: false }; }; NullEngine.prototype.createIndexBuffer = function (indices) { return { capacity: 0, references: 1, is32Bits: false }; }; NullEngine.prototype.clear = function (color, backBuffer, depth, stencil) { if (stencil === void 0) { stencil = false; } }; NullEngine.prototype.getRenderWidth = function (useScreen) { if (useScreen === void 0) { useScreen = false; } if (!useScreen && this._currentRenderTarget) { return this._currentRenderTarget.width; } return this._options.renderWidth; }; NullEngine.prototype.getRenderHeight = function (useScreen) { if (useScreen === void 0) { useScreen = false; } if (!useScreen && this._currentRenderTarget) { return this._currentRenderTarget.height; } return this._options.renderHeight; }; NullEngine.prototype.setViewport = function (viewport, requiredWidth, requiredHeight) { this._cachedViewport = viewport; }; NullEngine.prototype.createShaderProgram = function (vertexCode, fragmentCode, defines, context) { return { transformFeedback: null, __SPECTOR_rebuildProgram: null }; }; NullEngine.prototype.getUniforms = function (shaderProgram, uniformsNames) { return []; }; NullEngine.prototype.getAttributes = function (shaderProgram, attributesNames) { return []; }; NullEngine.prototype.bindSamplers = function (effect) { this._currentEffect = null; }; NullEngine.prototype.enableEffect = function (effect) { this._currentEffect = effect; if (effect.onBind) { effect.onBind(effect); } effect.onBindObservable.notifyObservers(effect); }; NullEngine.prototype.setState = function (culling, zOffset, force, reverseSide) { if (zOffset === void 0) { zOffset = 0; } if (reverseSide === void 0) { reverseSide = false; } }; NullEngine.prototype.setIntArray = function (uniform, array) { }; NullEngine.prototype.setIntArray2 = function (uniform, array) { }; NullEngine.prototype.setIntArray3 = function (uniform, array) { }; NullEngine.prototype.setIntArray4 = function (uniform, array) { }; NullEngine.prototype.setFloatArray = function (uniform, array) { }; NullEngine.prototype.setFloatArray2 = function (uniform, array) { }; NullEngine.prototype.setFloatArray3 = function (uniform, array) { }; NullEngine.prototype.setFloatArray4 = function (uniform, array) { }; NullEngine.prototype.setArray = function (uniform, array) { }; NullEngine.prototype.setArray2 = function (uniform, array) { }; NullEngine.prototype.setArray3 = function (uniform, array) { }; NullEngine.prototype.setArray4 = function (uniform, array) { }; NullEngine.prototype.setMatrices = function (uniform, matrices) { }; NullEngine.prototype.setMatrix = function (uniform, matrix) { }; NullEngine.prototype.setMatrix3x3 = function (uniform, matrix) { }; NullEngine.prototype.setMatrix2x2 = function (uniform, matrix) { }; NullEngine.prototype.setFloat = function (uniform, value) { }; NullEngine.prototype.setFloat2 = function (uniform, x, y) { }; NullEngine.prototype.setFloat3 = function (uniform, x, y, z) { }; NullEngine.prototype.setBool = function (uniform, bool) { }; NullEngine.prototype.setFloat4 = function (uniform, x, y, z, w) { }; NullEngine.prototype.setColor3 = function (uniform, color3) { }; NullEngine.prototype.setColor4 = function (uniform, color3, alpha) { }; NullEngine.prototype.setAlphaMode = function (mode, noDepthWriteChange) { if (noDepthWriteChange === void 0) { noDepthWriteChange = false; } if (this._alphaMode === mode) { return; } this._alphaState.alphaBlend = (mode !== BABYLON.Engine.ALPHA_DISABLE); if (!noDepthWriteChange) { this.setDepthWrite(mode === BABYLON.Engine.ALPHA_DISABLE); } this._alphaMode = mode; }; NullEngine.prototype.bindBuffers = function (vertexBuffers, indexBuffer, effect) { }; NullEngine.prototype.wipeCaches = function (bruteForce) { if (this.preventCacheWipeBetweenFrames) { return; } this.resetTextureCache(); this._currentEffect = null; if (bruteForce) { this._currentProgram = null; this._stencilState.reset(); this._depthCullingState.reset(); this._alphaState.reset(); } this._cachedVertexBuffers = null; this._cachedIndexBuffer = null; this._cachedEffectForVertexBuffers = null; }; NullEngine.prototype.draw = function (useTriangles, indexStart, indexCount, instancesCount) { }; NullEngine.prototype.drawElementsType = function (fillMode, indexStart, indexCount, instancesCount) { }; NullEngine.prototype.drawArraysType = function (fillMode, verticesStart, verticesCount, instancesCount) { }; NullEngine.prototype._createTexture = function () { return {}; }; NullEngine.prototype._releaseTexture = function (texture) { }; NullEngine.prototype.createTexture = function (urlArg, noMipmap, invertY, scene, samplingMode, onLoad, onError, buffer, fallBack, format) { if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; } if (onLoad === void 0) { onLoad = null; } if (onError === void 0) { onError = null; } if (buffer === void 0) { buffer = null; } var texture = new BABYLON.InternalTexture(this, BABYLON.InternalTexture.DATASOURCE_URL); var url = String(urlArg); texture.url = url; texture.generateMipMaps = !noMipmap; texture.samplingMode = samplingMode; texture.invertY = invertY; texture.baseWidth = this._options.textureSize; texture.baseHeight = this._options.textureSize; texture.width = this._options.textureSize; texture.height = this._options.textureSize; if (format) { texture.format = format; } texture.isReady = true; if (onLoad) { onLoad(); } return texture; }; NullEngine.prototype.createRenderTargetTexture = function (size, options) { var fullOptions = new BABYLON.RenderTargetCreationOptions(); if (options !== undefined && typeof options === "object") { fullOptions.generateMipMaps = options.generateMipMaps; fullOptions.generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer; fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer; fullOptions.type = options.type === undefined ? BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT : options.type; fullOptions.samplingMode = options.samplingMode === undefined ? BABYLON.Texture.TRILINEAR_SAMPLINGMODE : options.samplingMode; } else { fullOptions.generateMipMaps = options; fullOptions.generateDepthBuffer = true; fullOptions.generateStencilBuffer = false; fullOptions.type = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; fullOptions.samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; } var texture = new BABYLON.InternalTexture(this, BABYLON.InternalTexture.DATASOURCE_RENDERTARGET); var width = size.width || size; var height = size.height || size; texture._depthStencilBuffer = {}; texture._framebuffer = {}; texture.baseWidth = width; texture.baseHeight = height; texture.width = width; texture.height = height; texture.isReady = true; texture.samples = 1; texture.generateMipMaps = fullOptions.generateMipMaps ? true : false; texture.samplingMode = fullOptions.samplingMode; texture.type = fullOptions.type; texture._generateDepthBuffer = fullOptions.generateDepthBuffer; texture._generateStencilBuffer = fullOptions.generateStencilBuffer ? true : false; return texture; }; NullEngine.prototype.updateTextureSamplingMode = function (samplingMode, texture) { texture.samplingMode = samplingMode; }; NullEngine.prototype.bindFramebuffer = function (texture, faceIndex, requiredWidth, requiredHeight, forceFullscreenViewport) { if (this._currentRenderTarget) { this.unBindFramebuffer(this._currentRenderTarget); } this._currentRenderTarget = texture; this._currentFramebuffer = texture._MSAAFramebuffer ? texture._MSAAFramebuffer : texture._framebuffer; if (this._cachedViewport && !forceFullscreenViewport) { this.setViewport(this._cachedViewport, requiredWidth, requiredHeight); } }; NullEngine.prototype.unBindFramebuffer = function (texture, disableGenerateMipMaps, onBeforeUnbind) { if (disableGenerateMipMaps === void 0) { disableGenerateMipMaps = false; } this._currentRenderTarget = null; if (onBeforeUnbind) { if (texture._MSAAFramebuffer) { this._currentFramebuffer = texture._framebuffer; } onBeforeUnbind(); } this._currentFramebuffer = null; }; NullEngine.prototype.createDynamicVertexBuffer = function (vertices) { var vbo = { capacity: 1, references: 1, is32Bits: false }; return vbo; }; NullEngine.prototype.updateDynamicIndexBuffer = function (indexBuffer, indices, offset) { if (offset === void 0) { offset = 0; } }; /** * Updates a dynamic vertex buffer. * @param vertexBuffer the vertex buffer to update * @param data the data used to update the vertex buffer * @param byteOffset the byte offset of the data (optional) * @param byteLength the byte length of the data (optional) */ NullEngine.prototype.updateDynamicVertexBuffer = function (vertexBuffer, vertices, byteOffset, byteLength) { }; NullEngine.prototype._bindTextureDirectly = function (target, texture) { if (this._boundTexturesCache[this._activeChannel] !== texture) { this._boundTexturesCache[this._activeChannel] = texture; } }; NullEngine.prototype._bindTexture = function (channel, texture) { if (channel < 0) { return; } this._bindTextureDirectly(0, texture); }; NullEngine.prototype._releaseBuffer = function (buffer) { buffer.references--; if (buffer.references === 0) { return true; } return false; }; return NullEngine; }(BABYLON.Engine)); BABYLON.NullEngine = NullEngine; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.nullEngine.js.map var BABYLON; (function (BABYLON) { /** * This class can be used to get instrumentation data from a Babylon engine */ var EngineInstrumentation = /** @class */ (function () { function EngineInstrumentation(engine) { this.engine = engine; this._captureGPUFrameTime = false; this._gpuFrameTime = new BABYLON.PerfCounter(); this._captureShaderCompilationTime = false; this._shaderCompilationTime = new BABYLON.PerfCounter(); // Observers this._onBeginFrameObserver = null; this._onEndFrameObserver = null; this._onBeforeShaderCompilationObserver = null; this._onAfterShaderCompilationObserver = null; } Object.defineProperty(EngineInstrumentation.prototype, "gpuFrameTimeCounter", { // Properties /** * Gets the perf counter used for GPU frame time */ get: function () { return this._gpuFrameTime; }, enumerable: true, configurable: true }); Object.defineProperty(EngineInstrumentation.prototype, "captureGPUFrameTime", { /** * Gets the GPU frame time capture status */ get: function () { return this._captureGPUFrameTime; }, /** * Enable or disable the GPU frame time capture */ set: function (value) { var _this = this; if (value === this._captureGPUFrameTime) { return; } this._captureGPUFrameTime = value; if (value) { this._onBeginFrameObserver = this.engine.onBeginFrameObservable.add(function () { if (!_this._gpuFrameTimeToken) { _this._gpuFrameTimeToken = _this.engine.startTimeQuery(); } }); this._onEndFrameObserver = this.engine.onEndFrameObservable.add(function () { if (!_this._gpuFrameTimeToken) { return; } var time = _this.engine.endTimeQuery(_this._gpuFrameTimeToken); if (time > -1) { _this._gpuFrameTimeToken = null; _this._gpuFrameTime.fetchNewFrame(); _this._gpuFrameTime.addCount(time, true); } }); } else { this.engine.onBeginFrameObservable.remove(this._onBeginFrameObserver); this._onBeginFrameObserver = null; this.engine.onEndFrameObservable.remove(this._onEndFrameObserver); this._onEndFrameObserver = null; } }, enumerable: true, configurable: true }); Object.defineProperty(EngineInstrumentation.prototype, "shaderCompilationTimeCounter", { /** * Gets the perf counter used for shader compilation time */ get: function () { return this._shaderCompilationTime; }, enumerable: true, configurable: true }); Object.defineProperty(EngineInstrumentation.prototype, "captureShaderCompilationTime", { /** * Gets the shader compilation time capture status */ get: function () { return this._captureShaderCompilationTime; }, /** * Enable or disable the shader compilation time capture */ set: function (value) { var _this = this; if (value === this._captureShaderCompilationTime) { return; } this._captureShaderCompilationTime = value; if (value) { this._onBeforeShaderCompilationObserver = this.engine.onBeforeShaderCompilationObservable.add(function () { _this._shaderCompilationTime.fetchNewFrame(); _this._shaderCompilationTime.beginMonitoring(); }); this._onAfterShaderCompilationObserver = this.engine.onAfterShaderCompilationObservable.add(function () { _this._shaderCompilationTime.endMonitoring(); }); } else { this.engine.onBeforeShaderCompilationObservable.remove(this._onBeforeShaderCompilationObserver); this._onBeforeShaderCompilationObserver = null; this.engine.onAfterShaderCompilationObservable.remove(this._onAfterShaderCompilationObserver); this._onAfterShaderCompilationObserver = null; } }, enumerable: true, configurable: true }); EngineInstrumentation.prototype.dispose = function () { this.engine.onBeginFrameObservable.remove(this._onBeginFrameObserver); this._onBeginFrameObserver = null; this.engine.onEndFrameObservable.remove(this._onEndFrameObserver); this._onEndFrameObserver = null; this.engine.onBeforeShaderCompilationObservable.remove(this._onBeforeShaderCompilationObserver); this._onBeforeShaderCompilationObserver = null; this.engine.onAfterShaderCompilationObservable.remove(this._onAfterShaderCompilationObserver); this._onAfterShaderCompilationObserver = null; this.engine = null; }; return EngineInstrumentation; }()); BABYLON.EngineInstrumentation = EngineInstrumentation; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.engineInstrumentation.js.map var BABYLON; (function (BABYLON) { /** * This class can be used to get instrumentation data from a Babylon engine */ var SceneInstrumentation = /** @class */ (function () { function SceneInstrumentation(scene) { var _this = this; this.scene = scene; this._captureActiveMeshesEvaluationTime = false; this._activeMeshesEvaluationTime = new BABYLON.PerfCounter(); this._captureRenderTargetsRenderTime = false; this._renderTargetsRenderTime = new BABYLON.PerfCounter(); this._captureFrameTime = false; this._frameTime = new BABYLON.PerfCounter(); this._captureRenderTime = false; this._renderTime = new BABYLON.PerfCounter(); this._captureInterFrameTime = false; this._interFrameTime = new BABYLON.PerfCounter(); this._captureParticlesRenderTime = false; this._particlesRenderTime = new BABYLON.PerfCounter(); this._captureSpritesRenderTime = false; this._spritesRenderTime = new BABYLON.PerfCounter(); this._capturePhysicsTime = false; this._physicsTime = new BABYLON.PerfCounter(); this._captureAnimationsTime = false; this._animationsTime = new BABYLON.PerfCounter(); // Observers this._onBeforeActiveMeshesEvaluationObserver = null; this._onAfterActiveMeshesEvaluationObserver = null; this._onBeforeRenderTargetsRenderObserver = null; this._onAfterRenderTargetsRenderObserver = null; this._onAfterRenderObserver = null; this._onBeforeDrawPhaseObserver = null; this._onAfterDrawPhaseObserver = null; this._onBeforeAnimationsObserver = null; this._onBeforeParticlesRenderingObserver = null; this._onAfterParticlesRenderingObserver = null; this._onBeforeSpritesRenderingObserver = null; this._onAfterSpritesRenderingObserver = null; this._onBeforePhysicsObserver = null; this._onAfterPhysicsObserver = null; this._onAfterAnimationsObserver = null; // Before render this._onBeforeAnimationsObserver = scene.onBeforeAnimationsObservable.add(function () { if (_this._captureActiveMeshesEvaluationTime) { _this._activeMeshesEvaluationTime.fetchNewFrame(); } if (_this._captureRenderTargetsRenderTime) { _this._renderTargetsRenderTime.fetchNewFrame(); } if (_this._captureFrameTime) { BABYLON.Tools.StartPerformanceCounter("Scene rendering"); _this._frameTime.beginMonitoring(); } if (_this._captureInterFrameTime) { _this._interFrameTime.endMonitoring(); } if (_this._captureParticlesRenderTime) { _this._particlesRenderTime.fetchNewFrame(); } if (_this._captureSpritesRenderTime) { _this._spritesRenderTime.fetchNewFrame(); } if (_this._captureAnimationsTime) { _this._animationsTime.beginMonitoring(); } _this.scene.getEngine()._drawCalls.fetchNewFrame(); _this.scene.getEngine()._textureCollisions.fetchNewFrame(); }); // After render this._onAfterRenderObserver = scene.onAfterRenderObservable.add(function () { if (_this._captureFrameTime) { BABYLON.Tools.EndPerformanceCounter("Scene rendering"); _this._frameTime.endMonitoring(); } if (_this._captureRenderTime) { _this._renderTime.endMonitoring(false); } if (_this._captureInterFrameTime) { _this._interFrameTime.beginMonitoring(); } }); } Object.defineProperty(SceneInstrumentation.prototype, "activeMeshesEvaluationTimeCounter", { // Properties /** * Gets the perf counter used for active meshes evaluation time */ get: function () { return this._activeMeshesEvaluationTime; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "captureActiveMeshesEvaluationTime", { /** * Gets the active meshes evaluation time capture status */ get: function () { return this._captureActiveMeshesEvaluationTime; }, /** * Enable or disable the active meshes evaluation time capture */ set: function (value) { var _this = this; if (value === this._captureActiveMeshesEvaluationTime) { return; } this._captureActiveMeshesEvaluationTime = value; if (value) { this._onBeforeActiveMeshesEvaluationObserver = this.scene.onBeforeActiveMeshesEvaluationObservable.add(function () { BABYLON.Tools.StartPerformanceCounter("Active meshes evaluation"); _this._activeMeshesEvaluationTime.beginMonitoring(); }); this._onAfterActiveMeshesEvaluationObserver = this.scene.onAfterActiveMeshesEvaluationObservable.add(function () { BABYLON.Tools.EndPerformanceCounter("Active meshes evaluation"); _this._activeMeshesEvaluationTime.endMonitoring(); }); } else { this.scene.onBeforeActiveMeshesEvaluationObservable.remove(this._onBeforeActiveMeshesEvaluationObserver); this._onBeforeActiveMeshesEvaluationObserver = null; this.scene.onAfterActiveMeshesEvaluationObservable.remove(this._onAfterActiveMeshesEvaluationObserver); this._onAfterActiveMeshesEvaluationObserver = null; } }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "renderTargetsRenderTimeCounter", { /** * Gets the perf counter used for render targets render time */ get: function () { return this._renderTargetsRenderTime; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "captureRenderTargetsRenderTime", { /** * Gets the render targets render time capture status */ get: function () { return this._captureRenderTargetsRenderTime; }, /** * Enable or disable the render targets render time capture */ set: function (value) { var _this = this; if (value === this._captureRenderTargetsRenderTime) { return; } this._captureRenderTargetsRenderTime = value; if (value) { this._onBeforeRenderTargetsRenderObserver = this.scene.onBeforeRenderTargetsRenderObservable.add(function () { BABYLON.Tools.StartPerformanceCounter("Render targets rendering"); _this._renderTargetsRenderTime.beginMonitoring(); }); this._onAfterRenderTargetsRenderObserver = this.scene.onAfterRenderTargetsRenderObservable.add(function () { BABYLON.Tools.EndPerformanceCounter("Render targets rendering"); _this._renderTargetsRenderTime.endMonitoring(false); }); } else { this.scene.onBeforeRenderTargetsRenderObservable.remove(this._onBeforeRenderTargetsRenderObserver); this._onBeforeRenderTargetsRenderObserver = null; this.scene.onAfterRenderTargetsRenderObservable.remove(this._onAfterRenderTargetsRenderObserver); this._onAfterRenderTargetsRenderObserver = null; } }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "particlesRenderTimeCounter", { /** * Gets the perf counter used for particles render time */ get: function () { return this._particlesRenderTime; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "captureParticlesRenderTime", { /** * Gets the particles render time capture status */ get: function () { return this._captureParticlesRenderTime; }, /** * Enable or disable the particles render time capture */ set: function (value) { var _this = this; if (value === this._captureParticlesRenderTime) { return; } this._captureParticlesRenderTime = value; if (value) { this._onBeforeParticlesRenderingObserver = this.scene.onBeforeParticlesRenderingObservable.add(function () { BABYLON.Tools.StartPerformanceCounter("Particles"); _this._particlesRenderTime.beginMonitoring(); }); this._onAfterParticlesRenderingObserver = this.scene.onAfterParticlesRenderingObservable.add(function () { BABYLON.Tools.EndPerformanceCounter("Particles"); _this._particlesRenderTime.endMonitoring(false); }); } else { this.scene.onBeforeParticlesRenderingObservable.remove(this._onBeforeParticlesRenderingObserver); this._onBeforeParticlesRenderingObserver = null; this.scene.onAfterParticlesRenderingObservable.remove(this._onAfterParticlesRenderingObserver); this._onAfterParticlesRenderingObserver = null; } }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "spritesRenderTimeCounter", { /** * Gets the perf counter used for sprites render time */ get: function () { return this._spritesRenderTime; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "captureSpritesRenderTime", { /** * Gets the sprites render time capture status */ get: function () { return this._captureSpritesRenderTime; }, /** * Enable or disable the sprites render time capture */ set: function (value) { var _this = this; if (value === this._captureSpritesRenderTime) { return; } this._captureSpritesRenderTime = value; if (value) { this._onBeforeSpritesRenderingObserver = this.scene.onBeforeSpritesRenderingObservable.add(function () { BABYLON.Tools.StartPerformanceCounter("Sprites"); _this._spritesRenderTime.beginMonitoring(); }); this._onAfterSpritesRenderingObserver = this.scene.onAfterSpritesRenderingObservable.add(function () { BABYLON.Tools.EndPerformanceCounter("Sprites"); _this._spritesRenderTime.endMonitoring(false); }); } else { this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver); this._onBeforeSpritesRenderingObserver = null; this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver); this._onAfterSpritesRenderingObserver = null; } }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "physicsTimeCounter", { /** * Gets the perf counter used for physics time */ get: function () { return this._physicsTime; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "capturePhysicsTime", { /** * Gets the physics time capture status */ get: function () { return this._capturePhysicsTime; }, /** * Enable or disable the physics time capture */ set: function (value) { var _this = this; if (value === this._capturePhysicsTime) { return; } this._capturePhysicsTime = value; if (value) { this._onBeforePhysicsObserver = this.scene.onBeforePhysicsObservable.add(function () { BABYLON.Tools.StartPerformanceCounter("Physics"); _this._physicsTime.beginMonitoring(); }); this._onAfterPhysicsObserver = this.scene.onAfterPhysicsObservable.add(function () { BABYLON.Tools.EndPerformanceCounter("Physics"); _this._physicsTime.endMonitoring(); }); } else { this.scene.onBeforePhysicsObservable.remove(this._onBeforePhysicsObserver); this._onBeforePhysicsObserver = null; this.scene.onAfterPhysicsObservable.remove(this._onAfterPhysicsObserver); this._onAfterPhysicsObserver = null; } }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "animationsTimeCounter", { /** * Gets the perf counter used for animations time */ get: function () { return this._animationsTime; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "captureAnimationsTime", { /** * Gets the animations time capture status */ get: function () { return this._captureAnimationsTime; }, /** * Enable or disable the animations time capture */ set: function (value) { var _this = this; if (value === this._captureAnimationsTime) { return; } this._captureAnimationsTime = value; if (value) { this._onAfterAnimationsObserver = this.scene.onAfterAnimationsObservable.add(function () { _this._animationsTime.endMonitoring(); }); } else { this.scene.onAfterAnimationsObservable.remove(this._onAfterAnimationsObserver); this._onAfterAnimationsObserver = null; } }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "frameTimeCounter", { /** * Gets the perf counter used for frame time capture */ get: function () { return this._frameTime; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "captureFrameTime", { /** * Gets the frame time capture status */ get: function () { return this._captureFrameTime; }, /** * Enable or disable the frame time capture */ set: function (value) { this._captureFrameTime = value; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "interFrameTimeCounter", { /** * Gets the perf counter used for inter-frames time capture */ get: function () { return this._interFrameTime; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "captureInterFrameTime", { /** * Gets the inter-frames time capture status */ get: function () { return this._captureInterFrameTime; }, /** * Enable or disable the inter-frames time capture */ set: function (value) { this._captureInterFrameTime = value; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "renderTimeCounter", { /** * Gets the perf counter used for render time capture */ get: function () { return this._renderTime; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "captureRenderTime", { /** * Gets the render time capture status */ get: function () { return this._captureRenderTime; }, /** * Enable or disable the render time capture */ set: function (value) { var _this = this; if (value === this._captureRenderTime) { return; } this._captureRenderTime = value; if (value) { this._onBeforeDrawPhaseObserver = this.scene.onBeforeDrawPhaseObservable.add(function () { _this._renderTime.beginMonitoring(); BABYLON.Tools.StartPerformanceCounter("Main render"); }); this._onAfterDrawPhaseObserver = this.scene.onAfterDrawPhaseObservable.add(function () { _this._renderTime.endMonitoring(false); BABYLON.Tools.EndPerformanceCounter("Main render"); }); } else { this.scene.onBeforeDrawPhaseObservable.remove(this._onBeforeDrawPhaseObserver); this._onBeforeDrawPhaseObserver = null; this.scene.onAfterDrawPhaseObservable.remove(this._onAfterDrawPhaseObserver); this._onAfterDrawPhaseObserver = null; } }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "drawCallsCounter", { /** * Gets the perf counter used for draw calls */ get: function () { return this.scene.getEngine()._drawCalls; }, enumerable: true, configurable: true }); Object.defineProperty(SceneInstrumentation.prototype, "textureCollisionsCounter", { /** * Gets the perf counter used for texture collisions */ get: function () { return this.scene.getEngine()._textureCollisions; }, enumerable: true, configurable: true }); SceneInstrumentation.prototype.dispose = function () { this.scene.onAfterRenderObservable.remove(this._onAfterRenderObserver); this._onAfterRenderObserver = null; this.scene.onBeforeActiveMeshesEvaluationObservable.remove(this._onBeforeActiveMeshesEvaluationObserver); this._onBeforeActiveMeshesEvaluationObserver = null; this.scene.onAfterActiveMeshesEvaluationObservable.remove(this._onAfterActiveMeshesEvaluationObserver); this._onAfterActiveMeshesEvaluationObserver = null; this.scene.onBeforeRenderTargetsRenderObservable.remove(this._onBeforeRenderTargetsRenderObserver); this._onBeforeRenderTargetsRenderObserver = null; this.scene.onAfterRenderTargetsRenderObservable.remove(this._onAfterRenderTargetsRenderObserver); this._onAfterRenderTargetsRenderObserver = null; this.scene.onBeforeAnimationsObservable.remove(this._onBeforeAnimationsObserver); this._onBeforeAnimationsObserver = null; this.scene.onBeforeParticlesRenderingObservable.remove(this._onBeforeParticlesRenderingObserver); this._onBeforeParticlesRenderingObserver = null; this.scene.onAfterParticlesRenderingObservable.remove(this._onAfterParticlesRenderingObserver); this._onAfterParticlesRenderingObserver = null; this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver); this._onBeforeSpritesRenderingObserver = null; this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver); this._onAfterSpritesRenderingObserver = null; this.scene.onBeforeDrawPhaseObservable.remove(this._onBeforeDrawPhaseObserver); this._onBeforeDrawPhaseObserver = null; this.scene.onAfterDrawPhaseObservable.remove(this._onAfterDrawPhaseObserver); this._onAfterDrawPhaseObserver = null; this.scene.onBeforePhysicsObservable.remove(this._onBeforePhysicsObserver); this._onBeforePhysicsObserver = null; this.scene.onAfterPhysicsObservable.remove(this._onAfterPhysicsObserver); this._onAfterPhysicsObserver = null; this.scene.onAfterAnimationsObservable.remove(this._onAfterAnimationsObserver); this._onAfterAnimationsObserver = null; this.scene = null; }; return SceneInstrumentation; }()); BABYLON.SceneInstrumentation = SceneInstrumentation; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.sceneInstrumentation.js.map var BABYLON; (function (BABYLON) { var _TimeToken = /** @class */ (function () { function _TimeToken() { this._timeElapsedQueryEnded = false; } return _TimeToken; }()); BABYLON._TimeToken = _TimeToken; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.timeToken.js.map var BABYLON; (function (BABYLON) { /** * Background material defines definition. * @ignore Mainly internal Use */ var BackgroundMaterialDefines = /** @class */ (function (_super) { __extends(BackgroundMaterialDefines, _super); /** * Constructor of the defines. */ function BackgroundMaterialDefines() { var _this = _super.call(this) || this; /** * True if the diffuse texture is in use. */ _this.DIFFUSE = false; /** * The direct UV channel to use. */ _this.DIFFUSEDIRECTUV = 0; /** * True if the diffuse texture is in gamma space. */ _this.GAMMADIFFUSE = false; /** * True if the diffuse texture has opacity in the alpha channel. */ _this.DIFFUSEHASALPHA = false; /** * True if you want the material to fade to transparent at grazing angle. */ _this.OPACITYFRESNEL = false; /** * True if an extra blur needs to be added in the reflection. */ _this.REFLECTIONBLUR = false; /** * True if you want the material to fade to reflection at grazing angle. */ _this.REFLECTIONFRESNEL = false; /** * True if you want the material to falloff as far as you move away from the scene center. */ _this.REFLECTIONFALLOFF = false; /** * False if the current Webgl implementation does not support the texture lod extension. */ _this.TEXTURELODSUPPORT = false; /** * True to ensure the data are premultiplied. */ _this.PREMULTIPLYALPHA = false; /** * True if the texture contains cooked RGB values and not gray scaled multipliers. */ _this.USERGBCOLOR = false; /** * True if highlight and shadow levels have been specified. It can help ensuring the main perceived color * stays aligned with the desired configuration. */ _this.USEHIGHLIGHTANDSHADOWCOLORS = false; /** * True to add noise in order to reduce the banding effect. */ _this.NOISE = false; /** * is the reflection texture in BGR color scheme? * Mainly used to solve a bug in ios10 video tag */ _this.REFLECTIONBGR = false; _this.IMAGEPROCESSING = false; _this.VIGNETTE = false; _this.VIGNETTEBLENDMODEMULTIPLY = false; _this.VIGNETTEBLENDMODEOPAQUE = false; _this.TONEMAPPING = false; _this.CONTRAST = false; _this.COLORCURVES = false; _this.COLORGRADING = false; _this.COLORGRADING3D = false; _this.SAMPLER3DGREENDEPTH = false; _this.SAMPLER3DBGRMAP = false; _this.IMAGEPROCESSINGPOSTPROCESS = false; _this.EXPOSURE = false; // Reflection. _this.REFLECTION = false; _this.REFLECTIONMAP_3D = false; _this.REFLECTIONMAP_SPHERICAL = false; _this.REFLECTIONMAP_PLANAR = false; _this.REFLECTIONMAP_CUBIC = false; _this.REFLECTIONMAP_PROJECTION = false; _this.REFLECTIONMAP_SKYBOX = false; _this.REFLECTIONMAP_EXPLICIT = false; _this.REFLECTIONMAP_EQUIRECTANGULAR = false; _this.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false; _this.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false; _this.INVERTCUBICMAP = false; _this.REFLECTIONMAP_OPPOSITEZ = false; _this.LODINREFLECTIONALPHA = false; _this.GAMMAREFLECTION = false; _this.EQUIRECTANGULAR_RELFECTION_FOV = false; // Default BJS. _this.MAINUV1 = false; _this.MAINUV2 = false; _this.UV1 = false; _this.UV2 = false; _this.CLIPPLANE = false; _this.POINTSIZE = false; _this.FOG = false; _this.NORMAL = false; _this.NUM_BONE_INFLUENCERS = 0; _this.BonesPerMesh = 0; _this.INSTANCES = false; _this.SHADOWFLOAT = false; _this.rebuild(); return _this; } return BackgroundMaterialDefines; }(BABYLON.MaterialDefines)); /** * Background material used to create an efficient environement around your scene. */ var BackgroundMaterial = /** @class */ (function (_super) { __extends(BackgroundMaterial, _super); /** * Instantiates a Background Material in the given scene * @param name The friendly name of the material * @param scene The scene to add the material to */ function BackgroundMaterial(name, scene) { var _this = _super.call(this, name, scene) || this; /** * Key light Color (multiply against the environement texture) */ _this.primaryColor = BABYLON.Color3.White(); _this._primaryColorShadowLevel = 0; _this._primaryColorHighlightLevel = 0; /** * Reflection Texture used in the material. * Should be author in a specific way for the best result (refer to the documentation). */ _this.reflectionTexture = null; /** * Reflection Texture level of blur. * * Can be use to reuse an existing HDR Texture and target a specific LOD to prevent authoring the * texture twice. */ _this.reflectionBlur = 0; /** * Diffuse Texture used in the material. * Should be author in a specific way for the best result (refer to the documentation). */ _this.diffuseTexture = null; _this._shadowLights = null; /** * Specify the list of lights casting shadow on the material. * All scene shadow lights will be included if null. */ _this.shadowLights = null; /** * Helps adjusting the shadow to a softer level if required. * 0 means black shadows and 1 means no shadows. */ _this.shadowLevel = 0; /** * In case of opacity Fresnel or reflection falloff, this is use as a scene center. * It is usually zero but might be interesting to modify according to your setup. */ _this.sceneCenter = BABYLON.Vector3.Zero(); /** * This helps specifying that the material is falling off to the sky box at grazing angle. * This helps ensuring a nice transition when the camera goes under the ground. */ _this.opacityFresnel = true; /** * This helps specifying that the material is falling off from diffuse to the reflection texture at grazing angle. * This helps adding a mirror texture on the ground. */ _this.reflectionFresnel = false; /** * This helps specifying the falloff radius off the reflection texture from the sceneCenter. * This helps adding a nice falloff effect to the reflection if used as a mirror for instance. */ _this.reflectionFalloffDistance = 0.0; /** * This specifies the weight of the reflection against the background in case of reflection Fresnel. */ _this.reflectionAmount = 1.0; /** * This specifies the weight of the reflection at grazing angle. */ _this.reflectionReflectance0 = 0.05; /** * This specifies the weight of the reflection at a perpendicular point of view. */ _this.reflectionReflectance90 = 0.5; /** * Helps to directly use the maps channels instead of their level. */ _this.useRGBColor = true; /** * This helps reducing the banding effect that could occur on the background. */ _this.enableNoise = false; _this._fovMultiplier = 1.0; /** * Enable the FOV adjustment feature controlled by fovMultiplier. */ _this.useEquirectangularFOV = false; _this._maxSimultaneousLights = 4; /** * Number of Simultaneous lights allowed on the material. */ _this.maxSimultaneousLights = 4; /** * Keep track of the image processing observer to allow dispose and replace. */ _this._imageProcessingObserver = null; /** * Due to a bug in iOS10, video tags (which are using the background material) are in BGR and not RGB. * Setting this flag to true (not done automatically!) will convert it back to RGB. */ _this.switchToBGR = false; // Temp values kept as cache in the material. _this._renderTargets = new BABYLON.SmartArray(16); _this._reflectionControls = BABYLON.Vector4.Zero(); _this._white = BABYLON.Color3.White(); _this._primaryShadowColor = BABYLON.Color3.Black(); _this._primaryHighlightColor = BABYLON.Color3.Black(); // Setup the default processing configuration to the scene. _this._attachImageProcessingConfiguration(null); _this.getRenderTargetTextures = function () { _this._renderTargets.reset(); if (_this._diffuseTexture && _this._diffuseTexture.isRenderTarget) { _this._renderTargets.push(_this._diffuseTexture); } if (_this._reflectionTexture && _this._reflectionTexture.isRenderTarget) { _this._renderTargets.push(_this._reflectionTexture); } return _this._renderTargets; }; return _this; } Object.defineProperty(BackgroundMaterial.prototype, "perceptualColor", { /** * Key light Color in "perceptual value" meaning the color you would like to see on screen. * This acts as a helper to set the primary color to a more "human friendly" value. * Conversion to linear space as well as exposure and tone mapping correction will be applied to keep the * output color as close as possible from the chosen value. * (This does not account for contrast color grading and color curves as they are considered post effect and not directly * part of lighting setup.) */ get: function () { return this._perceptualColor; }, set: function (value) { this._perceptualColor = value; this._computePrimaryColorFromPerceptualColor(); this._markAllSubMeshesAsLightsDirty(); }, enumerable: true, configurable: true }); Object.defineProperty(BackgroundMaterial.prototype, "primaryColorShadowLevel", { /** * Defines the level of the shadows (dark area of the reflection map) in order to help scaling the colors. * The color opposite to the primary color is used at the level chosen to define what the black area would look. */ get: function () { return this._primaryColorShadowLevel; }, set: function (value) { this._primaryColorShadowLevel = value; this._computePrimaryColors(); this._markAllSubMeshesAsLightsDirty(); }, enumerable: true, configurable: true }); Object.defineProperty(BackgroundMaterial.prototype, "primaryColorHighlightLevel", { /** * Defines the level of the highliights (highlight area of the reflection map) in order to help scaling the colors. * The primary color is used at the level chosen to define what the white area would look. */ get: function () { return this._primaryColorHighlightLevel; }, set: function (value) { this._primaryColorHighlightLevel = value; this._computePrimaryColors(); this._markAllSubMeshesAsLightsDirty(); }, enumerable: true, configurable: true }); Object.defineProperty(BackgroundMaterial.prototype, "reflectionStandardFresnelWeight", { /** * Sets the reflection reflectance fresnel values according to the default standard * empirically know to work well :-) */ set: function (value) { var reflectionWeight = value; if (reflectionWeight < 0.5) { reflectionWeight = reflectionWeight * 2.0; this.reflectionReflectance0 = BackgroundMaterial.StandardReflectance0 * reflectionWeight; this.reflectionReflectance90 = BackgroundMaterial.StandardReflectance90 * reflectionWeight; } else { reflectionWeight = reflectionWeight * 2.0 - 1.0; this.reflectionReflectance0 = BackgroundMaterial.StandardReflectance0 + (1.0 - BackgroundMaterial.StandardReflectance0) * reflectionWeight; this.reflectionReflectance90 = BackgroundMaterial.StandardReflectance90 + (1.0 - BackgroundMaterial.StandardReflectance90) * reflectionWeight; } }, enumerable: true, configurable: true }); Object.defineProperty(BackgroundMaterial.prototype, "fovMultiplier", { /** * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out". * Best used when trying to implement visual zoom effects like fish-eye or binoculars while not adjusting camera fov. * Recommended to be keep at 1.0 except for special cases. */ get: function () { return this._fovMultiplier; }, set: function (value) { if (isNaN(value)) { value = 1.0; } this._fovMultiplier = Math.max(0.0, Math.min(2.0, value)); }, enumerable: true, configurable: true }); /** * Attaches a new image processing configuration to the PBR Material. * @param configuration (if null the scene configuration will be use) */ BackgroundMaterial.prototype._attachImageProcessingConfiguration = function (configuration) { var _this = this; if (configuration === this._imageProcessingConfiguration) { return; } // Detaches observer. if (this._imageProcessingConfiguration && this._imageProcessingObserver) { this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver); } // Pick the scene configuration if needed. if (!configuration) { this._imageProcessingConfiguration = this.getScene().imageProcessingConfiguration; } else { this._imageProcessingConfiguration = configuration; } // Attaches observer. this._imageProcessingObserver = this._imageProcessingConfiguration.onUpdateParameters.add(function (conf) { _this._computePrimaryColorFromPerceptualColor(); _this._markAllSubMeshesAsImageProcessingDirty(); }); }; Object.defineProperty(BackgroundMaterial.prototype, "imageProcessingConfiguration", { /** * Gets the image processing configuration used either in this material. */ get: function () { return this._imageProcessingConfiguration; }, /** * Sets the Default image processing configuration used either in the this material. * * If sets to null, the scene one is in use. */ set: function (value) { this._attachImageProcessingConfiguration(value); // Ensure the effect will be rebuilt. this._markAllSubMeshesAsTexturesDirty(); }, enumerable: true, configurable: true }); Object.defineProperty(BackgroundMaterial.prototype, "cameraColorCurvesEnabled", { /** * Gets wether the color curves effect is enabled. */ get: function () { return this.imageProcessingConfiguration.colorCurvesEnabled; }, /** * Sets wether the color curves effect is enabled. */ set: function (value) { this.imageProcessingConfiguration.colorCurvesEnabled = value; }, enumerable: true, configurable: true }); Object.defineProperty(BackgroundMaterial.prototype, "cameraColorGradingEnabled", { /** * Gets wether the color grading effect is enabled. */ get: function () { return this.imageProcessingConfiguration.colorGradingEnabled; }, /** * Gets wether the color grading effect is enabled. */ set: function (value) { this.imageProcessingConfiguration.colorGradingEnabled = value; }, enumerable: true, configurable: true }); Object.defineProperty(BackgroundMaterial.prototype, "cameraToneMappingEnabled", { /** * Gets wether tonemapping is enabled or not. */ get: function () { return this._imageProcessingConfiguration.toneMappingEnabled; }, /** * Sets wether tonemapping is enabled or not */ set: function (value) { this._imageProcessingConfiguration.toneMappingEnabled = value; }, enumerable: true, configurable: true }); ; ; Object.defineProperty(BackgroundMaterial.prototype, "cameraExposure", { /** * The camera exposure used on this material. * This property is here and not in the camera to allow controlling exposure without full screen post process. * This corresponds to a photographic exposure. */ get: function () { return this._imageProcessingConfiguration.exposure; }, /** * The camera exposure used on this material. * This property is here and not in the camera to allow controlling exposure without full screen post process. * This corresponds to a photographic exposure. */ set: function (value) { this._imageProcessingConfiguration.exposure = value; }, enumerable: true, configurable: true }); ; ; Object.defineProperty(BackgroundMaterial.prototype, "cameraContrast", { /** * Gets The camera contrast used on this material. */ get: function () { return this._imageProcessingConfiguration.contrast; }, /** * Sets The camera contrast used on this material. */ set: function (value) { this._imageProcessingConfiguration.contrast = value; }, enumerable: true, configurable: true }); Object.defineProperty(BackgroundMaterial.prototype, "cameraColorGradingTexture", { /** * Gets the Color Grading 2D Lookup Texture. */ get: function () { return this._imageProcessingConfiguration.colorGradingTexture; }, /** * Sets the Color Grading 2D Lookup Texture. */ set: function (value) { this.imageProcessingConfiguration.colorGradingTexture = value; }, enumerable: true, configurable: true }); Object.defineProperty(BackgroundMaterial.prototype, "cameraColorCurves", { /** * The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT). * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects. * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; * corresponding to low luminance, medium luminance, and high luminance areas respectively. */ get: function () { return this.imageProcessingConfiguration.colorCurves; }, /** * The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT). * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects. * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; * corresponding to low luminance, medium luminance, and high luminance areas respectively. */ set: function (value) { this.imageProcessingConfiguration.colorCurves = value; }, enumerable: true, configurable: true }); /** * The entire material has been created in order to prevent overdraw. * @returns false */ BackgroundMaterial.prototype.needAlphaTesting = function () { return true; }; /** * The entire material has been created in order to prevent overdraw. * @returns true if blending is enable */ BackgroundMaterial.prototype.needAlphaBlending = function () { return ((this.alpha < 0) || (this._diffuseTexture != null && this._diffuseTexture.hasAlpha)); }; /** * Checks wether the material is ready to be rendered for a given mesh. * @param mesh The mesh to render * @param subMesh The submesh to check against * @param useInstances Specify wether or not the material is used with instances * @returns true if all the dependencies are ready (Textures, Effects...) */ BackgroundMaterial.prototype.isReadyForSubMesh = function (mesh, subMesh, useInstances) { var _this = this; if (useInstances === void 0) { useInstances = false; } if (subMesh.effect && this.isFrozen) { if (this._wasPreviouslyReady) { return true; } } if (!subMesh._materialDefines) { subMesh._materialDefines = new BackgroundMaterialDefines(); } var scene = this.getScene(); var defines = subMesh._materialDefines; if (!this.checkReadyOnEveryCall && subMesh.effect) { if (defines._renderId === scene.getRenderId()) { return true; } } var engine = scene.getEngine(); // Lights BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights); defines._needNormals = true; // Textures if (defines._areTexturesDirty) { defines._needUVs = false; if (scene.texturesEnabled) { if (scene.getEngine().getCaps().textureLOD) { defines.TEXTURELODSUPPORT = true; } if (this._diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) { if (!this._diffuseTexture.isReadyOrNotBlocking()) { return false; } BABYLON.MaterialHelper.PrepareDefinesForMergedUV(this._diffuseTexture, defines, "DIFFUSE"); defines.DIFFUSEHASALPHA = this._diffuseTexture.hasAlpha; defines.GAMMADIFFUSE = this._diffuseTexture.gammaSpace; defines.OPACITYFRESNEL = this._opacityFresnel; } else { defines.DIFFUSE = false; defines.DIFFUSEHASALPHA = false; defines.GAMMADIFFUSE = false; defines.OPACITYFRESNEL = false; } var reflectionTexture = this._reflectionTexture; if (reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) { if (!reflectionTexture.isReadyOrNotBlocking()) { return false; } defines.REFLECTION = true; defines.GAMMAREFLECTION = reflectionTexture.gammaSpace; defines.REFLECTIONBLUR = this._reflectionBlur > 0; defines.REFLECTIONMAP_OPPOSITEZ = this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ; defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha; defines.EQUIRECTANGULAR_RELFECTION_FOV = this.useEquirectangularFOV; defines.REFLECTIONBGR = this.switchToBGR; if (reflectionTexture.coordinatesMode === BABYLON.Texture.INVCUBIC_MODE) { defines.INVERTCUBICMAP = true; } defines.REFLECTIONMAP_3D = reflectionTexture.isCube; switch (reflectionTexture.coordinatesMode) { case BABYLON.Texture.CUBIC_MODE: case BABYLON.Texture.INVCUBIC_MODE: defines.REFLECTIONMAP_CUBIC = true; break; case BABYLON.Texture.EXPLICIT_MODE: defines.REFLECTIONMAP_EXPLICIT = true; break; case BABYLON.Texture.PLANAR_MODE: defines.REFLECTIONMAP_PLANAR = true; break; case BABYLON.Texture.PROJECTION_MODE: defines.REFLECTIONMAP_PROJECTION = true; break; case BABYLON.Texture.SKYBOX_MODE: defines.REFLECTIONMAP_SKYBOX = true; break; case BABYLON.Texture.SPHERICAL_MODE: defines.REFLECTIONMAP_SPHERICAL = true; break; case BABYLON.Texture.EQUIRECTANGULAR_MODE: defines.REFLECTIONMAP_EQUIRECTANGULAR = true; break; case BABYLON.Texture.FIXED_EQUIRECTANGULAR_MODE: defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = true; break; case BABYLON.Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE: defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = true; break; } if (this.reflectionFresnel) { defines.REFLECTIONFRESNEL = true; defines.REFLECTIONFALLOFF = this.reflectionFalloffDistance > 0; this._reflectionControls.x = this.reflectionAmount; this._reflectionControls.y = this.reflectionReflectance0; this._reflectionControls.z = this.reflectionReflectance90; this._reflectionControls.w = 1 / this.reflectionFalloffDistance; } else { defines.REFLECTIONFRESNEL = false; defines.REFLECTIONFALLOFF = false; } } else { defines.REFLECTION = false; defines.REFLECTIONFALLOFF = false; defines.REFLECTIONBLUR = false; defines.REFLECTIONMAP_3D = false; defines.REFLECTIONMAP_SPHERICAL = false; defines.REFLECTIONMAP_PLANAR = false; defines.REFLECTIONMAP_CUBIC = false; defines.REFLECTIONMAP_PROJECTION = false; defines.REFLECTIONMAP_SKYBOX = false; defines.REFLECTIONMAP_EXPLICIT = false; defines.REFLECTIONMAP_EQUIRECTANGULAR = false; defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false; defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false; defines.INVERTCUBICMAP = false; defines.REFLECTIONMAP_OPPOSITEZ = false; defines.LODINREFLECTIONALPHA = false; defines.GAMMAREFLECTION = false; } } defines.PREMULTIPLYALPHA = (this.alphaMode === BABYLON.Engine.ALPHA_PREMULTIPLIED || this.alphaMode === BABYLON.Engine.ALPHA_PREMULTIPLIED_PORTERDUFF); defines.USERGBCOLOR = this._useRGBColor; defines.NOISE = this._enableNoise; } if (defines._areLightsDirty) { defines.USEHIGHLIGHTANDSHADOWCOLORS = !this._useRGBColor && (this._primaryColorShadowLevel !== 0 || this._primaryColorHighlightLevel !== 0); } if (defines._areImageProcessingDirty) { if (!this._imageProcessingConfiguration.isReady()) { return false; } this._imageProcessingConfiguration.prepareDefines(defines); } // Misc. BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines); // Values that need to be evaluated on every frame BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances); // Attribs if (BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true, false)) { if (mesh) { if (!scene.getEngine().getCaps().standardDerivatives && !mesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) { mesh.createNormals(true); BABYLON.Tools.Warn("BackgroundMaterial: Normals have been created for the mesh: " + mesh.name); } } } // Get correct effect if (defines.isDirty) { defines.markAsProcessed(); scene.resetCachedMaterial(); // Fallbacks var fallbacks = new BABYLON.EffectFallbacks(); if (defines.FOG) { fallbacks.addFallback(0, "FOG"); } if (defines.POINTSIZE) { fallbacks.addFallback(1, "POINTSIZE"); } BABYLON.MaterialHelper.HandleFallbacksForShadows(defines, fallbacks, this._maxSimultaneousLights); if (defines.NUM_BONE_INFLUENCERS > 0) { fallbacks.addCPUSkinningFallback(0, mesh); } //Attributes var attribs = [BABYLON.VertexBuffer.PositionKind]; if (defines.NORMAL) { attribs.push(BABYLON.VertexBuffer.NormalKind); } if (defines.UV1) { attribs.push(BABYLON.VertexBuffer.UVKind); } if (defines.UV2) { attribs.push(BABYLON.VertexBuffer.UV2Kind); } BABYLON.MaterialHelper.PrepareAttributesForBones(attribs, mesh, defines, fallbacks); BABYLON.MaterialHelper.PrepareAttributesForInstances(attribs, defines); var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vFogInfos", "vFogColor", "pointSize", "vClipPlane", "mBones", "vPrimaryColor", "vPrimaryColorShadow", "vReflectionInfos", "reflectionMatrix", "vReflectionMicrosurfaceInfos", "fFovMultiplier", "shadowLevel", "alpha", "vBackgroundCenter", "vReflectionControl", "vDiffuseInfos", "diffuseMatrix", ]; var samplers = ["diffuseSampler", "reflectionSampler", "reflectionSamplerLow", "reflectionSamplerHigh"]; var uniformBuffers = ["Material", "Scene"]; BABYLON.ImageProcessingConfiguration.PrepareUniforms(uniforms, defines); BABYLON.ImageProcessingConfiguration.PrepareSamplers(samplers, defines); BABYLON.MaterialHelper.PrepareUniformsAndSamplersList({ uniformsNames: uniforms, uniformBuffersNames: uniformBuffers, samplers: samplers, defines: defines, maxSimultaneousLights: this._maxSimultaneousLights }); var onCompiled = function (effect) { if (_this.onCompiled) { _this.onCompiled(effect); } _this.bindSceneUniformBuffer(effect, scene.getSceneUniformBuffer()); }; var join = defines.toString(); subMesh.setEffect(scene.getEngine().createEffect("background", { attributes: attribs, uniformsNames: uniforms, uniformBuffersNames: uniformBuffers, samplers: samplers, defines: join, fallbacks: fallbacks, onCompiled: onCompiled, onError: this.onError, indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights } }, engine), defines); this.buildUniformLayout(); } if (!subMesh.effect || !subMesh.effect.isReady()) { return false; } defines._renderId = scene.getRenderId(); this._wasPreviouslyReady = true; return true; }; /** * Compute the primary color according to the chosen perceptual color. */ BackgroundMaterial.prototype._computePrimaryColorFromPerceptualColor = function () { if (!this._perceptualColor) { return; } this._primaryColor.copyFrom(this._perceptualColor); // Revert gamma space. this._primaryColor.toLinearSpaceToRef(this._primaryColor); // Revert image processing configuration. if (this._imageProcessingConfiguration) { // Revert tone mapping. if (this._imageProcessingConfiguration.toneMappingEnabled) { // shader reference. // tonemapped.rgb = 1.0 - exp2(-tonemappingCalibration * color.rgb); // providing // log2(1.0 - tonemapped.rgb) / -tonemappingCalibration = color.rgb; // 1.0 - tonemapped.rgb this._white.subtractToRef(this._primaryColor, this._primaryColor); // log2(1.0 - tonemapped.rgb) this._primaryColor.r = BABYLON.Scalar.Log2(this._primaryColor.r); this._primaryColor.g = BABYLON.Scalar.Log2(this._primaryColor.g); this._primaryColor.b = BABYLON.Scalar.Log2(this._primaryColor.b); // log2(1.0 - tonemapped.rgb) / -tonemappingCalibration this._primaryColor.scaleToRef(-1 / BackgroundMaterial._tonemappingCalibration, this._primaryColor); } // Revert Exposure. this._primaryColor.scaleToRef(1 / this._imageProcessingConfiguration.exposure, this._primaryColor); } this._computePrimaryColors(); }; /** * Compute the highlights and shadow colors according to their chosen levels. */ BackgroundMaterial.prototype._computePrimaryColors = function () { if (this._primaryColorShadowLevel === 0 && this._primaryColorHighlightLevel === 0) { return; } // Find the highlight color based on the configuration. this._primaryColor.scaleToRef(this._primaryColorShadowLevel, this._primaryShadowColor); this._primaryColor.subtractToRef(this._primaryShadowColor, this._primaryShadowColor); this._primaryShadowColor.clampToRef(0, 1, this._primaryShadowColor); // Find the shadow color based on the configuration. this._white.subtractToRef(this._primaryColor, this._primaryHighlightColor); this._primaryHighlightColor.scaleToRef(this._primaryColorHighlightLevel, this._primaryHighlightColor); this._primaryColor.addToRef(this._primaryHighlightColor, this._primaryHighlightColor); this._primaryHighlightColor.clampToRef(0, 1, this._primaryHighlightColor); }; /** * Build the uniform buffer used in the material. */ BackgroundMaterial.prototype.buildUniformLayout = function () { // Order is important ! this._uniformBuffer.addUniform("vPrimaryColor", 4); this._uniformBuffer.addUniform("vPrimaryColorShadow", 4); this._uniformBuffer.addUniform("vDiffuseInfos", 2); this._uniformBuffer.addUniform("vReflectionInfos", 2); this._uniformBuffer.addUniform("diffuseMatrix", 16); this._uniformBuffer.addUniform("reflectionMatrix", 16); this._uniformBuffer.addUniform("vReflectionMicrosurfaceInfos", 3); this._uniformBuffer.addUniform("fFovMultiplier", 1); this._uniformBuffer.addUniform("pointSize", 1); this._uniformBuffer.addUniform("shadowLevel", 1); this._uniformBuffer.addUniform("alpha", 1); this._uniformBuffer.addUniform("vBackgroundCenter", 3); this._uniformBuffer.addUniform("vReflectionControl", 4); this._uniformBuffer.create(); }; /** * Unbind the material. */ BackgroundMaterial.prototype.unbind = function () { if (this._diffuseTexture && this._diffuseTexture.isRenderTarget) { this._uniformBuffer.setTexture("diffuseSampler", null); } if (this._reflectionTexture && this._reflectionTexture.isRenderTarget) { this._uniformBuffer.setTexture("reflectionSampler", null); } _super.prototype.unbind.call(this); }; /** * Bind only the world matrix to the material. * @param world The world matrix to bind. */ BackgroundMaterial.prototype.bindOnlyWorldMatrix = function (world) { this._activeEffect.setMatrix("world", world); }; /** * Bind the material for a dedicated submeh (every used meshes will be considered opaque). * @param world The world matrix to bind. * @param subMesh The submesh to bind for. */ BackgroundMaterial.prototype.bindForSubMesh = function (world, mesh, subMesh) { var scene = this.getScene(); var defines = subMesh._materialDefines; if (!defines) { return; } var effect = subMesh.effect; if (!effect) { return; } this._activeEffect = effect; // Matrices this.bindOnlyWorldMatrix(world); // Bones BABYLON.MaterialHelper.BindBonesParameters(mesh, this._activeEffect); var mustRebind = this._mustRebind(scene, effect, mesh.visibility); if (mustRebind) { this._uniformBuffer.bindToEffect(effect, "Material"); this.bindViewProjection(effect); var reflectionTexture = this._reflectionTexture; if (!this._uniformBuffer.useUbo || !this.isFrozen || !this._uniformBuffer.isSync) { // Texture uniforms if (scene.texturesEnabled) { if (this._diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) { this._uniformBuffer.updateFloat2("vDiffuseInfos", this._diffuseTexture.coordinatesIndex, this._diffuseTexture.level); BABYLON.MaterialHelper.BindTextureMatrix(this._diffuseTexture, this._uniformBuffer, "diffuse"); } if (reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) { this._uniformBuffer.updateMatrix("reflectionMatrix", reflectionTexture.getReflectionTextureMatrix()); this._uniformBuffer.updateFloat2("vReflectionInfos", reflectionTexture.level, this._reflectionBlur); this._uniformBuffer.updateFloat3("vReflectionMicrosurfaceInfos", reflectionTexture.getSize().width, reflectionTexture.lodGenerationScale, reflectionTexture.lodGenerationOffset); } } if (this.shadowLevel > 0) { this._uniformBuffer.updateFloat("shadowLevel", this.shadowLevel); } this._uniformBuffer.updateFloat("alpha", this.alpha); // Point size if (this.pointsCloud) { this._uniformBuffer.updateFloat("pointSize", this.pointSize); } if (defines.USEHIGHLIGHTANDSHADOWCOLORS) { this._uniformBuffer.updateColor4("vPrimaryColor", this._primaryHighlightColor, 1.0); this._uniformBuffer.updateColor4("vPrimaryColorShadow", this._primaryShadowColor, 1.0); } else { this._uniformBuffer.updateColor4("vPrimaryColor", this._primaryColor, 1.0); } } this._uniformBuffer.updateFloat("fFovMultiplier", this._fovMultiplier); // Textures if (scene.texturesEnabled) { if (this._diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) { this._uniformBuffer.setTexture("diffuseSampler", this._diffuseTexture); } if (reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) { if (defines.REFLECTIONBLUR && defines.TEXTURELODSUPPORT) { this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture); } else if (!defines.REFLECTIONBLUR) { this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture); } else { this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture._lodTextureMid || reflectionTexture); this._uniformBuffer.setTexture("reflectionSamplerLow", reflectionTexture._lodTextureLow || reflectionTexture); this._uniformBuffer.setTexture("reflectionSamplerHigh", reflectionTexture._lodTextureHigh || reflectionTexture); } if (defines.REFLECTIONFRESNEL) { this._uniformBuffer.updateFloat3("vBackgroundCenter", this.sceneCenter.x, this.sceneCenter.y, this.sceneCenter.z); this._uniformBuffer.updateFloat4("vReflectionControl", this._reflectionControls.x, this._reflectionControls.y, this._reflectionControls.z, this._reflectionControls.w); } } } // Clip plane BABYLON.MaterialHelper.BindClipPlane(this._activeEffect, scene); BABYLON.MaterialHelper.BindEyePosition(effect, scene); } if (mustRebind || !this.isFrozen) { if (scene.lightsEnabled) { BABYLON.MaterialHelper.BindLights(scene, mesh, this._activeEffect, defines, this._maxSimultaneousLights, false); } // View this.bindView(effect); // Fog BABYLON.MaterialHelper.BindFogParameters(scene, mesh, this._activeEffect); // image processing this._imageProcessingConfiguration.bind(this._activeEffect); } this._uniformBuffer.update(); this._afterBind(mesh); }; /** * Dispose the material. * @param forceDisposeEffect Force disposal of the associated effect. * @param forceDisposeTextures Force disposal of the associated textures. */ BackgroundMaterial.prototype.dispose = function (forceDisposeEffect, forceDisposeTextures) { if (forceDisposeEffect === void 0) { forceDisposeEffect = false; } if (forceDisposeTextures === void 0) { forceDisposeTextures = false; } if (forceDisposeTextures) { if (this.diffuseTexture) { this.diffuseTexture.dispose(); } if (this.reflectionTexture) { this.reflectionTexture.dispose(); } } this._renderTargets.dispose(); if (this._imageProcessingConfiguration && this._imageProcessingObserver) { this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver); } _super.prototype.dispose.call(this, forceDisposeEffect); }; /** * Clones the material. * @param name The cloned name. * @returns The cloned material. */ BackgroundMaterial.prototype.clone = function (name) { var _this = this; return BABYLON.SerializationHelper.Clone(function () { return new BackgroundMaterial(name, _this.getScene()); }, this); }; /** * Serializes the current material to its JSON representation. * @returns The JSON representation. */ BackgroundMaterial.prototype.serialize = function () { var serializationObject = BABYLON.SerializationHelper.Serialize(this); serializationObject.customType = "BABYLON.BackgroundMaterial"; return serializationObject; }; /** * Gets the class name of the material * @returns "BackgroundMaterial" */ BackgroundMaterial.prototype.getClassName = function () { return "BackgroundMaterial"; }; /** * Parse a JSON input to create back a background material. * @param source The JSON data to parse * @param scene The scene to create the parsed material in * @param rootUrl The root url of the assets the material depends upon * @returns the instantiated BackgroundMaterial. */ BackgroundMaterial.Parse = function (source, scene, rootUrl) { return BABYLON.SerializationHelper.Parse(function () { return new BackgroundMaterial(source.name, scene); }, source, scene, rootUrl); }; /** * Standard reflectance value at parallel view angle. */ BackgroundMaterial.StandardReflectance0 = 0.05; /** * Standard reflectance value at grazing angle. */ BackgroundMaterial.StandardReflectance90 = 0.5; /** * Tone Mapping calibration (should match image processing tone mapping calibration value). */ BackgroundMaterial._tonemappingCalibration = 1.590579; __decorate([ BABYLON.serializeAsColor3() ], BackgroundMaterial.prototype, "_primaryColor", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsLightsDirty") ], BackgroundMaterial.prototype, "primaryColor", void 0); __decorate([ BABYLON.serializeAsColor3() ], BackgroundMaterial.prototype, "_perceptualColor", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_primaryColorShadowLevel", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_primaryColorHighlightLevel", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsLightsDirty") ], BackgroundMaterial.prototype, "primaryColorHighlightLevel", null); __decorate([ BABYLON.serializeAsTexture() ], BackgroundMaterial.prototype, "_reflectionTexture", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "reflectionTexture", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_reflectionBlur", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "reflectionBlur", void 0); __decorate([ BABYLON.serializeAsTexture() ], BackgroundMaterial.prototype, "_diffuseTexture", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "diffuseTexture", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "shadowLights", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_shadowLevel", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "shadowLevel", void 0); __decorate([ BABYLON.serializeAsVector3() ], BackgroundMaterial.prototype, "_sceneCenter", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "sceneCenter", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_opacityFresnel", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "opacityFresnel", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_reflectionFresnel", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "reflectionFresnel", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_reflectionFalloffDistance", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "reflectionFalloffDistance", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_reflectionAmount", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "reflectionAmount", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_reflectionReflectance0", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "reflectionReflectance0", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_reflectionReflectance90", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "reflectionReflectance90", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_useRGBColor", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "useRGBColor", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_enableNoise", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "enableNoise", void 0); __decorate([ BABYLON.serialize() ], BackgroundMaterial.prototype, "_maxSimultaneousLights", void 0); __decorate([ BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty") ], BackgroundMaterial.prototype, "maxSimultaneousLights", void 0); __decorate([ BABYLON.serializeAsImageProcessingConfiguration() ], BackgroundMaterial.prototype, "_imageProcessingConfiguration", void 0); return BackgroundMaterial; }(BABYLON.PushMaterial)); BABYLON.BackgroundMaterial = BackgroundMaterial; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.backgroundMaterial.js.map var __assign = (this && this.__assign) || Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; var BABYLON; (function (BABYLON) { /** * The Environment helper class can be used to add a fully featuread none expensive background to your scene. * It includes by default a skybox and a ground relying on the BackgroundMaterial. * It also helps with the default setup of your imageProcessing configuration. */ var EnvironmentHelper = /** @class */ (function () { /** * constructor * @param options * @param scene The scene to add the material to */ function EnvironmentHelper(options, scene) { var _this = this; this._errorHandler = function (message, exception) { _this.onErrorObservable.notifyObservers({ message: message, exception: exception }); }; this._options = __assign({}, EnvironmentHelper._getDefaultOptions(), options); this._scene = scene; this.onErrorObservable = new BABYLON.Observable(); this._setupBackground(); this._setupImageProcessing(); } /** * Creates the default options for the helper. */ EnvironmentHelper._getDefaultOptions = function () { return { createGround: true, groundSize: 15, groundTexture: this._groundTextureCDNUrl, groundColor: new BABYLON.Color3(0.2, 0.2, 0.3).toLinearSpace().scale(3), groundOpacity: 0.9, enableGroundShadow: true, groundShadowLevel: 0.5, enableGroundMirror: false, groundMirrorSizeRatio: 0.3, groundMirrorBlurKernel: 64, groundMirrorAmount: 1, groundMirrorFresnelWeight: 1, groundMirrorFallOffDistance: 0, groundMirrorTextureType: BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, groundYBias: 0.00001, createSkybox: true, skyboxSize: 20, skyboxTexture: this._skyboxTextureCDNUrl, skyboxColor: new BABYLON.Color3(0.2, 0.2, 0.3).toLinearSpace().scale(3), backgroundYRotation: 0, sizeAuto: true, rootPosition: BABYLON.Vector3.Zero(), setupImageProcessing: true, environmentTexture: this._environmentTextureCDNUrl, cameraExposure: 0.8, cameraContrast: 1.2, toneMappingEnabled: true, }; }; Object.defineProperty(EnvironmentHelper.prototype, "rootMesh", { /** * Gets the root mesh created by the helper. */ get: function () { return this._rootMesh; }, enumerable: true, configurable: true }); Object.defineProperty(EnvironmentHelper.prototype, "skybox", { /** * Gets the skybox created by the helper. */ get: function () { return this._skybox; }, enumerable: true, configurable: true }); Object.defineProperty(EnvironmentHelper.prototype, "skyboxTexture", { /** * Gets the skybox texture created by the helper. */ get: function () { return this._skyboxTexture; }, enumerable: true, configurable: true }); Object.defineProperty(EnvironmentHelper.prototype, "skyboxMaterial", { /** * Gets the skybox material created by the helper. */ get: function () { return this._skyboxMaterial; }, enumerable: true, configurable: true }); Object.defineProperty(EnvironmentHelper.prototype, "ground", { /** * Gets the ground mesh created by the helper. */ get: function () { return this._ground; }, enumerable: true, configurable: true }); Object.defineProperty(EnvironmentHelper.prototype, "groundTexture", { /** * Gets the ground texture created by the helper. */ get: function () { return this._groundTexture; }, enumerable: true, configurable: true }); Object.defineProperty(EnvironmentHelper.prototype, "groundMirror", { /** * Gets the ground mirror created by the helper. */ get: function () { return this._groundMirror; }, enumerable: true, configurable: true }); Object.defineProperty(EnvironmentHelper.prototype, "groundMirrorRenderList", { /** * Gets the ground mirror render list to helps pushing the meshes * you wish in the ground reflection. */ get: function () { if (this._groundMirror) { return this._groundMirror.renderList; } return null; }, enumerable: true, configurable: true }); Object.defineProperty(EnvironmentHelper.prototype, "groundMaterial", { /** * Gets the ground material created by the helper. */ get: function () { return this._groundMaterial; }, enumerable: true, configurable: true }); /** * Updates the background according to the new options * @param options */ EnvironmentHelper.prototype.updateOptions = function (options) { var newOptions = __assign({}, this._options, options); if (this._ground && !newOptions.createGround) { this._ground.dispose(); this._ground = null; } if (this._groundMaterial && !newOptions.createGround) { this._groundMaterial.dispose(); this._groundMaterial = null; } if (this._groundTexture) { if (this._options.groundTexture != newOptions.groundTexture) { this._groundTexture.dispose(); this._groundTexture = null; } } if (this._skybox && !newOptions.createSkybox) { this._skybox.dispose(); this._skybox = null; } if (this._skyboxMaterial && !newOptions.createSkybox) { this._skyboxMaterial.dispose(); this._skyboxMaterial = null; } if (this._skyboxTexture) { if (this._options.skyboxTexture != newOptions.skyboxTexture) { this._skyboxTexture.dispose(); this._skyboxTexture = null; } } if (this._groundMirror && !newOptions.enableGroundMirror) { this._groundMirror.dispose(); this._groundMirror = null; } if (this._scene.environmentTexture) { if (this._options.environmentTexture != newOptions.environmentTexture) { this._scene.environmentTexture.dispose(); } } this._options = newOptions; this._setupBackground(); this._setupImageProcessing(); }; /** * Sets the primary color of all the available elements. * @param color the main color to affect to the ground and the background * @param perceptual Specifies wether the chosen color has been set as intented to be seen e.g. in gamma space not accounting for exposure and tone mapping */ EnvironmentHelper.prototype.setMainColor = function (color, perceptual) { if (perceptual === void 0) { perceptual = false; } if (this.groundMaterial) { if (perceptual) { this.groundMaterial.perceptualColor = color; } else { this.groundMaterial.primaryColor = color; } } if (this.skyboxMaterial) { if (perceptual) { this.skyboxMaterial.perceptualColor = color; } else { this.skyboxMaterial.primaryColor = color; } } if (this.groundMirror) { if (perceptual && this.groundMaterial) { this.groundMirror.clearColor = new BABYLON.Color4(this.groundMaterial.primaryColor.r, this.groundMaterial.primaryColor.g, this.groundMaterial.primaryColor.b, 1.0); } else { this.groundMirror.clearColor = new BABYLON.Color4(color.r, color.g, color.b, 1.0); } } }; /** * Setup the image processing according to the specified options. */ EnvironmentHelper.prototype._setupImageProcessing = function () { if (this._options.setupImageProcessing) { this._scene.imageProcessingConfiguration.contrast = this._options.cameraContrast; this._scene.imageProcessingConfiguration.exposure = this._options.cameraExposure; this._scene.imageProcessingConfiguration.toneMappingEnabled = this._options.toneMappingEnabled; this._setupEnvironmentTexture(); } }; /** * Setup the environment texture according to the specified options. */ EnvironmentHelper.prototype._setupEnvironmentTexture = function () { if (this._scene.environmentTexture) { return; } if (this._options.environmentTexture instanceof BABYLON.BaseTexture) { this._scene.environmentTexture = this._options.environmentTexture; return; } var environmentTexture = BABYLON.CubeTexture.CreateFromPrefilteredData(this._options.environmentTexture, this._scene); this._scene.environmentTexture = environmentTexture; }; /** * Setup the background according to the specified options. */ EnvironmentHelper.prototype._setupBackground = function () { if (!this._rootMesh) { this._rootMesh = new BABYLON.Mesh("BackgroundHelper", this._scene); } this._rootMesh.rotation.y = this._options.backgroundYRotation; var sceneSize = this._getSceneSize(); if (this._options.createGround) { this._setupGround(sceneSize); this._setupGroundMaterial(); this._setupGroundDiffuseTexture(); if (this._options.enableGroundMirror) { this._setupGroundMirrorTexture(sceneSize); } this._setupMirrorInGroundMaterial(); } if (this._options.createSkybox) { this._setupSkybox(sceneSize); this._setupSkyboxMaterial(); this._setupSkyboxReflectionTexture(); } this._rootMesh.position.x = sceneSize.rootPosition.x; this._rootMesh.position.z = sceneSize.rootPosition.z; this._rootMesh.position.y = sceneSize.rootPosition.y; }; /** * Get the scene sizes according to the setup. */ EnvironmentHelper.prototype._getSceneSize = function () { var _this = this; var groundSize = this._options.groundSize; var skyboxSize = this._options.skyboxSize; var rootPosition = this._options.rootPosition; if (!this._scene.meshes || this._scene.meshes.length === 1) { // 1 only means the root of the helper. return { groundSize: groundSize, skyboxSize: skyboxSize, rootPosition: rootPosition }; } var sceneExtends = this._scene.getWorldExtends(function (mesh) { return (mesh !== _this._ground && mesh !== _this._rootMesh && mesh !== _this._skybox); }); var sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min); if (this._options.sizeAuto) { if (this._scene.activeCamera instanceof BABYLON.ArcRotateCamera && this._scene.activeCamera.upperRadiusLimit) { groundSize = this._scene.activeCamera.upperRadiusLimit * 2; skyboxSize = groundSize; } var sceneDiagonalLenght = sceneDiagonal.length(); if (sceneDiagonalLenght > groundSize) { groundSize = sceneDiagonalLenght * 2; skyboxSize = groundSize; } // 10 % bigger. groundSize *= 1.1; skyboxSize *= 1.5; rootPosition = sceneExtends.min.add(sceneDiagonal.scale(0.5)); rootPosition.y = sceneExtends.min.y - this._options.groundYBias; } return { groundSize: groundSize, skyboxSize: skyboxSize, rootPosition: rootPosition }; }; /** * Setup the ground according to the specified options. */ EnvironmentHelper.prototype._setupGround = function (sceneSize) { var _this = this; if (!this._ground) { this._ground = BABYLON.Mesh.CreatePlane("BackgroundPlane", sceneSize.groundSize, this._scene); this._ground.rotation.x = Math.PI / 2; // Face up by default. this._ground.parent = this._rootMesh; this._ground.onDisposeObservable.add(function () { _this._ground = null; }); } this._ground.receiveShadows = this._options.enableGroundShadow; }; /** * Setup the ground material according to the specified options. */ EnvironmentHelper.prototype._setupGroundMaterial = function () { if (!this._groundMaterial) { this._groundMaterial = new BABYLON.BackgroundMaterial("BackgroundPlaneMaterial", this._scene); } this._groundMaterial.alpha = this._options.groundOpacity; this._groundMaterial.alphaMode = BABYLON.Engine.ALPHA_PREMULTIPLIED_PORTERDUFF; this._groundMaterial.shadowLevel = this._options.groundShadowLevel; this._groundMaterial.primaryColor = this._options.groundColor; this._groundMaterial.useRGBColor = false; this._groundMaterial.enableNoise = true; if (this._ground) { this._ground.material = this._groundMaterial; } }; /** * Setup the ground diffuse texture according to the specified options. */ EnvironmentHelper.prototype._setupGroundDiffuseTexture = function () { if (!this._groundMaterial) { return; } if (this._groundTexture) { return; } if (this._options.groundTexture instanceof BABYLON.BaseTexture) { this._groundMaterial.diffuseTexture = this._options.groundTexture; return; } var diffuseTexture = new BABYLON.Texture(this._options.groundTexture, this._scene, undefined, undefined, undefined, undefined, this._errorHandler); diffuseTexture.gammaSpace = false; diffuseTexture.hasAlpha = true; this._groundMaterial.diffuseTexture = diffuseTexture; }; /** * Setup the ground mirror texture according to the specified options. */ EnvironmentHelper.prototype._setupGroundMirrorTexture = function (sceneSize) { var wrapping = BABYLON.Texture.CLAMP_ADDRESSMODE; if (!this._groundMirror) { this._groundMirror = new BABYLON.MirrorTexture("BackgroundPlaneMirrorTexture", { ratio: this._options.groundMirrorSizeRatio }, this._scene, false, this._options.groundMirrorTextureType, BABYLON.Texture.BILINEAR_SAMPLINGMODE, true); this._groundMirror.mirrorPlane = new BABYLON.Plane(0, -1, 0, sceneSize.rootPosition.y); this._groundMirror.anisotropicFilteringLevel = 1; this._groundMirror.wrapU = wrapping; this._groundMirror.wrapV = wrapping; this._groundMirror.gammaSpace = false; if (this._groundMirror.renderList) { for (var i = 0; i < this._scene.meshes.length; i++) { var mesh = this._scene.meshes[i]; if (mesh !== this._ground && mesh !== this._skybox && mesh !== this._rootMesh) { this._groundMirror.renderList.push(mesh); } } } } this._groundMirror.clearColor = new BABYLON.Color4(this._options.groundColor.r, this._options.groundColor.g, this._options.groundColor.b, 1); this._groundMirror.adaptiveBlurKernel = this._options.groundMirrorBlurKernel; }; /** * Setup the ground to receive the mirror texture. */ EnvironmentHelper.prototype._setupMirrorInGroundMaterial = function () { if (this._groundMaterial) { this._groundMaterial.reflectionTexture = this._groundMirror; this._groundMaterial.reflectionFresnel = true; this._groundMaterial.reflectionAmount = this._options.groundMirrorAmount; this._groundMaterial.reflectionStandardFresnelWeight = this._options.groundMirrorFresnelWeight; this._groundMaterial.reflectionFalloffDistance = this._options.groundMirrorFallOffDistance; } }; /** * Setup the skybox according to the specified options. */ EnvironmentHelper.prototype._setupSkybox = function (sceneSize) { var _this = this; if (!this._skybox) { this._skybox = BABYLON.Mesh.CreateBox("BackgroundSkybox", sceneSize.skyboxSize, this._scene, undefined, BABYLON.Mesh.BACKSIDE); this._skybox.onDisposeObservable.add(function () { _this._skybox = null; }); } this._skybox.parent = this._rootMesh; }; /** * Setup the skybox material according to the specified options. */ EnvironmentHelper.prototype._setupSkyboxMaterial = function () { if (!this._skybox) { return; } if (!this._skyboxMaterial) { this._skyboxMaterial = new BABYLON.BackgroundMaterial("BackgroundSkyboxMaterial", this._scene); } this._skyboxMaterial.useRGBColor = false; this._skyboxMaterial.primaryColor = this._options.skyboxColor; this._skyboxMaterial.enableNoise = true; this._skybox.material = this._skyboxMaterial; }; /** * Setup the skybox reflection texture according to the specified options. */ EnvironmentHelper.prototype._setupSkyboxReflectionTexture = function () { if (!this._skyboxMaterial) { return; } if (this._skyboxTexture) { return; } if (this._options.skyboxTexture instanceof BABYLON.BaseTexture) { this._skyboxMaterial.reflectionTexture = this._options.skyboxTexture; return; } this._skyboxTexture = new BABYLON.CubeTexture(this._options.skyboxTexture, this._scene, undefined, undefined, undefined, undefined, this._errorHandler); this._skyboxTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE; this._skyboxTexture.gammaSpace = false; this._skyboxMaterial.reflectionTexture = this._skyboxTexture; }; /** * Dispose all the elements created by the Helper. */ EnvironmentHelper.prototype.dispose = function () { if (this._groundMaterial) { this._groundMaterial.dispose(true, true); } if (this._skyboxMaterial) { this._skyboxMaterial.dispose(true, true); } this._rootMesh.dispose(false); }; /** * Default ground texture URL. */ EnvironmentHelper._groundTextureCDNUrl = "https://assets.babylonjs.com/environments/backgroundGround.png"; /** * Default skybox texture URL. */ EnvironmentHelper._skyboxTextureCDNUrl = "https://assets.babylonjs.com/environments/backgroundSkybox.dds"; /** * Default environment texture URL. */ EnvironmentHelper._environmentTextureCDNUrl = "https://assets.babylonjs.com/environments/environmentSpecular.dds"; return EnvironmentHelper; }()); BABYLON.EnvironmentHelper = EnvironmentHelper; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.environmentHelper.js.map var BABYLON; (function (BABYLON) { /** * Display a 360 degree video on an approximately spherical surface, useful for VR applications or skyboxes. * As a subclass of Node, this allow parenting to the camera or multiple videos with different locations in the scene. * This class achieves its effect with a VideoTexture and a correctly configured BackgroundMaterial on an inverted sphere. * Potential additions to this helper include zoom and and non-infinite distance rendering effects. */ var VideoDome = /** @class */ (function (_super) { __extends(VideoDome, _super); /** * Create an instance of this class and pass through the parameters to the relevant classes, VideoTexture, StandardMaterial, and Mesh. * @param name Element's name, child elements will append suffixes for their own names. * @param urlsOrVideo * @param options An object containing optional or exposed sub element properties: * @param options **resolution=12** Integer, lower resolutions have more artifacts at extreme fovs * @param options **clickToPlay=false** Add a click to play listener to the video, does not prevent autoplay. * @param options **autoPlay=true** Automatically attempt to being playing the video. * @param options **loop=true** Automatically loop video on end. * @param options **size=1000** Physical radius to create the dome at, defaults to approximately half the far clip plane. */ function VideoDome(name, urlsOrVideo, options, scene) { var _this = _super.call(this, name, scene) || this; // set defaults and manage values name = name || "videoDome"; options.resolution = (Math.abs(options.resolution) | 0) || 12; options.clickToPlay = Boolean(options.clickToPlay); options.autoPlay = options.autoPlay === undefined ? true : Boolean(options.autoPlay); options.loop = options.loop === undefined ? true : Boolean(options.loop); options.size = Math.abs(options.size) || (scene.activeCamera ? scene.activeCamera.maxZ * 0.48 : 1000); // create var tempOptions = { loop: options.loop, autoPlay: options.autoPlay, autoUpdateTexture: true }; var material = _this._material = new BABYLON.BackgroundMaterial(name + "_material", scene); var texture = _this._videoTexture = new BABYLON.VideoTexture(name + "_texture", urlsOrVideo, scene, false, false, BABYLON.Texture.TRILINEAR_SAMPLINGMODE, tempOptions); _this._mesh = BABYLON.MeshBuilder.CreateIcoSphere(name + "_mesh", { flat: false, radius: options.size, subdivisions: options.resolution, sideOrientation: BABYLON.Mesh.BACKSIDE // needs to be inside out }, scene); // configure material texture.coordinatesMode = BABYLON.Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE; // matches orientation texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE; // always clamp the up/down material.reflectionTexture = _this._videoTexture; material.useEquirectangularFOV = true; material.fovMultiplier = 1.0; // configure mesh _this._mesh.material = material; _this._mesh.parent = _this; // optional configuration if (options.clickToPlay) { scene.onPointerUp = function () { _this._videoTexture.video.play(); }; } return _this; } Object.defineProperty(VideoDome.prototype, "fovMultiplier", { /** * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out". * Also see the options.resolution property. */ get: function () { return this._material.fovMultiplier; }, set: function (value) { this._material.fovMultiplier = value; }, enumerable: true, configurable: true }); /** * Releases resources associated with this node. * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default) * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default) */ VideoDome.prototype.dispose = function (doNotRecurse, disposeMaterialAndTextures) { if (disposeMaterialAndTextures === void 0) { disposeMaterialAndTextures = false; } this._videoTexture.dispose(); this._mesh.dispose(); this._material.dispose(); _super.prototype.dispose.call(this, doNotRecurse, disposeMaterialAndTextures); }; return VideoDome; }(BABYLON.Node)); BABYLON.VideoDome = VideoDome; })(BABYLON || (BABYLON = {})); //# sourceMappingURL=babylon.videoDome.js.map BABYLON.Effect.ShadersStore={"defaultVertexShader":"#include<__decl__defaultVertex>\n\n#define CUSTOM_VERTEX_BEGIN\nattribute vec3 position;\n#ifdef NORMAL\nattribute vec3 normal;\n#endif\n#ifdef TANGENT\nattribute vec4 tangent;\n#endif\n#ifdef UV1\nattribute vec2 uv;\n#endif\n#ifdef UV2\nattribute vec2 uv2;\n#endif\n#ifdef VERTEXCOLOR\nattribute vec4 color;\n#endif\n#include