Skip to content

Commit

Permalink
Merge 101ffb9 into f20a4a3
Browse files Browse the repository at this point in the history
  • Loading branch information
Xintong Xia committed Sep 13, 2019
2 parents f20a4a3 + 101ffb9 commit 56929a6
Show file tree
Hide file tree
Showing 12 changed files with 3,124 additions and 3,141 deletions.
Expand Up @@ -3,7 +3,7 @@
The `Tile3DLayer` renders tileset data formatted according to the [3D Tiles Category](docs/specifications/3d-tiles),
which is supported by the [Tileset3DLoader](docs/api-reference/3d-tiles/tileset-3d-loader).

Tile3DLayer is a [CompositeLayer](/docs/api-reference/composite-layer.md). Base on each tile content [format](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#introduction), it uses either a [PointCloudLayer](/docs/api-reference/point-cloud-layer.md) or [ScenegraphLayer](/docs/api-reference/scenegraph-layer.md) to render.
Tile3DLayer is a [CompositeLayer](/docs/api-reference/composite-layer.md). Base on each tile content [format](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#introduction), it uses either a [PointCloudLayer](/docs/layers/point-cloud-layer.md) or [ScenegraphLayer](/docs/layers/scenegraph-layer.md) to render.

References
- [3D Tiles](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification).
Expand All @@ -30,11 +30,7 @@ export default class App extends Component {
zoom
}
});
},
onTileLoad: (tile) => {
// force update rendering
this.forceUpdate();
},
}
});

return (<DeckGL {...viewport} layers={[layer]} />);
Expand All @@ -60,10 +56,10 @@ new Tile3DLayer({});
To use pre-bundled scripts:

```html
<script src="https://unpkg.com/deck.gl@~7.0.0/dist.min.js"></script>
<script src="https://unpkg.com/deck.gl@~7.3.0/dist.min.js"></script>
<!-- or -->
<script src="https://unpkg.com/@deck.gl/core@~7.0.0/dist.min.js"></script>
<script src="https://unpkg.com/@deck.gl/layers@~7.0.0/dist.min.js"></script>
<script src="https://unpkg.com/@deck.gl/core@~7.3.0/dist.min.js"></script>
<script src="https://unpkg.com/@deck.gl/layers@~7.3.0/dist.min.js"></script>
```

```js
Expand All @@ -84,14 +80,23 @@ Along with other options as below,

- url to fetch tiles entry point [Tileset JSON](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#tileset-json) file.

##### `ionAssetId` (Number|String, Optional)
##### `ionAccessToken` (String, Optional)
##### `_ionAssetId` (Number|String, Optional)
##### `_ionAccessToken` (String, Optional)

- `ionAssetId` and `ionAccessToken` are used to fetch ion dataset.
- `_ionAssetId` and `_ionAccessToken` are used to fetch ion dataset. They are experimental properties, may change in next releases.

[Set up Ion account](https://cesium.com/docs/tutorials/getting-started/#your-first-app);

### Render Options
##### `DracoLoader` (Object, Optional)
##### `DracoWorkerLoader` (Object, Optional)

One of `DracoLoader` or `DracoWorkerLoader` is required if the tileset contains any draco compressed tiles. [`@loaders.gl/draco`](https://github.com/uber-web/loaders.gl/tree/master/modules/draco) provides the draco decoding modules.

```js
import {DracoLoader, DracoWorkerLoader} from '@loaders.gl/draco';
```

### Callbacks

##### `onTilesetLoad` (Function, optional)
`onTilesetLoad` is a function that is called when Tileset JSON file is loaded. [Tileset](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#tileset-json) object is passed in the callback.
Expand All @@ -118,6 +123,15 @@ Along with other options as below,
- `url`: the url of the failed tile.
- `message`: the error message.

## Sub Layers

The Tile3DLayer renders the following sublayers based on tile [format](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#introduction):

* `scenegraph` - a [ScenegraphLayer](/docs/layers/scenegraph-layer.md) rendering all the tiles with Batched 3D Model format or Instanced 3D Model format.
- `_lighting` is default to `pbr`.
* `pointcloud` - a [PointCloudLayer](/docs/layers/point-cloud-layer.md) rendering all the tiles with Point Cloud format.
- `pointSize` is default to `1.0`.

## Source

[modules/tile-layers/src/tile-3d-layer](https://github.com/uber/deck.gl/tree/master/modules/tile-layers/src/tile-3d-layer)
2 changes: 1 addition & 1 deletion examples/playground/package.json
Expand Up @@ -12,7 +12,7 @@
"@deck.gl/json": "^7.3.0-alpha",
"@deck.gl/layers": "^7.3.0-alpha",
"@deck.gl/react": "^7.3.0-alpha",
"@luma.gl/constants": "^7.3.0-alpha",
"@luma.gl/constants": "^7.3.0-alpha.8",
"brace": "^0.11.1",
"react": "~16.9.0",
"react-ace": "^6.1.4",
Expand Down
4 changes: 2 additions & 2 deletions examples/website/3d-tiles/app.js
Expand Up @@ -66,8 +66,8 @@ export class App extends PureComponent {
_renderTile3DLayer() {
return new Tile3DLayer({
id: 'tile-3d-layer',
ionAssetId: 33301,
ionAccessToken: ION_TOKEN,
_ionAssetId: 33301,
_ionAccessToken: ION_TOKEN,
DracoWorkerLoader,
DracoLoader,
onTilesetLoad: this._onTilesetLoad
Expand Down
5 changes: 2 additions & 3 deletions modules/geo-layers/src/tile-3d-layer/get-frame-state.js
Expand Up @@ -15,9 +15,8 @@ const cullingVolume = new CullingVolume([

// Extracts a frame state appropriate for tile culling from a deck.gl viewport
// TODO - this could likely be generalized and merged back into deck.gl for other culling scenarios
export function getFrameState(viewport, timeline) {
export function getFrameState(viewport, options = {}) {
// Traverse and and request. Update _selectedTiles so that we know what to render.
const tick = timeline.getTime();
const {cameraDirection, cameraUp, height} = viewport;
const {metersPerPixel} = viewport.distanceScales;

Expand Down Expand Up @@ -55,7 +54,7 @@ export function getFrameState(viewport, timeline) {
},
height,
cullingVolume,
frameNumber: tick, // TODO: This can be the same between updates, what number is unique for between updates?
frameNumber: options.frameNumber, // TODO: This can be the same between updates, what number is unique for between updates?
sseDenominator: 1.15 // Assumes fovy = 60 degrees
};
}
Expand Down
138 changes: 75 additions & 63 deletions modules/geo-layers/src/tile-3d-layer/tile-3d-layer.js
Expand Up @@ -4,27 +4,24 @@ import {COORDINATE_SYSTEM, CompositeLayer} from '@deck.gl/core';
import {PointCloudLayer} from '@deck.gl/layers';
import {ScenegraphLayer} from '@deck.gl/mesh-layers';

import {parse, registerLoaders} from '@loaders.gl/core';
import {parse} from '@loaders.gl/core';
import {GLTFLoader} from '@loaders.gl/gltf';
import {
Tileset3DLoader,
Tile3DLoader,
Tileset3D,
_getIonTilesetMetadata
} from '@loaders.gl/3d-tiles';
import {Tileset3D, _getIonTilesetMetadata} from '@loaders.gl/3d-tiles';

import {getFrameState} from './get-frame-state';

registerLoaders([Tile3DLoader, Tileset3DLoader, GLTFLoader]);

const defaultProps = {
_lighting: 'pbr',
pointSize: 1.0,
opacity: 1.0,

tilesetUrl: null,
ionAssetId: null,
ionAccessToken: null,
color: [155, 155, 155, 200],
depthLimit: Number.MAX_SAFE_INTEGER,
_ionAssetId: null,
_ionAccessToken: null,
onTilesetLoad: tileset3d => {},
onTileLoad: tileHeader => {}
onTileLoad: tileHeader => {},
onTileUnload: tileHeader => {},
onTileLoadFail: (tile, message, url) => {}
};

function unpackTile(tileHeader, dracoLoader) {
Expand All @@ -48,7 +45,7 @@ function unpackTile(tileHeader, dracoLoader) {
// DracoLoading is typically async on worker, better keep it in the top-level `parse` promise...
function unpackGLTF(tileHeader, dracoLoader) {
if (tileHeader.content.gltfArrayBuffer) {
tileHeader.userData.gltf = parse(tileHeader.content.gltfArrayBuffer, {
tileHeader.userData.gltf = parse(tileHeader.content.gltfArrayBuffer, [GLTFLoader], {
DracoLoader: dracoLoader,
decompress: true
});
Expand All @@ -62,7 +59,6 @@ export default class Tile3DLayer extends CompositeLayer {
initializeState() {
this.state = {
layerMap: {},
layers: [],
tileset3d: null
};
}
Expand All @@ -75,28 +71,30 @@ export default class Tile3DLayer extends CompositeLayer {
if (props.tilesetUrl && props.tilesetUrl !== oldProps.tilesetUrl) {
await this._loadTileset(props.tilesetUrl);
} else if (
(props.ionAccessToken || props.ionAssetId) &&
(props.ionAccessToken !== oldProps.ionAccessToken || props.ionAssetId !== oldProps.ionAssetId)
(props._ionAccessToken || props._ionAssetId) &&
(props._ionAccessToken !== oldProps._ionAccessToken ||
props._ionAssetId !== oldProps._ionAssetId)
) {
await this._loadTilesetFromIon(props.ionAccessToken, props.ionAssetId);
await this._loadTilesetFromIon(props._ionAccessToken, props._ionAssetId);
}

const {tileset3d} = this.state;
this._updateTileset(tileset3d);
await this._updateTileset(tileset3d);
}

async _loadTileset(tilesetUrl, fetchOptions, ionMetadata) {
let tileset3d = null;

const response = await fetch(tilesetUrl, fetchOptions);
const tilesetJson = await response.json();

tileset3d = new Tileset3D(tilesetJson, tilesetUrl, {
const tileset3d = new Tileset3D(tilesetJson, tilesetUrl, {
throttleRequests: true,
onTileLoad: tileHeader => {
this.props.onTileLoad(tileHeader);
this._updateTileset(tileset3d);
this.setNeedsUpdate();
},
onTileUnload: this.props.onTileUnload,
onTileLoadFail: this.props.onTileLoadFail,
// TODO: explicit passing should not be needed, registerLoaders should suffice
DracoLoader: this.props.DracoWorkerLoader || this.props.DracoLoader,
fetchOptions,
Expand All @@ -105,8 +103,7 @@ export default class Tile3DLayer extends CompositeLayer {

this.setState({
tileset3d,
layerMap: {},
layers: []
layerMap: {}
});

if (tileset3d) {
Expand All @@ -126,17 +123,18 @@ export default class Tile3DLayer extends CompositeLayer {
return;
}

const frameState = getFrameState(viewport, timeline);
// use Date.now() as frame identifier for now and later used to filter layers for rendering
const frameState = getFrameState(viewport, {frameNumber: Date.now()});
tileset3d.update(frameState);
this._updateLayerMap();
this._selectLayers(frameState.frameNumber);
this._updateLayerMap(frameState.frameNumber);
}

// `Layer` instances is created and added to the map if it doesn't exist yet.
_updateLayerMap() {
_updateLayerMap(frameNumber) {
const {tileset3d, layerMap} = this.state;
const {selectedTiles} = tileset3d;

// create layers for new tiles
const {selectedTiles} = tileset3d;
const tilesWithoutLayer = selectedTiles.filter(tile => !layerMap[tile.contentUri]);

for (const tile of tilesWithoutLayer) {
Expand All @@ -149,12 +147,14 @@ export default class Tile3DLayer extends CompositeLayer {
tile
};
}

// update layer visibility
this._selectLayers(frameNumber);
}

// Grab only those layers who were selected this frame.
_selectLayers(frameNumber) {
const {layerMap} = this.state;
const selectedLayers = [];
const layerMapValues = Object.values(layerMap);

for (const value of layerMapValues) {
Expand All @@ -167,7 +167,6 @@ export default class Tile3DLayer extends CompositeLayer {
layer = layer.clone({visible: true});
layerMap[tile.contentUri].layer = layer;
}
selectedLayers.push(layer);
} else if (tile.contentUnloaded) {
// Was cleaned up from tileset cache. We no longer need to track it.
delete layerMap[tile.contentUri];
Expand All @@ -178,7 +177,7 @@ export default class Tile3DLayer extends CompositeLayer {
}
}

this.setState({layers: selectedLayers});
this.setState({layers: Object.values(layerMap).map(layer => layer.layer)});
}

_create3DTileLayer(tileHeader) {
Expand All @@ -201,24 +200,30 @@ export default class Tile3DLayer extends CompositeLayer {
const {gltf} = tileHeader.userData;
const {instances, cartographicOrigin, modelMatrix} = tileHeader.content;

return new ScenegraphLayer({
id: `3d-model-tile-layer-${tileHeader.contentUri}`,
data: instances || [{}],
coordinateSystem: COORDINATE_SYSTEM.METER_OFFSETS,
coordinateOrigin: cartographicOrigin,

pickable: true,
scenegraph: gltf,
sizeScale: 1,
opacity: 1.0,
_lighting: 'pbr', // enable gltf pbr lighting model

// Fix for ScenegraphLayer.modelMatrix, under flag in deck 7.3 to avoid breaking existing code
_enableOffsetModelMatrix: true,
modelMatrix,
getTransformMatrix: instance => instance.modelMatrix,
getPosition: instance => [0, 0, 0]
});
const SubLayerClass = this.getSubLayerClass('scenegraph', ScenegraphLayer);

const {_lighting} = this.props;
return new SubLayerClass(
{
_lighting
},
this.getSubLayerProps({
id: 'scenegraph'
}),
{
id: `${this.id}-scenegraph-${tileHeader.contentUri}`,
// Fix for ScenegraphLayer.modelMatrix, under flag in deck 7.3 to avoid breaking existing code
data: instances || [{}],
scenegraph: gltf,

coordinateSystem: COORDINATE_SYSTEM.METER_OFFSETS,
coordinateOrigin: cartographicOrigin,
modelMatrix,
_enableOffsetModelMatrix: true,
getTransformMatrix: instance => instance.modelMatrix,
getPosition: instance => [0, 0, 0]
}
);
}

_createPointCloudTileLayer(tileHeader) {
Expand All @@ -231,10 +236,22 @@ export default class Tile3DLayer extends CompositeLayer {
} = tileHeader.content;
const {positions, normals, colors} = attributes;

return (
positions &&
new PointCloudLayer({
id: `3d-point-cloud-tile-layer-${tileHeader.contentUri}`,
if (!positions) {
return null;
}

const {getColor, pointSize} = this.props;
const SubLayerClass = this.getSubLayerClass('pointcloud', PointCloudLayer);

return new SubLayerClass(
{
pointSize
},
this.getSubLayerProps({
id: 'pointcloud'
}),
{
id: `${this.id}-pointcloud-${tileHeader.contentUri}`,
data: {
header: {
vertexCount: pointCount
Expand All @@ -249,18 +266,13 @@ export default class Tile3DLayer extends CompositeLayer {
coordinateOrigin: cartographicOrigin,
modelMatrix,

getColor: constantRGBA || this.props.color,
pickable: true,
numInstances: pointCount,
opacity: 1.0,
pointSize: 2
})
getColor: constantRGBA || getColor
}
);
}

renderLayers() {
const layerMapValues = Object.values(this.state.layerMap);
return layerMapValues.map(x => x.layer);
return this.state.layers;
}
}

Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -44,6 +44,7 @@
"@luma.gl/effects": "^7.3.0-alpha.8",
"@probe.gl/bench": "^3.1.0-beta.3",
"@probe.gl/test-utils": "^3.1.0-beta.3",
"@loaders.gl/polyfills": "1.3.0-beta.1",
"babel-loader": "^8.0.0",
"babel-plugin-inline-webgl-constants": "^1.0.1",
"babel-plugin-remove-glsl-comments": "^0.1.0",
Expand Down
1 change: 1 addition & 0 deletions test/modules/geo-layers/index.js
Expand Up @@ -44,3 +44,4 @@ import './s2-layer.spec';
import './trips-layer.spec';
import './great-circle-layer.spec';
import './h3-layers.spec';
import './tile-3d-layer';

0 comments on commit 56929a6

Please sign in to comment.