瀏覽代碼

Updated examples builds

Mr.doob 4 年之前
父節點
當前提交
6ea3e57d7f

+ 6 - 0
examples/js/controls/OrbitControls.js

@@ -111,6 +111,12 @@
 
 
 			};
 			};
 
 
+			this.getDistance = function () {
+
+				return this.object.position.distanceTo( this.target );
+
+			};
+
 			this.listenToKeyEvents = function ( domElement ) {
 			this.listenToKeyEvents = function ( domElement ) {
 
 
 				domElement.addEventListener( 'keydown', onKeyDown );
 				domElement.addEventListener( 'keydown', onKeyDown );

+ 3 - 7
examples/js/exporters/GLTFExporter.js

@@ -1126,14 +1126,10 @@
 					index: this.processTexture( material.normalMap )
 					index: this.processTexture( material.normalMap )
 				};
 				};
 
 
-				if ( material.normalScale && material.normalScale.x !== - 1 ) {
-
-					if ( material.normalScale.x !== material.normalScale.y ) {
-
-						console.warn( 'THREE.GLTFExporter: Normal scale components are different, ignoring Y and exporting X.' );
-
-					}
+				if ( material.normalScale && material.normalScale.x !== 1 ) {
 
 
+					// glTF normal scale is univariate. Ignore `y`, which may be flipped.
+					// Context: https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995
 					normalMapDef.scale = material.normalScale.x;
 					normalMapDef.scale = material.normalScale.x;
 
 
 				}
 				}

+ 40 - 6
examples/js/loaders/FBXLoader.js

@@ -549,7 +549,13 @@
 					case 'DiffuseColor':
 					case 'DiffuseColor':
 					case 'Maya|TEX_color_map':
 					case 'Maya|TEX_color_map':
 						parameters.map = scope.getTexture( textureMap, child.ID );
 						parameters.map = scope.getTexture( textureMap, child.ID );
-						parameters.map.encoding = THREE.sRGBEncoding;
+
+						if ( parameters.map !== undefined ) {
+
+							parameters.map.encoding = THREE.sRGBEncoding;
+
+						}
+
 						break;
 						break;
 
 
 					case 'DisplacementColor':
 					case 'DisplacementColor':
@@ -558,7 +564,13 @@
 
 
 					case 'EmissiveColor':
 					case 'EmissiveColor':
 						parameters.emissiveMap = scope.getTexture( textureMap, child.ID );
 						parameters.emissiveMap = scope.getTexture( textureMap, child.ID );
-						parameters.emissiveMap.encoding = THREE.sRGBEncoding;
+
+						if ( parameters.emissiveMap !== undefined ) {
+
+							parameters.emissiveMap.encoding = THREE.sRGBEncoding;
+
+						}
+
 						break;
 						break;
 
 
 					case 'NormalMap':
 					case 'NormalMap':
@@ -568,13 +580,25 @@
 
 
 					case 'ReflectionColor':
 					case 'ReflectionColor':
 						parameters.envMap = scope.getTexture( textureMap, child.ID );
 						parameters.envMap = scope.getTexture( textureMap, child.ID );
-						parameters.envMap.mapping = THREE.EquirectangularReflectionMapping;
-						parameters.envMap.encoding = THREE.sRGBEncoding;
+
+						if ( parameters.envMap !== undefined ) {
+
+							parameters.envMap.mapping = THREE.EquirectangularReflectionMapping;
+							parameters.envMap.encoding = THREE.sRGBEncoding;
+
+						}
+
 						break;
 						break;
 
 
 					case 'SpecularColor':
 					case 'SpecularColor':
 						parameters.specularMap = scope.getTexture( textureMap, child.ID );
 						parameters.specularMap = scope.getTexture( textureMap, child.ID );
-						parameters.specularMap.encoding = THREE.sRGBEncoding;
+
+						if ( parameters.specularMap !== undefined ) {
+
+							parameters.specularMap.encoding = THREE.sRGBEncoding;
+
+						}
+
 						break;
 						break;
 
 
 					case 'TransparentColor':
 					case 'TransparentColor':
@@ -612,7 +636,17 @@
 
 
 			}
 			}
 
 
-			return textureMap.get( id );
+			const texture = textureMap.get( id );
+
+			if ( texture.image !== undefined ) {
+
+				return texture;
+
+			} else {
+
+				return undefined;
+
+			}
 
 
 		} // Parse nodes in FBXTree.Objects.Deformer
 		} // Parse nodes in FBXTree.Objects.Deformer
 		// Deformer node can contain skinning or Vertex Cache animation data, however only skinning is supported here
 		// Deformer node can contain skinning or Vertex Cache animation data, however only skinning is supported here

+ 1 - 2
examples/js/loaders/GLTFLoader.js

@@ -2610,8 +2610,7 @@
 
 
 					if ( useVertexTangents ) {
 					if ( useVertexTangents ) {
 
 
-						cachedMaterial.vertexTangents = true; // https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995
-
+						// https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995
 						if ( cachedMaterial.normalScale ) cachedMaterial.normalScale.y *= - 1;
 						if ( cachedMaterial.normalScale ) cachedMaterial.normalScale.y *= - 1;
 						if ( cachedMaterial.clearcoatNormalScale ) cachedMaterial.clearcoatNormalScale.y *= - 1;
 						if ( cachedMaterial.clearcoatNormalScale ) cachedMaterial.clearcoatNormalScale.y *= - 1;
 
 

+ 153 - 121
examples/js/loaders/LDrawLoader.js

@@ -17,89 +17,130 @@
 	const FILE_LOCATION_TRY_RELATIVE = 4;
 	const FILE_LOCATION_TRY_RELATIVE = 4;
 	const FILE_LOCATION_TRY_ABSOLUTE = 5;
 	const FILE_LOCATION_TRY_ABSOLUTE = 5;
 	const FILE_LOCATION_NOT_FOUND = 6;
 	const FILE_LOCATION_NOT_FOUND = 6;
-	const conditionalLineVertShader =
-/* glsl */
-`
-	attribute vec3 control0;
-	attribute vec3 control1;
-	attribute vec3 direction;
-	varying float discardFlag;
-
-	#include <common>
-	#include <color_pars_vertex>
-	#include <fog_pars_vertex>
-	#include <logdepthbuf_pars_vertex>
-	#include <clipping_planes_pars_vertex>
-	void main() {
-		#include <color_vertex>
-
-		vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
-		gl_Position = projectionMatrix * mvPosition;
-
-		// Transform the line segment ends and control points into camera clip space
-		vec4 c0 = projectionMatrix * modelViewMatrix * vec4( control0, 1.0 );
-		vec4 c1 = projectionMatrix * modelViewMatrix * vec4( control1, 1.0 );
-		vec4 p0 = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
-		vec4 p1 = projectionMatrix * modelViewMatrix * vec4( position + direction, 1.0 );
-
-		c0.xy /= c0.w;
-		c1.xy /= c1.w;
-		p0.xy /= p0.w;
-		p1.xy /= p1.w;
-
-		// Get the direction of the segment and an orthogonal vector
-		vec2 dir = p1.xy - p0.xy;
-		vec2 norm = vec2( -dir.y, dir.x );
-
-		// Get control point directions from the line
-		vec2 c0dir = c0.xy - p1.xy;
-		vec2 c1dir = c1.xy - p1.xy;
-
-		// If the vectors to the controls points are pointed in different directions away
-		// from the line segment then the line should not be drawn.
-		float d0 = dot( normalize( norm ), normalize( c0dir ) );
-		float d1 = dot( normalize( norm ), normalize( c1dir ) );
-		discardFlag = float( sign( d0 ) != sign( d1 ) );
-
-		#include <logdepthbuf_vertex>
-		#include <clipping_planes_vertex>
-		#include <fog_vertex>
-	}
-	`;
-	const conditionalLineFragShader =
-/* glsl */
-`
-	uniform vec3 diffuse;
-	uniform float opacity;
-	varying float discardFlag;
-
-	#include <common>
-	#include <color_pars_fragment>
-	#include <fog_pars_fragment>
-	#include <logdepthbuf_pars_fragment>
-	#include <clipping_planes_pars_fragment>
-	void main() {
-
-		if ( discardFlag > 0.5 ) discard;
-
-		#include <clipping_planes_fragment>
-		vec3 outgoingLight = vec3( 0.0 );
-		vec4 diffuseColor = vec4( diffuse, opacity );
-		#include <logdepthbuf_fragment>
-		#include <color_fragment>
-		outgoingLight = diffuseColor.rgb; // simple shader
-		gl_FragColor = vec4( outgoingLight, diffuseColor.a );
-		#include <tonemapping_fragment>
-		#include <encodings_fragment>
-		#include <fog_fragment>
-		#include <premultiplied_alpha_fragment>
-	}
-	`;
 
 
 	const _tempVec0 = new THREE.Vector3();
 	const _tempVec0 = new THREE.Vector3();
 
 
 	const _tempVec1 = new THREE.Vector3();
 	const _tempVec1 = new THREE.Vector3();
 
 
+	class LDrawConditionalLineMaterial extends THREE.ShaderMaterial {
+
+		constructor( parameters ) {
+
+			super( {
+				uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib.fog, {
+					diffuse: {
+						value: new THREE.Color()
+					},
+					opacity: {
+						value: 1.0
+					}
+				} ] ),
+				vertexShader:
+      /* glsl */
+      `
+				attribute vec3 control0;
+				attribute vec3 control1;
+				attribute vec3 direction;
+				varying float discardFlag;
+
+				#include <common>
+				#include <color_pars_vertex>
+				#include <fog_pars_vertex>
+				#include <logdepthbuf_pars_vertex>
+				#include <clipping_planes_pars_vertex>
+				void main() {
+					#include <color_vertex>
+
+					vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
+					gl_Position = projectionMatrix * mvPosition;
+
+					// Transform the line segment ends and control points into camera clip space
+					vec4 c0 = projectionMatrix * modelViewMatrix * vec4( control0, 1.0 );
+					vec4 c1 = projectionMatrix * modelViewMatrix * vec4( control1, 1.0 );
+					vec4 p0 = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
+					vec4 p1 = projectionMatrix * modelViewMatrix * vec4( position + direction, 1.0 );
+
+					c0.xy /= c0.w;
+					c1.xy /= c1.w;
+					p0.xy /= p0.w;
+					p1.xy /= p1.w;
+
+					// Get the direction of the segment and an orthogonal vector
+					vec2 dir = p1.xy - p0.xy;
+					vec2 norm = vec2( -dir.y, dir.x );
+
+					// Get control point directions from the line
+					vec2 c0dir = c0.xy - p1.xy;
+					vec2 c1dir = c1.xy - p1.xy;
+
+					// If the vectors to the controls points are pointed in different directions away
+					// from the line segment then the line should not be drawn.
+					float d0 = dot( normalize( norm ), normalize( c0dir ) );
+					float d1 = dot( normalize( norm ), normalize( c1dir ) );
+					discardFlag = float( sign( d0 ) != sign( d1 ) );
+
+					#include <logdepthbuf_vertex>
+					#include <clipping_planes_vertex>
+					#include <fog_vertex>
+				}
+			`,
+				fragmentShader:
+      /* glsl */
+      `
+			uniform vec3 diffuse;
+			uniform float opacity;
+			varying float discardFlag;
+
+			#include <common>
+			#include <color_pars_fragment>
+			#include <fog_pars_fragment>
+			#include <logdepthbuf_pars_fragment>
+			#include <clipping_planes_pars_fragment>
+			void main() {
+
+				if ( discardFlag > 0.5 ) discard;
+
+				#include <clipping_planes_fragment>
+				vec3 outgoingLight = vec3( 0.0 );
+				vec4 diffuseColor = vec4( diffuse, opacity );
+				#include <logdepthbuf_fragment>
+				#include <color_fragment>
+				outgoingLight = diffuseColor.rgb; // simple shader
+				gl_FragColor = vec4( outgoingLight, diffuseColor.a );
+				#include <tonemapping_fragment>
+				#include <encodings_fragment>
+				#include <fog_fragment>
+				#include <premultiplied_alpha_fragment>
+			}
+			`
+			} );
+			Object.defineProperties( this, {
+				opacity: {
+					get: function () {
+
+						return this.uniforms.opacity.value;
+
+					},
+					set: function ( value ) {
+
+						this.uniforms.opacity.value = value;
+
+					}
+				},
+				color: {
+					get: function () {
+
+						return this.uniforms.diffuse.value;
+
+					}
+				}
+			} );
+			this.setValues( parameters );
+
+		}
+
+	}
+
 	function smoothNormals( triangles, lineSegments ) {
 	function smoothNormals( triangles, lineSegments ) {
 
 
 		function hashVertex( v ) {
 		function hashVertex( v ) {
@@ -154,13 +195,7 @@
 
 
 			}
 			}
 
 
-		} // NOTE: Some of the normals wind up being skewed in an unexpected way because
-		// quads provide more "influence" to some vertex normals than a triangle due to
-		// the fact that a quad is made up of two triangles and all triangles are weighted
-		// equally. To fix this quads could be tracked separately so their vertex normals
-		// are weighted appropriately or we could try only adding a normal direction
-		// once per normal.
-		// Iterate until we've tried to connect all triangles to share normals
+		} // Iterate until we've tried to connect all triangles to share normals
 
 
 
 
 		while ( true ) {
 		while ( true ) {
@@ -181,14 +216,14 @@
 
 
 				if ( tri.n0 === null ) {
 				if ( tri.n0 === null ) {
 
 
-					tri.n0 = faceNormal.clone();
+					tri.n0 = faceNormal.clone().multiplyScalar( tri.fromQuad ? 0.5 : 1.0 );
 					normals.push( tri.n0 );
 					normals.push( tri.n0 );
 
 
 				}
 				}
 
 
 				if ( tri.n1 === null ) {
 				if ( tri.n1 === null ) {
 
 
-					tri.n1 = faceNormal.clone();
+					tri.n1 = faceNormal.clone().multiplyScalar( tri.fromQuad ? 0.5 : 1.0 );
 					normals.push( tri.n1 );
 					normals.push( tri.n1 );
 
 
 				}
 				}
@@ -249,7 +284,8 @@
 
 
 									const norm = tri[ `n${next}` ];
 									const norm = tri[ `n${next}` ];
 									otherTri[ `n${otherIndex}` ] = norm;
 									otherTri[ `n${otherIndex}` ] = norm;
-									norm.add( otherTri.faceNormal );
+									const isDoubledVert = otherTri.fromQuad && otherIndex !== 2;
+									norm.addScaledVector( otherTri.faceNormal, isDoubledVert ? 0.5 : 1.0 );
 
 
 								}
 								}
 
 
@@ -257,7 +293,8 @@
 
 
 									const norm = tri[ `n${index}` ];
 									const norm = tri[ `n${index}` ];
 									otherTri[ `n${otherNext}` ] = norm;
 									otherTri[ `n${otherNext}` ] = norm;
-									norm.add( otherTri.faceNormal );
+									const isDoubledVert = otherTri.fromQuad && otherNext !== 2;
+									norm.addScaledVector( otherTri.faceNormal, isDoubledVert ? 0.5 : 1.0 );
 
 
 								}
 								}
 
 
@@ -723,7 +760,6 @@
 
 
 			let luminance = 0;
 			let luminance = 0;
 			let finishType = FINISH_TYPE_DEFAULT;
 			let finishType = FINISH_TYPE_DEFAULT;
-			let canHaveEnvMap = true;
 			let edgeMaterial = null;
 			let edgeMaterial = null;
 			const name = lineParser.getToken();
 			const name = lineParser.getToken();
 
 
@@ -904,7 +940,6 @@
 						roughness: 0.9,
 						roughness: 0.9,
 						metalness: 0
 						metalness: 0
 					} );
 					} );
-					canHaveEnvMap = false;
 					break;
 					break;
 
 
 				case FINISH_TYPE_MATTE_METALLIC:
 				case FINISH_TYPE_MATTE_METALLIC:
@@ -937,7 +972,6 @@
 			material.depthWrite = ! isTransparent;
 			material.depthWrite = ! isTransparent;
 			material.polygonOffset = true;
 			material.polygonOffset = true;
 			material.polygonOffsetFactor = 1;
 			material.polygonOffsetFactor = 1;
-			material.userData.canHaveEnvMap = canHaveEnvMap;
 
 
 			if ( luminance !== 0 ) {
 			if ( luminance !== 0 ) {
 
 
@@ -955,25 +989,15 @@
 					depthWrite: ! isTransparent
 					depthWrite: ! isTransparent
 				} );
 				} );
 				edgeMaterial.userData.code = code;
 				edgeMaterial.userData.code = code;
-				edgeMaterial.name = name + ' - Edge';
-				edgeMaterial.userData.canHaveEnvMap = false; // This is the material used for conditional edges
-
-				edgeMaterial.userData.conditionalEdgeMaterial = new THREE.ShaderMaterial( {
-					vertexShader: conditionalLineVertShader,
-					fragmentShader: conditionalLineFragShader,
-					uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib.fog, {
-						diffuse: {
-							value: new THREE.Color( edgeColour )
-						},
-						opacity: {
-							value: alpha
-						}
-					} ] ),
+				edgeMaterial.name = name + ' - Edge'; // This is the material used for conditional edges
+
+				edgeMaterial.userData.conditionalEdgeMaterial = new LDrawConditionalLineMaterial( {
 					fog: true,
 					fog: true,
 					transparent: isTransparent,
 					transparent: isTransparent,
-					depthWrite: ! isTransparent
+					depthWrite: ! isTransparent,
+					color: edgeColour,
+					opacity: alpha
 				} );
 				} );
-				edgeMaterial.userData.conditionalEdgeMaterial.userData.canHaveEnvMap = false;
 
 
 			}
 			}
 
 
@@ -1367,7 +1391,8 @@
 							faceNormal: faceNormal,
 							faceNormal: faceNormal,
 							n0: null,
 							n0: null,
 							n1: null,
 							n1: null,
-							n2: null
+							n2: null,
+							fromQuad: false
 						} );
 						} );
 
 
 						if ( doubleSided === true ) {
 						if ( doubleSided === true ) {
@@ -1381,7 +1406,8 @@
 								faceNormal: faceNormal,
 								faceNormal: faceNormal,
 								n0: null,
 								n0: null,
 								n1: null,
 								n1: null,
-								n2: null
+								n2: null,
+								fromQuad: false
 							} );
 							} );
 
 
 						}
 						}
@@ -1415,17 +1441,20 @@
 
 
 						_tempVec1.subVectors( v2, v1 );
 						_tempVec1.subVectors( v2, v1 );
 
 
-						faceNormal = new THREE.Vector3().crossVectors( _tempVec0, _tempVec1 ).normalize();
+						faceNormal = new THREE.Vector3().crossVectors( _tempVec0, _tempVec1 ).normalize(); // specifically place the triangle diagonal in the v0 and v1 slots so we can
+						// account for the doubling of vertices later when smoothing normals.
+
 						triangles.push( {
 						triangles.push( {
 							material: material,
 							material: material,
 							colourCode: material.userData.code,
 							colourCode: material.userData.code,
-							v0: v0,
-							v1: v1,
-							v2: v2,
+							v0: v2,
+							v1: v0,
+							v2: v1,
 							faceNormal: faceNormal,
 							faceNormal: faceNormal,
 							n0: null,
 							n0: null,
 							n1: null,
 							n1: null,
-							n2: null
+							n2: null,
+							fromQuad: true
 						} );
 						} );
 						triangles.push( {
 						triangles.push( {
 							material: material,
 							material: material,
@@ -1436,7 +1465,8 @@
 							faceNormal: faceNormal,
 							faceNormal: faceNormal,
 							n0: null,
 							n0: null,
 							n1: null,
 							n1: null,
-							n2: null
+							n2: null,
+							fromQuad: true
 						} );
 						} );
 
 
 						if ( doubleSided === true ) {
 						if ( doubleSided === true ) {
@@ -1450,18 +1480,20 @@
 								faceNormal: faceNormal,
 								faceNormal: faceNormal,
 								n0: null,
 								n0: null,
 								n1: null,
 								n1: null,
-								n2: null
+								n2: null,
+								fromQuad: true
 							} );
 							} );
 							triangles.push( {
 							triangles.push( {
 								material: material,
 								material: material,
 								colourCode: material.userData.code,
 								colourCode: material.userData.code,
-								v0: v0,
-								v1: v3,
-								v2: v2,
+								v0: v2,
+								v1: v0,
+								v2: v3,
 								faceNormal: faceNormal,
 								faceNormal: faceNormal,
 								n0: null,
 								n0: null,
 								n1: null,
 								n1: null,
-								n2: null
+								n2: null,
+								fromQuad: true
 							} );
 							} );
 
 
 						}
 						}

+ 1 - 1
examples/js/postprocessing/CubeTexturePass.js

@@ -40,7 +40,7 @@
 			this.cubeCamera.projectionMatrix.copy( this.camera.projectionMatrix );
 			this.cubeCamera.projectionMatrix.copy( this.camera.projectionMatrix );
 			this.cubeCamera.quaternion.setFromRotationMatrix( this.camera.matrixWorld );
 			this.cubeCamera.quaternion.setFromRotationMatrix( this.camera.matrixWorld );
 			this.cubeMesh.material.uniforms.envMap.value = this.envMap;
 			this.cubeMesh.material.uniforms.envMap.value = this.envMap;
-			this.cubeMesh.material.uniforms.flipEnvMap.value = this.envMap.isCubeTexture && this.envMap._needsFlipEnvMap ? - 1 : 1;
+			this.cubeMesh.material.uniforms.flipEnvMap.value = this.envMap.isCubeTexture && this.envMap.isRenderTargetTexture === false ? - 1 : 1;
 			this.cubeMesh.material.uniforms.opacity.value = this.opacity;
 			this.cubeMesh.material.uniforms.opacity.value = this.opacity;
 			this.cubeMesh.material.transparent = this.opacity < 1.0;
 			this.cubeMesh.material.transparent = this.opacity < 1.0;
 			renderer.setRenderTarget( this.renderToScreen ? null : readBuffer );
 			renderer.setRenderTarget( this.renderToScreen ? null : readBuffer );

+ 134 - 0
examples/js/utils/GPUStatsPanel.js

@@ -0,0 +1,134 @@
+( function () {
+
+	// https://www.khronos.org/registry/webgl/extensions/EXT_disjoint_timer_query_webgl2/
+
+	class GPUStatsPanel extends Stats.Panel {
+
+		constructor( context, name = 'GPU MS' ) {
+
+			super( name, '#f90', '#210' );
+			let isWebGL2 = true;
+			let extension = context.getExtension( 'EXT_disjoint_timer_query_webgl2' );
+
+			if ( extension === null ) {
+
+				isWebGL2 = false;
+				extension = context.getExtension( 'EXT_disjoint_timer_query' );
+
+				if ( extension === null ) {
+
+					console.warn( 'GPUStatsPanel: disjoint_time_query extension not available.' );
+
+				}
+
+			}
+
+			this.context = context;
+			this.extension = extension;
+			this.maxTime = 30;
+			this.activeQueries = 0;
+
+			this.startQuery = function () {
+
+				const gl = this.context;
+				const ext = this.extension;
+
+				if ( ext === null ) {
+
+					return;
+
+				} // create the query object
+
+
+				let query;
+
+				if ( isWebGL2 ) {
+
+					query = gl.createQuery();
+					gl.beginQuery( ext.TIME_ELAPSED_EXT, query );
+
+				} else {
+
+					query = ext.createQueryEXT();
+					ext.beginQueryEXT( ext.TIME_ELAPSED_EXT, query );
+
+				}
+
+				this.activeQueries ++;
+
+				const checkQuery = () => {
+
+					// check if the query is available and valid
+					let available, disjoint, ns;
+
+					if ( isWebGL2 ) {
+
+						available = gl.getQueryParameter( query, gl.QUERY_RESULT_AVAILABLE );
+						disjoint = gl.getParameter( ext.GPU_DISJOINT_EXT );
+						ns = gl.getQueryParameter( query, gl.QUERY_RESULT );
+
+					} else {
+
+						available = ext.getQueryObjectEXT( query, ext.QUERY_RESULT_AVAILABLE_EXT );
+						disjoint = gl.getParameter( ext.GPU_DISJOINT_EXT );
+						ns = ext.getQueryObjectEXT( query, ext.QUERY_RESULT_EXT );
+
+					}
+
+					const ms = ns * 1e-6;
+
+					if ( available ) {
+
+						// update the display if it is valid
+						if ( ! disjoint ) {
+
+							this.update( ms, this.maxTime );
+
+						}
+
+						this.activeQueries --;
+
+					} else {
+
+						// otherwise try again the next frame
+						requestAnimationFrame( checkQuery );
+
+					}
+
+				};
+
+				requestAnimationFrame( checkQuery );
+
+			};
+
+			this.endQuery = function () {
+
+				// finish the query measurement
+				const ext = this.extension;
+				const gl = this.context;
+
+				if ( ext === null ) {
+
+					return;
+
+				}
+
+				if ( isWebGL2 ) {
+
+					gl.endQuery( ext.TIME_ELAPSED_EXT );
+
+				} else {
+
+					ext.endQueryEXT( ext.TIME_ELAPSED_EXT );
+
+				}
+
+			};
+
+		}
+
+	}
+
+	THREE.GPUStatsPanel = GPUStatsPanel;
+
+} )();