Просмотр исходного кода

NormalMapNode: Add basic support for normal unpacking. (#31695)

Ignacio Castaño 1 месяц назад
Родитель
Сommit
ffe6b1ae00

+ 24 - 0
src/constants.js

@@ -1280,6 +1280,30 @@ export const LinearTransfer = 'linear';
  */
 export const SRGBTransfer = 'srgb';
 
+/**
+ * No normal map packing.
+ *
+ * @type {string}
+ * @constant
+ */
+export const NoNormalPacking = '';
+
+/**
+ * Normal RG packing.
+ *
+ * @type {string}
+ * @constant
+ */
+export const NormalRGPacking = 'rg';
+
+/**
+ * Normal GA packing.
+ *
+ * @type {string}
+ * @constant
+ */
+export const NormalGAPacking = 'ga';
+
 /**
  * Sets the stencil buffer value to `0`.
  *

+ 8 - 0
src/nodes/accessors/MaterialNode.js

@@ -7,6 +7,8 @@ import { uniform } from '../core/UniformNode.js';
 import { normalMap } from '../display/NormalMapNode.js';
 import { bumpMap } from '../display/BumpMapNode.js';
 import { Vector2 } from '../../math/Vector2.js';
+import { RGFormat, RED_GREEN_RGTC2_Format, NormalRGPacking } from '../../constants.js';
+
 
 const _propertyCache = new Map();
 
@@ -235,6 +237,12 @@ class MaterialNode extends Node {
 				node = normalMap( this.getTexture( 'normal' ), this.getCache( 'normalScale', 'vec2' ) );
 				node.normalMapType = material.normalMapType;
 
+				if ( material.normalMap.format == RGFormat || material.normalMap.format == RED_GREEN_RGTC2_Format ) {
+
+					node.unpackNormalMode = NormalRGPacking;
+
+				}
+
 			} else if ( material.bumpMap ) {
 
 				node = bumpMap( this.getTexture( 'bump' ).r, this.getFloat( 'bumpScale' ) );

+ 37 - 2
src/nodes/display/NormalMapNode.js

@@ -4,8 +4,9 @@ import { normalView, transformNormalToView } from '../accessors/Normal.js';
 import { TBNViewMatrix } from '../accessors/AccessorsUtils.js';
 import { nodeProxy, vec3 } from '../tsl/TSLBase.js';
 
-import { TangentSpaceNormalMap, ObjectSpaceNormalMap } from '../../constants.js';
+import { TangentSpaceNormalMap, ObjectSpaceNormalMap, NoNormalPacking, NormalRGPacking, NormalGAPacking } from '../../constants.js';
 import { directionToFaceDirection } from './FrontFacingNode.js';
+import { unpackNormal } from '../utils/Packing.js';
 import { error } from '../../utils.js';
 
 /**
@@ -58,14 +59,48 @@ class NormalMapNode extends TempNode {
 		 */
 		this.normalMapType = TangentSpaceNormalMap;
 
+		/**
+		 * Controls how to unpack the sampled normal map values.
+		 *
+		 * @type {string}
+		 * @default NoNormalPacking
+		 */
+		this.unpackNormalMode = NoNormalPacking;
+
 	}
 
 	setup( { material } ) {
 
-		const { normalMapType, scaleNode } = this;
+		const { normalMapType, scaleNode, unpackNormalMode } = this;
 
 		let normalMap = this.node.mul( 2.0 ).sub( 1.0 );
 
+		if ( normalMapType === TangentSpaceNormalMap ) {
+
+			if ( unpackNormalMode == NormalRGPacking ) {
+
+				normalMap = unpackNormal( normalMap.xy );
+
+			} else if ( unpackNormalMode == NormalGAPacking ) {
+
+				normalMap = unpackNormal( normalMap.yw );
+
+			} else if ( unpackNormalMode != NoNormalPacking ) {
+
+				console.error( `THREE.NodeMaterial: Unexpected unpack normal mode: ${ unpackNormalMode }` );
+
+			}
+
+		} else {
+
+			if ( unpackNormalMode != NoNormalPacking ) {
+
+				console.error( `THREE.NodeMaterial: Normal map type '${ normalMapType }' is not compatible with unpack normal mode '${ unpackNormalMode }'` );
+
+			}
+
+		}
+
 		if ( scaleNode !== null ) {
 
 			let scale = scaleNode;

+ 13 - 1
src/nodes/utils/Packing.js

@@ -1,4 +1,5 @@
-import { nodeObject } from '../tsl/TSLBase.js';
+import { nodeObject, vec3, float } from '../tsl/TSLBase.js';
+import { dot, sqrt, saturate } from '../math/MathNode.js';
 
 /**
  * Packs a direction vector into a color value.
@@ -19,3 +20,14 @@ export const directionToColor = ( node ) => nodeObject( node ).mul( 0.5 ).add( 0
  * @return {Node<vec3>} The direction.
  */
 export const colorToDirection = ( node ) => nodeObject( node ).mul( 2.0 ).sub( 1 );
+
+/**
+ * Unpacks a tangent space normal, reconstructing the Z component by projecting the X,Y coordinates onto the hemisphere.
+ * The X,Y coordinates are expected to be in the [-1, 1] range.
+ *
+ * @tsl
+ * @function
+ * @param {Node<vec2>} xy - The X,Y coordinates of the normal.
+ * @return {Node<vec3>} The resulting normal.
+ */
+export const unpackNormal = ( xy ) => vec3( xy, sqrt( saturate( float( 1.0 ).sub( dot( xy, xy ) ) ) ) );

粤ICP备19079148号