Browse Source

Nodes: ViewportNode (#24934)

* NodeBuilder: Add .getFragCoord(), .isFlipY()

* Add ViewportNode

* ShaderNode: Add viewport* elements

* Example: add texture screen projection

* cleanup
sunag 2 năm trước cách đây
mục cha
commit
87c581c966

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

@@ -61,6 +61,7 @@ import FrontFacingNode from './display/FrontFacingNode.js';
 import NormalMapNode from './display/NormalMapNode.js';
 import NormalMapNode from './display/NormalMapNode.js';
 import PosterizeNode from './display/PosterizeNode.js';
 import PosterizeNode from './display/PosterizeNode.js';
 import ToneMappingNode from './display/ToneMappingNode.js';
 import ToneMappingNode from './display/ToneMappingNode.js';
+import ViewportNode from './display/ViewportNode.js';
 
 
 // math
 // math
 import MathNode from './math/MathNode.js';
 import MathNode from './math/MathNode.js';
@@ -187,6 +188,7 @@ const nodeLib = {
 	NormalMapNode,
 	NormalMapNode,
 	PosterizeNode,
 	PosterizeNode,
 	ToneMappingNode,
 	ToneMappingNode,
+	ViewportNode,
 
 
 	// math
 	// math
 	MathNode,
 	MathNode,
@@ -306,6 +308,7 @@ export {
 	NormalMapNode,
 	NormalMapNode,
 	PosterizeNode,
 	PosterizeNode,
 	ToneMappingNode,
 	ToneMappingNode,
+	ViewportNode,
 
 
 	// math
 	// math
 	MathNode,
 	MathNode,

+ 12 - 0
examples/jsm/nodes/core/NodeBuilder.js

@@ -181,6 +181,18 @@ class NodeBuilder {
 
 
 	}
 	}
 
 
+	getFragCoord() {
+
+		console.warn( 'Abstract function.' );
+
+	}
+
+	isFlipY() {
+
+		return false;
+
+	}
+
 	getTexture( /* textureProperty, uvSnippet */ ) {
 	getTexture( /* textureProperty, uvSnippet */ ) {
 
 
 		console.warn( 'Abstract function.' );
 		console.warn( 'Abstract function.' );

+ 106 - 0
examples/jsm/nodes/display/ViewportNode.js

@@ -0,0 +1,106 @@
+import Node from '../core/Node.js';
+import { uniform, div, vec2, invert } from '../shadernode/ShaderNodeBaseElements.js';
+import { Vector2 } from 'three';
+import { NodeUpdateType } from '../core/constants.js';
+
+let resolution;
+
+class ViewportNode extends Node {
+
+	static COORDINATE = 'coordinate';
+	static RESOLUTION = 'resolution';
+	static TOP_LEFT = 'topLeft';
+	static BOTTOM_LEFT = 'bottomLeft';
+	static TOP_RIGHT = 'topRight';
+	static BOTTOM_RIGHT = 'bottomRight';
+
+	constructor( scope ) {
+
+		super();
+
+		this.scope = scope;
+
+		this.isScreenNode = true;
+
+	}
+
+	getNodeType() {
+
+		return this.scope === ViewportNode.COORDINATE ? 'vec4' : 'vec2';
+
+	}
+
+	getUpdateType() {
+
+		let updateType = NodeUpdateType.NONE;
+
+		if ( this.scope === ViewportNode.RESOLUTION ) {
+
+			updateType = NodeUpdateType.FRAME;
+
+		}
+
+		this.updateType = updateType;
+
+		return updateType;
+
+	}
+
+	update( { renderer } ) {
+
+		renderer.getSize( resolution );
+
+	}
+
+	construct( builder ) {
+
+		const scope = this.scope;
+
+		if ( scope === ViewportNode.COORDINATE ) return;
+
+		let output = null;
+
+		if ( scope === ViewportNode.RESOLUTION ) {
+
+			resolution ||= new Vector2();
+
+			output = uniform( resolution );
+
+		} else {
+
+			const coordinateNode = vec2( new ViewportNode( ViewportNode.COORDINATE ) );
+			const resolutionNode = new ViewportNode( ViewportNode.RESOLUTION );
+
+			output = div( coordinateNode, resolutionNode );
+
+			let outX = output.x;
+			let outY = output.y;
+
+			if ( /top/i.test( scope ) && builder.isFlipY() ) outY = invert( outY );
+			else if ( /bottom/i.test( scope ) && builder.isFlipY() === false ) outY = invert( outY );
+
+			if ( /right/i.test( scope ) ) outX = invert( outX );
+
+			output = vec2( outX, outY );
+
+		}
+
+		return output;
+
+	}
+
+	generate( builder ) {
+
+		if ( this.scope === ViewportNode.COORDINATE ) {
+
+			return builder.getFragCoord();
+
+		}
+
+		return super.generate( builder );
+
+	}
+
+}
+
+export default ViewportNode;

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

@@ -11,6 +11,7 @@ import ColorSpaceNode from '../display/ColorSpaceNode.js';
 import NormalMapNode from '../display/NormalMapNode.js';
 import NormalMapNode from '../display/NormalMapNode.js';
 import PosterizeNode from '../display/PosterizeNode.js';
 import PosterizeNode from '../display/PosterizeNode.js';
 import ToneMappingNode from '../display/ToneMappingNode.js';
 import ToneMappingNode from '../display/ToneMappingNode.js';
+import ViewportNode from '../display/ViewportNode.js';
 
 
 // lighting
 // lighting
 import LightsNode from '../lighting/LightsNode.js';
 import LightsNode from '../lighting/LightsNode.js';
@@ -92,6 +93,13 @@ export const toneMapping = ( mapping, exposure, color ) => nodeObject( new ToneM
 
 
 export const posterize = nodeProxy( PosterizeNode );
 export const posterize = nodeProxy( PosterizeNode );
 
 
+export const viewportCoordinate = nodeImmutable( ViewportNode, ViewportNode.COORDINATE );
+export const viewportResolution = nodeImmutable( ViewportNode, ViewportNode.RESOLUTION );
+export const viewportTopLeft = nodeImmutable( ViewportNode, ViewportNode.TOP_LEFT );
+export const viewportBottomLeft = nodeImmutable( ViewportNode, ViewportNode.BOTTOM_LEFT );
+export const viewportTopRight = nodeImmutable( ViewportNode, ViewportNode.TOP_RIGHT );
+export const viewportBottomRight = nodeImmutable( ViewportNode, ViewportNode.BOTTOM_RIGHT );
+
 // lighting
 // lighting
 
 
 //export const lighting = nodeProxy( LightingNode ); // abstract
 //export const lighting = nodeProxy( LightingNode ); // abstract

+ 8 - 11
examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js

@@ -1,7 +1,6 @@
 import { defaultShaderStages, NodeFrame, MathNode, GLSLNodeParser, NodeBuilder } from 'three/nodes';
 import { defaultShaderStages, NodeFrame, MathNode, GLSLNodeParser, NodeBuilder } from 'three/nodes';
 import SlotNode from './SlotNode.js';
 import SlotNode from './SlotNode.js';
-import { PerspectiveCamera, ShaderChunk, ShaderLib, UniformsUtils, UniformsLib,
-	LinearEncoding, RGBAFormat, UnsignedByteType, sRGBEncoding } from 'three';
+import { PerspectiveCamera, ShaderChunk, ShaderLib, UniformsUtils, UniformsLib } from 'three';
 
 
 const nodeFrame = new NodeFrame();
 const nodeFrame = new NodeFrame();
 nodeFrame.camera = new PerspectiveCamera();
 nodeFrame.camera = new PerspectiveCamera();
@@ -572,23 +571,21 @@ class WebGLNodeBuilder extends NodeBuilder {
 
 
 	}
 	}
 
 
-	getTextureEncodingFromMap( map ) {
+	getFrontFacing() {
 
 
-		const isWebGL2 = this.renderer.capabilities.isWebGL2;
+		return 'gl_FrontFacing';
 
 
-		if ( isWebGL2 && map && map.isTexture && map.format === RGBAFormat && map.type === UnsignedByteType && map.encoding === sRGBEncoding ) {
+	}
 
 
-			return LinearEncoding; // disable inline decode for sRGB textures in WebGL 2
+	getFragCoord() {
 
 
-		}
-
-		return super.getTextureEncodingFromMap( map );
+		return 'gl_FragCoord';
 
 
 	}
 	}
 
 
-	getFrontFacing() {
+	isFlipY() {
 
 
-		return 'gl_FrontFacing';
+		return true;
 
 
 	}
 	}
 
 

+ 12 - 0
examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js

@@ -399,6 +399,18 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 
 	}
 	}
 
 
+	getFragCoord() {
+
+		return this.getBuiltin( 'position', 'fragCoord', 'vec4<f32>', 'fragment' );
+
+	}
+
+	isFlipY() {
+
+		return false;
+
+	}
+
 	getAttributes( shaderStage ) {
 	getAttributes( shaderStage ) {
 
 
 		const snippets = [];
 		const snippets = [];

+ 6 - 1
examples/webgpu_materials.html

@@ -34,7 +34,7 @@
 
 
 			import { TeapotGeometry } from 'three/addons/geometries/TeapotGeometry.js';
 			import { TeapotGeometry } from 'three/addons/geometries/TeapotGeometry.js';
 
 
-			import { ShaderNode, vec3, dot, triplanarTexture } from 'three/nodes';
+			import { ShaderNode, vec3, dot, triplanarTexture, viewportBottomLeft } from 'three/nodes';
 
 
 			import Stats from 'three/addons/libs/stats.module.js';
 			import Stats from 'three/addons/libs/stats.module.js';
 
 
@@ -182,6 +182,11 @@
 				material.colorNode = triplanarTexture( new Nodes.TextureNode( texture ) );
 				material.colorNode = triplanarTexture( new Nodes.TextureNode( texture ) );
 				materials.push( material );
 				materials.push( material );
 
 
+				// Screen Projection Texture
+				material = new Nodes.MeshBasicNodeMaterial();
+				material.colorNode = Nodes.texture( texture, viewportBottomLeft );
+				materials.push( material );
+
 				//
 				//
 				// Geometry
 				// Geometry
 				//
 				//