multiRenderTarget.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. import { Scene } from "../../scene";
  2. import { Engine } from "../../Engines/engine";
  3. import { InternalTexture } from "../../Materials/Textures/internalTexture";
  4. import { Texture } from "../../Materials/Textures/texture";
  5. import { RenderTargetTexture } from "../../Materials/Textures/renderTargetTexture";
  6. import { Constants } from "../../Engines/constants";
  7. import "../../Engines/Extensions/engine.multiRender";
  8. /**
  9. * Creation options of the multi render target texture.
  10. */
  11. export interface IMultiRenderTargetOptions {
  12. /**
  13. * Define if the texture needs to create mip maps after render.
  14. */
  15. generateMipMaps?: boolean;
  16. /**
  17. * Define the types of all the draw buffers we want to create
  18. */
  19. types?: number[];
  20. /**
  21. * Define the sampling modes of all the draw buffers we want to create
  22. */
  23. samplingModes?: number[];
  24. /**
  25. * Define if a depth buffer is required
  26. */
  27. generateDepthBuffer?: boolean;
  28. /**
  29. * Define if a stencil buffer is required
  30. */
  31. generateStencilBuffer?: boolean;
  32. /**
  33. * Define if a depth texture is required instead of a depth buffer
  34. */
  35. generateDepthTexture?: boolean;
  36. /**
  37. * Define the number of desired draw buffers
  38. */
  39. textureCount?: number;
  40. /**
  41. * Define if aspect ratio should be adapted to the texture or stay the scene one
  42. */
  43. doNotChangeAspectRatio?: boolean;
  44. /**
  45. * Define the default type of the buffers we are creating
  46. */
  47. defaultType?: number;
  48. }
  49. /**
  50. * A multi render target, like a render target provides the ability to render to a texture.
  51. * Unlike the render target, it can render to several draw buffers in one draw.
  52. * This is specially interesting in deferred rendering or for any effects requiring more than
  53. * just one color from a single pass.
  54. */
  55. export class MultiRenderTarget extends RenderTargetTexture {
  56. private _internalTextures: InternalTexture[];
  57. private _textures: Texture[];
  58. private _multiRenderTargetOptions: IMultiRenderTargetOptions;
  59. private _count: number;
  60. /**
  61. * Get if draw buffers are currently supported by the used hardware and browser.
  62. */
  63. public get isSupported(): boolean {
  64. return this._getEngine()!.webGLVersion > 1 || this._getEngine()!.getCaps().drawBuffersExtension;
  65. }
  66. /**
  67. * Get the list of textures generated by the multi render target.
  68. */
  69. public get textures(): Texture[] {
  70. return this._textures;
  71. }
  72. /**
  73. * Gets the number of textures in this MRT. This number can be different from `_textures.length` in case a depth texture is generated.
  74. */
  75. public get count(): number {
  76. return this._count;
  77. }
  78. /**
  79. * Get the depth texture generated by the multi render target if options.generateDepthTexture has been set
  80. */
  81. public get depthTexture(): Texture {
  82. return this._textures[this._textures.length - 1];
  83. }
  84. /**
  85. * Set the wrapping mode on U of all the textures we are rendering to.
  86. * Can be any of the Texture. (CLAMP_ADDRESSMODE, MIRROR_ADDRESSMODE or WRAP_ADDRESSMODE)
  87. */
  88. public set wrapU(wrap: number) {
  89. if (this._textures) {
  90. for (var i = 0; i < this._textures.length; i++) {
  91. this._textures[i].wrapU = wrap;
  92. }
  93. }
  94. }
  95. /**
  96. * Set the wrapping mode on V of all the textures we are rendering to.
  97. * Can be any of the Texture. (CLAMP_ADDRESSMODE, MIRROR_ADDRESSMODE or WRAP_ADDRESSMODE)
  98. */
  99. public set wrapV(wrap: number) {
  100. if (this._textures) {
  101. for (var i = 0; i < this._textures.length; i++) {
  102. this._textures[i].wrapV = wrap;
  103. }
  104. }
  105. }
  106. /**
  107. * Instantiate a new multi render target texture.
  108. * A multi render target, like a render target provides the ability to render to a texture.
  109. * Unlike the render target, it can render to several draw buffers in one draw.
  110. * This is specially interesting in deferred rendering or for any effects requiring more than
  111. * just one color from a single pass.
  112. * @param name Define the name of the texture
  113. * @param size Define the size of the buffers to render to
  114. * @param count Define the number of target we are rendering into
  115. * @param scene Define the scene the texture belongs to
  116. * @param options Define the options used to create the multi render target
  117. */
  118. constructor(name: string, size: any, count: number, scene: Scene, options?: IMultiRenderTargetOptions) {
  119. var generateMipMaps = options && options.generateMipMaps ? options.generateMipMaps : false;
  120. var generateDepthTexture = options && options.generateDepthTexture ? options.generateDepthTexture : false;
  121. var doNotChangeAspectRatio = !options || options.doNotChangeAspectRatio === undefined ? true : options.doNotChangeAspectRatio;
  122. super(name, size, scene, generateMipMaps, doNotChangeAspectRatio);
  123. if (!this.isSupported) {
  124. this.dispose();
  125. return;
  126. }
  127. var types: number[] = [];
  128. var samplingModes: number[] = [];
  129. this._initTypes(count, types, samplingModes, options);
  130. var generateDepthBuffer = !options || options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
  131. var generateStencilBuffer = !options || options.generateStencilBuffer === undefined ? false : options.generateStencilBuffer;
  132. this._size = size;
  133. this._multiRenderTargetOptions = {
  134. samplingModes: samplingModes,
  135. generateMipMaps: generateMipMaps,
  136. generateDepthBuffer: generateDepthBuffer,
  137. generateStencilBuffer: generateStencilBuffer,
  138. generateDepthTexture: generateDepthTexture,
  139. types: types,
  140. textureCount: count
  141. };
  142. this._count = count;
  143. this._createInternalTextures();
  144. this._createTextures();
  145. }
  146. private _initTypes(count: number, types: number[], samplingModes: number[], options?: IMultiRenderTargetOptions) {
  147. for (var i = 0; i < count; i++) {
  148. if (options && options.types && options.types[i] !== undefined) {
  149. types.push(options.types[i]);
  150. } else {
  151. types.push(options && options.defaultType ? options.defaultType : Constants.TEXTURETYPE_UNSIGNED_INT);
  152. }
  153. if (options && options.samplingModes && options.samplingModes[i] !== undefined) {
  154. samplingModes.push(options.samplingModes[i]);
  155. } else {
  156. samplingModes.push(Texture.BILINEAR_SAMPLINGMODE);
  157. }
  158. }
  159. }
  160. /** @hidden */
  161. public _rebuild(forceFullRebuild: boolean = false): void {
  162. this.releaseInternalTextures();
  163. this._createInternalTextures();
  164. if (forceFullRebuild) {
  165. this._createTextures();
  166. }
  167. for (var i = 0; i < this._internalTextures.length; i++) {
  168. var texture = this._textures[i];
  169. texture._texture = this._internalTextures[i];
  170. }
  171. // Keeps references to frame buffer and stencil/depth buffer
  172. this._texture = this._internalTextures[0];
  173. if (this.samples !== 1) {
  174. this._getEngine()!.updateMultipleRenderTargetTextureSampleCount(this._internalTextures, this.samples);
  175. }
  176. }
  177. private _createInternalTextures(): void {
  178. this._internalTextures = this._getEngine()!.createMultipleRenderTarget(this._size, this._multiRenderTargetOptions);
  179. }
  180. private _createTextures(): void {
  181. this._textures = [];
  182. for (var i = 0; i < this._internalTextures.length; i++) {
  183. var texture = new Texture(null, this.getScene());
  184. texture._texture = this._internalTextures[i];
  185. this._textures.push(texture);
  186. }
  187. // Keeps references to frame buffer and stencil/depth buffer
  188. this._texture = this._internalTextures[0];
  189. }
  190. /**
  191. * Replaces a texture within the MRT.
  192. * @param texture The new texture to insert in the MRT
  193. * @param index The index of the texture to replace
  194. */
  195. public replaceTexture(texture: Texture, index: number) {
  196. if (texture._texture) {
  197. this._textures[index] = texture;
  198. this._internalTextures[index] = texture._texture;
  199. }
  200. }
  201. /**
  202. * Define the number of samples used if MSAA is enabled.
  203. */
  204. public get samples(): number {
  205. return this._samples;
  206. }
  207. public set samples(value: number) {
  208. if (this._samples === value) {
  209. return;
  210. }
  211. this._samples = this._getEngine()!.updateMultipleRenderTargetTextureSampleCount(this._internalTextures, value);
  212. }
  213. /**
  214. * Resize all the textures in the multi render target.
  215. * Be careful as it will recreate all the data in the new texture.
  216. * @param size Define the new size
  217. */
  218. public resize(size: any) {
  219. this._size = size;
  220. this._rebuild();
  221. }
  222. /**
  223. * Changes the number of render targets in this MRT
  224. * Be careful as it will recreate all the data in the new texture.
  225. * @param count new texture count
  226. * @param options Specifies texture types and sampling modes for new textures
  227. */
  228. public updateCount(count: number, options?: IMultiRenderTargetOptions) {
  229. this._multiRenderTargetOptions.textureCount = count;
  230. this._count = count;
  231. const types: number[] = [];
  232. const samplingModes: number[] = [];
  233. this._initTypes(count, types, samplingModes, options);
  234. this._multiRenderTargetOptions.types = types;
  235. this._multiRenderTargetOptions.samplingModes = samplingModes;
  236. this._rebuild(true);
  237. }
  238. protected unbindFrameBuffer(engine: Engine, faceIndex: number): void {
  239. engine.unBindMultiColorAttachmentFramebuffer(this._internalTextures, this.isCube, () => {
  240. this.onAfterRenderObservable.notifyObservers(faceIndex);
  241. });
  242. }
  243. /**
  244. * Dispose the render targets and their associated resources
  245. */
  246. public dispose(): void {
  247. this.releaseInternalTextures();
  248. super.dispose();
  249. }
  250. /**
  251. * Release all the underlying texture used as draw buffers.
  252. */
  253. public releaseInternalTextures(): void {
  254. if (!this._internalTextures) {
  255. return;
  256. }
  257. for (var i = this._internalTextures.length - 1; i >= 0; i--) {
  258. if (this._internalTextures[i] !== undefined) {
  259. this._internalTextures[i].dispose();
  260. this._internalTextures.splice(i, 1);
  261. }
  262. }
  263. }
  264. }