babylon.lensRenderingPipeline.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // BABYLON.JS Chromatic Aberration GLSL Shader
  2. // Author: Olivier Guyot
  3. // Separates very slightly R, G and B colors on the edges of the screen
  4. // Inspired by Francois Tarlier & Martins Upitis
  5. var __extends = (this && this.__extends) || function (d, b) {
  6. for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
  7. function __() { this.constructor = d; }
  8. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  9. };
  10. var BABYLON;
  11. (function (BABYLON) {
  12. var LensRenderingPipeline = (function (_super) {
  13. __extends(LensRenderingPipeline, _super);
  14. /**
  15. * @constructor
  16. *
  17. * Effect parameters are as follow:
  18. * {
  19. * chromatic_aberration: number; // from 0 to x (1 for realism)
  20. * edge_blur: number; // from 0 to x (1 for realism)
  21. * distortion: number; // from 0 to x (1 for realism)
  22. * grain_amount: number; // from 0 to 1
  23. * grain_texture: BABYLON.Texture; // texture to use for grain effect; if unset, use random B&W noise
  24. * dof_focus_distance: number; // depth-of-field: focus distance; unset to disable (disabled by default)
  25. * dof_aperture: number; // depth-of-field: focus blur bias (default: 1)
  26. * dof_darken: number; // depth-of-field: darken that which is out of focus (from 0 to 1, disabled by default)
  27. * dof_pentagon: boolean; // depth-of-field: makes a pentagon-like "bokeh" effect
  28. * dof_gain: number; // depth-of-field: highlights gain; unset to disable (disabled by default)
  29. * dof_threshold: number; // depth-of-field: highlights threshold (default: 1)
  30. * blur_noise: boolean; // add a little bit of noise to the blur (default: true)
  31. * }
  32. * Note: if an effect parameter is unset, effect is disabled
  33. *
  34. * @param {string} name - The rendering pipeline name
  35. * @param {object} parameters - An object containing all parameters (see above)
  36. * @param {BABYLON.Scene} scene - The scene linked to this pipeline
  37. * @param {number} 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)
  38. * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
  39. */
  40. function LensRenderingPipeline(name, parameters, scene, ratio, cameras) {
  41. var _this = this;
  42. if (ratio === void 0) { ratio = 1.0; }
  43. _super.call(this, scene.getEngine(), name);
  44. // Lens effects can be of the following:
  45. // - chromatic aberration (slight shift of RGB colors)
  46. // - blur on the edge of the lens
  47. // - lens distortion
  48. // - depth-of-field blur & highlights enhancing
  49. // - depth-of-field 'bokeh' effect (shapes appearing in blurred areas)
  50. // - grain effect (noise or custom texture)
  51. // Two additional texture samplers are needed:
  52. // - depth map (for depth-of-field)
  53. // - grain texture
  54. /**
  55. * The chromatic aberration PostProcess id in the pipeline
  56. * @type {string}
  57. */
  58. this.LensChromaticAberrationEffect = "LensChromaticAberrationEffect";
  59. /**
  60. * The highlights enhancing PostProcess id in the pipeline
  61. * @type {string}
  62. */
  63. this.HighlightsEnhancingEffect = "HighlightsEnhancingEffect";
  64. /**
  65. * The depth-of-field PostProcess id in the pipeline
  66. * @type {string}
  67. */
  68. this.LensDepthOfFieldEffect = "LensDepthOfFieldEffect";
  69. this._scene = scene;
  70. // Fetch texture samplers
  71. this._depthTexture = scene.enableDepthRenderer().getDepthMap(); // Force depth renderer "on"
  72. if (parameters.grain_texture) {
  73. this._grainTexture = parameters.grain_texture;
  74. }
  75. else {
  76. this._createGrainTexture();
  77. }
  78. // save parameters
  79. this._edgeBlur = parameters.edge_blur ? parameters.edge_blur : 0;
  80. this._grainAmount = parameters.grain_amount ? parameters.grain_amount : 0;
  81. this._chromaticAberration = parameters.chromatic_aberration ? parameters.chromatic_aberration : 0;
  82. this._distortion = parameters.distortion ? parameters.distortion : 0;
  83. this._highlightsGain = parameters.dof_gain !== undefined ? parameters.dof_gain : -1;
  84. this._highlightsThreshold = parameters.dof_threshold ? parameters.dof_threshold : 1;
  85. this._dofDistance = parameters.dof_focus_distance !== undefined ? parameters.dof_focus_distance : -1;
  86. this._dofAperture = parameters.dof_aperture ? parameters.dof_aperture : 1;
  87. this._dofDarken = parameters.dof_darken ? parameters.dof_darken : 0;
  88. this._dofPentagon = parameters.dof_pentagon !== undefined ? parameters.dof_pentagon : true;
  89. this._blurNoise = parameters.blur_noise !== undefined ? parameters.blur_noise : true;
  90. // Create effects
  91. this._createChromaticAberrationPostProcess(ratio);
  92. this._createHighlightsPostProcess(ratio);
  93. this._createDepthOfFieldPostProcess(ratio / 4);
  94. // Set up pipeline
  95. this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), this.LensChromaticAberrationEffect, function () { return _this._chromaticAberrationPostProcess; }, true));
  96. this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), this.HighlightsEnhancingEffect, function () { return _this._highlightsPostProcess; }, true));
  97. this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), this.LensDepthOfFieldEffect, function () { return _this._depthOfFieldPostProcess; }, true));
  98. if (this._highlightsGain === -1) {
  99. this._disableEffect(this.HighlightsEnhancingEffect, null);
  100. }
  101. // Finish
  102. scene.postProcessRenderPipelineManager.addPipeline(this);
  103. if (cameras) {
  104. scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
  105. }
  106. }
  107. // public methods (self explanatory)
  108. LensRenderingPipeline.prototype.setEdgeBlur = function (amount) { this._edgeBlur = amount; };
  109. LensRenderingPipeline.prototype.disableEdgeBlur = function () { this._edgeBlur = 0; };
  110. LensRenderingPipeline.prototype.setGrainAmount = function (amount) { this._grainAmount = amount; };
  111. LensRenderingPipeline.prototype.disableGrain = function () { this._grainAmount = 0; };
  112. LensRenderingPipeline.prototype.setChromaticAberration = function (amount) { this._chromaticAberration = amount; };
  113. LensRenderingPipeline.prototype.disableChromaticAberration = function () { this._chromaticAberration = 0; };
  114. LensRenderingPipeline.prototype.setEdgeDistortion = function (amount) { this._distortion = amount; };
  115. LensRenderingPipeline.prototype.disableEdgeDistortion = function () { this._distortion = 0; };
  116. LensRenderingPipeline.prototype.setFocusDistance = function (amount) { this._dofDistance = amount; };
  117. LensRenderingPipeline.prototype.disableDepthOfField = function () { this._dofDistance = -1; };
  118. LensRenderingPipeline.prototype.setAperture = function (amount) { this._dofAperture = amount; };
  119. LensRenderingPipeline.prototype.setDarkenOutOfFocus = function (amount) { this._dofDarken = amount; };
  120. LensRenderingPipeline.prototype.enablePentagonBokeh = function () {
  121. this._highlightsPostProcess.updateEffect("#define PENTAGON\n");
  122. };
  123. LensRenderingPipeline.prototype.disablePentagonBokeh = function () {
  124. this._highlightsPostProcess.updateEffect();
  125. };
  126. LensRenderingPipeline.prototype.enableNoiseBlur = function () { this._blurNoise = true; };
  127. LensRenderingPipeline.prototype.disableNoiseBlur = function () { this._blurNoise = false; };
  128. LensRenderingPipeline.prototype.setHighlightsGain = function (amount) {
  129. this._highlightsGain = amount;
  130. };
  131. LensRenderingPipeline.prototype.setHighlightsThreshold = function (amount) {
  132. if (this._highlightsGain === -1) {
  133. this._highlightsGain = 1.0;
  134. }
  135. this._highlightsThreshold = amount;
  136. };
  137. LensRenderingPipeline.prototype.disableHighlights = function () {
  138. this._highlightsGain = -1;
  139. };
  140. /**
  141. * Removes the internal pipeline assets and detaches the pipeline from the scene cameras
  142. */
  143. LensRenderingPipeline.prototype.dispose = function (disableDepthRender) {
  144. if (disableDepthRender === void 0) { disableDepthRender = false; }
  145. this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
  146. this._chromaticAberrationPostProcess = undefined;
  147. this._highlightsPostProcess = undefined;
  148. this._depthOfFieldPostProcess = undefined;
  149. this._grainTexture.dispose();
  150. if (disableDepthRender)
  151. this._scene.disableDepthRenderer();
  152. };
  153. // colors shifting and distortion
  154. LensRenderingPipeline.prototype._createChromaticAberrationPostProcess = function (ratio) {
  155. var _this = this;
  156. this._chromaticAberrationPostProcess = new BABYLON.PostProcess("LensChromaticAberration", "chromaticAberration", ["chromatic_aberration", "screen_width", "screen_height"], // uniforms
  157. [], // samplers
  158. ratio, null, BABYLON.Texture.TRILINEAR_SAMPLINGMODE, this._scene.getEngine(), false);
  159. this._chromaticAberrationPostProcess.onApply = function (effect) {
  160. effect.setFloat('chromatic_aberration', _this._chromaticAberration);
  161. effect.setFloat('screen_width', _this._scene.getEngine().getRenderingCanvas().width);
  162. effect.setFloat('screen_height', _this._scene.getEngine().getRenderingCanvas().height);
  163. };
  164. };
  165. // highlights enhancing
  166. LensRenderingPipeline.prototype._createHighlightsPostProcess = function (ratio) {
  167. var _this = this;
  168. this._highlightsPostProcess = new BABYLON.PostProcess("LensHighlights", "lensHighlights", ["gain", "threshold", "screen_width", "screen_height"], // uniforms
  169. [], // samplers
  170. ratio, null, BABYLON.Texture.TRILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, this._dofPentagon ? "#define PENTAGON\n" : "");
  171. this._highlightsPostProcess.onApply = function (effect) {
  172. effect.setFloat('gain', _this._highlightsGain);
  173. effect.setFloat('threshold', _this._highlightsThreshold);
  174. effect.setTextureFromPostProcess("textureSampler", _this._chromaticAberrationPostProcess);
  175. effect.setFloat('screen_width', _this._scene.getEngine().getRenderingCanvas().width);
  176. effect.setFloat('screen_height', _this._scene.getEngine().getRenderingCanvas().height);
  177. };
  178. };
  179. // colors shifting and distortion
  180. LensRenderingPipeline.prototype._createDepthOfFieldPostProcess = function (ratio) {
  181. var _this = this;
  182. this._depthOfFieldPostProcess = new BABYLON.PostProcess("LensDepthOfField", "depthOfField", [
  183. "grain_amount", "blur_noise", "screen_width", "screen_height", "distortion", "dof_enabled",
  184. "screen_distance", "aperture", "darken", "edge_blur", "highlights", "near", "far"
  185. ], ["depthSampler", "grainSampler", "highlightsSampler"], ratio, null, BABYLON.Texture.TRILINEAR_SAMPLINGMODE, this._scene.getEngine(), false);
  186. this._depthOfFieldPostProcess.onApply = function (effect) {
  187. effect.setTexture("depthSampler", _this._depthTexture);
  188. effect.setTexture("grainSampler", _this._grainTexture);
  189. effect.setTextureFromPostProcess("textureSampler", _this._highlightsPostProcess);
  190. effect.setTextureFromPostProcess("highlightsSampler", _this._depthOfFieldPostProcess);
  191. effect.setFloat('grain_amount', _this._grainAmount);
  192. effect.setBool('blur_noise', _this._blurNoise);
  193. effect.setFloat('screen_width', _this._scene.getEngine().getRenderingCanvas().width);
  194. effect.setFloat('screen_height', _this._scene.getEngine().getRenderingCanvas().height);
  195. effect.setFloat('distortion', _this._distortion);
  196. effect.setBool('dof_enabled', (_this._dofDistance !== -1));
  197. effect.setFloat('screen_distance', 1.0 / (0.1 - 1.0 / _this._dofDistance));
  198. effect.setFloat('aperture', _this._dofAperture);
  199. effect.setFloat('darken', _this._dofDarken);
  200. effect.setFloat('edge_blur', _this._edgeBlur);
  201. effect.setBool('highlights', (_this._highlightsGain !== -1));
  202. effect.setFloat('near', _this._scene.activeCamera.minZ);
  203. effect.setFloat('far', _this._scene.activeCamera.maxZ);
  204. };
  205. };
  206. // creates a black and white random noise texture, 512x512
  207. LensRenderingPipeline.prototype._createGrainTexture = function () {
  208. var size = 512;
  209. this._grainTexture = new BABYLON.DynamicTexture("LensNoiseTexture", size, this._scene, false, BABYLON.Texture.BILINEAR_SAMPLINGMODE);
  210. this._grainTexture.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
  211. this._grainTexture.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
  212. var context = this._grainTexture.getContext();
  213. var rand = function (min, max) {
  214. return Math.random() * (max - min) + min;
  215. };
  216. var value;
  217. for (var x = 0; x < size; x++) {
  218. for (var y = 0; y < size; y++) {
  219. value = Math.floor(rand(0.42, 0.58) * 255);
  220. context.fillStyle = 'rgb(' + value + ', ' + value + ', ' + value + ')';
  221. context.fillRect(x, y, 1, 1);
  222. }
  223. }
  224. this._grainTexture.update(false);
  225. };
  226. return LensRenderingPipeline;
  227. })(BABYLON.PostProcessRenderPipeline);
  228. BABYLON.LensRenderingPipeline = LensRenderingPipeline;
  229. })(BABYLON || (BABYLON = {}));