cubeTexture.ts 12 KB

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