Browse Source

Merge branch 'mrdoob-dev' into dev

Rik Cabanier 3 years ago
parent
commit
a97dc9c2db
37 changed files with 1011 additions and 570 deletions
  1. 28 40
      build/three.js
  2. 0 0
      build/three.min.js
  3. 35 52
      build/three.module.js
  4. 15 1
      docs/examples/en/renderers/CSS2DRenderer.html
  5. 15 1
      docs/examples/en/renderers/CSS3DRenderer.html
  6. 1 1
      editor/sw.js
  7. 2 1
      examples/files.json
  8. 27 14
      examples/jsm/exporters/USDZExporter.js
  9. 19 0
      examples/jsm/loaders/KTX2Loader.js
  10. 5 4
      examples/jsm/renderers/CSS2DRenderer.js
  11. 5 4
      examples/jsm/renderers/CSS3DRenderer.js
  12. 11 9
      examples/jsm/renderers/nodes/ShaderNode.js
  13. 13 1
      examples/jsm/renderers/nodes/accessors/NormalNode.js
  14. 15 3
      examples/jsm/renderers/nodes/accessors/PositionNode.js
  15. 105 0
      examples/jsm/renderers/nodes/accessors/SkinningNode.js
  16. 6 0
      examples/jsm/renderers/nodes/core/AttributeNode.js
  17. 32 0
      examples/jsm/renderers/nodes/core/BypassNode.js
  18. 31 3
      examples/jsm/renderers/nodes/core/Node.js
  19. 63 18
      examples/jsm/renderers/nodes/core/NodeBuilder.js
  20. 24 2
      examples/jsm/renderers/nodes/core/NodeKeywords.js
  21. 10 1
      examples/jsm/renderers/nodes/core/VaryNode.js
  22. 22 0
      examples/jsm/renderers/nodes/inputs/BufferNode.js
  23. 1 1
      examples/jsm/renderers/nodes/procedural/CheckerNode.js
  24. 4 4
      examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js
  25. 2 2
      examples/jsm/renderers/webgl/nodes/WebGLNodes.js
  26. 0 13
      examples/jsm/renderers/webgpu/WebGPURenderer.js
  27. 48 11
      examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js
  28. 1 1
      examples/jsm/renderers/webgpu/nodes/WebGPUNodes.js
  29. 44 44
      examples/misc_exporter_collada.html
  30. BIN
      examples/screenshots/webgpu_skinning.jpg
  31. 22 17
      examples/webgl_geometry_spline_editor.html
  32. 2 0
      examples/webgl_interactive_voxelpainter.html
  33. 20 9
      examples/webgl_loader_texture_ktx2.html
  34. 131 0
      examples/webgpu_skinning.html
  35. 241 302
      package-lock.json
  36. 10 10
      package.json
  37. 1 1
      src/renderers/WebGLRenderer.js

+ 28 - 40
build/three.js

@@ -9,7 +9,7 @@
 	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.THREE = {}));
 }(this, (function (exports) { 'use strict';
 
-	const REVISION = '133dev';
+	const REVISION = '133';
 	const MOUSE = {
 		LEFT: 0,
 		MIDDLE: 1,
@@ -12503,7 +12503,6 @@
 
 				getExtension('OES_texture_float_linear');
 				getExtension('EXT_color_buffer_half_float');
-				getExtension('EXT_multisampled_render_to_texture');
 			},
 			get: function (name) {
 				const extension = getExtension(name);
@@ -12844,13 +12843,15 @@
 							buffer[offset + stride + 0] = morph.x;
 							buffer[offset + stride + 1] = morph.y;
 							buffer[offset + stride + 2] = morph.z;
+							buffer[offset + stride + 3] = 0;
 
 							if (hasMorphNormals === true) {
 								morph.fromBufferAttribute(morphNormal, j);
 								if (morphNormal.normalized === true) denormalize(morph, morphNormal);
-								buffer[offset + stride + 3] = morph.x;
-								buffer[offset + stride + 4] = morph.y;
-								buffer[offset + stride + 5] = morph.z;
+								buffer[offset + stride + 4] = morph.x;
+								buffer[offset + stride + 5] = morph.y;
+								buffer[offset + stride + 6] = morph.z;
+								buffer[offset + stride + 7] = 0;
 							}
 						}
 					}
@@ -17622,8 +17623,6 @@
 			let xrFrame = null;
 			let depthStyle = null;
 			let clearStyle = null;
-			const msaartcSupported = renderer.extensions.has('EXT_multisampled_render_to_texture');
-			let msaaExt = null;
 			const controllers = [];
 			const inputSourcesMap = new Map(); //
 
@@ -17822,9 +17821,7 @@
 							layers: [glProjLayer]
 						});
 
-						if (isMultisample && msaartcSupported) {
-							msaaExt = renderer.extensions.get('EXT_multisampled_render_to_texture');
-						} else if (isMultisample) {
+						if (isMultisample) {
 							glMultisampledFramebuffer = gl.createFramebuffer();
 							glColorRenderbuffer = gl.createRenderbuffer();
 							gl.bindRenderbuffer(gl.RENDERBUFFER, glColorRenderbuffer);
@@ -18053,20 +18050,11 @@
 							const glSubImage = glBinding.getViewSubImage(glProjLayer, view);
 							state.bindXRFramebuffer(glFramebuffer);
 
-							if (isMultisample && msaartcSupported) {
-								if (glSubImage.depthStencilTexture !== undefined) {
-									msaaExt.framebufferTexture2DMultisampleEXT(gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_2D, glSubImage.depthStencilTexture, 0, 4);
-								}
-
-								msaaExt.framebufferTexture2DMultisampleEXT(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, glSubImage.colorTexture, 0, 4);
-							} else {
-								if (glSubImage.depthStencilTexture !== undefined) {
-									gl.framebufferTexture2D(gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_2D, glSubImage.depthStencilTexture, 0);
-								}
-
-								gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, glSubImage.colorTexture, 0);
+							if (glSubImage.depthStencilTexture !== undefined) {
+								gl.framebufferTexture2D(gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_2D, glSubImage.depthStencilTexture, 0);
 							}
 
+							gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, glSubImage.colorTexture, 0);
 							viewport = glSubImage.viewport;
 						}
 
@@ -18084,7 +18072,7 @@
 						}
 					}
 
-					if (isMultisample && !msaartcSupported) {
+					if (isMultisample) {
 						state.bindXRFramebuffer(glMultisampledFramebuffer);
 						if (clearStyle !== null) gl.clear(clearStyle);
 					}
@@ -18101,7 +18089,7 @@
 
 				if (onAnimationFrameCallback) onAnimationFrameCallback(time, frame);
 
-				if (isMultisample && !msaartcSupported) {
+				if (isMultisample) {
 					const width = glProjLayer.textureWidth;
 					const height = glProjLayer.textureHeight;
 					state.bindFramebuffer(gl.READ_FRAMEBUFFER, glMultisampledFramebuffer);
@@ -19168,7 +19156,7 @@
 			if (scene === null) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)
 
 			const frontFaceCW = object.isMesh && object.matrixWorld.determinant() < 0;
-			const program = setProgram(camera, scene, material, object);
+			const program = setProgram(camera, scene, geometry, material, object);
 			state.setMaterial(material, frontFaceCW); //
 
 			let index = geometry.index;
@@ -19188,10 +19176,6 @@
 				rangeFactor = 2;
 			}
 
-			if (geometry.morphAttributes.position !== undefined || geometry.morphAttributes.normal !== undefined) {
-				morphtargets.update(object, geometry, material, program);
-			}
-
 			bindingStates.setup(object, material, program, geometry, index);
 			let attribute;
 			let renderer = bufferRenderer;
@@ -19551,7 +19535,7 @@
 			material.onBeforeRender(_this, scene, camera, geometry, object, group);
 
 			if (object.isImmediateRenderObject) {
-				const program = setProgram(camera, scene, material, object);
+				const program = setProgram(camera, scene, geometry, material, object);
 				state.setMaterial(material);
 				bindingStates.reset();
 				renderObjectImmediate(object, program);
@@ -19669,7 +19653,7 @@
 			materialProperties.vertexTangents = parameters.vertexTangents;
 		}
 
-		function setProgram(camera, scene, material, object) {
+		function setProgram(camera, scene, geometry, material, object) {
 			if (scene.isScene !== true) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
 
 			textures.resetTextureUnits();
@@ -19677,11 +19661,11 @@
 			const environment = material.isMeshStandardMaterial ? scene.environment : null;
 			const encoding = _currentRenderTarget === null ? _this.outputEncoding : _currentRenderTarget.texture.encoding;
 			const envMap = (material.isMeshStandardMaterial ? cubeuvmaps : cubemaps).get(material.envMap || environment);
-			const vertexAlphas = material.vertexColors === true && !!object.geometry && !!object.geometry.attributes.color && object.geometry.attributes.color.itemSize === 4;
-			const vertexTangents = !!material.normalMap && !!object.geometry && !!object.geometry.attributes.tangent;
-			const morphTargets = !!object.geometry && !!object.geometry.morphAttributes.position;
-			const morphNormals = !!object.geometry && !!object.geometry.morphAttributes.normal;
-			const morphTargetsCount = !!object.geometry && !!object.geometry.morphAttributes.position ? object.geometry.morphAttributes.position.length : 0;
+			const vertexAlphas = material.vertexColors === true && !!geometry && !!geometry.attributes.color && geometry.attributes.color.itemSize === 4;
+			const vertexTangents = !!material.normalMap && !!geometry && !!geometry.attributes.tangent;
+			const morphTargets = !!geometry && !!geometry.morphAttributes.position;
+			const morphNormals = !!geometry && !!geometry.morphAttributes.normal;
+			const morphTargetsCount = !!geometry && !!geometry.morphAttributes.position ? geometry.morphAttributes.position.length : 0;
 			const materialProperties = properties.get(material);
 			const lights = currentRenderState.state.lights;
 
@@ -19791,9 +19775,9 @@
 				if (material.isMeshPhongMaterial || material.isMeshToonMaterial || material.isMeshLambertMaterial || material.isMeshBasicMaterial || material.isMeshStandardMaterial || material.isShaderMaterial || material.isShadowMaterial || object.isSkinnedMesh) {
 					p_uniforms.setValue(_gl, 'viewMatrix', camera.matrixWorldInverse);
 				}
-			} // skinning uniforms must be set even if material didn't change
-			// auto-setting of texture unit for bone texture must go before other textures
-			// otherwise textures used for skinning can take over texture units reserved for other material textures
+			} // skinning and morph target uniforms must be set even if material didn't change
+			// auto-setting of texture unit for bone and morph texture must go before other textures
+			// otherwise textures used for skinning and morphing can take over texture units reserved for other material textures
 
 
 			if (object.isSkinnedMesh) {
@@ -19812,6 +19796,10 @@
 				}
 			}
 
+			if (!!geometry && (geometry.morphAttributes.position !== undefined || geometry.morphAttributes.normal !== undefined)) {
+				morphtargets.update(object, geometry, material, program);
+			}
+
 			if (refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow) {
 				materialProperties.receiveShadow = object.receiveShadow;
 				p_uniforms.setValue(_gl, 'receiveShadow', object.receiveShadow);
@@ -20973,7 +20961,7 @@
 
 			_skinWeight.fromBufferAttribute(geometry.attributes.skinWeight, index);
 
-			_basePosition.fromBufferAttribute(geometry.attributes.position, index).applyMatrix4(this.bindMatrix);
+			_basePosition.copy(target).applyMatrix4(this.bindMatrix);
 
 			target.set(0, 0, 0);
 

File diff suppressed because it is too large
+ 0 - 0
build/three.min.js


+ 35 - 52
build/three.module.js

@@ -3,7 +3,7 @@
  * Copyright 2010-2021 Three.js Authors
  * SPDX-License-Identifier: MIT
  */
-const REVISION = '133dev';
+const REVISION = '133';
 const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };
 const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };
 const CullFaceNone = 0;
@@ -6706,8 +6706,9 @@ class Object3D extends EventDispatcher {
 
 	}
 
-	onBeforeRender() {}
-	onAfterRender() {}
+	onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {}
+
+	onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {}
 
 	applyMatrix4( matrix ) {
 
@@ -16193,7 +16194,6 @@ function WebGLExtensions( gl ) {
 
 			getExtension( 'OES_texture_float_linear' );
 			getExtension( 'EXT_color_buffer_half_float' );
-			getExtension( 'EXT_multisampled_render_to_texture' );
 
 		},
 
@@ -16673,6 +16673,7 @@ function WebGLMorphtargets( gl, capabilities, textures ) {
 						buffer[ offset + stride + 0 ] = morph.x;
 						buffer[ offset + stride + 1 ] = morph.y;
 						buffer[ offset + stride + 2 ] = morph.z;
+						buffer[ offset + stride + 3 ] = 0;
 
 						if ( hasMorphNormals === true ) {
 
@@ -16680,9 +16681,10 @@ function WebGLMorphtargets( gl, capabilities, textures ) {
 
 							if ( morphNormal.normalized === true ) denormalize( morph, morphNormal );
 
-							buffer[ offset + stride + 3 ] = morph.x;
-							buffer[ offset + stride + 4 ] = morph.y;
-							buffer[ offset + stride + 5 ] = morph.z;
+							buffer[ offset + stride + 4 ] = morph.x;
+							buffer[ offset + stride + 5 ] = morph.y;
+							buffer[ offset + stride + 6 ] = morph.z;
+							buffer[ offset + stride + 7 ] = 0;
 
 						}
 
@@ -23662,8 +23664,6 @@ class WebXRManager extends EventDispatcher {
 		let xrFrame = null;
 		let depthStyle = null;
 		let clearStyle = null;
-		const msaartcSupported = renderer.extensions.has( 'EXT_multisampled_render_to_texture' );
-		let msaaExt = null;
 
 		const controllers = [];
 		const inputSourcesMap = new Map();
@@ -23933,11 +23933,7 @@ class WebXRManager extends EventDispatcher {
 
 					session.updateRenderState( { layers: [ glProjLayer ] } );
 
-					if ( isMultisample && msaartcSupported ) {
-
-						msaaExt = renderer.extensions.get( 'EXT_multisampled_render_to_texture' );
-
-					} else if ( isMultisample ) {
+					if ( isMultisample ) {
 
 						glMultisampledFramebuffer = gl.createFramebuffer();
 						glColorRenderbuffer = gl.createRenderbuffer();
@@ -24258,28 +24254,14 @@ class WebXRManager extends EventDispatcher {
 
 						state.bindXRFramebuffer( glFramebuffer );
 
-						if ( isMultisample && msaartcSupported ) {
-
-							if ( glSubImage.depthStencilTexture !== undefined ) {
-
-								msaaExt.framebufferTexture2DMultisampleEXT( 36160, depthStyle, 3553, glSubImage.depthStencilTexture, 0, 4 );
-
-							}
-
-							msaaExt.framebufferTexture2DMultisampleEXT( 36160, 36064, 3553, glSubImage.colorTexture, 0, 4 );
-
-						} else {
-
-							if ( glSubImage.depthStencilTexture !== undefined ) {
-
-								gl.framebufferTexture2D( 36160, depthStyle, 3553, glSubImage.depthStencilTexture, 0 );
-
-							}
+						if ( glSubImage.depthStencilTexture !== undefined ) {
 
-							gl.framebufferTexture2D( 36160, 36064, 3553, glSubImage.colorTexture, 0 );
+							gl.framebufferTexture2D( 36160, depthStyle, 3553, glSubImage.depthStencilTexture, 0 );
 
 						}
 
+						gl.framebufferTexture2D( 36160, 36064, 3553, glSubImage.colorTexture, 0 );
+
 						viewport = glSubImage.viewport;
 
 					}
@@ -24304,7 +24286,7 @@ class WebXRManager extends EventDispatcher {
 
 				}
 
-				if ( isMultisample && ! msaartcSupported ) {
+				if ( isMultisample ) {
 
 					state.bindXRFramebuffer( glMultisampledFramebuffer );
 
@@ -24329,7 +24311,7 @@ class WebXRManager extends EventDispatcher {
 
 			if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );
 
-			if ( isMultisample && ! msaartcSupported ) {
+			if ( isMultisample ) {
 
 				const width = glProjLayer.textureWidth;
 				const height = glProjLayer.textureHeight;
@@ -25837,7 +25819,7 @@ function WebGLRenderer( parameters = {} ) {
 
 		const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
 
-		const program = setProgram( camera, scene, material, object );
+		const program = setProgram( camera, scene, geometry, material, object );
 
 		state.setMaterial( material, frontFaceCW );
 
@@ -25869,12 +25851,6 @@ function WebGLRenderer( parameters = {} ) {
 
 		}
 
-		if ( geometry.morphAttributes.position !== undefined || geometry.morphAttributes.normal !== undefined ) {
-
-			morphtargets.update( object, geometry, material, program );
-
-		}
-
 		bindingStates.setup( object, material, program, geometry, index );
 
 		let attribute;
@@ -26439,7 +26415,7 @@ function WebGLRenderer( parameters = {} ) {
 
 		if ( object.isImmediateRenderObject ) {
 
-			const program = setProgram( camera, scene, material, object );
+			const program = setProgram( camera, scene, geometry, material, object );
 
 			state.setMaterial( material );
 
@@ -26604,7 +26580,7 @@ function WebGLRenderer( parameters = {} ) {
 
 	}
 
-	function setProgram( camera, scene, material, object ) {
+	function setProgram( camera, scene, geometry, material, object ) {
 
 		if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
 
@@ -26614,11 +26590,11 @@ function WebGLRenderer( parameters = {} ) {
 		const environment = material.isMeshStandardMaterial ? scene.environment : null;
 		const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : _currentRenderTarget.texture.encoding;
 		const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
-		const vertexAlphas = material.vertexColors === true && !! object.geometry && !! object.geometry.attributes.color && object.geometry.attributes.color.itemSize === 4;
-		const vertexTangents = !! material.normalMap && !! object.geometry && !! object.geometry.attributes.tangent;
-		const morphTargets = !! object.geometry && !! object.geometry.morphAttributes.position;
-		const morphNormals = !! object.geometry && !! object.geometry.morphAttributes.normal;
-		const morphTargetsCount = ( !! object.geometry && !! object.geometry.morphAttributes.position ) ? object.geometry.morphAttributes.position.length : 0;
+		const vertexAlphas = material.vertexColors === true && !! geometry && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4;
+		const vertexTangents = !! material.normalMap && !! geometry && !! geometry.attributes.tangent;
+		const morphTargets = !! geometry && !! geometry.morphAttributes.position;
+		const morphNormals = !! geometry && !! geometry.morphAttributes.normal;
+		const morphTargetsCount = ( !! geometry && !! geometry.morphAttributes.position ) ? geometry.morphAttributes.position.length : 0;
 
 		const materialProperties = properties.get( material );
 		const lights = currentRenderState.state.lights;
@@ -26816,9 +26792,9 @@ function WebGLRenderer( parameters = {} ) {
 
 		}
 
-		// skinning uniforms must be set even if material didn't change
-		// auto-setting of texture unit for bone texture must go before other textures
-		// otherwise textures used for skinning can take over texture units reserved for other material textures
+		// skinning and morph target uniforms must be set even if material didn't change
+		// auto-setting of texture unit for bone and morph texture must go before other textures
+		// otherwise textures used for skinning and morphing can take over texture units reserved for other material textures
 
 		if ( object.isSkinnedMesh ) {
 
@@ -26846,6 +26822,13 @@ function WebGLRenderer( parameters = {} ) {
 
 		}
 
+		if ( !! geometry && ( geometry.morphAttributes.position !== undefined || geometry.morphAttributes.normal !== undefined ) ) {
+
+			morphtargets.update( object, geometry, material, program );
+
+		}
+
+
 		if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {
 
 			materialProperties.receiveShadow = object.receiveShadow;
@@ -28431,7 +28414,7 @@ class SkinnedMesh extends Mesh {
 		_skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
 		_skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
 
-		_basePosition.fromBufferAttribute( geometry.attributes.position, index ).applyMatrix4( this.bindMatrix );
+		_basePosition.copy( target ).applyMatrix4( this.bindMatrix );
 
 		target.set( 0, 0, 0 );
 

+ 15 - 1
docs/examples/en/renderers/CSS2DRenderer.html

@@ -22,7 +22,21 @@
 
 		<h2>Constructor</h2>
 
-		<h3>[name]()</h3>
+		<h3>[name]( [param:Object parameters] )</h3>
+		<p>
+		[page:DOMElement element] - A [link:https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement HTMLElement]
+		where the renderer appends its child-elements.
+		This corresponds to the [page:CSS2DRenderer.domElement domElement] property below.
+		If not passed in here, a new div element will be created.
+		</p>
+
+		<h2>Properties</h2>
+
+		<h3>[property:DOMElement domElement]</h3>
+		<p>
+			A [link:https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement HTMLElement] where the renderer appends its child-elements.<br />
+			This is automatically created by the renderer in the constructor (if not provided already).
+		</p>
 
 		<h2>Methods</h2>
 

+ 15 - 1
docs/examples/en/renderers/CSS3DRenderer.html

@@ -33,7 +33,21 @@
 
 		<h2>Constructor</h2>
 
-		<h3>[name]()</h3>
+		<h3>[name]( [param:Object parameters] )</h3>
+		<p>
+			[page:DOMElement element] - A [link:https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement HTMLElement]
+			where the renderer appends its child-elements.
+			This corresponds to the [page:CSS3DRenderer.domElement domElement] property below.
+			If not passed in here, a new div element will be created.
+		</p>
+
+		<h2>Properties</h2>
+
+		<h3>[property:DOMElement domElement]</h3>
+		<p>
+			A [link:https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement HTMLElement] where the renderer appends its child-elements.<br />
+			This is automatically created by the renderer in the constructor (if not provided already).
+		</p>
 
 		<h2>Methods</h2>
 

+ 1 - 1
editor/sw.js

@@ -1,4 +1,4 @@
-// r133
+// r133.1
 
 const cacheName = 'threejs-editor';
 

+ 2 - 1
examples/files.json

@@ -322,7 +322,8 @@
 		"webgpu_lights_selective",
 		"webgpu_materials",
 		"webgpu_rtt",
-		"webgpu_sandbox"
+		"webgpu_sandbox",
+		"webgpu_skinning"
 	],
 	"webaudio": [
 		"webaudio_orientation",

+ 27 - 14
examples/jsm/exporters/USDZExporter.js

@@ -247,7 +247,7 @@ function buildMesh( geometry ) {
 
 function buildMeshVertexCount( geometry ) {
 
-	const count = geometry.index !== null ? geometry.index.array.length : geometry.attributes.position.count;
+	const count = geometry.index !== null ? geometry.index.count : geometry.attributes.position.count;
 
 	return Array( count / 3 ).fill( 3 ).join( ', ' );
 
@@ -255,18 +255,26 @@ function buildMeshVertexCount( geometry ) {
 
 function buildMeshVertexIndices( geometry ) {
 
-	if ( geometry.index !== null ) {
+	const index = geometry.index;
+	const array = [];
 
-		return geometry.index.array.join( ', ' );
+	if ( index !== null ) {
 
-	}
+		for ( let i = 0; i < index.count; i ++ ) {
 
-	const array = [];
-	const length = geometry.attributes.position.count;
+			array.push( index.getX( i ) );
+
+		}
+
+	} else {
+
+		const length = geometry.attributes.position.count;
+
+		for ( let i = 0; i < length; i ++ ) {
 
-	for ( let i = 0; i < length; i ++ ) {
+			array.push( i );
 
-		array.push( i );
+		}
 
 	}
 
@@ -284,11 +292,14 @@ function buildVector3Array( attribute, count ) {
 	}
 
 	const array = [];
-	const data = attribute.array;
 
-	for ( let i = 0; i < data.length; i += 3 ) {
+	for ( let i = 0; i < attribute.count; i ++ ) {
+
+		const x = attribute.getX( i );
+		const y = attribute.getY( i );
+		const z = attribute.getZ( i );
 
-		array.push( `(${ data[ i + 0 ].toPrecision( PRECISION ) }, ${ data[ i + 1 ].toPrecision( PRECISION ) }, ${ data[ i + 2 ].toPrecision( PRECISION ) })` );
+		array.push( `(${ x.toPrecision( PRECISION ) }, ${ y.toPrecision( PRECISION ) }, ${ z.toPrecision( PRECISION ) })` );
 
 	}
 
@@ -306,11 +317,13 @@ function buildVector2Array( attribute, count ) {
 	}
 
 	const array = [];
-	const data = attribute.array;
 
-	for ( let i = 0; i < data.length; i += 2 ) {
+	for ( let i = 0; i < attribute.count; i ++ ) {
+
+		const x = attribute.getX( i );
+		const y = attribute.getY( i );
 
-		array.push( `(${ data[ i + 0 ].toPrecision( PRECISION ) }, ${ 1 - data[ i + 1 ].toPrecision( PRECISION ) })` );
+		array.push( `(${ x.toPrecision( PRECISION ) }, ${ 1 - y.toPrecision( PRECISION ) })` );
 
 	}
 

+ 19 - 0
examples/jsm/loaders/KTX2Loader.js

@@ -37,6 +37,8 @@ const KTX2TransferSRGB = 2;
 const KTX2_ALPHA_PREMULTIPLIED = 1;
 const _taskCache = new WeakMap();
 
+let _activeLoaders = 0;
+
 class KTX2Loader extends Loader {
 
 	constructor( manager ) {
@@ -154,6 +156,21 @@ class KTX2Loader extends Loader {
 
 				} );
 
+			if ( _activeLoaders > 0 ) {
+
+				// Each instance loads a transcoder and allocates workers, increasing network and memory cost.
+
+				console.warn(
+
+					'THREE.KTX2Loader: Multiple active KTX2 loaders may cause performance issues.'
+					+ ' Use a single KTX2Loader instance, or call .dispose() on old instances.'
+
+				);
+
+			}
+
+			_activeLoaders++;
+
 		}
 
 		return this.transcoderPending;
@@ -248,6 +265,8 @@ class KTX2Loader extends Loader {
 		URL.revokeObjectURL( this.workerSourceURL );
 		this.workerPool.dispose();
 
+		_activeLoaders--;
+
 		return this;
 
 	}

+ 5 - 4
examples/jsm/renderers/CSS2DRenderer.js

@@ -6,11 +6,11 @@ import {
 
 class CSS2DObject extends Object3D {
 
- 	constructor( element ) {
+	constructor( element = document.createElement( 'div' ) ) {
 
 		super();
 
-		this.element = element || document.createElement( 'div' );
+		this.element = element;
 
 		this.element.style.position = 'absolute';
 		this.element.style.userSelect = 'none';
@@ -57,7 +57,7 @@ const _b = new Vector3();
 
 class CSS2DRenderer {
 
-	constructor() {
+	constructor( parameters = {} ) {
 
 		const _this = this;
 
@@ -68,7 +68,8 @@ class CSS2DRenderer {
 			objects: new WeakMap()
 		};
 
-		const domElement = document.createElement( 'div' );
+		const domElement = parameters.element !== undefined ? parameters.element : document.createElement( 'div' );
+
 		domElement.style.overflow = 'hidden';
 
 		this.domElement = domElement;

+ 5 - 4
examples/jsm/renderers/CSS3DRenderer.js

@@ -15,11 +15,11 @@ const _scale = new Vector3();
 
 class CSS3DObject extends Object3D {
 
-	constructor( element ) {
+	constructor( element = document.createElement( 'div' ) ) {
 
 		super();
 
-		this.element = element || document.createElement( 'div' );
+		this.element = element;
 		this.element.style.position = 'absolute';
 		this.element.style.pointerEvents = 'auto';
 		this.element.style.userSelect = 'none';
@@ -87,7 +87,7 @@ const _matrix2 = new Matrix4();
 
 class CSS3DRenderer {
 
-	constructor() {
+	constructor( parameters = {} ) {
 
 		const _this = this;
 
@@ -99,7 +99,8 @@ class CSS3DRenderer {
 			objects: new WeakMap()
 		};
 
-		const domElement = document.createElement( 'div' );
+		const domElement = parameters.element !== undefined ? parameters.element : document.createElement( 'div' );
+
 		domElement.style.overflow = 'hidden';
 
 		this.domElement = domElement;

+ 11 - 9
examples/jsm/renderers/nodes/ShaderNode.js

@@ -18,6 +18,12 @@ import { Vector2, Vector3, Vector4, Color } from 'three';
 
 const NodeHandler = {
 
+	construct( NodeClosure, params ) {
+
+		return NodeClosure( params[ 0 ] );
+
+	},
+
 	get: function ( node, prop ) {
 
 		// Split Properties Pass
@@ -40,7 +46,7 @@ const NodeHandler = {
 
 };
 
-export const ShaderNodeObject = ( obj ) => {
+const ShaderNodeObject = ( obj ) => {
 
 	const type = typeof obj;
 
@@ -70,7 +76,7 @@ export const ShaderNodeObject = ( obj ) => {
 
 };
 
-export const ShaderNodeArray = ( array ) => {
+const ShaderNodeArray = ( array ) => {
 
 	const len = array.length;
 
@@ -84,7 +90,7 @@ export const ShaderNodeArray = ( array ) => {
 
 };
 
-export const ShaderNodeScript = ( jsFunc ) => {
+const ShaderNodeScript = function ( jsFunc ) {
 
 	return ( ...params ) => {
 
@@ -96,17 +102,13 @@ export const ShaderNodeScript = ( jsFunc ) => {
 
 };
 
-export const ShaderNode = ( obj ) => {
-
-	return ShaderNodeScript( obj );
-
-};
+export const ShaderNode = new Proxy( ShaderNodeScript, NodeHandler );
 
 //
 // Node Material Shader Syntax
 //
 
-export const uniform = ShaderNodeScript( ( inputNode ) => {
+export const uniform = new ShaderNode( ( inputNode ) => {
 
 	inputNode.setConst( false );
 

+ 13 - 1
examples/jsm/renderers/nodes/accessors/NormalNode.js

@@ -1,5 +1,6 @@
 import Node from '../core/Node.js';
 import AttributeNode from '../core/AttributeNode.js';
+import NodeKeywords from '../core/NodeKeywords.js';
 import VaryNode from '../core/VaryNode.js';
 import ModelNode from '../accessors/ModelNode.js';
 import CameraNode from '../accessors/CameraNode.js';
@@ -9,6 +10,7 @@ import { inverseTransformDirection } from '../functions/MathFunctions.js';
 
 class NormalNode extends Node {
 
+	static GEOMETRY = 'geometry';
 	static LOCAL = 'local';
 	static WORLD = 'world';
 	static VIEW = 'view';
@@ -21,16 +23,26 @@ class NormalNode extends Node {
 
 	}
 
+	getHash( /*builder*/ ) {
+
+		return `normal-${this.scope}`;
+
+	}
+
 	generate( builder ) {
 
 		const scope = this.scope;
 
 		let outputNode = null;
 
-		if ( scope === NormalNode.LOCAL ) {
+		if ( scope === NormalNode.GEOMETRY ) {
 
 			outputNode = new AttributeNode( 'normal', 'vec3' );
 
+		} else if ( scope === NormalNode.LOCAL ) {
+
+			outputNode = new VaryNode( new NormalNode( NormalNode.GEOMETRY ) );
+
 		} else if ( scope === NormalNode.VIEW ) {
 
 			const vertexNormalNode = new OperatorNode( '*', new ModelNode( ModelNode.NORMAL_MATRIX ), new NormalNode( NormalNode.LOCAL ) );

+ 15 - 3
examples/jsm/renderers/nodes/accessors/PositionNode.js

@@ -1,5 +1,6 @@
 import Node from '../core/Node.js';
 import AttributeNode from '../core/AttributeNode.js';
+import NodeKeywords from '../core/NodeKeywords.js';
 import VaryNode from '../core/VaryNode.js';
 import ModelNode from '../accessors/ModelNode.js';
 import MathNode from '../math/MathNode.js';
@@ -8,6 +9,7 @@ import { transformDirection } from '../functions/MathFunctions.js';
 
 class PositionNode extends Node {
 
+	static GEOMETRY = 'geometry';
 	static LOCAL = 'local';
 	static WORLD = 'world';
 	static VIEW = 'view';
@@ -21,16 +23,26 @@ class PositionNode extends Node {
 
 	}
 
+	getHash( /*builder*/ ) {
+
+		return `position-${this.scope}`;
+
+	}
+
 	generate( builder ) {
 
 		const scope = this.scope;
 
 		let outputNode = null;
 
-		if ( scope === PositionNode.LOCAL ) {
-			
+		if ( scope === PositionNode.GEOMETRY ) {
+
 			outputNode = new AttributeNode( 'position', 'vec3' );
-			
+
+		} else if ( scope === PositionNode.LOCAL ) {
+
+			outputNode = new VaryNode( new PositionNode( PositionNode.GEOMETRY ) );
+
 		} else if ( scope === PositionNode.WORLD ) {
 
 			const vertexPositionNode = transformDirection.call( { dir: new PositionNode( PositionNode.LOCAL ), matrix: new ModelNode( ModelNode.WORLD_MATRIX ) } );

+ 105 - 0
examples/jsm/renderers/nodes/accessors/SkinningNode.js

@@ -0,0 +1,105 @@
+import Node from '../core/Node.js';
+import AttributeNode from '../core/AttributeNode.js';
+import ConstNode from '../core/ConstNode.js';
+import PositionNode from '../accessors/PositionNode.js';
+import NormalNode from '../accessors/NormalNode.js';
+import FunctionNode from '../core/FunctionNode.js';
+import Matrix4Node from '../inputs/Matrix4Node.js';
+import BufferNode from '../inputs/BufferNode.js';
+
+import { NodeUpdateType } from '../core/constants.js';
+
+const Skinning = new FunctionNode( `
+	void ( inout vec3 position, inout vec3 normal, const in vec4 index, const in vec4 weight, const in mat4 bindMatrix, const in mat4 bindMatrixInverse ) {
+
+		mat4 boneMatX = BoneMatrices[ int( index.x ) ];
+		mat4 boneMatY = BoneMatrices[ int( index.y ) ];
+		mat4 boneMatZ = BoneMatrices[ int( index.z ) ];
+		mat4 boneMatW = BoneMatrices[ int( index.w ) ];
+
+		// POSITION
+
+		vec4 skinVertex = bindMatrix * vec4( position, 1.0 );
+
+		vec4 skinned = vec4( 0.0 );
+		skinned += boneMatX * skinVertex * weight.x;
+		skinned += boneMatY * skinVertex * weight.y;
+		skinned += boneMatZ * skinVertex * weight.z;
+		skinned += boneMatW * skinVertex * weight.w;
+
+		position = ( bindMatrixInverse * skinned ).xyz;
+
+		// NORMAL
+
+		mat4 skinMatrix = mat4( 0.0 );
+		skinMatrix += skinWeight.x * boneMatX;
+		skinMatrix += skinWeight.y * boneMatY;
+		skinMatrix += skinWeight.z * boneMatZ;
+		skinMatrix += skinWeight.w * boneMatW;
+		skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;
+
+		normal = vec4( skinMatrix * vec4( normal, 0.0 ) ).xyz;
+
+	}`
+);
+
+class SkinningNode extends Node {
+
+	constructor( skinnedMesh ) {
+
+		super( 'void' );
+
+		this.skinnedMesh = skinnedMesh;
+
+		this.updateType = NodeUpdateType.Object;
+
+		//
+
+		this.skinIndexNode = new AttributeNode( 'skinIndex', 'uvec4' );
+		this.skinWeightNode = new AttributeNode( 'skinWeight', 'vec4' );
+
+		this.bindMatrixNode = new Matrix4Node( skinnedMesh.bindMatrix );
+		this.bindMatrixInverseNode = new Matrix4Node( skinnedMesh.bindMatrixInverse );
+		this.boneMatricesNode = new BufferNode( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length );
+
+	}
+
+	generate( builder ) {
+
+		const keywords = builder.getContextValue( 'keywords' );
+
+		keywords.addKeyword( 'BoneMatrices', () => {
+
+			return new ConstNode( this.boneMatricesNode.build( builder ), 'mat4', 'BoneMatrices' );
+
+		} );
+
+		// inout nodes
+		const position = new PositionNode( PositionNode.LOCAL );
+		const normal = new NormalNode( NormalNode.LOCAL );
+
+		const index = this.skinIndexNode;
+		const weight = this.skinWeightNode;
+		const bindMatrix = this.bindMatrixNode;
+		const bindMatrixInverse = this.bindMatrixInverseNode;
+
+		return Skinning.call( {
+			position,
+			normal,
+			index,
+			weight,
+			bindMatrix,
+			bindMatrixInverse
+		} ).build( builder );
+
+	}
+
+	update() {
+
+		this.skinnedMesh.skeleton.update();
+
+	}
+
+}
+
+export default SkinningNode;

+ 6 - 0
examples/jsm/renderers/nodes/core/AttributeNode.js

@@ -11,6 +11,12 @@ class AttributeNode extends Node {
 
 	}
 
+	getHash( builder ) {
+
+		return this.getAttributeName( builder );
+
+	}
+
 	setAttributeName( attributeName ) {
 
 		this._attributeName = attributeName;

+ 32 - 0
examples/jsm/renderers/nodes/core/BypassNode.js

@@ -0,0 +1,32 @@
+import Node from './Node.js';
+
+class BypassNode extends Node {
+
+	constructor( returnNode, callNode ) {
+
+		super();
+
+		this.outputNode = returnNode;
+		this.callNode = callNode;
+
+	}
+
+	getNodeType( builder ) {
+
+		return this.outputNode.getNodeType( builder );
+
+	}
+
+	generate( builder, output ) {
+
+		builder.addFlowCode( this.callNode.build( builder, 'void' ) );
+
+		return this.outputNode.build( builder, output );
+
+	}
+
+}
+
+BypassNode.prototype.isBypassNode = true;
+
+export default BypassNode;

+ 31 - 3
examples/jsm/renderers/nodes/core/Node.js

@@ -1,5 +1,7 @@
 import { NodeUpdateType } from './constants.js';
 
+import { MathUtils } from 'three';
+
 class Node {
 
 	constructor( nodeType = null ) {
@@ -8,6 +10,8 @@ class Node {
 
 		this.updateType = NodeUpdateType.None;
 
+		this.uuid = MathUtils.generateUUID();
+
 	}
 
 	get type() {
@@ -16,6 +20,12 @@ class Node {
 
 	}
 
+	getHash( /*builder*/ ) {
+
+		return this.uuid;
+
+	}
+
 	getUpdateType( /*builder*/ ) {
 
 		return this.updateType;
@@ -48,16 +58,28 @@ class Node {
 
 	build( builder, output = null ) {
 
+		const hash = this.getHash( builder );
+		const sharedNode = builder.getNodeFromHash( hash );
+
+		if ( sharedNode !== undefined && this !== sharedNode ) {
+
+			return sharedNode.build( builder, output );
+
+		}
+
 		builder.addNode( this );
+		builder.addStack( this );
 
 		const isGenerateOnce = this.generate.length === 1;
 
+		let snippet = null;
+
 		if ( isGenerateOnce ) {
 
 			const type = this.getNodeType( builder );
 			const nodeData = builder.getDataFromNode( this );
 
-			let snippet = nodeData.snippet;
+			snippet = nodeData.snippet;
 
 			if ( snippet === undefined ) {
 
@@ -67,11 +89,17 @@ class Node {
 
 			}
 
-			return builder.format( snippet, type, output );
+			snippet = builder.format( snippet, type, output );
+
+		} else {
+
+			snippet = this.generate( builder, output );
 
 		}
 
-		return this.generate( builder, output );
+		builder.removeStack( this );
+
+		return snippet;
 
 	}
 

+ 63 - 18
examples/jsm/renderers/nodes/core/NodeBuilder.js

@@ -10,13 +10,15 @@ import { LinearEncoding } from 'three';
 
 class NodeBuilder {
 
-	constructor( material, renderer ) {
+	constructor( object, renderer ) {
 
-		this.material = material;
+		this.object = object;
+		this.material = object.material;
 		this.renderer = renderer;
 
 		this.nodes = [];
 		this.updateNodes = [];
+		this.hashNodes = {};
 
 		this.vertexShader = null;
 		this.fragmentShader = null;
@@ -29,10 +31,11 @@ class NodeBuilder {
 		this.varys = [];
 		this.vars = { vertex: [], fragment: [] };
 		this.flow = { code: '' };
+		this.stack = [];
 
 		this.context = {
 			keywords: new NodeKeywords(),
-			material: material
+			material: object.material
 		};
 
 		this.nodesData = new WeakMap();
@@ -42,6 +45,30 @@ class NodeBuilder {
 
 	}
 
+	addStack( node ) {
+/*
+		if ( this.stack.indexOf( node ) !== - 1 ) {
+
+			console.warn( 'Recursive node: ', node );
+
+		}
+*/
+		this.stack.push( node );
+
+	}
+
+	removeStack( node ) {
+
+		const lastStack = this.stack.pop();
+
+		if ( lastStack !== node ) {
+
+			throw new Error( 'NodeBuilder: Invalid node stack!' );
+
+		}
+
+	}
+
 	addNode( node ) {
 
 		if ( this.nodes.indexOf( node ) === - 1 ) {
@@ -56,10 +83,18 @@ class NodeBuilder {
 
 			this.nodes.push( node );
 
+			this.hashNodes[ node.getHash( this ) ] = node;
+
 		}
 
 	}
 
+	getNodeFromHash( hash ) {
+
+		return this.hashNodes[ hash ];
+
+	}
+
 	addSlot( shaderStage, slot ) {
 
 		this.slots[ shaderStage ].push( slot );
@@ -503,15 +538,25 @@ class NodeBuilder {
 
 	build() {
 
-		const shaderStages = [ 'vertex', 'fragment' ];
+		const shaderStages = [ 'fragment', 'vertex' ];
 		const shaderData = {};
 
 		for ( const shaderStage of shaderStages ) {
 
-			this.setShaderStage( shaderStage );
-
 			this.define( shaderStage, 'NODE_CODE', '' );
 
+		}
+
+		if ( this.context.vertex !== undefined && this.context.vertex !== null ) {
+
+			this.flowNodeFromShaderStage( 'vertex', this.context.vertex );
+
+		}
+
+		for ( const shaderStage of shaderStages ) {
+
+			this.setShaderStage( shaderStage );
+
 			const slots = this.slots[ shaderStage ];
 
 			for ( const slot of slots ) {
@@ -582,26 +627,26 @@ class NodeBuilder {
 			case 'float to vec4' : return `vec4( vec3( ${snippet} ), 1.0 )`;
 
 			case 'vec2 to float' : return `${snippet}.x`;
-			case 'vec2 to vec3'  : return `vec3( ${snippet}, 0.0 )`;
-			case 'vec2 to vec4'  : return `vec4( ${snippet}.xy, 0.0, 1.0 )`;
+			case 'vec2 to vec3' : return `vec3( ${snippet}, 0.0 )`;
+			case 'vec2 to vec4' : return `vec4( ${snippet}.xy, 0.0, 1.0 )`;
 
 			case 'vec3 to float' : return `${snippet}.x`;
-			case 'vec3 to vec2'  : return `${snippet}.xy`;
-			case 'vec3 to vec4'  : return `vec4( ${snippet}, 1.0 )`;
+			case 'vec3 to vec2' : return `${snippet}.xy`;
+			case 'vec3 to vec4' : return `vec4( ${snippet}, 1.0 )`;
 
 			case 'vec4 to float' : return `${snippet}.x`;
-			case 'vec4 to vec2'  : return `${snippet}.xy`;
-			case 'vec4 to vec3'  : return `${snippet}.xyz`;
+			case 'vec4 to vec2' : return `${snippet}.xy`;
+			case 'vec4 to vec3' : return `${snippet}.xyz`;
 
 			case 'mat3 to float' : return `( ${snippet} * vec3( 1.0 ) ).x`;
-			case 'mat3 to vec2'  : return `( ${snippet} * vec3( 1.0 ) ).xy`;
-			case 'mat3 to vec3'  : return `( ${snippet} * vec3( 1.0 ) ).xyz`;
-			case 'mat3 to vec4'  : return `vec4( ${snippet} * vec3( 1.0 ), 1.0 )`;
+			case 'mat3 to vec2' : return `( ${snippet} * vec3( 1.0 ) ).xy`;
+			case 'mat3 to vec3' : return `( ${snippet} * vec3( 1.0 ) ).xyz`;
+			case 'mat3 to vec4' : return `vec4( ${snippet} * vec3( 1.0 ), 1.0 )`;
 
 			case 'mat4 to float' : return `( ${snippet} * vec4( 1.0 ) ).x`;
-			case 'mat4 to vec2'  : return `( ${snippet} * vec4( 1.0 ) ).xy`;
-			case 'mat4 to vec3'  : return `( ${snippet} * vec4( 1.0 ) ).xyz`;
-			case 'mat4 to vec4'  : return `( ${snippet} * vec4( 1.0 ) )`;
+			case 'mat4 to vec2' : return `( ${snippet} * vec4( 1.0 ) ).xy`;
+			case 'mat4 to vec3' : return `( ${snippet} * vec4( 1.0 ) ).xyz`;
+			case 'mat4 to vec4' : return `( ${snippet} * vec4( 1.0 ) )`;
 
 		}
 

+ 24 - 2
examples/jsm/renderers/nodes/core/NodeKeywords.js

@@ -71,6 +71,8 @@ class NodeKeywords {
 
 		this.nodes = [];
 
+		this.keywordsCallback = {};
+
 	}
 
 	getNode( name ) {
@@ -79,6 +81,16 @@ class NodeKeywords {
 
 		if ( node === undefined ) {
 
+			if ( this.keywordsCallback[ name ] !== undefined ) {
+				
+				node = this.keywordsCallback[ name ]( name );
+				
+				this.nodes[ name ] = node;
+				
+				return node;
+				
+			}
+
 			switch ( name ) {
 
 				case NodeKeywords.PI:
@@ -113,7 +125,7 @@ class NodeKeywords {
 
 				case NodeKeywords.PositionLocal:
 
-					node = new VarNode( new PositionNode( PositionNode.LOCAL ), name );
+					node = new VarNode( new PositionNode( PositionNode.GEOMETRY ), name );
 
 					break;
 
@@ -137,7 +149,7 @@ class NodeKeywords {
 
 				case NodeKeywords.NormalLocal:
 
-					node = new VarNode( new NormalNode( NormalNode.LOCAL ), name );
+					node = new VarNode( new NormalNode( NormalNode.GEOMETRY ), name );
 
 					break;
 
@@ -194,6 +206,16 @@ class NodeKeywords {
 
 	}
 
+	addKeyword( name, callback ) {
+		
+		this.keywords.push( name );
+		
+		this.keywordsCallback[ name ] = callback;
+		
+		return this;
+		
+	}
+
 	parse( code ) {
 
 		const keywordNames = this.keywords;

+ 10 - 1
examples/jsm/renderers/nodes/core/VaryNode.js

@@ -3,11 +3,12 @@ import { NodeShaderStage } from './constants.js';
 
 class VaryNode extends Node {
 
-	constructor( value ) {
+	constructor( value, name = '' ) {
 
 		super();
 
 		this.value = value;
+		this.name = name;
 
 	}
 
@@ -23,8 +24,16 @@ class VaryNode extends Node {
 
 		const type = this.getNodeType( builder );
 		const value = this.value;
+		const name = this.name;
 
 		const nodeVary = builder.getVaryFromNode( this, type );
+
+		if ( name !== '' ) {
+
+			nodeVary.name = name;
+
+		}
+
 		const propertyName = builder.getPropertyName( nodeVary );
 
 		// force nodeVary.snippet work in vertex stage

+ 22 - 0
examples/jsm/renderers/nodes/inputs/BufferNode.js

@@ -0,0 +1,22 @@
+import InputNode from '../core/InputNode.js';
+import ExpressionNode from '../core/ExpressionNode.js';
+import UVNode from '../accessors/UVNode.js';
+import ColorSpaceNode from '../display/ColorSpaceNode.js';
+
+class BufferNode extends InputNode {
+
+	constructor( value, bufferType, bufferCount = 0 ) {
+
+		super( 'buffer' );
+
+		this.value = value;
+		this.bufferType = bufferType;
+		this.bufferCount = bufferCount;
+
+	}
+
+}
+
+BufferNode.prototype.isBufferNode = true;
+
+export default BufferNode;

+ 1 - 1
examples/jsm/renderers/nodes/procedural/CheckerNode.js

@@ -5,7 +5,7 @@ import UVNode from '../accessors/UVNode.js';
 import { ShaderNode, float, add, mul, floor, mod, sign } from '../ShaderNode.js';
 
 // Three.JS Shader Language
-const checkerShaderNode = ShaderNode( ( uv ) => {
+const checkerShaderNode = new ShaderNode( ( uv ) => {
 
 	uv = mul( uv, 2.0 );
 

+ 4 - 4
examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js

@@ -20,17 +20,17 @@ function getShaderStageProperty( shaderStage ) {
 
 class WebGLNodeBuilder extends NodeBuilder {
 
-	constructor( material, renderer, shader ) {
+	constructor( object, renderer, shader ) {
 
-		super( material, renderer );
+		super( object, renderer );
 
 		this.shader = shader;
 
-		this._parseMaterial();
+		this._parseObject();
 
 	}
 
-	_parseMaterial() {
+	_parseObject() {
 
 		const material = this.material;
 

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

@@ -6,9 +6,9 @@ import { Material } from 'three';
 const builders = new WeakMap();
 export const nodeFrame = new NodeFrame();
 
-Material.prototype.onBuild = function ( parameters, renderer ) {
+Material.prototype.onBuild = function ( object, parameters, renderer ) {
 
-	builders.set( this, new WebGLNodeBuilder( this, renderer, parameters ).build() );
+	builders.set( this, new WebGLNodeBuilder( object, renderer, parameters ).build() );
 
 };
 

+ 0 - 13
examples/jsm/renderers/webgpu/WebGPURenderer.js

@@ -693,19 +693,6 @@ class WebGPURenderer {
 
 			} else if ( object.isMesh || object.isLine || object.isPoints ) {
 
-				if ( object.isSkinnedMesh ) {
-
-					// update skeleton only once in a frame
-
-					if ( object.skeleton.frame !== info.render.frame ) {
-
-						object.skeleton.update();
-						object.skeleton.frame = info.render.frame;
-
-					}
-
-				}
-
 				if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
 
 					if ( this.sortObjects === true ) {

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

@@ -6,22 +6,26 @@ import {
 import WebGPUNodeSampler from './WebGPUNodeSampler.js';
 import { WebGPUNodeSampledTexture } from './WebGPUNodeSampledTexture.js';
 
+import WebGPUUniformBuffer from '../WebGPUUniformBuffer.js';
 import { getVectorLength, getStrideLength } from '../WebGPUBufferUtils.js';
 
 import NodeSlot from '../../nodes/core/NodeSlot.js';
 import VarNode from '../../nodes/core/VarNode.js';
+import BypassNode from '../../nodes/core/BypassNode.js';
 import NodeBuilder from '../../nodes/core/NodeBuilder.js';
 import MaterialNode from '../../nodes/accessors/MaterialNode.js';
+import PositionNode from '../../nodes/accessors/PositionNode.js';
 import NormalNode from '../../nodes/accessors/NormalNode.js';
 import ModelViewProjectionNode from '../../nodes/accessors/ModelViewProjectionNode.js';
+import SkinningNode from '../../nodes/accessors/SkinningNode.js';
 import LightContextNode from '../../nodes/lights/LightContextNode.js';
 import ShaderLib from './ShaderLib.js';
 
 class WebGPUNodeBuilder extends NodeBuilder {
 
-	constructor( material, renderer, lightNode = null ) {
+	constructor( object, renderer, lightNode = null ) {
 
-		super( material, renderer );
+		super( object, renderer );
 
 		this.lightNode = lightNode;
 
@@ -32,12 +36,13 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 		this.nativeShader = null;
 
-		this._parseMaterial();
+		this._parseObject();
 
 	}
 
-	_parseMaterial() {
+	_parseObject() {
 
+		const object = this.object;
 		const material = this.material;
 
 		// get shader
@@ -60,23 +65,31 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 		if ( material.isMeshStandardMaterial || material.isMeshBasicMaterial || material.isPointsMaterial || material.isLineBasicMaterial ) {
 
-			const mvpNode = new ModelViewProjectionNode();
-
 			let lightNode = material.lightNode;
 
+			let vertex = new PositionNode( PositionNode.GEOMETRY );
+
 			if ( lightNode === null && this.lightNode && this.lightNode.hasLights === true ) {
 
 				lightNode = this.lightNode;
 
 			}
 
-			if ( material.positionNode && material.positionNode.isNode ) {
+			if ( material.positionNode !== undefined ) {
+
+				vertex = material.positionNode;
+
+			}
+
+			if ( object.isSkinnedMesh === true ) {
 
-				mvpNode.position = material.positionNode;
+				vertex = new BypassNode( vertex, new SkinningNode( object ) );
 
 			}
 
-			this.addSlot( 'vertex', new NodeSlot( mvpNode, 'MVP', 'vec4' ) );
+			this.context.vertex = vertex;
+
+			this.addSlot( 'vertex', new NodeSlot( new ModelViewProjectionNode(), 'MVP', 'vec4' ) );
 
 			if ( material.alphaTestNode && material.alphaTestNode.isNode ) {
 
@@ -205,6 +218,10 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 				return name;
 
+			} else if ( type === 'buffer' ) {
+
+				return `${name}.value`;
+
 			} else {
 
 				return `nodeUniforms.${name}`;
@@ -249,6 +266,18 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 				uniformGPU = [ sampler, texture ];
 
+			} else if ( type === 'buffer' ) {
+
+				const buffer = new WebGPUUniformBuffer( 'NodeBuffer', node.value );
+
+				// add first textures in sequence and group for last
+				const lastBinding = bindings[ bindings.length - 1 ];
+				const index = lastBinding && lastBinding.isUniformsGroup ? bindings.length - 1 : bindings.length;
+
+				bindings.splice( index, 0, buffer );
+
+				uniformGPU = buffer;
+
 			} else {
 
 				let uniformsGroup = this.uniformsGroup[ shaderStage ];
@@ -363,6 +392,14 @@ class WebGPUNodeBuilder extends NodeBuilder {
 				snippet += `layout(set = 0, binding = ${index ++}) uniform sampler ${uniform.name}_sampler; `;
 				snippet += `layout(set = 0, binding = ${index ++}) uniform texture2D ${uniform.name}; `;
 
+			} else if ( uniform.type === 'buffer' ) {
+
+				const bufferNode = uniform.node;
+				const bufferType = bufferNode.bufferType;
+				const bufferCount = bufferNode.bufferCount;
+
+				snippet += `layout(set = 0, binding = ${index ++}) uniform NodeBuffer { uniform ${bufferType}[ ${bufferCount} ] value; } ${uniform.name}; `;
+
 			} else {
 
 				const vectorType = this.getVectorType( uniform.type );
@@ -397,11 +434,11 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 		const keywords = this.getContextValue( 'keywords' );
 
-		for ( const shaderStage of [ 'vertex', 'fragment' ] ) {
+		for ( const shaderStage of [ 'fragment', 'vertex' ] ) {
 
 			this.shaderStage = shaderStage;
 
-			keywords.include( this, this.nativeShader.fragmentShader );
+			keywords.include( this, this.nativeShader[ shaderStage + 'Shader' ] );
 
 		}
 

+ 1 - 1
examples/jsm/renderers/webgpu/nodes/WebGPUNodes.js

@@ -19,7 +19,7 @@ class WebGPUNodes {
 
 		if ( nodeBuilder === undefined ) {
 
-			nodeBuilder = new WebGPUNodeBuilder( object.material, this.renderer, lightNode ).build();
+			nodeBuilder = new WebGPUNodeBuilder( object, this.renderer, lightNode ).build();
 
 			this.builders.set( object, nodeBuilder );
 

+ 44 - 44
examples/misc_exporter_collada.html

@@ -97,11 +97,11 @@
 				const normalMap = loader.load( 'textures/floors/FloorsCheckerboard_S_Normal.jpg' );
 
 				// REFLECTION MAP
-				const path = "textures/cube/pisa/";
+				const path = 'textures/cube/pisa/';
 				const urls = [
-					path + "px.png", path + "nx.png",
-					path + "py.png", path + "ny.png",
-					path + "pz.png", path + "nz.png"
+					path + 'px.png', path + 'nx.png',
+					path + 'py.png', path + 'ny.png',
+					path + 'pz.png', path + 'nz.png'
 				];
 
 				textureCube = new THREE.CubeTextureLoader().load( urls );
@@ -182,7 +182,7 @@
 					body: true,
 					fitLid: false,
 					nonblinn: false,
-					newShading: "glossy"
+					newShading: 'glossy'
 				};
 
 				let h;
@@ -191,49 +191,49 @@
 
 				// material (attributes)
 
-				h = gui.addFolder( "Material control" );
+				h = gui.addFolder( 'Material control' );
 
-				h.add( effectController, "shininess", 1.0, 400.0, 1.0 ).name( "shininess" ).onChange( render );
-				h.add( effectController, "kd", 0.0, 1.0, 0.025 ).name( "diffuse strength" ).onChange( render );
-				h.add( effectController, "ks", 0.0, 1.0, 0.025 ).name( "specular strength" ).onChange( render );
-				h.add( effectController, "metallic" ).onChange( render );
+				h.add( effectController, 'shininess', 1.0, 400.0, 1.0 ).name( 'shininess' ).onChange( render );
+				h.add( effectController, 'kd', 0.0, 1.0, 0.025 ).name( 'diffuse strength' ).onChange( render );
+				h.add( effectController, 'ks', 0.0, 1.0, 0.025 ).name( 'specular strength' ).onChange( render );
+				h.add( effectController, 'metallic' ).onChange( render );
 
 				// material (color)
 
-				h = gui.addFolder( "Material color" );
+				h = gui.addFolder( 'Material color' );
 
-				h.add( effectController, "hue", 0.0, 1.0, 0.025 ).name( "hue" ).onChange( render );
-				h.add( effectController, "saturation", 0.0, 1.0, 0.025 ).name( "saturation" ).onChange( render );
-				h.add( effectController, "lightness", 0.0, 1.0, 0.025 ).name( "lightness" ).onChange( render );
+				h.add( effectController, 'hue', 0.0, 1.0, 0.025 ).name( 'hue' ).onChange( render );
+				h.add( effectController, 'saturation', 0.0, 1.0, 0.025 ).name( 'saturation' ).onChange( render );
+				h.add( effectController, 'lightness', 0.0, 1.0, 0.025 ).name( 'lightness' ).onChange( render );
 
 				// light (point)
 
-				h = gui.addFolder( "Lighting" );
+				h = gui.addFolder( 'Lighting' );
 
-				h.add( effectController, "lhue", 0.0, 1.0, 0.025 ).name( "hue" ).onChange( render );
-				h.add( effectController, "lsaturation", 0.0, 1.0, 0.025 ).name( "saturation" ).onChange( render );
-				h.add( effectController, "llightness", 0.0, 1.0, 0.025 ).name( "lightness" ).onChange( render );
-				h.add( effectController, "ka", 0.0, 1.0, 0.025 ).name( "ambient" ).onChange( render );
+				h.add( effectController, 'lhue', 0.0, 1.0, 0.025 ).name( 'hue' ).onChange( render );
+				h.add( effectController, 'lsaturation', 0.0, 1.0, 0.025 ).name( 'saturation' ).onChange( render );
+				h.add( effectController, 'llightness', 0.0, 1.0, 0.025 ).name( 'lightness' ).onChange( render );
+				h.add( effectController, 'ka', 0.0, 1.0, 0.025 ).name( 'ambient' ).onChange( render );
 
 				// light (directional)
 
-				h = gui.addFolder( "Light direction" );
+				h = gui.addFolder( 'Light direction' );
 
-				h.add( effectController, "lx", - 1.0, 1.0, 0.025 ).name( "x" ).onChange( render );
-				h.add( effectController, "ly", - 1.0, 1.0, 0.025 ).name( "y" ).onChange( render );
-				h.add( effectController, "lz", - 1.0, 1.0, 0.025 ).name( "z" ).onChange( render );
+				h.add( effectController, 'lx', - 1.0, 1.0, 0.025 ).name( 'x' ).onChange( render );
+				h.add( effectController, 'ly', - 1.0, 1.0, 0.025 ).name( 'y' ).onChange( render );
+				h.add( effectController, 'lz', - 1.0, 1.0, 0.025 ).name( 'z' ).onChange( render );
 
-				h = gui.addFolder( "Tessellation control" );
-				h.add( effectController, "newTess", [ 2, 3, 4, 5, 6, 8, 10, 15, 20, 30, 40, 50 ] ).name( "Tessellation Level" ).onChange( render );
-				h.add( effectController, "lid" ).name( "display lid" ).onChange( render );
-				h.add( effectController, "body" ).name( "display body" ).onChange( render );
-				h.add( effectController, "bottom" ).name( "display bottom" ).onChange( render );
-				h.add( effectController, "fitLid" ).name( "snug lid" ).onChange( render );
-				h.add( effectController, "nonblinn" ).name( "original scale" ).onChange( render );
+				h = gui.addFolder( 'Tessellation control' );
+				h.add( effectController, 'newTess', [ 2, 3, 4, 5, 6, 8, 10, 15, 20, 30, 40, 50 ] ).name( 'Tessellation Level' ).onChange( render );
+				h.add( effectController, 'lid' ).name( 'display lid' ).onChange( render );
+				h.add( effectController, 'body' ).name( 'display body' ).onChange( render );
+				h.add( effectController, 'bottom' ).name( 'display bottom' ).onChange( render );
+				h.add( effectController, 'fitLid' ).name( 'snug lid' ).onChange( render );
+				h.add( effectController, 'nonblinn' ).name( 'original scale' ).onChange( render );
 
 				// shading
 
-				gui.add( effectController, "newShading", [ "wireframe", "flat", "smooth", "glossy", "textured", "normal", "reflective" ] ).name( "Shading" ).onChange( render );
+				gui.add( effectController, 'newShading', [ 'wireframe', 'flat', 'smooth', 'glossy', 'textured', 'normal', 'reflective' ] ).name( 'Shading' ).onChange( render );
 
 				const exportButton = document.getElementById( 'export' );
 				exportButton.addEventListener( 'click', exportCollada );
@@ -303,7 +303,7 @@
 				light.color.setHSL( effectController.lhue, effectController.lsaturation, effectController.llightness );
 
 				// skybox is rendered separately, so that it is always behind the teapot.
-				if ( shading === "reflective" ) {
+				if ( shading === 'reflective' ) {
 
 					scene.background = textureCube;
 
@@ -337,12 +337,12 @@
 
 				teapot = new THREE.Mesh(
 					teapotGeometry,
-					shading === "wireframe" ? wireMaterial : (
-						shading === "flat" ? flatMaterial : (
-							shading === "smooth" ? gouraudMaterial : (
-								shading === "glossy" ? phongMaterial : (
-									shading === "textured" ? texturedMaterial : (
-										shading === "normal" ? normalMaterial : reflectiveMaterial ) ) ) ) ) );	// if no match, pick Phong
+					shading === 'wireframe' ? wireMaterial : (
+						shading === 'flat' ? flatMaterial : (
+							shading === 'smooth' ? gouraudMaterial : (
+								shading === 'glossy' ? phongMaterial : (
+									shading === 'textured' ? texturedMaterial : (
+										shading === 'normal' ? normalMaterial : reflectiveMaterial ) ) ) ) ) );	// if no match, pick Phong
 
 				scene.add( teapot );
 
@@ -353,21 +353,21 @@
 			function exportCollada() {
 
 				const result = exporter.parse( teapot, undefined, { upAxis: 'Y_UP', unitName: 'millimeter', unitMeter: 0.001 } );
-				let materialType = "Phong";
+				let materialType = 'Phong';
 
-				if ( shading === "wireframe" ) {
+				if ( shading === 'wireframe' ) {
 
-					materialType = "Constant";
+					materialType = 'Constant';
 
 				}
 
-				if ( shading === "smooth" ) {
+				if ( shading === 'smooth' ) {
 
-					materialType = "Lambert";
+					materialType = 'Lambert';
 
 				}
 
-				saveString( result.data, 'teapot_' + shading + "_" + materialType + '.dae' );
+				saveString( result.data, 'teapot_' + shading + '_' + materialType + '.dae' );
 
 				result.textures.forEach( tex => {
 

BIN
examples/screenshots/webgpu_skinning.jpg


+ 22 - 17
examples/webgl_geometry_spline_editor.html

@@ -26,13 +26,12 @@
 
 			import * as THREE from '../build/three.module.js';
 
-			import Stats from './jsm/libs/stats.module.js';
 			import { GUI } from './jsm/libs/dat.gui.module.js';
 
 			import { OrbitControls } from './jsm/controls/OrbitControls.js';
 			import { TransformControls } from './jsm/controls/TransformControls.js';
 
-			let container, stats;
+			let container;
 			let camera, scene, renderer;
 			const splineHelperObjects = [];
 			let splinePointsLength = 4;
@@ -62,7 +61,6 @@
 			};
 
 			init();
-			animate();
 
 			function init() {
 
@@ -108,20 +106,18 @@
 				renderer.shadowMap.enabled = true;
 				container.appendChild( renderer.domElement );
 
-				stats = new Stats();
-				container.appendChild( stats.dom );
-
 				const gui = new GUI();
 
-				gui.add( params, 'uniform' );
+				gui.add( params, 'uniform' ).onChange( render );
 				gui.add( params, 'tension', 0, 1 ).step( 0.01 ).onChange( function ( value ) {
 
 					splines.uniform.tension = value;
 					updateSplineOutline();
+					render();
 
 				} );
-				gui.add( params, 'centripetal' );
-				gui.add( params, 'chordal' );
+				gui.add( params, 'centripetal' ).onChange( render );
+				gui.add( params, 'chordal' ).onChange( render );
 				gui.add( params, 'addPoint' );
 				gui.add( params, 'removePoint' );
 				gui.add( params, 'exportSpline' );
@@ -150,6 +146,7 @@
 				document.addEventListener( 'pointerdown', onPointerDown );
 				document.addEventListener( 'pointerup', onPointerUp );
 				document.addEventListener( 'pointermove', onPointerMove );
+				window.addEventListener( 'resize', onWindowResize );
 
 				/*******
 				 * Curves
@@ -211,6 +208,8 @@
 					new THREE.Vector3( - 91.40118730204415, 176.4306956436485, - 6.958271935582161 ),
 					new THREE.Vector3( - 383.785318791128, 491.1365363371675, 47.869296953772746 ) ] );
 
+				render();
+
 			}
 
 			function addSplineObject( position ) {
@@ -246,6 +245,8 @@
 
 				updateSplineOutline();
 
+				render();
+
 			}
 
 			function removePoint() {
@@ -265,6 +266,8 @@
 
 				updateSplineOutline();
 
+				render();
+
 			}
 
 			function updateSplineOutline() {
@@ -331,14 +334,6 @@
 
 			}
 
-			function animate() {
-
-				requestAnimationFrame( animate );
-				render();
-				stats.update();
-
-			}
-
 			function render() {
 
 				splines.uniform.mesh.visible = params.uniform;
@@ -387,6 +382,16 @@
 
 			}
 
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				render();
+
+			}
 
 		</script>
 

+ 2 - 0
examples/webgl_interactive_voxelpainter.html

@@ -109,6 +109,8 @@
 
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
+				render();
+
 			}
 
 			function onPointerMove( event ) {

+ 20 - 9
examples/webgl_loader_texture_ktx2.html

@@ -63,21 +63,32 @@
 			};
 
 			// Samples: sample_etc1s.ktx2, sample_uastc.ktx2, sample_uastc_zstd.ktx2
-			new KTX2Loader()
+			const loader = new KTX2Loader()
 				.setTranscoderPath( 'js/libs/basis/' )
-				.detectSupport( renderer )
-				.load( './textures/compressed/sample_uastc_zstd.ktx2', ( texture ) => {
+				.detectSupport( renderer );
 
-					console.info( `transcoded to ${formatStrings[ texture.format ]}` );
+			animate();
 
-					material.map = texture;
-					material.transparent = true;
+			try {
 
-					material.needsUpdate = true;
+				const texture = await loader.loadAsync( './textures/compressed/sample_uastc_zstd.ktx2' );
 
-				}, ( p ) => console.log( `...${p}` ), ( e ) => console.error( e ) );
+				console.info( `transcoded to ${formatStrings[ texture.format ]}` );
 
-			animate();
+				material.map = texture;
+				material.transparent = true;
+
+				material.needsUpdate = true;
+
+			} catch ( e ) {
+
+				console.error( e );
+
+			} finally {
+
+				loader.dispose();
+
+			}
 
 			function animate() {
 

+ 131 - 0
examples/webgpu_skinning.html

@@ -0,0 +1,131 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js - WebGPU - Skinning</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 - Skinning<br />
+			(Chrome Canary with flag: --enable-unsafe-webgpu)
+		</div>
+
+		<script type="importmap">
+		{
+			"imports": {
+				"three": "../build/three.module.js"
+			}
+		}
+		</script>
+		<script type="module">
+
+			import * as THREE from 'three';
+
+			import { FBXLoader } from './jsm/loaders/FBXLoader.js';
+
+			import WebGPURenderer from './jsm/renderers/webgpu/WebGPURenderer.js';
+			import WebGPU from './jsm/renderers/webgpu/WebGPU.js';
+
+			import LightsNode from './jsm/renderers/nodes/lights/LightsNode.js';
+
+			let camera, scene, renderer;
+
+			let mixer, clock;
+
+			init().then( animate ).catch( error );
+
+			async function init() {
+
+				if ( WebGPU.isAvailable() === false ) {
+
+					document.body.appendChild( WebGPU.getErrorMessage() );
+
+					throw 'No WebGPU support';
+
+				}
+
+				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.set( 100, 200, 300 );
+
+				scene = new THREE.Scene();
+				camera.lookAt( 0, 100, 0 );
+
+				clock = new THREE.Clock();
+
+				//lights
+
+				const light = new THREE.PointLight( 0xffffff );
+				camera.add( light );
+				scene.add( camera );
+
+				const lightNode = LightsNode.fromLights( [ light ] );
+
+				const loader = new FBXLoader();
+				loader.load( 'models/fbx/Samba Dancing.fbx', function ( object ) {
+
+					mixer = new THREE.AnimationMixer( object );
+
+					const action = mixer.clipAction( object.animations[ 0 ] );
+					action.play();
+
+					object.traverse( function ( child ) {
+
+						if ( child.isMesh ) {
+
+							child.material = new THREE.MeshStandardMaterial();
+							child.material.lightNode = lightNode;
+
+						}
+
+					} );
+
+					scene.add( object );
+
+				} );
+
+				//renderer
+
+				renderer = new WebGPURenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				window.addEventListener( 'resize', onWindowResize );
+
+				return renderer.init();
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				const delta = clock.getDelta();
+
+				if ( mixer ) mixer.update( delta );
+
+				renderer.render( scene, camera );
+
+			}
+
+			function error( error ) {
+
+				console.error( error );
+
+			}
+
+		</script>
+	</body>
+</html>

File diff suppressed because it is too large
+ 241 - 302
package-lock.json


+ 10 - 10
package.json

@@ -1,6 +1,6 @@
 {
   "name": "three",
-  "version": "0.133.0",
+  "version": "0.133.1",
   "description": "JavaScript 3D library",
   "main": "build/three.js",
   "module": "build/three.module.js",
@@ -104,23 +104,23 @@
   },
   "homepage": "https://threejs.org/",
   "devDependencies": {
-    "@babel/core": "^7.15.0",
-    "@babel/eslint-parser": "^7.15.0",
+    "@babel/core": "^7.15.5",
+    "@babel/eslint-parser": "^7.15.7",
     "@babel/plugin-proposal-class-properties": "^7.14.5",
-    "@babel/preset-env": "^7.15.0",
+    "@babel/preset-env": "^7.15.6",
     "@rollup/plugin-babel": "^5.3.0",
-    "@rollup/plugin-node-resolve": "^13.0.4",
+    "@rollup/plugin-node-resolve": "^13.0.5",
     "chalk": "^4.1.2",
-    "concurrently": "^6.2.1",
+    "concurrently": "^6.2.2",
     "eslint": "^7.32.0",
     "eslint-config-mdcs": "^5.0.0",
-    "eslint-plugin-html": "^6.1.2",
-    "glob": "^7.1.7",
-    "rollup": "^2.56.3",
+    "eslint-plugin-html": "^6.2.0",
+    "glob": "^7.2.0",
+    "rollup": "^2.57.0",
     "rollup-plugin-filesize": "^9.1.1",
     "rollup-plugin-terser": "^7.0.2",
     "rollup-plugin-visualizer": "^5.5.2",
-    "servez": "^1.11.1"
+    "servez": "^1.12.0"
   },
   "jspm": {
     "files": [

+ 1 - 1
src/renderers/WebGLRenderer.js

@@ -1419,7 +1419,7 @@ function WebGLRenderer( parameters = {} ) {
 
 			parameters.uniforms = programCache.getUniforms( material );
 
-			material.onBuild( parameters, _this );
+			material.onBuild( object, parameters, _this );
 
 			material.onBeforeCompile( parameters, _this );
 

Some files were not shown because too many files changed in this diff