environmentHelper.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. import { Observable } from "../Misc/observable";
  2. import { Nullable } from "../types";
  3. import { ArcRotateCamera } from "../Cameras/arcRotateCamera";
  4. import { Scene } from "../scene";
  5. import { Vector3 } from "../Maths/math.vector";
  6. import { Color3, Color4 } from '../Maths/math.color';
  7. import { AbstractMesh } from "../Meshes/abstractMesh";
  8. import { Mesh } from "../Meshes/mesh";
  9. import { BaseTexture } from "../Materials/Textures/baseTexture";
  10. import { Texture } from "../Materials/Textures/texture";
  11. import { MirrorTexture } from "../Materials/Textures/mirrorTexture";
  12. import { CubeTexture } from "../Materials/Textures/cubeTexture";
  13. import { BackgroundMaterial } from "../Materials/Background/backgroundMaterial";
  14. import { _TimeToken } from "../Instrumentation/timeToken";
  15. import { Constants } from "../Engines/constants";
  16. import "../Meshes/Builders/planeBuilder";
  17. import "../Meshes/Builders/boxBuilder";
  18. import { Plane } from '../Maths/math.plane';
  19. /**
  20. * Represents the different options available during the creation of
  21. * a Environment helper.
  22. *
  23. * This can control the default ground, skybox and image processing setup of your scene.
  24. */
  25. export interface IEnvironmentHelperOptions {
  26. /**
  27. * Specifies wether or not to create a ground.
  28. * True by default.
  29. */
  30. createGround: boolean;
  31. /**
  32. * Specifies the ground size.
  33. * 15 by default.
  34. */
  35. groundSize: number;
  36. /**
  37. * The texture used on the ground for the main color.
  38. * Comes from the BabylonJS CDN by default.
  39. *
  40. * Remarks: Can be either a texture or a url.
  41. */
  42. groundTexture: string | BaseTexture;
  43. /**
  44. * The color mixed in the ground texture by default.
  45. * BabylonJS clearColor by default.
  46. */
  47. groundColor: Color3;
  48. /**
  49. * Specifies the ground opacity.
  50. * 1 by default.
  51. */
  52. groundOpacity: number;
  53. /**
  54. * Enables the ground to receive shadows.
  55. * True by default.
  56. */
  57. enableGroundShadow: boolean;
  58. /**
  59. * Helps preventing the shadow to be fully black on the ground.
  60. * 0.5 by default.
  61. */
  62. groundShadowLevel: number;
  63. /**
  64. * Creates a mirror texture attach to the ground.
  65. * false by default.
  66. */
  67. enableGroundMirror: boolean;
  68. /**
  69. * Specifies the ground mirror size ratio.
  70. * 0.3 by default as the default kernel is 64.
  71. */
  72. groundMirrorSizeRatio: number;
  73. /**
  74. * Specifies the ground mirror blur kernel size.
  75. * 64 by default.
  76. */
  77. groundMirrorBlurKernel: number;
  78. /**
  79. * Specifies the ground mirror visibility amount.
  80. * 1 by default
  81. */
  82. groundMirrorAmount: number;
  83. /**
  84. * Specifies the ground mirror reflectance weight.
  85. * This uses the standard weight of the background material to setup the fresnel effect
  86. * of the mirror.
  87. * 1 by default.
  88. */
  89. groundMirrorFresnelWeight: number;
  90. /**
  91. * Specifies the ground mirror Falloff distance.
  92. * This can helps reducing the size of the reflection.
  93. * 0 by Default.
  94. */
  95. groundMirrorFallOffDistance: number;
  96. /**
  97. * Specifies the ground mirror texture type.
  98. * Unsigned Int by Default.
  99. */
  100. groundMirrorTextureType: number;
  101. /**
  102. * Specifies a bias applied to the ground vertical position to prevent z-fighting with
  103. * the shown objects.
  104. */
  105. groundYBias: number;
  106. /**
  107. * Specifies wether or not to create a skybox.
  108. * True by default.
  109. */
  110. createSkybox: boolean;
  111. /**
  112. * Specifies the skybox size.
  113. * 20 by default.
  114. */
  115. skyboxSize: number;
  116. /**
  117. * The texture used on the skybox for the main color.
  118. * Comes from the BabylonJS CDN by default.
  119. *
  120. * Remarks: Can be either a texture or a url.
  121. */
  122. skyboxTexture: string | BaseTexture;
  123. /**
  124. * The color mixed in the skybox texture by default.
  125. * BabylonJS clearColor by default.
  126. */
  127. skyboxColor: Color3;
  128. /**
  129. * The background rotation around the Y axis of the scene.
  130. * This helps aligning the key lights of your scene with the background.
  131. * 0 by default.
  132. */
  133. backgroundYRotation: number;
  134. /**
  135. * Compute automatically the size of the elements to best fit with the scene.
  136. */
  137. sizeAuto: boolean;
  138. /**
  139. * Default position of the rootMesh if autoSize is not true.
  140. */
  141. rootPosition: Vector3;
  142. /**
  143. * Sets up the image processing in the scene.
  144. * true by default.
  145. */
  146. setupImageProcessing: boolean;
  147. /**
  148. * The texture used as your environment texture in the scene.
  149. * Comes from the BabylonJS CDN by default and in use if setupImageProcessing is true.
  150. *
  151. * Remarks: Can be either a texture or a url.
  152. */
  153. environmentTexture: string | BaseTexture;
  154. /**
  155. * The value of the exposure to apply to the scene.
  156. * 0.6 by default if setupImageProcessing is true.
  157. */
  158. cameraExposure: number;
  159. /**
  160. * The value of the contrast to apply to the scene.
  161. * 1.6 by default if setupImageProcessing is true.
  162. */
  163. cameraContrast: number;
  164. /**
  165. * Specifies wether or not tonemapping should be enabled in the scene.
  166. * true by default if setupImageProcessing is true.
  167. */
  168. toneMappingEnabled: boolean;
  169. }
  170. interface ISceneSize {
  171. groundSize: number;
  172. skyboxSize: number;
  173. rootPosition: Vector3;
  174. }
  175. /**
  176. * The Environment helper class can be used to add a fully featuread none expensive background to your scene.
  177. * It includes by default a skybox and a ground relying on the BackgroundMaterial.
  178. * It also helps with the default setup of your imageProcessing configuration.
  179. */
  180. export class EnvironmentHelper {
  181. /**
  182. * Default ground texture URL.
  183. */
  184. private static _groundTextureCDNUrl = "https://assets.babylonjs.com/environments/backgroundGround.png";
  185. /**
  186. * Default skybox texture URL.
  187. */
  188. private static _skyboxTextureCDNUrl = "https://assets.babylonjs.com/environments/backgroundSkybox.dds";
  189. /**
  190. * Default environment texture URL.
  191. */
  192. private static _environmentTextureCDNUrl = "https://assets.babylonjs.com/environments/environmentSpecular.env";
  193. /**
  194. * Creates the default options for the helper.
  195. */
  196. private static _getDefaultOptions(): IEnvironmentHelperOptions {
  197. return {
  198. createGround: true,
  199. groundSize: 15,
  200. groundTexture: this._groundTextureCDNUrl,
  201. groundColor: new Color3(0.2, 0.2, 0.3).toLinearSpace().scale(3),
  202. groundOpacity: 0.9,
  203. enableGroundShadow: true,
  204. groundShadowLevel: 0.5,
  205. enableGroundMirror: false,
  206. groundMirrorSizeRatio: 0.3,
  207. groundMirrorBlurKernel: 64,
  208. groundMirrorAmount: 1,
  209. groundMirrorFresnelWeight: 1,
  210. groundMirrorFallOffDistance: 0,
  211. groundMirrorTextureType: Constants.TEXTURETYPE_UNSIGNED_INT,
  212. groundYBias: 0.00001,
  213. createSkybox: true,
  214. skyboxSize: 20,
  215. skyboxTexture: this._skyboxTextureCDNUrl,
  216. skyboxColor: new Color3(0.2, 0.2, 0.3).toLinearSpace().scale(3),
  217. backgroundYRotation: 0,
  218. sizeAuto: true,
  219. rootPosition: Vector3.Zero(),
  220. setupImageProcessing: true,
  221. environmentTexture: this._environmentTextureCDNUrl,
  222. cameraExposure: 0.8,
  223. cameraContrast: 1.2,
  224. toneMappingEnabled: true,
  225. };
  226. }
  227. private _rootMesh: Mesh;
  228. /**
  229. * Gets the root mesh created by the helper.
  230. */
  231. public get rootMesh(): Mesh {
  232. return this._rootMesh;
  233. }
  234. private _skybox: Nullable<Mesh>;
  235. /**
  236. * Gets the skybox created by the helper.
  237. */
  238. public get skybox(): Nullable<Mesh> {
  239. return this._skybox;
  240. }
  241. private _skyboxTexture: Nullable<BaseTexture>;
  242. /**
  243. * Gets the skybox texture created by the helper.
  244. */
  245. public get skyboxTexture(): Nullable<BaseTexture> {
  246. return this._skyboxTexture;
  247. }
  248. private _skyboxMaterial: Nullable<BackgroundMaterial>;
  249. /**
  250. * Gets the skybox material created by the helper.
  251. */
  252. public get skyboxMaterial(): Nullable<BackgroundMaterial> {
  253. return this._skyboxMaterial;
  254. }
  255. private _ground: Nullable<Mesh>;
  256. /**
  257. * Gets the ground mesh created by the helper.
  258. */
  259. public get ground(): Nullable<Mesh> {
  260. return this._ground;
  261. }
  262. private _groundTexture: Nullable<BaseTexture>;
  263. /**
  264. * Gets the ground texture created by the helper.
  265. */
  266. public get groundTexture(): Nullable<BaseTexture> {
  267. return this._groundTexture;
  268. }
  269. private _groundMirror: Nullable<MirrorTexture>;
  270. /**
  271. * Gets the ground mirror created by the helper.
  272. */
  273. public get groundMirror(): Nullable<MirrorTexture> {
  274. return this._groundMirror;
  275. }
  276. /**
  277. * Gets the ground mirror render list to helps pushing the meshes
  278. * you wish in the ground reflection.
  279. */
  280. public get groundMirrorRenderList(): Nullable<AbstractMesh[]> {
  281. if (this._groundMirror) {
  282. return this._groundMirror.renderList;
  283. }
  284. return null;
  285. }
  286. private _groundMaterial: Nullable<BackgroundMaterial>;
  287. /**
  288. * Gets the ground material created by the helper.
  289. */
  290. public get groundMaterial(): Nullable<BackgroundMaterial> {
  291. return this._groundMaterial;
  292. }
  293. /**
  294. * Stores the creation options.
  295. */
  296. private readonly _scene: Scene;
  297. private _options: IEnvironmentHelperOptions;
  298. /**
  299. * This observable will be notified with any error during the creation of the environment,
  300. * mainly texture creation errors.
  301. */
  302. public onErrorObservable: Observable<{ message?: string, exception?: any }>;
  303. /**
  304. * constructor
  305. * @param options Defines the options we want to customize the helper
  306. * @param scene The scene to add the material to
  307. */
  308. constructor(options: Partial<IEnvironmentHelperOptions>, scene: Scene) {
  309. this._options = {
  310. ...EnvironmentHelper._getDefaultOptions(),
  311. ...options
  312. };
  313. this._scene = scene;
  314. this.onErrorObservable = new Observable();
  315. this._setupBackground();
  316. this._setupImageProcessing();
  317. }
  318. /**
  319. * Updates the background according to the new options
  320. * @param options
  321. */
  322. public updateOptions(options: Partial<IEnvironmentHelperOptions>) {
  323. const newOptions = {
  324. ...this._options,
  325. ...options
  326. };
  327. if (this._ground && !newOptions.createGround) {
  328. this._ground.dispose();
  329. this._ground = null;
  330. }
  331. if (this._groundMaterial && !newOptions.createGround) {
  332. this._groundMaterial.dispose();
  333. this._groundMaterial = null;
  334. }
  335. if (this._groundTexture) {
  336. if (this._options.groundTexture != newOptions.groundTexture) {
  337. this._groundTexture.dispose();
  338. this._groundTexture = null;
  339. }
  340. }
  341. if (this._skybox && !newOptions.createSkybox) {
  342. this._skybox.dispose();
  343. this._skybox = null;
  344. }
  345. if (this._skyboxMaterial && !newOptions.createSkybox) {
  346. this._skyboxMaterial.dispose();
  347. this._skyboxMaterial = null;
  348. }
  349. if (this._skyboxTexture) {
  350. if (this._options.skyboxTexture != newOptions.skyboxTexture) {
  351. this._skyboxTexture.dispose();
  352. this._skyboxTexture = null;
  353. }
  354. }
  355. if (this._groundMirror && !newOptions.enableGroundMirror) {
  356. this._groundMirror.dispose();
  357. this._groundMirror = null;
  358. }
  359. if (this._scene.environmentTexture) {
  360. if (this._options.environmentTexture != newOptions.environmentTexture) {
  361. this._scene.environmentTexture.dispose();
  362. }
  363. }
  364. this._options = newOptions;
  365. this._setupBackground();
  366. this._setupImageProcessing();
  367. }
  368. /**
  369. * Sets the primary color of all the available elements.
  370. * @param color the main color to affect to the ground and the background
  371. */
  372. public setMainColor(color: Color3): void {
  373. if (this.groundMaterial) {
  374. this.groundMaterial.primaryColor = color;
  375. }
  376. if (this.skyboxMaterial) {
  377. this.skyboxMaterial.primaryColor = color;
  378. }
  379. if (this.groundMirror) {
  380. this.groundMirror.clearColor = new Color4(color.r, color.g, color.b, 1.0);
  381. }
  382. }
  383. /**
  384. * Setup the image processing according to the specified options.
  385. */
  386. private _setupImageProcessing(): void {
  387. if (this._options.setupImageProcessing) {
  388. this._scene.imageProcessingConfiguration.contrast = this._options.cameraContrast;
  389. this._scene.imageProcessingConfiguration.exposure = this._options.cameraExposure;
  390. this._scene.imageProcessingConfiguration.toneMappingEnabled = this._options.toneMappingEnabled;
  391. this._setupEnvironmentTexture();
  392. }
  393. }
  394. /**
  395. * Setup the environment texture according to the specified options.
  396. */
  397. private _setupEnvironmentTexture(): void {
  398. if (this._scene.environmentTexture) {
  399. return;
  400. }
  401. if (this._options.environmentTexture instanceof BaseTexture) {
  402. this._scene.environmentTexture = this._options.environmentTexture;
  403. return;
  404. }
  405. const environmentTexture = CubeTexture.CreateFromPrefilteredData(this._options.environmentTexture, this._scene);
  406. this._scene.environmentTexture = environmentTexture;
  407. }
  408. /**
  409. * Setup the background according to the specified options.
  410. */
  411. private _setupBackground(): void {
  412. if (!this._rootMesh) {
  413. this._rootMesh = new Mesh("BackgroundHelper", this._scene);
  414. }
  415. this._rootMesh.rotation.y = this._options.backgroundYRotation;
  416. const sceneSize = this._getSceneSize();
  417. if (this._options.createGround) {
  418. this._setupGround(sceneSize);
  419. this._setupGroundMaterial();
  420. this._setupGroundDiffuseTexture();
  421. if (this._options.enableGroundMirror) {
  422. this._setupGroundMirrorTexture(sceneSize);
  423. }
  424. this._setupMirrorInGroundMaterial();
  425. }
  426. if (this._options.createSkybox) {
  427. this._setupSkybox(sceneSize);
  428. this._setupSkyboxMaterial();
  429. this._setupSkyboxReflectionTexture();
  430. }
  431. this._rootMesh.position.x = sceneSize.rootPosition.x;
  432. this._rootMesh.position.z = sceneSize.rootPosition.z;
  433. this._rootMesh.position.y = sceneSize.rootPosition.y;
  434. }
  435. /**
  436. * Get the scene sizes according to the setup.
  437. */
  438. private _getSceneSize(): ISceneSize {
  439. let groundSize = this._options.groundSize;
  440. let skyboxSize = this._options.skyboxSize;
  441. let rootPosition = this._options.rootPosition;
  442. if (!this._scene.meshes || this._scene.meshes.length === 1) { // 1 only means the root of the helper.
  443. return { groundSize, skyboxSize, rootPosition };
  444. }
  445. const sceneExtends = this._scene.getWorldExtends((mesh) => {
  446. return (mesh !== this._ground && mesh !== this._rootMesh && mesh !== this._skybox);
  447. });
  448. const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
  449. if (this._options.sizeAuto) {
  450. if (this._scene.activeCamera instanceof ArcRotateCamera &&
  451. this._scene.activeCamera.upperRadiusLimit) {
  452. groundSize = this._scene.activeCamera.upperRadiusLimit * 2;
  453. skyboxSize = groundSize;
  454. }
  455. const sceneDiagonalLenght = sceneDiagonal.length();
  456. if (sceneDiagonalLenght > groundSize) {
  457. groundSize = sceneDiagonalLenght * 2;
  458. skyboxSize = groundSize;
  459. }
  460. // 10 % bigger.
  461. groundSize *= 1.1;
  462. skyboxSize *= 1.5;
  463. rootPosition = sceneExtends.min.add(sceneDiagonal.scale(0.5));
  464. rootPosition.y = sceneExtends.min.y - this._options.groundYBias;
  465. }
  466. return { groundSize, skyboxSize, rootPosition };
  467. }
  468. /**
  469. * Setup the ground according to the specified options.
  470. */
  471. private _setupGround(sceneSize: ISceneSize): void {
  472. if (!this._ground || this._ground.isDisposed()) {
  473. this._ground = Mesh.CreatePlane("BackgroundPlane", sceneSize.groundSize, this._scene);
  474. this._ground.rotation.x = Math.PI / 2; // Face up by default.
  475. this._ground.parent = this._rootMesh;
  476. this._ground.onDisposeObservable.add(() => { this._ground = null; });
  477. }
  478. this._ground.receiveShadows = this._options.enableGroundShadow;
  479. }
  480. /**
  481. * Setup the ground material according to the specified options.
  482. */
  483. private _setupGroundMaterial(): void {
  484. if (!this._groundMaterial) {
  485. this._groundMaterial = new BackgroundMaterial("BackgroundPlaneMaterial", this._scene);
  486. }
  487. this._groundMaterial.alpha = this._options.groundOpacity;
  488. this._groundMaterial.alphaMode = Constants.ALPHA_PREMULTIPLIED_PORTERDUFF;
  489. this._groundMaterial.shadowLevel = this._options.groundShadowLevel;
  490. this._groundMaterial.primaryColor = this._options.groundColor;
  491. this._groundMaterial.useRGBColor = false;
  492. this._groundMaterial.enableNoise = true;
  493. if (this._ground) {
  494. this._ground.material = this._groundMaterial;
  495. }
  496. }
  497. /**
  498. * Setup the ground diffuse texture according to the specified options.
  499. */
  500. private _setupGroundDiffuseTexture(): void {
  501. if (!this._groundMaterial) {
  502. return;
  503. }
  504. if (this._groundTexture) {
  505. return;
  506. }
  507. if (this._options.groundTexture instanceof BaseTexture) {
  508. this._groundMaterial.diffuseTexture = this._options.groundTexture;
  509. return;
  510. }
  511. const diffuseTexture = new Texture(this._options.groundTexture, this._scene, undefined, undefined, undefined, undefined, this._errorHandler);
  512. diffuseTexture.gammaSpace = false;
  513. diffuseTexture.hasAlpha = true;
  514. this._groundMaterial.diffuseTexture = diffuseTexture;
  515. }
  516. /**
  517. * Setup the ground mirror texture according to the specified options.
  518. */
  519. private _setupGroundMirrorTexture(sceneSize: ISceneSize): void {
  520. let wrapping = Texture.CLAMP_ADDRESSMODE;
  521. if (!this._groundMirror) {
  522. this._groundMirror = new MirrorTexture("BackgroundPlaneMirrorTexture",
  523. { ratio: this._options.groundMirrorSizeRatio },
  524. this._scene,
  525. false,
  526. this._options.groundMirrorTextureType,
  527. Texture.BILINEAR_SAMPLINGMODE,
  528. true);
  529. this._groundMirror.mirrorPlane = new Plane(0, -1, 0, sceneSize.rootPosition.y);
  530. this._groundMirror.anisotropicFilteringLevel = 1;
  531. this._groundMirror.wrapU = wrapping;
  532. this._groundMirror.wrapV = wrapping;
  533. this._groundMirror.gammaSpace = false;
  534. if (this._groundMirror.renderList) {
  535. for (let i = 0; i < this._scene.meshes.length; i++) {
  536. const mesh = this._scene.meshes[i];
  537. if (mesh !== this._ground &&
  538. mesh !== this._skybox &&
  539. mesh !== this._rootMesh) {
  540. this._groundMirror.renderList.push(mesh);
  541. }
  542. }
  543. }
  544. }
  545. this._groundMirror.clearColor = new Color4(
  546. this._options.groundColor.r,
  547. this._options.groundColor.g,
  548. this._options.groundColor.b,
  549. 1);
  550. this._groundMirror.adaptiveBlurKernel = this._options.groundMirrorBlurKernel;
  551. }
  552. /**
  553. * Setup the ground to receive the mirror texture.
  554. */
  555. private _setupMirrorInGroundMaterial(): void {
  556. if (this._groundMaterial) {
  557. this._groundMaterial.reflectionTexture = this._groundMirror;
  558. this._groundMaterial.reflectionFresnel = true;
  559. this._groundMaterial.reflectionAmount = this._options.groundMirrorAmount;
  560. this._groundMaterial.reflectionStandardFresnelWeight = this._options.groundMirrorFresnelWeight;
  561. this._groundMaterial.reflectionFalloffDistance = this._options.groundMirrorFallOffDistance;
  562. }
  563. }
  564. /**
  565. * Setup the skybox according to the specified options.
  566. */
  567. private _setupSkybox(sceneSize: ISceneSize): void {
  568. if (!this._skybox || this._skybox.isDisposed()) {
  569. this._skybox = Mesh.CreateBox("BackgroundSkybox", sceneSize.skyboxSize, this._scene, undefined, Mesh.BACKSIDE);
  570. this._skybox.onDisposeObservable.add(() => { this._skybox = null; });
  571. }
  572. this._skybox.parent = this._rootMesh;
  573. }
  574. /**
  575. * Setup the skybox material according to the specified options.
  576. */
  577. private _setupSkyboxMaterial(): void {
  578. if (!this._skybox) {
  579. return;
  580. }
  581. if (!this._skyboxMaterial) {
  582. this._skyboxMaterial = new BackgroundMaterial("BackgroundSkyboxMaterial", this._scene);
  583. }
  584. this._skyboxMaterial.useRGBColor = false;
  585. this._skyboxMaterial.primaryColor = this._options.skyboxColor;
  586. this._skyboxMaterial.enableNoise = true;
  587. this._skybox.material = this._skyboxMaterial;
  588. }
  589. /**
  590. * Setup the skybox reflection texture according to the specified options.
  591. */
  592. private _setupSkyboxReflectionTexture(): void {
  593. if (!this._skyboxMaterial) {
  594. return;
  595. }
  596. if (this._skyboxTexture) {
  597. return;
  598. }
  599. if (this._options.skyboxTexture instanceof BaseTexture) {
  600. this._skyboxMaterial.reflectionTexture = this._options.skyboxTexture;
  601. return;
  602. }
  603. this._skyboxTexture = new CubeTexture(this._options.skyboxTexture, this._scene, undefined, undefined, undefined, undefined, this._errorHandler);
  604. this._skyboxTexture.coordinatesMode = Texture.SKYBOX_MODE;
  605. this._skyboxTexture.gammaSpace = false;
  606. this._skyboxMaterial.reflectionTexture = this._skyboxTexture;
  607. }
  608. private _errorHandler = (message?: string, exception?: any) => {
  609. this.onErrorObservable.notifyObservers({ message: message, exception: exception });
  610. }
  611. /**
  612. * Dispose all the elements created by the Helper.
  613. */
  614. public dispose(): void {
  615. if (this._groundMaterial) {
  616. this._groundMaterial.dispose(true, true);
  617. }
  618. if (this._skyboxMaterial) {
  619. this._skyboxMaterial.dispose(true, true);
  620. }
  621. this._rootMesh.dispose(false);
  622. }
  623. }