MaskPass.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import { Pass } from './Pass.js';
  2. /**
  3. * This pass can be used to define a mask during post processing.
  4. * Meaning only areas of subsequent post processing are affected
  5. * which lie in the masking area of this pass. Internally, the masking
  6. * is implemented with the stencil buffer.
  7. *
  8. * ```js
  9. * const maskPass = new MaskPass( scene, camera );
  10. * composer.addPass( maskPass );
  11. * ```
  12. *
  13. * @augments Pass
  14. * @three_import import { MaskPass } from 'three/addons/postprocessing/MaskPass.js';
  15. */
  16. class MaskPass extends Pass {
  17. /**
  18. * Constructs a new mask pass.
  19. *
  20. * @param {Scene} scene - The 3D objects in this scene will define the mask.
  21. * @param {Camera} camera - The camera.
  22. */
  23. constructor( scene, camera ) {
  24. super();
  25. /**
  26. * The scene that defines the mask.
  27. *
  28. * @type {Scene}
  29. */
  30. this.scene = scene;
  31. /**
  32. * The camera.
  33. *
  34. * @type {Camera}
  35. */
  36. this.camera = camera;
  37. /**
  38. * Overwritten to perform a clear operation by default.
  39. *
  40. * @type {boolean}
  41. * @default true
  42. */
  43. this.clear = true;
  44. /**
  45. * Overwritten to disable the swap.
  46. *
  47. * @type {boolean}
  48. * @default false
  49. */
  50. this.needsSwap = false;
  51. /**
  52. * Whether to inverse the mask or not.
  53. *
  54. * @type {boolean}
  55. * @default false
  56. */
  57. this.inverse = false;
  58. }
  59. /**
  60. * Performs a mask pass with the configured scene and camera.
  61. *
  62. * @param {WebGLRenderer} renderer - The renderer.
  63. * @param {WebGLRenderTarget} writeBuffer - The write buffer. This buffer is intended as the rendering
  64. * destination for the pass.
  65. * @param {WebGLRenderTarget} readBuffer - The read buffer. The pass can access the result from the
  66. * previous pass from this buffer.
  67. * @param {number} deltaTime - The delta time in seconds.
  68. * @param {boolean} maskActive - Whether masking is active or not.
  69. */
  70. render( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
  71. const context = renderer.getContext();
  72. const state = renderer.state;
  73. // don't update color or depth
  74. state.buffers.color.setMask( false );
  75. state.buffers.depth.setMask( false );
  76. // lock buffers
  77. state.buffers.color.setLocked( true );
  78. state.buffers.depth.setLocked( true );
  79. // set up stencil
  80. let writeValue, clearValue;
  81. if ( this.inverse ) {
  82. writeValue = 0;
  83. clearValue = 1;
  84. } else {
  85. writeValue = 1;
  86. clearValue = 0;
  87. }
  88. state.buffers.stencil.setTest( true );
  89. state.buffers.stencil.setOp( context.REPLACE, context.REPLACE, context.REPLACE );
  90. state.buffers.stencil.setFunc( context.ALWAYS, writeValue, 0xffffffff );
  91. state.buffers.stencil.setClear( clearValue );
  92. state.buffers.stencil.setLocked( true );
  93. // draw into the stencil buffer
  94. renderer.setRenderTarget( readBuffer );
  95. if ( this.clear ) renderer.clear();
  96. renderer.render( this.scene, this.camera );
  97. renderer.setRenderTarget( writeBuffer );
  98. if ( this.clear ) renderer.clear();
  99. renderer.render( this.scene, this.camera );
  100. // unlock color and depth buffer and make them writable for subsequent rendering/clearing
  101. state.buffers.color.setLocked( false );
  102. state.buffers.depth.setLocked( false );
  103. state.buffers.color.setMask( true );
  104. state.buffers.depth.setMask( true );
  105. // only render where stencil is set to 1
  106. state.buffers.stencil.setLocked( false );
  107. state.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
  108. state.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );
  109. state.buffers.stencil.setLocked( true );
  110. }
  111. }
  112. /**
  113. * This pass can be used to clear a mask previously defined with {@link MaskPass}.
  114. *
  115. * ```js
  116. * const clearPass = new ClearMaskPass();
  117. * composer.addPass( clearPass );
  118. * ```
  119. *
  120. * @augments Pass
  121. */
  122. class ClearMaskPass extends Pass {
  123. /**
  124. * Constructs a new clear mask pass.
  125. */
  126. constructor() {
  127. super();
  128. /**
  129. * Overwritten to disable the swap.
  130. *
  131. * @type {boolean}
  132. * @default false
  133. */
  134. this.needsSwap = false;
  135. }
  136. /**
  137. * Performs the clear of the currently defined mask.
  138. *
  139. * @param {WebGLRenderer} renderer - The renderer.
  140. * @param {WebGLRenderTarget} writeBuffer - The write buffer. This buffer is intended as the rendering
  141. * destination for the pass.
  142. * @param {WebGLRenderTarget} readBuffer - The read buffer. The pass can access the result from the
  143. * previous pass from this buffer.
  144. * @param {number} deltaTime - The delta time in seconds.
  145. * @param {boolean} maskActive - Whether masking is active or not.
  146. */
  147. render( renderer /*, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
  148. renderer.state.buffers.stencil.setLocked( false );
  149. renderer.state.buffers.stencil.setTest( false );
  150. }
  151. }
  152. export { MaskPass, ClearMaskPass };