ColorAdjustmentNode.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import TempNode from '../core/TempNode.js';
  2. import { dot, mix } from '../math/MathNode.js';
  3. import { add } from '../math/OperatorNode.js';
  4. import { addNodeClass } from '../core/Node.js';
  5. import { addNodeElement, tslFn, nodeProxy, float, vec3 } from '../shadernode/ShaderNode.js';
  6. const saturationNode = tslFn( ( { color, adjustment } ) => {
  7. return adjustment.mix( luminance( color.rgb ), color.rgb );
  8. } );
  9. const vibranceNode = tslFn( ( { color, adjustment } ) => {
  10. const average = add( color.r, color.g, color.b ).div( 3.0 );
  11. const mx = color.r.max( color.g.max( color.b ) );
  12. const amt = mx.sub( average ).mul( adjustment ).mul( - 3.0 );
  13. return mix( color.rgb, mx, amt );
  14. } );
  15. const hueNode = tslFn( ( { color, adjustment } ) => {
  16. const k = vec3( 0.57735, 0.57735, 0.57735 );
  17. const cosAngle = adjustment.cos();
  18. return vec3( color.rgb.mul( cosAngle ).add( k.cross( color.rgb ).mul( adjustment.sin() ).add( k.mul( dot( k, color.rgb ).mul( cosAngle.oneMinus() ) ) ) ) );
  19. } );
  20. class ColorAdjustmentNode extends TempNode {
  21. constructor( method, colorNode, adjustmentNode = float( 1 ) ) {
  22. super( 'vec3' );
  23. this.method = method;
  24. this.colorNode = colorNode;
  25. this.adjustmentNode = adjustmentNode;
  26. }
  27. setup() {
  28. const { method, colorNode, adjustmentNode } = this;
  29. const callParams = { color: colorNode, adjustment: adjustmentNode };
  30. let outputNode = null;
  31. if ( method === ColorAdjustmentNode.SATURATION ) {
  32. outputNode = saturationNode( callParams );
  33. } else if ( method === ColorAdjustmentNode.VIBRANCE ) {
  34. outputNode = vibranceNode( callParams );
  35. } else if ( method === ColorAdjustmentNode.HUE ) {
  36. outputNode = hueNode( callParams );
  37. } else {
  38. console.error( `${ this.type }: Method "${ this.method }" not supported!` );
  39. }
  40. return outputNode;
  41. }
  42. }
  43. ColorAdjustmentNode.SATURATION = 'saturation';
  44. ColorAdjustmentNode.VIBRANCE = 'vibrance';
  45. ColorAdjustmentNode.HUE = 'hue';
  46. export default ColorAdjustmentNode;
  47. export const saturation = nodeProxy( ColorAdjustmentNode, ColorAdjustmentNode.SATURATION );
  48. export const vibrance = nodeProxy( ColorAdjustmentNode, ColorAdjustmentNode.VIBRANCE );
  49. export const hue = nodeProxy( ColorAdjustmentNode, ColorAdjustmentNode.HUE );
  50. export const lumaCoeffs = vec3( 0.2125, 0.7154, 0.0721 );
  51. export const luminance = ( color, luma = lumaCoeffs ) => dot( color, luma );
  52. export const threshold = ( color, threshold ) => mix( vec3( 0.0 ), color, luminance( color ).sub( threshold ).max( 0 ) );
  53. addNodeElement( 'saturation', saturation );
  54. addNodeElement( 'vibrance', vibrance );
  55. addNodeElement( 'hue', hue );
  56. addNodeElement( 'threshold', threshold );
  57. addNodeClass( 'ColorAdjustmentNode', ColorAdjustmentNode );