DepthOfFieldNode.js 8.2 KB

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