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

ShaderNode: MaterialX Procedural functions and overloading support (#24699)

* move lib to parent folder

* Added overloading support

* Added convert()

* Added MaterialX Procedural functions

* update example
sunag 2 жил өмнө
parent
commit
7aa0748cb9

+ 3 - 0
examples/jsm/nodes/Nodes.js

@@ -114,6 +114,9 @@ export * from './materials/Materials.js';
 // shader node
 // shader node
 export * from './shadernode/ShaderNodeElements.js';
 export * from './shadernode/ShaderNodeElements.js';
 
 
+// extensions
+export * from './materialx/MaterialXNodes.js';
+
 // shader stages
 // shader stages
 export { defaultShaderStages } from './core/NodeBuilder.js';
 export { defaultShaderStages } from './core/NodeBuilder.js';
 
 

+ 55 - 0
examples/jsm/nodes/materialx/MaterialXNodes.js

@@ -0,0 +1,55 @@
+import {
+	mx_perlin_noise_float, mx_perlin_noise_vec2, mx_perlin_noise_vec3,
+	mx_worley_noise_float as worley_noise_float, mx_worley_noise_vec2 as worley_noise_vec2, mx_worley_noise_vec3 as worley_noise_vec3,
+	mx_cell_noise_float as cell_noise_float,
+	mx_fractal_noise_float as fractal_noise_float, mx_fractal_noise_vec2 as fractal_noise_vec2, mx_fractal_noise_vec3 as fractal_noise_vec3, mx_fractal_noise_vec4 as fractal_noise_vec4
+} from './lib/mx_noise.js';
+import { mx_hsvtorgb, mx_rgbtohsv } from './lib/mx_hsv.js';
+import { nodeObject, float, vec2, vec4, add, sub, mul, mix, clamp, uv, length, smoothstep, dFdx, dFdy, convert } from '../shadernode/ShaderNodeElements.js';
+
+export const mx_aastep = ( threshold, value ) => {
+
+	threshold = float( threshold );
+	value = float( value );
+
+	const afwidth = mul( length( vec2( dFdx( value ), dFdy( value ) ) ), 0.70710678118654757 );
+
+	return smoothstep( sub( threshold, afwidth ), add( threshold, afwidth ), value );
+
+};
+
+const _ramp = ( a, b, uv, p ) => mix( a, b, clamp( nodeObject( uv )[ p ] ) );
+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 ] ) );
+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_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 );
+export const mx_noise_vec4 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => {
+
+	texcoord = convert( texcoord, 'vec2|vec3' ); // overloading type
+
+	const noise_vec4 = vec4( mx_perlin_noise_vec3( texcoord ), mx_perlin_noise_float( add( texcoord, vec2( 19, 73 ) ) ) );
+
+	return add( mul( amplitude, noise_vec4 ), 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_cell_noise_float = ( texcoord = uv() ) => cell_noise_float( convert( texcoord, '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 { mx_hsvtorgb, mx_rgbtohsv };

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

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

+ 13 - 3
examples/jsm/nodes/materialx/functions/lib/mx_noise.js → examples/jsm/nodes/materialx/lib/mx_noise.js

@@ -1,4 +1,4 @@
-import { code, fn } from '../../../Nodes.js';
+import { code, fn } from '../../Nodes.js';
 
 
 // Original shader code from:
 // Original shader code from:
 // https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_noise.glsl
 // https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/stdlib/genglsl/lib/mx_noise.glsl
@@ -601,7 +601,17 @@ vec3 mx_worley_noise_vec3(vec3 p, float jitter, int metric)
 
 
 const includes = [ mx_noise ];
 const includes = [ mx_noise ];
 
 
-export const mx_perlin_noise_float = fn( 'float mx_perlin_noise_float( vec3 p )', includes );
+export const mx_perlin_noise_float = fn( 'float mx_perlin_noise_float( any p )', includes );
+export const mx_perlin_noise_vec2 = fn( 'vec2 mx_perlin_noise_vec2( any p )', includes );
+export const mx_perlin_noise_vec3 = fn( 'vec3 mx_perlin_noise_vec3( any p )', includes );
+
 export const mx_cell_noise_float = fn( 'float mx_cell_noise_float( vec3 p )', includes );
 export const mx_cell_noise_float = fn( 'float mx_cell_noise_float( vec3 p )', includes );
-export const mx_worley_noise_float = fn( 'float mx_worley_noise_float( vec3 p, float jitter, int metric )', includes );
+
+export const mx_worley_noise_float = fn( 'float mx_worley_noise_float( any p, float jitter, int metric )', includes );
+export const mx_worley_noise_vec2 = fn( 'float mx_worley_noise_vec2( any p, float jitter, int metric )', includes );
+export const mx_worley_noise_vec3 = fn( 'float mx_worley_noise_vec3( any p, float jitter, int metric )', includes );
+
 export const mx_fractal_noise_float = fn( 'float mx_fractal_noise_float( vec3 p, int octaves, float lacunarity, float diminish )', includes );
 export const mx_fractal_noise_float = fn( 'float mx_fractal_noise_float( vec3 p, int octaves, float lacunarity, float diminish )', includes );
+export const mx_fractal_noise_vec2 = fn( 'float mx_fractal_noise_vec2( vec3 p, int octaves, float lacunarity, float diminish )', includes );
+export const mx_fractal_noise_vec3 = fn( 'float mx_fractal_noise_vec3( vec3 p, int octaves, float lacunarity, float diminish )', includes );
+export const mx_fractal_noise_vec4 = fn( 'float mx_fractal_noise_vec4( vec3 p, int octaves, float lacunarity, float diminish )', includes );

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

@@ -116,6 +116,8 @@ export const fn = ( code, includes ) => func( code, includes ).call;
 export const attribute = ( name, nodeType ) => nodeObject( new AttributeNode( name, nodeType ) );
 export const attribute = ( name, nodeType ) => nodeObject( new AttributeNode( name, nodeType ) );
 export const property = ( name, nodeOrType ) => nodeObject( new PropertyNode( name, getConstNodeType( nodeOrType ) ) );
 export const property = ( name, nodeOrType ) => nodeObject( new PropertyNode( name, getConstNodeType( nodeOrType ) ) );
 
 
+export const convert = ( node, types ) => nodeObject( new ConvertNode( nodeObject( node ), types ) );
+
 export const bypass = nodeProxy( BypassNode );
 export const bypass = nodeProxy( BypassNode );
 export const code = nodeProxy( CodeNode );
 export const code = nodeProxy( CodeNode );
 export const context = nodeProxy( ContextNode );
 export const context = nodeProxy( ContextNode );

+ 15 - 14
examples/jsm/nodes/utils/ConvertNode.js

@@ -11,31 +11,32 @@ class ConvertNode extends Node {
 
 
 	}
 	}
 
 
-	getNodeType( /*builder*/ ) {
+	getNodeType( builder ) {
 
 
-		return this.convertTo;
+		const requestType = this.node.getNodeType( builder );
 
 
-	}
+		let convertTo = null;
 
 
-	generate( builder, output ) {
+		for ( const overloadingType of this.convertTo.split( '|' ) ) {
 
 
-		const convertTo = this.convertTo;
-		const node = this.node;
-		const type = this.getNodeType( builder );
+			if ( convertTo === null || builder.getTypeLength( requestType ) === builder.getTypeLength( overloadingType ) ) {
 
 
-		let snippet = null;
+				convertTo = overloadingType;
 
 
-		if ( builder.isReference( convertTo ) === false ) {
+			}
 
 
-			const nodeSnippet = node.build( builder, convertTo );
+		}
 
 
-			snippet = builder.format( nodeSnippet, type, convertTo );
+		return convertTo;
 
 
-		} else {
+	}
 
 
-			snippet = node.build( builder, convertTo );
+	generate( builder, output ) {
 
 
-		}
+		const node = this.node;
+		const type = this.getNodeType( builder );
+
+		const snippet = node.build( builder, type );
 
 
 		return builder.format( snippet, type, output );
 		return builder.format( snippet, type, output );
 
 

BIN
examples/screenshots/webgl_nodes_materialx_noise.jpg


+ 4 - 11
examples/webgl_nodes_materialx_noise.html

@@ -28,14 +28,7 @@
 		<script type="module">
 		<script type="module">
 
 
 			import * as THREE from 'three';
 			import * as THREE from 'three';
-			import { MeshPhysicalNodeMaterial, add, mul, normalWorld, clamp, timerLocal } from 'three/nodes';
-
-			import {
-				mx_perlin_noise_float,
-				mx_cell_noise_float,
-				mx_worley_noise_float,
-				mx_fractal_noise_float
-			} from 'three/addons/nodes/materialx/functions/lib/mx_noise.js';
+			import { MeshPhysicalNodeMaterial, add, mul, normalWorld, timerLocal, mx_noise_vec3, mx_worley_noise_vec3, mx_cell_noise_float, mx_fractal_noise_vec3 } from 'three/nodes';
 
 
 			import { nodeFrame } from 'three/addons/renderers/webgl/nodes/WebGLNodes.js';
 			import { nodeFrame } from 'three/addons/renderers/webgl/nodes/WebGLNodes.js';
 
 
@@ -80,7 +73,7 @@
 							// left top
 							// left top
 
 
 							let material = new MeshPhysicalNodeMaterial();
 							let material = new MeshPhysicalNodeMaterial();
-							material.colorNode = mx_perlin_noise_float( customUV );
+							material.colorNode = mx_noise_vec3( customUV );
 
 
 							let mesh = new THREE.Mesh( geometry, material );
 							let mesh = new THREE.Mesh( geometry, material );
 							mesh.position.x = - 100;
 							mesh.position.x = - 100;
@@ -100,7 +93,7 @@
 							// left bottom
 							// left bottom
 
 
 							material = new MeshPhysicalNodeMaterial();
 							material = new MeshPhysicalNodeMaterial();
-							material.colorNode = mx_worley_noise_float( customUV, 1, 1 );
+							material.colorNode = mx_worley_noise_vec3( customUV );
 
 
 							mesh = new THREE.Mesh( geometry, material );
 							mesh = new THREE.Mesh( geometry, material );
 							mesh.position.x = - 100;
 							mesh.position.x = - 100;
@@ -110,7 +103,7 @@
 							// right bottom
 							// right bottom
 
 
 							material = new MeshPhysicalNodeMaterial();
 							material = new MeshPhysicalNodeMaterial();
-							material.colorNode = clamp( mul( add( mx_fractal_noise_float( mul( customUV, .2 ), 7, 2, .7 ), 1 ), .5 ) );
+							material.colorNode = mx_fractal_noise_vec3( mul( customUV, .2 ) );
 
 
 							mesh = new THREE.Mesh( geometry, material );
 							mesh = new THREE.Mesh( geometry, material );
 							mesh.position.x = 100;
 							mesh.position.x = 100;