Просмотр исходного кода

Addons: Remove `PackedPhongMaterial`. (#29382)

Michael Herzog 1 год назад
Родитель
Сommit
eada853a19

+ 0 - 1
examples/files.json

@@ -253,7 +253,6 @@
 		"webgl_buffergeometry",
 		"webgl_buffergeometry_attributes_integer",
 		"webgl_buffergeometry_attributes_none",
-		"webgl_buffergeometry_compression",
 		"webgl_buffergeometry_custom_attributes_particles",
 		"webgl_buffergeometry_drawrange",
 		"webgl_buffergeometry_glbufferattribute",

+ 37 - 122
examples/jsm/utils/GeometryCompressionUtils.js

@@ -11,27 +11,19 @@ import {
 	Matrix4,
 	Vector3
 } from 'three';
-import { PackedPhongMaterial } from './PackedPhongMaterial.js';
 
 
 
 /**
- * Make the input mesh.geometry's normal attribute encoded and compressed by 3 different methods.
- * Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the normal data.
+ * Make the input geometry's normal attribute encoded and compressed by 3 different methods.
  *
- * @param {THREE.Mesh} mesh
+ * @param {THREE.BufferGeometry} geometry
  * @param {String} encodeMethod		"DEFAULT" || "OCT1Byte" || "OCT2Byte" || "ANGLES"
  *
  */
-function compressNormals( mesh, encodeMethod ) {
+function compressNormals( geometry, encodeMethod ) {
 
-	if ( ! mesh.geometry ) {
-
-		console.error( 'Mesh must contain geometry. ' );
-
-	}
-
-	const normal = mesh.geometry.attributes.normal;
+	const normal = geometry.attributes.normal;
 
 	if ( ! normal ) {
 
@@ -66,8 +58,8 @@ function compressNormals( mesh, encodeMethod ) {
 
 		}
 
-		mesh.geometry.setAttribute( 'normal', new BufferAttribute( result, 3, true ) );
-		mesh.geometry.attributes.normal.bytes = result.length * 1;
+		geometry.setAttribute( 'normal', new BufferAttribute( result, 3, true ) );
+		geometry.attributes.normal.bytes = result.length * 1;
 
 	} else if ( encodeMethod == 'OCT1Byte' ) {
 
@@ -88,8 +80,8 @@ function compressNormals( mesh, encodeMethod ) {
 
 		}
 
-		mesh.geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) );
-		mesh.geometry.attributes.normal.bytes = result.length * 1;
+		geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) );
+		geometry.attributes.normal.bytes = result.length * 1;
 
 	} else if ( encodeMethod == 'OCT2Byte' ) {
 
@@ -104,8 +96,8 @@ function compressNormals( mesh, encodeMethod ) {
 
 		}
 
-		mesh.geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) );
-		mesh.geometry.attributes.normal.bytes = result.length * 2;
+		geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) );
+		geometry.attributes.normal.bytes = result.length * 2;
 
 	} else if ( encodeMethod == 'ANGLES' ) {
 
@@ -120,8 +112,8 @@ function compressNormals( mesh, encodeMethod ) {
 
 		}
 
-		mesh.geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) );
-		mesh.geometry.attributes.normal.bytes = result.length * 2;
+		geometry.setAttribute( 'normal', new BufferAttribute( result, 2, true ) );
+		geometry.attributes.normal.bytes = result.length * 2;
 
 	} else {
 
@@ -129,60 +121,22 @@ function compressNormals( mesh, encodeMethod ) {
 
 	}
 
-	mesh.geometry.attributes.normal.needsUpdate = true;
-	mesh.geometry.attributes.normal.isPacked = true;
-	mesh.geometry.attributes.normal.packingMethod = encodeMethod;
-
-	// modify material
-	if ( ! ( mesh.material instanceof PackedPhongMaterial ) ) {
-
-		mesh.material = new PackedPhongMaterial().copy( mesh.material );
-
-	}
-
-	if ( encodeMethod == 'ANGLES' ) {
-
-		mesh.material.defines.USE_PACKED_NORMAL = 0;
-
-	}
-
-	if ( encodeMethod == 'OCT1Byte' ) {
-
-		mesh.material.defines.USE_PACKED_NORMAL = 1;
-
-	}
-
-	if ( encodeMethod == 'OCT2Byte' ) {
-
-		mesh.material.defines.USE_PACKED_NORMAL = 1;
-
-	}
-
-	if ( encodeMethod == 'DEFAULT' ) {
-
-		mesh.material.defines.USE_PACKED_NORMAL = 2;
-
-	}
+	geometry.attributes.normal.needsUpdate = true;
+	geometry.attributes.normal.isPacked = true;
+	geometry.attributes.normal.packingMethod = encodeMethod;
 
 }
 
 
 /**
-	 * Make the input mesh.geometry's position attribute encoded and compressed.
-	 * Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the position data.
+	 * Make the input geometry's position attribute encoded and compressed.
 	 *
-	 * @param {THREE.Mesh} mesh
+	 * @param {THREE.BufferGeometry} geometry
 	 *
 	 */
-function compressPositions( mesh ) {
+function compressPositions( geometry ) {
 
-	if ( ! mesh.geometry ) {
-
-		console.error( 'Mesh must contain geometry. ' );
-
-	}
-
-	const position = mesh.geometry.attributes.position;
+	const position = geometry.attributes.position;
 
 	if ( ! position ) {
 
@@ -204,47 +158,27 @@ function compressPositions( mesh ) {
 	const result = quantizedEncode( array, encodingBytes );
 
 	const quantized = result.quantized;
-	const decodeMat = result.decodeMat;
 
 	// IMPORTANT: calculate original geometry bounding info first, before updating packed positions
-	if ( mesh.geometry.boundingBox == null ) mesh.geometry.computeBoundingBox();
-	if ( mesh.geometry.boundingSphere == null ) mesh.geometry.computeBoundingSphere();
+	if ( geometry.boundingBox == null ) geometry.computeBoundingBox();
+	if ( geometry.boundingSphere == null ) geometry.computeBoundingSphere();
 
-	mesh.geometry.setAttribute( 'position', new BufferAttribute( quantized, 3 ) );
-	mesh.geometry.attributes.position.isPacked = true;
-	mesh.geometry.attributes.position.needsUpdate = true;
-	mesh.geometry.attributes.position.bytes = quantized.length * encodingBytes;
-
-	// modify material
-	if ( ! ( mesh.material instanceof PackedPhongMaterial ) ) {
-
-		mesh.material = new PackedPhongMaterial().copy( mesh.material );
-
-	}
-
-	mesh.material.defines.USE_PACKED_POSITION = 0;
-
-	mesh.material.uniforms.quantizeMatPos.value = decodeMat;
-	mesh.material.uniforms.quantizeMatPos.needsUpdate = true;
+	geometry.setAttribute( 'position', new BufferAttribute( quantized, 3 ) );
+	geometry.attributes.position.isPacked = true;
+	geometry.attributes.position.needsUpdate = true;
+	geometry.attributes.position.bytes = quantized.length * encodingBytes;
 
 }
 
 /**
- * Make the input mesh.geometry's uv attribute encoded and compressed.
- * Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the uv data.
+ * Make the input geometry's uv attribute encoded and compressed.
  *
- * @param {THREE.Mesh} mesh
+ * @param {THREE.BufferGeometry} geometry
  *
  */
-function compressUvs( mesh ) {
+function compressUvs( geometry ) {
 
-	if ( ! mesh.geometry ) {
-
-		console.error( 'Mesh must contain geometry property. ' );
-
-	}
-
-	const uvs = mesh.geometry.attributes.uv;
+	const uvs = geometry.attributes.uv;
 
 	if ( ! uvs ) {
 
@@ -281,39 +215,20 @@ function compressUvs( mesh ) {
 
 		}
 
-		mesh.geometry.setAttribute( 'uv', new BufferAttribute( result, 2, true ) );
-		mesh.geometry.attributes.uv.isPacked = true;
-		mesh.geometry.attributes.uv.needsUpdate = true;
-		mesh.geometry.attributes.uv.bytes = result.length * 2;
-
-		if ( ! ( mesh.material instanceof PackedPhongMaterial ) ) {
-
-			mesh.material = new PackedPhongMaterial().copy( mesh.material );
-
-		}
-
-		mesh.material.defines.USE_PACKED_UV = 0;
+		geometry.setAttribute( 'uv', new BufferAttribute( result, 2, true ) );
+		geometry.attributes.uv.isPacked = true;
+		geometry.attributes.uv.needsUpdate = true;
+		geometry.attributes.uv.bytes = result.length * 2;
 
 	} else {
 
 		// use quantized encoding method
 		result = quantizedEncodeUV( array, 2 );
 
-		mesh.geometry.setAttribute( 'uv', new BufferAttribute( result.quantized, 2 ) );
-		mesh.geometry.attributes.uv.isPacked = true;
-		mesh.geometry.attributes.uv.needsUpdate = true;
-		mesh.geometry.attributes.uv.bytes = result.quantized.length * 2;
-
-		if ( ! ( mesh.material instanceof PackedPhongMaterial ) ) {
-
-			mesh.material = new PackedPhongMaterial().copy( mesh.material );
-
-		}
-
-		mesh.material.defines.USE_PACKED_UV = 1;
-
-		mesh.material.uniforms.quantizeMatUV.value = result.decodeMat;
-		mesh.material.uniforms.quantizeMatUV.needsUpdate = true;
+		geometry.setAttribute( 'uv', new BufferAttribute( result.quantized, 2 ) );
+		geometry.attributes.uv.isPacked = true;
+		geometry.attributes.uv.needsUpdate = true;
+		geometry.attributes.uv.bytes = result.quantized.length * 2;
 
 	}
 

+ 0 - 178
examples/jsm/utils/PackedPhongMaterial.js

@@ -1,178 +0,0 @@
-
-/**
- * `PackedPhongMaterial` inherited from THREE.MeshPhongMaterial
- *
- * @param {Object} parameters
- */
-import {
-	MeshPhongMaterial,
-	ShaderChunk,
-	ShaderLib,
-	UniformsUtils,
-} from 'three';
-
-class PackedPhongMaterial extends MeshPhongMaterial {
-
-	constructor( parameters ) {
-
-		super();
-
-		this.defines = {};
-		this.type = 'PackedPhongMaterial';
-		this.uniforms = UniformsUtils.merge( [
-
-			ShaderLib.phong.uniforms,
-
-			{
-				quantizeMatPos: { value: null },
-				quantizeMatUV: { value: null }
-			}
-
-		] );
-
-		this.vertexShader = [
-			'#define PHONG',
-
-			'varying vec3 vViewPosition;',
-
-			ShaderChunk.common,
-			ShaderChunk.uv_pars_vertex,
-			ShaderChunk.displacementmap_pars_vertex,
-			ShaderChunk.envmap_pars_vertex,
-			ShaderChunk.color_pars_vertex,
-			ShaderChunk.fog_pars_vertex,
-			ShaderChunk.normal_pars_vertex,
-			ShaderChunk.morphtarget_pars_vertex,
-			ShaderChunk.skinning_pars_vertex,
-			ShaderChunk.shadowmap_pars_vertex,
-			ShaderChunk.logdepthbuf_pars_vertex,
-			ShaderChunk.clipping_planes_pars_vertex,
-
-			`#ifdef USE_PACKED_NORMAL
-					#if USE_PACKED_NORMAL == 0
-						vec3 decodeNormal(vec3 packedNormal)
-						{
-							float x = packedNormal.x * 2.0 - 1.0;
-							float y = packedNormal.y * 2.0 - 1.0;
-							vec2 scth = vec2(sin(x * PI), cos(x * PI));
-							vec2 scphi = vec2(sqrt(1.0 - y * y), y);
-							return normalize( vec3(scth.y * scphi.x, scth.x * scphi.x, scphi.y) );
-						}
-					#endif
-
-					#if USE_PACKED_NORMAL == 1
-						vec3 decodeNormal(vec3 packedNormal)
-						{
-							vec3 v = vec3(packedNormal.xy, 1.0 - abs(packedNormal.x) - abs(packedNormal.y));
-							if (v.z < 0.0)
-							{
-								v.xy = (1.0 - abs(v.yx)) * vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);
-							}
-							return normalize(v);
-						}
-					#endif
-
-					#if USE_PACKED_NORMAL == 2
-						vec3 decodeNormal(vec3 packedNormal)
-						{
-							vec3 v = (packedNormal * 2.0) - 1.0;
-							return normalize(v);
-						}
-					#endif
-				#endif`,
-
-			`#ifdef USE_PACKED_POSITION
-					#if USE_PACKED_POSITION == 0
-						uniform mat4 quantizeMatPos;
-					#endif
-				#endif`,
-
-			`#ifdef USE_PACKED_UV
-					#if USE_PACKED_UV == 1
-						uniform mat3 quantizeMatUV;
-					#endif
-				#endif`,
-
-			`#ifdef USE_PACKED_UV
-					#if USE_PACKED_UV == 0
-						vec2 decodeUV(vec2 packedUV)
-						{
-							vec2 uv = (packedUV * 2.0) - 1.0;
-							return uv;
-						}
-					#endif
-
-					#if USE_PACKED_UV == 1
-						vec2 decodeUV(vec2 packedUV)
-						{
-							vec2 uv = ( vec3(packedUV, 1.0) * quantizeMatUV ).xy;
-							return uv;
-						}
-					#endif
-				#endif`,
-
-			'void main() {',
-
-			ShaderChunk.uv_vertex,
-
-			`#ifdef USE_MAP
-					#ifdef USE_PACKED_UV
-						vMapUv = decodeUV(vMapUv);
-					#endif
-				#endif`,
-
-			ShaderChunk.color_vertex,
-			ShaderChunk.morphcolor_vertex,
-
-			ShaderChunk.beginnormal_vertex,
-
-			`#ifdef USE_PACKED_NORMAL
-					objectNormal = decodeNormal(objectNormal);
-				#endif
-
-				#ifdef USE_TANGENT
-					vec3 objectTangent = vec3( tangent.xyz );
-				#endif
-				`,
-
-			ShaderChunk.morphnormal_vertex,
-			ShaderChunk.skinbase_vertex,
-			ShaderChunk.skinnormal_vertex,
-			ShaderChunk.defaultnormal_vertex,
-			ShaderChunk.normal_vertex,
-
-			ShaderChunk.begin_vertex,
-
-			`#ifdef USE_PACKED_POSITION
-					#if USE_PACKED_POSITION == 0
-						transformed = ( vec4(transformed, 1.0) * quantizeMatPos ).xyz;
-					#endif
-				#endif`,
-
-			ShaderChunk.morphtarget_vertex,
-			ShaderChunk.skinning_vertex,
-			ShaderChunk.displacementmap_vertex,
-			ShaderChunk.project_vertex,
-			ShaderChunk.logdepthbuf_vertex,
-			ShaderChunk.clipping_planes_vertex,
-
-			'vViewPosition = - mvPosition.xyz;',
-
-			ShaderChunk.worldpos_vertex,
-			ShaderChunk.envmap_vertex,
-			ShaderChunk.shadowmap_vertex,
-			ShaderChunk.fog_vertex,
-
-			'}',
-		].join( '\n' );
-
-		// Use the original MeshPhongMaterial's fragmentShader.
-		this.fragmentShader = ShaderLib.phong.fragmentShader;
-
-		this.setValues( parameters );
-
-	}
-
-}
-
-export { PackedPhongMaterial };

BIN
examples/screenshots/webgl_buffergeometry_compression.jpg


+ 0 - 273
examples/webgl_buffergeometry_compression.html

@@ -1,273 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<title>three.js webgl - buffergeometry - compression</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> - BufferGeometry Compression<br />
-			Octahedron and Quantization encoding methods from Tarek Sherif
-		</div>
-
-		<script type="importmap">
-			{
-				"imports": {
-					"three": "../build/three.module.js",
-					"three/addons/": "./jsm/"
-				}
-			}
-		</script>
-
-		<script type="module">
-
-			import * as THREE from 'three';
-
-			import Stats from 'three/addons/libs/stats.module.js';
-			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
-			import * as GeometryCompressionUtils from 'three/addons/utils/GeometryCompressionUtils.js';
-			import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js';
-			import { TeapotGeometry } from 'three/addons/geometries/TeapotGeometry.js';
-			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
-
-			let container, stats, gui;
-
-			let camera, scene, renderer, controls;
-
-			const lights = [];
-
-			// options
-			const data = {
-				'model': 'Icosahedron',
-				'wireframe': false,
-				'texture': false,
-				'detail': 4,
-
-				'QuantizePosEncoding': false,
-				'NormEncodingMethods': 'None', // for normal encodings
-				'DefaultUVEncoding': false,
-
-				'totalGPUMemory': '0 bytes'
-			};
-			let memoryDisplay;
-
-			// geometry params
-			const radius = 100;
-
-			// materials
-			const lineMaterial = new THREE.LineBasicMaterial( { color: 0xaaaaaa, transparent: true, opacity: 0.8 } );
-			const meshMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, side: THREE.DoubleSide } );
-
-			// texture
-			const texture = new THREE.TextureLoader().load( 'textures/uv_grid_opengl.jpg' );
-			texture.wrapS = THREE.RepeatWrapping;
-			texture.wrapT = THREE.RepeatWrapping;
-			texture.colorSpace = THREE.SRGBColorSpace;
-
-			//
-			init();
-
-			function init() {
-
-				//
-
-				container = document.createElement( 'div' );
-				document.body.appendChild( container );
-
-				//
-
-				scene = new THREE.Scene();
-
-				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
-				camera.position.setScalar( 2 * radius );
-
-				//
-
-				scene.add( new THREE.AmbientLight( 0xffffff, 0.3 ) );
-
-				lights[ 0 ] = new THREE.DirectionalLight( 0xffffff, 2.5 );
-				lights[ 1 ] = new THREE.DirectionalLight( 0xffffff, 2.5 );
-				lights[ 2 ] = new THREE.DirectionalLight( 0xffffff, 2.5 );
-
-				lights[ 0 ].position.set( 0, 2 * radius, 0 );
-				lights[ 1 ].position.set( 2 * radius, - 2 * radius, 2 * radius );
-				lights[ 2 ].position.set( - 2 * radius, - 2 * radius, - 2 * radius );
-
-				scene.add( lights[ 0 ] );
-				scene.add( lights[ 1 ] );
-				scene.add( lights[ 2 ] );
-
-				//
-
-				scene.add( new THREE.AxesHelper( radius * 5 ) );
-
-				//
-
-				let geom = newGeometry( data );
-
-				const mesh = new THREE.Mesh( geom, meshMaterial );
-				scene.add( mesh );
-
-				const lineSegments = new THREE.LineSegments( new THREE.WireframeGeometry( geom ), lineMaterial );
-				lineSegments.visible = data.wireframe;
-
-				scene.add( lineSegments );
-
-				//
-
-				gui = new GUI();
-				gui.width = 350;
-
-				function newGeometry( data ) {
-
-					switch ( data.model ) {
-
-						case 'Icosahedron':
-							return new THREE.IcosahedronGeometry( radius, data.detail );
-						case 'Cylinder':
-							return new THREE.CylinderGeometry( radius / 1.5, radius / 1.5, radius, data.detail * 6 );
-						case 'Teapot':
-							return new TeapotGeometry( radius / 1.5, data.detail * 3, true, true, true, true, true );
-						case 'TorusKnot':
-							return new THREE.TorusKnotGeometry( radius / 2, 10, data.detail * 30, data.detail * 6, 3, 4 );
-
-					}
-
-				}
-
-				function generateGeometry() {
-
-					geom = newGeometry( data );
-
-					updateGroupGeometry( mesh, lineSegments, geom, data );
-
-				}
-
-				function updateLineSegments() {
-
-					lineSegments.visible = data.wireframe;
-
-				}
-
-				let folder = gui.addFolder( 'Scene' );
-				folder.add( data, 'model', [ 'Icosahedron', 'Cylinder', 'TorusKnot', 'Teapot' ] ).onChange( generateGeometry );
-				folder.add( data, 'wireframe', false ).onChange( updateLineSegments );
-				folder.add( data, 'texture', false ).onChange( generateGeometry );
-				folder.add( data, 'detail', 1, 8, 1 ).onChange( generateGeometry );
-				folder.open();
-
-				folder = gui.addFolder( 'Position Compression' );
-				folder.add( data, 'QuantizePosEncoding', false ).onChange( generateGeometry );
-				folder.open();
-
-				folder = gui.addFolder( 'Normal Compression' );
-				folder.add( data, 'NormEncodingMethods', [ 'None', 'DEFAULT', 'OCT1Byte', 'OCT2Byte', 'ANGLES' ] ).onChange( generateGeometry );
-				folder.open();
-
-				folder = gui.addFolder( 'UV Compression' );
-				folder.add( data, 'DefaultUVEncoding', false ).onChange( generateGeometry );
-				folder.open();
-
-				folder = gui.addFolder( 'Memory Info' );
-				folder.open();
-				memoryDisplay = folder.add( data, 'totalGPUMemory', '0 bytes' );
-				computeGPUMemory( mesh );
-
-				//
-
-				renderer = new THREE.WebGLRenderer( { antialias: true } );
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( window.innerWidth, window.innerHeight );
-				renderer.setAnimationLoop( animate );
-				container.appendChild( renderer.domElement );
-
-				//
-
-				controls = new OrbitControls( camera, renderer.domElement );
-				controls.enablePan = false;
-				controls.enableZoom = false;
-
-				//
-
-				stats = new Stats();
-				container.appendChild( stats.dom );
-
-				window.addEventListener( 'resize', onWindowResize );
-
-			}
-
-			//
-
-			function onWindowResize() {
-
-				renderer.setSize( window.innerWidth, window.innerHeight );
-
-				camera.aspect = window.innerWidth / window.innerHeight;
-
-				camera.updateProjectionMatrix();
-
-			}
-
-			//
-
-			function animate() {
-
-				renderer.render( scene, camera );
-
-				stats.update();
-
-			}
-
-			//
-
-			function updateGroupGeometry( mesh, lineSegments, geometry, data ) {
-
-				// dispose first
-
-				lineSegments.geometry.dispose();
-				mesh.geometry.dispose();
-				mesh.material.dispose();
-				if ( mesh.material.map ) mesh.material.map.dispose();
-
-				lineSegments.geometry = new THREE.WireframeGeometry( geometry );
-				mesh.geometry = geometry;
-				mesh.material = new THREE.MeshPhongMaterial( { color: 0xffffff, side: THREE.DoubleSide } );
-				mesh.material.map = data.texture ? texture : null;
-
-				if ( data[ 'QuantizePosEncoding' ] ) {
-
-					GeometryCompressionUtils.compressPositions( mesh );
-
-				}
-
-				if ( data[ 'NormEncodingMethods' ] !== 'None' ) {
-
-					GeometryCompressionUtils.compressNormals( mesh, data[ 'NormEncodingMethods' ] );
-
-				}
-
-				if ( data[ 'DefaultUVEncoding' ] ) {
-
-					GeometryCompressionUtils.compressUvs( mesh );
-
-				}
-
-				computeGPUMemory( mesh );
-
-			}
-
-
-			function computeGPUMemory( mesh ) {
-
-				// Use BufferGeometryUtils to do memory calculation
-
-				memoryDisplay.setValue( BufferGeometryUtils.estimateBytesUsed( mesh.geometry ) + ' bytes' );
-
-			}
-
-		</script>
-
-	</body>
-</html>

粤ICP备19079148号