layer.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. import { Observer, Observable } from "../Misc/observable";
  2. import { Nullable } from "../types";
  3. import { Scene } from "../scene";
  4. import { Vector2 } from "../Maths/math.vector";
  5. import { Color4 } from '../Maths/math.color';
  6. import { EngineStore } from "../Engines/engineStore";
  7. import { VertexBuffer } from "../Meshes/buffer";
  8. import { Effect } from "../Materials/effect";
  9. import { Material } from "../Materials/material";
  10. import { Texture } from "../Materials/Textures/texture";
  11. import { SceneComponentConstants } from "../sceneComponent";
  12. import { _TimeToken } from "../Instrumentation/timeToken";
  13. import { LayerSceneComponent } from "./layerSceneComponent";
  14. import { Constants } from "../Engines/constants";
  15. import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
  16. import "../Shaders/layer.fragment";
  17. import "../Shaders/layer.vertex";
  18. import { DataBuffer } from '../Meshes/dataBuffer';
  19. /**
  20. * This represents a full screen 2d layer.
  21. * This can be useful to display a picture in the background of your scene for instance.
  22. * @see https://www.babylonjs-playground.com/#08A2BS#1
  23. */
  24. export class Layer {
  25. /**
  26. * Define the texture the layer should display.
  27. */
  28. public texture: Nullable<Texture>;
  29. /**
  30. * Is the layer in background or foreground.
  31. */
  32. public isBackground: boolean;
  33. /**
  34. * Define the color of the layer (instead of texture).
  35. */
  36. public color: Color4;
  37. /**
  38. * Define the scale of the layer in order to zoom in out of the texture.
  39. */
  40. public scale = new Vector2(1, 1);
  41. /**
  42. * Define an offset for the layer in order to shift the texture.
  43. */
  44. public offset = new Vector2(0, 0);
  45. /**
  46. * Define the alpha blending mode used in the layer in case the texture or color has an alpha.
  47. */
  48. public alphaBlendingMode = Constants.ALPHA_COMBINE;
  49. /**
  50. * Define if the layer should alpha test or alpha blend with the rest of the scene.
  51. * Alpha test will not mix with the background color in case of transparency.
  52. * It will either use the texture color or the background depending on the alpha value of the current pixel.
  53. */
  54. public alphaTest: boolean;
  55. /**
  56. * Define a mask to restrict the layer to only some of the scene cameras.
  57. */
  58. public layerMask: number = 0x0FFFFFFF;
  59. /**
  60. * Define the list of render target the layer is visible into.
  61. */
  62. public renderTargetTextures: RenderTargetTexture[] = [];
  63. /**
  64. * Define if the layer is only used in renderTarget or if it also
  65. * renders in the main frame buffer of the canvas.
  66. */
  67. public renderOnlyInRenderTargetTextures = false;
  68. private _scene: Scene;
  69. private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
  70. private _indexBuffer: Nullable<DataBuffer>;
  71. private _effect: Effect;
  72. private _previousDefines: string;
  73. /**
  74. * An event triggered when the layer is disposed.
  75. */
  76. public onDisposeObservable = new Observable<Layer>();
  77. private _onDisposeObserver: Nullable<Observer<Layer>>;
  78. /**
  79. * Back compatibility with callback before the onDisposeObservable existed.
  80. * The set callback will be triggered when the layer has been disposed.
  81. */
  82. public set onDispose(callback: () => void) {
  83. if (this._onDisposeObserver) {
  84. this.onDisposeObservable.remove(this._onDisposeObserver);
  85. }
  86. this._onDisposeObserver = this.onDisposeObservable.add(callback);
  87. }
  88. /**
  89. * An event triggered before rendering the scene
  90. */
  91. public onBeforeRenderObservable = new Observable<Layer>();
  92. private _onBeforeRenderObserver: Nullable<Observer<Layer>>;
  93. /**
  94. * Back compatibility with callback before the onBeforeRenderObservable existed.
  95. * The set callback will be triggered just before rendering the layer.
  96. */
  97. public set onBeforeRender(callback: () => void) {
  98. if (this._onBeforeRenderObserver) {
  99. this.onBeforeRenderObservable.remove(this._onBeforeRenderObserver);
  100. }
  101. this._onBeforeRenderObserver = this.onBeforeRenderObservable.add(callback);
  102. }
  103. /**
  104. * An event triggered after rendering the scene
  105. */
  106. public onAfterRenderObservable = new Observable<Layer>();
  107. private _onAfterRenderObserver: Nullable<Observer<Layer>>;
  108. /**
  109. * Back compatibility with callback before the onAfterRenderObservable existed.
  110. * The set callback will be triggered just after rendering the layer.
  111. */
  112. public set onAfterRender(callback: () => void) {
  113. if (this._onAfterRenderObserver) {
  114. this.onAfterRenderObservable.remove(this._onAfterRenderObserver);
  115. }
  116. this._onAfterRenderObserver = this.onAfterRenderObservable.add(callback);
  117. }
  118. /**
  119. * Instantiates a new layer.
  120. * This represents a full screen 2d layer.
  121. * This can be useful to display a picture in the background of your scene for instance.
  122. * @see https://www.babylonjs-playground.com/#08A2BS#1
  123. * @param name Define the name of the layer in the scene
  124. * @param imgUrl Define the url of the texture to display in the layer
  125. * @param scene Define the scene the layer belongs to
  126. * @param isBackground Defines whether the layer is displayed in front or behind the scene
  127. * @param color Defines a color for the layer
  128. */
  129. constructor(
  130. /**
  131. * Define the name of the layer.
  132. */
  133. public name: string,
  134. imgUrl: Nullable<string>,
  135. scene: Nullable<Scene>,
  136. isBackground?: boolean, color?: Color4) {
  137. this.texture = imgUrl ? new Texture(imgUrl, scene, true) : null;
  138. this.isBackground = isBackground === undefined ? true : isBackground;
  139. this.color = color === undefined ? new Color4(1, 1, 1, 1) : color;
  140. this._scene = <Scene>(scene || EngineStore.LastCreatedScene);
  141. let layerComponent = this._scene._getComponent(SceneComponentConstants.NAME_LAYER) as LayerSceneComponent;
  142. if (!layerComponent) {
  143. layerComponent = new LayerSceneComponent(this._scene);
  144. this._scene._addComponent(layerComponent);
  145. }
  146. this._scene.layers.push(this);
  147. var engine = this._scene.getEngine();
  148. // VBO
  149. var vertices = [];
  150. vertices.push(1, 1);
  151. vertices.push(-1, 1);
  152. vertices.push(-1, -1);
  153. vertices.push(1, -1);
  154. var vertexBuffer = new VertexBuffer(engine, vertices, VertexBuffer.PositionKind, false, false, 2);
  155. this._vertexBuffers[VertexBuffer.PositionKind] = vertexBuffer;
  156. this._createIndexBuffer();
  157. }
  158. private _createIndexBuffer(): void {
  159. var engine = this._scene.getEngine();
  160. // Indices
  161. var indices = [];
  162. indices.push(0);
  163. indices.push(1);
  164. indices.push(2);
  165. indices.push(0);
  166. indices.push(2);
  167. indices.push(3);
  168. this._indexBuffer = engine.createIndexBuffer(indices);
  169. }
  170. /** @hidden */
  171. public _rebuild(): void {
  172. let vb = this._vertexBuffers[VertexBuffer.PositionKind];
  173. if (vb) {
  174. vb._rebuild();
  175. }
  176. this._createIndexBuffer();
  177. }
  178. /**
  179. * Renders the layer in the scene.
  180. */
  181. public render(): void {
  182. var engine = this._scene.getEngine();
  183. var defines = "";
  184. if (this.alphaTest) {
  185. defines = "#define ALPHATEST";
  186. }
  187. if (this.texture && !this.texture.gammaSpace) {
  188. defines += "\r\n#define LINEAR";
  189. }
  190. if (this._previousDefines !== defines) {
  191. this._previousDefines = defines;
  192. this._effect = engine.createEffect("layer",
  193. [VertexBuffer.PositionKind],
  194. ["textureMatrix", "color", "scale", "offset"],
  195. ["textureSampler"], defines);
  196. }
  197. var currentEffect = this._effect;
  198. // Check
  199. if (!currentEffect || !currentEffect.isReady() || !this.texture || !this.texture.isReady()) {
  200. return;
  201. }
  202. var engine = this._scene.getEngine();
  203. this.onBeforeRenderObservable.notifyObservers(this);
  204. // Render
  205. engine.enableEffect(currentEffect);
  206. engine.setState(false);
  207. // Texture
  208. currentEffect.setTexture("textureSampler", this.texture);
  209. currentEffect.setMatrix("textureMatrix", this.texture.getTextureMatrix());
  210. // Color
  211. currentEffect.setFloat4("color", this.color.r, this.color.g, this.color.b, this.color.a);
  212. // Scale / offset
  213. currentEffect.setVector2("offset", this.offset);
  214. currentEffect.setVector2("scale", this.scale);
  215. // VBOs
  216. engine.bindBuffers(this._vertexBuffers, this._indexBuffer, currentEffect);
  217. // Draw order
  218. if (!this.alphaTest) {
  219. engine.setAlphaMode(this.alphaBlendingMode);
  220. engine.drawElementsType(Material.TriangleFillMode, 0, 6);
  221. engine.setAlphaMode(Constants.ALPHA_DISABLE);
  222. }
  223. else {
  224. engine.drawElementsType(Material.TriangleFillMode, 0, 6);
  225. }
  226. this.onAfterRenderObservable.notifyObservers(this);
  227. }
  228. /**
  229. * Disposes and releases the associated ressources.
  230. */
  231. public dispose(): void {
  232. var vertexBuffer = this._vertexBuffers[VertexBuffer.PositionKind];
  233. if (vertexBuffer) {
  234. vertexBuffer.dispose();
  235. this._vertexBuffers[VertexBuffer.PositionKind] = null;
  236. }
  237. if (this._indexBuffer) {
  238. this._scene.getEngine()._releaseBuffer(this._indexBuffer);
  239. this._indexBuffer = null;
  240. }
  241. if (this.texture) {
  242. this.texture.dispose();
  243. this.texture = null;
  244. }
  245. // Clean RTT list
  246. this.renderTargetTextures = [];
  247. // Remove from scene
  248. var index = this._scene.layers.indexOf(this);
  249. this._scene.layers.splice(index, 1);
  250. // Callback
  251. this.onDisposeObservable.notifyObservers(this);
  252. this.onDisposeObservable.clear();
  253. this.onAfterRenderObservable.clear();
  254. this.onBeforeRenderObservable.clear();
  255. }
  256. }