ShaderNode.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. // core nodes
  2. import PropertyNode from './core/PropertyNode.js';
  3. import VarNode from './core/VarNode.js';
  4. import AttributeNode from './core/AttributeNode.js';
  5. // input nodes
  6. import ColorNode from './inputs/ColorNode.js';
  7. import FloatNode from './inputs/FloatNode.js';
  8. import IntNode from './inputs/IntNode.js';
  9. import Vector2Node from './inputs/Vector2Node.js';
  10. import Vector3Node from './inputs/Vector3Node.js';
  11. import Vector4Node from './inputs/Vector4Node.js';
  12. import Matrix3Node from './inputs/Matrix3Node.js';
  13. import Matrix4Node from './inputs/Matrix4Node.js';
  14. import TextureNode from './inputs/TextureNode.js';
  15. // accessor nodes
  16. import PositionNode from './accessors/PositionNode.js';
  17. import NormalNode from './accessors/NormalNode.js';
  18. import UVNode from './accessors/UVNode.js';
  19. // math nodes
  20. import OperatorNode from './math/OperatorNode.js';
  21. import CondNode from './math/CondNode.js';
  22. import MathNode from './math/MathNode.js';
  23. // util nodes
  24. import ArrayElementNode from './utils/ArrayElementNode.js';
  25. import ConvertNode from './utils/ConvertNode.js';
  26. import JoinNode from './utils/JoinNode.js';
  27. import SplitNode from './utils/SplitNode.js';
  28. // core
  29. import { Vector2, Vector3, Vector4, Matrix3, Matrix4, Color } from 'three';
  30. const NodeHandler = {
  31. construct( NodeClosure, params ) {
  32. const inputs = params.shift();
  33. return NodeClosure( new ShaderNodeObjects( inputs ), ...params );
  34. },
  35. get: function ( node, prop ) {
  36. if ( typeof prop === 'string' && node[ prop ] === undefined ) {
  37. if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true ) {
  38. // accessing properties ( swizzle )
  39. prop = prop
  40. .replace( /r|s/g, 'x' )
  41. .replace( /g|t/g, 'y' )
  42. .replace( /b|p/g, 'z' )
  43. .replace( /a|q/g, 'w' );
  44. return new ShaderNodeObject( new SplitNode( node, prop ) );
  45. } else if ( /^\d+$/.test( prop ) === true ) {
  46. // accessing array
  47. return new ShaderNodeObject( new ArrayElementNode( node, new FloatNode( Number( prop ) ).setConst( true ) ) );
  48. }
  49. }
  50. return node[ prop ];
  51. }
  52. };
  53. const nodeObjects = new WeakMap();
  54. const ShaderNodeObject = function( obj ) {
  55. const type = typeof obj;
  56. if ( type === 'number' ) {
  57. return new ShaderNodeObject( new FloatNode( obj ).setConst( true ) );
  58. } else if ( type === 'object' ) {
  59. if ( obj.isNode === true ) {
  60. let nodeObject = nodeObjects.get( obj );
  61. if ( nodeObject === undefined ) {
  62. nodeObject = new Proxy( obj, NodeHandler );
  63. nodeObjects.set( obj, nodeObject );
  64. nodeObjects.set( nodeObject, nodeObject );
  65. }
  66. return nodeObject;
  67. }
  68. }
  69. return obj;
  70. };
  71. const ShaderNodeObjects = function( objects ) {
  72. for ( const name in objects ) {
  73. objects[ name ] = new ShaderNodeObject( objects[ name ] );
  74. }
  75. return objects;
  76. };
  77. const getShaderNodeArray = ( array ) => {
  78. const len = array.length;
  79. for ( let i = 0; i < len; i ++ ) {
  80. array[ i ] = new ShaderNodeObject( array[ i ] );
  81. }
  82. return array;
  83. };
  84. const ShaderNodeProxy = function( NodeClass, scope = null, factor = null ) {
  85. if ( scope === null ) {
  86. return ( ...params ) => {
  87. return new ShaderNodeObject( new NodeClass( ...getShaderNodeArray( params ) ) );
  88. };
  89. } else if ( factor === null ) {
  90. return ( ...params ) => {
  91. return new ShaderNodeObject( new NodeClass( scope, ...getShaderNodeArray( params ) ) );
  92. };
  93. } else {
  94. factor = new ShaderNodeObject( factor );
  95. return ( ...params ) => {
  96. return new ShaderNodeObject( new NodeClass( scope, ...getShaderNodeArray( params ), factor ) );
  97. };
  98. }
  99. };
  100. const ShaderNodeScript = function ( jsFunc ) {
  101. return ( inputs, builder ) => {
  102. new ShaderNodeObjects( inputs );
  103. return new ShaderNodeObject( jsFunc( inputs, builder ) );
  104. };
  105. };
  106. export const ShaderNode = new Proxy( ShaderNodeScript, NodeHandler );
  107. //
  108. // Node Material Shader Syntax
  109. //
  110. export const uniform = new ShaderNode( ( inputNode ) => {
  111. inputNode.setConst( false );
  112. return inputNode;
  113. } );
  114. export const nodeObject = ( val ) => {
  115. return new ShaderNodeObject( val );
  116. };
  117. export const label = ( node, name = null, nodeType = null ) => {
  118. if ( node.isVarNode === true ) {
  119. // node is already a VarNode
  120. if ( ( node.name !== name ) && ( name !== null ) ) {
  121. node.name = name;
  122. }
  123. if ( ( node.nodeType !== nodeType ) && ( nodeType !== null ) ) {
  124. node.nodeType = nodeType;
  125. }
  126. return nodeObject( node );
  127. }
  128. return nodeObject( new VarNode( nodeObject( node ), name, nodeType ) );
  129. };
  130. export const temp = ( node, nodeType = null ) => label( node, null, nodeType );
  131. const ConvertType = function ( nodeClass, type, valueClass = null, valueComponents = 1 ) {
  132. return ( ...params ) => {
  133. if ( params[ 0 ]?.isNode === true ) {
  134. return nodeObject( new ConvertNode( params[ 0 ], type ) );
  135. }
  136. if ( ( params.length === 1 ) && ( valueComponents !== 1 ) ) {
  137. // Providing one scalar value: This value is used for all components
  138. for ( let i = 1; i < valueComponents; i ++ ) {
  139. params[ i ] = params [ 0 ];
  140. }
  141. }
  142. const val = ( ( valueClass === null ) || ( params[ 0 ] instanceof valueClass ) ) ? params[ 0 ] : new valueClass().set( ...params );
  143. return nodeObject( new nodeClass( val ).setConst( true ) );
  144. };
  145. };
  146. export const float = new ConvertType( FloatNode, 'float' );
  147. export const int = new ConvertType( IntNode, 'int' );
  148. export const color = new ConvertType( ColorNode, 'color', Color );
  149. export const vec2 = new ConvertType( Vector2Node, 'vec2', Vector2, 2 );
  150. export const vec3 = new ConvertType( Vector3Node, 'vec3', Vector3, 3 );
  151. export const vec4 = new ConvertType( Vector4Node, 'vec4', Vector4, 4 );
  152. export const mat3 = new ConvertType( Matrix3Node, 'mat3', Matrix3 );
  153. export const mat4 = new ConvertType( Matrix4Node, 'mat4', Matrix4 );
  154. export const join = ( ...params ) => {
  155. return nodeObject( new JoinNode( getShaderNodeArray( params ) ) );
  156. };
  157. export const cond = ( ...params ) => {
  158. return nodeObject( new CondNode( ...getShaderNodeArray( params ) ) );
  159. };
  160. export const addTo = ( varNode, ...params ) => {
  161. varNode.node = add( varNode.node, ...getShaderNodeArray( params ) );
  162. return nodeObject( varNode );
  163. };
  164. export const uv = new ShaderNodeProxy( UVNode );
  165. export const attribute = new ShaderNodeProxy( AttributeNode );
  166. export const texture = new ShaderNodeProxy( TextureNode );
  167. export const add = new ShaderNodeProxy( OperatorNode, '+' );
  168. export const sub = new ShaderNodeProxy( OperatorNode, '-' );
  169. export const mul = new ShaderNodeProxy( OperatorNode, '*' );
  170. export const div = new ShaderNodeProxy( OperatorNode, '/' );
  171. export const remainder = new ShaderNodeProxy( OperatorNode, '%' );
  172. export const equal = new ShaderNodeProxy( OperatorNode, '==' );
  173. export const assign = new ShaderNodeProxy( OperatorNode, '=' );
  174. export const lessThan = new ShaderNodeProxy( OperatorNode, '<' );
  175. export const greaterThan = new ShaderNodeProxy( OperatorNode, '>' );
  176. export const lessThanEqual = new ShaderNodeProxy( OperatorNode, '<=' );
  177. export const greaterThanEqual = new ShaderNodeProxy( OperatorNode, '>=' );
  178. export const and = new ShaderNodeProxy( OperatorNode, '&&' );
  179. export const or = new ShaderNodeProxy( OperatorNode, '||' );
  180. export const xor = new ShaderNodeProxy( OperatorNode, '^^' );
  181. export const bitAnd = new ShaderNodeProxy( OperatorNode, '&' );
  182. export const bitOr = new ShaderNodeProxy( OperatorNode, '|' );
  183. export const bitXor = new ShaderNodeProxy( OperatorNode, '^' );
  184. export const shiftLeft = new ShaderNodeProxy( OperatorNode, '<<' );
  185. export const shiftRight = new ShaderNodeProxy( OperatorNode, '>>' );
  186. export const element = new ShaderNodeProxy( ArrayElementNode );
  187. export const normalGeometry = new ShaderNodeObject( new NormalNode( NormalNode.GEOMETRY ) );
  188. export const normalLocal = new ShaderNodeObject( new NormalNode( NormalNode.LOCAL ) );
  189. export const normalWorld = new ShaderNodeObject( new NormalNode( NormalNode.WORLD ) );
  190. export const normalView = new ShaderNodeObject( new NormalNode( NormalNode.VIEW ) );
  191. export const transformedNormalView = new ShaderNodeObject( new VarNode( new NormalNode( NormalNode.VIEW ), 'TransformedNormalView', 'vec3' ) );
  192. export const positionLocal = new ShaderNodeObject( new PositionNode( PositionNode.LOCAL ) );
  193. export const positionWorld = new ShaderNodeObject( new PositionNode( PositionNode.WORLD ) );
  194. export const positionView = new ShaderNodeObject( new PositionNode( PositionNode.VIEW ) );
  195. export const positionViewDirection = new ShaderNodeObject( new PositionNode( PositionNode.VIEW_DIRECTION ) );
  196. export const PI = float( 3.141592653589793 );
  197. export const PI2 = float( 6.283185307179586 );
  198. export const PI_HALF = float( 1.5707963267948966 );
  199. export const RECIPROCAL_PI = float( 0.3183098861837907 );
  200. export const RECIPROCAL_PI2 = float( 0.15915494309189535 );
  201. export const EPSILON = float( 1e-6 );
  202. export const diffuseColor = new ShaderNodeObject( new PropertyNode( 'DiffuseColor', 'vec4' ) );
  203. export const roughness = new ShaderNodeObject( new PropertyNode( 'Roughness', 'float' ) );
  204. export const metalness = new ShaderNodeObject( new PropertyNode( 'Metalness', 'float' ) );
  205. export const alphaTest = new ShaderNodeObject( new PropertyNode( 'AlphaTest', 'float' ) );
  206. export const specularColor = new ShaderNodeObject( new PropertyNode( 'SpecularColor', 'color' ) );
  207. export const abs = new ShaderNodeProxy( MathNode, 'abs' );
  208. export const acos = new ShaderNodeProxy( MathNode, 'acos' );
  209. export const asin = new ShaderNodeProxy( MathNode, 'asin' );
  210. export const atan = new ShaderNodeProxy( MathNode, 'atan' );
  211. export const ceil = new ShaderNodeProxy( MathNode, 'ceil' );
  212. export const clamp = new ShaderNodeProxy( MathNode, 'clamp' );
  213. export const cos = new ShaderNodeProxy( MathNode, 'cos' );
  214. export const cross = new ShaderNodeProxy( MathNode, 'cross' );
  215. export const degrees = new ShaderNodeProxy( MathNode, 'degrees' );
  216. export const dFdx = new ShaderNodeProxy( MathNode, 'dFdx' );
  217. export const dFdy = new ShaderNodeProxy( MathNode, 'dFdy' );
  218. export const distance = new ShaderNodeProxy( MathNode, 'distance' );
  219. export const dot = new ShaderNodeProxy( MathNode, 'dot' );
  220. export const exp = new ShaderNodeProxy( MathNode, 'exp' );
  221. export const exp2 = new ShaderNodeProxy( MathNode, 'exp2' );
  222. export const faceforward = new ShaderNodeProxy( MathNode, 'faceforward' );
  223. export const floor = new ShaderNodeProxy( MathNode, 'floor' );
  224. export const fract = new ShaderNodeProxy( MathNode, 'fract' );
  225. export const invert = new ShaderNodeProxy( MathNode, 'invert' );
  226. export const inversesqrt = new ShaderNodeProxy( MathNode, 'inversesqrt' );
  227. export const length = new ShaderNodeProxy( MathNode, 'length' );
  228. export const log = new ShaderNodeProxy( MathNode, 'log' );
  229. export const log2 = new ShaderNodeProxy( MathNode, 'log2' );
  230. export const max = new ShaderNodeProxy( MathNode, 'max' );
  231. export const min = new ShaderNodeProxy( MathNode, 'min' );
  232. export const mix = new ShaderNodeProxy( MathNode, 'mix' );
  233. export const mod = new ShaderNodeProxy( MathNode, 'mod' );
  234. export const negate = new ShaderNodeProxy( MathNode, 'negate' );
  235. export const normalize = new ShaderNodeProxy( MathNode, 'normalize' );
  236. export const pow = new ShaderNodeProxy( MathNode, 'pow' );
  237. export const pow2 = new ShaderNodeProxy( MathNode, 'pow', 2 );
  238. export const pow3 = new ShaderNodeProxy( MathNode, 'pow', 3 );
  239. export const pow4 = new ShaderNodeProxy( MathNode, 'pow', 4 );
  240. export const radians = new ShaderNodeProxy( MathNode, 'radians' );
  241. export const reflect = new ShaderNodeProxy( MathNode, 'reflect' );
  242. export const refract = new ShaderNodeProxy( MathNode, 'refract' );
  243. export const round = new ShaderNodeProxy( MathNode, 'round' );
  244. export const saturate = new ShaderNodeProxy( MathNode, 'saturate' );
  245. export const sign = new ShaderNodeProxy( MathNode, 'sign' );
  246. export const sin = new ShaderNodeProxy( MathNode, 'sin' );
  247. export const smoothstep = new ShaderNodeProxy( MathNode, 'smoothstep' );
  248. export const sqrt = new ShaderNodeProxy( MathNode, 'sqrt' );
  249. export const step = new ShaderNodeProxy( MathNode, 'step' );
  250. export const tan = new ShaderNodeProxy( MathNode, 'tan' );
  251. export const transformDirection = new ShaderNodeProxy( MathNode, 'transformDirection' );