babylon.layer.ts 10 KB

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