layer.js 9.3 KB

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