DepthOfFieldNode.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import { TempNode, NodeUpdateType } from 'three/webgpu';
  2. import { convertToTexture, nodeObject, Fn, uv, uniform, vec2, vec4, clamp } from 'three/tsl';
  3. /**
  4. * Post processing node for creating depth of field (DOF) effect.
  5. *
  6. * @augments TempNode
  7. * @three_import import { dof } from 'three/addons/tsl/display/DepthOfFieldNode.js';
  8. */
  9. class DepthOfFieldNode extends TempNode {
  10. static get type() {
  11. return 'DepthOfFieldNode';
  12. }
  13. /**
  14. * Constructs a new DOF node.
  15. *
  16. * @param {TextureNode} textureNode - The texture node that represents the input of the effect.
  17. * @param {Node<float>} viewZNode - Represents the viewZ depth values of the scene.
  18. * @param {Node<float>} focusNode - Defines the effect's focus which is the distance along the camera's look direction in world units.
  19. * @param {Node<float>} apertureNode - Defines the effect's aperture.
  20. * @param {Node<float>} maxblurNode - Defines the effect's maximum blur.
  21. */
  22. constructor( textureNode, viewZNode, focusNode, apertureNode, maxblurNode ) {
  23. super( 'vec4' );
  24. /**
  25. * The texture node that represents the input of the effect.
  26. *
  27. * @type {TextureNode}
  28. */
  29. this.textureNode = textureNode;
  30. /**
  31. * Represents the viewZ depth values of the scene.
  32. *
  33. * @type {Node<float>}
  34. */
  35. this.viewZNode = viewZNode;
  36. /**
  37. * Defines the effect's focus which is the distance along the camera's look direction in world units.
  38. *
  39. * @type {Node<float>}
  40. */
  41. this.focusNode = focusNode;
  42. /**
  43. * Defines the effect's aperture.
  44. *
  45. * @type {Node<float>}
  46. */
  47. this.apertureNode = apertureNode;
  48. /**
  49. * Defines the effect's maximum blur.
  50. *
  51. * @type {Node<float>}
  52. */
  53. this.maxblurNode = maxblurNode;
  54. /**
  55. * Represents the input's aspect ratio.
  56. *
  57. * @private
  58. * @type {UniformNode<float>}
  59. */
  60. this._aspect = uniform( 0 );
  61. /**
  62. * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node updates
  63. * its internal uniforms once per frame in `updateBefore()`.
  64. *
  65. * @type {string}
  66. * @default 'frame'
  67. */
  68. this.updateBeforeType = NodeUpdateType.FRAME;
  69. }
  70. /**
  71. * This method is used to update the effect's uniforms once per frame.
  72. *
  73. * @param {NodeFrame} frame - The current node frame.
  74. */
  75. updateBefore() {
  76. const map = this.textureNode.value;
  77. this._aspect.value = map.image.width / map.image.height;
  78. }
  79. /**
  80. * This method is used to setup the effect's TSL code.
  81. *
  82. * @param {NodeBuilder} builder - The current node builder.
  83. * @return {ShaderCallNodeInternal}
  84. */
  85. setup() {
  86. const textureNode = this.textureNode;
  87. const uvNode = textureNode.uvNode || uv();
  88. const sampleTexture = ( uv ) => textureNode.sample( uv );
  89. const dof = Fn( () => {
  90. const aspectcorrect = vec2( 1.0, this._aspect );
  91. const factor = this.focusNode.add( this.viewZNode );
  92. const dofblur = vec2( clamp( factor.mul( this.apertureNode ), this.maxblurNode.negate(), this.maxblurNode ) );
  93. const dofblur9 = dofblur.mul( 0.9 );
  94. const dofblur7 = dofblur.mul( 0.7 );
  95. const dofblur4 = dofblur.mul( 0.4 );
  96. let col = vec4( 0.0 );
  97. col = col.add( sampleTexture( uvNode ) );
  98. col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  99. col = col.add( sampleTexture( uvNode.add( vec2( 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  100. col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  101. col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  102. col = col.add( sampleTexture( uvNode.add( vec2( 0.40, 0.0 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  103. col = col.add( sampleTexture( uvNode.add( vec2( 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  104. col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  105. col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  106. col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  107. col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  108. col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  109. col = col.add( sampleTexture( uvNode.add( vec2( 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  110. col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  111. col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  112. col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  113. col = col.add( sampleTexture( uvNode.add( vec2( 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur ) ) ) );
  114. col = col.add( sampleTexture( uvNode.add( vec2( 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) );
  115. col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) );
  116. col = col.add( sampleTexture( uvNode.add( vec2( 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) );
  117. col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) );
  118. col = col.add( sampleTexture( uvNode.add( vec2( - 0.15, 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) );
  119. col = col.add( sampleTexture( uvNode.add( vec2( 0.37, 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) );
  120. col = col.add( sampleTexture( uvNode.add( vec2( - 0.37, - 0.15 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) );
  121. col = col.add( sampleTexture( uvNode.add( vec2( 0.15, - 0.37 ).mul( aspectcorrect ).mul( dofblur9 ) ) ) );
  122. col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) );
  123. col = col.add( sampleTexture( uvNode.add( vec2( 0.40, 0.0 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) );
  124. col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) );
  125. col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) );
  126. col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) );
  127. col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) );
  128. col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) );
  129. col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur7 ) ) ) );
  130. col = col.add( sampleTexture( uvNode.add( vec2( 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) );
  131. col = col.add( sampleTexture( uvNode.add( vec2( 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) );
  132. col = col.add( sampleTexture( uvNode.add( vec2( 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) );
  133. col = col.add( sampleTexture( uvNode.add( vec2( 0.0, - 0.4 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) );
  134. col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) );
  135. col = col.add( sampleTexture( uvNode.add( vec2( - 0.4, 0.0 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) );
  136. col = col.add( sampleTexture( uvNode.add( vec2( - 0.29, - 0.29 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) );
  137. col = col.add( sampleTexture( uvNode.add( vec2( 0.0, 0.4 ).mul( aspectcorrect ).mul( dofblur4 ) ) ) );
  138. col = col.div( 41 );
  139. col.a = 1;
  140. return vec4( col );
  141. } );
  142. const outputNode = dof();
  143. return outputNode;
  144. }
  145. }
  146. export default DepthOfFieldNode;
  147. /**
  148. * TSL function for creating a depth-of-field effect (DOF) for post processing.
  149. *
  150. * @tsl
  151. * @function
  152. * @param {Node<vec4>} node - The node that represents the input of the effect.
  153. * @param {Node<float>} viewZNode - Represents the viewZ depth values of the scene.
  154. * @param {Node<float> | number} focus - Defines the effect's focus which is the distance along the camera's look direction in world units.
  155. * @param {Node<float> | number} aperture - Defines the effect's aperture.
  156. * @param {Node<float> | number} maxblur - Defines the effect's maximum blur.
  157. * @returns {DepthOfFieldNode}
  158. */
  159. export const dof = ( node, viewZNode, focus = 1, aperture = 0.025, maxblur = 1 ) => nodeObject( new DepthOfFieldNode( convertToTexture( node ), nodeObject( viewZNode ), nodeObject( focus ), nodeObject( aperture ), nodeObject( maxblur ) ) );