Quellcode durchsuchen

TSL: Introduce `node.toTexture()` and `rtt()` (#28773)

* TextureNode: Fix analyze reference

* Add RTTNode

* rgbShift: add `.toTexture()` and updated example

* Update GaussianBlurNode.js

* add procedural texture

* Update AnamorphicNode.js

* update imports

* update build for now

* update build

* update names
sunag vor 1 Jahr
Ursprung
Commit
08d5412aa0

Datei-Diff unterdrückt, da er zu groß ist
+ 159 - 65
build/three.webgpu.js


+ 1 - 0
examples/files.json

@@ -372,6 +372,7 @@
 		"webgpu_postprocessing_dof",
 		"webgpu_postprocessing_sobel",
 		"webgpu_postprocessing",
+		"webgpu_procedural_texture",
 		"webgpu_reflection",
 		"webgpu_refraction",
 		"webgpu_rtt",

BIN
examples/screenshots/webgpu_procedural_texture.jpg


+ 1 - 1
examples/webgpu_postprocessing.html

@@ -76,7 +76,7 @@
 				const dotScreenPass = scenePassColor.dotScreen();
 				dotScreenPass.scale.value = 0.3;
 
-				const rgbShiftPass = dotScreenPass.getTextureNode().rgbShift();
+				const rgbShiftPass = dotScreenPass.rgbShift();
 				rgbShiftPass.amount.value = 0.001;
 
 				postProcessing.outputNode = rgbShiftPass;

+ 109 - 0
examples/webgpu_procedural_texture.html

@@ -0,0 +1,109 @@
+<html lang="en">
+	<head>
+		<title>three.js webgpu - procedural texture</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="main.css">
+	</head>
+	<body>
+
+		<div id="info">
+			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgpu - procedural texture
+		</div>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.webgpu.js",
+					"three/tsl": "../build/three.webgpu.js",
+					"three/addons/": "./jsm/"
+				}
+			}
+		</script>
+
+		<script type="module">
+
+			import * as THREE from 'three';
+			import { checker, uv, uniform } from 'three/tsl';
+
+			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
+
+			let camera, scene, renderer;
+
+			init();
+			render();
+
+			function init() {
+
+				const aspect = window.innerWidth / window.innerHeight;
+				camera = new THREE.OrthographicCamera( - aspect, aspect, 1, - 1, 0, 2 );
+				camera.position.z = 1;
+
+				scene = new THREE.Scene();
+
+				// procedural to texture
+
+				const uvScale = uniform( 4 );
+				const blurAmount = uniform( .5 );
+
+				const procedural = checker( uv().mul( uvScale ) );
+				const proceduralToTexture = procedural.toTexture( 512, 512 ); // ( width, height ) <- texture size
+
+				const colorNode = proceduralToTexture.gaussianBlur( blurAmount, 10 );
+
+				// extra
+
+				//proceduralToTexture.autoUpdate = false; // update just once
+				//proceduralToTexture.textureNeedsUpdate = true; // manually update
+
+				// scene
+
+				const material = new THREE.MeshBasicNodeMaterial();
+				material.colorNode = colorNode;
+
+				const plane = new THREE.Mesh( new THREE.PlaneGeometry( 1, 1 ), material );
+				scene.add( plane );
+
+				// renderer
+
+				renderer = new THREE.WebGPURenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setAnimationLoop( render );
+				document.body.appendChild( renderer.domElement );
+
+				window.addEventListener( 'resize', onWindowResize );
+
+				// gui
+
+				const gui = new GUI();
+				gui.add( uvScale, 'value', 1, 10 ).name( 'uv scale ( before rtt )' );
+				gui.add( blurAmount, 'value', 0, 2 ).name( 'blur amount ( after rtt )' );
+				gui.add( proceduralToTexture, 'autoUpdate' ).name( 'auto update' );
+
+			}
+
+			function onWindowResize() {
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				const aspect = window.innerWidth / window.innerHeight;
+
+				const frustumHeight = camera.top - camera.bottom;
+
+				camera.left = - frustumHeight * aspect / 2;
+				camera.right = frustumHeight * aspect / 2;
+
+				camera.updateProjectionMatrix();
+
+			}
+
+			function render() {
+
+				renderer.renderAsync( scene, camera );
+
+			}
+
+		</script>
+	</body>
+</html>

+ 1 - 0
src/nodes/Nodes.js

@@ -70,6 +70,7 @@ export { default as StorageArrayElementNode } from './utils/StorageArrayElementN
 export { default as TimerNode, timerLocal, timerGlobal, timerDelta, frameId } from './utils/TimerNode.js';
 export { default as TriplanarTexturesNode, triplanarTextures, triplanarTexture } from './utils/TriplanarTexturesNode.js';
 export { default as ReflectorNode, reflector } from './utils/ReflectorNode.js';
+export { default as RTTNode, rtt } from './utils/RTTNode.js';
 
 // shadernode
 export * from './shadernode/ShaderNode.js';

+ 1 - 0
src/nodes/accessors/TextureNode.js

@@ -132,6 +132,7 @@ class TextureNode extends UniformNode {
 	setup( builder ) {
 
 		const properties = builder.getNodeProperties( this );
+		properties.referenceNode = this.referenceNode;
 
 		//
 

+ 2 - 2
src/nodes/display/AnamorphicNode.js

@@ -99,7 +99,7 @@ class AnamorphicNode extends TempNode {
 
 		const uvNode = textureNode.uvNode || uv();
 
-		const sampleTexture = ( uv ) => textureNode.cache().context( { getUV: () => uv, forceUVContext: true } );
+		const sampleTexture = ( uv ) => textureNode.uv( uv );
 
 		const anamorph = tslFn( () => {
 
@@ -142,7 +142,7 @@ class AnamorphicNode extends TempNode {
 
 }
 
-export const anamorphic = ( node, threshold = .9, scale = 3, samples = 32 ) => nodeObject( new AnamorphicNode( nodeObject( node ), nodeObject( threshold ), nodeObject( scale ), samples ) );
+export const anamorphic = ( node, threshold = .9, scale = 3, samples = 32 ) => nodeObject( new AnamorphicNode( nodeObject( node ).toTexture(), nodeObject( threshold ), nodeObject( scale ), samples ) );
 
 addNodeElement( 'anamorphic', anamorphic );
 

+ 6 - 6
src/nodes/display/GaussianBlurNode.js

@@ -18,15 +18,14 @@ const quadMesh2 = new QuadMesh();
 
 class GaussianBlurNode extends TempNode {
 
-	constructor( textureNode, sigma = 2 ) {
+	constructor( textureNode, directionNode = null, sigma = 2 ) {
 
 		super( 'vec4' );
 
 		this.textureNode = textureNode;
+		this.directionNode = directionNode;
 		this.sigma = sigma;
 
-		this.directionNode = vec2( 1 );
-
 		this._invSize = uniform( new Vector2() );
 		this._passDirection = uniform( new Vector2() );
 
@@ -119,8 +118,9 @@ class GaussianBlurNode extends TempNode {
 		//
 
 		const uvNode = textureNode.uvNode || uv();
+		const directionNode = vec2( this.directionNode || 1 );
 
-		const sampleTexture = ( uv ) => textureNode.cache().context( { getUV: () => uv, forceUVContext: true } );
+		const sampleTexture = ( uv ) => textureNode.uv( uv );
 
 		const blur = tslFn( () => {
 
@@ -128,7 +128,7 @@ class GaussianBlurNode extends TempNode {
 			const gaussianCoefficients = this._getCoefficients( kernelSize );
 
 			const invSize = this._invSize;
-			const direction = vec2( this.directionNode ).mul( this._passDirection );
+			const direction = directionNode.mul( this._passDirection );
 
 			const weightSum = float( gaussianCoefficients[ 0 ] ).toVar();
 			const diffuseSum = vec4( sampleTexture( uvNode ).mul( weightSum ) ).toVar();
@@ -184,7 +184,7 @@ class GaussianBlurNode extends TempNode {
 
 }
 
-export const gaussianBlur = ( node, sigma ) => nodeObject( new GaussianBlurNode( nodeObject( node ), sigma ) );
+export const gaussianBlur = ( node, directionNode, sigma ) => nodeObject( new GaussianBlurNode( nodeObject( node ), directionNode, sigma ) );
 
 addNodeElement( 'gaussianBlur', gaussianBlur );
 

+ 1 - 1
src/nodes/display/RGBShiftNode.js

@@ -41,7 +41,7 @@ class RGBShiftNode extends TempNode {
 
 }
 
-export const rgbShift = ( node, amount, angle ) => nodeObject( new RGBShiftNode( nodeObject( node ), amount, angle ) );
+export const rgbShift = ( node, amount, angle ) => nodeObject( new RGBShiftNode( nodeObject( node ).toTexture(), amount, angle ) );
 
 addNodeElement( 'rgbShift', rgbShift );
 

+ 106 - 0
src/nodes/utils/RTTNode.js

@@ -0,0 +1,106 @@
+import { nodeObject, addNodeElement } from '../shadernode/ShaderNode.js';
+import TextureNode from '../accessors/TextureNode.js';
+import { NodeUpdateType } from '../core/constants.js';
+import { addNodeClass } from '../core/Node.js';
+import NodeMaterial from '../materials/NodeMaterial.js';
+import { uv } from '../accessors/UVNode.js';
+import QuadMesh from '../../renderers/common/QuadMesh.js';
+
+import { RenderTarget } from '../../core/RenderTarget.js';
+import { Vector2 } from '../../math/Vector2.js';
+import { HalfFloatType } from '../../constants.js';
+
+const _quadMesh = new QuadMesh( new NodeMaterial() );
+const _size = new Vector2();
+
+class RTTNode extends TextureNode {
+
+	constructor( node, width = null, height = null, options = { type: HalfFloatType } ) {
+
+		const renderTarget = new RenderTarget( width, height, options );
+
+		super( renderTarget.texture, uv() );
+
+		this.node = node;
+		this.width = width;
+		this.height = height;
+
+		this.renderTarget = renderTarget;
+
+		this.textureNeedsUpdate = true;
+		this.autoUpdate = true;
+
+		this.updateMap = new WeakMap();
+
+		this.updateBeforeType = NodeUpdateType.RENDER;
+
+	}
+
+	get autoSize() {
+
+		return this.width === null;
+
+	}
+
+	setSize( width, height ) {
+
+		this.width = width;
+		this.height = height;
+
+		this.renderTarget.setSize( width, height );
+
+		this.textureNeedsUpdate = true;
+
+	}
+
+	updateBefore( { renderer } ) {
+
+		if ( this.textureNeedsUpdate === false && this.autoUpdate === false ) return;
+
+		this.textureNeedsUpdate = false;
+
+		//
+
+		if ( this.autoSize === true ) {
+
+			const size = renderer.getSize( _size );
+
+			this.setSize( size.width, size.height );
+
+		}
+
+		//
+
+		_quadMesh.material.fragmentNode = this.node;
+
+		//
+
+		const currentRenderTarget = renderer.getRenderTarget();
+
+		renderer.setRenderTarget( this.renderTarget );
+
+		_quadMesh.render( renderer );
+
+		renderer.setRenderTarget( currentRenderTarget );
+
+	}
+
+	clone() {
+
+		const newNode = new TextureNode( this.value, this.uvNode, this.levelNode );
+		newNode.sampler = this.sampler;
+		newNode.referenceNode = this;
+
+		return newNode;
+
+	}
+
+}
+
+export default RTTNode;
+
+export const rtt = ( node, ...params ) => nodeObject( new RTTNode( nodeObject( node ), ...params ) );
+
+addNodeElement( 'toTexture', ( node, ...params ) => node.isTextureNode ? node : rtt( node, ...params ) );
+
+addNodeClass( 'RTTNode', RTTNode );

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.