Browse Source

TSL: Introduce `sample()` (#31287)

* introduce ``sample`

* optimize example using packing
sunag 6 months ago
parent
commit
5f6ec60648
4 changed files with 105 additions and 3 deletions
  1. 22 3
      examples/webgpu_postprocessing_ssr.html
  2. 1 0
      src/Three.TSL.js
  3. 1 0
      src/nodes/TSL.js
  4. 81 0
      src/nodes/utils/SampleNode.js

+ 22 - 3
examples/webgpu_postprocessing_ssr.html

@@ -11,11 +11,13 @@
 	</head>
 
 <body>
+
 	<div id="info">
 		<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgpu - postprocessing - screen space reflections<br />
 		<a href="https://skfb.ly/6tqYD" target="_blank" rel="noopener">Steampunk Camera</a> by 
 		<a href="https://sketchfab.com/lumoize" target="_blank" rel="noopener">dylanheyes</a> is licensed under <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noopener">Creative Commons Attribution</a>.<br />
 	</div>
+
 	<script type="importmap">
 		{
 			"imports": {
@@ -28,8 +30,9 @@
 	</script>
 
 	<script type="module">
+
 		import * as THREE from 'three';
-		import { pass, mrt, output, normalView, metalness, blendColor, screenUV, color } from 'three/tsl';
+		import { pass, mrt, output, normalView, metalness, blendColor, screenUV, color, sample, directionToColor, colorToDirection } from 'three/tsl';
 		import { ssr } from 'three/addons/tsl/display/SSRNode.js';
 		import { smaa } from 'three/addons/tsl/display/SMAANode.js';
 
@@ -109,7 +112,7 @@
 			const scenePass = pass( scene, camera, { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter } );
 			scenePass.setMRT( mrt( {
 				output: output,
-				normal: normalView,
+				normal: directionToColor( normalView ),
 				metalness: metalness
 			} ) );
 
@@ -118,7 +121,23 @@
 			const scenePassDepth = scenePass.getTextureNode( 'depth' );
 			const scenePassMetalness = scenePass.getTextureNode( 'metalness' );
 
-			ssrPass = ssr( scenePassColor, scenePassDepth, scenePassNormal, scenePassMetalness, camera );
+			// optimization bandwidth packing the normals and reducing the texture precision if possible
+
+			const metalnessTexture = scenePass.getTexture( 'metalness' );
+			metalnessTexture.type = THREE.UnsignedByteType;
+
+			const normalTexture = scenePass.getTexture( 'normal' );
+			normalTexture.type = THREE.UnsignedByteType;
+
+			const customNormal = sample( ( uv ) => {
+
+				return colorToDirection( scenePassNormal.sample( uv ) );
+
+			} );
+
+			//
+
+			ssrPass = ssr( scenePassColor, scenePassDepth, customNormal, scenePassMetalness, camera );
 			ssrPass.resolutionScale = 1.0;
 
 			// blend SSR over beauty

+ 1 - 0
src/Three.TSL.js

@@ -420,6 +420,7 @@ export const round = TSL.round;
 export const rtt = TSL.rtt;
 export const sRGBTransferEOTF = TSL.sRGBTransferEOTF;
 export const sRGBTransferOETF = TSL.sRGBTransferOETF;
+export const sample = TSL.sample;
 export const sampler = TSL.sampler;
 export const samplerComparison = TSL.samplerComparison;
 export const saturate = TSL.saturate;

+ 1 - 0
src/nodes/TSL.js

@@ -42,6 +42,7 @@ export * from './utils/TriplanarTextures.js';
 export * from './utils/ReflectorNode.js';
 export * from './utils/RTTNode.js';
 export * from './utils/PostProcessingUtils.js';
+export * from './utils/SampleNode.js';
 
 // three.js shading language
 export * from './tsl/TSLBase.js';

+ 81 - 0
src/nodes/utils/SampleNode.js

@@ -0,0 +1,81 @@
+import Node from '../core/Node.js';
+import { uv } from '../accessors/UV.js';
+import { nodeObject } from '../tsl/TSLCore.js';
+
+/**
+ * Class representing a node that samples a value using a provided callback function.
+ *
+ * @extends Node
+ */
+class SampleNode extends Node {
+
+	/**
+	 * Returns the type of the node.
+	 *
+	 * @type {string}
+	 * @readonly
+	 * @static
+	 */
+	static get type() {
+
+		return 'SampleNode';
+
+	}
+
+	/**
+	 * Creates an instance of SampleNode.
+	 *
+	 * @param {Function} callback - The function to be called when sampling. Should accept a UV node and return a value.
+	 */
+	constructor( callback ) {
+
+		super();
+
+		this.callback = callback;
+
+		/**
+		 * This flag can be used for type testing.
+		 *
+		 * @type {boolean}
+		 * @readonly
+		 * @default true
+		 */
+		this.isSampleNode = true;
+
+	}
+
+	/**
+	 * Sets up the node by sampling with the default UV accessor.
+	 *
+	 * @returns {Node} The result of the callback function when called with the UV node.
+	 */
+	setup() {
+
+		return this.sample( uv() );
+
+	}
+
+	/**
+	 * Calls the callback function with the provided UV node.
+	 *
+	 * @param {Node<vec2>} uv - The UV node or value to be passed to the callback.
+	 * @returns {Node} The result of the callback function.
+	 */
+	sample( uv ) {
+
+		return this.callback( uv );
+
+	}
+
+}
+
+export default SampleNode;
+
+/**
+ * Helper function to create a SampleNode wrapped as a node object.
+ *
+ * @function
+ * @param {Function} callback - The function to be called when sampling. Should accept a UV node and return a value.
+ * @returns {SampleNode} The created SampleNode instance wrapped as a node object.
+ */
+export const sample = /*@__PURE__*/ ( callback ) => nodeObject( new SampleNode( callback ) );

粤ICP备19079148号