Browse Source

Nodes: Add more exports to ShaderNode (#23901)

* Add more exports to ShaderNode

* Fix brackets

* Fix one more bracket

* Fixes

* Another fix

* Cleanup

* Fix quotes

* Fixes

* Fix

* Another fix

* One more fix

* New fix

* Fix utils

* Cleanup

* Change `func` signature

* Fix

* Add `storage` and `compute`

* Fixes

* Fix

* `functionCall` -> `call`

* Remove `arrayElement`

* Update `compute` signature

* Update webgpu_compute.html

* Fix `getConstNodeType`

* Workaround

* Use `context`

* Radians, degrees, inversesqrt

* Remove 'inverseSqrt' alias
Levi Pesin 3 năm trước cách đây
mục cha
commit
6e5147206c
28 tập tin đã thay đổi với 640 bổ sung518 xóa
  1. 12 6
      examples/jsm/nodes/Nodes.js
  2. 2 2
      examples/jsm/nodes/accessors/InstanceNode.js
  3. 2 2
      examples/jsm/nodes/accessors/ReflectNode.js
  4. 2 2
      examples/jsm/nodes/accessors/SkinningNode.js
  5. 0 2
      examples/jsm/nodes/core/VarNode.js
  6. 2 3
      examples/jsm/nodes/display/ColorSpaceNode.js
  7. 2 3
      examples/jsm/nodes/display/NormalMapNode.js
  8. 1 2
      examples/jsm/nodes/display/ToneMappingNode.js
  9. 1 1
      examples/jsm/nodes/fog/FogRangeNode.js
  10. 2 3
      examples/jsm/nodes/functions/BSDF/BRDF_GGX.js
  11. 1 2
      examples/jsm/nodes/functions/BSDF/BRDF_Lambert.js
  12. 1 2
      examples/jsm/nodes/functions/BSDF/D_GGX.js
  13. 1 2
      examples/jsm/nodes/functions/BSDF/F_Schlick.js
  14. 1 2
      examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated.js
  15. 2 3
      examples/jsm/nodes/functions/PhysicalLightingModel.js
  16. 2 3
      examples/jsm/nodes/functions/light/getDistanceAttenuation.js
  17. 1 2
      examples/jsm/nodes/functions/material/getGeometryRoughness.js
  18. 1 2
      examples/jsm/nodes/functions/material/getRoughness.js
  19. 1 1
      examples/jsm/nodes/lights/LightContextNode.js
  20. 3 3
      examples/jsm/nodes/math/MathNode.js
  21. 1 2
      examples/jsm/nodes/procedural/CheckerNode.js
  22. 260 3
      examples/jsm/nodes/shadernode/ShaderNode.js
  23. 265 0
      examples/jsm/nodes/shadernode/ShaderNodeBaseElements.js
  24. 67 208
      examples/jsm/nodes/shadernode/ShaderNodeElements.js
  25. 0 250
      examples/jsm/nodes/shadernode/ShaderNodeUtils.js
  26. 3 3
      examples/jsm/nodes/utils/MatcapUVNode.js
  27. 1 1
      examples/jsm/nodes/utils/OscNode.js
  28. 3 3
      examples/webgpu_compute.html

+ 12 - 6
examples/jsm/nodes/Nodes.js

@@ -61,15 +61,17 @@ import CondNode from './math/CondNode.js';
 import LightContextNode from './lights/LightContextNode.js';
 import LightNode from './lights/LightNode.js';
 import LightsNode from './lights/LightsNode.js';
+import ReflectedLightNode from './lights/ReflectedLightNode.js';
 
 // utils
 import ArrayElementNode from './utils/ArrayElementNode.js';
 import ConvertNode from './utils/ConvertNode.js';
 import JoinNode from './utils/JoinNode.js';
-import SplitNode from './utils/SplitNode.js';
-import SpriteSheetUVNode from './utils/SpriteSheetUVNode.js';
 import MatcapUVNode from './utils/MatcapUVNode.js';
+import MaxMipLevelNode from './utils/MaxMipLevelNode.js';
 import OscNode from './utils/OscNode.js';
+import SplitNode from './utils/SplitNode.js';
+import SpriteSheetUVNode from './utils/SpriteSheetUVNode.js';
 import TimerNode from './utils/TimerNode.js';
 
 // loaders
@@ -157,15 +159,17 @@ const nodeLib = {
 	LightContextNode,
 	LightNode,
 	LightsNode,
+	ReflectedLightNode,
 
 	// utils
 	ArrayElementNode,
 	ConvertNode,
 	JoinNode,
-	SplitNode,
-	SpriteSheetUVNode,
 	MatcapUVNode,
+	MaxMipLevelNode,
 	OscNode,
+	SplitNode,
+	SpriteSheetUVNode,
 	TimerNode,
 
 	// procedural
@@ -252,15 +256,17 @@ export {
 	LightContextNode,
 	LightNode,
 	LightsNode,
+	ReflectedLightNode,
 
 	// utils
 	ArrayElementNode,
 	ConvertNode,
 	JoinNode,
-	SplitNode,
-	SpriteSheetUVNode,
 	MatcapUVNode,
+	MaxMipLevelNode,
 	OscNode,
+	SplitNode,
+	SpriteSheetUVNode,
 	TimerNode,
 
 	// procedural

+ 2 - 2
examples/jsm/nodes/accessors/InstanceNode.js

@@ -12,7 +12,7 @@ import {
 	instanceIndex,
 	positionLocal,
 	normalLocal
-} from '../shadernode/ShaderNodeElements.js';
+} from '../shadernode/ShaderNodeBaseElements.js';
 
 class InstanceNode extends Node {
 
@@ -26,7 +26,7 @@ class InstanceNode extends Node {
 
 		const instanceBufferNode = buffer( instanceMesh.instanceMatrix.array, 'mat4', instanceMesh.count );
 
-		this.instanceMatrixNode = temp( element( instanceBufferNode, instanceIndex ) );
+		this.instanceMatrixNode = temp( element( instanceBufferNode, instanceIndex ) ); // @TODO: a possible caching issue here?
 
 	}
 

+ 2 - 2
examples/jsm/nodes/accessors/ReflectNode.js

@@ -1,5 +1,5 @@
 import Node from '../core/Node.js';
-import { nodeObject, normalWorld, positionWorld, cameraPosition, sub, normalize, join, negate, reflect } from '../shadernode/ShaderNodeElements.js';
+import { nodeObject, normalWorld, positionWorld, cameraPosition, sub, normalize, vec3, negate, reflect } from '../shadernode/ShaderNodeBaseElements.js';
 
 class ReflectNode extends Node {
 
@@ -34,7 +34,7 @@ class ReflectNode extends Node {
 		} else if ( scope === ReflectNode.CUBE ) {
 
 			const reflectVec = nodeObject( new ReflectNode( ReflectNode.VECTOR ) );
-			const cubeUV = join( negate( reflectVec.x ), reflectVec.yz );
+			const cubeUV = vec3( negate( reflectVec.x ), reflectVec.yz );
 
 			return cubeUV.build( builder );
 

+ 2 - 2
examples/jsm/nodes/accessors/SkinningNode.js

@@ -1,6 +1,6 @@
 import Node from '../core/Node.js';
-import ShaderNode from '../shadernode/ShaderNode.js';
 import {
+	ShaderNode,
 	attribute,
 	buffer,
 	mat4,
@@ -12,7 +12,7 @@ import {
 	add,
 	mul,
 	transformDirection
-} from '../shadernode/ShaderNodeElements.js';
+} from '../shadernode/ShaderNodeBaseElements.js';
 
 import { NodeUpdateType } from '../core/constants.js';
 

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

@@ -94,6 +94,4 @@ class VarNode extends Node {
 
 }
 
-VarNode.prototype.isVarNode = true;
-
 export default VarNode;

+ 2 - 3
examples/jsm/nodes/display/ColorSpaceNode.js

@@ -1,6 +1,5 @@
 import TempNode from '../core/Node.js';
-import ShaderNode from '../shadernode/ShaderNode.js';
-import { vec3, pow, mul, sub, mix, join, lessThanEqual } from '../shadernode/ShaderNodeElements.js';
+import { ShaderNode, vec3, pow, mul, sub, mix, vec4, lessThanEqual } from '../shadernode/ShaderNodeBaseElements.js';
 
 import { LinearEncoding, sRGBEncoding } from 'three';
 
@@ -22,7 +21,7 @@ export const LinearTosRGB = new ShaderNode( ( inputs ) => {
 
 	const rgbResult = mix( a, b, factor );
 
-	return join( rgbResult.r, rgbResult.g, rgbResult.b, value.a );
+	return vec4( rgbResult, value.a );
 
 } );
 

+ 2 - 3
examples/jsm/nodes/display/NormalMapNode.js

@@ -1,7 +1,6 @@
 import TempNode from '../core/TempNode.js';
 import ModelNode from '../accessors/ModelNode.js';
-import ShaderNode from '../shadernode/ShaderNode.js';
-import { positionView, normalView, uv, join, cond, add, sub, mul, dFdx, dFdy, cross, max, dot, normalize, inversesqrt, equal } from '../shadernode/ShaderNodeElements.js';
+import { ShaderNode, positionView, normalView, uv, vec3, cond, add, sub, mul, dFdx, dFdy, cross, max, dot, normalize, inversesqrt, equal } from '../shadernode/ShaderNodeBaseElements.js';
 
 import { TangentSpaceNormalMap, ObjectSpaceNormalMap } from 'three';
 
@@ -57,7 +56,7 @@ class NormalMapNode extends TempNode {
 		if ( scaleNode !== null ) {
 
 			const normalMapScale = mul( normalMap.xy, scaleNode );
-			normalMap = join( normalMapScale, normalMap.z );
+			normalMap = vec3( normalMapScale, normalMap.z );
 
 		}
 

+ 1 - 2
examples/jsm/nodes/display/ToneMappingNode.js

@@ -1,6 +1,5 @@
 import TempNode from '../core/Node.js';
-import ShaderNode from '../shadernode/ShaderNode.js';
-import { mul, float } from '../shadernode/ShaderNodeElements.js';
+import { ShaderNode, mul, float } from '../shadernode/ShaderNodeBaseElements.js';
 
 import { LinearToneMapping } from 'three';
 

+ 1 - 1
examples/jsm/nodes/fog/FogRangeNode.js

@@ -1,5 +1,5 @@
 import FogNode from './FogNode.js';
-import { smoothstep, negate, positionView } from '../shadernode/ShaderNodeElements.js';
+import { smoothstep, negate, positionView } from '../shadernode/ShaderNodeBaseElements.js';
 
 class FogRangeNode extends FogNode {
 

+ 2 - 3
examples/jsm/nodes/functions/BSDF/BRDF_GGX.js

@@ -1,11 +1,10 @@
 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 from '../../shadernode/ShaderNode.js';
 import {
-	dotNV, add, mul, saturate, dot, pow2, normalize,
+	ShaderNode, dotNV, add, mul, saturate, dot, pow2, normalize,
 	transformedNormalView, positionViewDirection
-} from '../../shadernode/ShaderNodeElements.js';
+} from '../../shadernode/ShaderNodeBaseElements.js';
 
 // GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility
 const BRDF_GGX = new ShaderNode( ( inputs ) => {

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

@@ -1,5 +1,4 @@
-import ShaderNode from '../../shadernode/ShaderNode.js';
-import { mul } from '../../shadernode/ShaderNodeElements.js';
+import { ShaderNode, mul } from '../../shadernode/ShaderNodeBaseElements.js';
 
 const BRDF_Lambert = new ShaderNode( ( inputs ) => {
 

+ 1 - 2
examples/jsm/nodes/functions/BSDF/D_GGX.js

@@ -1,5 +1,4 @@
-import ShaderNode from '../../shadernode/ShaderNode.js';
-import { add, sub, mul, div, pow2 } from '../../shadernode/ShaderNodeElements.js';
+import { ShaderNode, add, sub, mul, div, pow2 } from '../../shadernode/ShaderNodeBaseElements.js';
 
 // Microfacet Models for Refraction through Rough Surfaces - equation (33)
 // http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html

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

@@ -1,5 +1,4 @@
-import ShaderNode from '../../shadernode/ShaderNode.js';
-import { add, sub, mul, exp2 } from '../../shadernode/ShaderNodeElements.js';
+import { ShaderNode, add, sub, mul, exp2 } from '../../shadernode/ShaderNodeBaseElements.js';
 
 const F_Schlick = new ShaderNode( ( inputs ) => {
 

+ 1 - 2
examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated.js

@@ -1,5 +1,4 @@
-import ShaderNode from '../../shadernode/ShaderNode.js';
-import { add, sub, mul, div, pow2, max, sqrt, EPSILON } from '../../shadernode/ShaderNodeElements.js';
+import { ShaderNode, add, sub, mul, div, pow2, max, sqrt, EPSILON } from '../../shadernode/ShaderNodeBaseElements.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

+ 2 - 3
examples/jsm/nodes/functions/PhysicalLightingModel.js

@@ -1,10 +1,9 @@
 import BRDF_Lambert from './BSDF/BRDF_Lambert.js';
 import BRDF_GGX from './BSDF/BRDF_GGX.js';
-import ShaderNode from '../shadernode/ShaderNode.js';
 import {
-	mul, saturate, dot, transformedNormalView,
+	ShaderNode, mul, saturate, dot, transformedNormalView,
 	diffuseColor, specularColor, roughness
-} from '../shadernode/ShaderNodeElements.js';
+} from '../shadernode/ShaderNodeBaseElements.js';
 
 const RE_Direct_Physical = new ShaderNode( ( inputs ) => {
 

+ 2 - 3
examples/jsm/nodes/functions/light/getDistanceAttenuation.js

@@ -1,7 +1,6 @@
-import ShaderNode from '../../shadernode/ShaderNode.js';
 import {
-	div, max, sub, mul, saturate, pow, pow2, pow4, cond, greaterThan
-} from '../../shadernode/ShaderNodeElements.js';
+	ShaderNode, div, max, sub, mul, saturate, pow, pow2, pow4, cond, greaterThan
+} from '../../shadernode/ShaderNodeBaseElements.js';
 
 const getDistanceAttenuation = new ShaderNode( ( inputs ) => {
 

+ 1 - 2
examples/jsm/nodes/functions/material/getGeometryRoughness.js

@@ -1,5 +1,4 @@
-import ShaderNode from '../../shadernode/ShaderNode.js';
-import { max, abs, dFdx, dFdy, normalGeometry } from '../../shadernode/ShaderNodeElements.js';
+import { ShaderNode, max, abs, dFdx, dFdy, normalGeometry } from '../../shadernode/ShaderNodeBaseElements.js';
 
 const getGeometryRoughness = new ShaderNode( () => {
 

+ 1 - 2
examples/jsm/nodes/functions/material/getRoughness.js

@@ -1,6 +1,5 @@
 import getGeometryRoughness from './getGeometryRoughness.js';
-import ShaderNode from '../../shadernode/ShaderNode.js';
-import { add, max, min } from '../../shadernode/ShaderNodeElements.js';
+import { ShaderNode, add, max, min } from '../../shadernode/ShaderNodeBaseElements.js';
 
 const getRoughness = new ShaderNode( ( inputs ) => {
 

+ 1 - 1
examples/jsm/nodes/lights/LightContextNode.js

@@ -1,5 +1,5 @@
 import ContextNode from '../core/ContextNode.js';
-import { reflectedLight } from '../shadernode/ShaderNodeElements.js';
+import { reflectedLight } from '../shadernode/ShaderNodeBaseElements.js';
 
 class LightContextNode extends ContextNode {
 

+ 3 - 3
examples/jsm/nodes/math/MathNode.js

@@ -8,14 +8,14 @@ class MathNode extends TempNode {
 
 	// 1 input
 
-	static RAD = 'radians';
-	static DEG = 'degrees';
+	static RADIANS = 'radians';
+	static DEGREES = 'degrees';
 	static EXP = 'exp';
 	static EXP2 = 'exp2';
 	static LOG = 'log';
 	static LOG2 = 'log2';
 	static SQRT = 'sqrt';
-	static INV_SQRT = 'inversesqrt';
+	static INVERSE_SQRT = 'inversesqrt';
 	static FLOOR = 'floor';
 	static CEIL = 'ceil';
 	static NORMALIZE = 'normalize';

+ 1 - 2
examples/jsm/nodes/procedural/CheckerNode.js

@@ -1,6 +1,5 @@
 import Node from '../core/Node.js';
-import ShaderNode from '../shadernode/ShaderNode.js';
-import { uv, add, mul, floor, mod, sign } from '../shadernode/ShaderNodeElements.js';
+import { ShaderNode, uv, add, mul, floor, mod, sign } from '../shadernode/ShaderNodeBaseElements.js';
 
 const checkerShaderNode = new ShaderNode( ( inputs ) => {
 

+ 260 - 3
examples/jsm/nodes/shadernode/ShaderNode.js

@@ -1,5 +1,262 @@
-import { ShaderNodeScript, shaderNodeHandler } from './ShaderNodeUtils.js';
+import ArrayElementNode from '../utils/ArrayElementNode.js';
+import ConvertNode from '../utils/ConvertNode.js';
+import JoinNode from '../utils/JoinNode.js';
+import SplitNode from '../utils/SplitNode.js';
+import ConstNode from '../core/ConstNode.js';
+import { getValueFromType } from '../core/NodeUtils.js';
 
-const ShaderNode = new Proxy( ShaderNodeScript, shaderNodeHandler );
+const shaderNodeHandler = {
 
-export default ShaderNode;
+	construct( NodeClosure, params ) {
+
+		const inputs = params.shift();
+
+		return NodeClosure( nodeObjects( inputs ), ...params );
+
+	},
+
+	get: function ( node, prop ) {
+
+		if ( typeof prop === 'string' && node[ prop ] === undefined ) {
+
+			if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true ) {
+
+				// accessing properties ( swizzle )
+
+				prop = prop
+					.replace( /r|s/g, 'x' )
+					.replace( /g|t/g, 'y' )
+					.replace( /b|p/g, 'z' )
+					.replace( /a|q/g, 'w' );
+
+				return nodeObject( new SplitNode( node, prop ) );
+
+			} else if ( /^\d+$/.test( prop ) === true ) {
+
+				// accessing array
+
+				return nodeObject( new ArrayElementNode( node, new ConstNode( Number( prop ), 'uint' ) ) );
+
+			}
+
+		}
+
+		return node[ prop ];
+
+	}
+
+};
+
+const nodeObjectsCacheMap = new WeakMap();
+
+const ShaderNodeObject = function ( obj ) {
+
+	const type = typeof obj;
+
+	if ( ( type === 'number' ) || ( type === 'boolean' ) ) {
+
+		return nodeObject( getAutoTypedConstNode( obj ) );
+
+	} else if ( type === 'object' ) {
+
+		if ( obj?.isNode === true ) {
+
+			let nodeObject = nodeObjectsCacheMap.get( obj );
+
+			if ( nodeObject === undefined ) {
+
+				nodeObject = new Proxy( obj, shaderNodeHandler );
+				nodeObjectsCacheMap.set( obj, nodeObject );
+				nodeObjectsCacheMap.set( nodeObject, nodeObject );
+
+			}
+
+			return nodeObject;
+
+		}
+
+	}
+
+	return obj;
+
+};
+
+const ShaderNodeObjects = function ( objects ) {
+
+	for ( const name in objects ) {
+
+		objects[ name ] = nodeObject( objects[ name ] );
+
+	}
+
+	return objects;
+
+};
+
+const ShaderNodeArray = function ( array ) {
+
+	const len = array.length;
+
+	for ( let i = 0; i < len; i ++ ) {
+
+		array[ i ] = nodeObject( array[ i ] );
+
+	}
+
+	return array;
+
+};
+
+const ShaderNodeProxy = function ( NodeClass, scope = null, factor = null ) {
+
+	if ( scope === null ) {
+
+		return ( ...params ) => {
+
+			return nodeObject( new NodeClass( ...nodeArray( params ) ) );
+
+		};
+
+	} else if ( factor === null ) {
+
+		return ( ...params ) => {
+
+			return nodeObject( new NodeClass( scope, ...nodeArray( params ) ) );
+
+		};
+
+	} else {
+
+		factor = nodeObject( factor );
+
+		return ( ...params ) => {
+
+			return nodeObject( new NodeClass( scope, ...nodeArray( params ), factor ) );
+
+		};
+
+	}
+
+};
+
+const ShaderNodeImmutable = function ( NodeClass, ...params ) {
+
+	return nodeObject( new NodeClass( ...nodeArray( params ) ) );
+
+};
+
+const ShaderNodeScript = function ( jsFunc ) {
+
+	// @TODO: Move this to Node extended class
+
+	const self = {
+
+		build: ( builder ) => {
+
+			self.call( {}, builder );
+
+			return '';
+
+		},
+
+		call: ( inputs, builder ) => {
+
+			inputs = nodeObjects( inputs );
+
+			return nodeObject( jsFunc( inputs, builder ) );
+
+		}
+
+	};
+
+	return self;
+
+};
+
+export const ShaderNode = new Proxy( ShaderNodeScript, shaderNodeHandler );
+
+export const nodeObject = ( val ) => /* new */ ShaderNodeObject( val );
+export const nodeObjects = ( val ) => new ShaderNodeObjects( val );
+export const nodeArray = ( val ) => new ShaderNodeArray( val );
+export const nodeProxy = ( ...val ) => new ShaderNodeProxy( ...val );
+export const nodeImmutable = ( ...val ) => new ShaderNodeImmutable( ...val );
+
+const bools = [ false, true ];
+const uints = [ 0, 1, 2, 3 ];
+const ints = [ - 1, - 2 ];
+const floats = [ 0.5, 1.5, 1 / 3, 1e-6, 1e6, Math.PI, Math.PI * 2, 1 / Math.PI, 2 / Math.PI, 1 / ( Math.PI * 2 ), Math.PI / 2 ];
+
+const boolsCacheMap = new Map();
+for ( let bool of bools ) boolsCacheMap.set( bool, new ConstNode( bool ) );
+
+const uintsCacheMap = new Map();
+for ( let uint of uints ) uintsCacheMap.set( uint, new ConstNode( uint, 'uint' ) );
+
+const intsCacheMap = new Map( [ ...uintsCacheMap ].map( el => new ConstNode( el.value, 'int' ) ) );
+for ( let int of ints ) intsCacheMap.set( int, new ConstNode( int, 'int' ) );
+
+const floatsCacheMap = new Map( [ ...intsCacheMap ].map( el => new ConstNode( el.value ) ) );
+for ( let float of floats ) floatsCacheMap.set( float, new ConstNode( float ) );
+for ( let float of floats ) floatsCacheMap.set( - float, new ConstNode( - float ) );
+
+export const cacheMaps = { bool: boolsCacheMap, uint: uintsCacheMap, ints: intsCacheMap, float: floatsCacheMap };
+
+const constNodesCacheMap = new Map( [ ...boolsCacheMap, ...floatsCacheMap ] );
+
+const getAutoTypedConstNode = ( value ) => {
+
+	if ( constNodesCacheMap.has( value ) ) {
+
+		return constNodesCacheMap.get( value );
+
+	} else if ( value.isNode === true ) {
+
+		return value;
+
+	} else {
+
+		return new ConstNode( value );
+
+	}
+
+};
+
+export const ConvertType = function ( type, cacheMap = null ) {
+
+	return ( ...params ) => {
+
+		if ( params.length === 0 ) {
+
+			return nodeObject( new ConstNode( getValueFromType( type ), type ) );
+
+		} else {
+
+			if ( type === 'color' && params[ 0 ].isNode !== true ) {
+
+				params = [ getValueFromType( type, ...params ) ];
+
+			}
+
+			if ( params.length === 1 && cacheMap !== null && cacheMap.has( params[ 0 ] ) ) {
+
+				return cacheMap.get( params[ 0 ] );
+
+			}
+
+			const nodes = params.map( getAutoTypedConstNode );
+
+			if ( nodes.length === 1 ) {
+
+				return nodeObject( nodes[ 0 ].nodeType === type ? nodes[ 0 ] : new ConvertNode( nodes[ 0 ], type ) );
+
+			}
+
+			return nodeObject( new ConvertNode( new JoinNode( nodes ), type ) );
+
+		}
+
+	};
+
+};
+
+export const getConstNodeType = ( value ) => value.nodeType || value.convertTo || ( typeof value === 'string' ? value : null );

+ 265 - 0
examples/jsm/nodes/shadernode/ShaderNodeBaseElements.js

@@ -0,0 +1,265 @@
+// core
+//import ArrayUniformNode from '../core/ArrayUniformNode.js';
+import AttributeNode from '../core/AttributeNode.js';
+import BypassNode from '../core/BypassNode.js';
+import CodeNode from '../core/CodeNode.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 PropertyNode from '../core/PropertyNode.js';
+import UniformNode from '../core/UniformNode.js';
+import VarNode from '../core/VarNode.js';
+import VaryNode from '../core/VaryNode.js';
+
+// accessors
+import BufferNode from '../accessors/BufferNode.js';
+import CameraNode from '../accessors/CameraNode.js';
+import MaterialNode from '../accessors/MaterialNode.js';
+import MaterialReferenceNode from '../accessors/MaterialReferenceNode.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 StorageBufferNode from '../accessors/StorageBufferNode.js';
+import TextureNode from '../accessors/TextureNode.js';
+import UVNode from '../accessors/UVNode.js';
+
+// gpgpu
+import ComputeNode from '../gpgpu/ComputeNode.js';
+
+// math
+import MathNode from '../math/MathNode.js';
+import OperatorNode from '../math/OperatorNode.js';
+import CondNode from '../math/CondNode.js';
+
+// lights
+import ReflectedLightNode from '../lights/ReflectedLightNode.js';
+
+// utils
+import ArrayElementNode from '../utils/ArrayElementNode.js';
+import ConvertNode from '../utils/ConvertNode.js';
+
+// shader node utils
+import { ShaderNode, nodeObject, nodeObjects, nodeArray, nodeProxy, nodeImmutable, ConvertType, getConstNodeType, cacheMaps } from './ShaderNode.js';
+
+// shader node utils
+
+export { ShaderNode, nodeObject, nodeObjects, nodeArray, nodeProxy, nodeImmutable };
+
+export const color = new ConvertType( 'color' );
+
+export const float = new ConvertType( 'float', cacheMaps.float );
+export const int = new ConvertType( 'int', cacheMaps.int );
+export const uint = new ConvertType( 'uint', cacheMaps.uint );
+export const bool = new ConvertType( 'bool', cacheMaps.bool );
+
+export const vec2 = new ConvertType( 'vec2' );
+export const ivec2 = new ConvertType( 'ivec2' );
+export const uvec2 = new ConvertType( 'uvec2' );
+export const bvec2 = new ConvertType( 'bvec2' );
+
+export const vec3 = new ConvertType( 'vec3' );
+export const ivec3 = new ConvertType( 'ivec3' );
+export const uvec3 = new ConvertType( 'uvec3' );
+export const bvec3 = new ConvertType( 'bvec3' );
+
+export const vec4 = new ConvertType( 'vec4' );
+export const ivec4 = new ConvertType( 'ivec4' );
+export const uvec4 = new ConvertType( 'uvec4' );
+export const bvec4 = new ConvertType( 'bvec4' );
+
+export const mat3 = new ConvertType( 'mat3' );
+export const imat3 = new ConvertType( 'imat3' );
+export const umat3 = new ConvertType( 'umat3' );
+export const bmat3 = new ConvertType( 'bmat3' );
+
+export const mat4 = new ConvertType( 'mat4' );
+export const imat4 = new ConvertType( 'imat4' );
+export const umat4 = new ConvertType( 'umat4' );
+export const bmat4 = new ConvertType( 'bmat4' );
+
+// core
+
+// @TODO: ArrayUniformNode
+
+export const func = ( code ) => {
+
+	const node = nodeObject( new FunctionNode( code ) );
+
+	const call = node.call.bind( node );
+	node.call = ( params ) => nodeObject( call( params ) );
+
+	return node;
+
+};
+
+export const uniform = ( nodeOrType ) => {
+
+	const nodeType = getConstNodeType( nodeOrType );
+
+	// TODO: get ConstNode from .traverse() in the future
+	const value = nodeOrType.isNode === true ? nodeOrType.node?.value || nodeOrType.value : nodeOrType;
+
+	return nodeObject( new UniformNode( value, nodeType ) );
+
+};
+
+export const attribute = ( name, nodeOrType ) => nodeObject( new AttributeNode( name, getConstNodeType( nodeOrType ) ) );
+export const property = ( name, nodeOrType ) => nodeObject( new PropertyNode( name, getConstNodeType( nodeOrType ) ) );
+
+export const bypass = nodeProxy( BypassNode );
+export const code = nodeProxy( CodeNode );
+export const context = nodeProxy( ContextNode );
+export const expression = nodeProxy( ExpressionNode );
+export const call = nodeProxy( FunctionCallNode );
+export const instanceIndex = nodeImmutable( InstanceIndexNode );
+export const label = nodeProxy( VarNode );
+export const temp = label;
+export const vary = nodeProxy( VaryNode );
+
+// accesors
+
+export const buffer = ( value, nodeOrType, count ) => nodeObject( new BufferNode( value, getConstNodeType( nodeOrType ), count ) );
+export const storage = ( value, nodeOrType, count ) => nodeObject( new StorageBufferNode( value, getConstNodeType( nodeOrType ), count ) );
+
+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 );
+
+export const materialAlphaTest = nodeImmutable( MaterialNode, MaterialNode.ALPHA_TEST );
+export const materialColor = nodeImmutable( MaterialNode, MaterialNode.COLOR );
+export const materialOpacity = nodeImmutable( MaterialNode, MaterialNode.OPACITY );
+export const materialSpecular = nodeImmutable( MaterialNode, MaterialNode.SPECULAR );
+export const materialRoughness = nodeImmutable( MaterialNode, MaterialNode.ROUGHNESS );
+export const materialMetalness = nodeImmutable( MaterialNode, MaterialNode.METALNESS );
+
+export const diffuseColor = nodeImmutable( PropertyNode, 'DiffuseColor', 'vec4' );
+export const roughness = nodeImmutable( PropertyNode, 'Roughness', 'float' );
+export const metalness = nodeImmutable( PropertyNode, 'Metalness', 'float' );
+export const alphaTest = nodeImmutable( PropertyNode, 'AlphaTest', 'float' );
+export const specularColor = nodeImmutable( PropertyNode, 'SpecularColor', 'color' );
+
+export const reference = ( name, nodeOrType, object ) => nodeObject( new ReferenceNode( name, getConstNodeType( nodeOrType ), object ) );
+export const materialReference = ( name, nodeOrType, material ) => nodeObject( new MaterialReferenceNode( name, getConstNodeType( nodeOrType ), material ) );
+
+export const modelViewProjection = nodeProxy( ModelViewProjectionNode );
+
+export const normalGeometry = nodeImmutable( NormalNode, NormalNode.GEOMETRY );
+export const normalLocal = nodeImmutable( NormalNode, NormalNode.LOCAL );
+export const normalWorld = nodeImmutable( NormalNode, NormalNode.WORLD );
+export const normalView = nodeImmutable( NormalNode, NormalNode.VIEW );
+export const transformedNormalView = nodeImmutable( VarNode, normalView, 'TransformedNormalView' );
+
+export const viewMatrix = nodeProxy( Object3DNode, Object3DNode.VIEW_MATRIX );
+export const normalMatrix = nodeProxy( Object3DNode, Object3DNode.NORMAL_MATRIX );
+export const worldMatrix = nodeProxy( Object3DNode, Object3DNode.WORLD_MATRIX );
+export const position = nodeProxy( Object3DNode, Object3DNode.POSITION );
+export const viewPosition = nodeProxy( Object3DNode, Object3DNode.VIEW_POSITION );
+
+export const positionGeometry = nodeImmutable( PositionNode, PositionNode.GEOMETRY );
+export const positionLocal = nodeImmutable( PositionNode, PositionNode.LOCAL );
+export const positionWorld = nodeImmutable( PositionNode, PositionNode.WORLD );
+export const positionView = nodeImmutable( PositionNode, PositionNode.VIEW );
+export const positionViewDirection = nodeImmutable( PositionNode, PositionNode.VIEW_DIRECTION );
+
+export const texture = nodeProxy( TextureNode );
+export const sampler = ( texture ) => nodeObject( new ConvertNode( texture.isNode === true ? texture : new TextureNode( texture ), 'sampler' ) );
+export const uv = ( ...params ) => nodeObject( new UVNode( ...params ) );
+export const pointUV = nodeImmutable( PointUVNode );
+
+// gpgpu
+
+export const compute = ( node, count, workgroupSize ) => nodeObject( new ComputeNode( nodeObject( node ), count, workgroupSize ) );
+
+// math
+
+export const EPSILON = float( 1e-6 );
+export const INFINITY = float( 1e6 );
+
+export const cond = nodeProxy( CondNode );
+
+export const add = nodeProxy( OperatorNode, '+' );
+export const sub = nodeProxy( OperatorNode, '-' );
+export const mul = nodeProxy( OperatorNode, '*' );
+export const div = nodeProxy( OperatorNode, '/' );
+export const remainder = nodeProxy( OperatorNode, '%' );
+export const equal = nodeProxy( OperatorNode, '==' );
+export const assign = nodeProxy( OperatorNode, '=' );
+export const lessThan = nodeProxy( OperatorNode, '<' );
+export const greaterThan = nodeProxy( OperatorNode, '>' );
+export const lessThanEqual = nodeProxy( OperatorNode, '<=' );
+export const greaterThanEqual = nodeProxy( OperatorNode, '>=' );
+export const and = nodeProxy( OperatorNode, '&&' );
+export const or = nodeProxy( OperatorNode, '||' );
+export const xor = nodeProxy( OperatorNode, '^^' );
+export const bitAnd = nodeProxy( OperatorNode, '&' );
+export const bitOr = nodeProxy( OperatorNode, '|' );
+export const bitXor = nodeProxy( OperatorNode, '^' );
+export const shiftLeft = nodeProxy( OperatorNode, '<<' );
+export const shiftRight = nodeProxy( OperatorNode, '>>' );
+
+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 saturate = nodeProxy( MathNode, MathNode.SATURATE );
+export const round = nodeProxy( MathNode, MathNode.ROUND );
+
+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 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 = nodeProxy( MathNode, MathNode.CLAMP );
+export const refract = nodeProxy( MathNode, MathNode.REFRACT );
+export const smoothstep = nodeProxy( MathNode, MathNode.SMOOTHSTEP );
+export const faceforward = nodeProxy( MathNode, MathNode.FACEFORWARD );
+
+// lights
+
+export const reflectedLight = nodeProxy( ReflectedLightNode );
+
+// utils
+
+export const element = nodeProxy( ArrayElementNode );
+
+// miscellaneous
+
+export const dotNV = saturate( dot( transformedNormalView, positionViewDirection ) );

+ 67 - 208
examples/jsm/nodes/shadernode/ShaderNodeElements.js

@@ -1,244 +1,103 @@
-// core nodes
-import PropertyNode from '../core/PropertyNode.js';
-import VarNode from '../core/VarNode.js';
-import AttributeNode from '../core/AttributeNode.js';
-import UniformNode from '../core/UniformNode.js';
-import BypassNode from '../core/BypassNode.js';
-import InstanceIndexNode from '../core/InstanceIndexNode.js';
-import ContextNode from '../core/ContextNode.js';
-import FunctionNode from '../core/FunctionNode.js';
-
-// accessor nodes
-import BufferNode from '../accessors/BufferNode.js';
-import StorageBufferNode from '../accessors/StorageBufferNode.js';
-import CameraNode from '../accessors/CameraNode.js';
-import MaterialNode from '../accessors/MaterialNode.js';
-import ModelNode from '../accessors/ModelNode.js';
-import ModelViewProjectionNode from '../accessors/ModelViewProjectionNode.js';
-import NormalNode from '../accessors/NormalNode.js';
-import PositionNode from '../accessors/PositionNode.js';
-import SkinningNode from '../accessors/SkinningNode.js';
-import TextureNode from '../accessors/TextureNode.js';
-import UVNode from '../accessors/UVNode.js';
+// accessors
+import CubeTextureNode from '../accessors/CubeTextureNode.js';
 import InstanceNode from '../accessors/InstanceNode.js';
+import ReflectNode from '../accessors/ReflectNode.js';
+import SkinningNode from '../accessors/SkinningNode.js';
 
-// gpgpu
-import ComputeNode from '../gpgpu/ComputeNode.js';
+// display
+import ColorSpaceNode from '../display/ColorSpaceNode.js';
+import NormalMapNode from '../display/NormalMapNode.js';
+import ToneMappingNode from '../display/ToneMappingNode.js';
 
-// math nodes
-import OperatorNode from '../math/OperatorNode.js';
-import CondNode from '../math/CondNode.js';
-import MathNode from '../math/MathNode.js';
+// lights
+import LightNode from '../lights/LightNode.js';
+import LightsNode from '../lights/LightsNode.js';
+import LightContextNode from '../lights/LightContextNode.js';
 
-// util nodes
-import ArrayElementNode from '../utils/ArrayElementNode.js';
-import ConvertNode from '../utils/ConvertNode.js';
-import JoinNode from '../utils/JoinNode.js';
+// utils
+import MatcapUVNode from '../utils/MatcapUVNode.js';
+import MaxMipLevelNode from '../utils/MaxMipLevelNode.js';
+import OscNode from '../utils/OscNode.js';
+import SpriteSheetUVNode from '../utils/SpriteSheetUVNode.js';
 import TimerNode from '../utils/TimerNode.js';
 
-// other nodes
-import ColorSpaceNode from '../display/ColorSpaceNode.js';
-import LightContextNode from '../lights/LightContextNode.js';
-import ReflectedLightNode from '../lights/ReflectedLightNode.js';
+// procedural
+import CheckerNode from '../procedural/CheckerNode.js';
 
-// utils
-import ShaderNode from './ShaderNode.js';
-import { nodeObject, nodeObjects, nodeArray, nodeProxy, ConvertType, cacheMaps } from './ShaderNodeUtils.js';
+// fog
+import FogNode from '../fog/FogNode.js';
+import FogRangeNode from '../fog/FogRangeNode.js';
+
+// shader node utils
+import { nodeObject, nodeProxy, nodeImmutable } from './ShaderNode.js';
 
 //
 // Node Material Shader Syntax
 //
 
-export { ShaderNode, nodeObject, nodeObjects, nodeArray, nodeProxy };
-
-export const color = new ConvertType( 'color' );
-
-export const float = new ConvertType( 'float', cacheMaps.float );
-export const int = new ConvertType( 'int', cacheMaps.int );
-export const uint = new ConvertType( 'uint', cacheMaps.uint );
-export const bool = new ConvertType( 'bool', cacheMaps.bool );
-
-export const vec2 = new ConvertType( 'vec2' );
-export const ivec2 = new ConvertType( 'ivec2' );
-export const uvec2 = new ConvertType( 'uvec2' );
-export const bvec2 = new ConvertType( 'bvec2' );
-
-export const vec3 = new ConvertType( 'vec3' );
-export const ivec3 = new ConvertType( 'ivec3' );
-export const uvec3 = new ConvertType( 'uvec3' );
-export const bvec3 = new ConvertType( 'bvec3' );
-
-export const vec4 = new ConvertType( 'vec4' );
-export const ivec4 = new ConvertType( 'ivec4' );
-export const uvec4 = new ConvertType( 'uvec4' );
-export const bvec4 = new ConvertType( 'bvec4' );
-
-export const mat3 = new ConvertType( 'mat3' );
-export const imat3 = new ConvertType( 'imat3' );
-export const umat3 = new ConvertType( 'umat3' );
-export const bmat3 = new ConvertType( 'bmat3' );
-
-export const mat4 = new ConvertType( 'mat4' );
-export const imat4 = new ConvertType( 'imat4' );
-export const umat4 = new ConvertType( 'umat4' );
-export const bmat4 = new ConvertType( 'bmat4' );
-
-export const uniform = ( value ) => {
+// shader node utils
 
-	const nodeType = value.nodeType || value.convertTo;
+export * from './ShaderNodeBaseElements.js';
 
-	// TODO: get ConstNode from .traverse() in the future
-	value = value.isNode === true ? value.node?.value || value.value : value;
+// functions
 
-	return nodeObject( new UniformNode( value, nodeType ) );
+export { default as BRDF_GGX } from '../functions/BSDF/BRDF_GGX.js'; // see https://github.com/tc39/proposal-export-default-from
+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 F_Schlick } from '../functions/BSDF/F_Schlick.js';
+export { default as V_GGX_SmithCorrelated } from '../functions/BSDF/V_GGX_SmithCorrelated.js';
 
-};
+export { default as getDistanceAttenuation } from '../functions/light/getDistanceAttenuation.js';
 
-export const label = ( node, name ) => {
+export { default as getGeometryRoughness } from '../functions/material/getGeometryRoughness.js';
+export { default as getRoughness } from '../functions/material/getRoughness.js';
 
-	node = nodeObject( node );
+export { default as PhysicalLightingModel } from '../functions/PhysicalLightingModel.js';
 
-	if ( ( node.isVarNode === true ) && ( node.name === name ) ) {
+// accessors
 
-		return node;
+export const cubeTexture = nodeProxy( CubeTextureNode );
 
-	}
-
-	return nodeObject( new VarNode( node, name ) );
-
-};
-
-export const temp = nodeProxy( VarNode );
-
-export const join = ( ...params ) => nodeObject( new JoinNode( nodeArray( params ) ) );
-
-export const uv = ( ...params ) => nodeObject( new UVNode( ...params ) );
-export const attribute = ( ...params ) => nodeObject( new AttributeNode( ...params ) );
-export const buffer = ( ...params ) => nodeObject( new BufferNode( ...params ) );
-export const storage = ( ...params ) => nodeObject( new StorageBufferNode( ...params ) );
-export const texture = ( ...params ) => nodeObject( new TextureNode( ...params ) );
-export const sampler = ( texture ) => nodeObject( new ConvertNode( texture.isNode === true ? texture : new TextureNode( texture ), 'sampler' ) );
-
-export const timer = ( ...params ) => nodeObject( new TimerNode( ...params ) );
-
-export const compute = ( ...params ) => nodeObject( new ComputeNode( ...params ) );
-export const func = ( ...params ) => nodeObject( new FunctionNode( ...params ) );
+export const instance = nodeProxy( InstanceNode );
 
-export const cond = nodeProxy( CondNode );
+export const reflectVector = nodeImmutable( ReflectNode, ReflectNode.VECTOR );
+export const reflectCube = nodeImmutable( ReflectNode, ReflectNode.CUBE );
 
-export const add = nodeProxy( OperatorNode, '+' );
-export const sub = nodeProxy( OperatorNode, '-' );
-export const mul = nodeProxy( OperatorNode, '*' );
-export const div = nodeProxy( OperatorNode, '/' );
-export const remainder = nodeProxy( OperatorNode, '%' );
-export const equal = nodeProxy( OperatorNode, '==' );
-export const assign = nodeProxy( OperatorNode, '=' );
-export const lessThan = nodeProxy( OperatorNode, '<' );
-export const greaterThan = nodeProxy( OperatorNode, '>' );
-export const lessThanEqual = nodeProxy( OperatorNode, '<=' );
-export const greaterThanEqual = nodeProxy( OperatorNode, '>=' );
-export const and = nodeProxy( OperatorNode, '&&' );
-export const or = nodeProxy( OperatorNode, '||' );
-export const xor = nodeProxy( OperatorNode, '^^' );
-export const bitAnd = nodeProxy( OperatorNode, '&' );
-export const bitOr = nodeProxy( OperatorNode, '|' );
-export const bitXor = nodeProxy( OperatorNode, '^' );
-export const shiftLeft = nodeProxy( OperatorNode, '<<' );
-export const shiftRight = nodeProxy( OperatorNode, '>>' );
+export const skinning = nodeProxy( SkinningNode );
 
-export const element = nodeProxy( ArrayElementNode );
-export const instanceIndex = nodeObject( new InstanceIndexNode() );
+// display
 
-export const modelViewProjection = nodeProxy( ModelViewProjectionNode );
+export const colorSpace = ( node, encoding ) => nodeObject( new ColorSpaceNode( null, nodeObject( node ) ).fromEncoding( encoding ) );
+export const normalMap = nodeProxy( NormalMapNode );
+export const toneMapping = ( mapping, exposure, color ) => nodeObject( new ToneMappingNode( mapping, nodeObject( exposure ), nodeObject( color ) ) );
 
-export const normalGeometry = nodeObject( new NormalNode( NormalNode.GEOMETRY ) );
-export const normalLocal = nodeObject( new NormalNode( NormalNode.LOCAL ) );
-export const normalWorld = nodeObject( new NormalNode( NormalNode.WORLD ) );
-export const normalView = nodeObject( new NormalNode( NormalNode.VIEW ) );
-export const transformedNormalView = nodeObject( new VarNode( new NormalNode( NormalNode.VIEW ), 'TransformedNormalView', 'vec3' ) );
+// lights
 
-export const positionGeometry = nodeObject( new PositionNode( PositionNode.GEOMETRY ) );
-export const positionLocal = nodeObject( new PositionNode( PositionNode.LOCAL ) );
-export const positionWorld = nodeObject( new PositionNode( PositionNode.WORLD ) );
-export const positionView = nodeObject( new PositionNode( PositionNode.VIEW ) );
-export const positionViewDirection = nodeObject( new PositionNode( PositionNode.VIEW_DIRECTION ) );
+export const light = nodeProxy( LightNode );
+export const fromLights = ( lights ) => nodeObject( new LightsNode().fromLights( lights ) );
+export const lightContext = nodeProxy( LightContextNode );
 
-export const viewMatrix = nodeObject( new ModelNode( ModelNode.VIEW_MATRIX ) );
+// utils
 
-export const cameraPosition = nodeObject( new CameraNode( CameraNode.POSITION ) );
+export const matcapUV = nodeImmutable( MatcapUVNode );
+export const maxMipLevel = nodeProxy( MaxMipLevelNode );
 
-export const diffuseColor = nodeObject( new PropertyNode( 'DiffuseColor', 'vec4' ) );
-export const roughness = nodeObject( new PropertyNode( 'Roughness', 'float' ) );
-export const metalness = nodeObject( new PropertyNode( 'Metalness', 'float' ) );
-export const alphaTest = nodeObject( new PropertyNode( 'AlphaTest', 'float' ) );
-export const specularColor = nodeObject( new PropertyNode( 'SpecularColor', 'color' ) );
+export const oscSine = nodeProxy( OscNode, OscNode.SINE );
+export const oscSquare = nodeProxy( OscNode, OscNode.SQUARE );
+export const oscTriangle = nodeProxy( OscNode, OscNode.TRIANGLE );
+export const oscSawtooth = nodeProxy( OscNode, OscNode.SAWTOOTH );
 
-export const materialAlphaTest = nodeObject( new MaterialNode( MaterialNode.ALPHA_TEST ) );
-export const materialColor = nodeObject( new MaterialNode( MaterialNode.COLOR ) );
-export const materialOpacity = nodeObject( new MaterialNode( MaterialNode.OPACITY ) );
-export const materialSpecular = nodeObject( new MaterialNode( MaterialNode.SPECULAR ) );
-export const materialRoughness = nodeObject( new MaterialNode( MaterialNode.ROUGHNESS ) );
-export const materialMetalness = nodeObject( new MaterialNode( MaterialNode.METALNESS ) );
+export const spritesheetUV = nodeProxy( SpriteSheetUVNode );
 
-export const skinning = nodeProxy( SkinningNode );
-export const instance = nodeProxy( InstanceNode );
+export const timerLocal = nodeImmutable( TimerNode, TimerNode.LOCAL );
+export const timerGlobal = nodeImmutable( TimerNode, TimerNode.GLOBAL );
+export const timerDelta = nodeImmutable( TimerNode, TimerNode.DELTA );
 
-export const context = nodeProxy( ContextNode );
-export const lightContext = nodeProxy( LightContextNode );
+// procedural
 
-export const reflectedLight = nodeProxy( ReflectedLightNode );
+export const checker = nodeProxy( CheckerNode );
 
-export const colorSpace = ( node, encoding ) => nodeObject( new ColorSpaceNode( null, nodeObject( node ) ).fromEncoding( encoding ) );
+// fog
 
-export const bypass = nodeProxy( BypassNode );
-
-export const abs = nodeProxy( MathNode, 'abs' );
-export const acos = nodeProxy( MathNode, 'acos' );
-export const asin = nodeProxy( MathNode, 'asin' );
-export const atan = nodeProxy( MathNode, 'atan' );
-export const ceil = nodeProxy( MathNode, 'ceil' );
-export const clamp = nodeProxy( MathNode, 'clamp' );
-export const cos = nodeProxy( MathNode, 'cos' );
-export const cross = nodeProxy( MathNode, 'cross' );
-export const degrees = nodeProxy( MathNode, 'degrees' );
-export const dFdx = nodeProxy( MathNode, 'dFdx' );
-export const dFdy = nodeProxy( MathNode, 'dFdy' );
-export const distance = nodeProxy( MathNode, 'distance' );
-export const dot = nodeProxy( MathNode, 'dot' );
-export const exp = nodeProxy( MathNode, 'exp' );
-export const exp2 = nodeProxy( MathNode, 'exp2' );
-export const faceforward = nodeProxy( MathNode, 'faceforward' );
-export const floor = nodeProxy( MathNode, 'floor' );
-export const fract = nodeProxy( MathNode, 'fract' );
-export const invert = nodeProxy( MathNode, 'invert' );
-export const inversesqrt = nodeProxy( MathNode, 'inversesqrt' );
-export const length = nodeProxy( MathNode, 'length' );
-export const log = nodeProxy( MathNode, 'log' );
-export const log2 = nodeProxy( MathNode, 'log2' );
-export const max = nodeProxy( MathNode, 'max' );
-export const min = nodeProxy( MathNode, 'min' );
-export const mix = nodeProxy( MathNode, 'mix' );
-export const mod = nodeProxy( MathNode, 'mod' );
-export const negate = nodeProxy( MathNode, 'negate' );
-export const normalize = nodeProxy( MathNode, 'normalize' );
-export const pow = nodeProxy( MathNode, 'pow' );
-export const pow2 = nodeProxy( MathNode, 'pow', 2 );
-export const pow3 = nodeProxy( MathNode, 'pow', 3 );
-export const pow4 = nodeProxy( MathNode, 'pow', 4 );
-export const radians = nodeProxy( MathNode, 'radians' );
-export const reflect = nodeProxy( MathNode, 'reflect' );
-export const refract = nodeProxy( MathNode, 'refract' );
-export const round = nodeProxy( MathNode, 'round' );
-export const saturate = nodeProxy( MathNode, 'saturate' );
-export const sign = nodeProxy( MathNode, 'sign' );
-export const sin = nodeProxy( MathNode, 'sin' );
-export const smoothstep = nodeProxy( MathNode, 'smoothstep' );
-export const sqrt = nodeProxy( MathNode, 'sqrt' );
-export const step = nodeProxy( MathNode, 'step' );
-export const tan = nodeProxy( MathNode, 'tan' );
-export const transformDirection = nodeProxy( MathNode, 'transformDirection' );
-
-export const EPSILON = float( 1e-6 );
-export const INFINITY = float( 1e6 );
-
-export const dotNV = saturate( dot( transformedNormalView, positionViewDirection ) );
+export const fog = nodeProxy( FogNode );
+export const rangeFog = nodeProxy( FogRangeNode );

+ 0 - 250
examples/jsm/nodes/shadernode/ShaderNodeUtils.js

@@ -1,250 +0,0 @@
-import ArrayElementNode from '../utils/ArrayElementNode.js';
-import ConvertNode from '../utils/ConvertNode.js';
-import JoinNode from '../utils/JoinNode.js';
-import SplitNode from '../utils/SplitNode.js';
-import ConstNode from '../core/ConstNode.js';
-import { getValueFromType } from '../core/NodeUtils.js';
-
-export const shaderNodeHandler = {
-
-	construct( NodeClosure, params ) {
-
-		const inputs = params.shift();
-
-		return NodeClosure( new ShaderNodeObjects( inputs ), ...params );
-
-	},
-
-	get: function ( node, prop ) {
-
-		if ( typeof prop === 'string' && node[ prop ] === undefined ) {
-
-			if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true ) {
-
-				// accessing properties ( swizzle )
-
-				prop = prop
-					.replace( /r|s/g, 'x' )
-					.replace( /g|t/g, 'y' )
-					.replace( /b|p/g, 'z' )
-					.replace( /a|q/g, 'w' );
-
-				return new ShaderNodeObject( new SplitNode( node, prop ) );
-
-			} else if ( /^\d+$/.test( prop ) === true ) {
-
-				// accessing array
-
-				return new ShaderNodeObject( new ArrayElementNode( node, new ConstNode( Number( prop ), 'uint' ) ) );
-
-			}
-
-		}
-
-		return node[ prop ];
-
-	}
-
-};
-
-const nodeObjectsCacheMap = new WeakMap();
-
-const ShaderNodeObject = function ( obj ) {
-
-	const type = typeof obj;
-
-	if ( ( type === 'number' ) || ( type === 'boolean' ) ) {
-
-		return new ShaderNodeObject( getAutoTypedConstNode( obj ) );
-
-	} else if ( type === 'object' ) {
-
-		if ( obj.isNode === true ) {
-
-			let nodeObject = nodeObjectsCacheMap.get( obj );
-
-			if ( nodeObject === undefined ) {
-
-				nodeObject = new Proxy( obj, shaderNodeHandler );
-				nodeObjectsCacheMap.set( obj, nodeObject );
-				nodeObjectsCacheMap.set( nodeObject, nodeObject );
-
-			}
-
-			return nodeObject;
-
-		}
-
-	}
-
-	return obj;
-
-};
-
-const ShaderNodeObjects = function ( objects ) {
-
-	for ( const name in objects ) {
-
-		objects[ name ] = new ShaderNodeObject( objects[ name ] );
-
-	}
-
-	return objects;
-
-};
-
-const ShaderNodeArray = function ( array ) {
-
-	const len = array.length;
-
-	for ( let i = 0; i < len; i ++ ) {
-
-		array[ i ] = new ShaderNodeObject( array[ i ] );
-
-	}
-
-	return array;
-
-};
-
-const ShaderNodeProxy = function ( NodeClass, scope = null, factor = null ) {
-
-	if ( scope === null ) {
-
-		return ( ...params ) => {
-
-			return new ShaderNodeObject( new NodeClass( ...( new ShaderNodeArray( params ) ) ) );
-
-		};
-
-	} else if ( factor === null ) {
-
-		return ( ...params ) => {
-
-			return new ShaderNodeObject( new NodeClass( scope, ...( new ShaderNodeArray( params ) ) ) );
-
-		};
-
-	} else {
-
-		factor = new ShaderNodeObject( factor );
-
-		return ( ...params ) => {
-
-			return new ShaderNodeObject( new NodeClass( scope, ...( new ShaderNodeArray( params ) ), factor ) );
-
-		};
-
-	}
-
-};
-
-export const ShaderNodeScript = function ( jsFunc ) {
-
-	//@TODO: Move this to Node extended class
-
-	const self =
-	{
-		build: ( builder ) => {
-
-			self.call( {}, builder );
-
-			return '';
-
-		},
-
-		call: ( inputs, builder ) => {
-
-			inputs = new ShaderNodeObjects( inputs );
-
-			return new ShaderNodeObject( jsFunc( inputs, builder ) );
-
-		}
-	};
-
-	return self;
-
-};
-
-export const nodeObject = ( val ) => new ShaderNodeObject( val );
-export const nodeObjects = ( val ) => new ShaderNodeObjects( val );
-export const nodeArray = ( val ) => new ShaderNodeArray( val );
-export const nodeProxy = ( ...val ) => new ShaderNodeProxy( ...val );
-
-const bools = [ false, true ];
-const uints = [ 0, 1, 2, 3 ];
-const ints = [ - 1, - 2 ];
-const floats = [ 0.5, 1.5, 1 / 3, 1e-6, 1e6, Math.PI, Math.PI * 2, 1 / Math.PI, 2 / Math.PI, 1 / ( Math.PI * 2 ), Math.PI / 2 ];
-
-const boolsCacheMap = new Map();
-for ( let bool of bools ) boolsCacheMap.set( bool, new ConstNode( bool ) );
-
-const uintsCacheMap = new Map();
-for ( let uint of uints ) uintsCacheMap.set( uint, new ConstNode( uint, 'uint' ) );
-
-const intsCacheMap = new Map( [ ...uintsCacheMap ].map( el => new ConstNode( el.value, 'int' ) ) );
-for ( let int of ints ) intsCacheMap.set( int, new ConstNode( int, 'int' ) );
-
-const floatsCacheMap = new Map( [ ...intsCacheMap ].map( el => new ConstNode( el.value ) ) );
-for ( let float of floats ) floatsCacheMap.set( float, new ConstNode( float ) );
-for ( let float of floats ) floatsCacheMap.set( - float, new ConstNode( - float ) );
-
-export const cacheMaps = { bool: boolsCacheMap, uint: uintsCacheMap, ints: intsCacheMap, float: floatsCacheMap };
-
-const constNodesCacheMap = new Map( [ ...boolsCacheMap, ...floatsCacheMap ] );
-
-const getAutoTypedConstNode = ( value ) => {
-
-	if ( constNodesCacheMap.has( value ) ) {
-
-		return constNodesCacheMap.get( value );
-
-	} else if ( value.isNode === true ) {
-
-		return value;
-
-	} else {
-
-		return new ConstNode( value );
-
-	}
-
-};
-
-export const ConvertType = function ( type, cacheMap = null ) {
-
-	return ( ...params ) => {
-
-		if ( params.length === 0 ) {
-
-			return nodeObject( new ConstNode( getValueFromType( type ), type ) );
-
-		} else {
-
-			if ( type === 'color' && params[ 0 ].isNode !== true ) {
-
-				params = [ getValueFromType( type, ...params ) ];
-
-			}
-
-			if ( params.length === 1 && cacheMap !== null && cacheMap.has( params[ 0 ] ) ) {
-
-				return cacheMap.get( params[ 0 ] );
-
-			}
-
-			const nodes = params.map( getAutoTypedConstNode );
-
-			if ( nodes.length === 1 ) {
-
-				return nodeObject( nodes[ 0 ].nodeType === type ? nodes[ 0 ] : new ConvertNode( nodes[ 0 ], type ) );
-
-			}
-
-			return nodeObject( new ConvertNode( new JoinNode( nodes ), type ) );
-
-		}
-
-	};
-
-};

+ 3 - 3
examples/jsm/nodes/utils/MatcapUVNode.js

@@ -1,5 +1,5 @@
 import TempNode from '../core/TempNode.js';
-import { join, negate, normalize, cross, dot, mul, add, transformedNormalView, positionViewDirection } from '../shadernode/ShaderNodeElements.js';
+import { vec2, vec3, negate, normalize, cross, dot, mul, add, transformedNormalView, positionViewDirection } from '../shadernode/ShaderNodeBaseElements.js';
 
 class MatcapUVNode extends TempNode {
 
@@ -11,10 +11,10 @@ class MatcapUVNode extends TempNode {
 
 	generate( builder ) {
 
-		const x = normalize( join( positionViewDirection.z, 0, negate( positionViewDirection.x ) ) );
+		const x = normalize( vec3( positionViewDirection.z, 0, negate( positionViewDirection.x ) ) );
 		const y = cross( positionViewDirection, x );
 
-		const uv = add( mul( join( dot( x, transformedNormalView ), dot( y, transformedNormalView ) ), 0.495 ), 0.5 );
+		const uv = add( mul( vec2( dot( x, transformedNormalView ), dot( y, transformedNormalView ) ), 0.495 ), 0.5 );
 
 		return uv.build( builder, this.getNodeType( builder ) );
 

+ 1 - 1
examples/jsm/nodes/utils/OscNode.js

@@ -1,6 +1,6 @@
 import Node from '../core/Node.js';
 import TimerNode from './TimerNode.js';
-import { abs, fract, round, sin, add, sub, mul } from '../shadernode/ShaderNodeElements.js';
+import { abs, fract, round, sin, add, sub, mul } from '../shadernode/ShaderNodeBaseElements.js';
 
 class OscNode extends Node {
 

+ 3 - 3
examples/webgpu_compute.html

@@ -29,7 +29,7 @@
 			import * as Nodes from 'three-nodes/Nodes.js';
 
 			import {
-				ShaderNode, compute,
+				ShaderNode, compute, context,
 				uniform, element, storage, attribute,
 				temp, assign, add, sub, cond, abs, negate, max, min, length, vec3, color,
 				greaterThanEqual, lessThanEqual, instanceIndex
@@ -99,8 +99,8 @@
 					const pointer = uniform( pointerVector );
 					const limit = uniform( scaleVector );
 
-					const position = temp( vec3() );
-					assign( position, add( particle, velocity ) ).build( builder ); // workaround
+					const position = temp( context( add( particle, velocity ), { temp: false } ) );
+					position.build( builder );
 
 					assign( velocity.x, cond( greaterThanEqual( abs( position.x ), limit.x ), negate( velocity.x ), velocity.x ) ).build( builder );
 					assign( velocity.y, cond( greaterThanEqual( abs( position.y ), limit.y ), negate( velocity.y ), velocity.y ) ).build( builder );