Browse Source

NodeMaterial: Revision and updates (#22878)

* optimize to bvec, ivec and uvec

* greaterThan and lessThanEqual returns vector if need

* ConvertNode: Convert a node type manually

* add lessThanEqual, mix

* support to manually vector convert: e.g: vec3 ( node )

* Support to sRGBToLinear

* Sync with https://github.com/mrdoob/three.js/pull/22759
sunag 3 years ago
parent
commit
5a6e9c0c04

+ 1 - 0
examples/jsm/renderers/nodes/Nodes.js

@@ -63,6 +63,7 @@ import LightsNode from './lights/LightsNode.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';

+ 42 - 15
examples/jsm/renderers/nodes/ShaderNode.js

@@ -20,6 +20,7 @@ import MathNode from './math/MathNode.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';
 
@@ -208,43 +209,67 @@ export const cond = ( ...params ) => {
 
 export const vec2 = ( ...params ) => {
 
-	// Providing one scalar value: This value is used for all components
+	if ( params[0]?.isNode === true ) {
 
-	if ( params.length === 1 ) {
+		return ShaderNodeObject( new ConvertNode( params[0], 'vec2' ) );
 
-		params[ 1 ] = params[ 0 ];
+	} else {
 
-	}
+		// Providing one scalar value: This value is used for all components
+
+		if ( params.length === 1 ) {
+
+			params[ 1 ] = params[ 0 ];
+
+		}
 
-	return ShaderNodeObject( new Vector2Node( new Vector2( ...params ) ).setConst( true ) );
+		return ShaderNodeObject( new Vector2Node( new Vector2( ...params ) ).setConst( true ) );
+
+	}
 
 };
 
 export const vec3 = ( ...params ) => {
 
-	// Providing one scalar value: This value is used for all components
+	if ( params[0]?.isNode === true ) {
+
+		return ShaderNodeObject( new ConvertNode( params[0], 'vec3' ) );
 
-	if ( params.length === 1 ) {
+	} else {
 
-		params[ 1 ] = params[ 2 ] = params[ 0 ];
+		// Providing one scalar value: This value is used for all components
 
-	}
+		if ( params.length === 1 ) {
+
+			params[ 1 ] = params[ 2 ] = params[ 0 ];
 
-	return ShaderNodeObject( new Vector3Node( new Vector3( ...params ) ).setConst( true ) );
+		}
+
+		return ShaderNodeObject( new Vector3Node( new Vector3( ...params ) ).setConst( true ) );
+
+	}
 
 };
 
 export const vec4 = ( ...params ) => {
 
-	// Providing one scalar value: This value is used for all components
+	if ( params[0]?.isNode === true ) {
 
-	if ( params.length === 1 ) {
+		return ShaderNodeObject( new ConvertNode( params[0], 'vec4' ) );
 
-		params[ 1 ] = params[ 2 ] = params[ 3 ] = params[ 0 ];
+	} else {
 
-	}
+		// Providing one scalar value: This value is used for all components
 
-	return ShaderNodeObject( new Vector4Node( new Vector4( ...params ) ).setConst( true ) );
+		if ( params.length === 1 ) {
+
+			params[ 1 ] = params[ 2 ] = params[ 3 ] = params[ 0 ];
+
+		}
+
+		return ShaderNodeObject( new Vector4Node( new Vector4( ...params ) ).setConst( true ) );
+
+	}
 
 };
 
@@ -263,6 +288,7 @@ export const div = ShaderNodeProxy( OperatorNode, '/' );
 export const equal = ShaderNodeProxy( OperatorNode, '==' );
 export const assign = ShaderNodeProxy( OperatorNode, '=' );
 export const greaterThan = ShaderNodeProxy( OperatorNode, '>' );
+export const lessThanEqual = ShaderNodeProxy( OperatorNode, '<=' );
 export const and = ShaderNodeProxy( OperatorNode, '&&' );
 
 export const element = ShaderNodeProxy( ArrayElementNode );
@@ -314,5 +340,6 @@ export const pow3 = ShaderNodeProxy( MathNode, 'pow', 3 );
 export const pow4 = ShaderNodeProxy( MathNode, 'pow', 4 );
 export const exp = ShaderNodeProxy( MathNode, 'exp' );
 export const exp2 = ShaderNodeProxy( MathNode, 'exp2' );
+export const mix = ShaderNodeProxy( MathNode, 'mix' );
 export const saturate = ShaderNodeProxy( MathNode, 'saturate' );
 export const transformDirection = ShaderNodeProxy( MathNode, 'transformDirection' );

+ 3 - 4
examples/jsm/renderers/nodes/core/NodeBuilder.js

@@ -258,11 +258,10 @@ class NodeBuilder {
 	getTypeLength( type ) {
 
 		const vecType = this.getVectorType( type );
+		const vecNum = /vec([2-4])/.exec( vecType );
 
-		if ( vecType === 'float' ) return 1;
-		if ( vecType === 'vec2' ) return 2;
-		if ( vecType === 'vec3' ) return 3;
-		if ( vecType === 'vec4' ) return 4;
+		if ( vecNum !== null ) return Number( vecNum[ 1 ] );
+		if ( vecType === 'float' || vecType === 'bool' ) return 1;
 
 		return 0;
 

+ 1 - 1
examples/jsm/renderers/nodes/core/TempNode.js

@@ -10,7 +10,7 @@ class TempNode extends Node {
 
 	build( builder, output ) {
 
-		const type = builder.getVectorType( this.getNodeType( builder ) );
+		const type = builder.getVectorType( this.getNodeType( builder, output ) );
 
 		if ( builder.context.temp !== false && type !== 'void ' && output !== 'void' ) {
 

+ 29 - 9
examples/jsm/renderers/nodes/display/ColorSpaceNode.js

@@ -1,8 +1,8 @@
 import TempNode from '../core/Node.js';
-import { ShaderNode } from '../ShaderNode.js';
+import { ShaderNode, vec3, pow, mul, add, mix, join, lessThanEqual } from '../ShaderNode.js';
 
-import { LinearEncoding/*,
-	sRGBEncoding, RGBEEncoding, RGBM7Encoding, RGBM16Encoding,
+import { LinearEncoding,
+	sRGBEncoding/*, RGBEEncoding, RGBM7Encoding, RGBM16Encoding,
 	RGBDEncoding, GammaEncoding*/ } from 'three';
 
 export const LinearToLinear = new ShaderNode( ( inputs ) => {
@@ -11,15 +11,36 @@ export const LinearToLinear = new ShaderNode( ( inputs ) => {
 
 } );
 
+export const sRGBToLinear = new ShaderNode( ( inputs ) => {
+
+	const { value } = inputs;
+
+	const rgb = value.rgb;
+
+	const a = pow( add( mul( rgb, 0.9478672986 ), vec3( 0.0521327014 ) ), vec3( 2.4 ) );
+	const b = mul( rgb, 0.0773993808 );
+	const factor = vec3( lessThanEqual( rgb, vec3( 0.04045 ) ) );
+
+	const rgbResult = mix( a, b, factor );
+
+	return join( rgbResult.r, rgbResult.g, rgbResult.b, value.a );
+
+} );
+
+const EncodingLib = {
+	LinearToLinear,
+	sRGBToLinear
+};
+
 function getEncodingComponents ( encoding ) {
 
 	switch ( encoding ) {
 
 		case LinearEncoding:
 			return [ 'Linear' ];
-/*
 		case sRGBEncoding:
 			return [ 'sRGB' ];
+/*
 		case RGBEEncoding:
 			return [ 'RGBE' ];
 		case RGBM7Encoding:
@@ -38,12 +59,12 @@ function getEncodingComponents ( encoding ) {
 class ColorSpaceNode extends TempNode {
 
 	static LINEAR_TO_LINEAR = 'LinearToLinear';
-/*
-	static GAMMA_TO_LINEAR = 'GammaToLinear';
-	static LINEAR_TO_GAMMA = 'LinearToGamma';
 
 	static SRGB_TO_LINEAR = 'sRGBToLinear';
 	static LINEAR_TO_SRGB = 'LinearTosRGB';
+/*
+	static GAMMA_TO_LINEAR = 'GammaToLinear';
+	static LINEAR_TO_GAMMA = 'LinearToGamma';
 
 	static RGBE_TO_LINEAR = 'RGBEToLinear';
 	static LINEAR_TO_RGBE = 'LinearToRGBE';
@@ -96,8 +117,7 @@ class ColorSpaceNode extends TempNode {
 
 		if ( method !== ColorSpaceNode.LINEAR_TO_LINEAR ) {
 
-			// disable for now color space
-			const encodingFunctionNode = LinearToLinear;
+			const encodingFunctionNode = EncodingLib[ method ];			
 			const factor = this.factor;
 
 			return encodingFunctionNode( {

+ 19 - 3
examples/jsm/renderers/nodes/math/OperatorNode.js

@@ -27,7 +27,7 @@ class OperatorNode extends TempNode {
 
 	}
 
-	getNodeType( builder ) {
+	getNodeType( builder, output ) {
 
 		const op = this.op;
 
@@ -45,10 +45,16 @@ class OperatorNode extends TempNode {
 
 			return typeA;
 
-		} else if ( op === '==' || op === '>' || op === '&&' ) {
+		} else if ( op === '==' || op === '&&' ) {
 
 			return 'bool';
 
+		} else if ( op === '<=' || op === '>' ) {
+
+			const length = builder.getTypeLength( output );
+
+			return length > 1 ? `bvec${ length }` : 'bool';
+
 		} else {
 
 			if ( typeA === 'float' && builder.isMatrix( typeB ) ) {
@@ -88,7 +94,7 @@ class OperatorNode extends TempNode {
 		const aNode = this.aNode;
 		const bNode = this.bNode;
 
-		const type = this.getNodeType( builder );
+		const type = this.getNodeType( builder, output );
 
 		let typeA = null;
 		let typeB = null;
@@ -131,6 +137,8 @@ class OperatorNode extends TempNode {
 		const a = aNode.build( builder, typeA );
 		const b = bNode.build( builder, typeB );
 
+		const outputLength = builder.getTypeLength( output );
+
 		if ( output !== 'void' ) {
 
 			if ( op === '=' ) {
@@ -139,6 +147,14 @@ class OperatorNode extends TempNode {
 
 				return a;
 
+			} else if ( op === '>' && outputLength > 1 ) {
+
+				return `greaterThan( ${a}, ${b} )`;
+
+			} else if ( op === '<=' && outputLength > 1 ) {
+
+				return `lessThanEqual( ${a}, ${b} )`;
+
 			} else {
 
 				return `( ${a} ${this.op} ${b} )`;

+ 33 - 0
examples/jsm/renderers/nodes/utils/ConvertNode.js

@@ -0,0 +1,33 @@
+import Node from '../core/Node.js';
+
+class ConvertNode extends Node {
+
+	constructor( node, convertTo ) {
+
+		super();
+
+		this.node = node;
+		this.convertTo = convertTo;
+
+	}
+
+	getNodeType( /*builder*/ ) {
+
+		return this.convertTo;
+
+	}
+
+	generate( builder ) {
+
+		const convertTo = this.convertTo;
+
+		const convertToSnippet = builder.getType( convertTo );
+		const nodeSnippet = this.node.build( builder, convertTo );
+
+		return `${ convertToSnippet }( ${ nodeSnippet } )`;
+
+	}
+
+}
+
+export default ConvertNode;

+ 2 - 2
examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js

@@ -285,7 +285,7 @@ class WebGLNodeBuilder extends NodeBuilder {
 	}
 
 	getTextureEncodingFromMap( map ) {
-
+/*
 		const isWebGL2 = this.renderer.capabilities.isWebGL2;
 
 		if ( isWebGL2 && map && map.isTexture && map.format === RGBAFormat && map.type === UnsignedByteType && map.encoding === sRGBEncoding ) {
@@ -293,7 +293,7 @@ class WebGLNodeBuilder extends NodeBuilder {
 			return LinearEncoding; // disable inline decode for sRGB textures in WebGL 2
 
 		}
-
+*/
 		return super.getTextureEncodingFromMap( map );
 
 	}