ShaderNode.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // core
  2. import PropertyNode from './core/PropertyNode.js';
  3. import VarNode from './core/VarNode.js';
  4. // inputs
  5. import ColorNode from './inputs/ColorNode.js';
  6. import FloatNode from './inputs/FloatNode.js';
  7. import Vector2Node from './inputs/Vector2Node.js';
  8. import Vector3Node from './inputs/Vector3Node.js';
  9. import Vector4Node from './inputs/Vector4Node.js';
  10. // accessors
  11. import PositionNode from './accessors/PositionNode.js';
  12. import NormalNode from './accessors/NormalNode.js';
  13. // math
  14. import OperatorNode from './math/OperatorNode.js';
  15. import CondNode from './math/CondNode.js';
  16. import MathNode from './math/MathNode.js';
  17. // utils
  18. import ArrayElementNode from './utils/ArrayElementNode.js';
  19. import JoinNode from './utils/JoinNode.js';
  20. import SplitNode from './utils/SplitNode.js';
  21. // core
  22. import { Vector2, Vector3, Vector4, Color } from 'three';
  23. const NodeHandler = {
  24. construct( NodeClosure, params ) {
  25. const inputs = params.shift();
  26. return NodeClosure( ShaderNodeObjects( inputs ), ...params );
  27. },
  28. get: function ( node, prop ) {
  29. if ( typeof prop === 'string' && node[ prop ] === undefined ) {
  30. const splitProps = prop.match( /^[xyzwst]{1,4}$/ );
  31. if ( splitProps !== null ) {
  32. // accessing properties ( swizzle )
  33. return ShaderNodeObject( new SplitNode( node, splitProps[ 0 ] ) );
  34. } else if ( /^\d+$/.test( prop ) === true ) {
  35. // accessing array
  36. return ShaderNodeObject( new ArrayElementNode( node, new FloatNode( Number( prop ) ).setConst( true ) ) );
  37. }
  38. }
  39. return node[ prop ];
  40. }
  41. };
  42. const ShaderNodeObject = ( obj ) => {
  43. const type = typeof obj;
  44. if ( type === 'number' ) {
  45. return ShaderNodeObject( new FloatNode( obj ).setConst( true ) );
  46. } else if ( type === 'object' ) {
  47. if ( obj.isNode === true ) {
  48. const node = obj;
  49. if ( node.isProxyNode !== true ) {
  50. node.isProxyNode = true;
  51. return new Proxy( node, NodeHandler );
  52. }
  53. }
  54. }
  55. return obj;
  56. };
  57. const ShaderNodeObjects = ( objects ) => {
  58. for ( const name in objects ) {
  59. objects[ name ] = ShaderNodeObject( objects[ name ] );
  60. }
  61. return objects;
  62. };
  63. const ShaderNodeArray = ( array ) => {
  64. const len = array.length;
  65. for ( let i = 0; i < len; i ++ ) {
  66. array[ i ] = ShaderNodeObject( array[ i ] );
  67. }
  68. return array;
  69. };
  70. const ShaderNodeProxy = ( NodeClass, scope = null, factor = null ) => {
  71. if ( scope === null ) {
  72. return ( ...params ) => {
  73. return ShaderNodeObject( new NodeClass( ...ShaderNodeArray( params ) ) );
  74. };
  75. } else if ( factor === null ) {
  76. return ( ...params ) => {
  77. return ShaderNodeObject( new NodeClass( scope, ...ShaderNodeArray( params ) ) );
  78. };
  79. } else {
  80. factor = ShaderNodeObject( factor );
  81. return ( ...params ) => {
  82. return ShaderNodeObject( new NodeClass( scope, ...ShaderNodeArray( params ), factor ) );
  83. };
  84. }
  85. };
  86. const ShaderNodeScript = function ( jsFunc ) {
  87. return ( inputs, builder ) => {
  88. ShaderNodeObjects( inputs );
  89. return ShaderNodeObject( jsFunc( inputs, builder ) );
  90. };
  91. };
  92. export const ShaderNode = new Proxy( ShaderNodeScript, NodeHandler );
  93. //
  94. // Node Material Shader Syntax
  95. //
  96. export const uniform = new ShaderNode( ( inputNode ) => {
  97. inputNode.setConst( false );
  98. return inputNode;
  99. } );
  100. export const float = ( val ) => {
  101. return ShaderNodeObject( new FloatNode( val ).setConst( true ) );
  102. };
  103. export const color = ( ...params ) => {
  104. return ShaderNodeObject( new ColorNode( new Color( ...params ) ).setConst( true ) );
  105. };
  106. export const join = ( ...params ) => {
  107. return ShaderNodeObject( new JoinNode( ShaderNodeArray( params ) ) );
  108. };
  109. export const cond = ( ...params ) => {
  110. return ShaderNodeObject( new CondNode( ...ShaderNodeArray( params ) ) );
  111. };
  112. export const vec2 = ( ...params ) => {
  113. // Providing one scalar value: This value is used for all components
  114. if ( params.length === 1 ) {
  115. params[ 1 ] = params[ 0 ];
  116. }
  117. return ShaderNodeObject( new Vector2Node( new Vector2( ...params ) ).setConst( true ) );
  118. };
  119. export const vec3 = ( ...params ) => {
  120. // Providing one scalar value: This value is used for all components
  121. if ( params.length === 1 ) {
  122. params[ 1 ] = params[ 2 ] = params[ 0 ];
  123. }
  124. return ShaderNodeObject( new Vector3Node( new Vector3( ...params ) ).setConst( true ) );
  125. };
  126. export const vec4 = ( ...params ) => {
  127. // Providing one scalar value: This value is used for all components
  128. if ( params.length === 1 ) {
  129. params[ 1 ] = params[ 2 ] = params[ 3 ] = params[ 0 ];
  130. }
  131. return ShaderNodeObject( new Vector4Node( new Vector4( ...params ) ).setConst( true ) );
  132. };
  133. export const add = ShaderNodeProxy( OperatorNode, '+' );
  134. export const sub = ShaderNodeProxy( OperatorNode, '-' );
  135. export const mul = ShaderNodeProxy( OperatorNode, '*' );
  136. export const div = ShaderNodeProxy( OperatorNode, '/' );
  137. export const equal = ShaderNodeProxy( OperatorNode, '==' );
  138. export const assign = ShaderNodeProxy( OperatorNode, '=' );
  139. export const greaterThan = ShaderNodeProxy( OperatorNode, '>' );
  140. export const and = ShaderNodeProxy( OperatorNode, '&&' );
  141. export const element = ShaderNodeProxy( ArrayElementNode );
  142. export const normalLocal = new NormalNode( NormalNode.LOCAL );
  143. export const normalWorld = new NormalNode( NormalNode.WORLD );
  144. export const normalView = new NormalNode( NormalNode.VIEW );
  145. export const transformedNormalView = new VarNode( new NormalNode( NormalNode.VIEW ), 'TransformedNormalView', 'vec3' );
  146. export const positionLocal = new PositionNode( PositionNode.LOCAL );
  147. export const positionWorld = new PositionNode( PositionNode.WORLD );
  148. export const positionView = new PositionNode( PositionNode.VIEW );
  149. export const positionViewDirection = new PositionNode( PositionNode.VIEW_DIRECTION );
  150. export const PI = float( 3.141592653589793 );
  151. export const RECIPROCAL_PI = float( 0.3183098861837907 );
  152. export const EPSILON = float( 1e-6 );
  153. export const materialDiffuseColor = new PropertyNode( 'MaterialDiffuseColor', 'vec4' );
  154. export const materialRoughness = new PropertyNode( 'MaterialRoughness', 'float' );
  155. export const materialSpecularTint = new PropertyNode( 'MaterialSpecularTint', 'vec4' );
  156. export const negate = ShaderNodeProxy( MathNode, 'negate' );
  157. export const floor = ShaderNodeProxy( MathNode, 'floor' );
  158. export const mod = ShaderNodeProxy( MathNode, 'mod' );
  159. export const cross = ShaderNodeProxy( MathNode, 'cross' );
  160. export const max = ShaderNodeProxy( MathNode, 'max' );
  161. export const min = ShaderNodeProxy( MathNode, 'min' );
  162. export const dot = ShaderNodeProxy( MathNode, 'dot' );
  163. export const normalize = ShaderNodeProxy( MathNode, 'normalize' );
  164. export const sqrt = ShaderNodeProxy( MathNode, 'sqrt' );
  165. export const inversesqrt = ShaderNodeProxy( MathNode, 'inversesqrt' );
  166. export const sign = ShaderNodeProxy( MathNode, 'sign' );
  167. export const dFdx = ShaderNodeProxy( MathNode, 'dFdx' );
  168. export const dFdy = ShaderNodeProxy( MathNode, 'dFdy' );
  169. export const pow = ShaderNodeProxy( MathNode, 'pow' );
  170. export const pow2 = ShaderNodeProxy( MathNode, 'pow', 2 );
  171. export const pow3 = ShaderNodeProxy( MathNode, 'pow', 3 );
  172. export const pow4 = ShaderNodeProxy( MathNode, 'pow', 4 );
  173. export const exp2 = ShaderNodeProxy( MathNode, 'exp2' );
  174. export const saturate = ShaderNodeProxy( MathNode, 'saturate' );
  175. export const transformDirection = ShaderNodeProxy( MathNode, 'transformDirection' );