Browse Source

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

Fix incorrect i3dm transforms
Garrett Johnson 4 năm trước cách đây
mục cha
commit
e9e87f3414
5 tập tin đã thay đổi với 122 bổ sung60 xóa
  1. 11 0
      CHANGELOG.md
  2. 1 1
      package.json
  3. 12 22
      src/three/CMPTLoader.js
  4. 81 20
      src/three/I3DMLoader.js
  5. 17 17
      src/three/PNTSLoader.js

+ 11 - 0
CHANGELOG.md

@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## Unreleased
+### Added
+- Add warnings if unsupported feature semantics are detected for I3DM and PNTS files
+- Support for I3DM rotation, scale features.
+
+### Fixed
+- A case where I3DM instances could have an incorrect transformations by respecting existing Mesh transformations when converting them to InstancedMeshes.
+
+### Changed
+- Make CMPTLoader group child order consistent between loads.
+
 ## [0.2.6] - 2021-02-03
 ### Fixed
 - I3DM files not correctly loading external gltf files.

+ 1 - 1
package.json

@@ -48,7 +48,7 @@
     "jest-cli": "^25.4.0",
     "parcel-bundler": "^1.12.4",
     "static-server": "^2.2.1",
-    "three": ">=0.123.0",
+    "three": ">=0.125.0",
     "typescript": "^3.7.4"
   },
   "peerDependencies": {

+ 12 - 22
src/three/CMPTLoader.js

@@ -17,8 +17,6 @@ export class CMPTLoader extends CMPTLoaderBase {
 
 		const result = super.parse( buffer );
 		const manager = this.manager;
-		const group = new Group();
-		const results = [];
 		const promises = [];
 
 		for ( const i in result.tiles ) {
@@ -29,15 +27,7 @@ export class CMPTLoader extends CMPTLoaderBase {
 				case 'b3dm': {
 
 					const slicedBuffer = buffer.slice();
-					const promise = new B3DMLoader( manager )
-						.parse( slicedBuffer.buffer )
-						.then( res => {
-
-							results.push( res );
-							group.add( res.scene );
-
-						} );
-
+					const promise = new B3DMLoader( manager ).parse( slicedBuffer.buffer );
 					promises.push( promise );
 					break;
 
@@ -47,8 +37,8 @@ export class CMPTLoader extends CMPTLoaderBase {
 
 					const slicedBuffer = buffer.slice();
 					const pointsResult = new PNTSLoader( manager ).parse( slicedBuffer.buffer );
-					results.push( pointsResult );
-					group.add( pointsResult.scene );
+					const promise = Promise.resolve( pointsResult );
+					promises.push( promise );
 					break;
 
 				}
@@ -60,14 +50,7 @@ export class CMPTLoader extends CMPTLoaderBase {
 					loader.workingPath = this.workingPath;
 					loader.fetchOptions = this.fetchOptions;
 
-					const promise = loader
-						.parse( slicedBuffer.buffer )
-						.then( res => {
-
-							results.push( res );
-							group.add( res.scene );
-
-						} );
+					const promise = loader.parse( slicedBuffer.buffer );
 					promises.push( promise );
 					break;
 
@@ -77,7 +60,14 @@ export class CMPTLoader extends CMPTLoaderBase {
 
 		}
 
-		return Promise.all( promises ).then( () => {
+		return Promise.all( promises ).then( results => {
+
+			const group = new Group();
+			results.forEach( result => {
+
+				group.add( result.scene );
+
+			} );
 
 			return {
 

+ 81 - 20
src/three/I3DMLoader.js

@@ -2,6 +2,9 @@ import { I3DMLoaderBase } from '../base/I3DMLoaderBase.js';
 import { DefaultLoadingManager, Matrix4, InstancedMesh, Vector3, Quaternion } from 'three';
 import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
 
+const tempFwd = new Vector3();
+const tempUp = new Vector3();
+const tempRight = new Vector3();
 const tempPos = new Vector3();
 const tempQuat = new Quaternion();
 const tempSca = new Vector3();
@@ -36,22 +39,29 @@ export class I3DMLoader extends I3DMLoaderBase {
 					loader.parse( gltfBuffer, null, model => {
 
 						const INSTANCES_LENGTH = featureTable.getData( 'INSTANCES_LENGTH' );
+						const POSITION = featureTable.getData( 'POSITION', INSTANCES_LENGTH, 'FLOAT', 'VEC3' );
+						const NORMAL_UP = featureTable.getData( 'NORMAL_UP', INSTANCES_LENGTH, 'FLOAT', 'VEC3' );
+						const NORMAL_RIGHT = featureTable.getData( 'NORMAL_RIGHT', INSTANCES_LENGTH, 'FLOAT', 'VEC3' );
+						const SCALE_NON_UNIFORM = featureTable.getData( 'SCALE_NON_UNIFORM', INSTANCES_LENGTH, 'FLOAT', 'VEC3' );
+						const SCALE = featureTable.getData( 'SCALE', INSTANCES_LENGTH, 'FLOAT', 'SCALAR' );
 
-						// RTC_CENTER
-						// QUANTIZED_VOLUME_OFFSET
-						// QUANTIZED_VOLUME_SCALE
-						// EAST_NORTH_UP
+						[
+							'RTC_CENTER',
+							'QUANTIZED_VOLUME_OFFSET',
+							'QUANTIZED_VOLUME_SCALE',
+							'EAST_NORTH_UP',
+							'POSITION_QUANTIZED',
+							'NORMAL_UP_OCT32P',
+							'NORMAL_RIGHT_OCT32P',
+						].forEach( feature => {
 
-						const POSITION = featureTable.getData( 'POSITION', INSTANCES_LENGTH, 'FLOAT', 'VEC3' );
+							if ( feature in featureTable.header ) {
+
+								console.warn( `I3DMLoader: Unsupported FeatureTable feature "${ feature }" detected.` );
 
-						// POSITION_QUANTIZED
-						// NORMAL_UP
-						// NORMAL_RIGHT
-						// NORMAL_UP_OCT32P
-						// NORMAL_RIGHT_OCT32P
-						// SCALE
-						// SCALE_NON_UNIFORM
-						// BATCH_ID
+							}
+
+						} );
 
 						const instanceMap = new Map();
 						const instances = [];
@@ -61,6 +71,9 @@ export class I3DMLoader extends I3DMLoaderBase {
 
 								const { geometry, material } = child;
 								const instancedMesh = new InstancedMesh( geometry, material, INSTANCES_LENGTH );
+								instancedMesh.position.copy( child.position );
+								instancedMesh.rotation.copy( child.rotation );
+								instancedMesh.scale.copy( child.scale );
 								instances.push( instancedMesh );
 								instanceMap.set( child, instancedMesh );
 
@@ -71,7 +84,6 @@ export class I3DMLoader extends I3DMLoaderBase {
 						const averageVector = new Vector3();
 						for ( let i = 0; i < INSTANCES_LENGTH; i ++ ) {
 
-							// TODO: handle quantized position
 							averageVector.x += POSITION[ i * 3 + 0 ] / INSTANCES_LENGTH;
 							averageVector.y += POSITION[ i * 3 + 1 ] / INSTANCES_LENGTH;
 							averageVector.z += POSITION[ i * 3 + 2 ] / INSTANCES_LENGTH;
@@ -89,9 +101,13 @@ export class I3DMLoader extends I3DMLoaderBase {
 								parent.add( instancedMesh );
 
 								// Center the instance around an average point to avoid jitter at large scales.
+								// Transform the average vector by matrix world so we can account for any existing
+								// transforms of the instanced mesh.
+								instancedMesh.updateMatrixWorld();
 								instancedMesh
 									.position
-									.copy( averageVector );
+									.copy( averageVector )
+									.applyMatrix4( instancedMesh.matrixWorld );
 
 							}
 
@@ -99,18 +115,63 @@ export class I3DMLoader extends I3DMLoaderBase {
 
 						for ( let i = 0; i < INSTANCES_LENGTH; i ++ ) {
 
-							// TODO: handle quantized position
+							// position
 							tempPos.set(
 								POSITION[ i * 3 + 0 ] - averageVector.x,
 								POSITION[ i * 3 + 1 ] - averageVector.y,
 								POSITION[ i * 3 + 2 ] - averageVector.z,
 							);
 
-							// TODO: handle normal orientation features
-							tempQuat.set( 0, 0, 0, 1 );
+							// rotation
+							if ( NORMAL_UP ) {
+
+								tempUp.set(
+									NORMAL_UP[ i * 3 + 0 ],
+									NORMAL_UP[ i * 3 + 1 ],
+									NORMAL_UP[ i * 3 + 2 ],
+								);
+
+								tempRight.set(
+									NORMAL_RIGHT[ i * 3 + 0 ],
+									NORMAL_RIGHT[ i * 3 + 1 ],
+									NORMAL_RIGHT[ i * 3 + 2 ],
+								);
+
+								tempFwd.crossVectors( tempRight, tempUp )
+									.normalize();
+
+								tempMat.makeBasis(
+									tempRight,
+									tempUp,
+									tempFwd,
+								);
+
+								tempQuat.setFromRotationMatrix( tempMat );
 
-							// TODO: handle scale features
-							tempSca.set( 1, 1, 1 );
+							} else {
+
+								tempQuat.set( 0, 0, 0, 1 );
+
+							}
+
+							// scale
+							if ( SCALE ) {
+
+								tempSca.setScalar( SCALE[ i ] );
+
+							} else if ( SCALE_NON_UNIFORM ) {
+
+								tempSca.set(
+									SCALE_NON_UNIFORM[ i * 3 + 0 ],
+									SCALE_NON_UNIFORM[ i * 3 + 1 ],
+									SCALE_NON_UNIFORM[ i * 3 + 2 ],
+								);
+
+							} else {
+
+								tempSca.set( 1, 1, 1 );
+
+							}
 
 							tempMat.compose( tempPos, tempQuat, tempSca );
 

+ 17 - 17
src/three/PNTSLoader.js

@@ -15,30 +15,30 @@ export class PNTSLoader extends PNTSLoaderBase {
 		const result = super.parse( buffer );
 		const { featureTable } = result;
 
-		// global semantics
 		const POINTS_LENGTH = featureTable.getData( 'POINTS_LENGTH' );
-
-		// RTC_CENTER
-		// QUANTIZED_VOLUME_OFFSET
-		// QUANTIZED_VOLUME_SCALE
-		// CONSTANT_RGBA
-		// BATCH_LENGTH
-
 		const POSITION = featureTable.getData( 'POSITION', POINTS_LENGTH, 'FLOAT', 'VEC3' );
 		const RGB = featureTable.getData( 'RGB', POINTS_LENGTH, 'UNSIGNED_BYTE', 'VEC3' );
 
-		// POSITION_QUANTIZED
-		// RGBA
-		// RGB565
-		// NORMAL
-		// NORMAL_OCT16P
-		// BATCH_ID
+		[
+			'RTC_CENTER',
+			'QUANTIZED_VOLUME_OFFSET',
+			'QUANTIZED_VOLUME_SCALE',
+			'CONSTANT_RGBA',
+			'BATCH_LENGTH',
+			'POSITION_QUANTIZED',
+			'RGBA',
+			'RGB565',
+			'NORMAL',
+			'NORMAL_OCT16P',
+		].forEach( feature => {
 
-		if ( POSITION === null ) {
+			if ( feature in featureTable.header ) {
 
-			throw new Error( 'PNTSLoader : POSITION_QUANTIZED feature type is not supported.' );
+				console.warn( `PNTSLoader: Unsupported FeatureTable feature "${ feature }" detected.` );
 
-		}
+			}
+
+		} );
 
 		const geometry = new BufferGeometry();
 		geometry.setAttribute( 'position', new BufferAttribute( POSITION, 3, false ) );