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

Instanced 3D Model spec #34

Merged
merged 14 commits into from
Nov 8, 2015
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Topic | Status
[Batched 3D Model](b3dm/README.md) (b3dm) | :white_check_mark: **Solid base**, only minor changes expected
[Point Cloud](pnts/README.md) (pnts) | :rocket: **Prototype**, needs compression and additional attributes
[Composite](TileFormats/Composite/README.md) (cmpt) | :white_check_mark: **Solid base**, only minor changes expected
[Instanced 3D Model](TileFormats/Instanced3DModel/README.md) (i3dm) | :white_circle: **In progress**, [#23](https://github.com/AnalyticalGraphicsInc/3d-tiles/issues/23)
[Instanced 3D Model](TileFormats/Instanced3DModel/README.md) (i3dm) | :rocket: **Prototype**, needs optimizations, [#33](https://github.com/AnalyticalGraphicsInc/3d-tiles/issues/33)
[Vector Data](TileFormats/VectorData/README.md) | :white_circle: **In progress**, [#25](https://github.com/AnalyticalGraphicsInc/3d-tiles/issues/25)
[OpenStreetMap](TileFormats/OpenStreetMap/README.md) | :white_circle: **Not started**
[Massive Model](TileFormats/MassiveModel/README.md) | :white_circle: **Not started**
Expand Down
116 changes: 108 additions & 8 deletions TileFormats/Instanced3DModel/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,113 @@
# Instanced 3D Model

## Notes
## Contributors

**Use cases**: Trees, fire hydrants, sewer caps, lamps, traffic lights, etc.
* Sean Lilley, [@lilleyse](https://twitter.com/lilleyse)
* Patrick Cozzi, [@pjcozzi](https://twitter.com/pjcozzi)

**Format**
* Pointers to one or more internal or external (to share across tiles) glTF models. More than one model could also be handled with a `Composite` tile, should only that be supported?
* Per-instance properties, e.g., position/translation, scale, rotation, and user-defined properties like `Batched 3D Models`.
* Like `Batched 3D Model`, this needs to support per-instance metadata (and runtime interaction).
* If it makes sense for glTF itself to support instancing, perhaps through an extension, is this tile format needed?
## Overview

**Cesium implementation**: can prototype something with separate `Model` instances, but it will be slow. Instead, add support for [ANGLE_instanced_arrays](https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/) to the Renderer, and then render glTF models with true instancing.
_Instanced 3D Model_ is a tile format for efficient streaming and rendering of a large number of models, called _instances_, with slight variations. In the simplest case, the same tree model, for example, may be located - or _instanced_ - in several places. Each instance references the same model, and has per-instance properties, such as position.

In addition to trees, Instanced 3D Model is useful for fire hydrants, sewer caps, lamps, traffic lights, etc.

A Composite tile can be used to create tiles with different types of instanced models, e.g., trees and traffic lights.

Instanced 3D Model maps well to the [ANGLE_instanced_arrays](https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/) extension for efficient rendering with WebGL.

## Layout

A tile is composed of a header immediately followed by a body.

**Figure 1**: Instanced 3D Model layout (dashes indicate optional sections).

![](figures/layout.png)

## Header

The 28-byte header contains:

* `magic` - 4-byte ANSI string `i3dm`. This can be used to identify the arraybuffer as an Instanced 3D Model tile.
* `version` - `uint32`, which contains the version of the Instanced 3D Model format. It is currently `1`.
* `byteLength` - `uint32`, which contains the length of the entire tile, including the header, in bytes.
* `batchTableLength` - `uint32`, which contains the length of the batch table. This must be greater than or equal to zero. Zero indicates there is not a batch table.
* `glTFLength` - `uint32`, which contains the length of glTF field in bytes. This must be greater than or equal to zero.
* `glTFFormat` - `uint32`, which indicates the format of the glTF field of the body. `0` indicates it is a uri, `1` indicates it is embedded binary glTF. See the glTF section below.
* `instancesLength` - `uint32`, which contains the number of instances. This must be greater than or equal to zero.

_TODO: code example reading header_

If either `glTFLength` or `instancesLength` equal zero, the tile does not need to be rendered.

The body immediately follows the header, and is composed of three fields: `Batch Table`, `glTF`, and `instances`.

## Batch Table

_TODO: create a separate Batch Table spec that b3dm, i3dm, etc. can reference?_

The batch table is a `UTF-8` string containing JSON. It immediately follows the header. It can be extracted from the arraybuffer using the `TextDecoder` JavaScript API and transformed to a JavaScript object with `JSON.parse`.

Each property in the object is an array with its length equal to the number of instances in the tile. Each array is a homogeneous collection of `String`, `Number`, or `Boolean` elements. Elements may be `null`.

An instance's `batchId` is used to access elements in each array and extract the corresponding properties. For example, the following batch table has properties for two instances:
```json
{
"id" : ["unique id", "another unique id"],
"displayName" : ["Tree species", "Another tree species"],
"yearPlanted" : [1999, 2003]
}
```

The properties for the instance with `batchId = 0` are
```javascript
id[0] = 'unique id';
displayName[0] = 'Tree species';
yearBuilt[0] = 1999;
```

The properties for `batchId = 1` are
```javascript
id[1] = 'another unique id';
displayName[1] = 'Another tree species';
yearBuilt[1] = 2003;
```

## glTF

The glTF field immediately follows the batch table (or immediately follows the header, if `header.batchTableLength` is zero).

[glTF](https://www.khronos.org/gltf) is the runtime asset format for WebGL. [Binary glTF](https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_binary_glTF) is an extension defining a binary container for glTF. Instanced 3D Model uses glTF 1.0 with the [KHR_binary_glTF](https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_binary_glTF) extension.

`header.glTFFormat` determines the format of the glTF field. When it is `0`, the glTF field is

* a UTF-8 string, which contains a uri to a glTF model.

When the value of `header.glTFFormat` is `1`, the glTF field is

* a binary blob containing binary glTF.

In either case, `header.glTFLength` contains the length of the glTF field in bytes.

## Instances

The `instances` field immediately follows the `glTF` field (which may be omitted when `header.glTFLength` is `0`).

The `instances` field contains `header.instancesLength` tightly packed instances. Each instance has three fields:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a word missing here? I couldn't make sense of "contains header.instancesLength tightly packed instances"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A word is not missing. That should read as "the instances field contains x tightly packed instances" where the value of "x" is defined by header.instancesLength.

If you think we could make it more clear, please have at it.


* `longitude` - `double`, the longitude, in radians, in the range `[-PI, PI]`.
* `latitude` - `double`, the latitude, in radians, in the range `[-PI / 2, PI / 2]`.
* `batchId` - `uint32` in the range `[0, header.batchTableLength)`, which indicates the corresponding properties.

_TODO: make this much more memory efficient and more general._

Each instance is in the east-north-up reference frame (`x` points east, `y` points north, and `z` points along the geodetic surface normal).

## File Extension

`.i3dm`

## MIME Type

_TODO_

`application/octet-stream`
Binary file added TileFormats/Instanced3DModel/figures/Figures.pptx
Binary file not shown.
Binary file added TileFormats/Instanced3DModel/figures/layout.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 3 additions & 5 deletions b3dm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The 16-byte header contains:
* `magic` - 4-byte ANSI string `b3dm`. This can be used to identify the arraybuffer as a Batched 3D Model tile.
* `version` - `uint32`, which contains the version of the Batched 3D Model format. It is currently `1`.
* `byteLength` - `uint32`, the length of the entire tile, including the header, in bytes.
* `batchTableLength` - `uint32`, which contains the length of the batch table. It may be zero indicating there is not a batch table.
* `batchTableLength` - `uint32`, which contains the length of the batch table. This must be greater than or equal to zero. Zero indicates there is not a batch table.

_TODO: code example reading header_

Expand All @@ -36,7 +36,7 @@ In the Binary glTF section, each vertex has an unsigned short `batchId` attribut

The batch table maps each `batchId` to per-model properties. If present, the batch table immediately follows the header and is `batchTableLength` bytes long.

The batch table is a `UTF-8` string containing JSON. It can be extracted from the arraybuffer using the `TextDecoder` JavaScript API and transformed to a JavaScript object with `JSON.parse`.
The batch table is a `UTF-8` string containing JSON. It immediately follows the header. It can be extracted from the arraybuffer using the `TextDecoder` JavaScript API and transformed to a JavaScript object with `JSON.parse`.

Each property in the object is an array with its length equal to the number of models in the batch. Each array is a homogeneous collection of `String`, `Number`, or `Boolean` elements. Elements may be `null`.

Expand Down Expand Up @@ -65,9 +65,7 @@ yearBuilt[1] = 2015;

## Binary glTF

[glTF](https://www.khronos.org/gltf) is the runtime asset format for WebGL. [Binary glTF](https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_binary_glTF) is an extension defining a binary container for glTF.

Batched 3D Model uses glTF 1.0 with the [KHR_binary_glTF](https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_binary_glTF) extension.
[glTF](https://www.khronos.org/gltf) is the runtime asset format for WebGL. [Binary glTF](https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_binary_glTF) is an extension defining a binary container for glTF. Batched 3D Model uses glTF 1.0 with the [KHR_binary_glTF](https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_binary_glTF) extension.

Binary glTF immediately follows the batch table. It begins `12 + batchTableLength` bytes from the start of the arraybuffer and continues for the rest of arraybuffer. It may embed all of its geometry, texture, and animations, or it may refer to external sources for some or all of these data.

Expand Down