babylon.depthOfFieldEffect.ts 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. module BABYLON {
  2. /**
  3. * Specifies the level of max blur that should be applied when using the depth of field effect
  4. */
  5. export enum DepthOfFieldEffectBlurLevel {
  6. /**
  7. * Subtle blur
  8. */
  9. Low,
  10. /**
  11. * Medium blur
  12. */
  13. Medium,
  14. /**
  15. * Large blur
  16. */
  17. High
  18. };
  19. /**
  20. * The depth of field effect applies a blur to objects that are closer or further from where the camera is focusing.
  21. */
  22. export class DepthOfFieldEffect extends PostProcessRenderEffect{
  23. private _circleOfConfusion: CircleOfConfusionPostProcess;
  24. private _depthOfFieldBlurX: Array<DepthOfFieldBlurPostProcess>;
  25. private _depthOfFieldBlurY: Array<DepthOfFieldBlurPostProcess>;
  26. /**
  27. * Private, last post process of dof
  28. */
  29. public _depthOfFieldMerge: DepthOfFieldMergePostProcess;
  30. private _effects: Array<PostProcess> = [];
  31. /**
  32. * The focal the length of the camera used in the effect
  33. */
  34. public set focalLength(value: number){
  35. this._circleOfConfusion.focalLength = value;
  36. }
  37. public get focalLength(){
  38. return this._circleOfConfusion.focalLength;
  39. }
  40. /**
  41. * F-Stop of the effect's camera. The diamater of the resulting aperture can be computed by lensSize/fStop. (default: 1.4)
  42. */
  43. public set fStop(value: number){
  44. this._circleOfConfusion.fStop = value;
  45. }
  46. public get fStop(){
  47. return this._circleOfConfusion.fStop;
  48. }
  49. /**
  50. * Distance away from the camera to focus on in scene units/1000 (eg. millimeter). (default: 2000)
  51. */
  52. public set focusDistance(value: number){
  53. this._circleOfConfusion.focusDistance = value;
  54. }
  55. public get focusDistance(){
  56. return this._circleOfConfusion.focusDistance;
  57. }
  58. /**
  59. * Max lens size in scene units/1000 (eg. millimeter). Standard cameras are 50mm. (default: 50) The diamater of the resulting aperture can be computed by lensSize/fStop.
  60. */
  61. public set lensSize(value: number){
  62. this._circleOfConfusion.lensSize = value;
  63. }
  64. public get lensSize(){
  65. return this._circleOfConfusion.lensSize;
  66. }
  67. /**
  68. * Creates a new instance of @see DepthOfFieldEffect
  69. * @param scene The scene the effect belongs to.
  70. * @param depthTexture The depth texture of the scene to compute the circle of confusion.This must be set in order for this to function but may be set after initialization if needed.
  71. * @param pipelineTextureType The type of texture to be used when performing the post processing.
  72. * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
  73. */
  74. constructor(scene: Scene, depthTexture: Nullable<RenderTargetTexture>, blurLevel: DepthOfFieldEffectBlurLevel = DepthOfFieldEffectBlurLevel.Low, pipelineTextureType = 0, blockCompilation = false) {
  75. super(scene.getEngine(), "depth of field", ()=>{
  76. return this._effects;
  77. }, true);
  78. // Circle of confusion value for each pixel is used to determine how much to blur that pixel
  79. this._circleOfConfusion = new BABYLON.CircleOfConfusionPostProcess("circleOfConfusion", depthTexture, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
  80. // Create a pyramid of blurred images (eg. fullSize 1/4 blur, half size 1/2 blur, quarter size 3/4 blur, eith size 4/4 blur)
  81. // Blur the image but do not blur on sharp far to near distance changes to avoid bleeding artifacts
  82. // See section 2.6.2 http://fileadmin.cs.lth.se/cs/education/edan35/lectures/12dof.pdf
  83. this._depthOfFieldBlurY = []
  84. this._depthOfFieldBlurX = []
  85. var blurCount = 1;
  86. var kernelSize = 15;
  87. switch(blurLevel){
  88. case DepthOfFieldEffectBlurLevel.High: {
  89. blurCount = 3;
  90. kernelSize = 51;
  91. break;
  92. }
  93. case DepthOfFieldEffectBlurLevel.Medium: {
  94. blurCount = 2;
  95. kernelSize = 31;
  96. break;
  97. }
  98. default: {
  99. kernelSize = 15;
  100. blurCount = 1;
  101. break;
  102. }
  103. }
  104. var adjustedKernelSize = kernelSize/Math.pow(2, blurCount-1);
  105. for(var i = 0;i<blurCount;i++){
  106. var blurY = new DepthOfFieldBlurPostProcess("verticle blur", scene, new Vector2(0, 1.0), adjustedKernelSize, 1.0/Math.pow(2, i), null, this._circleOfConfusion, i == 0 ? this._circleOfConfusion : null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
  107. blurY.autoClear = false;
  108. var blurX = new DepthOfFieldBlurPostProcess("horizontal blur", scene, new Vector2(1.0, 0), adjustedKernelSize, 1.0/Math.pow(2, i), null, this._circleOfConfusion, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
  109. blurX.autoClear = false;
  110. this._depthOfFieldBlurY.push(blurY);
  111. this._depthOfFieldBlurX.push(blurX);
  112. }
  113. // Merge blurred images with original image based on circleOfConfusion
  114. this._depthOfFieldMerge = new DepthOfFieldMergePostProcess("depthOfFieldMerge", this._circleOfConfusion, this._circleOfConfusion, this._depthOfFieldBlurY.slice(0, this._depthOfFieldBlurY.length-1), 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
  115. this._depthOfFieldMerge.autoClear = false;
  116. // Set all post processes on the effect.
  117. this._effects= [this._circleOfConfusion];
  118. for(var i=0;i<this._depthOfFieldBlurX.length;i++){
  119. this._effects.push(this._depthOfFieldBlurY[i]);
  120. this._effects.push(this._depthOfFieldBlurX[i]);
  121. }
  122. this._effects.push(this._depthOfFieldMerge);
  123. }
  124. /**
  125. * Depth texture to be used to compute the circle of confusion. This must be set here or in the constructor in order for the post process to function.
  126. */
  127. public set depthTexture(value: RenderTargetTexture){
  128. this._circleOfConfusion.depthTexture = value;
  129. }
  130. /**
  131. * Disposes each of the internal effects for a given camera.
  132. * @param camera The camera to dispose the effect on.
  133. */
  134. public disposeEffects(camera:Camera){
  135. this._circleOfConfusion.dispose(camera);
  136. this._depthOfFieldBlurX.forEach(element => {
  137. element.dispose(camera);
  138. });
  139. this._depthOfFieldBlurY.forEach(element => {
  140. element.dispose(camera);
  141. });
  142. this._depthOfFieldMerge.dispose(camera);
  143. }
  144. /**
  145. * Internal
  146. */
  147. public _updateEffects(){
  148. for(var effect in this._effects){
  149. this._effects[effect].updateEffect();
  150. }
  151. }
  152. /**
  153. * Internal
  154. * @returns if all the contained post processes are ready.
  155. */
  156. public _isReady(){
  157. for(var effect in this._effects){
  158. if(!this._effects[effect].isReady()){
  159. return false;
  160. }
  161. }
  162. return true;
  163. }
  164. }
  165. }