2
0
Эх сурвалжийг харах

Nodes: Rework ShaderNodeElements and make some other refactorings (#25498)

* Nodes: Rework ShaderNodeElements and make some other refactorings

* Fixes

* fix add assign

* Fix circular dependency and clean up

* Rename addNode -> addNodeElement and LightsNode.setReference -> addLightNode, add addNodeClass and addNodeMaterial

---------

Co-authored-by: sunag <[email protected]>
Levi Pesin 2 жил өмнө
parent
commit
71c70a81b0
100 өөрчлөгдсөн 1428 нэмэгдсэн , 1072 устгасан
  1. 133 368
      examples/jsm/nodes/Nodes.js
  2. 38 11
      examples/jsm/nodes/accessors/BitangentNode.js
  3. 6 0
      examples/jsm/nodes/accessors/BufferNode.js
  4. 10 0
      examples/jsm/nodes/accessors/CameraNode.js
  5. 11 8
      examples/jsm/nodes/accessors/CubeTextureNode.js
  6. 12 6
      examples/jsm/nodes/accessors/ExtendedMaterialNode.js
  7. 17 21
      examples/jsm/nodes/accessors/InstanceNode.js
  8. 35 23
      examples/jsm/nodes/accessors/MaterialNode.js
  9. 6 0
      examples/jsm/nodes/accessors/MaterialReferenceNode.js
  10. 11 0
      examples/jsm/nodes/accessors/ModelNode.js
  11. 12 8
      examples/jsm/nodes/accessors/ModelViewProjectionNode.js
  12. 24 14
      examples/jsm/nodes/accessors/NormalNode.js
  13. 15 4
      examples/jsm/nodes/accessors/Object3DNode.js
  14. 6 1
      examples/jsm/nodes/accessors/PointUVNode.js
  15. 25 16
      examples/jsm/nodes/accessors/PositionNode.js
  16. 10 5
      examples/jsm/nodes/accessors/ReferenceNode.js
  17. 9 4
      examples/jsm/nodes/accessors/ReflectVectorNode.js
  18. 43 40
      examples/jsm/nodes/accessors/SkinningNode.js
  19. 6 0
      examples/jsm/nodes/accessors/StorageBufferNode.js
  20. 23 15
      examples/jsm/nodes/accessors/TangentNode.js
  21. 11 2
      examples/jsm/nodes/accessors/TextureNode.js
  22. 6 0
      examples/jsm/nodes/accessors/UVNode.js
  23. 6 0
      examples/jsm/nodes/accessors/UserDataNode.js
  24. 3 0
      examples/jsm/nodes/core/ArrayUniformNode.js
  25. 8 3
      examples/jsm/nodes/core/AttributeNode.js
  26. 8 1
      examples/jsm/nodes/core/BypassNode.js
  27. 8 1
      examples/jsm/nodes/core/CacheNode.js
  28. 6 1
      examples/jsm/nodes/core/CodeNode.js
  29. 3 0
      examples/jsm/nodes/core/ConstNode.js
  30. 8 1
      examples/jsm/nodes/core/ContextNode.js
  31. 11 6
      examples/jsm/nodes/core/ExpressionNode.js
  32. 14 0
      examples/jsm/nodes/core/FunctionCallNode.js
  33. 8 7
      examples/jsm/nodes/core/FunctionNode.js
  34. 3 1
      examples/jsm/nodes/core/InputNode.js
  35. 6 1
      examples/jsm/nodes/core/InstanceIndexNode.js
  36. 2 0
      examples/jsm/nodes/core/LightingModel.js
  37. 42 9
      examples/jsm/nodes/core/Node.js
  38. 10 8
      examples/jsm/nodes/core/NodeBuilder.js
  39. 12 1
      examples/jsm/nodes/core/PropertyNode.js
  40. 11 6
      examples/jsm/nodes/core/StackNode.js
  41. 4 2
      examples/jsm/nodes/core/TempNode.js
  42. 15 0
      examples/jsm/nodes/core/UniformNode.js
  43. 18 32
      examples/jsm/nodes/core/VarNode.js
  44. 8 1
      examples/jsm/nodes/core/VaryingNode.js
  45. 5 0
      examples/jsm/nodes/core/constants.js
  46. 20 6
      examples/jsm/nodes/display/BlendModeNode.js
  47. 26 10
      examples/jsm/nodes/display/ColorAdjustmentNode.js
  48. 16 26
      examples/jsm/nodes/display/ColorSpaceNode.js
  49. 7 1
      examples/jsm/nodes/display/FrontFacingNode.js
  50. 31 18
      examples/jsm/nodes/display/NormalMapNode.js
  51. 10 3
      examples/jsm/nodes/display/PosterizeNode.js
  52. 14 9
      examples/jsm/nodes/display/ToneMappingNode.js
  53. 18 7
      examples/jsm/nodes/display/ViewportNode.js
  54. 11 3
      examples/jsm/nodes/fog/FogExp2Node.js
  55. 9 3
      examples/jsm/nodes/fog/FogNode.js
  56. 11 2
      examples/jsm/nodes/fog/FogRangeNode.js
  57. 9 6
      examples/jsm/nodes/functions/BSDF/BRDF_BlinnPhong.js
  58. 10 13
      examples/jsm/nodes/functions/BSDF/BRDF_GGX.js
  59. 2 2
      examples/jsm/nodes/functions/BSDF/BRDF_Lambert.js
  60. 6 4
      examples/jsm/nodes/functions/BSDF/DFGApprox.js
  61. 4 4
      examples/jsm/nodes/functions/BSDF/D_GGX.js
  62. 2 2
      examples/jsm/nodes/functions/BSDF/F_Schlick.js
  63. 7 5
      examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated.js
  64. 10 11
      examples/jsm/nodes/functions/PhongLightingModel.js
  65. 31 29
      examples/jsm/nodes/functions/PhysicalLightingModel.js
  66. 4 7
      examples/jsm/nodes/functions/light/getDistanceAttenuation.js
  67. 4 3
      examples/jsm/nodes/functions/material/getGeometryRoughness.js
  68. 4 4
      examples/jsm/nodes/functions/material/getRoughness.js
  69. 10 5
      examples/jsm/nodes/geometry/RangeNode.js
  70. 8 1
      examples/jsm/nodes/gpgpu/ComputeNode.js
  71. 5 3
      examples/jsm/nodes/lighting/AONode.js
  72. 7 4
      examples/jsm/nodes/lighting/AmbientLightNode.js
  73. 4 1
      examples/jsm/nodes/lighting/AnalyticLightNode.js
  74. 7 4
      examples/jsm/nodes/lighting/DirectionalLightNode.js
  75. 19 11
      examples/jsm/nodes/lighting/EnvironmentNode.js
  76. 15 10
      examples/jsm/nodes/lighting/HemisphereLightNode.js
  77. 9 5
      examples/jsm/nodes/lighting/IESSpotLightNode.js
  78. 10 1
      examples/jsm/nodes/lighting/LightingContextNode.js
  79. 3 1
      examples/jsm/nodes/lighting/LightingNode.js
  80. 16 8
      examples/jsm/nodes/lighting/LightsNode.js
  81. 9 4
      examples/jsm/nodes/lighting/PointLightNode.js
  82. 10 4
      examples/jsm/nodes/lighting/SpotLightNode.js
  83. 4 3
      examples/jsm/nodes/loaders/NodeLoader.js
  84. 4 20
      examples/jsm/nodes/loaders/NodeMaterialLoader.js
  85. 4 1
      examples/jsm/nodes/materials/LineBasicNodeMaterial.js
  86. 11 61
      examples/jsm/nodes/materials/Materials.js
  87. 4 1
      examples/jsm/nodes/materials/MeshBasicNodeMaterial.js
  88. 9 2
      examples/jsm/nodes/materials/MeshNormalNodeMaterial.js
  89. 8 8
      examples/jsm/nodes/materials/MeshPhongNodeMaterial.js
  90. 6 1
      examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js
  91. 10 7
      examples/jsm/nodes/materials/MeshStandardNodeMaterial.js
  92. 87 30
      examples/jsm/nodes/materials/NodeMaterial.js
  93. 4 1
      examples/jsm/nodes/materials/PointsNodeMaterial.js
  94. 21 18
      examples/jsm/nodes/materials/SpriteNodeMaterial.js
  95. 31 22
      examples/jsm/nodes/materialx/MaterialXNodes.js
  96. 1 1
      examples/jsm/nodes/materialx/lib/mx_hsv.js
  97. 2 1
      examples/jsm/nodes/materialx/lib/mx_noise.js
  98. 2 1
      examples/jsm/nodes/materialx/lib/mx_transform_color.js
  99. 14 7
      examples/jsm/nodes/math/CondNode.js
  100. 120 20
      examples/jsm/nodes/math/MathNode.js

+ 133 - 368
examples/jsm/nodes/Nodes.js

@@ -1,391 +1,156 @@
+// @TODO: We can simplify "export { default as SomeNode, other, exports } from '...'" to just "export * from '...'" if we will use only named exports
+// this will also solve issues like "import TempNode from '../core/Node.js'"
+
+// constants
+export * from './core/constants.js';
+
 // core
-import ArrayUniformNode from './core/ArrayUniformNode.js';
-import AttributeNode from './core/AttributeNode.js';
-import BypassNode from './core/BypassNode.js';
-import CacheNode from './core/CacheNode.js';
-import CodeNode from './core/CodeNode.js';
-import ConstNode from './core/ConstNode.js';
-import ContextNode from './core/ContextNode.js';
-import ExpressionNode from './core/ExpressionNode.js';
-import FunctionCallNode from './core/FunctionCallNode.js';
-import FunctionNode from './core/FunctionNode.js';
-import InstanceIndexNode from './core/InstanceIndexNode.js';
-import LightingModel from './core/LightingModel.js';
-import Node from './core/Node.js';
-import NodeAttribute from './core/NodeAttribute.js';
-import NodeBuilder from './core/NodeBuilder.js';
-import NodeCache from './core/NodeCache.js';
-import NodeCode from './core/NodeCode.js';
-import NodeFrame from './core/NodeFrame.js';
-import NodeFunctionInput from './core/NodeFunctionInput.js';
-import NodeKeywords from './core/NodeKeywords.js';
-import NodeUniform from './core/NodeUniform.js';
-import NodeVar from './core/NodeVar.js';
-import NodeVarying from './core/NodeVarying.js';
-import PropertyNode from './core/PropertyNode.js';
-import StackNode from './core/StackNode.js';
-import TempNode from './core/TempNode.js';
-import UniformNode from './core/UniformNode.js';
-import VarNode from './core/VarNode.js';
-import VaryingNode from './core/VaryingNode.js';
+export { default as ArrayUniformNode /* @TODO: arrayUniform */ } from './core/ArrayUniformNode.js';
+export { default as AttributeNode, attribute } from './core/AttributeNode.js';
+export { default as BypassNode, bypass } from './core/BypassNode.js';
+export { default as CacheNode, cache } from './core/CacheNode.js';
+export { default as CodeNode, code } from './core/CodeNode.js';
+export { default as ConstNode } from './core/ConstNode.js';
+export { default as ContextNode, context } from './core/ContextNode.js';
+export { default as ExpressionNode, expression } from './core/ExpressionNode.js';
+export { default as FunctionCallNode, call } from './core/FunctionCallNode.js';
+export { default as FunctionNode, func, fn } from './core/FunctionNode.js';
+export { default as InstanceIndexNode, instanceIndex } from './core/InstanceIndexNode.js';
+export { default as LightingModel, lightingModel } from './core/LightingModel.js';
+export { default as Node, addNodeClass, createNodeFromType } from './core/Node.js';
+export { default as NodeAttribute } from './core/NodeAttribute.js';
+export { default as NodeBuilder } from './core/NodeBuilder.js';
+export { default as NodeCache } from './core/NodeCache.js';
+export { default as NodeCode } from './core/NodeCode.js';
+export { default as NodeFrame } from './core/NodeFrame.js';
+export { default as NodeFunctionInput } from './core/NodeFunctionInput.js';
+export { default as NodeKeywords } from './core/NodeKeywords.js';
+export { default as NodeUniform } from './core/NodeUniform.js';
+export { default as NodeVar } from './core/NodeVar.js';
+export { default as NodeVarying } from './core/NodeVarying.js';
+export { default as PropertyNode, property, diffuseColor, roughness, metalness, specularColor, shininess } from './core/PropertyNode.js';
+export { default as StackNode, stack } from './core/StackNode.js';
+export { default as TempNode } from './core/TempNode.js';
+export { default as UniformNode, uniform } from './core/UniformNode.js';
+export { default as VarNode, label, temp } from './core/VarNode.js';
+export { default as VaryingNode, varying } from './core/VaryingNode.js';
 
-// accessors
-import BitangentNode from './accessors/BitangentNode.js';
-import BufferNode from './accessors/BufferNode.js';
-import CameraNode from './accessors/CameraNode.js';
-import CubeTextureNode from './accessors/CubeTextureNode.js';
-import InstanceNode from './accessors/InstanceNode.js';
-import MaterialNode from './accessors/MaterialNode.js';
-import MaterialReferenceNode from './accessors/MaterialReferenceNode.js';
-import ModelNode from './accessors/ModelNode.js';
-import ModelViewProjectionNode from './accessors/ModelViewProjectionNode.js';
-import NormalNode from './accessors/NormalNode.js';
-import Object3DNode from './accessors/Object3DNode.js';
-import PointUVNode from './accessors/PointUVNode.js';
-import PositionNode from './accessors/PositionNode.js';
-import ReferenceNode from './accessors/ReferenceNode.js';
-import ReflectVectorNode from './accessors/ReflectVectorNode.js';
-import SkinningNode from './accessors/SkinningNode.js';
-import TangentNode from './accessors/TangentNode.js';
-import TextureNode from './accessors/TextureNode.js';
-import UVNode from './accessors/UVNode.js';
-import UserDataNode from './accessors/UserDataNode.js';
+// math
+export { default as MathNode, EPSILON, INFINITY, radians, degrees, exp, exp2, log, log2, sqrt, inversesqrt, floor, ceil, normalize, fract, sin, cos, tan, asin, acos, atan, abs, sign, length, negate, invert, dFdx, dFdy, round, reciprocal, atan2, min, max, mod, step, reflect, distance, difference, dot, cross, pow, pow2, pow3, pow4, transformDirection, mix, clamp, refract, smoothstep, faceforward } from './math/MathNode.js';
+export { default as OperatorNode, add, sub, mul, div, remainder, equal, assign, lessThan, greaterThan, lessThanEqual, greaterThanEqual, and, or, xor, bitAnd, bitOr, bitXor, shiftLeft, shiftRight } from './math/OperatorNode.js';
+export { default as CondNode, cond } from './math/CondNode.js';
 
-// geometry
-import RangeNode from './geometry/RangeNode.js';
+// utils
+export { default as ArrayElementNode } from './utils/ArrayElementNode.js';
+export { default as ConvertNode } from './utils/ConvertNode.js';
+export { default as DiscardNode, discard } from './utils/DiscardNode.js';
+export { default as EquirectUVNode, equirectUV } from './utils/EquirectUVNode.js';
+export { default as JoinNode } from './utils/JoinNode.js';
+export { default as MatcapUVNode, matcapUV } from './utils/MatcapUVNode.js';
+export { default as MaxMipLevelNode, maxMipLevel } from './utils/MaxMipLevelNode.js';
+export { default as OscNode, oscSine, oscSquare, oscTriangle, oscSawtooth } from './utils/OscNode.js';
+export { default as PackingNode, directionToColor, colorToDirection } from './utils/PackingNode.js';
+export { default as RemapNode, remap, remapClamp } from './utils/RemapNode.js';
+export { default as RotateUVNode, rotateUV } from './utils/RotateUVNode.js';
+export { default as SpecularMIPLevelNode, specularMIPLevel } from './utils/SpecularMIPLevelNode.js';
+export { default as SplitNode } from './utils/SplitNode.js';
+export { default as SpriteSheetUVNode, spritesheetUV } from './utils/SpriteSheetUVNode.js';
+export { default as TimerNode, timerLocal, timerGlobal, timerDelta, frameId } from './utils/TimerNode.js';
+export { default as TriplanarTexturesNode, triplanarTextures, triplanarTexture } from './utils/TriplanarTexturesNode.js';
+
+// shadernode
+export * from './shadernode/ShaderNode.js';
 
-// gpgpu
-import ComputeNode from './gpgpu/ComputeNode.js';
+// accessors
+export { default as BitangentNode, bitangentGeometry, bitangentLocal, bitangentView, bitangentWorld, transformedBitangentView, transformedBitangentWorld } from './accessors/BitangentNode.js';
+export { default as BufferNode, buffer } from './accessors/BufferNode.js';
+export { default as CameraNode, cameraProjectionMatrix, cameraViewMatrix, cameraNormalMatrix, cameraWorldMatrix, cameraPosition } from './accessors/CameraNode.js';
+export { default as CubeTextureNode, cubeTexture } from './accessors/CubeTextureNode.js';
+export { default as ExtendedMaterialNode, materialNormal } from './accessors/ExtendedMaterialNode.js';
+export { default as InstanceNode, instance } from './accessors/InstanceNode.js';
+export { default as MaterialNode, materialUV, materialAlphaTest, materialColor, materialShininess, materialEmissive, materialOpacity, materialSpecularColor, materialReflectivity, materialRoughness, materialMetalness, materialRotation } from './accessors/MaterialNode.js';
+export { default as MaterialReferenceNode, materialReference } from './accessors/MaterialReferenceNode.js';
+export { default as ModelNode, modelDirection, modelViewMatrix, modelNormalMatrix, modelWorldMatrix, modelPosition, modelViewPosition } from './accessors/ModelNode.js';
+export { default as ModelViewProjectionNode, modelViewProjection } from './accessors/ModelViewProjectionNode.js';
+export { default as NormalNode, normalGeometry, normalLocal, normalView, normalWorld, transformedNormalView, transformedNormalWorld } from './accessors/NormalNode.js';
+export { default as Object3DNode, objectDirection, objectViewMatrix, objectNormalMatrix, objectWorldMatrix, objectPosition, objectViewPosition } from './accessors/Object3DNode.js';
+export { default as PointUVNode, pointUV } from './accessors/PointUVNode.js';
+export { default as PositionNode, positionGeometry, positionLocal, positionWorld, positionWorldDirection, positionView, positionViewDirection } from './accessors/PositionNode.js';
+export { default as ReferenceNode, reference } from './accessors/ReferenceNode.js';
+export { default as ReflectVectorNode, reflectVector } from './accessors/ReflectVectorNode.js';
+export { default as SkinningNode, skinning } from './accessors/SkinningNode.js';
+export { default as StorageBufferNode, storage } from './accessors/StorageBufferNode.js';
+export { default as TangentNode, tangentGeometry, tangentLocal, tangentView, tangentWorld, transformedTangentView, transformedTangentWorld } from './accessors/TangentNode.js';
+export { default as TextureNode, texture, sampler } from './accessors/TextureNode.js';
+export { default as UVNode, uv } from './accessors/UVNode.js';
+export { default as UserDataNode, userData } from './accessors/UserDataNode.js';
 
 // display
-import BlendModeNode from './display/BlendModeNode.js';
-import ColorAdjustmentNode from './display/ColorAdjustmentNode.js';
-import ColorSpaceNode from './display/ColorSpaceNode.js';
-import FrontFacingNode from './display/FrontFacingNode.js';
-import NormalMapNode from './display/NormalMapNode.js';
-import PosterizeNode from './display/PosterizeNode.js';
-import ToneMappingNode from './display/ToneMappingNode.js';
-import ViewportNode from './display/ViewportNode.js';
-
-// math
-import MathNode from './math/MathNode.js';
-import OperatorNode from './math/OperatorNode.js';
-import CondNode from './math/CondNode.js';
+export { default as BlendModeNode, burn, dodge, overlay, screen } from './display/BlendModeNode.js';
+export { default as ColorAdjustmentNode, saturation, vibrance, hue, lumaCoeffs, luminance } from './display/ColorAdjustmentNode.js';
+export { default as ColorSpaceNode, colorSpace } from './display/ColorSpaceNode.js';
+export { default as FrontFacingNode, frontFacing, faceDirection } from './display/FrontFacingNode.js';
+export { default as NormalMapNode, normalMap, TBNViewMatrix } from './display/NormalMapNode.js';
+export { default as PosterizeNode, posterize } from './display/PosterizeNode.js';
+export { default as ToneMappingNode, toneMapping } from './display/ToneMappingNode.js';
+export { default as ViewportNode, viewportCoordinate, viewportResolution, viewportTopLeft, viewportBottomLeft, viewportTopRight, viewportBottomRight } from './display/ViewportNode.js';
 
-// lighting
-import PointLightNode from './lighting/PointLightNode.js';
-import DirectionalLightNode from './lighting/DirectionalLightNode.js';
-import SpotLightNode from './lighting/SpotLightNode.js';
-import IESSpotLightNode from './lighting/IESSpotLightNode.js';
-import AmbientLightNode from './lighting/AmbientLightNode.js';
-import LightsNode from './lighting/LightsNode.js';
-import LightingNode from './lighting/LightingNode.js';
-import LightingContextNode from './lighting/LightingContextNode.js';
-import HemisphereLightNode from './lighting/HemisphereLightNode.js';
-import EnvironmentNode from './lighting/EnvironmentNode.js';
-import AONode from './lighting/AONode.js';
-import AnalyticLightNode from './lighting/AnalyticLightNode.js';
+// fog
+export { default as FogNode, fog } from './fog/FogNode.js';
+export { default as FogRangeNode, rangeFog } from './fog/FogRangeNode.js';
+export { default as FogExp2Node, densityFog } from './fog/FogExp2Node.js';
 
-// utils
-import ArrayElementNode from './utils/ArrayElementNode.js';
-import ConvertNode from './utils/ConvertNode.js';
-import DiscardNode from './utils/DiscardNode.js';
-import EquirectUVNode from './utils/EquirectUVNode.js';
-import JoinNode from './utils/JoinNode.js';
-import MatcapUVNode from './utils/MatcapUVNode.js';
-import MaxMipLevelNode from './utils/MaxMipLevelNode.js';
-import OscNode from './utils/OscNode.js';
-import RemapNode from './utils/RemapNode.js';
-import RotateUVNode from './utils/RotateUVNode.js';
-import SpecularMIPLevelNode from './utils/SpecularMIPLevelNode.js';
-import SplitNode from './utils/SplitNode.js';
-import SpriteSheetUVNode from './utils/SpriteSheetUVNode.js';
-import TimerNode from './utils/TimerNode.js';
-import TriplanarTexturesNode from './utils/TriplanarTexturesNode.js';
+// geometry
+export { default as RangeNode, range } from './geometry/RangeNode.js';
 
-// loaders
-import NodeLoader from './loaders/NodeLoader.js';
-import NodeObjectLoader from './loaders/NodeObjectLoader.js';
-import NodeMaterialLoader from './loaders/NodeMaterialLoader.js';
+// gpgpu
+export { default as ComputeNode, compute } from './gpgpu/ComputeNode.js';
 
-// parsers
-import WGSLNodeParser from './parsers/WGSLNodeParser.js';
-import GLSLNodeParser from './parsers/GLSLNodeParser.js';
+// lighting
+export { default as PointLightNode } from './lighting/PointLightNode.js';
+export { default as DirectionalLightNode } from './lighting/DirectionalLightNode.js';
+export { default as SpotLightNode } from './lighting/SpotLightNode.js';
+export { default as IESSpotLightNode } from './lighting/IESSpotLightNode.js';
+export { default as AmbientLightNode } from './lighting/AmbientLightNode.js';
+export { default as LightsNode, lights, lightsWithoutWrap, addLightNode } from './lighting/LightsNode.js';
+export { default as LightingNode /* @TODO: lighting (abstract), light */ } from './lighting/LightingNode.js';
+export { default as LightingContextNode, lightingContext } from './lighting/LightingContextNode.js';
+export { default as HemisphereLightNode } from './lighting/HemisphereLightNode.js';
+export { default as EnvironmentNode } from './lighting/EnvironmentNode.js';
+export { default as AONode } from './lighting/AONode.js';
+export { default as AnalyticLightNode } from './lighting/AnalyticLightNode.js';
 
 // procedural
-import CheckerNode from './procedural/CheckerNode.js';
+export { default as CheckerNode, checker } from './procedural/CheckerNode.js';
 
-// fog
-import FogNode from './fog/FogNode.js';
-import FogRangeNode from './fog/FogRangeNode.js';
-import FogExp2Node from './fog/FogExp2Node.js';
+// loaders
+export { default as NodeLoader } from './loaders/NodeLoader.js';
+export { default as NodeObjectLoader } from './loaders/NodeObjectLoader.js';
+export { default as NodeMaterialLoader } from './loaders/NodeMaterialLoader.js';
 
-// core
-export * from './core/constants.js';
+// parsers
+export { default as WGSLNodeParser } from './parsers/WGSLNodeParser.js';
+export { default as GLSLNodeParser } from './parsers/GLSLNodeParser.js';
 
 // materials
 export * from './materials/Materials.js';
 
-// shader node
-export * from './shadernode/ShaderNodeElements.js';
-
-// extensions
+// materialX
 export * from './materialx/MaterialXNodes.js';
 
-// shader stages
-export { defaultShaderStages } from './core/NodeBuilder.js';
-
-const nodeLib = {
-	// core
-	ArrayUniformNode,
-	AttributeNode,
-	BypassNode,
-	CacheNode,
-	CodeNode,
-	ContextNode,
-	ConstNode,
-	ExpressionNode,
-	FunctionCallNode,
-	FunctionNode,
-	InstanceIndexNode,
-	LightingModel,
-	Node,
-	NodeAttribute,
-	NodeBuilder,
-	NodeCache,
-	NodeCode,
-	NodeFrame,
-	NodeFunctionInput,
-	NodeKeywords,
-	NodeUniform,
-	NodeVar,
-	NodeVarying,
-	PropertyNode,
-	StackNode,
-	TempNode,
-	UniformNode,
-	VarNode,
-	VaryingNode,
-
-	// geometry
-	RangeNode,
-
-	// gpgpu
-	ComputeNode,
-
-	// accessors
-	BitangentNode,
-	BufferNode,
-	CameraNode,
-	CubeTextureNode,
-	InstanceNode,
-	MaterialNode,
-	MaterialReferenceNode,
-	ModelNode,
-	ModelViewProjectionNode,
-	NormalNode,
-	Object3DNode,
-	PointUVNode,
-	PositionNode,
-	ReferenceNode,
-	ReflectVectorNode,
-	SkinningNode,
-	TangentNode,
-	TextureNode,
-	UVNode,
-	UserDataNode,
-
-	// display
-	BlendModeNode,
-	ColorAdjustmentNode,
-	ColorSpaceNode,
-	FrontFacingNode,
-	NormalMapNode,
-	PosterizeNode,
-	ToneMappingNode,
-	ViewportNode,
-
-	// math
-	MathNode,
-	OperatorNode,
-	CondNode,
-
-	// lighting
-	PointLightNode,
-	DirectionalLightNode,
-	SpotLightNode,
-	IESSpotLightNode,
-	AmbientLightNode,
-	LightsNode,
-	LightingNode,
-	LightingContextNode,
-	HemisphereLightNode,
-	EnvironmentNode,
-	AONode,
-	AnalyticLightNode,
-
-	// utils
-	ArrayElementNode,
-	ConvertNode,
-	DiscardNode,
-	EquirectUVNode,
-	JoinNode,
-	MatcapUVNode,
-	MaxMipLevelNode,
-	OscNode,
-	RemapNode,
-	RotateUVNode,
-	SpecularMIPLevelNode,
-	SplitNode,
-	SpriteSheetUVNode,
-	TimerNode,
-	TriplanarTexturesNode,
-
-	// procedural
-	CheckerNode,
-
-	// fog
-	FogNode,
-	FogRangeNode,
-	FogExp2Node,
-
-	// loaders
-	NodeLoader,
-	NodeObjectLoader,
-	NodeMaterialLoader,
-
-	// parsers
-	WGSLNodeParser,
-	GLSLNodeParser
-
-};
-
-export const fromType = ( type ) => {
-
-	return new nodeLib[ type ]();
-
-};
-
-export {
-	// core
-	ArrayUniformNode,
-	AttributeNode,
-	BypassNode,
-	CacheNode,
-	CodeNode,
-	ContextNode,
-	ConstNode,
-	ExpressionNode,
-	FunctionCallNode,
-	FunctionNode,
-	InstanceIndexNode,
-	LightingModel,
-	Node,
-	NodeAttribute,
-	NodeBuilder,
-	NodeCache,
-	NodeCode,
-	NodeFrame,
-	NodeFunctionInput,
-	NodeKeywords,
-	NodeUniform,
-	NodeVar,
-	NodeVarying,
-	PropertyNode,
-	StackNode,
-	TempNode,
-	UniformNode,
-	VarNode,
-	VaryingNode,
-
-	// geometry
-	RangeNode,
-
-	// gpgpu
-	ComputeNode,
-
-	// accessors
-	BitangentNode,
-	BufferNode,
-	CameraNode,
-	CubeTextureNode,
-	InstanceNode,
-	MaterialNode,
-	MaterialReferenceNode,
-	ModelNode,
-	ModelViewProjectionNode,
-	NormalNode,
-	Object3DNode,
-	PointUVNode,
-	PositionNode,
-	ReferenceNode,
-	ReflectVectorNode,
-	SkinningNode,
-	TangentNode,
-	TextureNode,
-	UVNode,
-	UserDataNode,
-
-	// display
-	BlendModeNode,
-	ColorAdjustmentNode,
-	ColorSpaceNode,
-	FrontFacingNode,
-	NormalMapNode,
-	PosterizeNode,
-	ToneMappingNode,
-	ViewportNode,
-
-	// math
-	MathNode,
-	OperatorNode,
-	CondNode,
-
-	// lighting
-	PointLightNode,
-	DirectionalLightNode,
-	SpotLightNode,
-	IESSpotLightNode,
-	AmbientLightNode,
-	LightsNode,
-	LightingNode,
-	LightingContextNode,
-	HemisphereLightNode,
-	EnvironmentNode,
-	AONode,
-	AnalyticLightNode,
-
-	// utils
-	ArrayElementNode,
-	ConvertNode,
-	DiscardNode,
-	EquirectUVNode,
-	JoinNode,
-	MatcapUVNode,
-	MaxMipLevelNode,
-	OscNode,
-	RemapNode,
-	RotateUVNode,
-	SpecularMIPLevelNode,
-	SplitNode,
-	SpriteSheetUVNode,
-	TimerNode,
-	TriplanarTexturesNode,
-
-	// procedural
-	CheckerNode,
+// functions
+export { default as BRDF_BlinnPhong } from './functions/BSDF/BRDF_BlinnPhong.js';
+export { default as BRDF_GGX } from './functions/BSDF/BRDF_GGX.js';
+export { default as BRDF_Lambert } from './functions/BSDF/BRDF_Lambert.js';
+export { default as D_GGX } from './functions/BSDF/D_GGX.js';
+export { default as DFGApprox } from './functions/BSDF/DFGApprox.js';
+export { default as F_Schlick } from './functions/BSDF/F_Schlick.js';
+export { default as V_GGX_SmithCorrelated } from './functions/BSDF/V_GGX_SmithCorrelated.js';
 
-	// fog
-	FogNode,
-	FogRangeNode,
-	FogExp2Node,
+export { default as getDistanceAttenuation } from './functions/light/getDistanceAttenuation.js';
 
-	// loaders
-	NodeLoader,
-	NodeObjectLoader,
-	NodeMaterialLoader,
+export { default as getGeometryRoughness } from './functions/material/getGeometryRoughness.js';
+export { default as getRoughness } from './functions/material/getRoughness.js';
 
-	// parsers
-	WGSLNodeParser,
-	GLSLNodeParser
-};
+export { default as phongLightingModel } from './functions/PhongLightingModel.js';
+export { default as physicalLightingModel } from './functions/PhysicalLightingModel.js';

+ 38 - 11
examples/jsm/nodes/accessors/BitangentNode.js

@@ -1,10 +1,10 @@
-import Node from '../core/Node.js';
-import VaryingNode from '../core/VaryingNode.js';
-import OperatorNode from '../math/OperatorNode.js';
-import MathNode from '../math/MathNode.js';
-import SplitNode from '../utils/SplitNode.js';
-import NormalNode from './NormalNode.js';
-import TangentNode from './TangentNode.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { varying } from '../core/VaryingNode.js';
+import { normalize } from '../math/MathNode.js';
+import { cameraViewMatrix } from './CameraNode.js';
+import { normalGeometry, normalLocal, normalView, normalWorld, transformedNormalView } from './NormalNode.js';
+import { tangentGeometry, tangentLocal, tangentView, tangentWorld, transformedTangentView } from './TangentNode.js';
+import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class BitangentNode extends Node {
 
@@ -26,11 +26,29 @@ class BitangentNode extends Node {
 
 		const scope = this.scope;
 
-		const crossNormalTangent = new MathNode( MathNode.CROSS, new NormalNode( scope ), new TangentNode( scope ) );
-		const tangentW = new SplitNode( new TangentNode( TangentNode.GEOMETRY ), 'w' );
-		const vertexNode = new SplitNode( new OperatorNode( '*', crossNormalTangent, tangentW ), 'xyz' );
+		let crossNormalTangent;
 
-		const outputNode = new MathNode( MathNode.NORMALIZE, new VaryingNode( vertexNode ) );
+		if ( scope === BitangentNode.GEOMETRY ) {
+
+			crossNormalTangent = normalGeometry.cross( tangentGeometry );
+
+		} else if ( scope === BitangentNode.LOCAL ) {
+
+			crossNormalTangent = normalLocal.cross( tangentLocal );
+
+		} else if ( scope === BitangentNode.VIEW ) {
+
+			crossNormalTangent = normalView.cross( tangentView );
+
+		} else if ( scope === BitangentNode.WORLD ) {
+
+			crossNormalTangent = normalWorld.cross( tangentWorld );
+
+		}
+
+		const vertexNode = crossNormalTangent.mul( tangentGeometry.w ).xyz;
+
+		const outputNode = normalize( varying( vertexNode ) );
 
 		return outputNode.build( builder, this.getNodeType( builder ) );
 
@@ -60,3 +78,12 @@ BitangentNode.VIEW = 'view';
 BitangentNode.WORLD = 'world';
 
 export default BitangentNode;
+
+export const bitangentGeometry = nodeImmutable( BitangentNode, BitangentNode.GEOMETRY );
+export const bitangentLocal = nodeImmutable( BitangentNode, BitangentNode.LOCAL );
+export const bitangentView = nodeImmutable( BitangentNode, BitangentNode.VIEW );
+export const bitangentWorld = nodeImmutable( BitangentNode, BitangentNode.WORLD );
+export const transformedBitangentView = normalize( transformedNormalView.cross( transformedTangentView ).mul( tangentGeometry.w ) );
+export const transformedBitangentWorld = normalize( transformedBitangentView.transformDirection( cameraViewMatrix ) );
+
+addNodeClass( BitangentNode );

+ 6 - 0
examples/jsm/nodes/accessors/BufferNode.js

@@ -1,4 +1,6 @@
 import UniformNode from '../core/UniformNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { nodeObject, getConstNodeType } from '../shadernode/ShaderNode.js';
 
 class BufferNode extends UniformNode {
 
@@ -22,3 +24,7 @@ class BufferNode extends UniformNode {
 }
 
 export default BufferNode;
+
+export const buffer = ( value, nodeOrType, count ) => nodeObject( new BufferNode( value, getConstNodeType( nodeOrType ), count ) );
+
+addNodeClass( BufferNode );

+ 10 - 0
examples/jsm/nodes/accessors/CameraNode.js

@@ -1,4 +1,6 @@
 import Object3DNode from './Object3DNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class CameraNode extends Object3DNode {
 
@@ -65,3 +67,11 @@ class CameraNode extends Object3DNode {
 CameraNode.PROJECTION_MATRIX = 'projectionMatrix';
 
 export default CameraNode;
+
+export const cameraProjectionMatrix = nodeImmutable( CameraNode, CameraNode.PROJECTION_MATRIX );
+export const cameraViewMatrix = nodeImmutable( CameraNode, CameraNode.VIEW_MATRIX );
+export const cameraNormalMatrix = nodeImmutable( CameraNode, CameraNode.NORMAL_MATRIX );
+export const cameraWorldMatrix = nodeImmutable( CameraNode, CameraNode.WORLD_MATRIX );
+export const cameraPosition = nodeImmutable( CameraNode, CameraNode.POSITION );
+
+addNodeClass( CameraNode );

+ 11 - 8
examples/jsm/nodes/accessors/CubeTextureNode.js

@@ -1,10 +1,8 @@
 import TextureNode from './TextureNode.js';
 import UniformNode from '../core/UniformNode.js';
-import ReflectVectorNode from './ReflectVectorNode.js';
-
-import { vec3, nodeObject } from '../shadernode/ShaderNodeBaseElements.js';
-
-let defaultUV;
+import { reflectVector } from './ReflectVectorNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { addNodeElement, nodeProxy, vec3 } from '../shadernode/ShaderNode.js';
 
 class CubeTextureNode extends TextureNode {
 
@@ -24,7 +22,7 @@ class CubeTextureNode extends TextureNode {
 
 	getDefaultUV() {
 
-		return defaultUV || ( defaultUV = new ReflectVectorNode() );
+		return reflectVector;
 
 	}
 
@@ -58,8 +56,7 @@ class CubeTextureNode extends TextureNode {
 
 			if ( propertyName === undefined ) {
 
-				const uvNodeObject = nodeObject( uvNode );
-				const cubeUV = vec3( uvNodeObject.x.negate(), uvNodeObject.yz );
+				const cubeUV = vec3( uvNode.x.negate(), uvNode.yz );
 				const uvSnippet = cubeUV.build( builder, 'vec3' );
 
 				const nodeVar = builder.getVarFromNode( this, 'vec4' );
@@ -96,3 +93,9 @@ class CubeTextureNode extends TextureNode {
 }
 
 export default CubeTextureNode;
+
+export const cubeTexture = nodeProxy( CubeTextureNode );
+
+addNodeElement( 'cubeTexture', cubeTexture );
+
+addNodeClass( CubeTextureNode );

+ 12 - 6
examples/jsm/nodes/accessors/ExtendedMaterialNode.js

@@ -1,9 +1,11 @@
-import MaterialNode from './MaterialNode.js';
-import NormalMapNode from '../display/NormalMapNode.js';
+// @TODO: Is this needed? Can it be moved in MaterialNode?
 
-import {
-	normalView, materialReference
-} from '../shadernode/ShaderNodeElements.js';
+import MaterialNode from './MaterialNode.js';
+import { materialReference } from './MaterialReferenceNode.js';
+import { normalView } from './NormalNode.js';
+import { normalMap } from '../display/NormalMapNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class ExtendedMaterialNode extends MaterialNode {
 
@@ -37,7 +39,7 @@ class ExtendedMaterialNode extends MaterialNode {
 
 		if ( scope === ExtendedMaterialNode.NORMAL ) {
 
-			node = material.normalMap ? new NormalMapNode( this.getTexture( 'normalMap' ), materialReference( 'normalScale', 'vec2' ) ) : normalView;
+			node = material.normalMap ? normalMap( this.getTexture( 'normalMap' ), materialReference( 'normalScale', 'vec2' ) ) : normalView;
 
 		}
 
@@ -50,3 +52,7 @@ class ExtendedMaterialNode extends MaterialNode {
 ExtendedMaterialNode.NORMAL = 'normal';
 
 export default ExtendedMaterialNode;
+
+export const materialNormal = nodeImmutable( ExtendedMaterialNode, ExtendedMaterialNode.NORMAL );
+
+addNodeClass( ExtendedMaterialNode );

+ 17 - 21
examples/jsm/nodes/accessors/InstanceNode.js

@@ -1,18 +1,10 @@
-import Node from '../core/Node.js';
-import {
-	vec3,
-	mat3,
-	mul,
-	assign,
-	buffer,
-	element,
-	dot,
-	div,
-	temp,
-	instanceIndex,
-	positionLocal,
-	normalLocal
-} from '../shadernode/ShaderNodeBaseElements.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { instanceIndex } from '../core/InstanceIndexNode.js';
+import { temp } from '../core/VarNode.js';
+import { buffer } from './BufferNode.js';
+import { normalLocal } from './NormalNode.js';
+import { positionLocal } from './PositionNode.js';
+import { nodeProxy, vec3, mat3 } from '../shadernode/ShaderNode.js';
 
 class InstanceNode extends Node {
 
@@ -26,7 +18,7 @@ class InstanceNode extends Node {
 
 		const instanceBufferNode = buffer( instanceMesh.instanceMatrix.array, 'mat4', instanceMesh.count );
 
-		this.instanceMatrixNode = temp( element( instanceBufferNode, instanceIndex ) ); // @TODO: a possible caching issue here?
+		this.instanceMatrixNode = temp( instanceBufferNode.element( instanceIndex ) ); // @TODO: a possible caching issue here?
 
 	}
 
@@ -36,23 +28,27 @@ class InstanceNode extends Node {
 
 		// POSITION
 
-		const instancePosition = mul( instanceMatrixNode, positionLocal ).xyz;
+		const instancePosition = instanceMatrixNode.mul( positionLocal ).xyz;
 
 		// NORMAL
 
 		const m = mat3( instanceMatrixNode[ 0 ].xyz, instanceMatrixNode[ 1 ].xyz, instanceMatrixNode[ 2 ].xyz );
 
-		const transformedNormal = div( normalLocal, vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) ) );
+		const transformedNormal = normalLocal.div( vec3( m[ 0 ].dot( m[ 0 ] ), m[ 1 ].dot( m[ 1 ] ), m[ 2 ].dot( m[ 2 ] ) ) );
 
-		const instanceNormal = mul( m, transformedNormal ).xyz;
+		const instanceNormal = m.mul( transformedNormal ).xyz;
 
 		// ASSIGNS
 
-		assign( positionLocal, instancePosition ).build( builder );
-		assign( normalLocal, instanceNormal ).build( builder );
+		positionLocal.assign( instancePosition ).build( builder );
+		normalLocal.assign( instanceNormal ).build( builder );
 
 	}
 
 }
 
 export default InstanceNode;
+
+export const instance = nodeProxy( InstanceNode );
+
+addNodeClass( InstanceNode );

+ 35 - 23
examples/jsm/nodes/accessors/MaterialNode.js

@@ -1,11 +1,8 @@
-import Node from '../core/Node.js';
-import UniformNode from '../core/UniformNode.js';
-import UVNode from '../accessors/UVNode.js';
-import ConstNode from '../core/ConstNode.js';
-import OperatorNode from '../math/OperatorNode.js';
-import JoinNode from '../utils/JoinNode.js';
-import MaterialReferenceNode from './MaterialReferenceNode.js';
-import SplitNode from '../utils/SplitNode.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { uniform } from '../core/UniformNode.js';
+import { materialReference } from './MaterialReferenceNode.js';
+import { uv } from './UVNode.js';
+import { nodeImmutable, vec3 } from '../shadernode/ShaderNode.js';
 
 class MaterialNode extends Node {
 
@@ -50,7 +47,7 @@ class MaterialNode extends Node {
 
 		//@TODO: Check if it can be cached by property name.
 
-		return new MaterialReferenceNode( property, 'float' );
+		return materialReference( property, 'float' );
 
 	}
 
@@ -58,7 +55,7 @@ class MaterialNode extends Node {
 
 		//@TODO: Check if it can be cached by property name.
 
-		return new MaterialReferenceNode( property, 'color' );
+		return materialReference( property, 'color' );
 
 	}
 
@@ -66,8 +63,8 @@ class MaterialNode extends Node {
 
 		//@TODO: Check if it can be cached by property name.
 
-		const textureRefNode = new MaterialReferenceNode( property, 'texture' );
-		textureRefNode.node.uvNode = new MaterialNode( MaterialNode.UV );
+		const textureRefNode = materialReference( property, 'texture' );
+		textureRefNode.node.uvNode = materialUV;
 
 		return textureRefNode;
 
@@ -90,7 +87,7 @@ class MaterialNode extends Node {
 
 			if ( material.map && material.map.isTexture === true ) {
 
-				node = new OperatorNode( '*', colorNode, this.getTexture( 'map' ) );
+				node = colorNode.mul( this.getTexture( 'map' ) );
 
 			} else {
 
@@ -104,7 +101,7 @@ class MaterialNode extends Node {
 
 			if ( material.alphaMap && material.alphaMap.isTexture === true ) {
 
-				node = new OperatorNode( '*', opacityNode, this.getTexture( 'alphaMap' ) );
+				node = opacityNode.mul( this.getTexture( 'alphaMap' ) );
 
 			} else {
 
@@ -126,7 +123,7 @@ class MaterialNode extends Node {
 
 			if ( material.specularMap && material.specularMap.isTexture === true ) {
 
-				node = new OperatorNode( '*', reflectivityNode, new SplitNode( this.getTexture( 'specularMap' ), 'r' ) );
+				node = reflectivityNode.mul( this.getTexture( 'specularMap' ).r );
 
 			} else {
 
@@ -140,7 +137,7 @@ class MaterialNode extends Node {
 
 			if ( material.roughnessMap && material.roughnessMap.isTexture === true ) {
 
-				node = new OperatorNode( '*', roughnessNode, new SplitNode( this.getTexture( 'roughnessMap' ), 'g' ) );
+				node = roughnessNode.mul( this.getTexture( 'roughnessMap' ).g );
 
 			} else {
 
@@ -154,7 +151,7 @@ class MaterialNode extends Node {
 
 			if ( material.metalnessMap && material.metalnessMap.isTexture === true ) {
 
-				node = new OperatorNode( '*', metalnessNode, new SplitNode( this.getTexture( 'metalnessMap' ), 'b' ) );
+				node = metalnessNode.mul( this.getTexture( 'metalnessMap' ).b );
 
 			} else {
 
@@ -168,7 +165,7 @@ class MaterialNode extends Node {
 
 			if ( material.emissiveMap && material.emissiveMap.isTexture === true ) {
 
-				node = new OperatorNode( '*', emissiveNode, this.getTexture( 'emissiveMap' ) );
+				node = emissiveNode.mul( this.getTexture( 'emissiveMap' ) );
 
 			} else {
 
@@ -184,7 +181,6 @@ class MaterialNode extends Node {
 
 			// uv repeat and offset setting priorities
 
-			let uvNode;
 			let uvScaleMap =
 				material.map ||
 				material.specularMap ||
@@ -222,17 +218,19 @@ class MaterialNode extends Node {
 
 				}
 
-				uvNode = new OperatorNode( '*', new UniformNode( uvScaleMap.matrix ), new JoinNode( [ new UVNode(), new ConstNode( 1 ) ] ) );
+				node = uniform( uvScaleMap.matrix ).mul( vec3( uv(), 1 ) );
 
-			}
+			} else {
 
-			return uvNode || new UVNode();
+				node = uv();
+
+			}
 
 		} else {
 
 			const outputType = this.getNodeType( builder );
 
-			node = new MaterialReferenceNode( scope, outputType );
+			node = materialReference( scope, outputType );
 
 		}
 
@@ -255,3 +253,17 @@ MaterialNode.ROTATION = 'rotation';
 MaterialNode.UV = 'uv';
 
 export default MaterialNode;
+
+export const materialUV = nodeImmutable( MaterialNode, MaterialNode.UV );
+export const materialAlphaTest = nodeImmutable( MaterialNode, MaterialNode.ALPHA_TEST );
+export const materialColor = nodeImmutable( MaterialNode, MaterialNode.COLOR );
+export const materialShininess = nodeImmutable( MaterialNode, MaterialNode.SHININESS );
+export const materialEmissive = nodeImmutable( MaterialNode, MaterialNode.EMISSIVE );
+export const materialOpacity = nodeImmutable( MaterialNode, MaterialNode.OPACITY );
+export const materialSpecularColor = nodeImmutable( MaterialNode, MaterialNode.SPECULAR_COLOR );
+export const materialReflectivity = nodeImmutable( MaterialNode, MaterialNode.REFLECTIVITY );
+export const materialRoughness = nodeImmutable( MaterialNode, MaterialNode.ROUGHNESS );
+export const materialMetalness = nodeImmutable( MaterialNode, MaterialNode.METALNESS );
+export const materialRotation = nodeImmutable( MaterialNode, MaterialNode.ROTATION );
+
+addNodeClass( MaterialNode );

+ 6 - 0
examples/jsm/nodes/accessors/MaterialReferenceNode.js

@@ -1,4 +1,6 @@
 import ReferenceNode from './ReferenceNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { nodeObject, getConstNodeType } from '../shadernode/ShaderNode.js';
 
 class MaterialReferenceNode extends ReferenceNode {
 
@@ -31,3 +33,7 @@ class MaterialReferenceNode extends ReferenceNode {
 }
 
 export default MaterialReferenceNode;
+
+export const materialReference = ( name, nodeOrType, material ) => nodeObject( new MaterialReferenceNode( name, getConstNodeType( nodeOrType ), material ) );
+
+addNodeClass( MaterialReferenceNode );

+ 11 - 0
examples/jsm/nodes/accessors/ModelNode.js

@@ -1,4 +1,6 @@
 import Object3DNode from './Object3DNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class ModelNode extends Object3DNode {
 
@@ -19,3 +21,12 @@ class ModelNode extends Object3DNode {
 }
 
 export default ModelNode;
+
+export const modelDirection = nodeImmutable( ModelNode, ModelNode.DIRECTION );
+export const modelViewMatrix = nodeImmutable( ModelNode, ModelNode.VIEW_MATRIX );
+export const modelNormalMatrix = nodeImmutable( ModelNode, ModelNode.NORMAL_MATRIX );
+export const modelWorldMatrix = nodeImmutable( ModelNode, ModelNode.WORLD_MATRIX );
+export const modelPosition = nodeImmutable( ModelNode, ModelNode.POSITION );
+export const modelViewPosition = nodeImmutable( ModelNode, ModelNode.VIEW_POSITION );
+
+addNodeClass( ModelNode );

+ 12 - 8
examples/jsm/nodes/accessors/ModelViewProjectionNode.js

@@ -1,12 +1,12 @@
-import Node from '../core/Node.js';
-import CameraNode from '../accessors/CameraNode.js';
-import ModelNode from '../accessors/ModelNode.js';
-import OperatorNode from '../math/OperatorNode.js';
-import PositionNode from '../accessors/PositionNode.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { cameraProjectionMatrix } from './CameraNode.js';
+import { modelViewMatrix } from './ModelNode.js';
+import { positionLocal } from './PositionNode.js';
+import { nodeProxy } from '../shadernode/ShaderNode.js';
 
 class ModelViewProjectionNode extends Node {
 
-	constructor( position = new PositionNode() ) {
+	constructor( position = positionLocal ) {
 
 		super( 'vec4' );
 
@@ -18,8 +18,8 @@ class ModelViewProjectionNode extends Node {
 
 		const position = this.position;
 
-		const mvpMatrix = new OperatorNode( '*', new CameraNode( CameraNode.PROJECTION_MATRIX ), new ModelNode( ModelNode.VIEW_MATRIX ) );
-		const mvpNode = new OperatorNode( '*', mvpMatrix, position );
+		const mvpMatrix = cameraProjectionMatrix.mul( modelViewMatrix );
+		const mvpNode = mvpMatrix.mul( position );
 
 		return mvpNode.build( builder );
 
@@ -28,3 +28,7 @@ class ModelViewProjectionNode extends Node {
 }
 
 export default ModelViewProjectionNode;
+
+export const modelViewProjection = nodeProxy( ModelViewProjectionNode );
+
+addNodeClass( ModelViewProjectionNode );

+ 24 - 14
examples/jsm/nodes/accessors/NormalNode.js

@@ -1,10 +1,11 @@
-import Node from '../core/Node.js';
-import AttributeNode from '../core/AttributeNode.js';
-import VaryingNode from '../core/VaryingNode.js';
-import ModelNode from '../accessors/ModelNode.js';
-import CameraNode from '../accessors/CameraNode.js';
-import OperatorNode from '../math/OperatorNode.js';
-import MathNode from '../math/MathNode.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { attribute } from '../core/AttributeNode.js';
+import { label } from '../core/VarNode.js';
+import { varying } from '../core/VaryingNode.js';
+import { normalize } from '../math/MathNode.js';
+import { cameraViewMatrix } from './CameraNode.js';
+import { modelNormalMatrix } from './ModelNode.js';
+import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class NormalNode extends Node {
 
@@ -36,22 +37,22 @@ class NormalNode extends Node {
 
 		if ( scope === NormalNode.GEOMETRY ) {
 
-			outputNode = new AttributeNode( 'normal', 'vec3' );
+			outputNode = attribute( 'normal', 'vec3' );
 
 		} else if ( scope === NormalNode.LOCAL ) {
 
-			outputNode = new VaryingNode( new NormalNode( NormalNode.GEOMETRY ) );
+			outputNode = varying( normalGeometry );
 
 		} else if ( scope === NormalNode.VIEW ) {
 
-			const vertexNode = new OperatorNode( '*', new ModelNode( ModelNode.NORMAL_MATRIX ), new NormalNode( NormalNode.LOCAL ) );
-			outputNode = new MathNode( MathNode.NORMALIZE, new VaryingNode( vertexNode ) );
+			const vertexNode = modelNormalMatrix.mul( normalLocal );
+			outputNode = normalize( varying( vertexNode ) );
 
 		} else if ( scope === NormalNode.WORLD ) {
 
-			// To use INVERSE_TRANSFORM_DIRECTION only inverse the param order like this: MathNode( ..., Vector, Matrix );
-			const vertexNode = new MathNode( MathNode.TRANSFORM_DIRECTION, new NormalNode( NormalNode.VIEW ), new CameraNode( CameraNode.VIEW_MATRIX ) );
-			outputNode = new MathNode( MathNode.NORMALIZE, new VaryingNode( vertexNode ) );
+			// To use inverseTransformDirection only inverse the param order like this: cameraViewMatrix.transformDirection( normalView )
+			const vertexNode = normalView.transformDirection( cameraViewMatrix );
+			outputNode = normalize( varying( vertexNode ) );
 
 		}
 
@@ -83,3 +84,12 @@ NormalNode.VIEW = 'view';
 NormalNode.WORLD = 'world';
 
 export default NormalNode;
+
+export const normalGeometry = nodeImmutable( NormalNode, NormalNode.GEOMETRY );
+export const normalLocal = nodeImmutable( NormalNode, NormalNode.LOCAL );
+export const normalView = nodeImmutable( NormalNode, NormalNode.VIEW );
+export const normalWorld = nodeImmutable( NormalNode, NormalNode.WORLD );
+export const transformedNormalView = label( normalView, 'TransformedNormalView' );
+export const transformedNormalWorld = transformedNormalView.transformDirection( cameraViewMatrix ).normalize();
+
+addNodeClass( NormalNode );

+ 15 - 4
examples/jsm/nodes/accessors/Object3DNode.js

@@ -1,7 +1,9 @@
-import { Vector3 } from 'three';
-import Node from '../core/Node.js';
-import UniformNode from '../core/UniformNode.js';
+import Node, { addNodeClass } from '../core/Node.js';
 import { NodeUpdateType } from '../core/constants.js';
+import { uniform } from '../core/UniformNode.js';
+import { nodeProxy } from '../shadernode/ShaderNode.js';
+
+import { Vector3 } from 'three';
 
 class Object3DNode extends Node {
 
@@ -14,7 +16,7 @@ class Object3DNode extends Node {
 
 		this.updateType = NodeUpdateType.OBJECT;
 
-		this._uniformNode = new UniformNode( null );
+		this._uniformNode = uniform( null );
 
 	}
 
@@ -129,3 +131,12 @@ Object3DNode.VIEW_POSITION = 'viewPosition';
 Object3DNode.DIRECTION = 'direction';
 
 export default Object3DNode;
+
+export const objectDirection = nodeProxy( Object3DNode, Object3DNode.DIRECTION );
+export const objectViewMatrix = nodeProxy( Object3DNode, Object3DNode.VIEW_MATRIX );
+export const objectNormalMatrix = nodeProxy( Object3DNode, Object3DNode.NORMAL_MATRIX );
+export const objectWorldMatrix = nodeProxy( Object3DNode, Object3DNode.WORLD_MATRIX );
+export const objectPosition = nodeProxy( Object3DNode, Object3DNode.POSITION );
+export const objectViewPosition = nodeProxy( Object3DNode, Object3DNode.VIEW_POSITION );
+
+addNodeClass( Object3DNode );

+ 6 - 1
examples/jsm/nodes/accessors/PointUVNode.js

@@ -1,4 +1,5 @@
-import Node from '../core/Node.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class PointUVNode extends Node {
 
@@ -19,3 +20,7 @@ class PointUVNode extends Node {
 }
 
 export default PointUVNode;
+
+export const pointUV = nodeImmutable( PointUVNode );
+
+addNodeClass( PointUVNode );

+ 25 - 16
examples/jsm/nodes/accessors/PositionNode.js

@@ -1,9 +1,9 @@
-import Node from '../core/Node.js';
-import AttributeNode from '../core/AttributeNode.js';
-import VaryingNode from '../core/VaryingNode.js';
-import ModelNode from '../accessors/ModelNode.js';
-import MathNode from '../math/MathNode.js';
-import OperatorNode from '../math/OperatorNode.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { attribute } from '../core/AttributeNode.js';
+import { varying } from '../core/VaryingNode.js';
+import { normalize } from '../math/MathNode.js';
+import { modelWorldMatrix, modelViewMatrix } from './ModelNode.js';
+import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class PositionNode extends Node {
 
@@ -35,31 +35,31 @@ class PositionNode extends Node {
 
 		if ( scope === PositionNode.GEOMETRY ) {
 
-			outputNode = new AttributeNode( 'position', 'vec3' );
+			outputNode = attribute( 'position', 'vec3' );
 
 		} else if ( scope === PositionNode.LOCAL ) {
 
-			outputNode = new VaryingNode( new PositionNode( PositionNode.GEOMETRY ) );
+			outputNode = varying( positionGeometry );
 
 		} else if ( scope === PositionNode.WORLD ) {
 
-			const vertexPositionNode = new MathNode( MathNode.TRANSFORM_DIRECTION, new ModelNode( ModelNode.WORLD_MATRIX ), new PositionNode( PositionNode.LOCAL ) );
-			outputNode = new VaryingNode( vertexPositionNode );
+			const vertexPositionNode = modelWorldMatrix.transformDirection( positionLocal );
+			outputNode = varying( vertexPositionNode );
 
 		} else if ( scope === PositionNode.VIEW ) {
 
-			const vertexPositionNode = new OperatorNode( '*', new ModelNode( ModelNode.VIEW_MATRIX ), new PositionNode( PositionNode.LOCAL ) );
-			outputNode = new VaryingNode( vertexPositionNode );
+			const vertexPositionNode = modelViewMatrix.mul( positionLocal );
+			outputNode = varying( vertexPositionNode );
 
 		} else if ( scope === PositionNode.VIEW_DIRECTION ) {
 
-			const vertexPositionNode = new MathNode( MathNode.NEGATE, new PositionNode( PositionNode.VIEW ) );
-			outputNode = new MathNode( MathNode.NORMALIZE, new VaryingNode( vertexPositionNode ) );
+			const vertexPositionNode = positionView.negate();
+			outputNode = normalize( varying( vertexPositionNode ) );
 
 		} else if ( scope === PositionNode.WORLD_DIRECTION ) {
 
-			const vertexPositionNode = new MathNode( MathNode.NEGATE, new PositionNode( PositionNode.WORLD ) );
-			outputNode = new MathNode( MathNode.NORMALIZE, new VaryingNode( vertexPositionNode ) );
+			const vertexPositionNode = positionWorld.negate();
+			outputNode = normalize( varying( vertexPositionNode ) );
 
 		}
 
@@ -93,3 +93,12 @@ PositionNode.VIEW = 'view';
 PositionNode.VIEW_DIRECTION = 'viewDirection';
 
 export default PositionNode;
+
+export const positionGeometry = nodeImmutable( PositionNode, PositionNode.GEOMETRY );
+export const positionLocal = nodeImmutable( PositionNode, PositionNode.LOCAL );
+export const positionWorld = nodeImmutable( PositionNode, PositionNode.WORLD );
+export const positionWorldDirection = nodeImmutable( PositionNode, PositionNode.WORLD_DIRECTION );
+export const positionView = nodeImmutable( PositionNode, PositionNode.VIEW );
+export const positionViewDirection = nodeImmutable( PositionNode, PositionNode.VIEW_DIRECTION );
+
+addNodeClass( PositionNode );

+ 10 - 5
examples/jsm/nodes/accessors/ReferenceNode.js

@@ -1,7 +1,8 @@
-import Node from '../core/Node.js';
-import UniformNode from '../core/UniformNode.js';
-import TextureNode from '../accessors/TextureNode.js';
+import Node, { addNodeClass } from '../core/Node.js';
 import { NodeUpdateType } from '../core/constants.js';
+import { uniform } from '../core/UniformNode.js';
+import { texture } from './TextureNode.js';
+import { nodeObject, getConstNodeType } from '../shadernode/ShaderNode.js';
 
 class ReferenceNode extends Node {
 
@@ -29,11 +30,11 @@ class ReferenceNode extends Node {
 
 		if ( uniformType === 'texture' ) {
 
-			node = new TextureNode( null );
+			node = texture( null );
 
 		} else {
 
-			node = new UniformNode( null, uniformType );
+			node = uniform( uniformType );
 
 		}
 
@@ -65,3 +66,7 @@ class ReferenceNode extends Node {
 }
 
 export default ReferenceNode;
+
+export const reference = ( name, nodeOrType, object ) => nodeObject( new ReferenceNode( name, getConstNodeType( nodeOrType ), object ) );
+
+addNodeClass( ReferenceNode );

+ 9 - 4
examples/jsm/nodes/accessors/ReflectVectorNode.js

@@ -1,7 +1,8 @@
-import Node from '../core/Node.js';
-import {
-	transformedNormalView, positionViewDirection, cameraViewMatrix
-} from '../shadernode/ShaderNodeBaseElements.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { cameraViewMatrix } from './CameraNode.js';
+import { transformedNormalView } from './NormalNode.js';
+import { positionViewDirection } from './PositionNode.js';
+import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class ReflectVectorNode extends Node {
 
@@ -28,3 +29,7 @@ class ReflectVectorNode extends Node {
 }
 
 export default ReflectVectorNode;
+
+export const reflectVector = nodeImmutable( ReflectVectorNode );
+
+addNodeClass( ReflectVectorNode );

+ 43 - 40
examples/jsm/nodes/accessors/SkinningNode.js

@@ -1,65 +1,57 @@
-import Node from '../core/Node.js';
-import {
-	ShaderNode,
-	attribute,
-	buffer,
-	mat4,
-	uniform,
-	positionLocal,
-	normalLocal,
-	tangentLocal,
-	assign,
-	element,
-	add,
-	mul,
-	transformDirection
-} from '../shadernode/ShaderNodeBaseElements.js';
-
+import Node, { addNodeClass } from '../core/Node.js';
 import { NodeUpdateType } from '../core/constants.js';
+import { ShaderNode, nodeProxy } from '../shadernode/ShaderNode.js';
+import { attribute } from '../core/AttributeNode.js';
+import { uniform } from '../core/UniformNode.js';
+import { add } from '../math/OperatorNode.js';
+import { buffer } from './BufferNode.js';
+import { normalLocal } from './NormalNode.js';
+import { positionLocal } from './PositionNode.js';
+import { tangentLocal } from './TangentNode.js';
 
-const Skinning = new ShaderNode( ( inputs, builder ) => {
+const Skinning = new ShaderNode( ( inputs, {}, builder ) => {
 
 	const { index, weight, bindMatrix, bindMatrixInverse, boneMatrices } = inputs;
 
-	const boneMatX = element( boneMatrices, index.x );
-	const boneMatY = element( boneMatrices, index.y );
-	const boneMatZ = element( boneMatrices, index.z );
-	const boneMatW = element( boneMatrices, index.w );
+	const boneMatX = boneMatrices.element( index.x );
+	const boneMatY = boneMatrices.element( index.y );
+	const boneMatZ = boneMatrices.element( index.z );
+	const boneMatW = boneMatrices.element( index.w );
 
 	// POSITION
 
-	const skinVertex = mul( bindMatrix, positionLocal );
+	const skinVertex = bindMatrix.mul( positionLocal );
 
 	const skinned = add(
-		mul( mul( boneMatX, skinVertex ), weight.x ),
-		mul( mul( boneMatY, skinVertex ), weight.y ),
-		mul( mul( boneMatZ, skinVertex ), weight.z ),
-		mul( mul( boneMatW, skinVertex ), weight.w )
+		boneMatX.mul( skinVertex ).mul( weight.x ),
+		boneMatY.mul( skinVertex ).mul( weight.y ),
+		boneMatZ.mul( skinVertex ).mul( weight.z ),
+		boneMatW.mul( skinVertex ).mul( weight.w )
 	);
 
-	const skinPosition = mul( bindMatrixInverse, skinned ).xyz;
+	const skinPosition = bindMatrixInverse.mul( skinned ).xyz;
 
 	// NORMAL
 
 	let skinMatrix = add(
-		mul( weight.x, boneMatX ),
-		mul( weight.y, boneMatY ),
-		mul( weight.z, boneMatZ ),
-		mul( weight.w, boneMatW )
+		weight.x.mul( boneMatX ),
+		weight.y.mul( boneMatY ),
+		weight.z.mul( boneMatZ ),
+		weight.w.mul( boneMatW )
 	);
 
-	skinMatrix = mul( mul( bindMatrixInverse, skinMatrix ), bindMatrix );
+	skinMatrix = bindMatrixInverse.mul( skinMatrix ).mul( bindMatrix );
 
-	const skinNormal = transformDirection( skinMatrix, normalLocal ).xyz;
+	const skinNormal = skinMatrix.transformDirection( normalLocal ).xyz;
 
 	// ASSIGNS
 
-	assign( positionLocal, skinPosition ).build( builder );
-	assign( normalLocal, skinNormal ).build( builder );
+	positionLocal.assign( skinPosition ).build( builder ); // @TODO: For some reason this doesn't work as stack.assign( positionLocal, skinPosition )?
+	normalLocal.assign( skinNormal ).build( builder );
 
 	if ( builder.hasGeometryAttribute( 'tangent' ) ) {
 
-		assign( tangentLocal, skinNormal ).build( builder );
+		tangentLocal.assign( skinNormal ).build( builder );
 
 	}
 
@@ -80,21 +72,28 @@ class SkinningNode extends Node {
 		this.skinIndexNode = attribute( 'skinIndex', 'uvec4' );
 		this.skinWeightNode = attribute( 'skinWeight', 'vec4' );
 
-		this.bindMatrixNode = uniform( mat4( skinnedMesh.bindMatrix ) );
-		this.bindMatrixInverseNode = uniform( mat4( skinnedMesh.bindMatrixInverse ) );
+		this.bindMatrixNode = uniform( skinnedMesh.bindMatrix, 'mat4' );
+		this.bindMatrixInverseNode = uniform( skinnedMesh.bindMatrixInverse, 'mat4' );
 		this.boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length );
 
 	}
 
 	generate( builder ) {
 
+		/*return new ShaderNode( ( {}, stack, builder ) => Skinning.call( {
+			index: this.skinIndexNode,
+			weight: this.skinWeightNode,
+			bindMatrix: this.bindMatrixNode,
+			bindMatrixInverse: this.bindMatrixInverseNode,
+			boneMatrices: this.boneMatricesNode
+		}, stack, builder ) ).build( builder );*/
 		Skinning.call( {
 			index: this.skinIndexNode,
 			weight: this.skinWeightNode,
 			bindMatrix: this.bindMatrixNode,
 			bindMatrixInverse: this.bindMatrixInverseNode,
 			boneMatrices: this.boneMatricesNode
-		}, builder );
+		}, {}, builder );
 
 	}
 
@@ -107,3 +106,7 @@ class SkinningNode extends Node {
 }
 
 export default SkinningNode;
+
+export const skinning = nodeProxy( SkinningNode );
+
+addNodeClass( SkinningNode );

+ 6 - 0
examples/jsm/nodes/accessors/StorageBufferNode.js

@@ -1,4 +1,6 @@
 import BufferNode from './BufferNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { nodeObject, getConstNodeType } from '../shadernode/ShaderNode.js';
 
 class StorageBufferNode extends BufferNode {
 
@@ -19,3 +21,7 @@ class StorageBufferNode extends BufferNode {
 }
 
 export default StorageBufferNode;
+
+export const storage = ( value, nodeOrType, count ) => nodeObject( new StorageBufferNode( value, getConstNodeType( nodeOrType ), count ) );
+
+addNodeClass( StorageBufferNode );

+ 23 - 15
examples/jsm/nodes/accessors/TangentNode.js

@@ -1,11 +1,11 @@
-import Node from '../core/Node.js';
-import AttributeNode from '../core/AttributeNode.js';
-import VaryingNode from '../core/VaryingNode.js';
-import ModelNode from '../accessors/ModelNode.js';
-import CameraNode from '../accessors/CameraNode.js';
-import OperatorNode from '../math/OperatorNode.js';
-import MathNode from '../math/MathNode.js';
-import SplitNode from '../utils/SplitNode.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { attribute } from '../core/AttributeNode.js';
+import { label } from '../core/VarNode.js';
+import { varying } from '../core/VaryingNode.js';
+import { normalize } from '../math/MathNode.js';
+import { cameraViewMatrix } from './CameraNode.js';
+import { modelViewMatrix } from './ModelNode.js';
+import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class TangentNode extends Node {
 
@@ -46,22 +46,21 @@ class TangentNode extends Node {
 
 		if ( scope === TangentNode.GEOMETRY ) {
 
-			outputNode = new AttributeNode( 'tangent', 'vec4' );
+			outputNode = attribute( 'tangent', 'vec4' );
 
 		} else if ( scope === TangentNode.LOCAL ) {
 
-			outputNode = new VaryingNode( new SplitNode( new TangentNode( TangentNode.GEOMETRY ), 'xyz' ) );
+			outputNode = varying( tangentGeometry.xyz );
 
 		} else if ( scope === TangentNode.VIEW ) {
 
-			const vertexNode = new SplitNode( new OperatorNode( '*', new ModelNode( ModelNode.VIEW_MATRIX ), new TangentNode( TangentNode.LOCAL ) ), 'xyz' );
-
-			outputNode = new MathNode( MathNode.NORMALIZE, new VaryingNode( vertexNode ) );
+			const vertexNode = modelViewMatrix.mul( tangentLocal ).xyz;
+			outputNode = normalize( varying( vertexNode ) );
 
 		} else if ( scope === TangentNode.WORLD ) {
 
-			const vertexNode = new MathNode( MathNode.TRANSFORM_DIRECTION, new TangentNode( TangentNode.VIEW ), new CameraNode( CameraNode.VIEW_MATRIX ) );
-			outputNode = new MathNode( MathNode.NORMALIZE, new VaryingNode( vertexNode ) );
+			const vertexNode = tangentView.transformDirection( cameraViewMatrix );
+			outputNode = normalize( varying( vertexNode ) );
 
 		}
 
@@ -93,3 +92,12 @@ TangentNode.VIEW = 'view';
 TangentNode.WORLD = 'world';
 
 export default TangentNode;
+
+export const tangentGeometry = nodeImmutable( TangentNode, TangentNode.GEOMETRY );
+export const tangentLocal = nodeImmutable( TangentNode, TangentNode.LOCAL );
+export const tangentView = nodeImmutable( TangentNode, TangentNode.VIEW );
+export const tangentWorld = nodeImmutable( TangentNode, TangentNode.WORLD );
+export const transformedTangentView = label( tangentView, 'TransformedTangentView' );
+export const transformedTangentWorld = normalize( transformedTangentView.transformDirection( cameraViewMatrix ) );
+
+addNodeClass( TangentNode );

+ 11 - 2
examples/jsm/nodes/accessors/TextureNode.js

@@ -1,5 +1,7 @@
 import UniformNode from '../core/UniformNode.js';
-import UVNode from './UVNode.js';
+import { uv } from './UVNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
 
 let defaultUV;
 
@@ -30,7 +32,7 @@ class TextureNode extends UniformNode {
 
 	getDefaultUV() {
 
-		return defaultUV || ( defaultUV = new UVNode() );
+		return defaultUV || ( defaultUV = uv() );
 
 	}
 
@@ -148,3 +150,10 @@ class TextureNode extends UniformNode {
 }
 
 export default TextureNode;
+
+export const texture = nodeProxy( TextureNode );
+export const sampler = ( aTexture ) => ( aTexture.isNode === true ? aTexture : texture( aTexture ) ).convert( 'sampler' );
+
+addNodeElement( 'texture', texture );
+
+addNodeClass( TextureNode );

+ 6 - 0
examples/jsm/nodes/accessors/UVNode.js

@@ -1,4 +1,6 @@
+import { addNodeClass } from '../core/Node.js';
 import AttributeNode from '../core/AttributeNode.js';
+import { nodeObject } from '../shadernode/ShaderNode.js';
 
 class UVNode extends AttributeNode {
 
@@ -39,3 +41,7 @@ class UVNode extends AttributeNode {
 }
 
 export default UVNode;
+
+export const uv = ( ...params ) => nodeObject( new UVNode( ...params ) );
+
+addNodeClass( UVNode );

+ 6 - 0
examples/jsm/nodes/accessors/UserDataNode.js

@@ -1,4 +1,6 @@
 import ReferenceNode from './ReferenceNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { nodeObject } from '../shadernode/ShaderNode.js';
 
 class UserDataNode extends ReferenceNode {
 
@@ -21,3 +23,7 @@ class UserDataNode extends ReferenceNode {
 }
 
 export default UserDataNode;
+
+export const userData = ( name, inputType, userData ) => nodeObject( new UserDataNode( name, inputType, userData ) );
+
+addNodeClass( UserDataNode );

+ 3 - 0
examples/jsm/nodes/core/ArrayUniformNode.js

@@ -1,4 +1,5 @@
 import UniformNode from './UniformNode.js';
+import { addNodeClass } from './Node.js';
 
 class ArrayUniformNode extends UniformNode {
 
@@ -21,3 +22,5 @@ class ArrayUniformNode extends UniformNode {
 }
 
 export default ArrayUniformNode;
+
+addNodeClass( ArrayUniformNode );

+ 8 - 3
examples/jsm/nodes/core/AttributeNode.js

@@ -1,5 +1,6 @@
-import Node from './Node.js';
-import VaryingNode from './VaryingNode.js';
+import Node, { addNodeClass } from './Node.js';
+import { varying } from './VaryingNode.js';
+import { nodeObject } from '../shadernode/ShaderNode.js';
 
 class AttributeNode extends Node {
 
@@ -73,7 +74,7 @@ class AttributeNode extends Node {
 
 			} else {
 
-				const nodeVarying = new VaryingNode( this );
+				const nodeVarying = varying( this );
 
 				return nodeVarying.build( builder, nodeAttribute.type );
 
@@ -92,3 +93,7 @@ class AttributeNode extends Node {
 }
 
 export default AttributeNode;
+
+export const attribute = ( name, nodeType ) => nodeObject( new AttributeNode( name, nodeType ) );
+
+addNodeClass( AttributeNode );

+ 8 - 1
examples/jsm/nodes/core/BypassNode.js

@@ -1,4 +1,5 @@
-import Node from './Node.js';
+import Node, { addNodeClass } from './Node.js';
+import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
 
 class BypassNode extends Node {
 
@@ -36,3 +37,9 @@ class BypassNode extends Node {
 }
 
 export default BypassNode;
+
+export const bypass = nodeProxy( BypassNode );
+
+addNodeElement( 'bypass', bypass );
+
+addNodeClass( BypassNode );

+ 8 - 1
examples/jsm/nodes/core/CacheNode.js

@@ -1,5 +1,6 @@
-import Node from './Node.js';
+import Node, { addNodeClass } from './Node.js';
 import NodeCache from './NodeCache.js';
+import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
 
 class CacheNode extends Node {
 
@@ -37,3 +38,9 @@ class CacheNode extends Node {
 }
 
 export default CacheNode;
+
+export const cache = nodeProxy( CacheNode );
+
+addNodeElement( 'cache', cache );
+
+addNodeClass( CacheNode );

+ 6 - 1
examples/jsm/nodes/core/CodeNode.js

@@ -1,4 +1,5 @@
-import Node from './Node.js';
+import Node, { addNodeClass } from './Node.js';
+import { nodeProxy } from '../shadernode/ShaderNode.js';
 
 class CodeNode extends Node {
 
@@ -48,3 +49,7 @@ class CodeNode extends Node {
 }
 
 export default CodeNode;
+
+export const code = nodeProxy( CodeNode );
+
+addNodeClass( CodeNode );

+ 3 - 0
examples/jsm/nodes/core/ConstNode.js

@@ -1,4 +1,5 @@
 import InputNode from './InputNode.js';
+import { addNodeClass } from './Node.js';
 
 class ConstNode extends InputNode {
 
@@ -27,3 +28,5 @@ class ConstNode extends InputNode {
 }
 
 export default ConstNode;
+
+addNodeClass( ConstNode );

+ 8 - 1
examples/jsm/nodes/core/ContextNode.js

@@ -1,4 +1,5 @@
-import Node from './Node.js';
+import Node, { addNodeClass } from './Node.js';
+import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
 
 class ContextNode extends Node {
 
@@ -50,3 +51,9 @@ class ContextNode extends Node {
 }
 
 export default ContextNode;
+
+export const context = nodeProxy( ContextNode );
+
+addNodeElement( 'context', context );
+
+addNodeClass( ContextNode );

+ 11 - 6
examples/jsm/nodes/core/ExpressionNode.js

@@ -1,27 +1,28 @@
-import Node from './Node.js';
+import Node, { addNodeClass } from './Node.js';
+import { nodeProxy } from '../shadernode/ShaderNode.js';
 
 class ExpressionNode extends Node {
 
-	constructor( snipped = '', nodeType = 'void' ) {
+	constructor( snippet = '', nodeType = 'void' ) {
 
 		super( nodeType );
 
-		this.snipped = snipped;
+		this.snippet = snippet;
 
 	}
 
 	generate( builder, output ) {
 
 		const type = this.getNodeType( builder );
-		const snipped = this.snipped;
+		const snippet = this.snippet;
 
 		if ( type === 'void' ) {
 
-			builder.addFlowCode( snipped );
+			builder.addFlowCode( snippet );
 
 		} else {
 
-			return builder.format( `( ${ snipped } )`, type, output );
+			return builder.format( `( ${ snippet } )`, type, output );
 
 		}
 
@@ -30,3 +31,7 @@ class ExpressionNode extends Node {
 }
 
 export default ExpressionNode;
+
+export const expression = nodeProxy( ExpressionNode );
+
+addNodeClass( ExpressionNode );

+ 14 - 0
examples/jsm/nodes/core/FunctionCallNode.js

@@ -1,4 +1,6 @@
 import TempNode from './TempNode.js';
+import { addNodeClass } from './Node.js';
+import { addNodeElement, nodeArray, nodeObject, nodeObjects } from '../shadernode/ShaderNode.js';
 
 class FunctionCallNode extends TempNode {
 
@@ -80,3 +82,15 @@ class FunctionCallNode extends TempNode {
 }
 
 export default FunctionCallNode;
+
+export const call = ( func, ...params ) => {
+
+	params = params.length > 1 || ( params[ 0 ] && params[ 0 ].isNode === true ) ? nodeArray( params ) : nodeObjects( params[ 0 ] );
+
+	return nodeObject( new FunctionCallNode( nodeObject( func ), params ) );
+
+};
+
+addNodeElement( 'call', call );
+
+addNodeClass( FunctionCallNode );

+ 8 - 7
examples/jsm/nodes/core/FunctionNode.js

@@ -1,5 +1,6 @@
 import CodeNode from './CodeNode.js';
-import FunctionCallNode from './FunctionCallNode.js';
+import { addNodeClass } from './Node.js';
+import { nodeObject } from '../shadernode/ShaderNode.js';
 
 class FunctionNode extends CodeNode {
 
@@ -41,12 +42,6 @@ class FunctionNode extends CodeNode {
 
 	}
 
-	call( parameters = {} ) {
-
-		return new FunctionCallNode( this, parameters );
-
-	}
-
 	generate( builder, output ) {
 
 		super.generate( builder );
@@ -103,3 +98,9 @@ class FunctionNode extends CodeNode {
 }
 
 export default FunctionNode;
+
+export const func = ( code, includes ) => nodeObject( new FunctionNode( code, includes ) );
+
+export const fn = ( code, includes ) => func( code, includes ).call;
+
+addNodeClass( FunctionNode );

+ 3 - 1
examples/jsm/nodes/core/InputNode.js

@@ -1,4 +1,4 @@
-import Node from './Node.js';
+import Node, { addNodeClass } from './Node.js';
 import { getValueType, getValueFromType } from './NodeUtils.js';
 
 class InputNode extends Node {
@@ -64,3 +64,5 @@ class InputNode extends Node {
 }
 
 export default InputNode;
+
+addNodeClass( InputNode );

+ 6 - 1
examples/jsm/nodes/core/InstanceIndexNode.js

@@ -1,4 +1,5 @@
-import Node from './Node.js';
+import Node, { addNodeClass } from './Node.js';
+import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class InstanceIndexNode extends Node {
 
@@ -19,3 +20,7 @@ class InstanceIndexNode extends Node {
 }
 
 export default InstanceIndexNode;
+
+export const instanceIndex = nodeImmutable( InstanceIndexNode );
+
+addNodeClass( InstanceIndexNode );

+ 2 - 0
examples/jsm/nodes/core/LightingModel.js

@@ -12,3 +12,5 @@ class LightingModel {
 }
 
 export default LightingModel;
+
+export const lightingModel = ( ...params ) => new LightingModel( ...params );

+ 42 - 9
examples/jsm/nodes/core/Node.js

@@ -2,6 +2,8 @@ import { NodeUpdateType } from './constants.js';
 import { getNodesKeys, getCacheKey } from './NodeUtils.js';
 import { MathUtils } from 'three';
 
+const NodeClasses = new Map();
+
 let _nodeId = 0;
 
 class Node {
@@ -32,9 +34,7 @@ class Node {
 
 	}
 
-	getChildren() {
-
-		const children = [];
+	* getChildren() {
 
 		for ( const property in this ) {
 
@@ -42,11 +42,13 @@ class Node {
 
 			if ( Array.isArray( object ) === true ) {
 
-				for ( const child of object ) {
+				for ( let i = 0; i < object.length; i++ ) {
+
+					const child = object[ i ];
 
 					if ( child && child.isNode === true ) {
 
-						children.push( child );
+						yield { childNode: child, replaceNode( node ) { object[ i ] = node; } };
 
 					}
 
@@ -54,7 +56,8 @@ class Node {
 
 			} else if ( object && object.isNode === true ) {
 
-				children.push( object );
+				const self = this;
+				yield { childNode: object, replaceNode( node ) { self[ property ] = node; } };
 
 			} else if ( typeof object === 'object' ) {
 
@@ -64,7 +67,7 @@ class Node {
 
 					if ( child && child.isNode === true ) {
 
-						children.push( child );
+						yield { childNode: child, replaceNode( node ) { object[ property ] = node; } };
 
 					}
 
@@ -74,7 +77,16 @@ class Node {
 
 		}
 
-		return children;
+	}
+
+	traverse( callback, replaceNode = null ) {
+
+		callback( this, replaceNode );
+		for ( const { childNode, replaceNode } of this.getChildren() ) {
+
+			childNode.traverse( callback, replaceNode );
+
+		}
 
 	}
 
@@ -115,7 +127,7 @@ class Node {
 
 		const nodeProperties = builder.getNodeProperties( this );
 
-		for ( const childNode of this.getChildren() ) {
+		for ( const { childNode } of this.getChildren() ) {
 
 			nodeProperties[ '_node' + childNode.id ] = childNode;
 
@@ -366,3 +378,24 @@ class Node {
 }
 
 export default Node;
+
+export function addNodeClass( nodeClass ) {
+
+	if ( typeof nodeClass !== 'function' || ! nodeClass.name ) throw new Error( `Node class ${ nodeClass.name } is not a class` );
+	if ( NodeClasses.has( nodeClass.name ) ) throw new Error( `Redefinition of node class ${ nodeClass.name }` );
+
+	NodeClasses.set( nodeClass.name, nodeClass );
+
+}
+
+export function createNodeFromType( type ) {
+
+	const Class = NodeClasses.get( type );
+
+	if ( Class !== undefined ) {
+
+		return new Class();
+
+	}
+
+};

+ 10 - 8
examples/jsm/nodes/core/NodeBuilder.js

@@ -5,16 +5,12 @@ import NodeVar from './NodeVar.js';
 import NodeCode from './NodeCode.js';
 import NodeKeywords from './NodeKeywords.js';
 import NodeCache from './NodeCache.js';
-import { NodeUpdateType } from './constants.js';
+import { NodeUpdateType, defaultBuildStages, shaderStages } from './constants.js';
 
 import { REVISION, LinearEncoding, Color, Vector2, Vector3, Vector4 } from 'three';
 
-import { mul, maxMipLevel } from '../shadernode/ShaderNodeElements.js';
-
-export const defaultShaderStages = [ 'fragment', 'vertex' ];
-export const defaultBuildStages = [ 'construct', 'analyze', 'generate' ];
-export const shaderStages = [ ...defaultShaderStages, 'compute' ];
-export const vector = [ 'x', 'y', 'z', 'w' ];
+import { stack } from './StackNode.js';
+import { maxMipLevel } from '../utils/MaxMipLevelNode.js';
 
 const typeFromLength = new Map();
 typeFromLength.set( 2, 'vec2' );
@@ -66,7 +62,7 @@ class NodeBuilder {
 		this.context = {
 			keywords: new NodeKeywords(),
 			material: object.material,
-			getMIPLevelAlgorithmNode: ( textureNode, levelNode ) => mul( levelNode, maxMipLevel( textureNode ) )
+			getMIPLevelAlgorithmNode: ( textureNode, levelNode ) => levelNode.mul( maxMipLevel( textureNode ) )
 		};
 
 		this.cache = new NodeCache();
@@ -451,6 +447,12 @@ class NodeBuilder {
 
 	}
 
+	createStack() {
+
+		return stack();
+
+	}
+
 	getDataFromNode( node, shaderStage = this.shaderStage ) {
 
 		const cache = node.isGlobal( this ) ? this.globalCache : this.cache;

+ 12 - 1
examples/jsm/nodes/core/PropertyNode.js

@@ -1,4 +1,5 @@
-import Node from './Node.js';
+import Node, { addNodeClass } from './Node.js';
+import { nodeImmutable, nodeObject, getConstNodeType } from '../shadernode/ShaderNode.js';
 
 class PropertyNode extends Node {
 
@@ -40,3 +41,13 @@ class PropertyNode extends Node {
 }
 
 export default PropertyNode;
+
+export const property = ( name, nodeOrType ) => nodeObject( new PropertyNode( name, getConstNodeType( nodeOrType ) ) );
+
+export const diffuseColor = nodeImmutable( PropertyNode, 'vec4', 'DiffuseColor' );
+export const roughness = nodeImmutable( PropertyNode, 'float', 'Roughness' );
+export const metalness = nodeImmutable( PropertyNode, 'float', 'Metalness' );
+export const specularColor = nodeImmutable( PropertyNode, 'color', 'SpecularColor' );
+export const shininess = nodeImmutable( PropertyNode, 'float', 'Shininess' );
+
+addNodeClass( PropertyNode );

+ 11 - 6
examples/jsm/nodes/core/StackNode.js

@@ -1,7 +1,8 @@
-import Node from './Node.js';
-import OperatorNode from '../math/OperatorNode.js';
-import BypassNode from '../core/BypassNode.js';
-import ExpressionNode from '../core/ExpressionNode.js';
+import Node, { addNodeClass } from './Node.js';
+import { assign } from '../math/OperatorNode.js';
+import { bypass } from '../core/BypassNode.js';
+import { expression } from '../core/ExpressionNode.js';
+import { nodeProxy } from '../shadernode/ShaderNode.js';
 
 class StackNode extends Node {
 
@@ -24,7 +25,7 @@ class StackNode extends Node {
 
 	add( node ) {
 
-		this.nodes.push( new BypassNode( new ExpressionNode(), node ) );
+		this.nodes.push( bypass( expression(), node ) );
 
 		return this;
 
@@ -32,7 +33,7 @@ class StackNode extends Node {
 
 	assign( targetNode, sourceValue ) {
 
-		return this.add( new OperatorNode( '=', targetNode, sourceValue ) );
+		return this.add( assign( targetNode, sourceValue ) );
 
 	}
 
@@ -51,3 +52,7 @@ class StackNode extends Node {
 }
 
 export default StackNode;
+
+export const stack = nodeProxy( StackNode );
+
+addNodeClass( StackNode );

+ 4 - 2
examples/jsm/nodes/core/TempNode.js

@@ -1,4 +1,4 @@
-import Node from './Node.js';
+import Node, { addNodeClass } from './Node.js';
 
 class TempNode extends Node {
 
@@ -29,7 +29,7 @@ class TempNode extends Node {
 
 				return builder.format( nodeData.propertyName, type, output );
 
-			} else if ( builder.context.tempWrite !== false && type !== 'void ' && output !== 'void' && this.hasDependencies( builder ) ) {
+			} else if ( builder.context.tempWrite !== false && type !== 'void' && output !== 'void' && this.hasDependencies( builder ) ) {
 
 				const snippet = super.build( builder, type );
 
@@ -54,3 +54,5 @@ class TempNode extends Node {
 }
 
 export default TempNode;
+
+addNodeClass( TempNode );

+ 15 - 0
examples/jsm/nodes/core/UniformNode.js

@@ -1,4 +1,6 @@
 import InputNode from './InputNode.js';
+import { addNodeClass } from './Node.js';
+import { nodeObject, getConstNodeType } from '../shadernode/ShaderNode.js';
 
 class UniformNode extends InputNode {
 
@@ -44,3 +46,16 @@ class UniformNode extends InputNode {
 }
 
 export default UniformNode;
+
+export const uniform = ( arg1, arg2 ) => {
+
+	const nodeType = getConstNodeType( arg2 || arg1 );
+
+	// @TODO: get ConstNode from .traverse() in the future
+	const value = ( arg1 && arg1.isNode === true ) ? ( arg1.node && arg1.node.value ) || arg1.value : arg1;
+
+	return nodeObject( new UniformNode( value, nodeType ) );
+
+};
+
+addNodeClass( UniformNode );

+ 18 - 32
examples/jsm/nodes/core/VarNode.js

@@ -1,5 +1,5 @@
-import Node from './Node.js';
-import OperatorNode from '../math/OperatorNode.js';
+import Node, { addNodeClass } from './Node.js';
+import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
 
 class VarNode extends Node {
 
@@ -12,41 +12,19 @@ class VarNode extends Node {
 
 	}
 
-	op( op, ...params ) {
+	assign( node ) {
 
-		this.node = new OperatorNode( op, this.node, ...params );
+		node.traverse( ( childNode, replaceNode ) => {
 
-		return this;
-
-	}
-
-	assign( ...params ) {
-
-		return this.op( '=', ...params );
-
-	}
-
-	add( ...params ) {
-
-		return this.op( '+', ...params );
+			if ( replaceNode && childNode.uuid === this.uuid ) {
 
-	}
-
-	sub( ...params ) {
+				replaceNode( this.node );
 
-		return this.op( '-', ...params );
+			}
 
-	}
-
-	mul( ...params ) {
-
-		return this.op( '*', ...params );
-
-	}
-
-	div( ...params ) {
-
-		return this.op( '/', ...params );
+		} );
+		this.node = node;
+		return this;
 
 	}
 
@@ -101,3 +79,11 @@ class VarNode extends Node {
 }
 
 export default VarNode;
+
+export const label = nodeProxy( VarNode );
+export const temp = label;
+
+addNodeElement( 'label', label );
+addNodeElement( 'temp', temp );
+
+addNodeClass( VarNode );

+ 8 - 1
examples/jsm/nodes/core/VaryingNode.js

@@ -1,5 +1,6 @@
-import Node from './Node.js';
+import Node, { addNodeClass } from './Node.js';
 import { NodeShaderStage } from './constants.js';
+import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
 
 class VaryingNode extends Node {
 
@@ -60,3 +61,9 @@ class VaryingNode extends Node {
 }
 
 export default VaryingNode;
+
+export const varying = nodeProxy( VaryingNode );
+
+addNodeElement( 'varying', varying );
+
+addNodeClass( VaryingNode );

+ 5 - 0
examples/jsm/nodes/core/constants.js

@@ -19,3 +19,8 @@ export const NodeType = {
 	MATRIX3: 'mat3',
 	MATRIX4: 'mat4'
 };
+
+export const defaultShaderStages = [ 'fragment', 'vertex' ];
+export const defaultBuildStages = [ 'construct', 'analyze', 'generate' ];
+export const shaderStages = [ ...defaultShaderStages, 'compute' ];
+export const vectorComponents = [ 'x', 'y', 'z', 'w' ];

+ 20 - 6
examples/jsm/nodes/display/BlendModeNode.js

@@ -1,9 +1,11 @@
-import TempNode from '../core/Node.js';
-import { ShaderNode, EPSILON, vec3, sub, mul, div, cond, lessThan, equal, max } from '../shadernode/ShaderNodeBaseElements.js';
+import TempNode from '../core/TempNode.js';
+import { EPSILON } from '../math/MathNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { addNodeElement, ShaderNode, nodeProxy, vec3 } from '../shadernode/ShaderNode.js';
 
 export const BurnNode = new ShaderNode( ( { base, blend } ) => {
 
-	const fn = ( c ) => cond( lessThan( blend[ c ], EPSILON ), blend[ c ], max( sub( 1.0, div( sub( 1.0, base[ c ] ), blend[ c ] ) ), 0 ) );
+	const fn = ( c ) => blend[ c ].lessThan( EPSILON ).cond( blend[ c ], base[ c ].invert().div( blend[ c ] ).invert().max( 0 ) );
 
 	return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) );
 
@@ -11,7 +13,7 @@ export const BurnNode = new ShaderNode( ( { base, blend } ) => {
 
 export const DodgeNode = new ShaderNode( ( { base, blend } ) => {
 
-	const fn = ( c ) => cond( equal( blend[ c ], 1.0 ), blend[ c ], max( div( base[ c ], sub( 1.0, blend[ c ] ) ), 0 ) );
+	const fn = ( c ) => blend[ c ].equal( 1.0 ).cond( blend[ c ], base[ c ].div( blend[ c ].invert() ).max( 0 ) );
 
 	return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) );
 
@@ -19,7 +21,7 @@ export const DodgeNode = new ShaderNode( ( { base, blend } ) => {
 
 export const ScreenNode = new ShaderNode( ( { base, blend } ) => {
 
-	const fn = ( c ) => sub( 1.0, mul( sub( 1.0, base[ c ] ), sub( 1.0, blend[ c ] ) ) );
+	const fn = ( c ) => base[ c ].invert().mul( blend[ c ].invert() ).invert();
 
 	return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) );
 
@@ -27,7 +29,7 @@ export const ScreenNode = new ShaderNode( ( { base, blend } ) => {
 
 export const OverlayNode = new ShaderNode( ( { base, blend } ) => {
 
-	const fn = ( c ) => cond( lessThan( base[ c ], 0.5 ), mul( 2.0, base[ c ], blend[ c ] ), sub( 1.0, mul( sub( 1.0, base[ c ] ), sub( 1.0, blend[ c ] ) ) ) );
+	const fn = ( c ) => base[ c ].lessThan( 0.5 ).cond( base[ c ].mul( blend[ c ], 2.0 ), base[ c ].invert().mul( blend[ c ].invert() ).invert() );
 
 	return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) );
 
@@ -83,3 +85,15 @@ BlendModeNode.SCREEN = 'screen';
 BlendModeNode.OVERLAY = 'overlay';
 
 export default BlendModeNode;
+
+export const burn = nodeProxy( BlendModeNode, BlendModeNode.BURN );
+export const dodge = nodeProxy( BlendModeNode, BlendModeNode.DODGE );
+export const overlay = nodeProxy( BlendModeNode, BlendModeNode.OVERLAY );
+export const screen = nodeProxy( BlendModeNode, BlendModeNode.SCREEN );
+
+addNodeElement( 'burn', burn );
+addNodeElement( 'dodge', dodge );
+addNodeElement( 'overlay', overlay );
+addNodeElement( 'screen', screen );
+
+addNodeClass( BlendModeNode );

+ 26 - 10
examples/jsm/nodes/display/ColorAdjustmentNode.js

@@ -1,20 +1,23 @@
 import TempNode from '../core/TempNode.js';
-import { ShaderNode, vec3, mat3, add, sub, mul, max, div, float, mix, cos, sin, atan2, sqrt, luminance } from '../shadernode/ShaderNodeBaseElements.js';
+import { dot, mix } from '../math/MathNode.js';
+import { add } from '../math/OperatorNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { addNodeElement, ShaderNode, nodeProxy, float, vec3, mat3 } from '../shadernode/ShaderNode.js';
 
 const saturationNode = new ShaderNode( ( { color, adjustment } ) => {
 
-	return mix( luminance( color ), color, adjustment );
+	return luminance( color ).mix( color, adjustment );
 
 } );
 
 const vibranceNode = new ShaderNode( ( { color, adjustment } ) => {
 
-	const average = div( add( color.r, color.g, color.b ), 3.0 );
+	const average = add( color.r, color.g, color.b ).div( 3.0 );
 
-	const mx = max( color.r, max( color.g, color.b ) );
-	const amt = mul( sub( mx, average ), mul( - 3.0, adjustment ) );
+	const mx = color.r.max( color.g.max( color.b ) );
+	const amt = mx.sub( average ).mul( adjustment ).mul( - 3.0 );
 
-	return mix( color.rgb, vec3( mx ), amt );
+	return mix( color, mx, amt );
 
 } );
 
@@ -23,12 +26,12 @@ const hueNode = new ShaderNode( ( { color, adjustment } ) => {
 	const RGBtoYIQ = mat3( 0.299, 0.587, 0.114, 0.595716, - 0.274453, - 0.321263, 0.211456, - 0.522591, 0.311135 );
 	const YIQtoRGB = mat3( 1.0, 0.9563, 0.6210, 1.0, - 0.2721, - 0.6474, 1.0, - 1.107, 1.7046 );
 
-	const yiq = mul( RGBtoYIQ, color );
+	const yiq = RGBtoYIQ.mul( color );
 
-	const hue = add( atan2( yiq.z, yiq.y ), adjustment );
-	const chroma = sqrt( add( mul( yiq.z, yiq.z ), mul( yiq.y, yiq.y ) ) );
+	const hue = yiq.z.atan2( yiq.y ).add( adjustment );
+	const chroma = yiq.yz.length();
 
-	return mul( YIQtoRGB, vec3( yiq.x, mul( chroma, cos( hue ) ), mul( chroma, sin( hue ) ) ) );
+	return YIQtoRGB.mul( vec3( yiq.x, chroma.mul( hue.cos() ), chroma.mul( hue.sin() ) ) );
 
 } );
 
@@ -82,3 +85,16 @@ ColorAdjustmentNode.VIBRANCE = 'vibrance';
 ColorAdjustmentNode.HUE = 'hue';
 
 export default ColorAdjustmentNode;
+
+export const saturation = nodeProxy( ColorAdjustmentNode, ColorAdjustmentNode.SATURATION );
+export const vibrance = nodeProxy( ColorAdjustmentNode, ColorAdjustmentNode.VIBRANCE );
+export const hue = nodeProxy( ColorAdjustmentNode, ColorAdjustmentNode.HUE );
+
+export const lumaCoeffs = vec3( 0.2125, 0.7154, 0.0721 );
+export const luminance = ( color, luma = lumaCoeffs ) => dot( color, luma );
+
+addNodeElement( 'saturation', saturation );
+addNodeElement( 'vibrance', vibrance );
+addNodeElement( 'hue', hue );
+
+addNodeClass( ColorAdjustmentNode );

+ 16 - 26
examples/jsm/nodes/display/ColorSpaceNode.js

@@ -1,5 +1,7 @@
-import TempNode from '../core/Node.js';
-import { ShaderNode, vec3, pow, mul, sub, mix, vec4, lessThanEqual } from '../shadernode/ShaderNodeBaseElements.js';
+import TempNode from '../core/TempNode.js';
+import { mix } from '../math/MathNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { addNodeElement, ShaderNode, nodeObject, vec4 } from '../shadernode/ShaderNode.js';
 
 import { LinearEncoding, sRGBEncoding } from 'three';
 
@@ -12,12 +14,11 @@ export const LinearToLinear = new ShaderNode( ( inputs ) => {
 export const LinearTosRGB = new ShaderNode( ( inputs ) => {
 
 	const { value } = inputs;
+	const { rgb } = value;
 
-	const rgb = value.rgb;
-
-	const a = sub( mul( pow( value.rgb, vec3( 0.41666 ) ), 1.055 ), vec3( 0.055 ) );
-	const b = mul( rgb, 12.92 );
-	const factor = vec3( lessThanEqual( rgb, vec3( 0.0031308 ) ) );
+	const a = rgb.pow( 0.41666 ).mul( 1.055 ).sub( 0.055 );
+	const b = rgb.mul( 12.92 );
+	const factor = rgb.lessThanEqual( 0.0031308 );
 
 	const rgbResult = mix( a, b, factor );
 
@@ -64,26 +65,9 @@ class ColorSpaceNode extends TempNode {
 
 	construct() {
 
-		const method = this.method;
-		const node = this.node;
-
-		let outputNode = null;
-
-		if ( method !== ColorSpaceNode.LINEAR_TO_LINEAR ) {
-
-			const encodingFunctionNode = EncodingLib[ method ];
-
-			outputNode = encodingFunctionNode.call( {
-				value: node
-			} );
-
-		} else {
+		const { method, node } = this;
 
-			outputNode = node;
-
-		}
-
-		return outputNode;
+		return EncodingLib[ method ].call( { value: node } );
 
 	}
 
@@ -93,3 +77,9 @@ ColorSpaceNode.LINEAR_TO_LINEAR = 'LinearToLinear';
 ColorSpaceNode.LINEAR_TO_SRGB = 'LinearTosRGB';
 
 export default ColorSpaceNode;
+
+export const colorSpace = ( node, encoding ) => nodeObject( new ColorSpaceNode( null, nodeObject( node ) ).fromEncoding( encoding ) );
+
+addNodeElement( 'colorSpace', colorSpace );
+
+addNodeClass( ColorSpaceNode );

+ 7 - 1
examples/jsm/nodes/display/FrontFacingNode.js

@@ -1,4 +1,5 @@
-import Node from '../core/Node.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { nodeImmutable, float } from '../shadernode/ShaderNode.js';
 
 class FrontFacingNode extends Node {
 
@@ -19,3 +20,8 @@ class FrontFacingNode extends Node {
 }
 
 export default FrontFacingNode;
+
+export const frontFacing = nodeImmutable( FrontFacingNode );
+export const faceDirection = float( frontFacing ).mul( 2.0 ).sub( 1.0 );
+
+addNodeClass( FrontFacingNode );

+ 31 - 18
examples/jsm/nodes/display/NormalMapNode.js

@@ -1,5 +1,14 @@
 import TempNode from '../core/TempNode.js';
-import { ShaderNode, positionView, normalView, uv, vec3, add, sub, mul, dFdx, dFdy, cross, max, dot, normalize, inversesqrt, faceDirection, modelNormalMatrix, TBNViewMatrix } from '../shadernode/ShaderNodeBaseElements.js';
+import { add } from '../math/OperatorNode.js';
+import { bitangentView } from '../accessors/BitangentNode.js';
+import { modelNormalMatrix } from '../accessors/ModelNode.js';
+import { normalView } from '../accessors/NormalNode.js';
+import { positionView } from '../accessors/PositionNode.js';
+import { tangentView } from '../accessors/TangentNode.js';
+import { uv } from '../accessors/UVNode.js';
+import { faceDirection } from './FrontFacingNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { ShaderNode, nodeProxy, vec3, mat3 } from '../shadernode/ShaderNode.js';
 
 import { TangentSpaceNormalMap, ObjectSpaceNormalMap } from 'three';
 
@@ -10,23 +19,23 @@ const perturbNormal2ArbNode = new ShaderNode( ( inputs ) => {
 
 	const { eye_pos, surf_norm, mapN, uv } = inputs;
 
-	const q0 = dFdx( eye_pos.xyz );
-	const q1 = dFdy( eye_pos.xyz );
-	const st0 = dFdx( uv.st );
-	const st1 = dFdy( uv.st );
+	const q0 = eye_pos.dFdx();
+	const q1 = eye_pos.dFdy();
+	const st0 = uv.dFdx();
+	const st1 = uv.dFdy();
 
 	const N = surf_norm; // normalized
 
-	const q1perp = cross( q1, N );
-	const q0perp = cross( N, q0 );
+	const q1perp = q1.cross( N );
+	const q0perp = N.cross( q0 );
 
-	const T = add( mul( q1perp, st0.x ), mul( q0perp, st1.x ) );
-	const B = add( mul( q1perp, st0.y ), mul( q0perp, st1.y ) );
+	const T = q1perp.mul( st0.x ).add( q0perp.mul( st1.x ) );
+	const B = q1perp.mul( st0.y ).add( q0perp.mul( st1.y ) );
 
-	const det = max( dot( T, T ), dot( B, B ) );
-	const scale = mul( faceDirection, inversesqrt( det ) );
+	const det = T.dot( T ).max( B.dot( B ) );
+	const scale = faceDirection.mul( det.inversesqrt() );
 
-	return normalize( add( mul( T, mul( mapN.x, scale ) ), mul( B, mul( mapN.y, scale ) ), mul( N, mapN.z ) ) );
+	return add( T.mul( mapN.x, scale ), B.mul( mapN.y, scale ), N.mul( mapN.z ) ).normalize();
 
 } );
 
@@ -47,13 +56,11 @@ class NormalMapNode extends TempNode {
 
 		const { normalMapType, scaleNode } = this;
 
-		const normalOP = mul( this.node, 2.0 );
-		let normalMap = sub( normalOP, 1.0 );
+		let normalMap = this.node.mul( 2.0 ).sub( 1.0 );
 
 		if ( scaleNode !== null ) {
 
-			const normalMapScale = mul( normalMap.xy, scaleNode );
-			normalMap = vec3( normalMapScale, normalMap.z );
+			normalMap = vec3( normalMap.xy.mul( scaleNode ), normalMap.z );
 
 		}
 
@@ -61,7 +68,7 @@ class NormalMapNode extends TempNode {
 
 		if ( normalMapType === ObjectSpaceNormalMap ) {
 
-			outputNode = normalize( mul( modelNormalMatrix, normalMap ) );
+			outputNode = modelNormalMatrix.mul( normalMap ).normalize();
 
 		} else if ( normalMapType === TangentSpaceNormalMap ) {
 
@@ -69,7 +76,7 @@ class NormalMapNode extends TempNode {
 
 			if ( tangent === true ) {
 
-				outputNode = normalize( mul( TBNViewMatrix, normalMap ) );
+				outputNode = TBNViewMatrix.mul( normalMap ).normalize();
 
 			} else {
 
@@ -91,3 +98,9 @@ class NormalMapNode extends TempNode {
 }
 
 export default NormalMapNode;
+
+export const normalMap = nodeProxy( NormalMapNode );
+
+export const TBNViewMatrix = mat3( tangentView, bitangentView, normalView );
+
+addNodeClass( NormalMapNode );

+ 10 - 3
examples/jsm/nodes/display/PosterizeNode.js

@@ -1,5 +1,6 @@
-import TempNode from '../core/Node.js';
-import { mul, floor, reciprocal } from '../shadernode/ShaderNodeBaseElements.js';
+import TempNode from '../core/TempNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
 
 class PosterizeNode extends TempNode {
 
@@ -16,10 +17,16 @@ class PosterizeNode extends TempNode {
 
 		const { sourceNode, stepsNode } = this;
 
-		return mul( floor( mul( sourceNode, stepsNode ) ), reciprocal( stepsNode ) );
+		return sourceNode.mul( stepsNode ).floor().div( stepsNode );
 
 	}
 
 }
 
 export default PosterizeNode;
+
+export const posterize = nodeProxy( PosterizeNode );
+
+addNodeElement( 'posterize', posterize );
+
+addNodeClass( PosterizeNode );

+ 14 - 9
examples/jsm/nodes/display/ToneMappingNode.js

@@ -1,35 +1,36 @@
-import TempNode from '../core/Node.js';
-import { ShaderNode, vec3, mat3, float, clamp, max, pow } from '../shadernode/ShaderNodeBaseElements.js';
+import TempNode from '../core/TempNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { ShaderNode, nodeObject, float, vec3, mat3 } from '../shadernode/ShaderNode.js';
 
 import { NoToneMapping, LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping } from 'three';
 
 // exposure only
-export const LinearToneMappingNode = new ShaderNode( ( { color, exposure } ) => {
+const LinearToneMappingNode = new ShaderNode( ( { color, exposure } ) => {
 
 	return color.mul( exposure );
 
 } );
 
 // source: https://www.cs.utah.edu/docs/techreports/2002/pdf/UUCS-02-001.pdf
-export const ReinhardToneMappingNode = new ShaderNode( ( { color, exposure } ) => {
+const ReinhardToneMappingNode = new ShaderNode( ( { color, exposure } ) => {
 
 	color = color.mul( exposure );
 
-	return clamp( color.div( vec3( 1.0 ).add( color ) ) );
+	return color.div( color.add( 1.0 ) ).clamp();
 
 } );
 
 // source: http://filmicworlds.com/blog/filmic-tonemapping-operators/
-export const OptimizedCineonToneMappingNode = new ShaderNode( ( { color, exposure } ) => {
+const OptimizedCineonToneMappingNode = new ShaderNode( ( { color, exposure } ) => {
 
 	// optimized filmic operator by Jim Hejl and Richard Burgess-Dawson
 	color = color.mul( exposure );
-	color = max( vec3( 0.0 ), color.sub( 0.004 ) );
+	color = color.sub( 0.004 ).max( 0.0 );
 
 	const a = color.mul( color.mul( 6.2 ).add( 0.5 ) );
 	const b = color.mul( color.mul( 6.2 ).add( 1.7 ) ).add( 0.06 );
 
-	return pow( a.div( b ), vec3( 2.2 ) );
+	return a.div( b ).pow( 2.2 );
 
 } );
 
@@ -70,7 +71,7 @@ const ACESFilmicToneMappingNode = new ShaderNode( ( { color, exposure } ) => {
 	color = ACESOutputMat.mul( color );
 
 	// Clamp to [0, 1]
-	return clamp( color );
+	return color.clamp();
 
 } );
 
@@ -125,3 +126,7 @@ class ToneMappingNode extends TempNode {
 }
 
 export default ToneMappingNode;
+
+export const toneMapping = ( mapping, exposure, color ) => nodeObject( new ToneMappingNode( mapping, nodeObject( exposure ), nodeObject( color ) ) );
+
+addNodeClass( ToneMappingNode );

+ 18 - 7
examples/jsm/nodes/display/ViewportNode.js

@@ -1,7 +1,9 @@
-import Node from '../core/Node.js';
-import { uniform, div, vec2, invert } from '../shadernode/ShaderNodeBaseElements.js';
-import { Vector2 } from 'three';
+import Node, { addNodeClass } from '../core/Node.js';
 import { NodeUpdateType } from '../core/constants.js';
+import { uniform } from '../core/UniformNode.js';
+import { nodeImmutable, vec2 } from '../shadernode/ShaderNode.js';
+
+import { Vector2 } from 'three';
 
 let resolution;
 
@@ -62,15 +64,15 @@ class ViewportNode extends Node {
 			const coordinateNode = vec2( new ViewportNode( ViewportNode.COORDINATE ) );
 			const resolutionNode = new ViewportNode( ViewportNode.RESOLUTION );
 
-			output = div( coordinateNode, resolutionNode );
+			output = coordinateNode.div( resolutionNode );
 
 			let outX = output.x;
 			let outY = output.y;
 
-			if ( /top/i.test( scope ) && builder.isFlipY() ) outY = invert( outY );
-			else if ( /bottom/i.test( scope ) && builder.isFlipY() === false ) outY = invert( outY );
+			if ( /top/i.test( scope ) && builder.isFlipY() ) outY = outY.invert();
+			else if ( /bottom/i.test( scope ) && builder.isFlipY() === false ) outY = outY.invert();
 
-			if ( /right/i.test( scope ) ) outX = invert( outX );
+			if ( /right/i.test( scope ) ) outX = outX.invert();
 
 			output = vec2( outX, outY );
 
@@ -102,3 +104,12 @@ ViewportNode.TOP_RIGHT = 'topRight';
 ViewportNode.BOTTOM_RIGHT = 'bottomRight';
 
 export default ViewportNode;
+
+export const viewportCoordinate = nodeImmutable( ViewportNode, ViewportNode.COORDINATE );
+export const viewportResolution = nodeImmutable( ViewportNode, ViewportNode.RESOLUTION );
+export const viewportTopLeft = nodeImmutable( ViewportNode, ViewportNode.TOP_LEFT );
+export const viewportBottomLeft = nodeImmutable( ViewportNode, ViewportNode.BOTTOM_LEFT );
+export const viewportTopRight = nodeImmutable( ViewportNode, ViewportNode.TOP_RIGHT );
+export const viewportBottomRight = nodeImmutable( ViewportNode, ViewportNode.BOTTOM_RIGHT );
+
+addNodeClass( ViewportNode );

+ 11 - 3
examples/jsm/nodes/fog/FogExp2Node.js

@@ -1,5 +1,7 @@
 import FogNode from './FogNode.js';
-import { sub, exp, mul, negate, positionView } from '../shadernode/ShaderNodeBaseElements.js';
+import { positionView } from '../accessors/PositionNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
 
 class FogExp2Node extends FogNode {
 
@@ -15,13 +17,19 @@ class FogExp2Node extends FogNode {
 
 	construct() {
 
-		const depthNode = negate( positionView.z );
+		const depthNode = positionView.z.negate();
 		const densityNode = this.densityNode;
 
-		this.factorNode = sub( 1.0, exp( mul( negate( densityNode ), densityNode, depthNode, depthNode ) ) );
+		this.factorNode = densityNode.mul( densityNode, depthNode, depthNode ).negate().exp().invert();
 
 	}
 
 }
 
 export default FogExp2Node;
+
+export const densityFog = nodeProxy( FogExp2Node );
+
+addNodeElement( 'densityFog', densityFog );
+
+addNodeClass( FogExp2Node );

+ 9 - 3
examples/jsm/nodes/fog/FogNode.js

@@ -1,5 +1,5 @@
-import Node from '../core/Node.js';
-import MathNode from '../math/MathNode.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
 
 class FogNode extends Node {
 
@@ -16,7 +16,7 @@ class FogNode extends Node {
 
 	mix( outputNode ) {
 
-		return new MathNode( MathNode.MIX, outputNode, this.colorNode, this );
+		return outputNode.mix( this.colorNode, this );
 
 	}
 
@@ -29,3 +29,9 @@ class FogNode extends Node {
 }
 
 export default FogNode;
+
+export const fog = nodeProxy( FogNode );
+
+addNodeElement( 'fog', fog );
+
+addNodeClass( FogNode );

+ 11 - 2
examples/jsm/nodes/fog/FogRangeNode.js

@@ -1,5 +1,8 @@
 import FogNode from './FogNode.js';
-import { smoothstep, negate, positionView } from '../shadernode/ShaderNodeBaseElements.js';
+import { smoothstep } from '../math/MathNode.js';
+import { positionView } from '../accessors/PositionNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
 
 class FogRangeNode extends FogNode {
 
@@ -16,10 +19,16 @@ class FogRangeNode extends FogNode {
 
 	construct() {
 
-		this.factorNode = smoothstep( this.nearNode, this.farNode, negate( positionView.z ) );
+		this.factorNode = smoothstep( this.nearNode, this.farNode, positionView.z.negate() );
 
 	}
 
 }
 
 export default FogRangeNode;
+
+export const rangeFog = nodeProxy( FogRangeNode );
+
+addNodeElement( 'rangeFog', rangeFog );
+
+addNodeClass( FogRangeNode );

+ 9 - 6
examples/jsm/nodes/functions/BSDF/BRDF_BlinnPhong.js

@@ -1,26 +1,29 @@
 import F_Schlick from './F_Schlick.js';
-import { ShaderNode, shininess, specularColor, float, add, clamp, dot, mul, normalize, positionViewDirection, transformedNormalView } from '../../shadernode/ShaderNodeBaseElements.js';
+import { shininess, specularColor } from '../../core/PropertyNode.js';
+import { transformedNormalView } from '../../accessors/NormalNode.js';
+import { positionViewDirection } from '../../accessors/PositionNode.js';
+import { ShaderNode, float } from '../../shadernode/ShaderNode.js';
 
 const G_BlinnPhong_Implicit = () => float( 0.25 );
 
 const D_BlinnPhong = new ShaderNode( ( { dotNH } ) => {
 
-	return shininess.mul( 1 / Math.PI ).mul( 0.5 ).add( 1.0 ).mul( dotNH.pow( shininess ) );
+	return shininess.mul( 0.5 / Math.PI ).add( 1.0 ).mul( dotNH.pow( shininess ) );
 
 } );
 
 const BRDF_BlinnPhong = new ShaderNode( ( { lightDirection } ) => {
 
-	const halfDir = normalize( add( lightDirection, positionViewDirection ) );
+	const halfDir = lightDirection.add( positionViewDirection ).normalize();
 
-	const dotNH = clamp( dot( transformedNormalView, halfDir ) );
-	const dotVH = clamp( dot( positionViewDirection, halfDir ) );
+	const dotNH = transformedNormalView.dot( halfDir ).clamp();
+	const dotVH = positionViewDirection.dot( halfDir ).clamp();
 
 	const F = F_Schlick.call( { f0: specularColor, f90: 1.0, dotVH } );
 	const G = G_BlinnPhong_Implicit();
 	const D = D_BlinnPhong.call( { dotNH } );
 
-	return mul( F, G, D );
+	return F.mul( G ).mul( D );
 
 } );
 

+ 10 - 13
examples/jsm/nodes/functions/BSDF/BRDF_GGX.js

@@ -1,32 +1,29 @@
 import F_Schlick from './F_Schlick.js';
 import V_GGX_SmithCorrelated from './V_GGX_SmithCorrelated.js';
 import D_GGX from './D_GGX.js';
-import {
-	ShaderNode, dotNV, add, mul, clamp, dot, pow2, normalize,
-	transformedNormalView, positionViewDirection
-} from '../../shadernode/ShaderNodeBaseElements.js';
+import { transformedNormalView } from '../../accessors/NormalNode.js';
+import { positionViewDirection } from '../../accessors/PositionNode.js';
+import { ShaderNode } from '../../shadernode/ShaderNode.js';
 
 // GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility
 const BRDF_GGX = new ShaderNode( ( inputs ) => {
 
 	const { lightDirection, f0, f90, roughness } = inputs;
 
-	const alpha = pow2( roughness ); // UE4's roughness
+	const alpha = roughness.pow2(); // UE4's roughness
 
-	const halfDir = normalize( add( lightDirection, positionViewDirection ) );
+	const halfDir = lightDirection.add( positionViewDirection ).normalize();
 
-	const dotNL = clamp( dot( transformedNormalView, lightDirection ) );
-	//const dotNV = clamp( dot( transformedNormalView, positionViewDirection ) );
-	const dotNH = clamp( dot( transformedNormalView, halfDir ) );
-	const dotVH = clamp( dot( positionViewDirection, halfDir ) );
+	const dotNL = transformedNormalView.dot( lightDirection ).clamp();
+	const dotNV = transformedNormalView.dot( positionViewDirection ).clamp();
+	const dotNH = transformedNormalView.dot( halfDir ).clamp();
+	const dotVH = positionViewDirection.dot( halfDir ).clamp();
 
 	const F = F_Schlick.call( { f0, f90, dotVH } );
-
 	const V = V_GGX_SmithCorrelated.call( { alpha, dotNL, dotNV } );
-
 	const D = D_GGX.call( { alpha, dotNH } );
 
-	return mul( F, mul( V, D ) );
+	return F.mul( V ).mul( D );
 
 } ); // validated
 

+ 2 - 2
examples/jsm/nodes/functions/BSDF/BRDF_Lambert.js

@@ -1,8 +1,8 @@
-import { ShaderNode, mul } from '../../shadernode/ShaderNodeBaseElements.js';
+import { ShaderNode } from '../../shadernode/ShaderNode.js';
 
 const BRDF_Lambert = new ShaderNode( ( inputs ) => {
 
-	return mul( 1 / Math.PI, inputs.diffuseColor ); // punctual light
+	return inputs.diffuseColor.mul( 1 / Math.PI ); // punctual light
 
 } ); // validated
 

+ 6 - 4
examples/jsm/nodes/functions/BSDF/DFGApprox.js

@@ -1,6 +1,6 @@
-import {
-	ShaderNode, dotNV, vec2, vec4, mul, min
-} from '../../shadernode/ShaderNodeElements.js';
+import { transformedNormalView } from '../../accessors/NormalNode.js';
+import { positionViewDirection } from '../../accessors/PositionNode.js';
+import { ShaderNode, vec2, vec4 } from '../../shadernode/ShaderNode.js';
 
 // Analytical approximation of the DFG LUT, one half of the
 // split-sum approximation used in indirect specular lighting.
@@ -16,7 +16,9 @@ const DFGApprox = new ShaderNode( ( inputs ) => {
 
 	const r = roughness.mul( c0 ).add( c1 );
 
-	const a004 = min( mul( r.x, r.x ), dotNV.mul( - 9.28 ).exp2() ).mul( r.x ).add( r.y );
+	const dotNV = transformedNormalView.dot( positionViewDirection ).clamp();
+
+	const a004 = r.x.mul( r.x ).min( dotNV.mul( - 9.28 ).exp2() ).mul( r.x ).add( r.y );
 
 	const fab = vec2( - 1.04, 1.04 ).mul( a004 ).add( r.zw );
 

+ 4 - 4
examples/jsm/nodes/functions/BSDF/D_GGX.js

@@ -1,4 +1,4 @@
-import { ShaderNode, add, sub, mul, div, pow2 } from '../../shadernode/ShaderNodeBaseElements.js';
+import { ShaderNode } from '../../shadernode/ShaderNode.js';
 
 // Microfacet Models for Refraction through Rough Surfaces - equation (33)
 // http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
@@ -7,11 +7,11 @@ const D_GGX = new ShaderNode( ( inputs ) => {
 
 	const { alpha, dotNH } = inputs;
 
-	const a2 = pow2( alpha );
+	const a2 = alpha.pow2();
 
-	const denom = add( mul( pow2( dotNH ), sub( a2, 1.0 ) ), 1.0 ); // avoid alpha = 0 with dotNH = 1
+	const denom = dotNH.pow2().mul( a2.invert() ).invert(); // avoid alpha = 0 with dotNH = 1
 
-	return mul( 1 / Math.PI, div( a2, pow2( denom ) ) );
+	return a2.div( denom.pow2() ).mul( 1 / Math.PI );
 
 } ); // validated
 

+ 2 - 2
examples/jsm/nodes/functions/BSDF/F_Schlick.js

@@ -1,4 +1,4 @@
-import { ShaderNode, sub } from '../../shadernode/ShaderNodeBaseElements.js';
+import { ShaderNode } from '../../shadernode/ShaderNode.js';
 
 const F_Schlick = new ShaderNode( ( inputs ) => {
 
@@ -11,7 +11,7 @@ const F_Schlick = new ShaderNode( ( inputs ) => {
 	// https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf
 	const fresnel = dotVH.mul( - 5.55473 ).sub( 6.98316 ).mul( dotVH ).exp2();
 
-	return f0.mul( sub( 1.0, fresnel ) ).add( f90.mul( fresnel ) );
+	return f0.mul( fresnel.invert() ).add( f90.mul( fresnel ) );
 
 } ); // validated
 

+ 7 - 5
examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated.js

@@ -1,4 +1,6 @@
-import { ShaderNode, add, sub, mul, div, pow2, max, sqrt, EPSILON } from '../../shadernode/ShaderNodeBaseElements.js';
+import { div } from '../../math/OperatorNode.js';
+import { EPSILON } from '../../math/MathNode.js';
+import { ShaderNode } from '../../shadernode/ShaderNode.js';
 
 // Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2
 // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
@@ -6,12 +8,12 @@ const V_GGX_SmithCorrelated = new ShaderNode( ( inputs ) => {
 
 	const { alpha, dotNL, dotNV } = inputs;
 
-	const a2 = pow2( alpha );
+	const a2 = alpha.pow2();
 
-	const gv = mul( dotNL, sqrt( add( a2, mul( sub( 1.0, a2 ), pow2( dotNV ) ) ) ) );
-	const gl = mul( dotNV, sqrt( add( a2, mul( sub( 1.0, a2 ), pow2( dotNL ) ) ) ) );
+	const gv = dotNL.mul( a2.add( a2.invert().mul( dotNV.pow2() ) ).sqrt() );
+	const gl = dotNV.mul( a2.add( a2.invert().mul( dotNL.pow2() ) ).sqrt() );
 
-	return div( 0.5, max( add( gv, gl ), EPSILON ) );
+	return div( 0.5, gv.add( gl ).max( EPSILON ) );
 
 } ); // validated
 

+ 10 - 11
examples/jsm/nodes/functions/PhongLightingModel.js

@@ -1,26 +1,25 @@
 import BRDF_Lambert from './BSDF/BRDF_Lambert.js';
 import BRDF_BlinnPhong from './BSDF/BRDF_BlinnPhong.js';
-
-import {
-	ShaderNode,
-	mul, clamp, dot, transformedNormalView,
-	diffuseColor, materialReflectivity, lightingModel
-} from '../shadernode/ShaderNodeElements.js';
+import { lightingModel } from '../core/LightingModel.js';
+import { diffuseColor } from '../core/PropertyNode.js';
+import { materialReflectivity } from '../accessors/MaterialNode.js';
+import { transformedNormalView } from '../accessors/NormalNode.js';
+import { ShaderNode } from '../shadernode/ShaderNode.js';
 
 const RE_Direct_BlinnPhong = new ShaderNode( ( { lightDirection, lightColor, reflectedLight } ) => {
 
-	const dotNL = clamp( dot( transformedNormalView, lightDirection ) );
-	const irradiance = mul( dotNL, lightColor );
+	const dotNL = transformedNormalView.dot( lightDirection ).clamp();
+	const irradiance = dotNL.mul( lightColor );
 
-	reflectedLight.directDiffuse.add( mul( irradiance, BRDF_Lambert.call( { diffuseColor: diffuseColor.rgb } ) ) );
+	reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert.call( { diffuseColor: diffuseColor.rgb } ) ) );
 
-	reflectedLight.directSpecular.add( irradiance.mul( BRDF_BlinnPhong.call( { lightDirection } ) ).mul( materialReflectivity ) );
+	reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_BlinnPhong.call( { lightDirection } ) ).mul( materialReflectivity ) );
 
 } );
 
 const RE_IndirectDiffuse_BlinnPhong = new ShaderNode( ( { irradiance, reflectedLight } ) => {
 
-	reflectedLight.indirectDiffuse.add( irradiance.mul( BRDF_Lambert.call( { diffuseColor } ) ) );
+	reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert.call( { diffuseColor } ) ) );
 
 } );
 

+ 31 - 29
examples/jsm/nodes/functions/PhysicalLightingModel.js

@@ -1,30 +1,30 @@
 import BRDF_Lambert from './BSDF/BRDF_Lambert.js';
 import BRDF_GGX from './BSDF/BRDF_GGX.js';
 import DFGApprox from './BSDF/DFGApprox.js';
-import {
-	ShaderNode,
-	vec3, mul, clamp, add, sub, dot, div, transformedNormalView,
-	pow, exp2, dotNV,
-	diffuseColor, specularColor, roughness, temp, lightingModel
-} from '../shadernode/ShaderNodeElements.js';
+import { lightingModel } from '../core/LightingModel.js';
+import { temp } from '../core/VarNode.js';
+import { diffuseColor, specularColor, roughness } from '../core/PropertyNode.js';
+import { transformedNormalView } from '../accessors/NormalNode.js';
+import { positionViewDirection } from '../accessors/PositionNode.js';
+import { ShaderNode, float, vec3 } from '../shadernode/ShaderNode.js';
 
 // Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting"
 // Approximates multiscattering in order to preserve energy.
 // http://www.jcgt.org/published/0008/01/03/
-const computeMultiscattering = ( singleScatter, multiScatter, specularF90 = 1 ) => {
+const computeMultiscattering = ( singleScatter, multiScatter, specularF90 = float( 1 ) ) => {
 
 	const fab = DFGApprox.call( { roughness } );
 
-	const FssEss = add( mul( specularColor, fab.x ), mul( specularF90, fab.y ) );
+	const FssEss = specularColor.mul( fab.x ).add( specularF90.mul( fab.y ) );
 
-	const Ess = add( fab.x, fab.y );
-	const Ems = sub( 1.0, Ess );
+	const Ess = fab.x.add( fab.y );
+	const Ems = Ess.invert();
 
-	const Favg = add( specularColor, mul( sub( 1.0, specularColor ), 0.047619 ) ); // 1/21
-	const Fms = div( mul( FssEss, Favg ), sub( 1.0, mul( Ems, Favg ) ) );
+	const Favg = specularColor.add( specularColor.invert().mul( 0.047619 ) ); // 1/21
+	const Fms = FssEss.mul( Favg ).div( Ems.mul( Favg ).invert() );
 
-	singleScatter.add( FssEss );
-	multiScatter.add( mul( Fms, Ems ) );
+	singleScatter.addAssign( FssEss );
+	multiScatter.addAssign( Fms.mul( Ems ) );
 
 };
 
@@ -36,16 +36,16 @@ const RE_IndirectSpecular_Physical = new ShaderNode( ( inputs ) => {
 
 	const singleScattering = temp( vec3() );
 	const multiScattering = temp( vec3() );
-	const cosineWeightedIrradiance = mul( iblIrradiance, 1 / Math.PI );
+	const cosineWeightedIrradiance = iblIrradiance.mul( 1 / Math.PI );
 
 	computeMultiscattering( singleScattering, multiScattering );
 
-	const diffuse = mul( diffuseColor, sub( 1.0, add( singleScattering, multiScattering ) ) );
+	const diffuse = diffuseColor.mul( singleScattering.add( multiScattering ).invert() );
 
-	reflectedLight.indirectSpecular.add( mul( radiance, singleScattering ) );
-	reflectedLight.indirectSpecular.add( mul( multiScattering, cosineWeightedIrradiance ) );
+	reflectedLight.indirectSpecular.addAssign( radiance.mul( singleScattering ) );
+	reflectedLight.indirectSpecular.addAssign( multiScattering.mul( cosineWeightedIrradiance ) );
 
-	reflectedLight.indirectDiffuse.add( mul( diffuse, cosineWeightedIrradiance ) );
+	reflectedLight.indirectDiffuse.addAssign( diffuse.mul( cosineWeightedIrradiance ) );
 
 } );
 
@@ -53,7 +53,7 @@ const RE_IndirectDiffuse_Physical = new ShaderNode( ( inputs ) => {
 
 	const { irradiance, reflectedLight } = inputs;
 
-	reflectedLight.indirectDiffuse.add( mul( irradiance, BRDF_Lambert.call( { diffuseColor } ) ) );
+	reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert.call( { diffuseColor } ) ) );
 
 } );
 
@@ -61,25 +61,27 @@ const RE_Direct_Physical = new ShaderNode( ( inputs ) => {
 
 	const { lightDirection, lightColor, reflectedLight } = inputs;
 
-	const dotNL = clamp( dot( transformedNormalView, lightDirection ) );
-	const irradiance = mul( dotNL, lightColor );
+	const dotNL = transformedNormalView.dot( lightDirection ).clamp();
+	const irradiance = dotNL.mul( lightColor );
 
-	reflectedLight.directDiffuse.add( mul( irradiance, BRDF_Lambert.call( { diffuseColor: diffuseColor.rgb } ) ) );
+	reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert.call( { diffuseColor: diffuseColor.rgb } ) ) );
 
-	reflectedLight.directSpecular.add( mul( irradiance, BRDF_GGX.call( { lightDirection, f0: specularColor, f90: 1, roughness } ) ) );
+	reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX.call( { lightDirection, f0: specularColor, f90: 1, roughness } ) ) );
 
 } );
 
 const RE_AmbientOcclusion_Physical = new ShaderNode( ( { ambientOcclusion, reflectedLight } ) => {
 
-	const aoNV = add( dotNV, ambientOcclusion );
-	const aoExp = exp2( sub( mul( - 16.0, roughness ), 1.0 ) );
+	const dotNV = transformedNormalView.dot( positionViewDirection ).clamp();
 
-	const aoNode = clamp( add( sub( pow( aoNV, aoExp ), 1.0 ), ambientOcclusion ) );
+	const aoNV = dotNV.add( ambientOcclusion );
+	const aoExp = roughness.mul( - 16.0 ).invert().negate().exp2();
 
-	reflectedLight.indirectDiffuse.mul( ambientOcclusion );
+	const aoNode = ambientOcclusion.sub( aoNV.pow( aoExp ).invert() ).clamp();
 
-	reflectedLight.indirectSpecular.mul( aoNode );
+	reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion );
+
+	reflectedLight.indirectSpecular.mulAssign( aoNode );
 
 
 } );

+ 4 - 7
examples/jsm/nodes/functions/light/getDistanceAttenuation.js

@@ -1,6 +1,4 @@
-import {
-	ShaderNode, div, max, sub, mul, clamp, pow, pow2, pow4, cond, greaterThan
-} from '../../shadernode/ShaderNodeBaseElements.js';
+import { ShaderNode } from '../../shadernode/ShaderNode.js';
 
 const getDistanceAttenuation = new ShaderNode( ( inputs ) => {
 
@@ -9,11 +7,10 @@ const getDistanceAttenuation = new ShaderNode( ( inputs ) => {
 	// based upon Frostbite 3 Moving to Physically-based Rendering
 	// page 32, equation 26: E[window1]
 	// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
-	const distanceFalloff = div( 1.0, max( pow( lightDistance, decayExponent ), 0.01 ) );
+	const distanceFalloff = lightDistance.pow( decayExponent ).max( 0.01 ).reciprocal();
 
-	return cond(
-		greaterThan( cutoffDistance, 0 ),
-		mul( distanceFalloff, pow2( clamp( sub( 1.0, pow4( div( lightDistance, cutoffDistance ) ) ) ) ) ),
+	return cutoffDistance.greaterThan( 0 ).cond(
+		distanceFalloff.mul( lightDistance.div( cutoffDistance ).pow4().invert().clamp().pow2() ),
 		distanceFalloff
 	);
 

+ 4 - 3
examples/jsm/nodes/functions/material/getGeometryRoughness.js

@@ -1,9 +1,10 @@
-import { ShaderNode, max, abs, dFdx, dFdy, normalGeometry } from '../../shadernode/ShaderNodeBaseElements.js';
+import { normalGeometry } from '../../accessors/NormalNode.js';
+import { ShaderNode } from '../../shadernode/ShaderNode.js';
 
 const getGeometryRoughness = new ShaderNode( () => {
 
-	const dxy = max( abs( dFdx( normalGeometry ) ), abs( dFdy( normalGeometry ) ) );
-	const geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );
+	const dxy = normalGeometry.dFdx().abs().max( normalGeometry.dFdy().abs() );
+	const geometryRoughness = dxy.x.max( dxy.y ).max( dxy.z );
 
 	return geometryRoughness;
 

+ 4 - 4
examples/jsm/nodes/functions/material/getRoughness.js

@@ -1,5 +1,5 @@
 import getGeometryRoughness from './getGeometryRoughness.js';
-import { ShaderNode, add, max, min } from '../../shadernode/ShaderNodeBaseElements.js';
+import { ShaderNode } from '../../shadernode/ShaderNode.js';
 
 const getRoughness = new ShaderNode( ( inputs ) => {
 
@@ -7,9 +7,9 @@ const getRoughness = new ShaderNode( ( inputs ) => {
 
 	const geometryRoughness = getGeometryRoughness.call();
 
-	let roughnessFactor = max( roughness, 0.0525 ); // 0.0525 corresponds to the base mip of a 256 cubemap.
-	roughnessFactor = add( roughnessFactor, geometryRoughness );
-	roughnessFactor = min( roughnessFactor, 1.0 );
+	let roughnessFactor = roughness.max( 0.0525 ); // 0.0525 corresponds to the base mip of a 256 cubemap.
+	roughnessFactor = roughnessFactor.add( geometryRoughness );
+	roughnessFactor = roughnessFactor.min( 1.0 );
 
 	return roughnessFactor;
 

+ 10 - 5
examples/jsm/nodes/geometry/RangeNode.js

@@ -1,5 +1,7 @@
-import Node from '../core/Node.js';
-import { attribute, float } from '../shadernode/ShaderNodeBaseElements.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { attribute } from '../core/AttributeNode.js';
+import { nodeObject, float } from '../shadernode/ShaderNode.js';
+
 import { MathUtils, InstancedBufferAttribute } from 'three';
 
 class RangeNode extends Node {
@@ -20,9 +22,8 @@ class RangeNode extends Node {
 		let length = 1;
 
 		if ( min.isVector2 ) length = 2;
-		else if ( min.isVector3 ) length = 3;
+		else if ( min.isVector3 || min.isColor ) length = 3;
 		else if ( min.isVector4 ) length = 4;
-		else if ( min.isColor ) length = 3;
 
 		return length;
 
@@ -30,7 +31,7 @@ class RangeNode extends Node {
 
 	getNodeType( builder ) {
 
-		return ( builder.object.isInstancedMesh === true ) ? builder.getTypeFromLength( this.getVectorLength() ) : 'float';
+		return builder.object.isInstancedMesh === true ? builder.getTypeFromLength( this.getVectorLength() ) : 'float';
 
 	}
 
@@ -107,3 +108,7 @@ class RangeNode extends Node {
 }
 
 export default RangeNode;
+
+export const range = ( min, max ) => nodeObject( new RangeNode( min, max ) );
+
+addNodeClass( RangeNode );

+ 8 - 1
examples/jsm/nodes/gpgpu/ComputeNode.js

@@ -1,5 +1,6 @@
-import Node from '../core/Node.js';
+import Node, { addNodeClass } from '../core/Node.js';
 import { NodeUpdateType } from '../core/constants.js';
+import { addNodeElement, nodeObject } from '../shadernode/ShaderNode.js';
 
 class ComputeNode extends Node {
 
@@ -63,3 +64,9 @@ class ComputeNode extends Node {
 }
 
 export default ComputeNode;
+
+export const compute = ( node, count, workgroupSize ) => nodeObject( new ComputeNode( nodeObject( node ), count, workgroupSize ) );
+
+addNodeElement( 'compute', compute );
+
+addNodeClass( ComputeNode );

+ 5 - 3
examples/jsm/nodes/lighting/AONode.js

@@ -1,5 +1,5 @@
 import LightingNode from './LightingNode.js';
-import { float, add, mul, sub } from '../shadernode/ShaderNodeElements.js';
+import { addNodeClass } from '../core/Node.js';
 
 class AONode extends LightingNode {
 
@@ -14,12 +14,14 @@ class AONode extends LightingNode {
 	construct( builder ) {
 
 		const aoIntensity = 1;
-		const aoNode = add( mul( sub( float( this.aoNode ), 1.0 ), aoIntensity ), 1.0 );
+		const aoNode = this.aoNode.sub( 1.0 ).mul( aoIntensity ).add( 1.0 );
 
-		builder.context.ambientOcclusion.mul( aoNode );
+		builder.context.ambientOcclusion.mulAssign( aoNode );
 
 	}
 
 }
 
 export default AONode;
+
+addNodeClass( AONode );

+ 7 - 4
examples/jsm/nodes/lighting/AmbientLightNode.js

@@ -1,5 +1,6 @@
 import AnalyticLightNode from './AnalyticLightNode.js';
-import LightsNode from './LightsNode.js';
+import { addLightNode } from './LightsNode.js';
+import { addNodeClass } from '../core/Node.js';
 
 import { AmbientLight } from 'three';
 
@@ -13,12 +14,14 @@ class AmbientLightNode extends AnalyticLightNode {
 
 	construct( { context } ) {
 
-		context.irradiance.add( this.colorNode );
+		context.irradiance.addAssign( this.colorNode );
 
 	}
 
 }
 
-LightsNode.setReference( AmbientLight, AmbientLightNode );
-
 export default AmbientLightNode;
+
+addLightNode( AmbientLight, AmbientLightNode );
+
+addNodeClass( AmbientLightNode );

+ 4 - 1
examples/jsm/nodes/lighting/AnalyticLightNode.js

@@ -1,6 +1,7 @@
 import LightingNode from './LightingNode.js';
 import { NodeUpdateType } from '../core/constants.js';
-import { uniform } from '../shadernode/ShaderNodeElements.js';
+import { uniform } from '../core/UniformNode.js';
+import { addNodeClass } from '../core/Node.js';
 
 import { Color } from 'three';
 
@@ -35,3 +36,5 @@ class AnalyticLightNode extends LightingNode {
 }
 
 export default AnalyticLightNode;
+
+addNodeClass( AnalyticLightNode );

+ 7 - 4
examples/jsm/nodes/lighting/DirectionalLightNode.js

@@ -1,7 +1,8 @@
 import AnalyticLightNode from './AnalyticLightNode.js';
-import LightsNode from './LightsNode.js';
+import { addLightNode } from './LightsNode.js';
 import getDirectionVector from '../functions/light/getDirectionVector.js';
-import { uniform } from '../shadernode/ShaderNodeElements.js';
+import { uniform } from '../core/UniformNode.js';
+import { addNodeClass } from '../core/Node.js';
 
 import { Vector3, DirectionalLight } from 'three';
 
@@ -45,6 +46,8 @@ class DirectionalLightNode extends AnalyticLightNode {
 
 }
 
-LightsNode.setReference( DirectionalLight, DirectionalLightNode );
-
 export default DirectionalLightNode;
+
+addLightNode( DirectionalLight, DirectionalLightNode );
+
+addNodeClass( DirectionalLightNode );

+ 19 - 11
examples/jsm/nodes/lighting/EnvironmentNode.js

@@ -1,8 +1,14 @@
 import LightingNode from './LightingNode.js';
-import ContextNode from '../core/ContextNode.js';
-import CacheNode from '../core/CacheNode.js';
-import SpecularMIPLevelNode from '../utils/SpecularMIPLevelNode.js';
-import { float, mul, roughness, positionViewDirection, transformedNormalView, transformedNormalWorld, cameraViewMatrix, equirectUV, vec2 } from '../shadernode/ShaderNodeElements.js';
+import { cache } from '../core/CacheNode.js';
+import { context } from '../core/ContextNode.js';
+import { roughness } from '../core/PropertyNode.js';
+import { equirectUV } from '../utils/EquirectUVNode.js';
+import { specularMIPLevel } from '../utils/SpecularMIPLevelNode.js';
+import { cameraViewMatrix } from '../accessors/CameraNode.js';
+import { transformedNormalView, transformedNormalWorld } from '../accessors/NormalNode.js';
+import { positionViewDirection } from '../accessors/PositionNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { float, vec2 } from '../shadernode/ShaderNode.js';
 
 class EnvironmentNode extends LightingNode {
 
@@ -23,7 +29,7 @@ class EnvironmentNode extends LightingNode {
 		let radianceTextureUVNode;
 		let irradianceTextureUVNode;
 
-		const radianceContext = new ContextNode( envNode, {
+		const radianceContext = context( envNode, {
 			getUVNode: ( textureNode ) => {
 
 				let node = null;
@@ -65,12 +71,12 @@ class EnvironmentNode extends LightingNode {
 			},
 			getMIPLevelAlgorithmNode: ( textureNode, levelNode ) => {
 
-				return new SpecularMIPLevelNode( textureNode, levelNode );
+				return specularMIPLevel( textureNode, levelNode );
 
 			}
 		} );
 
-		const irradianceContext = new ContextNode( envNode, {
+		const irradianceContext = context( envNode, {
 			getUVNode: ( textureNode ) => {
 
 				let node = null;
@@ -104,20 +110,20 @@ class EnvironmentNode extends LightingNode {
 			},
 			getMIPLevelAlgorithmNode: ( textureNode, levelNode ) => {
 
-				return new SpecularMIPLevelNode( textureNode, levelNode );
+				return specularMIPLevel( textureNode, levelNode );
 
 			}
 		} );
 
 		//
 
-		const isolateRadianceFlowContext = new CacheNode( radianceContext );
+		const isolateRadianceFlowContext = cache( radianceContext );
 
 		//
 
-		builder.context.radiance.add( isolateRadianceFlowContext );
+		builder.context.radiance.addAssign( isolateRadianceFlowContext );
 
-		builder.context.iblIrradiance.add( mul( Math.PI, irradianceContext ) );
+		builder.context.iblIrradiance.addAssign( irradianceContext.mul( Math.PI ) );
 
 		properties.radianceContext = isolateRadianceFlowContext;
 		properties.irradianceContext = irradianceContext;
@@ -127,3 +133,5 @@ class EnvironmentNode extends LightingNode {
 }
 
 export default EnvironmentNode;
+
+addNodeClass( EnvironmentNode );

+ 15 - 10
examples/jsm/nodes/lighting/HemisphereLightNode.js

@@ -1,7 +1,10 @@
 import AnalyticLightNode from './AnalyticLightNode.js';
-import LightsNode from './LightsNode.js';
-import Object3DNode from '../accessors/Object3DNode.js';
-import { uniform, add, mul, dot, mix, normalize, normalView } from '../shadernode/ShaderNodeElements.js';
+import { addLightNode } from './LightsNode.js';
+import { uniform } from '../core/UniformNode.js';
+import { mix } from '../math/MathNode.js';
+import { normalView } from '../accessors/NormalNode.js';
+import { objectPosition } from '../accessors/Object3DNode.js';
+import { addNodeClass } from '../core/Node.js';
 
 import { Color, HemisphereLight } from 'three';
 
@@ -11,8 +14,8 @@ class HemisphereLightNode extends AnalyticLightNode {
 
 		super( light );
 
-		this.lightPositionNode = new Object3DNode( Object3DNode.POSITION );
-		this.lightDirectionNode = normalize( this.lightPositionNode );
+		this.lightPositionNode = objectPosition;
+		this.lightDirectionNode = objectPosition.normalize();
 
 		this.groundColorNode = uniform( new Color() );
 
@@ -34,17 +37,19 @@ class HemisphereLightNode extends AnalyticLightNode {
 
 		const { colorNode, groundColorNode, lightDirectionNode } = this;
 
-		const dotNL = dot( normalView, lightDirectionNode );
-		const hemiDiffuseWeight = add( mul( 0.5, dotNL ), 0.5 );
+		const dotNL = normalView.dot( lightDirectionNode );
+		const hemiDiffuseWeight = dotNL.mul( 0.5 ).add( 0.5 );
 
 		const irradiance = mix( groundColorNode, colorNode, hemiDiffuseWeight );
 
-		builder.context.irradiance.add( irradiance );
+		builder.context.irradiance.addAssign( irradiance );
 
 	}
 
 }
 
-LightsNode.setReference( HemisphereLight, HemisphereLightNode );
-
 export default HemisphereLightNode;
+
+addLightNode( HemisphereLight, HemisphereLightNode );
+
+addNodeClass( HemisphereLightNode );

+ 9 - 5
examples/jsm/nodes/lighting/IESSpotLightNode.js

@@ -1,6 +1,8 @@
 import SpotLightNode from './SpotLightNode.js';
-import LightsNode from './LightsNode.js';
-import { acos, texture, vec2 } from '../shadernode/ShaderNodeElements.js';
+import { addLightNode } from './LightsNode.js';
+import { texture } from '../accessors/TextureNode.js';
+import { vec2 } from '../shadernode/ShaderNode.js';
+import { addNodeClass } from '../core/Node.js';
 
 import IESSpotLight from '../../lights/IESSpotLight.js';
 
@@ -14,7 +16,7 @@ class IESSpotLightNode extends SpotLightNode {
 
 		if ( iesMap && iesMap.isTexture === true ) {
 
-			const angle = acos( angleCosine ).mul( 1.0 / Math.PI );
+			const angle = angleCosine.acos().mul( 1.0 / Math.PI );
 
 			spotAttenuation = texture( iesMap, vec2( angle, 0 ), 0 ).r;
 
@@ -30,6 +32,8 @@ class IESSpotLightNode extends SpotLightNode {
 
 }
 
-LightsNode.setReference( IESSpotLight, IESSpotLightNode );
-
 export default IESSpotLightNode;
+
+addLightNode( IESSpotLight, IESSpotLightNode );
+
+addNodeClass( IESSpotLightNode );

+ 10 - 1
examples/jsm/nodes/lighting/LightingContextNode.js

@@ -1,5 +1,8 @@
 import ContextNode from '../core/ContextNode.js';
-import { float, vec3, add, temp } from '../shadernode/ShaderNodeBaseElements.js';
+import { temp } from '../core/VarNode.js';
+import { add } from '../math/OperatorNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { addNodeElement, nodeProxy, float, vec3 } from '../shadernode/ShaderNode.js';
 
 class LightingContextNode extends ContextNode {
 
@@ -73,3 +76,9 @@ class LightingContextNode extends ContextNode {
 }
 
 export default LightingContextNode;
+
+export const lightingContext = nodeProxy( LightingContextNode );
+
+addNodeElement( 'lightingContext', lightingContext );
+
+addNodeClass( LightingContextNode );

+ 3 - 1
examples/jsm/nodes/lighting/LightingNode.js

@@ -1,4 +1,4 @@
-import Node from '../core/Node.js';
+import Node, { addNodeClass } from '../core/Node.js';
 
 class LightingNode extends Node {
 
@@ -17,3 +17,5 @@ class LightingNode extends Node {
 }
 
 export default LightingNode;
+
+addNodeClass( LightingNode );

+ 16 - 8
examples/jsm/nodes/lighting/LightsNode.js

@@ -1,7 +1,8 @@
 import Node from '../core/Node.js';
 import AnalyticLightNode from './AnalyticLightNode.js';
+import { nodeObject, nodeProxy } from '../shadernode/ShaderNode.js';
 
-const references = new WeakMap();
+const LightNodes = new WeakMap();
 
 const sortLights = ( lights ) => {
 
@@ -92,9 +93,9 @@ class LightsNode extends Node {
 			if ( lightNode === null ) {
 
 				const lightClass = light.constructor;
-				const lightNodeClass = references.has( lightClass ) ? references.get( lightClass ) : AnalyticLightNode;
+				const lightNodeClass = LightNodes.has( lightClass ) ? LightNodes.get( lightClass ) : AnalyticLightNode;
 
-				lightNode = new lightNodeClass( light );
+				lightNode = nodeObject( new lightNodeClass( light ) );
 
 			}
 
@@ -109,12 +110,19 @@ class LightsNode extends Node {
 
 	}
 
-	static setReference( lightClass, lightNodeClass ) {
+}
 
-		references.set( lightClass, lightNodeClass );
+export default LightsNode;
 
-	}
+export const lights = ( lights ) => nodeObject( new LightsNode().fromLights( lights ) );
+export const lightsWithoutWrap = nodeProxy( LightsNode );
 
-}
+export function addLightNode( lightClass, lightNodeClass ) {
 
-export default LightsNode;
+	if ( LightNodes.has( lightClass ) ) throw new Error( `Redefinition of light node ${ lightNodeClass.name }` );
+	if ( typeof lightClass !== 'function' || ! lightClass.name ) throw new Error( `Light ${ lightClass.name } is not a class` );
+	if ( typeof lightNodeClass !== 'function' || ! lightNodeClass.name ) throw new Error( `Light node ${ lightNodeClass.name } is not a class` );
+
+	LightNodes.set( lightClass, lightNodeClass );
+
+}

+ 9 - 4
examples/jsm/nodes/lighting/PointLightNode.js

@@ -1,7 +1,10 @@
 import AnalyticLightNode from './AnalyticLightNode.js';
-import LightsNode from './LightsNode.js';
+import { addLightNode } from './LightsNode.js';
 import getDistanceAttenuation from '../functions/light/getDistanceAttenuation.js';
-import { uniform, positionView, objectViewPosition } from '../shadernode/ShaderNodeElements.js';
+import { uniform } from '../core/UniformNode.js';
+import { objectViewPosition } from '../accessors/Object3DNode.js';
+import { positionView } from '../accessors/PositionNode.js';
+import { addNodeClass } from '../core/Node.js';
 
 import { PointLight } from 'three';
 
@@ -61,6 +64,8 @@ class PointLightNode extends AnalyticLightNode {
 
 }
 
-LightsNode.setReference( PointLight, PointLightNode );
-
 export default PointLightNode;
+
+addLightNode( PointLight, PointLightNode );
+
+addNodeClass( PointLightNode );

+ 10 - 4
examples/jsm/nodes/lighting/SpotLightNode.js

@@ -1,8 +1,12 @@
 import AnalyticLightNode from './AnalyticLightNode.js';
-import LightsNode from './LightsNode.js';
+import { addLightNode } from './LightsNode.js';
 import getDistanceAttenuation from '../functions/light/getDistanceAttenuation.js';
 import getDirectionVector from '../functions/light/getDirectionVector.js';
-import { uniform, smoothstep, positionView, objectViewPosition } from '../shadernode/ShaderNodeElements.js';
+import { uniform } from '../core/UniformNode.js';
+import { smoothstep } from '../math/MathNode.js';
+import { objectViewPosition } from '../accessors/Object3DNode.js';
+import { positionView } from '../accessors/PositionNode.js';
+import { addNodeClass } from '../core/Node.js';
 
 import { Vector3, SpotLight } from 'three';
 
@@ -85,6 +89,8 @@ class SpotLightNode extends AnalyticLightNode {
 
 }
 
-LightsNode.setReference( SpotLight, SpotLightNode );
-
 export default SpotLightNode;
+
+addLightNode( SpotLight, SpotLightNode );
+
+addNodeClass( SpotLightNode );

+ 4 - 3
examples/jsm/nodes/loaders/NodeLoader.js

@@ -1,4 +1,5 @@
-import * as Nodes from '../Nodes.js';
+import { createNodeFromType } from '../core/Node.js';
+import { nodeObject } from '../shadernode/ShaderNode.js';
 import { FileLoader, Loader } from 'three';
 
 class NodeLoader extends Loader {
@@ -53,7 +54,7 @@ class NodeLoader extends Loader {
 
 				const { uuid, type } = nodeJSON;
 
-				nodes[ uuid ] = Nodes.fromType( type );
+				nodes[ uuid ] = nodeObject( createNodeFromType( type ) ); // @TODO: Maybe nodeObjectify the node in createNodeFromType?
 				nodes[ uuid ].uuid = uuid;
 
 			}
@@ -79,7 +80,7 @@ class NodeLoader extends Loader {
 
 	parse( json ) {
 
-		const node = Nodes.fromType( json.type );
+		const node = nodeObject( createNodeFromType( type ) );
 		node.uuid = json.uuid;
 
 		const nodes = this.parseNodes( json.inputNodes );

+ 4 - 20
examples/jsm/nodes/loaders/NodeMaterialLoader.js

@@ -1,31 +1,15 @@
 import { MaterialLoader } from 'three';
-import {
-	NodeMaterial,
-	LineBasicNodeMaterial,
-	MeshBasicNodeMaterial,
-	MeshStandardNodeMaterial,
-	MeshPhysicalNodeMaterial,
-	PointsNodeMaterial,
-	SpriteNodeMaterial
-} from '../materials/Materials.js';
+import { createNodeMaterialFromType } from '../materials/Materials.js';
 
 const superFromTypeFunction = MaterialLoader.createMaterialFromType;
 
 MaterialLoader.createMaterialFromType = function ( type ) {
 
-	const materialLib = {
-		NodeMaterial,
-		LineBasicNodeMaterial,
-		MeshBasicNodeMaterial,
-		MeshStandardNodeMaterial,
-		MeshPhysicalNodeMaterial,
-		PointsNodeMaterial,
-		SpriteNodeMaterial
-	};
+	const material = createNodeMaterialFromType( type )
 
-	if ( materialLib[ type ] !== undefined ) {
+	if ( material !== undefined ) {
 
-		return new materialLib[ type ]();
+		return material;
 
 	}
 

+ 4 - 1
examples/jsm/nodes/materials/LineBasicNodeMaterial.js

@@ -1,4 +1,5 @@
-import NodeMaterial from './NodeMaterial.js';
+import NodeMaterial, { addNodeMaterial } from './NodeMaterial.js';
+
 import { LineBasicMaterial } from 'three';
 
 const defaultValues = new LineBasicMaterial();
@@ -47,3 +48,5 @@ class LineBasicNodeMaterial extends NodeMaterial {
 }
 
 export default LineBasicNodeMaterial;
+
+addNodeMaterial( LineBasicNodeMaterial );

+ 11 - 61
examples/jsm/nodes/materials/Materials.js

@@ -1,61 +1,11 @@
-import NodeMaterial from './NodeMaterial.js';
-import LineBasicNodeMaterial from './LineBasicNodeMaterial.js';
-import MeshNormalNodeMaterial from './MeshNormalNodeMaterial.js';
-import MeshBasicNodeMaterial from './MeshBasicNodeMaterial.js';
-import MeshPhongNodeMaterial from './MeshPhongNodeMaterial.js';
-import MeshStandardNodeMaterial from './MeshStandardNodeMaterial.js';
-import MeshPhysicalNodeMaterial from './MeshPhysicalNodeMaterial.js';
-import PointsNodeMaterial from './PointsNodeMaterial.js';
-import SpriteNodeMaterial from './SpriteNodeMaterial.js';
-
-export {
-	NodeMaterial,
-	LineBasicNodeMaterial,
-	MeshNormalNodeMaterial,
-	MeshBasicNodeMaterial,
-	MeshPhongNodeMaterial,
-	MeshStandardNodeMaterial,
-	MeshPhysicalNodeMaterial,
-	PointsNodeMaterial,
-	SpriteNodeMaterial
-};
-
-NodeMaterial.fromMaterial = function ( material ) {
-
-	const materialLib = {
-		NodeMaterial,
-		LineBasicNodeMaterial,
-		MeshNormalNodeMaterial,
-		MeshBasicNodeMaterial,
-		MeshPhongNodeMaterial,
-		MeshStandardNodeMaterial,
-		MeshPhysicalNodeMaterial,
-		PointsNodeMaterial,
-		SpriteNodeMaterial
-	};
-
-	const type = material.type.replace( 'Material', 'NodeMaterial' );
-
-	if ( materialLib[ type ] === undefined ) {
-
-		if ( material.isNodeMaterial !== true ) {
-
-			throw new Error( `NodeMaterial: Material "${ material.type }" is not compatible.` );
-
-		}
-
-		return material; // is already a node material
-
-	}
-
-	const nodeMaterial = new materialLib[ type ]();
-
-	for ( const key in material ) {
-
-		nodeMaterial[ key ] = material[ key ];
-
-	}
-
-	return nodeMaterial;
-
-};
+// @TODO: We can simplify "export { default as SomeNode, other, exports } from '...'" to just "export * from '...'" if we will use only named exports
+
+export { default as NodeMaterial, addNodeMaterial, createNodeMaterialFromType } from './NodeMaterial.js';
+export { default as LineBasicNodeMaterial } from './LineBasicNodeMaterial.js';
+export { default as MeshNormalNodeMaterial } from './MeshNormalNodeMaterial.js';
+export { default as MeshBasicNodeMaterial } from './MeshBasicNodeMaterial.js';
+export { default as MeshPhongNodeMaterial } from './MeshPhongNodeMaterial.js';
+export { default as MeshStandardNodeMaterial } from './MeshStandardNodeMaterial.js';
+export { default as MeshPhysicalNodeMaterial } from './MeshPhysicalNodeMaterial.js';
+export { default as PointsNodeMaterial } from './PointsNodeMaterial.js';
+export { default as SpriteNodeMaterial } from './SpriteNodeMaterial.js';

+ 4 - 1
examples/jsm/nodes/materials/MeshBasicNodeMaterial.js

@@ -1,4 +1,5 @@
-import NodeMaterial from './NodeMaterial.js';
+import NodeMaterial, { addNodeMaterial } from './NodeMaterial.js';
+
 import { MeshBasicMaterial } from 'three';
 
 const defaultValues = new MeshBasicMaterial();
@@ -46,3 +47,5 @@ class MeshBasicNodeMaterial extends NodeMaterial {
 }
 
 export default MeshBasicNodeMaterial;
+
+addNodeMaterial( MeshBasicNodeMaterial );

+ 9 - 2
examples/jsm/nodes/materials/MeshNormalNodeMaterial.js

@@ -1,6 +1,11 @@
-import NodeMaterial from './NodeMaterial.js';
+import NodeMaterial, { addNodeMaterial } from './NodeMaterial.js';
+import { diffuseColor } from '../core/PropertyNode.js';
+import { directionToColor } from '../utils/PackingNode.js';
+import { materialOpacity } from '../accessors/MaterialNode.js';
+import { transformedNormalView } from '../accessors/NormalNode.js';
+import { float, vec4 } from '../shadernode/ShaderNode.js';
+
 import { MeshNormalMaterial } from 'three';
-import { vec4, diffuseColor, materialOpacity, transformedNormalView, directionToColor } from '../shadernode/ShaderNodeElements.js';
 
 const defaultValues = new MeshNormalMaterial();
 
@@ -43,3 +48,5 @@ class MeshNormalNodeMaterial extends NodeMaterial {
 }
 
 export default MeshNormalNodeMaterial;
+
+addNodeMaterial( MeshNormalNodeMaterial );

+ 8 - 8
examples/jsm/nodes/materials/MeshPhongNodeMaterial.js

@@ -1,10 +1,8 @@
-import NodeMaterial from './NodeMaterial.js';
-import {
-	float, vec3,
-	materialShininess, materialSpecularColor,
-	shininess, specularColor
-} from '../shadernode/ShaderNodeElements.js';
+import NodeMaterial, { addNodeMaterial } from './NodeMaterial.js';
+import { shininess, specularColor } from '../core/PropertyNode.js';
+import { materialShininess, materialSpecularColor } from '../accessors/MaterialNode.js';
 import phongLightingModel from '../functions/PhongLightingModel.js';
+import { float } from '../shadernode/ShaderNode.js';
 
 import { MeshPhongMaterial } from 'three';
 
@@ -48,13 +46,13 @@ class MeshPhongNodeMaterial extends NodeMaterial {
 
 		// SHININESS
 
-		const shininessNode = float( this.shininessNode || materialShininess ).max( 1e-4 ); // to prevent pow( 0.0, 0.0 )
+		const shininessNode = ( this.shininessNode ? float( this.shininessNode ) : materialShininess ).max( 1e-4 ); // to prevent pow( 0.0, 0.0 )
 
 		stack.assign( shininess, shininessNode );
 
 		// SPECULAR COLOR
 
-		const specularNode = vec3( this.specularNode || materialSpecularColor );
+		const specularNode = this.specularNode || materialSpecularColor;
 
 		stack.assign( specularColor, specularNode );
 
@@ -81,3 +79,5 @@ class MeshPhongNodeMaterial extends NodeMaterial {
 }
 
 export default MeshPhongNodeMaterial;
+
+addNodeMaterial( MeshPhongNodeMaterial );

+ 6 - 1
examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js

@@ -1,10 +1,11 @@
+import { addNodeMaterial } from './NodeMaterial.js';
 import MeshStandardNodeMaterial from './MeshStandardNodeMaterial.js';
 
 import { MeshPhysicalMaterial } from 'three';
 
 const defaultValues = new MeshPhysicalMaterial();
 
-export default class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial {
+class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial {
 
 	constructor( parameters ) {
 
@@ -68,3 +69,7 @@ export default class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial {
 	}
 
 }
+
+export default MeshPhysicalNodeMaterial;
+
+addNodeMaterial( MeshPhysicalNodeMaterial );

+ 10 - 7
examples/jsm/nodes/materials/MeshStandardNodeMaterial.js

@@ -1,17 +1,16 @@
-import NodeMaterial from './NodeMaterial.js';
-import {
-	float, vec3, vec4, mix,
-	materialRoughness, materialMetalness, materialColor, diffuseColor,
-	metalness, roughness, specularColor
-} from '../shadernode/ShaderNodeElements.js';
+import NodeMaterial, { addNodeMaterial } from './NodeMaterial.js';
+import { diffuseColor, metalness, roughness, specularColor } from '../core/PropertyNode.js';
+import { mix } from '../math/MathNode.js';
+import { materialRoughness, materialMetalness, materialColor } from '../accessors/MaterialNode.js';
 import getRoughness from '../functions/material/getRoughness.js';
 import physicalLightingModel from '../functions/PhysicalLightingModel.js';
+import { float, vec3, vec4 } from '../shadernode/ShaderNode.js';
 
 import { MeshStandardMaterial } from 'three';
 
 const defaultValues = new MeshStandardMaterial();
 
-export default class MeshStandardNodeMaterial extends NodeMaterial {
+class MeshStandardNodeMaterial extends NodeMaterial {
 
 	constructor( parameters ) {
 
@@ -98,3 +97,7 @@ export default class MeshStandardNodeMaterial extends NodeMaterial {
 	}
 
 }
+
+export default MeshStandardNodeMaterial;
+
+addNodeMaterial( MeshStandardNodeMaterial );

+ 87 - 30
examples/jsm/nodes/materials/NodeMaterial.js

@@ -1,17 +1,25 @@
 import { Material, ShaderMaterial, NoToneMapping } from 'three';
 import { getNodesKeys, getCacheKey } from '../core/NodeUtils.js';
-import StackNode from '../core/StackNode.js';
-import LightsNode from '../lighting/LightsNode.js';
-import EnvironmentNode from '../lighting/EnvironmentNode.js';
-import ToneMappingNode from '../display/ToneMappingNode.js';
+import { attribute } from '../core/AttributeNode.js';
+import { diffuseColor } from '../core/PropertyNode.js';
+import { materialNormal } from '../accessors/ExtendedMaterialNode.js';
+import { materialAlphaTest, materialColor, materialOpacity, materialEmissive } from '../accessors/MaterialNode.js';
+import { modelViewProjection } from '../accessors/ModelViewProjectionNode.js';
+import { transformedNormalView } from '../accessors/NormalNode.js';
+import { instance } from '../accessors/InstanceNode.js';
+import { positionLocal } from '../accessors/PositionNode.js';
+import { reference } from '../accessors/ReferenceNode.js';
+import { skinning } from '../accessors/SkinningNode.js';
+import { texture } from '../accessors/TextureNode.js';
+import { toneMapping } from '../display/ToneMappingNode.js';
+import { rangeFog } from '../fog/FogRangeNode.js';
+import { densityFog } from '../fog/FogExp2Node.js';
+import { lightsWithoutWrap } from '../lighting/LightsNode.js';
 import AONode from '../lighting/AONode.js';
-import {
-	float, vec3, vec4,
-	assign, mul, bypass, attribute, context, texture, lessThanEqual, discard,
-	positionLocal, diffuseColor, skinning, instance, modelViewProjection, lightingContext, colorSpace,
-	materialAlphaTest, materialColor, materialOpacity, materialEmissive, materialNormal, transformedNormalView,
-	reference, rangeFog, densityFog
-} from '../shadernode/ShaderNodeElements.js';
+import EnvironmentNode from '../lighting/EnvironmentNode.js';
+import { float, vec3, vec4 } from '../shadernode/ShaderNode.js';
+
+const NodeMaterials = new Map();
 
 class NodeMaterial extends ShaderMaterial {
 
@@ -46,8 +54,8 @@ class NodeMaterial extends ShaderMaterial {
 
 		// < STACKS >
 
-		const vertexStack = new StackNode();
-		const fragmentStack = new StackNode();
+		const vertexStack = builder.createStack();
+		const fragmentStack = builder.createStack();
 
 		// < VERTEX STAGE >
 
@@ -79,19 +87,19 @@ class NodeMaterial extends ShaderMaterial {
 
 		if ( this.positionNode !== null ) {
 
-			vertex = bypass( vertex, assign( positionLocal, this.positionNode ) );
+			vertex = vertex.bypass( positionLocal.assign( this.positionNode ) );
 
 		}
 
 		if ( ( object.instanceMatrix && object.instanceMatrix.isInstancedBufferAttribute === true ) && builder.isAvailable( 'instance' ) === true ) {
 
-			vertex = bypass( vertex, instance( object ) );
+			vertex = vertex.bypass( instance( object ) );
 
 		}
 
 		if ( object.isSkinnedMesh === true ) {
 
-			vertex = bypass( vertex, skinning( object ) );
+			vertex = vertex.bypass( skinning( object ) );
 
 		}
 
@@ -103,14 +111,13 @@ class NodeMaterial extends ShaderMaterial {
 
 	constructDiffuseColor( builder, stack ) {
 
-		let colorNode = vec4( this.colorNode || materialColor );
-		const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity;
+		let colorNode = this.colorNode ? vec4( this.colorNode ) : materialColor;
 
 		// VERTEX COLORS
 
 		if ( this.vertexColors === true && builder.geometry.hasAttribute( 'color' ) ) {
 
-			colorNode = vec4( mul( colorNode.xyz, attribute( 'color' ) ), colorNode.a );
+			colorNode = vec4( colorNode.xyz.mul( attribute( 'color' ) ), colorNode.a );
 
 		}
 
@@ -120,6 +127,7 @@ class NodeMaterial extends ShaderMaterial {
 
 		// OPACITY
 
+		const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity;
 		stack.assign( diffuseColor.a, diffuseColor.a.mul( opacityNode ) );
 
 		// ALPHA TEST
@@ -128,7 +136,7 @@ class NodeMaterial extends ShaderMaterial {
 
 			const alphaTestNode = this.alphaTestNode ? float( this.alphaTestNode ) : materialAlphaTest;
 
-			stack.add( discard( lessThanEqual( diffuseColor.a, alphaTestNode ) ) );
+			stack.add( diffuseColor.a.lessThanEqual( alphaTestNode ).discard() );
 
 		}
 
@@ -173,7 +181,7 @@ class NodeMaterial extends ShaderMaterial {
 
 		if ( materialLightsNode.length > 0 ) {
 
-			lightsNode = new LightsNode( [ ...lightsNode.lightNodes, ...materialLightsNode ] );
+			lightsNode = lightsWithoutWrap( [ ...lightsNode.lightNodes, ...materialLightsNode ] );
 
 		}
 
@@ -193,16 +201,16 @@ class NodeMaterial extends ShaderMaterial {
 
 		// OUTGOING LIGHT
 
-		const lights = ( this.lights === true ) || this.lightsNode !== null;
+		const lights = this.lights === true || this.lightsNode !== null;
 
 		const lightsNode = lights ? this.constructLights( builder ) : null;
 		const lightingModelNode = lightsNode ? this.constructLightingModel( builder ) : null;
 
-		let outgoingLightNode = diffuseColor.xyz;
+		let outgoingLightNode = diffuseColor.rgb;
 
 		if ( lightsNode && lightsNode.hasLight !== false ) {
 
-			outgoingLightNode = lightingContext( lightsNode, lightingModelNode );
+			outgoingLightNode = lightsNode.lightingContext( lightingModelNode );
 
 		}
 
@@ -210,7 +218,7 @@ class NodeMaterial extends ShaderMaterial {
 
 		if ( ( this.emissiveNode && this.emissiveNode.isNode === true ) || ( material.emissive && material.emissive.isColor === true ) ) {
 
-			outgoingLightNode = outgoingLightNode.add( vec3( this.emissiveNode || materialEmissive ) );
+			outgoingLightNode = outgoingLightNode.add( this.emissiveNode ? vec3( this.emissiveNode ) : materialEmissive );
 
 		}
 
@@ -228,13 +236,13 @@ class NodeMaterial extends ShaderMaterial {
 
 		if ( ! toneMappingNode && renderer.toneMapping !== NoToneMapping ) {
 
-			toneMappingNode = new ToneMappingNode( renderer.toneMapping, reference( 'toneMappingExposure', 'float', renderer ), outgoingLight );
+			toneMappingNode = toneMapping( renderer.toneMapping, reference( 'toneMappingExposure', 'float', renderer ), outgoingLight );
 
 		}
 
 		if ( toneMappingNode && toneMappingNode.isNode === true ) {
 
-			outgoingLight = context( toneMappingNode, { color: outgoingLight } );
+			outgoingLight = toneMappingNode.context( { color: outgoingLight } );
 
 		}
 
@@ -244,7 +252,7 @@ class NodeMaterial extends ShaderMaterial {
 
 		// ENCODING
 
-		outputNode = colorSpace( outputNode, renderer.outputEncoding );
+		outputNode = outputNode.colorSpace( renderer.outputEncoding );
 
 		// FOG
 
@@ -270,7 +278,7 @@ class NodeMaterial extends ShaderMaterial {
 
 		}
 
-		if ( fogNode ) outputNode = vec4( vec3( fogNode.mix( outputNode ) ), outputNode.w );
+		if ( fogNode ) outputNode = vec4( fogNode.mix( outputNode.rgb ), outputNode.a );
 
 		return outputNode;
 
@@ -358,8 +366,57 @@ class NodeMaterial extends ShaderMaterial {
 
 	}
 
-	static fromMaterial( /*material*/ ) { }
+	static fromMaterial( material ) {
+
+		const type = material.type.replace( 'Material', 'NodeMaterial' );
+
+		const nodeMaterial = createNodeMaterialFromType( type );
+
+		if ( nodeMaterial === undefined ) {
+
+			if ( material.isNodeMaterial !== true ) {
+
+				throw new Error( `NodeMaterial: Material "${ material.type }" is not compatible.` );
+
+			}
+
+			return material; // is already a node material
+
+		}
+
+		for ( const key in material ) {
+
+			nodeMaterial[ key ] = material[ key ];
+
+		}
+
+		return nodeMaterial;
+
+	}
 
 }
 
 export default NodeMaterial;
+
+export function addNodeMaterial( nodeMaterial ) {
+
+	if ( typeof nodeMaterial !== 'function' || ! nodeMaterial.name ) throw new Error( `Node material ${ nodeMaterial.name } is not a class` );
+	if ( NodeMaterials.has( nodeMaterial.name ) ) throw new Error( `Redefinition of node material ${ nodeMaterial.name }` );
+
+	NodeMaterials.set( nodeMaterial.name, nodeMaterial );
+
+}
+
+export function createNodeMaterialFromType( type ) {
+
+	const Material = NodeMaterials.get( type );
+
+	if ( Material !== undefined ) {
+
+		return new Material();
+
+	}
+
+};
+
+addNodeMaterial( NodeMaterial );

+ 4 - 1
examples/jsm/nodes/materials/PointsNodeMaterial.js

@@ -1,4 +1,5 @@
-import NodeMaterial from './NodeMaterial.js';
+import NodeMaterial, { addNodeMaterial } from './NodeMaterial.js';
+
 import { PointsMaterial } from 'three';
 
 const defaultValues = new PointsMaterial();
@@ -53,3 +54,5 @@ class PointsNodeMaterial extends NodeMaterial {
 }
 
 export default PointsNodeMaterial;
+
+addNodeMaterial( PointsNodeMaterial );

+ 21 - 18
examples/jsm/nodes/materials/SpriteNodeMaterial.js

@@ -1,11 +1,12 @@
-import NodeMaterial from './NodeMaterial.js';
+import NodeMaterial, { addNodeMaterial } from './NodeMaterial.js';
+import { uniform } from '../core/UniformNode.js';
+import { cameraProjectionMatrix } from '../accessors/CameraNode.js';
+import { materialRotation } from '../accessors/MaterialNode.js';
+import { modelViewMatrix, modelWorldMatrix } from '../accessors/ModelNode.js';
+import { positionLocal } from '../accessors/PositionNode.js';
+import { vec2, vec3, vec4 } from '../shadernode/ShaderNode.js';
+
 import { SpriteMaterial } from 'three';
-import {
-	vec2, vec3, vec4,
-	uniform, mul,
-	positionLocal, cos, sin,
-	modelViewMatrix, cameraProjectionMatrix, modelWorldMatrix, materialRotation
-} from '../shadernode/ShaderNodeElements.js';
 
 const defaultValues = new SpriteMaterial();
 
@@ -45,12 +46,9 @@ class SpriteNodeMaterial extends NodeMaterial {
 
 		const vertex = positionLocal;
 
-		let mvPosition = mul( modelViewMatrix, positionNode ? vec4( positionNode.xyz, 1 ) : vec4( 0, 0, 0, 1 ) );
+		let mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) );
 
-		let scale = vec2(
-			vec3( modelWorldMatrix[ 0 ].x, modelWorldMatrix[ 0 ].y, modelWorldMatrix[ 0 ].z ).length(),
-			vec3( modelWorldMatrix[ 1 ].x, modelWorldMatrix[ 1 ].y, modelWorldMatrix[ 1 ].z ).length()
-		);
+		let scale = vec2( modelWorldMatrix[ 0 ].xyz.length(), modelWorldMatrix[ 1 ].xyz.length() );
 
 		if ( scaleNode !== null ) {
 
@@ -62,20 +60,23 @@ class SpriteNodeMaterial extends NodeMaterial {
 
 		if ( object.center && object.center.isVector2 === true ) {
 
-			alignedPosition = alignedPosition.sub( uniform( object.center ).sub( vec2( 0.5 ) ) );
+			alignedPosition = alignedPosition.sub( uniform( object.center ).sub( 0.5 ) );
 
 		}
 
-		alignedPosition = mul( alignedPosition, scale );
+		alignedPosition = alignedPosition.mul( scale );
 
 		const rotation = rotationNode || materialRotation;
 
-		const rotatedPosition = vec2(
-			cos( rotation ).mul( alignedPosition.x ).sub( sin( rotation ).mul( alignedPosition.y ) ),
-			sin( rotation ).mul( alignedPosition.x ).add( cos( rotation ).mul( alignedPosition.y ) )
+		const cosAngle = rotation.cos();
+		const sinAngle = rotation.sin();
+
+		const rotatedPosition = vec2( // @TODO: Maybe we can create mat2 and write something like rotationMatrix.mul( alignedPosition )?
+			vec2( cosAngle, sinAngle.negate() ).dot( alignedPosition ),
+			vec2( sinAngle, cosAngle ).dot( alignedPosition )
 		);
 
-		mvPosition = vec4( mvPosition.xy.add( rotatedPosition.xy ), mvPosition.z, mvPosition.w );
+		mvPosition = vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw );
 
 		const modelViewProjection = cameraProjectionMatrix.mul( mvPosition );
 
@@ -105,3 +106,5 @@ class SpriteNodeMaterial extends NodeMaterial {
 }
 
 export default SpriteNodeMaterial;
+
+addNodeMaterial( SpriteNodeMaterial );

+ 31 - 22
examples/jsm/nodes/materialx/MaterialXNodes.js

@@ -6,54 +6,63 @@ import {
 } from './lib/mx_noise.js';
 import { mx_hsvtorgb, mx_rgbtohsv } from './lib/mx_hsv.js';
 import { mx_srgb_texture_to_lin_rec709 } from './lib/mx_transform_color.js';
-import { nodeObject, float, vec2, vec4, add, sub, mul, mix, clamp, uv, length, smoothstep, dFdx, dFdy, sign, pow, abs, convert } from '../shadernode/ShaderNodeElements.js';
+import { mix, smoothstep } from '../math/MathNode.js';
+import { uv } from '../accessors/UVNode.js';
+import { float, vec2, vec4 } from '../shadernode/ShaderNode.js';
 
 export const mx_aastep = ( threshold, value ) => {
 
 	threshold = float( threshold );
 	value = float( value );
 
-	const afwidth = mul( length( vec2( dFdx( value ), dFdy( value ) ) ), 0.70710678118654757 );
+	const afwidth = vec2( value.dFdx(), value.dFdy() ).length().mul( 0.70710678118654757 );
 
-	return smoothstep( sub( threshold, afwidth ), add( threshold, afwidth ), value );
+	return smoothstep( threshold.sub( afwidth ), threshold.add( afwidth ), value );
 
 };
 
-const _ramp = ( a, b, uv, p ) => mix( a, b, clamp( nodeObject( uv )[ p ] ) );
+const _ramp = ( a, b, uv, p ) => mix( a, b, uv[ p ].clamp() );
 export const mx_ramplr = ( valuel, valuer, texcoord = uv() ) => _ramp( valuel, valuer, texcoord, 'x' );
 export const mx_ramptb = ( valuet, valueb, texcoord = uv() ) => _ramp( valuet, valueb, texcoord, 'y' );
 
-const _split = ( a, b, center, uv, p ) => mix( a, b, mx_aastep( center, nodeObject( uv )[ p ] ) );
+const _split = ( a, b, center, uv, p ) => mix( a, b, mx_aastep( center, uv[ p ] ) );
 export const mx_splitlr = ( valuel, valuer, center, texcoord = uv() ) => _split( valuel, valuer, center, texcoord, 'x' );
 export const mx_splittb = ( valuet, valueb, center, texcoord = uv() ) => _split( valuet, valueb, center, texcoord, 'y' );
 
-export const mx_transform_uv = ( uv_scale = 1, uv_offset = 0, uv_geo = uv() ) => add( mul( uv_geo, uv_scale ), uv_offset );
+export const mx_transform_uv = ( uv_scale = 1, uv_offset = 0, uv_geo = uv() ) => uv_geo.mul( uv_scale ).add( uv_offset );
 
-export const mx_safepower = ( in1, in2 = 1 ) => mul( sign( in1 ), pow( abs( in1 ), in2 ) );
-export const mx_contrast = ( input, amount = 1, pivot = .5 ) => add( mul( sub( input, pivot ), amount ), pivot );
+export const mx_safepower = ( in1, in2 = 1 ) => {
 
-export const mx_noise_float = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => add( mul( amplitude, mx_perlin_noise_float( convert( texcoord, 'vec2|vec3' ) ) ), pivot );
-export const mx_noise_vec2 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => add( mul( amplitude, mx_perlin_noise_vec2( convert( texcoord, 'vec2|vec3' ) ) ), pivot );
-export const mx_noise_vec3 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => add( mul( amplitude, mx_perlin_noise_vec3( convert( texcoord, 'vec2|vec3' ) ) ), pivot );
+	in1 = float( in1 );
+
+	return in1.abs().pow( in2 ).mul( in1.sign() );
+
+};
+
+export const mx_contrast = ( input, amount = 1, pivot = .5 ) => float( input ).sub( pivot ).mul( amount ).add( pivot );
+
+export const mx_noise_float = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_float( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot );
+export const mx_noise_vec2 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_vec2( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot );
+export const mx_noise_vec3 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_vec3( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot );
 export const mx_noise_vec4 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => {
 
-	texcoord = convert( texcoord, 'vec2|vec3' ); // overloading type
+	texcoord = texcoord.convert( 'vec2|vec3' ); // overloading type
 
-	const noise_vec4 = vec4( mx_perlin_noise_vec3( texcoord ), mx_perlin_noise_float( add( texcoord, vec2( 19, 73 ) ) ) );
+	const noise_vec4 = vec4( mx_perlin_noise_vec3( texcoord ), mx_perlin_noise_float( texcoord.add( vec2( 19, 73 ) ) ) );
 
-	return add( mul( amplitude, noise_vec4 ), pivot );
+	return noise_vec4.mul( amplitude ).add( pivot );
 
 };
 
-export const mx_worley_noise_float = ( texcoord = uv(), jitter = 1 ) => worley_noise_float( convert( texcoord, 'vec2|vec3' ), jitter, 1 );
-export const mx_worley_noise_vec2 = ( texcoord = uv(), jitter = 1 ) => worley_noise_vec2( convert( texcoord, 'vec2|vec3' ), jitter, 1 );
-export const mx_worley_noise_vec3 = ( texcoord = uv(), jitter = 1 ) => worley_noise_vec3( convert( texcoord, 'vec2|vec3' ), jitter, 1 );
+export const mx_worley_noise_float = ( texcoord = uv(), jitter = 1 ) => worley_noise_float( texcoord.convert( 'vec2|vec3' ), jitter, 1 );
+export const mx_worley_noise_vec2 = ( texcoord = uv(), jitter = 1 ) => worley_noise_vec2( texcoord.convert( 'vec2|vec3' ), jitter, 1 );
+export const mx_worley_noise_vec3 = ( texcoord = uv(), jitter = 1 ) => worley_noise_vec3( texcoord.convert( 'vec2|vec3' ), jitter, 1 );
 
-export const mx_cell_noise_float = ( texcoord = uv() ) => cell_noise_float( convert( texcoord, 'vec2|vec3' ) );
+export const mx_cell_noise_float = ( texcoord = uv() ) => cell_noise_float( texcoord.convert( 'vec2|vec3' ) );
 
-export const mx_fractal_noise_float = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mul( fractal_noise_float( position, octaves, lacunarity, diminish ), amplitude );
-export const mx_fractal_noise_vec2 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mul( fractal_noise_vec2( position, octaves, lacunarity, diminish ), amplitude );
-export const mx_fractal_noise_vec3 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mul( fractal_noise_vec3( position, octaves, lacunarity, diminish ), amplitude );
-export const mx_fractal_noise_vec4 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => mul( fractal_noise_vec4( position, octaves, lacunarity, diminish ), amplitude );
+export const mx_fractal_noise_float = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_float( position, octaves, lacunarity, diminish ).mul( amplitude );
+export const mx_fractal_noise_vec2 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_vec2( position, octaves, lacunarity, diminish ).mul( amplitude );
+export const mx_fractal_noise_vec3 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_vec3( position, octaves, lacunarity, diminish ).mul( amplitude );
+export const mx_fractal_noise_vec4 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_vec4( position, octaves, lacunarity, diminish ).mul( amplitude );
 
 export { mx_hsvtorgb, mx_rgbtohsv, mx_srgb_texture_to_lin_rec709 };

+ 1 - 1
examples/jsm/nodes/materialx/lib/mx_hsv.js

@@ -1,4 +1,4 @@
-import { fn } from '../../Nodes.js';
+import { fn } from '../../core/FunctionNode.js';
 
 // Original shader code from:
 // https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_hsv.glsl

+ 2 - 1
examples/jsm/nodes/materialx/lib/mx_noise.js

@@ -1,4 +1,5 @@
-import { code, fn } from '../../Nodes.js';
+import { code } from '../../core/CodeNode.js';
+import { fn } from '../../core/FunctionNode.js';
 
 // Original shader code from:
 // https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_noise.glsl

+ 2 - 1
examples/jsm/nodes/materialx/lib/mx_transform_color.js

@@ -1,4 +1,5 @@
-import { code, fn } from '../../Nodes.js';
+import { code } from '../../core/CodeNode.js';
+import { fn } from '../../core/FunctionNode.js';
 
 // Original shader code from:
 // https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_transform_color.glsl

+ 14 - 7
examples/jsm/nodes/math/CondNode.js

@@ -1,6 +1,7 @@
-import Node from '../core/Node.js';
-import PropertyNode from '../core/PropertyNode.js';
-import ContextNode from '../core/ContextNode.js';
+import Node, { addNodeClass } from '../core/Node.js';
+import { property } from '../core/PropertyNode.js';
+import { context as contextNode } from '../core/ContextNode.js';
+import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
 
 class CondNode extends Node {
 
@@ -41,19 +42,19 @@ class CondNode extends Node {
 		const context = { tempWrite: false };
 
 		const needsProperty = this.ifNode.getNodeType( builder ) !== 'void' || ( this.elseNode && this.elseNode.getNodeType( builder ) !== 'void' );
-		const nodeProperty = needsProperty ? new PropertyNode( type ).build( builder ) : '';
+		const nodeProperty = needsProperty ? property( type ).build( builder ) : '';
 
-		const nodeSnippet = new ContextNode( this.condNode/*, context*/ ).build( builder, 'bool' );
+		const nodeSnippet = contextNode( this.condNode/*, context*/ ).build( builder, 'bool' );
 
 		builder.addFlowCode( `if ( ${nodeSnippet} ) {\n\n\t\t`, false );
 
-		let ifSnippet = new ContextNode( this.ifNode, context ).build( builder, type );
+		let ifSnippet = contextNode( this.ifNode, context ).build( builder, type );
 
 		ifSnippet = needsProperty ? nodeProperty + ' = ' + ifSnippet + ';' : ifSnippet;
 
 		builder.addFlowCode( ifSnippet + '\n\n\t}', false );
 
-		let elseSnippet = this.elseNode ? new ContextNode( this.elseNode, context ).build( builder, type ) : null;
+		let elseSnippet = this.elseNode ? contextNode( this.elseNode, context ).build( builder, type ) : null;
 
 		if ( elseSnippet ) {
 
@@ -70,3 +71,9 @@ class CondNode extends Node {
 }
 
 export default CondNode;
+
+export const cond = nodeProxy( CondNode );
+
+addNodeElement( 'cond', cond );
+
+addNodeClass( CondNode );

+ 120 - 20
examples/jsm/nodes/math/MathNode.js

@@ -1,7 +1,7 @@
 import TempNode from '../core/TempNode.js';
-import ExpressionNode from '../core/ExpressionNode.js';
-import SplitNode from '../utils/SplitNode.js';
-import OperatorNode from './OperatorNode.js';
+import { sub, mul, div } from './OperatorNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { addNodeElement, nodeObject, nodeProxy, float, vec3, vec4 } from '../shadernode/ShaderNode.js';
 
 class MathNode extends TempNode {
 
@@ -88,29 +88,33 @@ class MathNode extends TempNode {
 
 			if ( builder.isMatrix( tA.getNodeType( builder ) ) ) {
 
-				tB = new ExpressionNode( `${ builder.getType( 'vec4' ) }( ${ tB.build( builder, 'vec3' ) }, 0.0 )`, 'vec4' );
+				tB = vec4( vec3( tB ), 0.0 );
 
 			} else {
 
-				tA = new ExpressionNode( `${ builder.getType( 'vec4' ) }( ${ tA.build( builder, 'vec3' ) }, 0.0 )`, 'vec4' );
+				tA = vec4( vec3( tA ), 0.0 );
 
 			}
 
-			const mulNode = new SplitNode( new OperatorNode( '*', tA, tB ), 'xyz' );
+			const mulNode = mul( tA, tB ).xyz;
 
-			return new MathNode( MathNode.NORMALIZE, mulNode ).build( builder );
+			return normalize( mulNode ).build( builder, output );
 
 		} else if ( method === MathNode.NEGATE ) {
 
-			return builder.format( '( -' + a.build( builder, inputType ) + ' )', type, output );
+			return builder.format( '-' + a.build( builder, inputType ), type, output );
 
 		} else if ( method === MathNode.INVERT ) {
 
-			return builder.format( '( 1.0 - ' + a.build( builder, inputType ) + ' )', type, output );
+			return sub( 1.0, a ).build( builder, output );
 
 		} else if ( method === MathNode.RECIPROCAL ) {
 
-			return builder.format( '( 1.0 / ' + a.build( builder, inputType ) + ' )', type, output );
+			return div( 1.0, a ).build( builder, output );
+
+		} else if ( method === MathNode.DIFFERENCE ) {
+
+			return abs( sub( a, b ) ).build( builder, output );
 
 		} else {
 
@@ -156,16 +160,8 @@ class MathNode extends TempNode {
 			} else {
 
 				params.push( a.build( builder, inputType ) );
-
-				if ( c !== null ) {
-
-					params.push( b.build( builder, inputType ), c.build( builder, inputType ) );
-
-				} else if ( b !== null ) {
-
-					params.push( b.build( builder, inputType ) );
-
-				}
+				if ( b !== null ) params.push( b.build( builder, inputType ) );
+				if ( c !== null ) params.push( c.build( builder, inputType ) );
 
 			}
 
@@ -232,6 +228,7 @@ MathNode.MOD = 'mod';
 MathNode.STEP = 'step';
 MathNode.REFLECT = 'reflect';
 MathNode.DISTANCE = 'distance';
+MathNode.DIFFERENCE = 'difference';
 MathNode.DOT = 'dot';
 MathNode.CROSS = 'cross';
 MathNode.POW = 'pow';
@@ -246,3 +243,106 @@ MathNode.SMOOTHSTEP = 'smoothstep';
 MathNode.FACEFORWARD = 'faceforward';
 
 export default MathNode;
+
+export const EPSILON = float( 1e-6 );
+export const INFINITY = float( 1e6 );
+
+export const radians = nodeProxy( MathNode, MathNode.RADIANS );
+export const degrees = nodeProxy( MathNode, MathNode.DEGREES );
+export const exp = nodeProxy( MathNode, MathNode.EXP );
+export const exp2 = nodeProxy( MathNode, MathNode.EXP2 );
+export const log = nodeProxy( MathNode, MathNode.LOG );
+export const log2 = nodeProxy( MathNode, MathNode.LOG2 );
+export const sqrt = nodeProxy( MathNode, MathNode.SQRT );
+export const inversesqrt = nodeProxy( MathNode, MathNode.INVERSE_SQRT );
+export const floor = nodeProxy( MathNode, MathNode.FLOOR );
+export const ceil = nodeProxy( MathNode, MathNode.CEIL );
+export const normalize = nodeProxy( MathNode, MathNode.NORMALIZE );
+export const fract = nodeProxy( MathNode, MathNode.FRACT );
+export const sin = nodeProxy( MathNode, MathNode.SIN );
+export const cos = nodeProxy( MathNode, MathNode.COS );
+export const tan = nodeProxy( MathNode, MathNode.TAN );
+export const asin = nodeProxy( MathNode, MathNode.ASIN );
+export const acos = nodeProxy( MathNode, MathNode.ACOS );
+export const atan = nodeProxy( MathNode, MathNode.ATAN );
+export const abs = nodeProxy( MathNode, MathNode.ABS );
+export const sign = nodeProxy( MathNode, MathNode.SIGN );
+export const length = nodeProxy( MathNode, MathNode.LENGTH );
+export const negate = nodeProxy( MathNode, MathNode.NEGATE );
+export const invert = nodeProxy( MathNode, MathNode.INVERT );
+export const dFdx = nodeProxy( MathNode, MathNode.DFDX );
+export const dFdy = nodeProxy( MathNode, MathNode.DFDY );
+export const round = nodeProxy( MathNode, MathNode.ROUND );
+export const reciprocal = nodeProxy( MathNode, MathNode.RECIPROCAL );
+
+export const atan2 = nodeProxy( MathNode, MathNode.ATAN2 );
+export const min = nodeProxy( MathNode, MathNode.MIN );
+export const max = nodeProxy( MathNode, MathNode.MAX );
+export const mod = nodeProxy( MathNode, MathNode.MOD );
+export const step = nodeProxy( MathNode, MathNode.STEP );
+export const reflect = nodeProxy( MathNode, MathNode.REFLECT );
+export const distance = nodeProxy( MathNode, MathNode.DISTANCE );
+export const difference = nodeProxy( MathNode, MathNode.DIFFERENCE );
+export const dot = nodeProxy( MathNode, MathNode.DOT );
+export const cross = nodeProxy( MathNode, MathNode.CROSS );
+export const pow = nodeProxy( MathNode, MathNode.POW );
+export const pow2 = nodeProxy( MathNode, MathNode.POW, 2 );
+export const pow3 = nodeProxy( MathNode, MathNode.POW, 3 );
+export const pow4 = nodeProxy( MathNode, MathNode.POW, 4 );
+export const transformDirection = nodeProxy( MathNode, MathNode.TRANSFORM_DIRECTION );
+
+export const mix = nodeProxy( MathNode, MathNode.MIX );
+export const clamp = ( value, low = 0, high = 1 ) => nodeObject( new MathNode( MathNode.CLAMP, nodeObject( value ), nodeObject( low ), nodeObject( high ) ) );
+export const refract = nodeProxy( MathNode, MathNode.REFRACT );
+export const smoothstep = nodeProxy( MathNode, MathNode.SMOOTHSTEP );
+export const faceforward = nodeProxy( MathNode, MathNode.FACEFORWARD );
+
+addNodeElement( 'radians', radians );
+addNodeElement( 'degrees', degrees );
+addNodeElement( 'exp', exp );
+addNodeElement( 'exp2', exp2 );
+addNodeElement( 'log', log );
+addNodeElement( 'log2', log2 );
+addNodeElement( 'sqrt', sqrt );
+addNodeElement( 'inversesqrt', inversesqrt );
+addNodeElement( 'floor', floor );
+addNodeElement( 'ceil', ceil );
+addNodeElement( 'normalize', normalize );
+addNodeElement( 'fract', fract );
+addNodeElement( 'sin', sin );
+addNodeElement( 'cos', cos );
+addNodeElement( 'tan', tan );
+addNodeElement( 'asin', asin );
+addNodeElement( 'acos', acos );
+addNodeElement( 'atan', atan );
+addNodeElement( 'abs', abs );
+addNodeElement( 'sign', sign );
+addNodeElement( 'length', length );
+addNodeElement( 'negate', negate );
+addNodeElement( 'invert', invert );
+addNodeElement( 'dFdx', dFdx );
+addNodeElement( 'dFdy', dFdy );
+addNodeElement( 'round', round );
+addNodeElement( 'reciprocal', reciprocal );
+addNodeElement( 'atan2', atan2 );
+addNodeElement( 'min', min );
+addNodeElement( 'max', max );
+addNodeElement( 'mod', mod );
+addNodeElement( 'step', step );
+addNodeElement( 'reflect', reflect );
+addNodeElement( 'distance', distance );
+addNodeElement( 'dot', dot );
+addNodeElement( 'cross', cross );
+addNodeElement( 'pow', pow );
+addNodeElement( 'pow2', pow2 );
+addNodeElement( 'pow3', pow3 );
+addNodeElement( 'pow4', pow4 );
+addNodeElement( 'transformDirection', transformDirection );
+addNodeElement( 'mix', mix );
+addNodeElement( 'clamp', clamp );
+addNodeElement( 'refract', refract );
+addNodeElement( 'smoothstep', smoothstep );
+addNodeElement( 'faceforward', faceforward );
+addNodeElement( 'difference', difference );
+
+addNodeClass( MathNode );

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно