Lut3DNode.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { TempNode } from 'three/webgpu';
  2. import { nodeObject, Fn, float, uniform, vec3, vec4, mix } from 'three/tsl';
  3. /**
  4. * A post processing node for color grading via lookup tables.
  5. *
  6. * @augments TempNode
  7. * @three_import import { lut3D } from 'three/addons/tsl/display/Lut3DNode.js';
  8. */
  9. class Lut3DNode extends TempNode {
  10. static get type() {
  11. return 'Lut3DNode';
  12. }
  13. /**
  14. * Constructs a new LUT node.
  15. *
  16. * @param {Node} inputNode - The node that represents the input of the effect.
  17. * @param {TextureNode} lutNode - A texture node that represents the lookup table.
  18. * @param {number} size - The size of the lookup table.
  19. * @param {Node<float>} intensityNode - Controls the intensity of the effect.
  20. */
  21. constructor( inputNode, lutNode, size, intensityNode ) {
  22. super( 'vec4' );
  23. /**
  24. * The node that represents the input of the effect.
  25. *
  26. * @type {Node}
  27. */
  28. this.inputNode = inputNode;
  29. /**
  30. * A texture node that represents the lookup table.
  31. *
  32. * @type {TextureNode}
  33. */
  34. this.lutNode = lutNode;
  35. /**
  36. * The size of the lookup table.
  37. *
  38. * @type {UniformNode<float>}
  39. */
  40. this.size = uniform( size );
  41. /**
  42. * Controls the intensity of the effect.
  43. *
  44. * @type {Node<float>}
  45. */
  46. this.intensityNode = intensityNode;
  47. }
  48. /**
  49. * This method is used to setup the effect's TSL code.
  50. *
  51. * @param {NodeBuilder} builder - The current node builder.
  52. * @return {ShaderCallNodeInternal}
  53. */
  54. setup() {
  55. const { inputNode, lutNode } = this;
  56. const sampleLut = ( uv ) => lutNode.sample( uv );
  57. const lut3D = Fn( () => {
  58. const base = inputNode;
  59. // pull the sample in by half a pixel so the sample begins at the center of the edge pixels.
  60. const pixelWidth = float( 1.0 ).div( this.size );
  61. const halfPixelWidth = float( 0.5 ).div( this.size );
  62. const uvw = vec3( halfPixelWidth ).add( base.rgb.mul( float( 1.0 ).sub( pixelWidth ) ) );
  63. const lutValue = vec4( sampleLut( uvw ).rgb, base.a );
  64. return vec4( mix( base, lutValue, this.intensityNode ) );
  65. } );
  66. const outputNode = lut3D();
  67. return outputNode;
  68. }
  69. }
  70. export default Lut3DNode;
  71. /**
  72. * TSL function for creating a LUT node for color grading via post processing.
  73. *
  74. * @tsl
  75. * @function
  76. * @param {Node} node - The node that represents the input of the effect.
  77. * @param {TextureNode} lut - A texture node that represents the lookup table.
  78. * @param {number} size - The size of the lookup table.
  79. * @param {Node<float> | number} intensity - Controls the intensity of the effect.
  80. * @returns {Lut3DNode}
  81. */
  82. export const lut3D = ( node, lut, size, intensity ) => nodeObject( new Lut3DNode( nodeObject( node ), nodeObject( lut ), size, nodeObject( intensity ) ) );