environmentHelper.ts 23 KB

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