ColorAdjustmentNode.js 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import TempNode from '../core/TempNode.js';
  2. import { ShaderNode, vec3, mat3, add, sub, mul, max, div, dot, float, mix, cos, sin, atan2, sqrt } from '../shadernode/ShaderNodeBaseElements.js';
  3. const luminanceNode = new ShaderNode( ( { color } ) => {
  4. const LUMA = vec3( 0.2125, 0.7154, 0.0721 );
  5. return dot( color, LUMA );
  6. } );
  7. const saturationNode = new ShaderNode( ( { color, adjustment } ) => {
  8. const intensityNode = luminanceNode.call( { color } );
  9. return mix( intensityNode, color, adjustment );
  10. } );
  11. const vibranceNode = new ShaderNode( ( { color, adjustment } ) => {
  12. const average = div( add( color.r, color.g, color.b ), 3.0 );
  13. const mx = max( color.r, max( color.g, color.b ) );
  14. const amt = mul( sub( mx, average ), mul( -3.0, adjustment ) );
  15. return mix( color.rgb, vec3( mx ), amt );
  16. } );
  17. const hueNode = new ShaderNode( ( { color, adjustment } ) => {
  18. const RGBtoYIQ = mat3( 0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135 );
  19. const YIQtoRGB = mat3( 1.0, 0.9563, 0.6210, 1.0, -0.2721, -0.6474, 1.0, -1.107, 1.7046 );
  20. const yiq = mul( RGBtoYIQ, color );
  21. const hue = add( atan2( yiq.z, yiq.y ), adjustment );
  22. const chroma = sqrt( add( mul( yiq.z, yiq.z ), mul( yiq.y, yiq.y ) ) );
  23. return mul( YIQtoRGB, vec3( yiq.x, mul( chroma, cos( hue ) ), mul( chroma, sin( hue ) ) ) );
  24. } );
  25. class ColorAdjustmentNode extends TempNode {
  26. static SATURATION = 'saturation';
  27. static VIBRANCE = 'vibrance';
  28. static HUE = 'hue';
  29. constructor( method, colorNode, adjustmentNode = float( 1 ) ) {
  30. super( 'vec3' );
  31. this.method = method;
  32. this.colorNode = colorNode;
  33. this.adjustmentNode = adjustmentNode;
  34. }
  35. construct() {
  36. const { method, colorNode, adjustmentNode } = this;
  37. const callParams = { color: colorNode, adjustment: adjustmentNode };
  38. let outputNode = null;
  39. if ( method === ColorAdjustmentNode.SATURATION ) {
  40. outputNode = saturationNode.call( callParams );
  41. } else if ( method === ColorAdjustmentNode.VIBRANCE ) {
  42. outputNode = vibranceNode.call( callParams );
  43. } else if ( method === ColorAdjustmentNode.HUE ) {
  44. outputNode = hueNode.call( callParams );
  45. } else {
  46. console.error( `${ this.type }: Method "${ this.method }" not supported!` );
  47. }
  48. return outputNode;
  49. }
  50. }
  51. export default ColorAdjustmentNode;