ChromaticAberrationNode.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import { TempNode } from 'three/webgpu';
  2. import {
  3. nodeObject,
  4. Fn,
  5. convertToTexture,
  6. float,
  7. vec4,
  8. uv,
  9. } from 'three/tsl';
  10. /**
  11. * Post processing node for applying chromatic aberration effect.
  12. * This effect simulates the color fringing that occurs in real camera lenses
  13. * by separating and offsetting the red, green, and blue channels.
  14. *
  15. * @augments TempNode
  16. * @three_import import { chromaticAberration } from 'three/addons/tsl/display/ChromaticAberrationNode.js';
  17. */
  18. class ChromaticAberrationNode extends TempNode {
  19. static get type() {
  20. return 'ChromaticAberrationNode';
  21. }
  22. /**
  23. * Constructs a new chromatic aberration node.
  24. *
  25. * @param {TextureNode} textureNode - The texture node that represents the input of the effect.
  26. * @param {Node} strengthNode - The strength of the chromatic aberration effect as a node.
  27. * @param {Node} centerNode - The center point of the effect as a node.
  28. * @param {Node} scaleNode - The scale factor for stepped scaling from center as a node.
  29. */
  30. constructor( textureNode, strengthNode, centerNode, scaleNode ) {
  31. super( 'vec4' );
  32. /**
  33. * The texture node that represents the input of the effect.
  34. *
  35. * @type {texture}
  36. */
  37. this.textureNode = textureNode;
  38. /**
  39. * A node holding the strength of the effect.
  40. *
  41. * @type {Node}
  42. */
  43. this.strengthNode = strengthNode;
  44. /**
  45. * A node holding the center point of the effect.
  46. *
  47. * @type {Node}
  48. */
  49. this.centerNode = centerNode;
  50. /**
  51. * A node holding the scale factor for stepped scaling.
  52. *
  53. * @type {Node}
  54. */
  55. this.scaleNode = scaleNode;
  56. }
  57. /**
  58. * This method is used to setup the effect's TSL code.
  59. *
  60. * @param {NodeBuilder} builder - The current node builder.
  61. * @return {ShaderCallNodeInternal}
  62. */
  63. setup( /* builder */ ) {
  64. const textureNode = this.textureNode;
  65. const uvNode = textureNode.uvNode || uv();
  66. const ApplyChromaticAberration = Fn( ( [ uv, strength, center, scale ] ) => {
  67. // Calculate distance from center
  68. const offset = uv.sub( center );
  69. const distance = offset.length();
  70. // Create stepped scaling zones based on distance
  71. // Each channel gets different scaling steps
  72. const redScale = float( 1.0 ).add( scale.mul( 0.02 ).mul( strength ) ); // Red channel scaled outward
  73. const greenScale = float( 1.0 ); // Green stays at original scale
  74. const blueScale = float( 1.0 ).sub( scale.mul( 0.02 ).mul( strength ) ); // Blue channel scaled inward
  75. // Create radial distortion based on distance from center
  76. const aberrationStrength = strength.mul( distance );
  77. // Calculate scaled UV coordinates for each channel
  78. const redUV = center.add( offset.mul( redScale ) );
  79. const greenUV = center.add( offset.mul( greenScale ) );
  80. const blueUV = center.add( offset.mul( blueScale ) );
  81. // Apply additional chromatic offset based on aberration strength
  82. const rOffset = offset.mul( aberrationStrength ).mul( float( 0.01 ) );
  83. const gOffset = offset.mul( aberrationStrength ).mul( float( 0.0 ) );
  84. const bOffset = offset.mul( aberrationStrength ).mul( float( - 0.01 ) );
  85. // Final UV coordinates combining scale and chromatic aberration
  86. const finalRedUV = redUV.add( rOffset );
  87. const finalGreenUV = greenUV.add( gOffset );
  88. const finalBlueUV = blueUV.add( bOffset );
  89. // Sample texture for each channel
  90. const r = textureNode.sample( finalRedUV ).r;
  91. const g = textureNode.sample( finalGreenUV ).g;
  92. const b = textureNode.sample( finalBlueUV ).b;
  93. // Get original alpha
  94. const a = textureNode.sample( uv ).a;
  95. return vec4( r, g, b, a );
  96. } ).setLayout( {
  97. name: 'ChromaticAberrationShader',
  98. type: 'vec4',
  99. inputs: [
  100. { name: 'uv', type: 'vec2' },
  101. { name: 'strength', type: 'float' },
  102. { name: 'center', type: 'vec2' },
  103. { name: 'scale', type: 'float' }
  104. ]
  105. } );
  106. const chromaticAberrationFn = Fn( () => {
  107. return ApplyChromaticAberration(
  108. uvNode,
  109. this.strengthNode,
  110. this.centerNode,
  111. this.scaleNode
  112. );
  113. } );
  114. const outputNode = chromaticAberrationFn();
  115. return outputNode;
  116. }
  117. }
  118. export default ChromaticAberrationNode;
  119. /**
  120. * TSL function for creating a chromatic aberration node for post processing.
  121. *
  122. * @tsl
  123. * @function
  124. * @param {Node<vec4>} node - The node that represents the input of the effect.
  125. * @param {Node|number} [strength=1.0] - The strength of the chromatic aberration effect as a node or value.
  126. * @param {?(Node|Vector2)} [center=null] - The center point of the effect as a node or value. If null, uses screen center (0.5, 0.5).
  127. * @param {Node|number} [scale=1.1] - The scale factor for stepped scaling from center as a node or value.
  128. * @returns {ChromaticAberrationNode}
  129. */
  130. export const chromaticAberration = ( node, strength = 1.0, center = null, scale = 1.1 ) => {
  131. return nodeObject(
  132. new ChromaticAberrationNode(
  133. convertToTexture( node ),
  134. nodeObject( strength ),
  135. nodeObject( center ),
  136. nodeObject( scale )
  137. )
  138. );
  139. };
粤ICP备19079148号