Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Draco PNTS proposal alternative #329

Merged
merged 9 commits into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,21 @@ const tilesRenderer = new TilesRenderer( './path/to/tileset.json' );
tilesRenderer.manager.addHandler( /\.gltf$/, loader );
```

Adding support for DRACO decompression within the PNTS files.

```js

// Note the DRACO compression files need to be supplied via an explicit source.
// We use unpkg here but in practice should be provided by the application.
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath( 'https://unpkg.com/[email protected]/examples/js/libs/draco/gltf/' );


const tilesRenderer = new TilesRenderer( './path/to/tileset.json' );
tilesRenderer.manager.addHandler( /\.drc$/, loader );
```


## Loading from Cesium Ion

Loading from Cesium Ion requires some extra fetching of the ion url endpoint, as well as a temporary bearer access token. A full example is found in the ionExample.js file in the examples folder.
Expand Down
131 changes: 94 additions & 37 deletions src/three/PNTSLoader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { PNTSLoaderBase } from '../base/PNTSLoaderBase.js';
import { Points, PointsMaterial, BufferGeometry, BufferAttribute, DefaultLoadingManager } from 'three';
import {
Points,
PointsMaterial,
BufferGeometry,
BufferAttribute,
DefaultLoadingManager,
} from 'three';

const DRACO_ATTRIBUTE_MAP = {
RGB: 'color',
POSITION: 'position',
};

export class PNTSLoader extends PNTSLoaderBase {

Expand All @@ -12,68 +23,114 @@ export class PNTSLoader extends PNTSLoaderBase {

parse( buffer ) {

return super
.parse( buffer )
.then( result => {
return super.parse( buffer ).then( async ( result ) => {

const { featureTable } = result;
const { featureTable } = result;

const POINTS_LENGTH = featureTable.getData( 'POINTS_LENGTH' );
const POSITION = featureTable.getData( 'POSITION', POINTS_LENGTH, 'FLOAT', 'VEC3' );
const RGB = featureTable.getData( 'RGB', POINTS_LENGTH, 'UNSIGNED_BYTE', 'VEC3' );
const material = new PointsMaterial();
const extensions = featureTable.header.extensions;
let geometry;

// handle loading the draco data
if ( extensions && extensions[ '3DTILES_draco_point_compression' ] ) {

const { byteOffset, byteLength, properties } = extensions[ '3DTILES_draco_point_compression' ];
const dracoLoader = this.manager.getHandler( 'draco.drc' );
if ( dracoLoader == null ) {

throw new Error( 'PNTSLoader: dracoLoader not available.' );

}

[
'QUANTIZED_VOLUME_OFFSET',
'QUANTIZED_VOLUME_SCALE',
'CONSTANT_RGBA',
'BATCH_LENGTH',
'POSITION_QUANTIZED',
'RGBA',
'RGB565',
'NORMAL',
'NORMAL_OCT16P',
].forEach( feature => {
// map PNTS keys to draco types
const attributeIDs = {};
for ( const key in properties ) {

if ( feature in featureTable.header ) {
if ( key in DRACO_ATTRIBUTE_MAP && key in properties ) {

console.warn( `PNTSLoader: Unsupported FeatureTable feature "${ feature }" detected.` );
const mappedKey = DRACO_ATTRIBUTE_MAP[ key ];
attributeIDs[ mappedKey ] = properties[ key ];

}

} );
}

// decode the geometry
const taskConfig = {
attributeIDs,
attributeTypes: {
position: 'Float32Array',
color: 'Uint8Array',
},
useUniqueIDs: true,
};

const geometry = new BufferGeometry();
geometry.setAttribute( 'position', new BufferAttribute( POSITION, 3, false ) );
const buffer = featureTable.getBuffer( byteOffset, byteLength );
geometry = await dracoLoader.decodeGeometry( buffer, taskConfig );
if ( geometry.attributes.color ) {

material.vertexColors = true;

}

const material = new PointsMaterial();
material.size = 2;
material.sizeAttenuation = false;
} else {

// handle non compressed case
const POINTS_LENGTH = featureTable.getData( 'POINTS_LENGTH' );
const POSITION = featureTable.getData( 'POSITION', POINTS_LENGTH, 'FLOAT', 'VEC3' );
const RGB = featureTable.getData( 'RGB', POINTS_LENGTH, 'UNSIGNED_BYTE', 'VEC3' );

geometry = new BufferGeometry();
geometry.setAttribute( 'position', new BufferAttribute( POSITION, 3, false ) );
if ( RGB !== null ) {

geometry.setAttribute( 'color', new BufferAttribute( RGB, 3, true ) );
material.vertexColors = true;

}

const object = new Points( geometry, material );
result.scene = object;
result.scene.featureTable = featureTable;
}

const rtcCenter = featureTable.getData( 'RTC_CENTER' );
[
'QUANTIZED_VOLUME_OFFSET',
'QUANTIZED_VOLUME_SCALE',
'CONSTANT_RGBA',
'BATCH_LENGTH',
'POSITION_QUANTIZED',
'RGBA',
'RGB565',
'NORMAL',
'NORMAL_OCT16P',
].forEach( ( feature ) => {

if ( rtcCenter ) {
if ( feature in featureTable.header ) {

result.scene.position.x += rtcCenter[ 0 ];
result.scene.position.y += rtcCenter[ 1 ];
result.scene.position.z += rtcCenter[ 2 ];
console.warn(
`PNTSLoader: Unsupported FeatureTable feature "${feature}" detected.`
);

}

return result;

} );

const object = new Points( geometry, material );
result.scene = object;
result.scene.featureTable = featureTable;

const rtcCenter = featureTable.getData( 'RTC_CENTER' );

if ( rtcCenter ) {

result.scene.position.x += rtcCenter[ 0 ];
result.scene.position.y += rtcCenter[ 1 ];
result.scene.position.z += rtcCenter[ 2 ];

}

return result;

} );

}

}
11 changes: 11 additions & 0 deletions src/utilities/FeatureTable.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
interface FeatureTableHeader {

extensions?: Object;
extras?: any;

}

export class FeatureTable {

header: FeatureTableHeader;

constructor(
buffer : ArrayBuffer,
start : Number,
Expand All @@ -16,6 +25,8 @@ export class FeatureTable {
defaultType? : String | null
) : Number | String | ArrayBufferView;

getBuffer( byteOffset : Number, byteLength : Number ) : ArrayBuffer;

}

export class BatchTable {
Expand Down
7 changes: 7 additions & 0 deletions src/utilities/FeatureTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ export class FeatureTable {

}

getBuffer( byteOffset, byteLength ) {

const { buffer, binOffset } = this;
return buffer.slice( binOffset + byteOffset, binOffset + byteOffset + byteLength );

}

}

export class BatchTable extends FeatureTable {
Expand Down