Explorar o código

NodeMaterial: CubeTexture WebGPU and WebGL (#23743)

* fix camera ref

* add viewMatrix, cameraPosition and cleanup

* fi texture parameter

* add getCubeTexture() and bias API update

* WebGLNodeBuilder: update bias API

* fix refresh uniforms of shared materials

* add WebGPUNodeSampledCubeTexture

* WebGPURenderer: CubeTexture support

* TextureNode: update bias API

* add CubeTextureNode and ReflectNode

* update examples

* Revert "WebGPURenderer: CubeTexture support"

This reverts commit 6c62b26612f790062a8797cda97e5e6b9b7c3dc3.

* Revert "Revert "WebGPURenderer: CubeTexture support""

This reverts commit 4498f37541c9906d52df9eb726ace396c3c11094.

* fix default value of baseArrayLayer

* CubeTextureNode instanceof of TextureNode
sunag %!s(int64=3) %!d(string=hai) anos
pai
achega
70b9ae878c

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

@@ -27,6 +27,7 @@ import VaryNode from './core/VaryNode.js';
 // accessors
 import BufferNode from './accessors/BufferNode.js';
 import CameraNode from './accessors/CameraNode.js';
+import CubeTextureNode from './accessors/CubeTextureNode.js';
 import MaterialNode from './accessors/MaterialNode.js';
 import MaterialReferenceNode from './accessors/MaterialReferenceNode.js';
 import ModelNode from './accessors/ModelNode.js';
@@ -36,6 +37,7 @@ import Object3DNode from './accessors/Object3DNode.js';
 import PointUVNode from './accessors/PointUVNode.js';
 import PositionNode from './accessors/PositionNode.js';
 import ReferenceNode from './accessors/ReferenceNode.js';
+import ReflectNode from './accessors/ReflectNode.js';
 import SkinningNode from './accessors/SkinningNode.js';
 import TextureNode from './accessors/TextureNode.js';
 import UVNode from './accessors/UVNode.js';
@@ -118,6 +120,7 @@ const nodeLib = {
 	// accessors
 	BufferNode,
 	CameraNode,
+	CubeTextureNode,
 	MaterialNode,
 	MaterialReferenceNode,
 	ModelNode,
@@ -127,6 +130,7 @@ const nodeLib = {
 	PointUVNode,
 	PositionNode,
 	ReferenceNode,
+	ReflectNode,
 	SkinningNode,
 	TextureNode,
 	UVNode,
@@ -205,6 +209,7 @@ export {
 	// accessors
 	BufferNode,
 	CameraNode,
+	CubeTextureNode,
 	MaterialNode,
 	MaterialReferenceNode,
 	ModelNode,
@@ -214,6 +219,7 @@ export {
 	PointUVNode,
 	PositionNode,
 	ReferenceNode,
+	ReflectNode,
 	SkinningNode,
 	TextureNode,
 	UVNode,

+ 8 - 10
examples/jsm/nodes/ShaderNode.js

@@ -9,6 +9,8 @@ import UniformNode from './core/UniformNode.js';
 import BufferNode from './accessors/BufferNode.js';
 import PositionNode from './accessors/PositionNode.js';
 import NormalNode from './accessors/NormalNode.js';
+import CameraNode from './accessors/CameraNode.js';
+import ModelNode from './accessors/ModelNode.js';
 import TextureNode from './accessors/TextureNode.js';
 import UVNode from './accessors/UVNode.js';
 
@@ -269,22 +271,14 @@ export const imat4 = new ConvertType( 'imat4', Matrix4 );
 export const umat4 = new ConvertType( 'umat4', Matrix4 );
 export const bmat4 = new ConvertType( 'bmat4', Matrix4 );
 
-export const join = ( ...params ) => {
-
-	return nodeObject( new JoinNode( getShaderNodeArray( params ) ) );
-
-};
+export const join = ( ...params ) => nodeObject( new JoinNode( getShaderNodeArray( params ) ) );
 
 export const uv = ( ...params ) => nodeObject( new UVNode( ...params ) );
 export const attribute = ( ...params ) => nodeObject( new AttributeNode( ...params ) );
 export const buffer = ( ...params ) => nodeObject( new BufferNode( ...params ) );
 export const texture = ( ...params ) => nodeObject( new TextureNode( ...params ) );
 
-export const cond = ( ...params ) => {
-
-	return nodeObject( new CondNode( ...getShaderNodeArray( params ) ) );
-
-};
+export const cond = ( ...params ) => nodeObject( new CondNode( ...getShaderNodeArray( params ) ) );
 
 export const addTo = ( varNode, ...params ) => {
 
@@ -327,6 +321,10 @@ export const positionWorld = new ShaderNodeObject( new PositionNode( PositionNod
 export const positionView = new ShaderNodeObject( new PositionNode( PositionNode.VIEW ) );
 export const positionViewDirection = new ShaderNodeObject( new PositionNode( PositionNode.VIEW_DIRECTION ) );
 
+export const viewMatrix = new ShaderNodeObject( new ModelNode( ModelNode.VIEW_MATRIX ) );
+
+export const cameraPosition = new ShaderNodeObject( new CameraNode( CameraNode.POSITION ) );
+
 export const PI = float( 3.141592653589793 );
 export const PI2 = float( 6.283185307179586 );
 export const PI_HALF = float( 1.5707963267948966 );

+ 2 - 0
examples/jsm/nodes/accessors/CameraNode.js

@@ -40,6 +40,8 @@ class CameraNode extends Object3DNode {
 
 		} else {
 
+			this.object3d = camera;
+
 			super.update( frame );
 
 		}

+ 76 - 0
examples/jsm/nodes/accessors/CubeTextureNode.js

@@ -0,0 +1,76 @@
+import TextureNode from './TextureNode.js';
+import UniformNode from '../core/UniformNode.js';
+import ReflectNode from './ReflectNode.js';
+
+class CubeTextureNode extends TextureNode {
+
+	constructor( value, uvNode = new ReflectNode(), biasNode = null ) {
+
+		super( value, uvNode, biasNode );
+
+	}
+
+	getInputType( /*builder*/ ) {
+
+		return 'cubeTexture';
+
+	}
+
+	generate( builder, output ) {
+
+		const texture = this.value;
+
+		if ( ! texture || texture.isCubeTexture !== true ) {
+
+			throw new Error( 'CubeTextureNode: Need a three.js cube texture.' );
+
+		}
+
+		const textureProperty = UniformNode.prototype.generate.call( this, builder, 'cubeTexture' );
+
+		if ( output === 'samplerCube' || output === 'textureCube' ) {
+
+			return textureProperty;
+
+		} else if ( output === 'sampler' ) {
+
+			return textureProperty + '_sampler';
+
+		} else {
+
+			const nodeData = builder.getDataFromNode( this );
+
+			let snippet = nodeData.snippet;
+
+			if ( snippet === undefined ) {
+
+				const uvSnippet = this.uvNode.build( builder, 'vec3' );
+				const biasNode = this.biasNode;
+
+				if ( biasNode !== null ) {
+
+					const biasSnippet = biasNode.build( builder, 'float' );
+
+					snippet = builder.getCubeTextureBias( textureProperty, uvSnippet, biasSnippet );
+
+				} else {
+
+					snippet = builder.getCubeTexture( textureProperty, uvSnippet );
+
+				}
+
+				nodeData.snippet = snippet;
+
+			}
+
+			return builder.format( snippet, 'vec4', output );
+
+		}
+
+	}
+
+}
+
+CubeTextureNode.prototype.isCubeTextureNode = true;
+
+export default CubeTextureNode;

+ 63 - 0
examples/jsm/nodes/accessors/ReflectNode.js

@@ -0,0 +1,63 @@
+import Node from '../core/Node.js';
+import { nodeObject, normalWorld, positionWorld, cameraPosition, sub, normalize, join, negate, reflect } from '../ShaderNode.js';
+
+class ReflectNode extends Node {
+
+	static VECTOR = 'vector';
+	static CUBE = 'cube';
+
+	constructor( scope = ReflectNode.CUBE ) {
+
+		super( 'vec3' );
+
+		this.scope = scope;
+
+	}
+
+	getHash( /*builder*/ ) {
+
+		return `reflect-${this.scope}`;
+
+	}
+
+	generate( builder ) {
+
+		const scope = this.scope;
+
+		if ( scope === ReflectNode.VECTOR ) {
+
+			const cameraToFrag = normalize( sub( positionWorld, cameraPosition ) );
+			const reflectVec = reflect( cameraToFrag, normalWorld );
+
+			return reflectVec.build( builder );
+
+		} else if ( scope === ReflectNode.CUBE ) {
+
+			const reflectVec = nodeObject( new ReflectNode( ReflectNode.VECTOR ) );
+			const cubeUV = join( negate( reflectVec.x ), reflectVec.yz );
+
+			return cubeUV.build( builder );
+
+		}
+
+	}
+
+	serialize( data ) {
+
+		super.serialize( data );
+
+		data.scope = this.scope;
+
+	}
+
+	deserialize( data ) {
+
+		super.deserialize( data );
+
+		this.scope = data.scope;
+
+	}
+
+}
+
+export default ReflectNode;

+ 8 - 6
examples/jsm/nodes/accessors/TextureNode.js

@@ -55,21 +55,23 @@ class TextureNode extends UniformNode {
 				const uvSnippet = this.uvNode.build( builder, 'vec2' );
 				const biasNode = this.biasNode;
 
-				let biasSnippet = null;
-
 				if ( biasNode !== null ) {
 
-					biasSnippet = biasNode.build( builder, 'float' );
+					const biasSnippet = biasNode.build( builder, 'float' );
 
-				}
+					snippet = builder.getTextureBias( textureProperty, uvSnippet, biasSnippet );
+
+				} else {
 
-				snippet = builder.getTexture( textureProperty, uvSnippet, biasSnippet );
+					snippet = builder.getTexture( textureProperty, uvSnippet );
+
+				}
 
 				nodeData.snippet = snippet;
 
 			}
 
-			return builder.format( snippet, 'texture', output );
+			return builder.format( snippet, 'vec4', output );
 
 		}
 

+ 14 - 2
examples/jsm/nodes/core/NodeBuilder.js

@@ -142,13 +142,25 @@ class NodeBuilder {
 
 	}
 
-	getTexture( /* textureProperty, uvSnippet, biasSnippet = null */ ) {
+	getTexture( /* textureProperty, uvSnippet */ ) {
 
 		console.warn( 'Abstract function.' );
 
 	}
 
-	getCubeTexture( /* textureProperty, uvSnippet, biasSnippet = null */ ) {
+	getTextureBias( /* textureProperty, uvSnippet, biasSnippet */ ) {
+
+		console.warn( 'Abstract function.' );
+
+	}
+
+	getCubeTexture( /* textureProperty, uvSnippet */ ) {
+
+		console.warn( 'Abstract function.' );
+
+	}
+
+	getCubeTextureBias( /* textureProperty, uvSnippet, biasSnippet */ ) {
 
 		console.warn( 'Abstract function.' );
 

+ 12 - 15
examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js

@@ -159,33 +159,31 @@ class WebGLNodeBuilder extends NodeBuilder {
 
 	}
 
-	getTexture( textureProperty, uvSnippet, biasSnippet = null ) {
+	getTexture( textureProperty, uvSnippet ) {
 
-		if ( biasSnippet !== null ) {
+		return `texture2D( ${textureProperty}, ${uvSnippet} )`;
 
-			return `texture2D( ${textureProperty}, ${uvSnippet}, ${biasSnippet} )`;
+	}
 
-		} else {
+	getTextureBias( textureProperty, uvSnippet, biasSnippet ) {
 
-			return `texture2D( ${textureProperty}, ${uvSnippet} )`;
+		if ( this.material.extensions !== undefined ) this.material.extensions.shaderTextureLOD = true;
 
-		}
+		return `textureLod( ${textureProperty}, ${uvSnippet}, ${biasSnippet} )`;
 
 	}
 
-	getCubeTexture( textureProperty, uvSnippet, biasSnippet = null ) {
-
-		const textureCube = 'textureCubeLodEXT'; // textureCubeLodEXT textureLod
+	getCubeTexture( textureProperty, uvSnippet ) {
 
-		if ( biasSnippet !== null ) {
+		return `textureCube( ${textureProperty}, ${uvSnippet} )`;
 
-			return `${textureCube}( ${textureProperty}, ${uvSnippet}, ${biasSnippet} )`;
+	}
 
-		} else {
+	getCubeTextureBias( textureProperty, uvSnippet, biasSnippet ) {
 
-			return `${textureCube}( ${textureProperty}, ${uvSnippet} )`;
+		if ( this.material.extensions !== undefined ) this.material.extensions.shaderTextureLOD = true;
 
-		}
+		return `textureLod( ${textureProperty}, ${uvSnippet}, ${biasSnippet} )`;
 
 	}
 
@@ -367,7 +365,6 @@ ${this.shader[ getShaderStageProperty( shaderStage ) ]}
 		this.vertexShader = shaderData.vertex;
 		this.fragmentShader = shaderData.fragment;
 
-
 	}
 
 	build() {

+ 13 - 2
examples/jsm/renderers/webgl/nodes/WebGLNodes.js

@@ -23,10 +23,21 @@ Material.prototype.onBeforeRender = function ( renderer, scene, camera, geometry
 		nodeFrame.object = object;
 		nodeFrame.renderer = renderer;
 
-		for ( const node of nodeBuilder.updateNodes ) {
+		const updateNodes = nodeBuilder.updateNodes;
 
-			nodeFrame.updateNode( node );
+		if ( updateNodes.length > 0 ) {
 
+			// force refresh material uniforms
+			renderer.state.useProgram( null );
+
+			//this.uniformsNeedUpdate = true;
+
+			for ( const node of updateNodes ) {
+
+				nodeFrame.updateNode( node );
+
+			}
+			
 		}
 
 	}

+ 6 - 6
examples/jsm/renderers/webgpu/WebGPUSampledTexture.js

@@ -30,9 +30,9 @@ WebGPUSampledTexture.prototype.isSampledTexture = true;
 
 class WebGPUSampledArrayTexture extends WebGPUSampledTexture {
 
-	constructor( name ) {
+	constructor( name, texture ) {
 
-		super( name );
+		super( name, texture );
 
 		this.dimension = GPUTextureViewDimension.TwoDArray;
 
@@ -44,9 +44,9 @@ WebGPUSampledArrayTexture.prototype.isSampledArrayTexture = true;
 
 class WebGPUSampled3DTexture extends WebGPUSampledTexture {
 
-	constructor( name ) {
+	constructor( name, texture ) {
 
-		super( name );
+		super( name, texture );
 
 		this.dimension = GPUTextureViewDimension.ThreeD;
 
@@ -58,9 +58,9 @@ WebGPUSampled3DTexture.prototype.isSampled3DTexture = true;
 
 class WebGPUSampledCubeTexture extends WebGPUSampledTexture {
 
-	constructor( name ) {
+	constructor( name, texture ) {
 
-		super( name );
+		super( name, texture );
 
 		this.dimension = GPUTextureViewDimension.Cube;
 

+ 4 - 3
examples/jsm/renderers/webgpu/WebGPUTextureUtils.js

@@ -123,7 +123,7 @@ fn main( @location( 0 ) vTex : vec2<f32> ) -> @location( 0 ) vec4<f32> {
 
 	}
 
-	generateMipmaps( textureGPU, textureGPUDescriptor ) {
+	generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer = 0, mipLevelOffset = 1 ) {
 
 		const pipeline = this.getMipmapPipeline( textureGPUDescriptor.format );
 
@@ -135,11 +135,12 @@ fn main( @location( 0 ) vTex : vec2<f32> ) -> @location( 0 ) vec4<f32> {
 			mipLevelCount: 1
 		} );
 
-		for ( let i = 1; i < textureGPUDescriptor.mipLevelCount; i ++ ) {
+		for ( let i = mipLevelOffset; i < textureGPUDescriptor.mipLevelCount; i ++ ) {
 
 			const dstView = textureGPU.createView( {
 				baseMipLevel: i,
-				mipLevelCount: 1
+				mipLevelCount: 1,
+				baseArrayLayer
 			} );
 
 			const passEncoder = commandEncoder.beginRenderPass( {

+ 14 - 8
examples/jsm/renderers/webgpu/WebGPUTextures.js

@@ -361,7 +361,11 @@ class WebGPUTextures {
 
 		} else if ( texture.isCubeTexture ) {
 
-			this._copyCubeMapToTexture( image, texture, textureGPU );
+			if ( image.length === 6 ) {
+
+				this._copyCubeMapToTexture( image, texture, textureGPU, textureGPUDescriptor, needsMipmaps );
+
+			}
 
 		} else {
 
@@ -415,15 +419,17 @@ class WebGPUTextures {
 
 	}
 
-	_copyCubeMapToTexture( images, texture, textureGPU ) {
+	_copyCubeMapToTexture( images, texture, textureGPU, textureGPUDescriptor, needsMipmaps ) {
 
-		for ( let i = 0; i < images.length; i ++ ) {
+		for ( let i = 5; i >= 0; i -- ) {
 
 			const image = images[ i ];
 
 			this._getImageBitmap( image, texture ).then( imageBitmap => {
 
-				this._copyExternalImageToTexture( imageBitmap, textureGPU, { x: 0, y: 0, z: i } );
+				this._copyExternalImageToTexture( imageBitmap, textureGPU );
+
+				if ( needsMipmaps === true ) this._generateMipmaps( textureGPU, textureGPUDescriptor, i, i > 0 ? 0 : 1 );
 
 			} );
 
@@ -439,7 +445,7 @@ class WebGPUTextures {
 			}, {
 				texture: textureGPU,
 				mipLevel: 0,
-				origin: origin
+				origin
 			}, {
 				width: image.width,
 				height: image.height,
@@ -477,14 +483,14 @@ class WebGPUTextures {
 				{
 					width: Math.ceil( width / blockData.width ) * blockData.width,
 					height: Math.ceil( height / blockData.width ) * blockData.width,
-					depthOrArrayLayers: 1,
+					depthOrArrayLayers: 1
 				} );
 
 		}
 
 	}
 
-	_generateMipmaps( textureGPU, textureGPUDescriptor ) {
+	_generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer, mipLevelOffset ) {
 
 		if ( this.utils === null ) {
 
@@ -492,7 +498,7 @@ class WebGPUTextures {
 
 		}
 
-		this.utils.generateMipmaps( textureGPU, textureGPUDescriptor );
+		this.utils.generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer, mipLevelOffset );
 
 	}
 

+ 43 - 11
examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js

@@ -6,7 +6,7 @@ import {
 	ColorNodeUniform, Matrix3NodeUniform, Matrix4NodeUniform
 } from './WebGPUNodeUniform.js';
 import WebGPUNodeSampler from './WebGPUNodeSampler.js';
-import { WebGPUNodeSampledTexture } from './WebGPUNodeSampledTexture.js';
+import { WebGPUNodeSampledTexture, WebGPUNodeSampledCubeTexture } from './WebGPUNodeSampledTexture.js';
 
 import WebGPUUniformBuffer from '../WebGPUUniformBuffer.js';
 import { getVectorLength, getStrideLength } from '../WebGPUBufferUtils.js';
@@ -33,27 +33,27 @@ const wgslTypeLib = {
 	int: 'i32',
 	uint: 'u32',
 	bool: 'bool',
-	
+
 	vec2: 'vec2<f32>',
 	ivec2: 'vec2<i32>',
 	uvec2: 'vec2<u32>',
 	bvec2: 'vec2<bool>',
-	
+
 	vec3: 'vec3<f32>',
 	ivec3: 'vec3<i32>',
 	uvec3: 'vec3<u32>',
 	bvec3: 'vec3<bool>',
-	
+
 	vec4: 'vec4<f32>',
 	ivec4: 'vec4<i32>',
 	uvec4: 'vec4<u32>',
 	bvec4: 'vec4<bool>',
-	
+
 	mat3: 'mat3x3<f32>',
 	imat3: 'mat3x3<i32>',
 	umat3: 'mat3x3<u32>',
 	bmat3: 'mat3x3<bool>',
-	
+
 	mat4: 'mat4x4<f32>',
 	imat4: 'mat4x4<i32>',
 	umat4: 'mat4x4<u32>',
@@ -362,7 +362,7 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 	}
 
-	getTexture( textureProperty, uvSnippet, biasSnippet, shaderStage = this.shaderStage ) {
+	getSampler( textureProperty, uvSnippet, shaderStage = this.shaderStage ) {
 
 		if ( shaderStage === 'fragment' ) {
 
@@ -380,6 +380,18 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 	}
 
+	getTexture( textureProperty, uvSnippet, shaderStage = this.shaderStage ) {
+
+		return this.getSampler( textureProperty, uvSnippet, shaderStage );
+
+	}
+
+	getCubeTexture( textureProperty, uvSnippet, shaderStage = this.shaderStage ) {
+
+		return this.getSampler( textureProperty, uvSnippet, shaderStage );
+
+	}
+
 	getPropertyName( node, shaderStage = this.shaderStage ) {
 
 		if ( node.isNodeVary === true ) {
@@ -395,7 +407,7 @@ class WebGPUNodeBuilder extends NodeBuilder {
 			const name = node.name;
 			const type = node.type;
 
-			if ( type === 'texture' ) {
+			if ( type === 'texture' || type === 'cubeTexture' ) {
 
 				return name;
 
@@ -434,10 +446,21 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 			const bindings = this.bindings[ shaderStage ];
 
-			if ( type === 'texture' ) {
+			if ( type === 'texture' || type === 'cubeTexture' ) {
 
 				const sampler = new WebGPUNodeSampler( `${uniformNode.name}_sampler`, uniformNode.node );
-				const texture = new WebGPUNodeSampledTexture( uniformNode.name, uniformNode.node );
+
+				let texture = null;
+
+				if ( type === 'texture' ) {
+
+					texture = new WebGPUNodeSampledTexture( uniformNode.name, uniformNode.node );
+
+				} else if ( type === 'cubeTexture' ) {
+
+					texture = new WebGPUNodeSampledCubeTexture( uniformNode.name, uniformNode.node );
+
+				}
 
 				// add first textures in sequence and group for last
 				const lastBinding = bindings[ bindings.length - 1 ];
@@ -455,7 +478,6 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 					uniformGPU = [ texture ];
 
-
 				}
 
 
@@ -652,6 +674,16 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 				snippet += `@group( 0 ) @binding( ${index ++} ) var ${uniform.name} : texture_2d<f32>; `;
 
+			} else if ( uniform.type === 'cubeTexture' ) {
+
+				if ( shaderStage === 'fragment' ) {
+
+					snippet += `@group( 0 ) @binding( ${index ++} ) var ${uniform.name}_sampler : sampler; `;
+
+				}
+
+				snippet += `@group( 0 ) @binding( ${index ++} ) var ${uniform.name} : texture_cube<f32>; `;
+
 			} else if ( uniform.type === 'buffer' ) {
 
 				const bufferNode = uniform.node;

+ 20 - 2
examples/jsm/renderers/webgpu/nodes/WebGPUNodeSampledTexture.js

@@ -1,4 +1,4 @@
-import { WebGPUSampledTexture } from '../WebGPUSampledTexture.js';
+import { WebGPUSampledTexture, WebGPUSampledCubeTexture } from '../WebGPUSampledTexture.js';
 
 class WebGPUNodeSampledTexture extends WebGPUSampledTexture {
 
@@ -18,4 +18,22 @@ class WebGPUNodeSampledTexture extends WebGPUSampledTexture {
 
 }
 
-export { WebGPUNodeSampledTexture };
+class WebGPUNodeSampledCubeTexture extends WebGPUSampledCubeTexture {
+
+	constructor( name, textureNode ) {
+
+		super( name, textureNode.value );
+
+		this.textureNode = textureNode;
+
+	}
+
+	getTexture() {
+
+		return this.textureNode.value;
+
+	}
+
+}
+
+export { WebGPUNodeSampledTexture, WebGPUNodeSampledCubeTexture };

BIN=BIN
examples/screenshots/webgl_materials_instance_uniform_nodes.jpg


BIN=BIN
examples/screenshots/webgpu_instance_uniform.jpg


+ 29 - 13
examples/webgl_materials_instance_uniform_nodes.html

@@ -28,9 +28,12 @@
 
 			import * as THREE from 'three';
 			import * as Nodes from 'three-nodes/Nodes.js';
+			import { add, mul } from 'three-nodes/ShaderNode.js';
 
 			import Stats from './jsm/libs/stats.module.js';
 
+			import { OrbitControls } from './jsm/controls/OrbitControls.js';
+
 			import { nodeFrame } from './jsm/renderers/webgl/nodes/WebGLNodes.js';
 
 			class InstanceUniformNode extends Nodes.Node {
@@ -54,9 +57,6 @@
 
 					this.uniformNode.value.copy( meshColor );
 
-					// force refresh material uniforms
-					rendererState.useProgram( null );
-
 				}
 
 				generate( builder, output ) {
@@ -70,6 +70,7 @@
 			let stats;
 
 			let camera, scene, renderer;
+			let controls;
 			let pointLight;
 
 			const objects = [];
@@ -82,8 +83,8 @@
 				const container = document.createElement( 'div' );
 				document.body.appendChild( container );
 
-				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
-				camera.position.set( 0, 200, 800 );
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 4000 );
+				camera.position.set( 0, 200, 1200 );
 
 				scene = new THREE.Scene();
 
@@ -93,12 +94,26 @@
 				helper.position.y = - 75;
 				scene.add( helper );
 
+				// CubeMap
+
+				const path = 'textures/cube/SwedishRoyalCastle/';
+				const format = '.jpg';
+				const urls = [
+					path + 'px' + format, path + 'nx' + format,
+					path + 'py' + format, path + 'ny' + format,
+					path + 'pz' + format, path + 'nz' + format
+				];
+
+				const cubeTexture = new THREE.CubeTextureLoader().load( urls );
+
 				// Material
 
 				const instanceUniform = new InstanceUniformNode();
+				const cubeTextureNode = new Nodes.CubeTextureNode( cubeTexture );
 
-				const material = new Nodes.MeshStandardNodeMaterial();
-				material.colorNode = instanceUniform;
+				const material = new THREE.MeshStandardMaterial();
+				material.colorNode = add( instanceUniform, cubeTextureNode );
+				material.emissiveNode = mul( instanceUniform, cubeTextureNode );
 
 				// Spheres geometry
 
@@ -137,6 +152,12 @@
 
 				//
 
+				controls = new OrbitControls( camera, renderer.domElement );
+				controls.minDistance = 400;
+				controls.maxDistance = 2000;
+
+				//
+
 				stats = new Stats();
 				container.appendChild( stats.dom );
 
@@ -152,7 +173,7 @@
 
 				mesh.color = new THREE.Color( Math.random() * 0xffffff );
 
-				mesh.position.x = ( objects.length % 4 ) * 200 - 400;
+				mesh.position.x = ( objects.length % 4 ) * 200 - 300;
 				mesh.position.z = Math.floor( objects.length / 4 ) * 200 - 200;
 
 				mesh.rotation.x = Math.random() * 200 - 100;
@@ -191,11 +212,6 @@
 
 				const timer = 0.0001 * Date.now();
 
-				camera.position.x = Math.cos( timer ) * 1000;
-				camera.position.z = Math.sin( timer ) * 1000;
-
-				camera.lookAt( scene.position );
-
 				for ( let i = 0, l = objects.length; i < l; i ++ ) {
 
 					const object = objects[ i ];

+ 29 - 10
examples/webgpu_instance_uniform.html

@@ -28,10 +28,13 @@
 
 			import * as THREE from 'three';
 			import * as Nodes from 'three-nodes/Nodes.js';
+			import { add, mul } from 'three-nodes/ShaderNode.js';
 
 			import WebGPU from './jsm/capabilities/WebGPU.js';
 			import WebGPURenderer from './jsm/renderers/webgpu/WebGPURenderer.js';
 
+			import { OrbitControls } from './jsm/controls/OrbitControls.js';
+
 			import { TeapotGeometry } from './jsm/geometries/TeapotGeometry.js';
 
 			import Stats from './jsm/libs/stats.module.js';
@@ -69,6 +72,7 @@
 			let stats;
 
 			let camera, scene, renderer;
+			let controls;
 
 			const objects = [];
 
@@ -87,8 +91,8 @@
 				const container = document.createElement( 'div' );
 				document.body.appendChild( container );
 
-				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
-				camera.position.set( 0, 200, 800 );
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 4000 );
+				camera.position.set( 0, 200, 1200 );
 
 				scene = new THREE.Scene();
 
@@ -99,12 +103,26 @@
 				helper.position.y = - 75;
 				scene.add( helper );
 
+				// CubeMap
+
+				const path = 'textures/cube/SwedishRoyalCastle/';
+				const format = '.jpg';
+				const urls = [
+					path + 'px' + format, path + 'nx' + format,
+					path + 'py' + format, path + 'ny' + format,
+					path + 'pz' + format, path + 'nz' + format
+				];
+
+				const cubeTexture = new THREE.CubeTextureLoader().load( urls );
+
 				// Materials
 
 				const instanceUniform = new InstanceUniformNode();
+				const cubeTextureNode = new Nodes.CubeTextureNode( cubeTexture );
 
-				const material = new Nodes.MeshBasicNodeMaterial();
-				material.colorNode = instanceUniform;
+				const material = new THREE.MeshStandardMaterial();
+				material.colorNode = add( instanceUniform, cubeTextureNode );
+				material.emissiveNode = mul( instanceUniform, cubeTextureNode );
 
 				// Geometry
 
@@ -125,6 +143,12 @@
 
 				//
 
+				controls = new OrbitControls( camera, renderer.domElement );
+				controls.minDistance = 400;
+				controls.maxDistance = 2000;
+
+				//
+
 				stats = new Stats();
 				container.appendChild( stats.dom );
 
@@ -142,7 +166,7 @@
 
 				mesh.color = new THREE.Color( Math.random() * 0xffffff );
 
-				mesh.position.x = ( objects.length % 4 ) * 200 - 400;
+				mesh.position.x = ( objects.length % 4 ) * 200 - 300;
 				mesh.position.z = Math.floor( objects.length / 4 ) * 200 - 200;
 
 				mesh.rotation.x = Math.random() * 200 - 100;
@@ -179,11 +203,6 @@
 
 				const timer = 0.0001 * Date.now();
 
-				camera.position.x = Math.cos( timer ) * 1000;
-				camera.position.z = Math.sin( timer ) * 1000;
-
-				camera.lookAt( scene.position );
-
 				for ( let i = 0, l = objects.length; i < l; i ++ ) {
 
 					const object = objects[ i ];