Browse Source

Merge pull request #87 from NASA-AMMOS/small-fixes

Small fixes
Garrett Johnson 5 years ago
parent
commit
e482e71cec

+ 10 - 0
CHANGELOG.md

@@ -9,6 +9,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 
 
 - Basic support for CMPT, PNTS, and I3DM file formats.
 - Basic support for CMPT, PNTS, and I3DM file formats.
 - `autoDisableRendererCulling` field to `TilesRenderer`.
 - `autoDisableRendererCulling` field to `TilesRenderer`.
+- A count of the amount of failed tile content loads to `TilesRenderer.stats`.
+
+### Fixed
+
+- Failed tileset downloads being indefinitely retried.
+- Tile content stats not being correctly updated if a tile failed to load.
+- Not propagating image load errors.
+- DebugTilesRenderer using a different color for every submesh in a tile. Now a single color is used for every submesh in a tile.
+- Tiles not rendering if an empty tile is encountered.
+- Child tiles not rendering if a parent tile content failed to load.
 
 
 ## [0.1.2] - 2020-06-08
 ## [0.1.2] - 2020-06-08
 ### Changed
 ### Changed

+ 24 - 0
TESTCASES.md

@@ -200,3 +200,27 @@ Verify the boxes change with the level of detail of the terrain.
 #### expected
 #### expected
 
 
 Verify the display does not change and the tiles to not disappear while parent tiles load.
 Verify the display does not change and the tiles to not disappear while parent tiles load.
+
+## Verify the renderer does not repeatedly try to download a failed tileset.json
+
+#### steps
+
+1. Open the kitchen sink example.
+1. Set the location hash to `#./non/existing/tileset.json` to load a different tileset.
+
+#### expected
+
+Verify that an error is logged stating that the tileset could not be found just once.
+
+## Verify that failing to load a parent tile does not prevent child tiles from loading
+
+#### steps
+
+1. Temporarily rename the root b3dm file the provided example tileset.
+1. Open the kitchen sink example.
+1. Set the error threshold as high as it goes.
+1. Click rebuild.
+
+#### expected
+
+Verify an error is logged stating that the root tile content could not be loaded, that the stats state that is 1 tile that failed, that "downloads" and "parsing" eventually settle to 0, and that child tiles continue to render.

+ 30 - 7
src/base/TilesRendererBase.js

@@ -55,6 +55,7 @@ export class TilesRendererBase {
 		this.stats = {
 		this.stats = {
 			parsing: 0,
 			parsing: 0,
 			downloading: 0,
 			downloading: 0,
+			failed: 0,
 			inFrustum: 0,
 			inFrustum: 0,
 			used: 0,
 			used: 0,
 			active: 0,
 			active: 0,
@@ -235,7 +236,7 @@ export class TilesRendererBase {
 
 
 						} else {
 						} else {
 
 
-							throw new Error( `Status ${ res.status } (${ res.statusText })` );
+							throw new Error( `TilesRenderer: Failed to load tileset "${ url }" with status ${ res.status } : ${ res.statusText }` );
 
 
 						}
 						}
 
 
@@ -253,19 +254,26 @@ export class TilesRendererBase {
 
 
 					} );
 					} );
 
 
-			pr.catch( e => {
+			pr.catch( err => {
 
 
-				console.error( `TilesLoader: Failed to load tile set json "${ url }"` );
-				console.error( e );
-				delete tileSets[ url ];
+				console.error( err );
+				tileSets[ url ] = err;
 
 
 			} );
 			} );
 
 
 			tileSets[ url ] = pr;
 			tileSets[ url ] = pr;
 
 
-		}
+			return pr;
+
+		} else if ( tileSets[ url ] instanceof Error ) {
+
+			return Promise.reject( tileSets[ url ] );
+
+		} else {
+
+			return Promise.resolve( tileSets[ url ] );
 
 
-		return Promise.resolve( tileSets[ url ] );
+		}
 
 
 	}
 	}
 
 
@@ -426,6 +434,21 @@ export class TilesRendererBase {
 
 
 				if ( e.name !== 'AbortError' ) {
 				if ( e.name !== 'AbortError' ) {
 
 
+					parseQueue.remove( tile );
+					downloadQueue.remove( tile );
+
+					if ( tile.__loadingState === PARSING ) {
+
+						stats.parsing --;
+
+					} else if ( tile.__loadingState === LOADING ) {
+
+						stats.downloading --;
+
+					}
+
+					stats.failed ++;
+
 					console.error( 'TilesRenderer : Failed to load tile.' );
 					console.error( 'TilesRenderer : Failed to load tile.' );
 					console.error( e );
 					console.error( e );
 					tile.__loadingState = FAILED;
 					tile.__loadingState = FAILED;

+ 12 - 4
src/base/traverseFunctions.js

@@ -1,4 +1,10 @@
-import { LOADED } from './constants.js';
+import { LOADED, FAILED } from './constants.js';
+
+function isDownloadFinished( value ) {
+
+	return value === LOADED || value === FAILED;
+
+}
 
 
 // Checks whether this tile was last used on the given frame.
 // Checks whether this tile was last used on the given frame.
 function isUsedThisFrame( tile, frameCount ) {
 function isUsedThisFrame( tile, frameCount ) {
@@ -195,7 +201,7 @@ export function markUsedSetLeaves( tile, renderer ) {
 
 
 			if ( isUsedThisFrame( c, frameCount ) ) {
 			if ( isUsedThisFrame( c, frameCount ) ) {
 
 
-				const childLoaded = ( ! c.__contentEmpty && c.__loadingState === LOADED ) || c.__allChildrenLoaded;
+				const childLoaded = ( ! c.__contentEmpty && isDownloadFinished( c.__loadingState ) ) || c.__allChildrenLoaded;
 				allChildrenLoaded = allChildrenLoaded && childLoaded;
 				allChildrenLoaded = allChildrenLoaded && childLoaded;
 
 
 			}
 			}
@@ -253,7 +259,7 @@ export function skipTraversal( tile, renderer ) {
 	const errorRequirement = ( renderer.errorTarget + 1 ) * renderer.errorThreshold;
 	const errorRequirement = ( renderer.errorTarget + 1 ) * renderer.errorThreshold;
 	const meetsSSE = tile.__error <= errorRequirement;
 	const meetsSSE = tile.__error <= errorRequirement;
 	const hasContent = ! tile.__contentEmpty;
 	const hasContent = ! tile.__contentEmpty;
-	const loadedContent = tile.__loadingState === LOADED && ! tile.__contentEmpty;
+	const loadedContent = isDownloadFinished( tile.__loadingState ) && ! tile.__contentEmpty;
 	const childrenWereVisible = tile.__childrenWereVisible;
 	const childrenWereVisible = tile.__childrenWereVisible;
 	const children = tile.children;
 	const children = tile.children;
 	let allChildrenHaveContent = tile.__allChildrenLoaded;
 	let allChildrenHaveContent = tile.__allChildrenLoaded;
@@ -277,7 +283,9 @@ export function skipTraversal( tile, renderer ) {
 	// all children have loaded yet, and if no children were visible last frame. We want to keep children visible
 	// all children have loaded yet, and if no children were visible last frame. We want to keep children visible
 	// that _were_ visible to avoid a pop in level of detail as the camera moves around and parent / sibling tiles
 	// that _were_ visible to avoid a pop in level of detail as the camera moves around and parent / sibling tiles
 	// load in.
 	// load in.
-	if ( meetsSSE && ! allChildrenHaveContent && ! childrenWereVisible ) {
+
+	// Skip the tile entirely if there's no content to load
+	if ( meetsSSE && ! allChildrenHaveContent && ! childrenWereVisible && hasContent ) {
 
 
 		if ( loadedContent ) {
 		if ( loadedContent ) {
 
 

+ 18 - 4
src/three/DebugTilesRenderer.js

@@ -68,7 +68,13 @@ export class DebugTilesRenderer extends TilesRenderer {
 	loadTileSet( ...args ) {
 	loadTileSet( ...args ) {
 
 
 		const pr = super.loadTileSet( ...args );
 		const pr = super.loadTileSet( ...args );
-		pr.then( () => this.initExtremes() );
+		pr
+			.then( () => this.initExtremes() )
+			.catch( () => {
+
+				// error is logged internally
+
+			} );
 
 
 		return pr;
 		return pr;
 
 
@@ -179,6 +185,17 @@ export class DebugTilesRenderer extends TilesRenderer {
 		visibleTiles.forEach( tile => {
 		visibleTiles.forEach( tile => {
 
 
 			const scene = tile.cached.scene;
 			const scene = tile.cached.scene;
+
+			// create a random color per-tile
+			let h, s, l;
+			if ( colorMode === RANDOM_COLOR ) {
+
+				h = Math.random();
+				s = 0.5 + Math.random() * 0.5;
+				l = 0.375 + Math.random() * 0.25;
+
+			}
+
 			scene.traverse( c => {
 			scene.traverse( c => {
 
 
 				const currMaterial = c.material;
 				const currMaterial = c.material;
@@ -280,9 +297,6 @@ export class DebugTilesRenderer extends TilesRenderer {
 
 
 							if ( ! c.material[ HAS_RANDOM_COLOR ] ) {
 							if ( ! c.material[ HAS_RANDOM_COLOR ] ) {
 
 
-								const h = Math.random();
-								const s = 0.5 + Math.random() * 0.5;
-								const l = 0.375 + Math.random() * 0.25;
 								c.material.color.setHSL( h, s, l );
 								c.material.color.setHSL( h, s, l );
 								c.material[ HAS_RANDOM_COLOR ] = true;
 								c.material[ HAS_RANDOM_COLOR ] = true;
 
 

+ 2 - 2
src/three/TilesRenderer.js

@@ -456,14 +456,14 @@ export class TilesRenderer extends TilesRendererBase {
 			// behavior. Fall back to regular texture loading
 			// behavior. Fall back to regular texture loading
 			manager.addHandler( /(^blob:)|(\.png$)|(\.jpg$)|(\.jpeg$)/g, {
 			manager.addHandler( /(^blob:)|(\.png$)|(\.jpg$)|(\.jpeg$)/g, {
 
 
-				load( url, onComplete ) {
+				load( url, onComplete, onProgress, onError ) {
 
 
 					const loader = new ImageBitmapLoader();
 					const loader = new ImageBitmapLoader();
 					loader.load( url, res => {
 					loader.load( url, res => {
 
 
 						onComplete( new CanvasTexture( res ) );
 						onComplete( new CanvasTexture( res ) );
 
 
-					} );
+					}, onProgress, onError);
 
 
 				}
 				}