ldj hace 1 año
padre
commit
75cfa04492

+ 48 - 41
package-lock.json

@@ -1960,6 +1960,49 @@
         "webpack-merge": "^5.7.3",
         "webpack-virtual-modules": "^0.4.2",
         "whatwg-fetch": "^3.6.2"
+      },
+      "dependencies": {
+        "@vue/vue-loader-v15": {
+          "version": "npm:vue-loader@15.11.1",
+          "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-15.11.1.tgz",
+          "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==",
+          "dev": true,
+          "requires": {
+            "@vue/component-compiler-utils": "^3.1.0",
+            "hash-sum": "^1.0.2",
+            "loader-utils": "^1.1.0",
+            "vue-hot-reload-api": "^2.3.0",
+            "vue-style-loader": "^4.1.0"
+          },
+          "dependencies": {
+            "hash-sum": {
+              "version": "1.0.2",
+              "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz",
+              "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
+              "dev": true
+            }
+          }
+        },
+        "json5": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmmirror.com/json5/-/json5-1.0.2.tgz",
+          "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+          "dev": true,
+          "requires": {
+            "minimist": "^1.2.0"
+          }
+        },
+        "loader-utils": {
+          "version": "1.4.2",
+          "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-1.4.2.tgz",
+          "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
+          "dev": true,
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^1.0.1"
+          }
+        }
       }
     },
     "@vue/cli-shared-utils": {
@@ -2206,47 +2249,6 @@
       "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.4.15.tgz",
       "integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g=="
     },
-    "@vue/vue-loader-v15": {
-      "version": "npm:vue-loader@15.11.1",
-      "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-15.11.1.tgz",
-      "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==",
-      "dev": true,
-      "requires": {
-        "@vue/component-compiler-utils": "^3.1.0",
-        "hash-sum": "^1.0.2",
-        "loader-utils": "^1.1.0",
-        "vue-hot-reload-api": "^2.3.0",
-        "vue-style-loader": "^4.1.0"
-      },
-      "dependencies": {
-        "hash-sum": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz",
-          "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
-          "dev": true
-        },
-        "json5": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmmirror.com/json5/-/json5-1.0.2.tgz",
-          "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.4.2",
-          "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-1.4.2.tgz",
-          "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^1.0.1"
-          }
-        }
-      }
-    },
     "@vue/web-component-wrapper": {
       "version": "1.3.0",
       "resolved": "https://registry.npmmirror.com/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz",
@@ -5425,6 +5427,11 @@
         "path-key": "^2.0.0"
       }
     },
+    "nprogress": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmmirror.com/nprogress/-/nprogress-0.2.0.tgz",
+      "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA=="
+    },
     "nth-check": {
       "version": "2.1.1",
       "resolved": "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz",

+ 1 - 0
package.json

@@ -10,6 +10,7 @@
     "core-js": "^3.8.3",
     "gsap": "^3.12.5",
     "jquery": "^3.7.1",
+    "nprogress": "^0.2.0",
     "three": "^0.158.0",
     "vue": "^3.2.13",
     "vue-router": "^4.0.3"

+ 28 - 89
src/examples/jsm/postprocessing/BloomPass2.js

@@ -26,27 +26,26 @@ import { LuminosityHighPassShader } from '../shaders/LuminosityHighPassShader.js
  */
 class BloomPass extends Pass {
 
-	constructor( resolution, strength, radius, threshold ) {
+	constructor( width, height ) {
 
 		super();
 
-		this.strength = ( strength !== undefined ) ? strength : 1;
+		this.strength = 1
 		this.interation = 6;
-		this.radius = radius;
-		this.threshold = threshold;
-		this.resolution = ( resolution !== undefined ) ? new Vector2( resolution.x, resolution.y ) : new Vector2( 256, 256 );
+		this.radius = 1;
+		this.threshold = 1;
+		this.width = ( width !== undefined ) ? width : 256
+		this.height = ( height !== undefined ) ? height : 256
 
 
-
-		// create color only once here, reuse it later inside the render function
 		this.clearColor = new Color( 0, 0, 0 );
 
 		// render targets
 		this.renderTargetsDownSample = [];
 		this.renderTargetsUpSample = [];
 		
-		let resx = Math.round( this.resolution.x / 2 );
-		let resy = Math.round( this.resolution.y / 2 );
+		let resx = Math.round( this.width / 2 );
+		let resy = Math.round( this.height / 2 );
 
 		this.renderTargetBright = new WebGLRenderTarget( resx, resy, { type: HalfFloatType } );
 		this.renderTargetBright.texture.name = 'UnrealBloomPass.bright';
@@ -67,18 +66,16 @@ class BloomPass extends Pass {
 			resx = Math.round( resx / 2 );
 			resy = Math.round( resy / 2 );
 		}
-		console.log(this.renderTargetsDownSample, this.renderTargetsUpSample)
-		this.renderTargetDown = new WebGLRenderTarget( resx, resy, { type: HalfFloatType } );
-		this.renderTargetDown.texture.generateMipmaps = false;
-
-
+		// console.log(this.renderTargetsDownSample, this.renderTargetsUpSample)
+		// this.renderTargetDown = new WebGLRenderTarget( resx, resy, { type: HalfFloatType } );
+		// this.renderTargetDown.texture.generateMipmaps = false;
 
 		// luminosity high pass material
 
 		const highPassShader = LuminosityHighPassShader;
 		this.highPassUniforms = UniformsUtils.clone( highPassShader.uniforms );
 
-		this.highPassUniforms[ 'luminosityThreshold' ].value = threshold;
+		this.highPassUniforms[ 'luminosityThreshold' ].value = this.threshold;
 		this.highPassUniforms[ 'smoothWidth' ].value = 0.01;
 
 		this.materialHighPassFilter = new ShaderMaterial( {
@@ -123,12 +120,11 @@ class BloomPass extends Pass {
 		this._oldClearColor = new Color();
 		this.oldClearAlpha = 1;
 
-		this.basic = new MeshBasicMaterial();
 
 		this.fsQuad = new FullScreenQuad( null );
 
 	}
-	render( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
+	render( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) {
 
 		renderer.getClearColor( this._oldClearColor );
 		this.oldClearAlpha = renderer.getClearAlpha();
@@ -136,20 +132,6 @@ class BloomPass extends Pass {
 		renderer.autoClear = false;
 
 		renderer.setClearColor( this.clearColor, 0 );
-		// if ( maskActive ) renderer.state.buffers.stencil.setTest( false );
-
-		// // Render input to screen
-
-		// if ( this.renderToScreen ) {
-
-		// 	this.fsQuad.material = this.basic;
-		// 	this.basic.map = readBuffer.texture;
-
-		// 	renderer.setRenderTarget( null );
-		// 	renderer.clear();
-		// 	this.fsQuad.render( renderer );
-
-		// }
 
 		// 1. Extract Bright Areas
 
@@ -188,42 +170,11 @@ class BloomPass extends Pass {
 		}
 	
 
-		// this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.renderTargetsDownSample[5].texture;
 		this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.renderTargetsUpSample[0].texture;
 		this.copyMaterial.uniforms[ 'strength' ].value = this.strength;
 
 		this.renderPass( renderer, this.copyMaterial, readBuffer );
 
-		// Composite All the mips
-
-		// this.fsQuad.material = this.compositeMaterial;
-		// this.compositeMaterial.uniforms[ 'bloomStrength' ].value = this.strength;
-		// this.compositeMaterial.uniforms[ 'bloomRadius' ].value = this.radius;
-		// this.compositeMaterial.uniforms[ 'bloomTintColors' ].value = this.bloomTintColors;
-
-		// renderer.setRenderTarget( this.renderTargetsHorizontal[ 0 ] );
-		// renderer.clear();
-		// this.fsQuad.render( renderer );
-
-		// // Blend it additively over the input texture
-
-		// this.fsQuad.material = this.blendMaterial;
-		// this.copyUniforms[ 'tDiffuse' ].value = this.renderTargetsHorizontal[ 0 ].texture;
-
-		// if ( maskActive ) renderer.state.buffers.stencil.setTest( true );
-
-		// if ( this.renderToScreen ) {
-
-		// 	renderer.setRenderTarget( null );
-		// 	this.fsQuad.render( renderer );
-
-		// } else {
-
-		// 	renderer.setRenderTarget( readBuffer );
-		// 	this.fsQuad.render( renderer );
-
-		// }
-
 		// Restore renderer settings
 
 		renderer.setClearColor( this._oldClearColor, this.oldClearAlpha );
@@ -261,33 +212,22 @@ class BloomPass extends Pass {
 
 	dispose() {
 
-		for ( let i = 0; i < this.renderTargetsHorizontal.length; i ++ ) {
-
-			this.renderTargetsHorizontal[ i ].dispose();
-
+		for ( let i = 0; i < this.renderTargetsDownSample.length; i ++ ) {
+			this.renderTargetsDownSample[ i ].dispose();
 		}
 
-		for ( let i = 0; i < this.renderTargetsVertical.length; i ++ ) {
-
-			this.renderTargetsVertical[ i ].dispose();
-
+		for ( let i = 0; i < this.renderTargetsUpSample.length; i ++ ) {
+			this.renderTargetsUpSample[ i ].dispose();
 		}
 
 		this.renderTargetBright.dispose();
 
-		//
 
-		for ( let i = 0; i < this.separableBlurMaterials.length; i ++ ) {
+		this.materialHighPassFilter.dispose();
+		this.downSampleMaterial.dispose();
+		this.upSampleMaterial.dispose();
+		this.copyMaterial.dispose();
 
-			this.separableBlurMaterials[ i ].dispose();
-
-		}
-
-		this.compositeMaterial.dispose();
-		this.blendMaterial.dispose();
-		this.basic.dispose();
-
-		//
 
 		this.fsQuad.dispose();
 
@@ -295,18 +235,19 @@ class BloomPass extends Pass {
 
 	setSize( width, height ) {
 
+		this.width = width;
+		this.height = height;
+
 		let resx = Math.round( width / 2 );
 		let resy = Math.round( height / 2 );
 
-		this.renderTargetBright.setSize( resx, resy );
+		this.renderTargetBright.setSize( resx, resy ); //threshold
 
 		for ( let i = 0; i < this.nMips; i ++ ) {
 
-			this.renderTargetsHorizontal[ i ].setSize( resx, resy );
-			this.renderTargetsVertical[ i ].setSize( resx, resy );
-
-			this.separableBlurMaterials[ i ].uniforms[ 'invSize' ].value = new Vector2( 1 / resx, 1 / resy );
-
+			this.renderTargetsDownSample[ i ].setSize( resx, resy );
+			this.renderTargetsUpSample[ i ].setSize( resx, resy );
+			
 			resx = Math.round( resx / 2 );
 			resy = Math.round( resy / 2 );
 
@@ -314,8 +255,6 @@ class BloomPass extends Pass {
 
 	}
 
-
-
 }
 const DownSampleShader = {
 

+ 27 - 34
src/examples/jsm/postprocessing/BokehPass3.js

@@ -76,6 +76,8 @@ class BokehPass extends Pass {
 			vertexShader: DownSampleShader.vertexShader,
 			fragmentShader: DownSampleShader.fragmentShader
 		} );
+		this.DownSampleMaterial.uniforms[ 'resolution' ].value.set(this.width, this.height);
+
 		
 
 		// bokeh 
@@ -89,6 +91,8 @@ class BokehPass extends Pass {
 			vertexShader: BokehShader.vertexShader,
 			fragmentShader: BokehShader.fragmentShader
 		} );
+		this.BokehMaterial.uniforms[ 'resolution' ].value.set(this.downSampleResX, this.downSampleResY);
+
 
 		// filter
 		this.FilterRenderTarget = new WebGLRenderTarget(this.downSampleResX, this.downSampleResY, {
@@ -101,6 +105,7 @@ class BokehPass extends Pass {
 			vertexShader: FilterShader.vertexShader,
 			fragmentShader: FilterShader.fragmentShader
 		} );
+		this.FileterMaterial.uniforms[ 'resolution' ].value.set(this.downSampleResX, this.downSampleResY);
 
 		// Scatter
 		this.ScatterRenderTarget = new WebGLRenderTarget(this.downSampleResX, this.downSampleResY, {
@@ -113,6 +118,7 @@ class BokehPass extends Pass {
 			vertexShader: ScatterShader.vertexShader,
 			fragmentShader: ScatterShader.fragmentShader
 		} );
+		this.ScatterMaterial.uniforms[ 'resolution' ].value.set(this.downSampleResX, this.downSampleResY);
 
 		// blend 
 		this.BlendMaterial = new ShaderMaterial( {
@@ -120,15 +126,16 @@ class BokehPass extends Pass {
 			vertexShader: BlendShader.vertexShader,
 			fragmentShader: BlendShader.fragmentShader,
 		})
+		this.BlendMaterial.uniforms[ 'resolution' ].value.set(this.width, this.height);
 
-		this.copyMaterial = new ShaderMaterial( {
-			uniforms: UniformsUtils.clone( CopyShader.uniforms ),
-			vertexShader: CopyShader.vertexShader,
-			fragmentShader: CopyShader.fragmentShader,
-			// transparent: true,
-			// depthTest: false,
-			// depthWrite: false,
-		} );
+		// this.copyMaterial = new ShaderMaterial( {
+		// 	uniforms: UniformsUtils.clone( CopyShader.uniforms ),
+		// 	vertexShader: CopyShader.vertexShader,
+		// 	fragmentShader: CopyShader.fragmentShader,
+		// 	// transparent: true,
+		// 	// depthTest: false,
+		// 	// depthWrite: false,
+		// } );
 
 		this.fsQuad = new FullScreenQuad( null );
 
@@ -139,22 +146,6 @@ class BokehPass extends Pass {
 	
 
 	render( renderer, writeBuffer, readBuffer, deltaTime, maskActive, GBuffer ) {
-
-		// Render depth into texture
-
-		// this.scene.overrideMaterial = this.materialDepth;
-
-		// renderer.getClearColor( this.originalClearColor );
-		// const oldClearAlpha = renderer.getClearAlpha();
-		// const oldAutoClear = renderer.autoClear;
-		// renderer.autoClear = false;
-
-		// renderer.setClearColor( 0xffffff );
-		// renderer.setClearAlpha( 1.0 );
-		// renderer.setRenderTarget( this.renderTargetDepth );
-		// renderer.clear();
-		// renderer.render( this.scene, this.camera );
-		
 		// render DofCoC
 		this.DofCoCMaterial.uniforms[ 'tDepth' ].value = GBuffer.depthTexture;
 		this.DofCoCMaterial.uniforms[ 'focus' ].value.copy(this.focus);
@@ -170,7 +161,6 @@ class BokehPass extends Pass {
 		this.DownSampleMaterial.uniforms[ 'tDiffuse' ].value = readBuffer.texture;
 		this.DownSampleMaterial.uniforms[ 'tCoC' ].value = this.DofCoCRenderTarget.texture;
 		this.DownSampleMaterial.uniforms[ 'bokehRadius' ].value = this.bokehRadius;
-		this.DownSampleMaterial.uniforms[ 'resolution' ].value.set(this.width, this.height);
 		this.renderPass( renderer, this.DownSampleMaterial, this.DownSampleRenderTarget);
 		
 
@@ -184,17 +174,14 @@ class BokehPass extends Pass {
 		this.BokehMaterial.uniforms[ 'uframe' ].value = this.frame;
 		this.BokehMaterial.uniforms[ 'maxblur' ].value = this.maxblur;
 		this.BokehMaterial.uniforms[ 'bladeCount' ].value = this.bladeCount;
-		this.BokehMaterial.uniforms[ 'resolution' ].value.set(this.downSampleResX, this.downSampleResY);
 		this.renderPass( renderer, this.BokehMaterial, this.BokehRenderTarget);
 
 		// render filter
 		this.FileterMaterial.uniforms[ 'tDiffuse' ].value = this.BokehRenderTarget.texture;
-		this.FileterMaterial.uniforms[ 'resolution' ].value.set(this.downSampleResX, this.downSampleResY);
 		this.renderPass( renderer, this.FileterMaterial, this.FilterRenderTarget);
 
 		// render scatter
 		this.ScatterMaterial.uniforms[ 'tDiffuse' ].value = this.FilterRenderTarget.texture;
-		this.ScatterMaterial.uniforms[ 'resolution' ].value.set(this.downSampleResX, this.downSampleResY);
 		this.renderPass( renderer, this.ScatterMaterial, this.ScatterRenderTarget);
 
 		// render blend
@@ -206,7 +193,6 @@ class BokehPass extends Pass {
 		this.BlendMaterial.uniforms[ 'tCoC' ].value = this.DofCoCRenderTarget.texture;
 		this.BlendMaterial.uniforms[ 'tDown' ].value = this.DownSampleRenderTarget.texture;
 		this.BlendMaterial.uniforms[ 'tDof' ].value = this.ScatterRenderTarget.texture;
-		this.BlendMaterial.uniforms[ 'resolution' ].value.set(this.width, this.height);
 		this.BlendMaterial.uniforms[ 'bokehRadius' ].value = this.bokehRadius;
 		this.renderPass( renderer, this.BlendMaterial, writeBuffer);
 
@@ -262,7 +248,6 @@ class BokehPass extends Pass {
 	}
 
 	setSize( width, height ) {
-		console.log(width, height);
 		this.width = width;
 		this.height = height;
 		this.downSampleResX = width * this.downSampleFactor;
@@ -274,7 +259,6 @@ class BokehPass extends Pass {
 		this.FilterRenderTarget.setSize( this.downSampleResX, this.downSampleResY );
 		this.ScatterRenderTarget.setSize( this.downSampleResX, this.downSampleResY );
 
-
 		this.DownSampleMaterial.uniforms[ 'resolution' ].value.set(width, height);
 		this.BokehMaterial.uniforms[ 'resolution' ].value.set( this.downSampleResX, this.downSampleResY );
 		this.FileterMaterial.uniforms[ 'resolution' ].value.set( this.downSampleResX, this.downSampleResY );
@@ -285,11 +269,20 @@ class BokehPass extends Pass {
 
 	dispose() {
 
-		this.renderTargetDepth.dispose();
+		this.DofCoCRenderTarget.dispose();
+		this.DownSampleRenderTarget.dispose();
+		this.BokehRenderTarget.dispose();
+		this.FilterRenderTarget.dispose();
+		this.ScatterRenderTarget.dispose();
 
-		this.materialDepth.dispose();
-		this.materialBokeh.dispose();
 
+		this.DofCoCMaterial.dispose();
+		this.DownSampleMaterial.dispose();
+		this.BokehMaterial.dispose();
+		this.FileterMaterial.dispose();
+		this.ScatterMaterial.dispose();
+		this.BlendMaterial.dispose();
+		
 		this.fsQuad.dispose();
 
 	}

+ 40 - 38
src/examples/jsm/postprocessing/SSRPass_Blending.js

@@ -123,8 +123,6 @@ class SSRPass extends Pass {
 		// metalness render target
 		const depthTexture = new DepthTexture();
 		depthTexture.type = UnsignedInt248Type;
-		// depthTexture.minFilter = NearestFilter;
-		// depthTexture.magFilter = NearestFilter;
 
 		this.metalnessRenderTarget = new WebGLMultipleRenderTargets( this.width, this.height, 5, {
 			samples: 0,
@@ -160,6 +158,15 @@ class SSRPass extends Pass {
 			type: HalfFloatType 
 		} );
 
+		this.historyRenderTarget = new WebGLRenderTarget( this.downSampleResX, this.downSampleResY, { 
+			samples: 0, 
+			type: HalfFloatType, 
+			minFilter: LinearFilter,
+			magFilter: LinearFilter,
+		} );
+		this.hasHistoryBuffer = false;
+		this.useHistoryBuffer = true;
+
 
 
 		// ssr material
@@ -260,14 +267,7 @@ class SSRPass extends Pass {
 			// premultipliedAlpha:true,
 		} );
 		this.copyMaterial.needsUpdate = true
-		this.historyRenderTarget = new WebGLRenderTarget( this.downSampleResX, this.downSampleResY, { 
-			samples: 0, 
-			type: HalfFloatType, 
-			minFilter: LinearFilter,
-			magFilter: LinearFilter,
-		} );
-		this.hasHistoryBuffer = false;
-		this.useHistoryBuffer = true;
+
 
 		this.fsQuad = new FullScreenQuad( null );
 
@@ -275,27 +275,6 @@ class SSRPass extends Pass {
 
 	}
 
-	dispose() {
-
-		// dispose render targets
-
-		this.metalnessRenderTarget.dispose();
-		this.ssrRenderTarget.dispose();
-		this.ssaoRenderTarget.dispose();
-
-
-		// dispose materials
-
-		this.ssrMaterial.dispose();
-		this.ssaoMaterial.dispose();
-		this.copyMaterial.dispose();  
-
-		// dipsose full screen quad
-
-		this.fsQuad.dispose();
-
-	}
-
 	render( renderer, writeBuffer , readBuffer, deltaTime, maskActive, GBuffer ) {
 		// debugger
 		// reset
@@ -560,21 +539,44 @@ class SSRPass extends Pass {
 		renderer.setClearAlpha( originalClearAlpha );
 	}
 
-	setSize( width, height ) {
+	dispose() {
 
+		// dispose render targets
+
+		this.metalnessRenderTarget.dispose();
+		this.ssrRenderTarget.dispose();
+		this.ssaoRenderTarget.dispose();
+		this.historyRenderTarget.dispose();
+
+
+		// dispose materials
+
+		this.ssrMaterial.dispose();
+		this.ssaoMaterial.dispose();
+		this.hbaoMaterial.dispose();
+		this.ssaoDepthMaterial.dispose();
+		this.copyMaterial.dispose();
+
+		// dipsose full screen quad
+
+		this.fsQuad.dispose();
+
+	}
+
+	setSize( width, height ) {
 		this.width = width;
 		this.height = height;
-		this.downSampleResX = width * this.downSampleFactor
-		this.downSampleResY = width * this.downSampleFactor
+		this.downSampleResX = this.width * this.downSampleFactor
+		this.downSampleResY = this.height * this.downSampleFactor
+		// console.log(this.width, this.height)
 
-		this.ssrMaterial.needsUpdate = true;
+		// this.ssrMaterial.needsUpdate = true;
+		this.metalnessRenderTarget.setSize( width, height );
 		this.ssrRenderTarget.setSize( this.downSampleResX, this.downSampleResY );
 		this.ssaoRenderTarget.setSize( this.downSampleResX, this.downSampleResY );
-		this.metalnessRenderTarget.setSize( width, height );
 		this.historyRenderTarget.setSize( this.downSampleResX, this.downSampleResY );
 
 
-
 		this.ssrMaterial.uniforms[ 'resolution' ].value.set( this.downSampleResX, this.downSampleResY );
 		this.ssrMaterial.uniforms[ 'cameraProjectionMatrix' ].value.copy( this.camera.projectionMatrix );
 		this.ssrMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.copy( this.camera.projectionMatrixInverse );
@@ -639,7 +641,7 @@ class SSRPass extends Pass {
 	}
 	getMipMapMaxLod() {
 		this.mipCount = Math.ceil(Math.log( this.height ) / Math.LN2);
-		console.log(this.mipCount);
+		// console.log(this.mipCount);
 	}
 }
 

+ 16 - 10
src/examples/jsm/postprocessing/TAARenderPass2.js

@@ -75,6 +75,7 @@ class TAARenderPass2 extends Pass {
 			vertexShader: MixShader.vertexShader,
 			fragmentShader: MixShader.fragmentShader,
 		} );
+		this.mixMaterial.uniforms[ 'resolution' ].value.set( this.width, this.height );
 	}
 
 	render( renderer, writeBuffer, readBuffer, deltaTime ) {
@@ -90,7 +91,6 @@ class TAARenderPass2 extends Pass {
 		this.mixMaterial.uniforms['tLast'].value = this.lastRenderTarget.texture;
 		this.mixMaterial.uniforms['tCurrent'].value = readBuffer.texture;
 		this.mixMaterial.uniforms['cameraMoving'].value = this.accumulate;
-		this.mixMaterial.uniforms[ 'resolution' ].value.set( this.width, this.height );
 		
 		this.renderPass( renderer, this.mixMaterial, writeBuffer );
 		this.copyMaterial.uniforms[ 'tDiffuse' ].value = writeBuffer.texture;
@@ -140,21 +140,26 @@ class TAARenderPass2 extends Pass {
 		renderer.setClearColor( this.originalClearColor );
 		renderer.setClearAlpha( originalClearAlpha );
 	}
+	
 	setSize( width, height ) {
 		this.width = width;
 		this.height = height;
+		// console.log(width, height)
+		if(/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) {
+			this.jitterStrength *= 0.5
+		}
+		this.currentRenderTarget.setSize( this.width, this.height );
+		this.lastRenderTarget.setSize( this.width, this.height );
 
-		this.currentRenderTarget.setSize( width, height );
-		this.lastRenderTarget.setSize( width, height );
-
-		this.mixMaterial.uniforms[ 'resolution' ].value.set(width, height);
+		this.mixMaterial.uniforms[ 'resolution' ].value.set( this.width, this.height );
 	}
 
 	dispose() {
+		this.currentRenderTarget.dispose();
+		this.lastRenderTarget.dispose();
 
-		super.dispose();
-
-		if ( this.holdRenderTarget ) this.holdRenderTarget.dispose();
+		this.mixMaterial.dispose();
+		this.copyMaterial.dispose()
 
 	}
 
@@ -363,7 +368,7 @@ const MixShader = {
 
 			vec4 current = texture2D( tCurrent, vUv );
 			vec4 last = texture2D( tLast, vUv);
-
+			float value = 0.05;
 			//unGhosting
 			if(!cameraMoving) {
 				current.rgb = RGB2YCoCgR(ToneMap(current.rgb));
@@ -371,10 +376,11 @@ const MixShader = {
 				last.rgb = clipAABB(current.rgb, last.rgb);
 				current.rgb = UnToneMap(YCoCgR2RGB(current.rgb));
 				last.rgb = UnToneMap(YCoCgR2RGB(last.rgb));
+				value = 1.0;
 			}
 	
 
-			vec4 result = mix(last, current, 0.05);
+			vec4 result = mix(last, current, value);
 			float luma = Luminance(result.rgb); //send To next Pass
 
 			gl_FragColor = vec4(result.rgb, luma);

+ 1 - 1
src/examples/jsm/shaders/SSAOShader2.js

@@ -426,7 +426,7 @@ const HBAOShader = {
 			vec2 noiseResolution = vec2(textureSize(tNoise, 0));
 			vec2 noiseUv = vUv * resolution / noiseResolution;
 			// vec4 noiseTexel = textureLod(tNoise, noiseUv, 0.0);
-			float uvScale = 2.0;
+			float uvScale = 4.0;
 			float noise = IGN(gl_FragCoord.y * uvScale, gl_FragCoord.x * uvScale, uframe);
 			vec3 randomVec = vec3(noise, fract(noise * 52.9829189), noise);
 

+ 183 - 78
src/views/Renderer.vue

@@ -2,6 +2,9 @@
   <div>
     <input type="file" ref="loadModel" id="load-model" style="display: none"/>
 	  <input type="file" ref="loadBackground" id="load-background" style="display: none"/>
+		<div id="mask">
+			<img id="cover"/>
+		</div>
   </div>
 </template>
 
@@ -14,10 +17,8 @@
 
 		import { EffectComposer } from '../examples/jsm/postprocessing/EffectComposer.js';
 		import { RenderPass } from '../examples/jsm/postprocessing/RenderPass.js';
-		import { SSAOPass } from '../examples/jsm/postprocessing/SSAOPass2.js';
 		import { SSRPass } from '../examples/jsm/postprocessing/SSRPass_Blending.js';
 		import { TAARenderPass2 } from '../examples/jsm/postprocessing/TAARenderPass2.js';
-		import { UnrealBloomPass } from '../examples/jsm/postprocessing/UnrealBloomPass2.js';
 		import { BloomPass } from '../examples/jsm/postprocessing/BloomPass2.js';
 		import { ShaderPass } from '../examples/jsm/postprocessing/ShaderPass.js'
 
@@ -40,8 +41,9 @@
 		import { EXRLoader } from '../examples/jsm/loaders/EXRLoader.js';
 		import { DRACOLoader } from '../examples/jsm/loaders/DRACOLoader.js';
 		import { RGBELoader } from '../examples/jsm/loaders/RGBELoader.js';
-		import {OBJLoader} from '../examples/jsm/loaders/OBJLoader.js'
-		import {MTLLoader} from '../examples/jsm/loaders/MTLLoader.js'
+		import { KTX2Loader } from '../examples/jsm/loaders/KTX2Loader.js';
+		import { OBJLoader } from '../examples/jsm/loaders/OBJLoader.js';
+		import { MTLLoader } from '../examples/jsm/loaders/MTLLoader.js';
 
 
 		import { OrbitControls } from '../examples/jsm/controls/OrbitControls.js'
@@ -49,6 +51,7 @@
 
 		import { ProgressiveShadows } from '../examples/jsm/postprocessing/ProgressiveShadows.js';
 		import { TransformControls } from '../examples/jsm/controls/TransformControls.js';
+		import { MeshoptDecoder } from '../examples/jsm/libs/meshopt_decoder.module.js';
     
     import $ from 'jquery'
     import gsap from 'gsap'
@@ -57,17 +60,23 @@
     import { useRouter, useRoute } from 'vue-router'
     import {ref, onMounted } from 'vue'
 
+		import NProgress from 'nprogress'
+		import 'nprogress/nprogress.css'
+
 
     const router = useRouter()
     const route = useRoute()
 
 		const baseURL = '/renderer' //'http://120.24.144.164:10003'
-		let container, stats;
-		let num;
+		const sourceURL = 'https://4dkk.4dage.com/renderer/'
+
+		let container, mask, stats;
+		let num, renderRes;
 		let metadata;
 		let modelFile, backgroundFile, coverFile;
 		let gui;
-		let camera, scene, renderer;
+		let camera, scene;
+		const renderer = new WebGLRenderer()
 		let composer;
 		let group = new THREE.Group();
 		let controls;
@@ -82,7 +91,6 @@
 		let renderPass;
 		let ssrPass;
 		let hbaoPass;
-		let ssaoPass;
 		let BCSPass;
 		let colorBalancePass;
 		let sharpenPass;
@@ -98,13 +106,24 @@
 		const loadModel = ref(null)
 		const loadBackground = ref(null)
 
+		const loadingManager = new THREE.LoadingManager()
+
+		let gltfLoader = new GLTFLoader(loadingManager);
+		let ktx2Loader = new KTX2Loader(loadingManager);
+ 		ktx2Loader.setTranscoderPath('../assets/libs/basis/');
+		ktx2Loader.detectSupport(renderer)
 
-		let gltfLoader = new GLTFLoader();
+		
 		const exrLoader = new EXRLoader();
 		const rgbeLoader = new RGBELoader();
 		let dracoLoader = new DRACOLoader();
-		dracoLoader.setDecoderPath('../examples/jsm/libs/draco');
+		dracoLoader.setDecoderPath('../assets/libs/draco/');
+
+		gltfLoader.setKTX2Loader(ktx2Loader);
 		gltfLoader.setDRACOLoader(dracoLoader);
+		gltfLoader.setMeshoptDecoder(MeshoptDecoder)
+
+
 		const toneMappingOptions = {
 			Linear: THREE.LinearToneMapping,
 			Reinhard: THREE.ReinhardToneMapping,
@@ -420,7 +439,8 @@
 					y: 0,
 					z: 0,
 				},
-			}
+			},
+			lock: false
 		}
 		let params;
 		const upload1 = () => {
@@ -457,7 +477,7 @@
 				lights.push(dL)
 			})
 		}
-		function updateCamera(time = 1, position = params.camera.position, quaternion = params.camera.quaternion, target = params.camera.target) {
+		function updateCamera(time = 2, position = params.camera.position, quaternion = params.camera.quaternion, target = params.camera.target) {
 			gsap.to(camera.position, {
 				duration: time,
 				ease: "circ.out",
@@ -480,26 +500,6 @@
 				y: target.y,
 				z: target.z,
 			})
-
-			// gsap.to(camera.position, {
-			// 	duration: 1,
-			// 	x: activeModel.position.x,
-			// 	y: activeModel.position.y,
-			// 	z: activeModel.position.z,
-			// })
-			// gsap.to(camera.quaternion, {
-			// 	duration: 1,
-			// 	x: activeModel.quaternion.x,
-			// 	y: activeModel.quaternion.y,
-			// 	z: activeModel.quaternion.z,
-			// 	w: activeModel.quaternion.x,
-			// })
-			// gsap.to(controls.target, {
-			// 	duration: 1,
-			// 	x: activeModel.target.x,
-			// 	y: activeModel.target.y,
-			// 	z: activeModel.target.z,
-			// })
 		}
 		function getCameraData() {
 
@@ -534,7 +534,7 @@
 			camera.aspect = screenShotSize.width / screenShotSize.height
 			renderer.setSize(screenShotSize.width, screenShotSize.height)
 			composer.setSize(screenShotSize.width, screenShotSize.height)
-			composer.setPixelRatio(2)
+			composer.setPixelRatio(renderRes * 2)
 			setTimeout(() => {
 				cameraMove()
 			}, 50)
@@ -545,13 +545,13 @@
 				link.download = saveAsFileName
 				link.click();
 				// reset
-				composer.setPixelRatio(1)
+				composer.setPixelRatio(renderRes)
 				canvas.width = width
 				canvas.height = height
 				camera.aspect = aspect
 				renderer.setSize(width, height)
 				composer.setSize(width, height)
-			}, 1000)
+			}, 2000)
 			
 			// canvas.width = width
 			// canvas.height = height
@@ -572,6 +572,7 @@
 
 		function initGui() {
 			// Init gui
+			if(gui) return
 			gui = new GUI();
 
 			//file
@@ -636,7 +637,7 @@
 				addGround(true)
 			}
 			
-			folderScene.add(group.rotation, 'y').min(0).max(10)
+			// folderScene.add(group.rotation, 'y').min(0).max(10)
 
 			// camera
 			const shotSize = {
@@ -651,6 +652,7 @@
 			const folderCamera = gui.addFolder('摄像机');
 			folderCamera.add(params.camera, 'fov').min(10).max(90).step(0.1).onChange(() => {
 				camera.fov = params.camera.fov;
+				cameraMove()
 			})
 			const cameraFun = {
 				saveCameraPos: getCameraData,
@@ -1022,18 +1024,57 @@
 
 			// folderTaa.add(fxaaPass,'enabled').name('fxaa')
 			folderTaa.close();
-		}	
+		}
+
+		function initLoadingManager() {
+			loadingManager.onStart = () => {
+				NProgress.start()
+			}
+
+			loadingManager.onProgress = (itemUrl, itemsLoaded, itemsTotal) => {
+				 if(itemsLoaded === 1) {
+				 	NProgress.inc(0.5)
+				 } else {
+				 	NProgress.inc()
+				 }
+			}
+
+			loadingManager.onLoad = () => {
+				initGui();
+				updateCamera(2, params.camera.position, params.camera.quaternion, params.camera.target)
+				gsap.to('#cover', {
+					duration: 1,
+					opacity: 0,
+				})
+				gsap.to('#mask', {
+					duration: 1,
+					opacity: 0,
+					onComplete: () => {
+						mask.style.display = 'none'
+					}
+				})
+				NProgress.done()
+			}
+
+			loadingManager.onError = () => {
+				console.log('load error')
+			}
+		}
 
 		function initScene() {
-			const width = window.innerWidth * window.devicePixelRatio;
-			const height = window.innerHeight * window.devicePixelRatio;
+			const width = window.innerWidth;
+			const height = window.innerHeight;
 			container = document.createElement('div');
+			mask = document.getElementById('mask');
+
+			// container = document.getElementById('container')
+			// let canvas = document.getElementById('canvas')
 			document.body.appendChild(container);
 			scene = new THREE.Scene();
 			// const texturePass = new TexturePass();
 			let envUrl = '../assets/textures/rainforest.exr'
 			envUrl = params.scene.envPath ? params.scene.envPath : envUrl; 
-			console.log(envUrl)
+			// console.log(envUrl)
 
 			exrLoader.load(envUrl, (exr) => {
 				exr.mapping = THREE.EquirectangularReflectionMapping;
@@ -1044,27 +1085,27 @@
 				scene.backgroundBlurriness = params.scene.backgroundBlurriness;
 			})
 
-			renderer = new WebGLRenderer({antialias: false});
+			// renderer = new WebGLRenderer({antialias: false});
 			renderer.shadowMap.enabled = true
 			renderer.shadowMap.type = THREE.PCFSoftShadowMap
 			renderer.useLegacyLights = true
 			renderer.toneMapping = THREE.ACESFilmicToneMapping
 
 			renderer.toneMappingExposure = params.toneMapping.toneMappingExposure
-			renderer.setSize(window.innerWidth, window.innerHeight);
-			console.log(window.devicePixelRatio)
+			renderer.setSize(width, height);
+			console.log(width, height, renderRes);
 			document.body.appendChild(renderer.domElement);
 			renderer.domElement.addEventListener( 'mousedown', onMouseDown );
 			renderer.domElement.addEventListener( 'mouseup', onMouseUp );
-			// renderer.setPixelRatio(2)
+			renderer.setPixelRatio(renderRes);
 
 			backgroundPlane = new THREE.Mesh(new THREE.PlaneGeometry(1000, 1000), new THREE.MeshBasicMaterial({color: params.backColor.color}))
-			backgroundPlane.position.z = -100
-			backgroundPlane.visible = params.backColor.enabled
+			backgroundPlane.position.z = -100;
+			backgroundPlane.visible = params.backColor.enabled;
 			camera = new THREE.PerspectiveCamera(params.camera.fov, window.innerWidth / window.innerHeight, 0.1, 150);
-			camera.add(backgroundPlane)
+			camera.add(backgroundPlane);
 			camera.position.set( 100, 2, 100 );
-			scene.add(camera)
+			scene.add(camera);
 
 			controls = new OrbitControls(camera, renderer.domElement)
 			controls.enableDamping = true;
@@ -1083,13 +1124,7 @@
 				controls.enabled = true
 			})
 			scene.add(transformControls)
-			if(params.scene.modelPath) {
-				gltfLoader.load(params.scene.modelPath, (gltf) => {
-					loadGLTF(gltf);
-				})
-			}
-			// switchModels(0);
-			scene.add(group);
+		
 
 			stats = new Stats();
 			container.appendChild(stats.dom);
@@ -1097,7 +1132,7 @@
 			
 
 			composer = new EffectComposer(renderer);
-
+			composer.setPixelRatio(renderRes)
 			// colorPass = new ColorPass();
 			// colorPass.enabled = params.backColor.enabled;
 			// colorPass.color.set(params.backColor.color);
@@ -1169,16 +1204,13 @@
 			sharpenPass.uniforms.strength.value = params.sharpen.strength;
 			composer.addPass(sharpenPass);
 
-			bloomPass = new BloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
+			bloomPass = new BloomPass( width, height );
 			composer.addPass( bloomPass );
 			bloomPass.enabled = params.bloom.enabled;
 			bloomPass.threshold = params.bloom.threshold;
 			bloomPass.strength = params.bloom.strength;
 			bloomPass.radius = params.bloom.radius;
 
-			
-
-
 			rgbShiftPass = new ShaderPass(RGBShiftShader);
 			rgbShiftPass.enabled = params.rgbShift.enabled;
 			rgbShiftPass.uniforms.amount.value = params.rgbShift.amount;
@@ -1194,24 +1226,48 @@
 			const outputPass = new OutputPass();
 			composer.addPass( outputPass );
 
+			if(params.scene.modelPath) {
+				gltfLoader.load(params.scene.modelPath, (gltf) => {
+					loadGLTF(gltf);
+				})
+			} else {
+				gsap.to('#cover', {
+					duration: 1,
+					opacity: 0,
+				})
+				gsap.to('#mask', {
+					duration: 1,
+					opacity: 0,
+					onComplete: () => {
+						mask.style.display = 'none'
+					}
+				})
+				initGui();
+			}
+			scene.add(group);
+
 			controls.addEventListener('change', () => {
-				ssrPass.cameraMoving = true
+				cameraMove()
 			})
 			camera.addEventListener('change', () => {
-				ssrPass.cameraMoving = true
-
+				cameraMove()
 			})
 			window.addEventListener('resize', () => {
 				onWindowResize()
-				ssrPass.cameraMoving = true
-
+				cameraMove()
 			});
 		}
 	
 		function onWindowResize() {
 
-			const width = window.innerWidth;
-			const height = window.innerHeight;
+			// const width = window.innerWidth;
+			// const height = window.innerHeight;
+			// const devicePixelRatio = window.devicePixelRatio;
+			const width = document.documentElement.clientWidth;
+			const height = document.documentElement.clientHeight;
+			console.log(width, height)
+			// console.log('window.inner:', width, height)
+			// console.log('document:', document.documentElement.clientWidth, document.documentElement.clientHeight)
 
 			camera.aspect = width / height;
 			camera.updateProjectionMatrix();
@@ -1235,10 +1291,8 @@
 			controls.update();
 			if(ssrPass.cameraMoving === false){
 				taaPass.accumulate = true;
-				// composer.setPixelRatio(2)
 			} else {
 				taaPass.accumulate = false;
-				// composer.setPixelRatio(1)
 			}
 			composer.render();
 			// renderer.render(scene, camera);
@@ -1286,7 +1340,7 @@
 					shadowGroundFolder.add(shadowGround.scale, 'x').onChange(() => {
 						shadowGround.scale.y = shadowGround.scale.x
 						params.scene.shadowGround.size = shadowGround.scale.x
-					}).min(1).max(5)
+					}).min(1).max(5).name('scale')
 
 				} else {
 					shadowGround.visible = true
@@ -1321,10 +1375,9 @@
 			boundingBox.setFromObject(model);
 			boundingBox.getCenter(center)
 			boundingBox.getSize(size);
-			console.log(size, center)
+			// console.log(size, center)
 			group.add(model)
 			if(params.scene.useShadows) useShadows(true)
-			updateCamera(1, params.camera.position, params.camera.quaternion, params.camera.target)
 		}
 		function loadEXR(exr) {
 			// console.log(exr)
@@ -1471,9 +1524,9 @@
 			camera.aspect = 16/9
 			renderer.setSize(960, 540)
 			composer.setSize(960, 540)
-			composer.setPixelRatio(2)
+			// composer.setPixelRatio(2)
 			setTimeout(() => {
-			cameraMove()
+				cameraMove()
 			}, 50)
 			setTimeout(async () => {
 				composer.render()
@@ -1484,7 +1537,7 @@
 				coverFile = file
 				console.log(coverFile)
 				// reset
-				composer.setPixelRatio(1)
+				// composer.setPixelRatio(1)
 				canvas.width = width
 				canvas.height = height
 				camera.aspect = aspect
@@ -1495,18 +1548,50 @@
 					alert('文件上传失败')
 					// return
 				}
-			}, 1000)
+			}, 2000)
+		}
+		function startLoad() {
+			let cover = document.getElementById('cover')
+			let url = sourceURL + num + "/cover.png"
+			
+			checkImgExists(url)
+			.then(() => {
+				cover.src = url;
+			})
+			.catch(() => {
+				mask.style.display = 'none'
+				initGui()
+			})
+		}
+		function checkImgExists(url) {
+			return new Promise(function(resolve, reject) {
+				let img = new Image();
+				img.src = url;
+				img.onload = function(res) {
+					resolve(res)
+				}
+				img.onerror = function(err) {
+					reject(err)
+				}
+			})
 		}
 
 		async function getNum() {
 			// num = decodeURI(window.location.search)
       num = route.params.num
 			// num = num.split('num=')[1]
+			if(/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) {
+				renderRes = window.devicePixelRatio * 0.5
+			} else {
+				renderRes = window.devicePixelRatio
+			}
+
 			if(!num) {
 				router.push('home')
 			} else {
 				console.log(num)
 				await getParams()
+				startLoad()
 			}
 		}
 		async function getParams() {
@@ -1523,8 +1608,8 @@
 						}
 						updateParams()
 						console.log(params)
+						initLoadingManager();
 						initScene();
-						initGui();
 						animate();
 					} else {
 						alert('场景初始化错误')
@@ -1694,7 +1779,8 @@
 			if(!params.dof.bladeCount) {
 				params.dof.bladeCount = 6
 			}
-			// params.lock = true
+			
+			params.lock = false
 
 			// params.colorBalance = {
 			// 	enabled: true,
@@ -1739,5 +1825,24 @@
     margin: 0;
     padding: 0;
     background-color: #252525;
+		overflow: hidden;
   }
+	#mask{
+		background-color: rgba(0,0,0,1);
+    width: 100%;
+    height: 100%;
+    position: absolute;
+		z-index: 100;
+		/* display: none; */
+	}
+	#cover{
+		/* height: 100%; */
+		width: 100%;
+		margin: 0;
+    padding: 0;
+		opacity: 0.5;
+		filter: blur(20px);
+		-webkit-filter: blur(20px);
+		pointer-events:none;
+	}
 </style>

+ 20 - 7
src/views/Renderer_Home.vue

@@ -48,13 +48,13 @@ let sceneList = []
         const item = $("<div></div>");
         item.addClass('item')
         const img = $('<img>')
-        try{
-          img.attr({src: sourceURL + i.num + "/cover.png"})
-        }catch (error) {
-          console.log(error)
-        }
-        img.one('error', function() {
-          $(this).attr({src:"../assets/textures/none.png"})
+        let url = sourceURL + i.num + "/cover.png"
+        checkImgExists(url)
+        .then(() => {
+          img.attr({src: url})
+        })
+        .catch(() => {
+          img.attr({src:"../assets/textures/none.png"})
         })
         img.addClass('cover')
         const title = $("<div></div>")
@@ -171,6 +171,19 @@ let sceneList = []
       })
     }
 
+    function checkImgExists(url) {
+			return new Promise(function(resolve, reject) {
+				let img = new Image();
+				img.src = url;
+				img.onload = function(res) {
+					resolve(res)
+				}
+				img.onerror = function(err) {
+					reject(err)
+				}
+			})
+		}
+
 </script>
 <style>
   html, body{