babylon.cubeTexture.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. module BABYLON {
  2. /**
  3. * Class for creating a cube texture
  4. */
  5. export class CubeTexture extends BaseTexture {
  6. /**
  7. * The url of the texture
  8. */
  9. public url: string;
  10. /**
  11. * Gets or sets the center of the bounding box associated with the cube texture
  12. * It must define where the camera used to render the texture was set
  13. */
  14. public boundingBoxPosition = Vector3.Zero();
  15. private _boundingBoxSize: Vector3;
  16. /**
  17. * Gets or sets the size of the bounding box associated with the cube texture
  18. * When defined, the cubemap will switch to local mode
  19. * @see https://community.arm.com/graphics/b/blog/posts/reflections-based-on-local-cubemaps-in-unity
  20. * @example https://www.babylonjs-playground.com/#RNASML
  21. */
  22. public set boundingBoxSize(value: Vector3) {
  23. if (this._boundingBoxSize && this._boundingBoxSize.equals(value)) {
  24. return;
  25. }
  26. this._boundingBoxSize = value;
  27. let scene = this.getScene();
  28. if (scene) {
  29. scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
  30. }
  31. }
  32. /**
  33. * Returns the bounding box size
  34. */
  35. public get boundingBoxSize(): Vector3 {
  36. return this._boundingBoxSize;
  37. }
  38. protected _rotationY: number = 0;
  39. /**
  40. * Sets texture matrix rotation angle around Y axis in radians.
  41. */
  42. @serialize("rotationY")
  43. public set rotationY(value: number) {
  44. this._rotationY = value;
  45. this.setReflectionTextureMatrix(BABYLON.Matrix.RotationY(this._rotationY));
  46. }
  47. /**
  48. * Gets texture matrix rotation angle around Y axis radians.
  49. */
  50. public get rotationY(): number {
  51. return this._rotationY;
  52. }
  53. private _noMipmap: boolean;
  54. private _files: string[];
  55. private _extensions: string[];
  56. private _textureMatrix: Matrix;
  57. private _format: number;
  58. private _createPolynomials: boolean;
  59. /** @hidden */
  60. public readonly _prefiltered: boolean = false;
  61. /**
  62. * Creates a cube texture from an array of image urls
  63. * @param files Array of image urls
  64. * @param scene Babylon.js scene
  65. * @param noMipmap Specifies if mip maps are not used
  66. * @returns A cube texture
  67. */
  68. public static CreateFromImages(files: string[], scene: Scene, noMipmap?: boolean): CubeTexture {
  69. let rootUrlKey = "";
  70. files.forEach(url => rootUrlKey += url);
  71. return new CubeTexture(rootUrlKey, scene, null, noMipmap, files);
  72. }
  73. /**
  74. * Creates and return a texture created from prefilterd data by tools like IBL Baker or Lys.
  75. * @param url defines the url of the prefiltered texture
  76. * @param scene defines the scene the texture is attached to
  77. * @param forcedExtension defines the extension of the file if different from the url
  78. * @param createPolynomials defines whether or not to create polynomial harmonics from the texture data if necessary
  79. * @return the prefiltered texture
  80. */
  81. public static CreateFromPrefilteredData(url: string, scene: Scene, forcedExtension: any = null, createPolynomials: boolean = true) {
  82. return new CubeTexture(url, scene, null, false, null, null, null, undefined, true, forcedExtension, createPolynomials);
  83. }
  84. /**
  85. * Creates a cube texture to use with reflection for instance. It can be based upon dds or six images as well
  86. * as prefiltered data.
  87. * @param rootUrl defines the url of the texture or the root name of the six images
  88. * @param scene defines the scene the texture is attached to
  89. * @param extensions defines the suffixes add to the picture name in case six images are in use like _px.jpg...
  90. * @param noMipmap defines if mipmaps should be created or not
  91. * @param files defines the six files to load for the different faces
  92. * @param onLoad defines a callback triggered at the end of the file load if no errors occured
  93. * @param onError defines a callback triggered in case of error during load
  94. * @param format defines the internal format to use for the texture once loaded
  95. * @param prefiltered defines whether or not the texture is created from prefiltered data
  96. * @param forcedExtension defines the extensions to use (force a special type of file to load) in case it is different from the file name
  97. * @param createPolynomials defines whether or not to create polynomial harmonics from the texture data if necessary
  98. * @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
  99. * @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
  100. * @return the cube texture
  101. */
  102. constructor(rootUrl: string, scene: Scene, extensions: Nullable<string[]> = null, noMipmap: boolean = false, files: Nullable<string[]> = null,
  103. onLoad: Nullable<() => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null, format: number = Engine.TEXTUREFORMAT_RGBA, prefiltered = false,
  104. forcedExtension: any = null, createPolynomials: boolean = false,
  105. lodScale: number = 0.8, lodOffset: number = 0) {
  106. super(scene);
  107. this.name = rootUrl;
  108. this.url = rootUrl;
  109. this._noMipmap = noMipmap;
  110. this.hasAlpha = false;
  111. this._format = format;
  112. this.isCube = true;
  113. this._textureMatrix = Matrix.Identity();
  114. this._createPolynomials = createPolynomials;
  115. this.coordinatesMode = Texture.CUBIC_MODE;
  116. if (!rootUrl && !files) {
  117. return;
  118. }
  119. const lastDot = rootUrl.lastIndexOf(".");
  120. const extension = forcedExtension ? forcedExtension : (lastDot > -1 ? rootUrl.substring(lastDot).toLowerCase() : "");
  121. const isDDS = (extension === ".dds");
  122. const isEnv = (extension === ".env");
  123. if (isEnv) {
  124. this.gammaSpace = false;
  125. this._prefiltered = false;
  126. }
  127. else {
  128. this._prefiltered = prefiltered;
  129. if (prefiltered) {
  130. this.gammaSpace = false;
  131. }
  132. }
  133. this._texture = this._getFromCache(rootUrl, noMipmap);
  134. if (!files) {
  135. if (!isEnv && !isDDS && !extensions) {
  136. extensions = ["_px.jpg", "_py.jpg", "_pz.jpg", "_nx.jpg", "_ny.jpg", "_nz.jpg"];
  137. }
  138. files = [];
  139. if (extensions) {
  140. for (var index = 0; index < extensions.length; index++) {
  141. files.push(rootUrl + extensions[index]);
  142. }
  143. }
  144. }
  145. this._files = files;
  146. if (!this._texture) {
  147. if (!scene.useDelayedTextureLoading) {
  148. if (prefiltered) {
  149. this._texture = scene.getEngine().createPrefilteredCubeTexture(rootUrl, scene, lodScale, lodOffset, onLoad, onError, format, forcedExtension, this._createPolynomials);
  150. }
  151. else {
  152. this._texture = scene.getEngine().createCubeTexture(rootUrl, scene, files, noMipmap, onLoad, onError, this._format, forcedExtension, false, lodScale, lodOffset);
  153. }
  154. } else {
  155. this.delayLoadState = Engine.DELAYLOADSTATE_NOTLOADED;
  156. }
  157. } else if (onLoad) {
  158. if (this._texture.isReady) {
  159. Tools.SetImmediate(() => onLoad());
  160. } else {
  161. this._texture.onLoadedObservable.add(onLoad);
  162. }
  163. }
  164. }
  165. /**
  166. * Delays loading of the cube texture
  167. */
  168. public delayLoad(): void {
  169. if (this.delayLoadState !== Engine.DELAYLOADSTATE_NOTLOADED) {
  170. return;
  171. }
  172. let scene = this.getScene();
  173. if (!scene) {
  174. return;
  175. }
  176. this.delayLoadState = Engine.DELAYLOADSTATE_LOADED;
  177. this._texture = this._getFromCache(this.url, this._noMipmap);
  178. if (!this._texture) {
  179. if (this._prefiltered) {
  180. this._texture = scene.getEngine().createPrefilteredCubeTexture(this.url, scene, this.lodGenerationScale, this.lodGenerationOffset, undefined, undefined, this._format, undefined, this._createPolynomials);
  181. }
  182. else {
  183. this._texture = scene.getEngine().createCubeTexture(this.url, scene, this._files, this._noMipmap, undefined, undefined, this._format);
  184. }
  185. }
  186. }
  187. /**
  188. * Returns the reflection texture matrix
  189. * @returns Reflection texture matrix
  190. */
  191. public getReflectionTextureMatrix(): Matrix {
  192. return this._textureMatrix;
  193. }
  194. /**
  195. * Sets the reflection texture matrix
  196. * @param value Reflection texture matrix
  197. */
  198. public setReflectionTextureMatrix(value: Matrix): void {
  199. this._textureMatrix = value;
  200. }
  201. /**
  202. * Parses text to create a cube texture
  203. * @param parsedTexture Serialized text to create a cube texture
  204. * @param scene BABYLON.Scene
  205. * @param rootUrl The root url of the cube texture
  206. * @returns A cube texture
  207. */
  208. public static Parse(parsedTexture: any, scene: Scene, rootUrl: string): CubeTexture {
  209. var texture = SerializationHelper.Parse(() => {
  210. var prefiltered:boolean = false;
  211. if (parsedTexture.prefiltered) {
  212. prefiltered = parsedTexture.prefiltered;
  213. }
  214. return new CubeTexture(rootUrl + parsedTexture.name, scene, parsedTexture.extensions, false, null, null, null, undefined, prefiltered);
  215. }, parsedTexture, scene);
  216. // Local Cubemaps
  217. if (parsedTexture.boundingBoxPosition) {
  218. texture.boundingBoxPosition = Vector3.FromArray(parsedTexture.boundingBoxPosition);
  219. }
  220. if (parsedTexture.boundingBoxSize) {
  221. texture.boundingBoxSize = Vector3.FromArray(parsedTexture.boundingBoxSize);
  222. }
  223. // Animations
  224. if (parsedTexture.animations) {
  225. for (var animationIndex = 0; animationIndex < parsedTexture.animations.length; animationIndex++) {
  226. var parsedAnimation = parsedTexture.animations[animationIndex];
  227. texture.animations.push(Animation.Parse(parsedAnimation));
  228. }
  229. }
  230. return texture;
  231. }
  232. /**
  233. * Makes a clone, or deep copy, of the cube texture
  234. * @returns A cube texture
  235. */
  236. public clone(): CubeTexture {
  237. return SerializationHelper.Clone(() => {
  238. let scene = this.getScene();
  239. if (!scene) {
  240. return this;
  241. }
  242. return new CubeTexture(this.url, scene, this._extensions, this._noMipmap, this._files);
  243. }, this);
  244. }
  245. }
  246. }