瀏覽代碼

Merge remote-tracking branch 'remotes/upstream/dev' into dev

webglzhang 5 年之前
父節點
當前提交
af9cae7272

+ 54 - 5
build/three.js

@@ -8604,7 +8604,7 @@
 
 		this.userData = {};
 
-		this.needsUpdate = true;
+		this.version = 0;
 
 	}
 
@@ -8952,6 +8952,16 @@
 
 	} );
 
+	Object.defineProperty( Material.prototype, 'needsUpdate', {
+
+		set: function ( value ) {
+
+			if ( value === true ) { this.version ++; }
+
+		}
+
+	} );
+
 	/**
 	 * @author mrdoob / http://mrdoob.com/
 	 * @author alteredq / http://alteredqualia.com/
@@ -14188,7 +14198,7 @@
 
 	var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal, mapN );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif";
 
-	var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tbool frontFacing = dot( cross( S, T ), N ) > 0.0;\n\t\t\tmapN.xy *= ( float( frontFacing ) * 2.0 - 1.0 );\n\t\t#else\n\t\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif";
+	var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tmat3 tsn = mat3( S, T, N );\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif";
 
 	var clearcoat_normal_fragment_begin = "#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif";
 
@@ -22843,6 +22853,7 @@
 		//
 
 		var triggers = [];
+		var grips = [];
 
 		function findGamepad( id ) {
 
@@ -22918,6 +22929,33 @@
 
 					}
 
+					// Grip
+					buttonId = 2;
+
+					if ( grips[ i ] === undefined ) { grips[ i ] = false; }
+
+					// Skip if the grip button doesn't exist on this controller
+					if ( gamepad.buttons[ buttonId ] !== undefined ) {
+
+						if ( grips[ i ] !== gamepad.buttons[ buttonId ].pressed ) {
+
+							grips[ i ] = gamepad.buttons[ buttonId ].pressed;
+
+							if ( grips[ i ] === true ) {
+
+								controller.dispatchEvent( { type: 'squeezestart' } );
+
+							} else {
+
+								controller.dispatchEvent( { type: 'squeezeend' } );
+								controller.dispatchEvent( { type: 'squeeze' } );
+
+							}
+
+						}
+
+					}
+
 				} else {
 
 					controller.visible = false;
@@ -23290,6 +23328,9 @@
 				session.addEventListener( 'select', onSessionEvent );
 				session.addEventListener( 'selectstart', onSessionEvent );
 				session.addEventListener( 'selectend', onSessionEvent );
+				session.addEventListener( 'squeeze', onSessionEvent );
+				session.addEventListener( 'squeezestart', onSessionEvent );
+				session.addEventListener( 'squeezeend', onSessionEvent );
 				session.addEventListener( 'end', onSessionEnd );
 
 				// eslint-disable-next-line no-undef
@@ -24200,6 +24241,14 @@
 
 			var index = geometry.index;
 			var position = geometry.attributes.position;
+
+			//
+
+			if ( index !== null && index.count === 0 ) { return; }
+			if ( position === undefined || position.count === 0 ) { return; }
+
+			//
+
 			var rangeFactor = 1;
 
 			if ( material.wireframe === true ) {
@@ -25133,7 +25182,7 @@
 
 			}
 
-			if ( material.needsUpdate === false ) {
+			if ( material.version === materialProperties.__version ) {
 
 				if ( materialProperties.program === undefined ) {
 
@@ -25157,10 +25206,10 @@
 
 			}
 
-			if ( material.needsUpdate ) {
+			if ( material.version !== materialProperties.__version ) {
 
 				initMaterial( material, fog, object );
-				material.needsUpdate = false;
+				materialProperties.__version = material.version;
 
 			}
 

文件差異過大導致無法顯示
+ 125 - 285
build/three.min.js


+ 54 - 5
build/three.module.js

@@ -8598,7 +8598,7 @@ function Material() {
 
 	this.userData = {};
 
-	this.needsUpdate = true;
+	this.version = 0;
 
 }
 
@@ -8946,6 +8946,16 @@ Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 
 } );
 
+Object.defineProperty( Material.prototype, 'needsUpdate', {
+
+	set: function ( value ) {
+
+		if ( value === true ) this.version ++;
+
+	}
+
+} );
+
 /**
  * @author mrdoob / http://mrdoob.com/
  * @author alteredq / http://alteredqualia.com/
@@ -14174,7 +14184,7 @@ var normal_fragment_begin = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewP
 
 var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal, mapN );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif";
 
-var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tbool frontFacing = dot( cross( S, T ), N ) > 0.0;\n\t\t\tmapN.xy *= ( float( frontFacing ) * 2.0 - 1.0 );\n\t\t#else\n\t\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif";
+var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tmat3 tsn = mat3( S, T, N );\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif";
 
 var clearcoat_normal_fragment_begin = "#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif";
 
@@ -22835,6 +22845,7 @@ function WebVRManager( renderer ) {
 	//
 
 	var triggers = [];
+	var grips = [];
 
 	function findGamepad( id ) {
 
@@ -22910,6 +22921,33 @@ function WebVRManager( renderer ) {
 
 				}
 
+				// Grip
+				buttonId = 2;
+
+				if ( grips[ i ] === undefined ) grips[ i ] = false;
+
+				// Skip if the grip button doesn't exist on this controller
+				if ( gamepad.buttons[ buttonId ] !== undefined ) {
+
+					if ( grips[ i ] !== gamepad.buttons[ buttonId ].pressed ) {
+
+						grips[ i ] = gamepad.buttons[ buttonId ].pressed;
+
+						if ( grips[ i ] === true ) {
+
+							controller.dispatchEvent( { type: 'squeezestart' } );
+
+						} else {
+
+							controller.dispatchEvent( { type: 'squeezeend' } );
+							controller.dispatchEvent( { type: 'squeeze' } );
+
+						}
+
+					}
+
+				}
+
 			} else {
 
 				controller.visible = false;
@@ -23282,6 +23320,9 @@ function WebXRManager( renderer, gl ) {
 			session.addEventListener( 'select', onSessionEvent );
 			session.addEventListener( 'selectstart', onSessionEvent );
 			session.addEventListener( 'selectend', onSessionEvent );
+			session.addEventListener( 'squeeze', onSessionEvent );
+			session.addEventListener( 'squeezestart', onSessionEvent );
+			session.addEventListener( 'squeezeend', onSessionEvent );
 			session.addEventListener( 'end', onSessionEnd );
 
 			// eslint-disable-next-line no-undef
@@ -24192,6 +24233,14 @@ function WebGLRenderer( parameters ) {
 
 		var index = geometry.index;
 		var position = geometry.attributes.position;
+
+		//
+
+		if ( index !== null && index.count === 0 ) return;
+		if ( position === undefined || position.count === 0 ) return;
+
+		//
+
 		var rangeFactor = 1;
 
 		if ( material.wireframe === true ) {
@@ -25125,7 +25174,7 @@ function WebGLRenderer( parameters ) {
 
 		}
 
-		if ( material.needsUpdate === false ) {
+		if ( material.version === materialProperties.__version ) {
 
 			if ( materialProperties.program === undefined ) {
 
@@ -25149,10 +25198,10 @@ function WebGLRenderer( parameters ) {
 
 		}
 
-		if ( material.needsUpdate ) {
+		if ( material.version !== materialProperties.__version ) {
 
 			initMaterial( material, fog, object );
-			material.needsUpdate = false;
+			materialProperties.__version = material.version;
 
 		}
 

+ 6 - 2
docs/api/en/materials/Material.html

@@ -186,8 +186,7 @@
 
 		<h3>[property:Boolean needsUpdate]</h3>
 		<p>
-		Specifies that the material needs to be recompiled.<br />
-		This property is automatically set to *true* when instancing a new material.
+		Specifies that the material needs to be recompiled.
 		</p>
 
 		<h3>[property:Float opacity]</h3>
@@ -296,6 +295,11 @@
 		This gets automatically assigned, so this shouldn't be edited.
 		</p>
 
+		<h3>[property:Integer version]</h3>
+		<p>
+		This starts at *0* and counts how many times [property:Boolean needsUpdate] is set to *true*.
+		</p>
+
 		<h3>[property:Integer vertexColors]</h3>
 		<p>
 		Defines whether vertex coloring is used.

+ 6 - 2
docs/api/zh/materials/Material.html

@@ -163,8 +163,7 @@ Which stencil operation to perform when the comparison function returns true and
 <p>对象的可选名称(不必是唯一的)。默认值为空字符串。</p>
 
 <h3>[property:Boolean needsUpdate]</h3>
-<p>指定需要重新编译材质。<br/>
-	实例化新材质时,此属性自动设置为true。
+<p>指定需要重新编译材质。
 </p>
 
 <h3>[property:Float opacity]</h3>
@@ -255,6 +254,11 @@ Defines whether this material is tone mapped according to the renderer's [page:W
 <p> 此材质实例的[link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID],会自动分配,不应该被更改。
 </p>
 
+<h3>[property:Integer version]</h3>
+<p>
+This starts at *0* and counts how many times [property:Boolean needsUpdate] is set to *true*.
+</p>
+
 <h3>[property:Integer vertexColors]</h3>
 <p> 是否使用顶点着色。默认值为[page:Materials THREE.NoColors]。
 	其他选项有[page:Materials THREE.VertexColors] 和 [page:Materials THREE.FaceColors]。

+ 4 - 3
examples/jsm/nodes/materials/NodeMaterial.js

@@ -30,7 +30,9 @@ function NodeMaterial( vertex, fragment ) {
 
 	this.onBeforeCompile = function ( shader, renderer ) {
 
-		if ( this.needsUpdate ) {
+		var materialProperties = renderer.properties.get( this );
+
+		if ( this.version !== materialProperties.__version ) {
 
 			this.build( { renderer: renderer } );
 
@@ -74,6 +76,7 @@ Object.defineProperties( NodeMaterial.prototype, {
 
 		set: function ( value ) {
 
+			if ( value === true ) this.version ++;
 			this.needsCompile = value;
 
 		},
@@ -120,8 +123,6 @@ NodeMaterial.prototype.build = function ( params ) {
 
 	this.transparent = builder.requires.transparent || this.blending > NormalBlending;
 
-	this.needsUpdate = false;
-
 	return this;
 
 };

+ 28 - 22
src/core/BufferAttribute.d.ts

@@ -16,54 +16,60 @@ export class BufferAttribute {
 	updateRange: { offset: number; count: number };
 	version: number;
 	normalized: boolean;
-	needsUpdate: boolean;
 	count: number;
-	onUpload: Function;
 
-	setUsage( usage: Usage ): BufferAttribute;
-	clone(): this;
+	set needsUpdate( value: boolean );
+
+	isBufferAttribute: true;
+
+	onUploadCallback: () => void;
+	onUpload( callback: () => void ): this;
+	setUsage( usage: Usage ): this;
+	clone(): BufferAttribute;
 	copy( source: BufferAttribute ): this;
 	copyAt(
 		index1: number,
 		attribute: BufferAttribute,
 		index2: number
-	): BufferAttribute;
-	copyArray( array: ArrayLike<number> ): BufferAttribute;
+	): this;
+	copyArray( array: ArrayLike<number> ): this;
 	copyColorsArray(
 		colors: { r: number; g: number; b: number }[]
-	): BufferAttribute;
-	copyVector2sArray( vectors: { x: number; y: number }[] ): BufferAttribute;
+	): this;
+	copyVector2sArray( vectors: { x: number; y: number }[] ): this;
 	copyVector3sArray(
 		vectors: { x: number; y: number; z: number }[]
-	): BufferAttribute;
+	): this;
 	copyVector4sArray(
 		vectors: { x: number; y: number; z: number; w: number }[]
-	): BufferAttribute;
+	): this;
 	set(
 		value: ArrayLike<number> | ArrayBufferView,
 		offset?: number
-	): BufferAttribute;
+	): this;
 	getX( index: number ): number;
-	setX( index: number, x: number ): BufferAttribute;
+	setX( index: number, x: number ): this;
 	getY( index: number ): number;
-	setY( index: number, y: number ): BufferAttribute;
+	setY( index: number, y: number ): this;
 	getZ( index: number ): number;
-	setZ( index: number, z: number ): BufferAttribute;
+	setZ( index: number, z: number ): this;
 	getW( index: number ): number;
-	setW( index: number, z: number ): BufferAttribute;
-	setXY( index: number, x: number, y: number ): BufferAttribute;
-	setXYZ( index: number, x: number, y: number, z: number ): BufferAttribute;
+	setW( index: number, z: number ): this;
+	setXY( index: number, x: number, y: number ): this;
+	setXYZ( index: number, x: number, y: number, z: number ): this;
 	setXYZW(
 		index: number,
 		x: number,
 		y: number,
 		z: number,
 		w: number
-	): BufferAttribute;
-	/**
-	 * @deprecated Use {@link BufferAttribute#count .count} instead.
-	 */
-	length: number;
+	): this;
+	toJSON(): {
+		itemSize: number,
+		type: string,
+		array: number[],
+		normalized: boolean
+	};
 
 }
 

+ 5 - 7
src/core/InterleavedBufferAttribute.d.ts

@@ -11,13 +11,15 @@ export class InterleavedBufferAttribute {
 		normalized?: boolean
 	);
 
-	uuid: string;
 	data: InterleavedBuffer;
 	itemSize: number;
 	offset: number;
-	count: number;
 	normalized: boolean;
-	array: any[];
+
+	get count(): number;
+	get array(): ArrayLike<number>;
+
+	isInterleavedBufferAttribute: true;
 
 	getX( index: number ): number;
 	setX( index: number, x: number ): InterleavedBufferAttribute;
@@ -41,9 +43,5 @@ export class InterleavedBufferAttribute {
 		z: number,
 		w: number
 	): InterleavedBufferAttribute;
-	/**
-	 * @deprecated Use {@link InterleavedBufferAttribute#count .count} instead.
-	 */
-	length: number;
 
 }

+ 2 - 2
src/loaders/AnimationLoader.d.ts

@@ -8,10 +8,10 @@ export class AnimationLoader extends Loader {
 
 	load(
 		url: string,
-		onLoad?: ( response: string | ArrayBuffer ) => void,
+		onLoad: ( response: AnimationClip[] ) => void,
 		onProgress?: ( request: ProgressEvent ) => void,
 		onError?: ( event: ErrorEvent ) => void
-	): any;
+	): void;
 	parse( json: any ): AnimationClip[];
 
 }

+ 3 - 3
src/loaders/AudioLoader.d.ts

@@ -7,9 +7,9 @@ export class AudioLoader extends Loader {
 
 	load(
 		url: string,
-		onLoad: Function,
-		onPrgress: Function,
-		onError: Function
+		onLoad: ( audioBuffer: AudioBuffer ) => void,
+		onProgress?: ( request: ProgressEvent ) => void,
+		onError?: ( event: ErrorEvent ) => void
 	): void;
 
 }

+ 5 - 4
src/loaders/BufferGeometryLoader.d.ts

@@ -1,6 +1,7 @@
 import { Loader } from './Loader';
 import { LoadingManager } from './LoadingManager';
 import { BufferGeometry } from './../core/BufferGeometry';
+import { InstancedBufferGeometry } from '../core/InstancedBufferGeometry';
 
 export class BufferGeometryLoader extends Loader {
 
@@ -8,10 +9,10 @@ export class BufferGeometryLoader extends Loader {
 
 	load(
 		url: string,
-		onLoad: ( bufferGeometry: BufferGeometry ) => void,
-		onProgress?: ( event: any ) => void,
-		onError?: ( event: any ) => void
+		onLoad: ( bufferGeometry: InstancedBufferGeometry | BufferGeometry ) => void,
+		onProgress?: ( request: ProgressEvent ) => void,
+		onError?: ( event: ErrorEvent ) => void
 	): void;
-	parse( json: any ): BufferGeometry;
+	parse( json: any ): InstancedBufferGeometry | BufferGeometry;
 
 }

+ 1 - 1
src/loaders/ImageBitmapLoader.d.ts

@@ -10,7 +10,7 @@ export class ImageBitmapLoader extends Loader {
 	setOptions( options: object ): ImageBitmapLoader;
 	load(
 		url: string,
-		onLoad?: ( response: string | ArrayBuffer ) => void,
+		onLoad?: ( response: ImageBitmap ) => void,
 		onProgress?: ( request: ProgressEvent ) => void,
 		onError?: ( event: ErrorEvent ) => void
 	): any;

+ 5 - 0
src/materials/Material.d.ts

@@ -293,6 +293,11 @@ export class Material extends EventDispatcher {
 	 */
 	userData: any;
 
+	/**
+	 * This starts at 0 and counts how many times .needsUpdate is set to true.
+	 */
+	version: number;
+
 	/**
 	 * Return a new material with the same parameters as this material.
 	 */

+ 10 - 1
src/materials/Material.js

@@ -74,7 +74,7 @@ function Material() {
 
 	this.userData = {};
 
-	this.needsUpdate = true;
+	this.version = 0;
 
 }
 
@@ -422,5 +422,14 @@ Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 
 } );
 
+Object.defineProperty( Material.prototype, 'needsUpdate', {
+
+	set: function ( value ) {
+
+		if ( value === true ) this.version ++;
+
+	}
+
+} );
 
 export { Material };

+ 11 - 3
src/renderers/WebGLRenderer.js

@@ -742,6 +742,14 @@ function WebGLRenderer( parameters ) {
 
 		var index = geometry.index;
 		var position = geometry.attributes.position;
+
+		//
+
+		if ( index !== null && index.count === 0 ) return;
+		if ( position === undefined || position.count === 0 ) return;
+
+		//
+
 		var rangeFactor = 1;
 
 		if ( material.wireframe === true ) {
@@ -1675,7 +1683,7 @@ function WebGLRenderer( parameters ) {
 
 		}
 
-		if ( material.needsUpdate === false ) {
+		if ( material.version === materialProperties.__version ) {
 
 			if ( materialProperties.program === undefined ) {
 
@@ -1699,10 +1707,10 @@ function WebGLRenderer( parameters ) {
 
 		}
 
-		if ( material.needsUpdate ) {
+		if ( material.version !== materialProperties.__version ) {
 
 			initMaterial( material, fog, object );
-			material.needsUpdate = false;
+			materialProperties.__version = material.version;
 
 		}
 

+ 2 - 13
src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js

@@ -32,21 +32,10 @@ export default /* glsl */`
 		vec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );
 		vec3 N = normalize( surf_norm );
 
-		#ifdef DOUBLE_SIDED
-
-			// Workaround for Adreno GPUs gl_FrontFacing bug. See #15850 and #10331
-
-			bool frontFacing = dot( cross( S, T ), N ) > 0.0;
-
-			mapN.xy *= ( float( frontFacing ) * 2.0 - 1.0 );
-
-		#else
-
-			mapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );
+		mat3 tsn = mat3( S, T, N );
 
-		#endif
+		mapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );
 
-		mat3 tsn = mat3( S, T, N );
 		return normalize( tsn * mapN );
 
 	}

+ 11 - 3
src/renderers/webgl/WebGLAttributes.d.ts

@@ -1,11 +1,19 @@
+import { BufferAttribute } from "../../core/BufferAttribute";
+import { InterleavedBufferAttribute } from "../../core/InterleavedBufferAttribute";
+
 export class WebGLAttributes {
 
 	constructor( gl: WebGLRenderingContext | WebGL2RenderingContext );
 
-	get( attribute: any ): any;
+	get( attribute: BufferAttribute | InterleavedBufferAttribute ): {
+		buffer: WebGLBuffer,
+		type: GLenum,
+		bytesPerElement: number,
+		version: number
+	};
 
-	remove( attribute: any ): void;
+	remove( attribute: BufferAttribute | InterleavedBufferAttribute ): void;
 
-	update( attribute: any, bufferType: Array<any> ): void;
+	update( attribute: BufferAttribute | InterleavedBufferAttribute, bufferType: GLenum ): void;
 
 }

+ 11 - 4
src/renderers/webgl/WebGLGeometries.d.ts

@@ -1,9 +1,16 @@
+import { WebGLAttributes } from './WebGLAttributes';
+import { WebGLInfo } from './WebGLInfo';
+import { BufferAttribute } from '../../core/BufferAttribute';
+import { BufferGeometry } from '../../core/BufferGeometry';
+import { Geometry } from '../../core/Geometry';
+import { Object3D } from '../../core/Object3D';
+
 export class WebGLGeometries {
 
-	constructor( gl: WebGLRenderingContext, attributes: any, info: any );
+	constructor( gl: WebGLRenderingContext, attributes: WebGLAttributes, info: WebGLInfo );
 
-	get( object: any, geometry: any ): any;
-	update( geometry: any ): any;
-	getWireframeAttribute( geometry: any ): any;
+	get( object: Object3D, geometry: Geometry | BufferGeometry ): BufferGeometry;
+	update( geometry: Geometry | BufferGeometry ): void;
+	getWireframeAttribute( geometry: Geometry | BufferGeometry ): BufferAttribute;
 
 }

+ 1 - 1
src/renderers/webgl/WebGLInfo.d.ts

@@ -20,7 +20,7 @@ export class WebGLInfo {
 		points: number;
 		triangles: number;
 	};
-	update( count: any, mode: any, instanceCount: any ): void;
+	update( count: number, mode: GLenum, instanceCount: number ): void;
 	reset(): void;
 
 }

+ 28 - 0
src/renderers/webvr/WebVRManager.js

@@ -104,6 +104,7 @@ function WebVRManager( renderer ) {
 	//
 
 	var triggers = [];
+	var grips = [];
 
 	function findGamepad( id ) {
 
@@ -179,6 +180,33 @@ function WebVRManager( renderer ) {
 
 				}
 
+				// Grip
+				buttonId = 2;
+
+				if ( grips[ i ] === undefined ) grips[ i ] = false;
+
+				// Skip if the grip button doesn't exist on this controller
+				if ( gamepad.buttons[ buttonId ] !== undefined ) {
+
+					if ( grips[ i ] !== gamepad.buttons[ buttonId ].pressed ) {
+
+						grips[ i ] = gamepad.buttons[ buttonId ].pressed;
+
+						if ( grips[ i ] === true ) {
+
+							controller.dispatchEvent( { type: 'squeezestart' } );
+
+						} else {
+
+							controller.dispatchEvent( { type: 'squeezeend' } );
+							controller.dispatchEvent( { type: 'squeeze' } );
+
+						}
+
+					}
+
+				}
+
 			} else {
 
 				controller.visible = false;

+ 3 - 0
src/renderers/webvr/WebXRManager.js

@@ -133,6 +133,9 @@ function WebXRManager( renderer, gl ) {
 			session.addEventListener( 'select', onSessionEvent );
 			session.addEventListener( 'selectstart', onSessionEvent );
 			session.addEventListener( 'selectend', onSessionEvent );
+			session.addEventListener( 'squeeze', onSessionEvent );
+			session.addEventListener( 'squeezestart', onSessionEvent );
+			session.addEventListener( 'squeezeend', onSessionEvent );
 			session.addEventListener( 'end', onSessionEnd );
 
 			// eslint-disable-next-line no-undef

部分文件因文件數量過多而無法顯示