Browse Source

Update ConvertType (#23635)

* Flat params

* Remove valueComponents

* Lint

* Lint

* Reuse functions from InputNode.js

* Fix

* Fix

* Add cache

* Move ArrayMap and flatArray

* Revert valueComponents' removal

* Fix ArrayMap

* Fix

* Fix

* Fix

* Add size cap to ArrayMap

* Fix

* Rework ConvertType

* Fix

* Another fix

* Fix uints in NodeBuilder

* Change ArrayMap cache to just Map

* optional params

* fix color type

* fix uniform

* recovering bad fix conflict

* static cacheMap

* cleanup

* Two cache maps

* Cleanup

* Fix

* Add constants' cache to ShaderNodeObject

* Fix

* Simplify cache

* Fix

* Fix typo

* fix negate cache

* cleanup

Co-authored-by: sunag <[email protected]>
LeviPesin 3 years ago
parent
commit
3b5ad8895e

+ 116 - 71
examples/jsm/nodes/ShaderNode.js

@@ -25,8 +25,8 @@ import ConvertNode from './utils/ConvertNode.js';
 import JoinNode from './utils/JoinNode.js';
 import SplitNode from './utils/SplitNode.js';
 
-// core
-import { Vector2, Vector3, Vector4, Matrix3, Matrix4, Color } from 'three';
+// utils
+import { getValueFromType } from './core/NodeUtils.js';
 
 const NodeHandler = {
 
@@ -58,7 +58,7 @@ const NodeHandler = {
 
 				// accessing array
 
-				return new ShaderNodeObject( new ArrayElementNode( node, new ConstNode( Number( prop ), 'uint' ) ) );
+				return new ShaderNodeObject( new ArrayElementNode( node, uint( Number( prop ) ) ) );
 
 			}
 
@@ -72,13 +72,13 @@ const NodeHandler = {
 
 const nodeObjects = new WeakMap();
 
-const ShaderNodeObject = function( obj ) {
+const ShaderNodeObject = function ( obj ) {
 
 	const type = typeof obj;
 
 	if ( ( type === 'number' ) || ( type === 'boolean' ) ) {
 
-		return new ShaderNodeObject( new ConstNode( obj ) );
+		return new ShaderNodeObject( getAutoTypedConstNode( obj ) );
 
 	} else if ( type === 'object' ) {
 
@@ -104,7 +104,7 @@ const ShaderNodeObject = function( obj ) {
 
 };
 
-const ShaderNodeObjects = function( objects ) {
+const ShaderNodeObjects = function ( objects ) {
 
 	for ( const name in objects ) {
 
@@ -130,7 +130,7 @@ const getShaderNodeArray = ( array ) => {
 
 };
 
-const ShaderNodeProxy = function( NodeClass, scope = null, factor = null ) {
+const ShaderNodeProxy = function ( NodeClass, scope = null, factor = null ) {
 
 	if ( scope === null ) {
 
@@ -174,21 +174,94 @@ const ShaderNodeScript = function ( jsFunc ) {
 
 };
 
-export const ShaderNode = new Proxy( ShaderNodeScript, NodeHandler );
+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 ) );
+
+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 );
+
+	}
+
+};
+
+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 );
+
+			return nodeObject( new ConvertNode( nodes.length === 1 ? nodes[ 0 ] : new JoinNode( nodes ), type ) );
+
+		}
+
+	};
+
+};
 
 //
 // Node Material Shader Syntax
 //
 
+export const ShaderNode = new Proxy( ShaderNodeScript, NodeHandler );
+
 export const nodeObject = ( val ) => {
 
 	return new ShaderNodeObject( val );
 
 };
 
-export const uniform = ( constNode ) => {
+export const uniform = ( value ) => {
+
+	// TODO: get ConstNode from .traverse() in the future
+	value = value.isNode === true ? value.node?.value || value.value : value;
 
-	return nodeObject( new UniformNode( constNode.value, constNode.nodeType ) );
+	return nodeObject( new UniformNode( value, value.nodeType ) );
 
 };
 
@@ -210,66 +283,37 @@ export const label = ( node, name ) => {
 
 export const temp = ( node ) => nodeObject( new VarNode( nodeObject( node ) ) );
 
-const ConvertType = function ( type, valueClass = null, valueComponents = 1 ) {
+export const color = new ConvertType( 'color' );
 
-	return ( ...params ) => {
-
-		if ( params[ 0 ]?.isNode === true ) {
+export const float = new ConvertType( 'float', floatsCacheMap );
+export const int = new ConvertType( 'int', intsCacheMap );
+export const uint = new ConvertType( 'uint', uintsCacheMap );
+export const bool = new ConvertType( 'bool', boolsCacheMap );
 
-			return nodeObject( new ConvertNode( params[ 0 ], type ) );
-
-		}
+export const vec2 = new ConvertType( 'vec2' );
+export const ivec2 = new ConvertType( 'ivec2' );
+export const uvec2 = new ConvertType( 'uvec2' );
+export const bvec2 = new ConvertType( 'bvec2' );
 
-		if ( ( params.length === 1 ) && ( valueComponents !== 1 ) ) {
+export const vec3 = new ConvertType( 'vec3' );
+export const ivec3 = new ConvertType( 'ivec3' );
+export const uvec3 = new ConvertType( 'uvec3' );
+export const bvec3 = new ConvertType( 'bvec3' );
 
-			// Providing one scalar value: This value is used for all components
+export const vec4 = new ConvertType( 'vec4' );
+export const ivec4 = new ConvertType( 'ivec4' );
+export const uvec4 = new ConvertType( 'uvec4' );
+export const bvec4 = new ConvertType( 'bvec4' );
 
-			for ( let i = 1; i < valueComponents; i ++ ) {
+export const mat3 = new ConvertType( 'mat3' );
+export const imat3 = new ConvertType( 'imat3' );
+export const umat3 = new ConvertType( 'umat3' );
+export const bmat3 = new ConvertType( 'bmat3' );
 
-				params[ i ] = params [ 0 ];
-
-			}
-
-		}
-
-		const val = ( ( valueClass === null ) || ( params[ 0 ] instanceof valueClass ) ) ? params[ 0 ] : new valueClass().set( ...params );
-
-		return nodeObject( new ConstNode( val, type ) );
-
-	};
-
-};
-
-export const float = new ConvertType( 'float' );
-export const int = new ConvertType( 'int' );
-export const uint = new ConvertType( 'uint' );
-export const bool = new ConvertType( 'bool' );
-export const color = new ConvertType( 'color', Color );
-
-export const vec2 = new ConvertType( 'vec2', Vector2, 2 );
-export const ivec2 = new ConvertType( 'ivec2', Vector2, 2 );
-export const uvec2 = new ConvertType( 'uvec2', Vector2, 2 );
-export const bvec2 = new ConvertType( 'bvec2', Vector2, 2 );
-
-export const vec3 = new ConvertType( 'vec3', Vector3, 3 );
-export const ivec3 = new ConvertType( 'ivec3', Vector3, 3 );
-export const uvec3 = new ConvertType( 'uvec3', Vector3, 3 );
-export const bvec3 = new ConvertType( 'bvec3', Vector3, 3 );
-
-export const vec4 = new ConvertType( 'vec4', Vector4, 4 );
-export const ivec4 = new ConvertType( 'ivec4', Vector4, 4 );
-export const uvec4 = new ConvertType( 'uvec4', Vector4, 4 );
-export const bvec4 = new ConvertType( 'bvec4', Vector4, 4 );
-
-export const mat3 = new ConvertType( 'mat3', Matrix3 );
-export const imat3 = new ConvertType( 'imat3', Matrix3 );
-export const umat3 = new ConvertType( 'umat3', Matrix3 );
-export const bmat3 = new ConvertType( 'bmat3', Matrix3 );
-
-export const mat4 = new ConvertType( 'mat4', Matrix4 );
-export const imat4 = new ConvertType( 'imat4', Matrix4 );
-export const umat4 = new ConvertType( 'umat4', Matrix4 );
-export const bmat4 = new ConvertType( 'bmat4', Matrix4 );
+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 join = ( ...params ) => nodeObject( new JoinNode( getShaderNodeArray( params ) ) );
 
@@ -325,13 +369,6 @@ export const viewMatrix = new ShaderNodeObject( new ModelNode( ModelNode.VIEW_MA
 
 export const cameraPosition = new ShaderNodeObject( new CameraNode( CameraNode.POSITION ) );
 
-export const PI = float( 3.141592653589793 );
-export const PI2 = float( 6.283185307179586 );
-export const PI_HALF = float( 1.5707963267948966 );
-export const RECIPROCAL_PI = float( 0.3183098861837907 );
-export const RECIPROCAL_PI2 = float( 0.15915494309189535 );
-export const EPSILON = float( 1e-6 );
-
 export const diffuseColor = new ShaderNodeObject( new PropertyNode( 'DiffuseColor', 'vec4' ) );
 export const roughness = new ShaderNodeObject( new PropertyNode( 'Roughness', 'float' ) );
 export const metalness = new ShaderNodeObject( new PropertyNode( 'Metalness', 'float' ) );
@@ -383,3 +420,11 @@ export const sqrt = new ShaderNodeProxy( MathNode, 'sqrt' );
 export const step = new ShaderNodeProxy( MathNode, 'step' );
 export const tan = new ShaderNodeProxy( MathNode, 'tan' );
 export const transformDirection = new ShaderNodeProxy( MathNode, 'transformDirection' );
+
+export const PI = float( Math.PI );
+export const PI2 = float( Math.PI * 2 );
+export const PI_HALF = float( Math.PI / 2 );
+export const RECIPROCAL_PI = float( 1 / Math.PI );
+export const RECIPROCAL_PI2 = float( 1 / ( 2 * Math.PI ) );
+export const EPSILON = float( 1e-6 );
+export const INFINITY = float( 1e6 );

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

@@ -1,77 +1,5 @@
-import { Color, Matrix3, Matrix4, Vector2, Vector3, Vector4 } from 'three';
 import Node from './Node.js';
-
-function getValueType( value ) {
-
-	if ( typeof value === 'number' ) {
-
-		return 'float';
-
-	} else if ( typeof value === 'boolean' ) {
-
-		return 'bool';
-
-	} else if ( value?.isVector2 === true ) {
-
-		return 'vec2';
-
-	} else if ( value?.isVector3 === true ) {
-
-		return 'vec3';
-
-	} else if ( value?.isVector4 === true ) {
-
-		return 'vec4';
-
-	} else if ( value?.isMatrix3 === true ) {
-
-		return 'mat3';
-
-	} else if ( value?.isMatrix4 === true ) {
-
-		return 'mat4';
-
-	} else if ( value?.isColor === true ) {
-
-		return 'color';
-
-	}
-
-	return null;
-
-}
-
-function getValueFromType( type ) {
-
-	if ( type === 'color' ) {
-
-		return new Color();
-
-	} else if ( type === 'vec2' ) {
-
-		return new Vector2();
-
-	} else if ( type === 'vec3' ) {
-
-		return new Vector3();
-
-	} else if ( type === 'vec4' ) {
-
-		return new Vector4();
-
-	} else if ( type === 'mat3' ) {
-
-		return new Matrix3();
-
-	} else if ( type === 'mat4' ) {
-
-		return new Matrix4();
-
-	}
-
-	return null;
-
-}
+import { getValueType, getValueFromType } from './NodeUtils.js';
 
 class InputNode extends Node {
 

+ 1 - 1
examples/jsm/nodes/core/NodeBuilder.js

@@ -171,7 +171,7 @@ class NodeBuilder {
 
 		if ( type === 'float' ) return toFloat( value );
 		if ( type === 'int' ) return `${ Math.round( value ) }`;
-		if ( type === 'uint' ) return value >= 0 ? `${ Math.round( value ) }` : '0';
+		if ( type === 'uint' ) return value >= 0 ? `${ Math.round( value ) }u` : '0u';
 		if ( type === 'bool' ) return value ? 'true' : 'false';
 		if ( type === 'color' ) return `${ this.getType( 'vec3' ) }( ${ toFloat( value.r ) }, ${ toFloat( value.g ) }, ${ toFloat( value.b ) } )`;
 

+ 84 - 0
examples/jsm/nodes/core/NodeUtils.js

@@ -1,3 +1,5 @@
+import { Color, Matrix3, Matrix4, Vector2, Vector3, Vector4 } from 'three';
+
 export const getNodesKeys = ( object ) => {
 
 	const props = [];
@@ -17,3 +19,85 @@ export const getNodesKeys = ( object ) => {
 	return props;
 
 };
+
+export const getValueType = ( value ) => {
+
+	if ( typeof value === 'number' ) {
+
+		return 'float';
+
+	} else if ( typeof value === 'boolean' ) {
+
+		return 'bool';
+
+	} else if ( value?.isVector2 === true ) {
+
+		return 'vec2';
+
+	} else if ( value?.isVector3 === true ) {
+
+		return 'vec3';
+
+	} else if ( value?.isVector4 === true ) {
+
+		return 'vec4';
+
+	} else if ( value?.isMatrix3 === true ) {
+
+		return 'mat3';
+
+	} else if ( value?.isMatrix4 === true ) {
+
+		return 'mat4';
+
+	} else if ( value?.isColor === true ) {
+
+		return 'color';
+
+	}
+
+	return null;
+
+};
+
+export const getValueFromType = ( type, ...params ) => {
+
+	const last4 = type?.slice( -4 );
+
+	if ( type === 'color' ) {
+
+		return new Color( ...params );
+
+	} else if ( last4 === 'vec2' ) {
+
+		return new Vector2( ...params );
+
+	} else if ( last4 === 'vec3' ) {
+
+		return new Vector3( ...params );
+
+	} else if ( last4 === 'vec4' ) {
+
+		return new Vector4( ...params );
+
+	} else if ( last4 === 'mat3' ) {
+
+		return new Matrix3( ...params );
+
+	} else if ( last4 === 'mat4' ) {
+
+		return new Matrix4( ...params );
+
+	} else if ( type === 'bool' ) {
+
+		return false;
+
+	} else if ( ( type === 'float' ) || ( type === 'int' ) || ( type === 'uint' ) ) {
+
+		return 0;
+
+	}
+
+	return null;
+
+};

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

@@ -24,7 +24,7 @@ class ConvertNode extends Node {
 		const convertToSnippet = builder.getType( convertTo );
 		const nodeSnippet = this.node.build( builder, convertTo );
 
-		return `${ convertToSnippet }( ${ nodeSnippet } )`;
+		return `${ builder.getVectorType( convertToSnippet ) }( ${ nodeSnippet } )`;
 
 	}