multiRenderTarget.ts 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. /**
  60. * Get if draw buffers are currently supported by the used hardware and browser.
  61. */
  62. public get isSupported(): boolean {
  63. return this._engine.webGLVersion > 1 || this._engine.getCaps().drawBuffersExtension;
  64. }
  65. /**
  66. * Get the list of textures generated by the multi render target.
  67. */
  68. public get textures(): Texture[] {
  69. return this._textures;
  70. }
  71. /**
  72. * Get the depth texture generated by the multi render target if options.generateDepthTexture has been set
  73. */
  74. public get depthTexture(): Texture {
  75. return this._textures[this._textures.length - 1];
  76. }
  77. /**
  78. * Set the wrapping mode on U of all the textures we are rendering to.
  79. * Can be any of the Texture. (CLAMP_ADDRESSMODE, MIRROR_ADDRESSMODE or WRAP_ADDRESSMODE)
  80. */
  81. public set wrapU(wrap: number) {
  82. if (this._textures) {
  83. for (var i = 0; i < this._textures.length; i++) {
  84. this._textures[i].wrapU = wrap;
  85. }
  86. }
  87. }
  88. /**
  89. * Set the wrapping mode on V of all the textures we are rendering to.
  90. * Can be any of the Texture. (CLAMP_ADDRESSMODE, MIRROR_ADDRESSMODE or WRAP_ADDRESSMODE)
  91. */
  92. public set wrapV(wrap: number) {
  93. if (this._textures) {
  94. for (var i = 0; i < this._textures.length; i++) {
  95. this._textures[i].wrapV = wrap;
  96. }
  97. }
  98. }
  99. /**
  100. * Instantiate a new multi render target texture.
  101. * A multi render target, like a render target provides the ability to render to a texture.
  102. * Unlike the render target, it can render to several draw buffers in one draw.
  103. * This is specially interesting in deferred rendering or for any effects requiring more than
  104. * just one color from a single pass.
  105. * @param name Define the name of the texture
  106. * @param size Define the size of the buffers to render to
  107. * @param count Define the number of target we are rendering into
  108. * @param scene Define the scene the texture belongs to
  109. * @param options Define the options used to create the multi render target
  110. */
  111. constructor(name: string, size: any, count: number, scene: Scene, options?: IMultiRenderTargetOptions) {
  112. var generateMipMaps = options && options.generateMipMaps ? options.generateMipMaps : false;
  113. var generateDepthTexture = options && options.generateDepthTexture ? options.generateDepthTexture : false;
  114. var doNotChangeAspectRatio = !options || options.doNotChangeAspectRatio === undefined ? true : options.doNotChangeAspectRatio;
  115. super(name, size, scene, generateMipMaps, doNotChangeAspectRatio);
  116. this._engine = scene.getEngine();
  117. if (!this.isSupported) {
  118. this.dispose();
  119. return;
  120. }
  121. var types = [];
  122. var samplingModes = [];
  123. for (var i = 0; i < count; i++) {
  124. if (options && options.types && options.types[i] !== undefined) {
  125. types.push(options.types[i]);
  126. } else {
  127. types.push(options && options.defaultType ? options.defaultType : Constants.TEXTURETYPE_UNSIGNED_INT);
  128. }
  129. if (options && options.samplingModes && options.samplingModes[i] !== undefined) {
  130. samplingModes.push(options.samplingModes[i]);
  131. } else {
  132. samplingModes.push(Texture.BILINEAR_SAMPLINGMODE);
  133. }
  134. }
  135. var generateDepthBuffer = !options || options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
  136. var generateStencilBuffer = !options || options.generateStencilBuffer === undefined ? false : options.generateStencilBuffer;
  137. this._size = size;
  138. this._multiRenderTargetOptions = {
  139. samplingModes: samplingModes,
  140. generateMipMaps: generateMipMaps,
  141. generateDepthBuffer: generateDepthBuffer,
  142. generateStencilBuffer: generateStencilBuffer,
  143. generateDepthTexture: generateDepthTexture,
  144. types: types,
  145. textureCount: count
  146. };
  147. this._createInternalTextures();
  148. this._createTextures();
  149. }
  150. /** @hidden */
  151. public _rebuild(): void {
  152. this.releaseInternalTextures();
  153. this._createInternalTextures();
  154. for (var i = 0; i < this._internalTextures.length; i++) {
  155. var texture = this._textures[i];
  156. texture._texture = this._internalTextures[i];
  157. }
  158. // Keeps references to frame buffer and stencil/depth buffer
  159. this._texture = this._internalTextures[0];
  160. }
  161. private _createInternalTextures(): void {
  162. this._internalTextures = this._engine.createMultipleRenderTarget(this._size, this._multiRenderTargetOptions);
  163. }
  164. private _createTextures(): void {
  165. this._textures = [];
  166. for (var i = 0; i < this._internalTextures.length; i++) {
  167. var texture = new Texture(null, this.getScene());
  168. texture._texture = this._internalTextures[i];
  169. this._textures.push(texture);
  170. }
  171. // Keeps references to frame buffer and stencil/depth buffer
  172. this._texture = this._internalTextures[0];
  173. }
  174. /**
  175. * Define the number of samples used if MSAA is enabled.
  176. */
  177. public get samples(): number {
  178. return this._samples;
  179. }
  180. public set samples(value: number) {
  181. if (this._samples === value) {
  182. return;
  183. }
  184. this._samples = this._engine.updateMultipleRenderTargetTextureSampleCount(this._internalTextures, value);
  185. }
  186. /**
  187. * Resize all the textures in the multi render target.
  188. * Be carrefull as it will recreate all the data in the new texture.
  189. * @param size Define the new size
  190. */
  191. public resize(size: any) {
  192. this.releaseInternalTextures();
  193. this._internalTextures = this._engine.createMultipleRenderTarget(size, this._multiRenderTargetOptions);
  194. this._createInternalTextures();
  195. }
  196. protected unbindFrameBuffer(engine: Engine, faceIndex: number): void {
  197. engine.unBindMultiColorAttachmentFramebuffer(this._internalTextures, this.isCube, () => {
  198. this.onAfterRenderObservable.notifyObservers(faceIndex);
  199. });
  200. }
  201. /**
  202. * Dispose the render targets and their associated resources
  203. */
  204. public dispose(): void {
  205. this.releaseInternalTextures();
  206. super.dispose();
  207. }
  208. /**
  209. * Release all the underlying texture used as draw buffers.
  210. */
  211. public releaseInternalTextures(): void {
  212. if (!this._internalTextures) {
  213. return;
  214. }
  215. for (var i = this._internalTextures.length - 1; i >= 0; i--) {
  216. if (this._internalTextures[i] !== undefined) {
  217. this._internalTextures[i].dispose();
  218. this._internalTextures.splice(i, 1);
  219. }
  220. }
  221. }
  222. }