Răsfoiți Sursa

NormalMapNode: Two sides supports and updates (#23971)

* NodeBuilder: add .getFrontFacing() and cleanup builtin

* add FrontFacingNode

* ShaderNode: add frontFacing and faceDirection

* NormalMapNode: two sides supports

* update to nodeImmutable

* FrontFacingNode: export to Nodes

* fix builtin lib
sunag 3 ani în urmă
părinte
comite
f62cd58320

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

@@ -49,6 +49,7 @@ import ComputeNode from './gpgpu/ComputeNode.js';
 
 // display
 import ColorSpaceNode from './display/ColorSpaceNode.js';
+import FrontFacingNode from './display/FrontFacingNode.js';
 import NormalMapNode from './display/NormalMapNode.js';
 import ToneMappingNode from './display/ToneMappingNode.js';
 
@@ -147,6 +148,7 @@ const nodeLib = {
 
 	// display
 	ColorSpaceNode,
+	FrontFacingNode,
 	NormalMapNode,
 	ToneMappingNode,
 
@@ -244,6 +246,7 @@ export {
 
 	// display
 	ColorSpaceNode,
+	FrontFacingNode,
 	NormalMapNode,
 	ToneMappingNode,
 

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

@@ -41,6 +41,10 @@ class NodeBuilder {
 		this.updateNodes = [];
 		this.hashNodes = {};
 
+		this.scene = null;
+		this.lightsNode = null;
+		this.fogNode = null;
+
 		this.vertexShader = null;
 		this.fragmentShader = null;
 		this.computeShader = null;
@@ -158,7 +162,13 @@ class NodeBuilder {
 
 	}
 
-	getInstanceIndex( /*shaderStage*/ ) {
+	getInstanceIndex() {
+
+		console.warn( 'Abstract function.' );
+
+	}
+
+	getFrontFacing() {
 
 		console.warn( 'Abstract function.' );
 

+ 21 - 0
examples/jsm/nodes/display/FrontFacingNode.js

@@ -0,0 +1,21 @@
+import Node from '../core/Node.js';
+
+class FrontFacingNode extends Node {
+
+	constructor() {
+
+		super( 'bool' );
+
+	}
+
+	generate( builder ) {
+
+		return builder.getFrontFacing();
+
+	}
+
+}
+
+FrontFacingNode.prototype.isFrontFacingNode = true;
+
+export default FrontFacingNode;

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

@@ -1,6 +1,6 @@
 import TempNode from '../core/TempNode.js';
 import ModelNode from '../accessors/ModelNode.js';
-import { ShaderNode, positionView, normalView, uv, vec3, cond, add, sub, mul, dFdx, dFdy, cross, max, dot, normalize, inversesqrt, equal } from '../shadernode/ShaderNodeBaseElements.js';
+import { ShaderNode, positionView, normalView, uv, vec3, cond, add, sub, mul, dFdx, dFdy, cross, max, dot, normalize, inversesqrt, equal, faceDirection } from '../shadernode/ShaderNodeBaseElements.js';
 
 import { TangentSpaceNormalMap, ObjectSpaceNormalMap } from 'three';
 
@@ -9,7 +9,7 @@ import { TangentSpaceNormalMap, ObjectSpaceNormalMap } from 'three';
 
 const perturbNormal2ArbNode = new ShaderNode( ( inputs ) => {
 
-	const { eye_pos, surf_norm, mapN, faceDirection, uv } = inputs;
+	const { eye_pos, surf_norm, mapN, uv } = inputs;
 
 	const q0 = dFdx( eye_pos.xyz );
 	const q1 = dFdy( eye_pos.xyz );
@@ -74,7 +74,6 @@ class NormalMapNode extends TempNode {
 				eye_pos: positionView,
 				surf_norm: normalView,
 				mapN: normalMap,
-				faceDirection: 1.0,
 				uv: uv()
 			} );
 

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

@@ -28,6 +28,9 @@ import StorageBufferNode from '../accessors/StorageBufferNode.js';
 import TextureNode from '../accessors/TextureNode.js';
 import UVNode from '../accessors/UVNode.js';
 
+// display
+import FrontFacingNode from '../display/FrontFacingNode.js';
+
 // gpgpu
 import ComputeNode from '../gpgpu/ComputeNode.js';
 
@@ -252,6 +255,11 @@ export const refract = nodeProxy( MathNode, MathNode.REFRACT );
 export const smoothstep = nodeProxy( MathNode, MathNode.SMOOTHSTEP );
 export const faceforward = nodeProxy( MathNode, MathNode.FACEFORWARD );
 
+// display
+
+export const frontFacing = nodeImmutable( FrontFacingNode );
+export const faceDirection = sub( mul( float( frontFacing ), 2 ), 1 );
+
 // lights
 
 export const reflectedLight = nodeProxy( ReflectedLightNode );

+ 48 - 7
examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js

@@ -105,7 +105,12 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 		this.uniformsGroup = {};
 
-		this.builtins = new Set();
+		this.builtins = {
+			vertex: new Map(),
+			fragment: new Map(),
+			compute: new Map(),
+			attribute: new Map()
+		};
 
 	}
 
@@ -364,14 +369,42 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 	}
 
-	getInstanceIndex( shaderStage = this.shaderStage ) {
+	getBuiltin( name, property, type, shaderStage = this.shaderStage ) {
 
-		this.builtins.add( 'instance_index' );
+		const map = this.builtins[ shaderStage ];
+
+		if ( map.has( name ) === false ) {
+
+			map.set( name, {
+				name,
+				property,
+				type
+			} );
+
+		}
+
+		return property;
+
+	}
+
+	getInstanceIndex() {
+
+		if ( this.shaderStage === 'vertex' ) {
+
+			return this.getBuiltin( 'instance_index', 'instanceIndex', 'u32', 'attribute' );
+
+		}
 
 		return 'instanceIndex';
 
 	}
 
+	getFrontFacing() {
+
+		return this.getBuiltin( 'front_facing', 'isFront', 'bool' );
+
+	}
+
 	getAttributes( shaderStage ) {
 
 		const snippets = [];
@@ -380,11 +413,13 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 			if ( shaderStage === 'compute' ) {
 
-				snippets.push( `@builtin( global_invocation_id ) id : vec3<u32>` );
+				this.getBuiltin( 'global_invocation_id', 'id', 'vec3<u32>', 'attribute' );
 
-			} else if ( this.builtins.has( 'instance_index' ) ) {
+			}
 
-				snippets.push( `@builtin( instance_index ) instanceIndex : u32` );
+			for ( const { name, property, type } of this.builtins.attribute.values() ) {
+
+				snippets.push( `@builtin( ${name} ) ${property} : ${type}` );
 
 			}
 
@@ -433,7 +468,7 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 		if ( shaderStage === 'vertex' ) {
 
-			snippets.push( '@builtin( position ) Vertex: vec4<f32>' );
+			this.getBuiltin( 'position', 'Vertex', 'vec4<f32>', 'vertex' );
 
 			const varys = this.varys;
 
@@ -459,6 +494,12 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 		}
 
+		for ( const { name, property, type } of this.builtins[ shaderStage ].values() ) {
+
+			snippets.push( `@builtin( ${name} ) ${property} : ${type}` );
+
+		}
+
 		const code = snippets.join( ',\n\t' );
 
 		return shaderStage === 'vertex' ? this._getWGSLStruct( 'NodeVarysStruct', '\t' + code ) : code;