babylon.standardRenderingPipeline.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. var __extends = (this && this.__extends) || function (d, b) {
  2. for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
  3. function __() { this.constructor = d; }
  4. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  5. };
  6. var BABYLON;
  7. (function (BABYLON) {
  8. var StandardRenderingPipeline = (function (_super) {
  9. __extends(StandardRenderingPipeline, _super);
  10. /**
  11. * @constructor
  12. * @param {string} name - The rendering pipeline name
  13. * @param {BABYLON.Scene} scene - The scene linked to this pipeline
  14. * @param {any} ratio - The size of the postprocesses (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
  15. * @param {BABYLON.PostProcess} originalPostProcess - the custom original color post-process. Must be "reusable". Can be null.
  16. * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
  17. */
  18. function StandardRenderingPipeline(name, scene, ratio, originalPostProcess, cameras) {
  19. var _this = this;
  20. if (originalPostProcess === void 0) { originalPostProcess = null; }
  21. _super.call(this, scene.getEngine(), name);
  22. this.downSampleX4PostProcess = null;
  23. this.brightPassPostProcess = null;
  24. this.gaussianBlurHPostProcesses = [];
  25. this.gaussianBlurVPostProcesses = [];
  26. this.textureAdderPostProcess = null;
  27. this.depthOfFieldSourcePostProcess = null;
  28. this.depthOfFieldPostProcess = null;
  29. this.brightThreshold = 1.0;
  30. this.gaussianCoefficient = 0.25;
  31. this.gaussianMean = 1.0;
  32. this.gaussianStandardDeviation = 1.0;
  33. this.exposure = 1.0;
  34. this.lensTexture = null;
  35. this.depthOfFieldDistance = 10.0;
  36. this._depthRenderer = null;
  37. // Getters and setters
  38. this._blurEnabled = true;
  39. this._depthOfFieldEnabled = false;
  40. // Initialize
  41. this._scene = scene;
  42. // Create pass post-processe
  43. if (!originalPostProcess) {
  44. this.originalPostProcess = new BABYLON.PostProcess("HDRPass", "standard", [], [], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define PASS_POST_PROCESS", BABYLON.Engine.TEXTURETYPE_FLOAT);
  45. }
  46. else {
  47. this.originalPostProcess = originalPostProcess;
  48. }
  49. this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRPassPostProcess", function () { return _this.originalPostProcess; }, true));
  50. // Create down sample X4 post-process
  51. this._createDownSampleX4PostProcess(scene, ratio / 2);
  52. // Create bright pass post-process
  53. this._createBrightPassPostProcess(scene, ratio / 2);
  54. // Create gaussian blur post-processes (down sampling blurs)
  55. this._createGaussianBlurPostProcesses(scene, ratio / 2, 0);
  56. this._createGaussianBlurPostProcesses(scene, ratio / 4, 1);
  57. this._createGaussianBlurPostProcesses(scene, ratio / 8, 2);
  58. this._createGaussianBlurPostProcesses(scene, ratio / 16, 3);
  59. // Create texture adder post-process
  60. this._createTextureAdderPostProcess(scene, ratio);
  61. // Create depth-of-field source post-process
  62. this.depthOfFieldSourcePostProcess = new BABYLON.PostProcess("HDRDepthOfFieldSource", "standard", [], [], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define PASS_POST_PROCESS", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
  63. this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRDepthOfFieldSource", function () { return _this.depthOfFieldSourcePostProcess; }, true));
  64. // Create gaussian blur used by depth-of-field
  65. this._createGaussianBlurPostProcesses(scene, ratio / 2, 4);
  66. // Create depth-of-field post-process
  67. this._createDepthOfFieldPostProcess(scene, ratio);
  68. // Finish
  69. scene.postProcessRenderPipelineManager.addPipeline(this);
  70. if (cameras !== null) {
  71. scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
  72. }
  73. this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfFieldSource", cameras);
  74. this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH4", cameras);
  75. this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV4", cameras);
  76. this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfField", cameras);
  77. }
  78. Object.defineProperty(StandardRenderingPipeline.prototype, "BlurEnabled", {
  79. get: function () {
  80. return this._blurEnabled;
  81. },
  82. set: function (enabled) {
  83. if (enabled && !this._blurEnabled || !enabled && this._blurEnabled) {
  84. for (var i = 0; i < this.gaussianBlurHPostProcesses.length - 1; i++) {
  85. if (enabled) {
  86. this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurH" + i, this._scene.cameras);
  87. this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurV" + i, this._scene.cameras);
  88. }
  89. else {
  90. this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH" + i, this._scene.cameras);
  91. this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV" + i, this._scene.cameras);
  92. }
  93. }
  94. }
  95. this._blurEnabled = enabled;
  96. },
  97. enumerable: true,
  98. configurable: true
  99. });
  100. Object.defineProperty(StandardRenderingPipeline.prototype, "DepthOfFieldEnabled", {
  101. get: function () {
  102. return this._depthOfFieldEnabled;
  103. },
  104. set: function (enabled) {
  105. if (enabled && !this._depthOfFieldEnabled) {
  106. this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRDepthOfFieldSource", this._scene.cameras);
  107. this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurH4", this._scene.cameras);
  108. this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurV4", this._scene.cameras);
  109. this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRDepthOfField", this._scene.cameras);
  110. this._depthRenderer = this._scene.enableDepthRenderer();
  111. }
  112. else if (!enabled && this._depthOfFieldEnabled) {
  113. this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfFieldSource", this._scene.cameras);
  114. this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH4", this._scene.cameras);
  115. this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV4", this._scene.cameras);
  116. this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfField", this._scene.cameras);
  117. }
  118. this._depthOfFieldEnabled = enabled;
  119. },
  120. enumerable: true,
  121. configurable: true
  122. });
  123. // Down Sample X4 Post-Processs
  124. StandardRenderingPipeline.prototype._createDownSampleX4PostProcess = function (scene, ratio) {
  125. var _this = this;
  126. var downSampleX4Offsets = new Array(32);
  127. this.downSampleX4PostProcess = new BABYLON.PostProcess("HDRDownSampleX4", "standard", ["dsOffsets"], [], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define DOWN_SAMPLE_X4", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
  128. this.downSampleX4PostProcess.onApply = function (effect) {
  129. var id = 0;
  130. for (var i = -2; i < 2; i++) {
  131. for (var j = -2; j < 2; j++) {
  132. downSampleX4Offsets[id] = (i + 0.5) * (1.0 / _this.downSampleX4PostProcess.width);
  133. downSampleX4Offsets[id + 1] = (j + 0.5) * (1.0 / _this.downSampleX4PostProcess.height);
  134. id += 2;
  135. }
  136. }
  137. effect.setArray2("dsOffsets", downSampleX4Offsets);
  138. };
  139. // Add to pipeline
  140. this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRDownSampleX4", function () { return _this.downSampleX4PostProcess; }, true));
  141. };
  142. // Brightpass Post-Process
  143. StandardRenderingPipeline.prototype._createBrightPassPostProcess = function (scene, ratio) {
  144. var _this = this;
  145. var brightOffsets = new Array(8);
  146. this.brightPassPostProcess = new BABYLON.PostProcess("HDRBrightPass", "standard", ["dsOffsets", "brightThreshold"], [], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define BRIGHT_PASS", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
  147. this.brightPassPostProcess.onApply = function (effect) {
  148. var sU = (1.0 / _this.brightPassPostProcess.width);
  149. var sV = (1.0 / _this.brightPassPostProcess.height);
  150. brightOffsets[0] = -0.5 * sU;
  151. brightOffsets[1] = 0.5 * sV;
  152. brightOffsets[2] = 0.5 * sU;
  153. brightOffsets[3] = 0.5 * sV;
  154. brightOffsets[4] = -0.5 * sU;
  155. brightOffsets[5] = -0.5 * sV;
  156. brightOffsets[6] = 0.5 * sU;
  157. brightOffsets[7] = -0.5 * sV;
  158. effect.setArray2("dsOffsets", brightOffsets);
  159. effect.setFloat("brightThreshold", _this.brightThreshold);
  160. };
  161. // Add to pipeline
  162. this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRBrightPass", function () { return _this.brightPassPostProcess; }, true));
  163. };
  164. // Create gaussian blur H&V post-processes
  165. StandardRenderingPipeline.prototype._createGaussianBlurPostProcesses = function (scene, ratio, indice) {
  166. var _this = this;
  167. var blurOffsets = new Array(9);
  168. var blurWeights = new Array(9);
  169. var uniforms = ["blurOffsets", "blurWeights"];
  170. var callback = function (height) {
  171. return function (effect) {
  172. // Weights
  173. var x = 0.0;
  174. for (var i = 0; i < 9; i++) {
  175. x = (i - 4.0) / 4.0;
  176. blurWeights[i] =
  177. _this.gaussianCoefficient
  178. * (1.0 / Math.sqrt(2.0 * Math.PI * _this.gaussianStandardDeviation))
  179. * Math.exp((-((x - _this.gaussianMean) * (x - _this.gaussianMean))) / (2.0 * _this.gaussianStandardDeviation * _this.gaussianStandardDeviation));
  180. }
  181. var lastOutputDimensions = {
  182. width: scene.getEngine().getRenderWidth(),
  183. height: scene.getEngine().getRenderHeight()
  184. };
  185. for (var i = 0; i < 9; i++) {
  186. var value = (i - 4.0) * (1.0 / (height === true ? lastOutputDimensions.height : lastOutputDimensions.width));
  187. blurOffsets[i] = value;
  188. }
  189. effect.setArray("blurOffsets", blurOffsets);
  190. effect.setArray("blurWeights", blurWeights);
  191. };
  192. };
  193. // Create horizontal gaussian blur post-processes
  194. var gaussianBlurHPostProcess = new BABYLON.PostProcess("HDRGaussianBlurH" + ratio, "standard", uniforms, [], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define GAUSSIAN_BLUR_H", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
  195. gaussianBlurHPostProcess.onApply = callback(false);
  196. // Create vertical gaussian blur post-process
  197. var gaussianBlurVPostProcess = new BABYLON.PostProcess("HDRGaussianBlurV" + ratio, "standard", uniforms, [], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define GAUSSIAN_BLUR_V", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
  198. gaussianBlurVPostProcess.onApply = callback(true);
  199. // Add to pipeline
  200. this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRGaussianBlurH" + indice, function () { return gaussianBlurHPostProcess; }, true));
  201. this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRGaussianBlurV" + indice, function () { return gaussianBlurVPostProcess; }, true));
  202. // Finish
  203. this.gaussianBlurHPostProcesses.push(gaussianBlurHPostProcess);
  204. this.gaussianBlurVPostProcesses.push(gaussianBlurVPostProcess);
  205. };
  206. // Create texture adder post-process
  207. StandardRenderingPipeline.prototype._createTextureAdderPostProcess = function (scene, ratio) {
  208. var _this = this;
  209. var lastGaussianBlurPostProcess = this.gaussianBlurVPostProcesses[3];
  210. this.textureAdderPostProcess = new BABYLON.PostProcess("HDRTextureAdder", "standard", ["exposure"], ["otherSampler", "lensSampler"], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define TEXTURE_ADDER", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
  211. this.textureAdderPostProcess.onApply = function (effect) {
  212. effect.setTextureFromPostProcess("otherSampler", _this.originalPostProcess);
  213. effect.setTexture("lensSampler", _this.lensTexture);
  214. effect.setFloat("exposure", _this.exposure);
  215. };
  216. // Add to pipeline
  217. this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRTextureAdder", function () { return _this.textureAdderPostProcess; }, true));
  218. };
  219. // Create depth-of-field post-process
  220. StandardRenderingPipeline.prototype._createDepthOfFieldPostProcess = function (scene, ratio) {
  221. var _this = this;
  222. this.depthOfFieldPostProcess = new BABYLON.PostProcess("HDRDepthOfField", "standard", ["distance"], ["otherSampler", "depthSampler"], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define DEPTH_OF_FIELD", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
  223. this.depthOfFieldPostProcess.onApply = function (effect) {
  224. effect.setTextureFromPostProcess("otherSampler", _this.depthOfFieldSourcePostProcess);
  225. effect.setTexture("depthSampler", _this._depthRenderer.getDepthMap());
  226. effect.setFloat("distance", _this.depthOfFieldDistance);
  227. };
  228. // Add to pipeline
  229. this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRDepthOfField", function () { return _this.depthOfFieldPostProcess; }, true));
  230. };
  231. return StandardRenderingPipeline;
  232. }(BABYLON.PostProcessRenderPipeline));
  233. BABYLON.StandardRenderingPipeline = StandardRenderingPipeline;
  234. })(BABYLON || (BABYLON = {}));