RenderTransitionPass.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import {
  2. HalfFloatType,
  3. ShaderMaterial,
  4. WebGLRenderTarget
  5. } from 'three';
  6. import { FullScreenQuad, Pass } from './Pass.js';
  7. /**
  8. * A special type of render pass for implementing transition effects.
  9. * When active, the pass will transition from scene A to scene B.
  10. *
  11. * ```js
  12. * const renderTransitionPass = new RenderTransitionPass( fxSceneA.scene, fxSceneA.camera, fxSceneB.scene, fxSceneB.camera );
  13. * renderTransitionPass.setTexture( textures[ 0 ] );
  14. * composer.addPass( renderTransitionPass );
  15. * ```
  16. *
  17. * @augments Pass
  18. * @three_import import { RenderTransitionPass } from 'three/addons/postprocessing/RenderTransitionPass.js';
  19. */
  20. class RenderTransitionPass extends Pass {
  21. /**
  22. * Constructs a render transition pass.
  23. *
  24. * @param {Scene} sceneA - The first scene.
  25. * @param {Camera} cameraA - The camera of the first scene.
  26. * @param {Scene} sceneB - The second scene.
  27. * @param {Camera} cameraB - The camera of the second scene.
  28. */
  29. constructor( sceneA, cameraA, sceneB, cameraB ) {
  30. super();
  31. /**
  32. * The first scene.
  33. *
  34. * @type {Scene}
  35. */
  36. this.sceneA = sceneA;
  37. /**
  38. * The camera of the first scene.
  39. *
  40. * @type {Camera}
  41. */
  42. this.cameraA = cameraA;
  43. /**
  44. * The second scene.
  45. *
  46. * @type {Scene}
  47. */
  48. this.sceneB = sceneB;
  49. /**
  50. * The camera of the second scene.
  51. *
  52. * @type {Camera}
  53. */
  54. this.cameraB = cameraB;
  55. /**
  56. * The pass material.
  57. *
  58. * @type {ShaderMaterial}
  59. */
  60. this.material = this._createMaterial();
  61. // internals
  62. this._renderTargetA = new WebGLRenderTarget();
  63. this._renderTargetA.texture.type = HalfFloatType;
  64. this._renderTargetB = new WebGLRenderTarget();
  65. this._renderTargetB.texture.type = HalfFloatType;
  66. this._fsQuad = new FullScreenQuad( this.material );
  67. }
  68. /**
  69. * Sets the transition factor. Must be in the range `[0,1]`.
  70. * This value determines to what degree both scenes are mixed.
  71. *
  72. * @param {boolean|number} value - The transition factor.
  73. */
  74. setTransition( value ) {
  75. this.material.uniforms.mixRatio.value = value;
  76. }
  77. /**
  78. * Toggles the usage of a texture for the effect.
  79. *
  80. * @param {boolean} value - Whether to use a texture for the transition effect or not.
  81. */
  82. useTexture( value ) {
  83. this.material.uniforms.useTexture.value = value ? 1 : 0;
  84. }
  85. /**
  86. * Sets the effect texture.
  87. *
  88. * @param {Texture} value - The effect texture.
  89. */
  90. setTexture( value ) {
  91. this.material.uniforms.tMixTexture.value = value;
  92. }
  93. /**
  94. * Sets the texture threshold. This value defined how strong the texture effects
  95. * the transition. Must be in the range `[0,1]` (0 means full effect, 1 means no effect).
  96. *
  97. * @param {boolean|number} value - The threshold value.
  98. */
  99. setTextureThreshold( value ) {
  100. this.material.uniforms.threshold.value = value;
  101. }
  102. /**
  103. * Sets the size of the pass.
  104. *
  105. * @param {number} width - The width to set.
  106. * @param {number} height - The width to set.
  107. */
  108. setSize( width, height ) {
  109. this._renderTargetA.setSize( width, height );
  110. this._renderTargetB.setSize( width, height );
  111. }
  112. /**
  113. * Performs the transition pass.
  114. *
  115. * @param {WebGLRenderer} renderer - The renderer.
  116. * @param {WebGLRenderTarget} writeBuffer - The write buffer. This buffer is intended as the rendering
  117. * destination for the pass.
  118. * @param {WebGLRenderTarget} readBuffer - The read buffer. The pass can access the result from the
  119. * previous pass from this buffer.
  120. * @param {number} deltaTime - The delta time in seconds.
  121. * @param {boolean} maskActive - Whether masking is active or not.
  122. */
  123. render( renderer, writeBuffer/*, readBuffer , deltaTime, maskActive */ ) {
  124. renderer.setRenderTarget( this._renderTargetA );
  125. renderer.render( this.sceneA, this.cameraA );
  126. renderer.setRenderTarget( this._renderTargetB );
  127. renderer.render( this.sceneB, this.cameraB );
  128. const uniforms = this._fsQuad.material.uniforms;
  129. uniforms.tDiffuse1.value = this._renderTargetA.texture;
  130. uniforms.tDiffuse2.value = this._renderTargetB.texture;
  131. if ( this.renderToScreen ) {
  132. renderer.setRenderTarget( null );
  133. renderer.clear();
  134. } else {
  135. renderer.setRenderTarget( writeBuffer );
  136. if ( this.clear ) renderer.clear();
  137. }
  138. this._fsQuad.render( renderer );
  139. }
  140. /**
  141. * Frees the GPU-related resources allocated by this instance. Call this
  142. * method whenever the pass is no longer used in your app.
  143. */
  144. dispose() {
  145. this.material.dispose();
  146. this._renderTargetA.dispose();
  147. this._renderTargetB.dispose();
  148. this._fsQuad.dispose();
  149. }
  150. // internals
  151. _createMaterial() {
  152. return new ShaderMaterial( {
  153. uniforms: {
  154. tDiffuse1: {
  155. value: null
  156. },
  157. tDiffuse2: {
  158. value: null
  159. },
  160. mixRatio: {
  161. value: 0.0
  162. },
  163. threshold: {
  164. value: 0.1
  165. },
  166. useTexture: {
  167. value: 1
  168. },
  169. tMixTexture: {
  170. value: null
  171. }
  172. },
  173. vertexShader: /* glsl */`
  174. varying vec2 vUv;
  175. void main() {
  176. vUv = vec2( uv.x, uv.y );
  177. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  178. }
  179. `,
  180. fragmentShader: /* glsl */`
  181. uniform float mixRatio;
  182. uniform sampler2D tDiffuse1;
  183. uniform sampler2D tDiffuse2;
  184. uniform sampler2D tMixTexture;
  185. uniform int useTexture;
  186. uniform float threshold;
  187. varying vec2 vUv;
  188. void main() {
  189. vec4 texel1 = texture2D( tDiffuse1, vUv );
  190. vec4 texel2 = texture2D( tDiffuse2, vUv );
  191. if (useTexture == 1) {
  192. vec4 transitionTexel = texture2D( tMixTexture, vUv );
  193. float r = mixRatio * ( 1.0 + threshold * 2.0 ) - threshold;
  194. float mixf = clamp( ( transitionTexel.r - r ) * ( 1.0 / threshold ), 0.0, 1.0 );
  195. gl_FragColor = mix( texel1, texel2, mixf );
  196. } else {
  197. gl_FragColor = mix( texel2, texel1, mixRatio );
  198. }
  199. }
  200. `
  201. } );
  202. }
  203. }
  204. export { RenderTransitionPass };