BlendModeNode.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import TempNode from '../core/TempNode.js';
  2. import { EPSILON } from '../math/MathNode.js';
  3. import { addNodeClass } from '../core/Node.js';
  4. import { addNodeElement, ShaderNode, nodeProxy, vec3 } from '../shadernode/ShaderNode.js';
  5. export const BurnNode = new ShaderNode( ( { base, blend } ) => {
  6. const fn = ( c ) => blend[ c ].lessThan( EPSILON ).cond( blend[ c ], base[ c ].oneMinus().div( blend[ c ] ).oneMinus().max( 0 ) );
  7. return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) );
  8. } );
  9. export const DodgeNode = new ShaderNode( ( { base, blend } ) => {
  10. const fn = ( c ) => blend[ c ].equal( 1.0 ).cond( blend[ c ], base[ c ].div( blend[ c ].oneMinus() ).max( 0 ) );
  11. return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) );
  12. } );
  13. export const ScreenNode = new ShaderNode( ( { base, blend } ) => {
  14. const fn = ( c ) => base[ c ].oneMinus().mul( blend[ c ].oneMinus() ).oneMinus();
  15. return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) );
  16. } );
  17. export const OverlayNode = new ShaderNode( ( { base, blend } ) => {
  18. const fn = ( c ) => base[ c ].lessThan( 0.5 ).cond( base[ c ].mul( blend[ c ], 2.0 ), base[ c ].oneMinus().mul( blend[ c ].oneMinus() ).oneMinus() );
  19. return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) );
  20. } );
  21. class BlendModeNode extends TempNode {
  22. constructor( blendMode, baseNode, blendNode ) {
  23. super();
  24. this.blendMode = blendMode;
  25. this.baseNode = baseNode;
  26. this.blendNode = blendNode;
  27. }
  28. construct() {
  29. const { blendMode, baseNode, blendNode } = this;
  30. const params = { base: baseNode, blend: blendNode };
  31. let outputNode = null;
  32. if ( blendMode === BlendModeNode.BURN ) {
  33. outputNode = BurnNode.call( params );
  34. } else if ( blendMode === BlendModeNode.DODGE ) {
  35. outputNode = DodgeNode.call( params );
  36. } else if ( blendMode === BlendModeNode.SCREEN ) {
  37. outputNode = ScreenNode.call( params );
  38. } else if ( blendMode === BlendModeNode.OVERLAY ) {
  39. outputNode = OverlayNode.call( params );
  40. }
  41. return outputNode;
  42. }
  43. }
  44. BlendModeNode.BURN = 'burn';
  45. BlendModeNode.DODGE = 'dodge';
  46. BlendModeNode.SCREEN = 'screen';
  47. BlendModeNode.OVERLAY = 'overlay';
  48. export default BlendModeNode;
  49. export const burn = nodeProxy( BlendModeNode, BlendModeNode.BURN );
  50. export const dodge = nodeProxy( BlendModeNode, BlendModeNode.DODGE );
  51. export const overlay = nodeProxy( BlendModeNode, BlendModeNode.OVERLAY );
  52. export const screen = nodeProxy( BlendModeNode, BlendModeNode.SCREEN );
  53. addNodeElement( 'burn', burn );
  54. addNodeElement( 'dodge', dodge );
  55. addNodeElement( 'overlay', overlay );
  56. addNodeElement( 'screen', screen );
  57. addNodeClass( BlendModeNode );