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 Table Specification #118

Merged
merged 38 commits into from
Aug 26, 2016
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
567ddcf
Added feature table spec
lasalvavida Aug 22, 2016
a3b0804
Fixed relative paths
lasalvavida Aug 22, 2016
0dcb9a0
Edit
lasalvavida Aug 22, 2016
4cf46ee
Added link to feature table specification
lasalvavida Aug 22, 2016
877ffb9
Tweaks
pjcozzi Aug 22, 2016
32eeef4
Merge branch 'master' of github.com:AnalyticalGraphicsInc/3d-tiles in…
lasalvavida Aug 22, 2016
3558daa
Initial commit of schema changes
lasalvavida Aug 23, 2016
1d5040b
Finalize v4 schema changes
lasalvavida Aug 23, 2016
d627dcb
Fix a grammatical error in tile.content schema
lasalvavida Aug 23, 2016
d161ccb
Tweaks
pjcozzi Aug 23, 2016
53481cb
Tweak description
pjcozzi Aug 23, 2016
eca2eff
Tweak description
pjcozzi Aug 23, 2016
61dbe26
Tweak description
pjcozzi Aug 23, 2016
dac1be0
Fix typo
pjcozzi Aug 23, 2016
57d4974
Merge branch 'master' of github.com:AnalyticalGraphicsInc/3d-tiles in…
lasalvavida Aug 23, 2016
1b78e6c
Merge branch 'feature-table' of github.com:lasalvavida/3d-tiles into …
lasalvavida Aug 23, 2016
21978df
Schema now contains targets for specific feature types
lasalvavida Aug 24, 2016
a053922
Added JSON schema README
lasalvavida Aug 24, 2016
662462f
Edits
lasalvavida Aug 24, 2016
e362488
Tweaks
pjcozzi Aug 24, 2016
ae362a2
Rename
pjcozzi Aug 24, 2016
fe8c394
Whitespace
pjcozzi Aug 24, 2016
06b1305
Edit validation instructions
pjcozzi Aug 24, 2016
519f006
Updated feature table schema
lasalvavida Aug 24, 2016
024a45e
Fix link
pjcozzi Aug 24, 2016
16a9447
Merge branch 'feature-table' of github.com:lasalvavida/3d-tiles into …
lasalvavida Aug 24, 2016
f46d4ad
Whitespace fix
lasalvavida Aug 24, 2016
6c0cfc9
Replace binaryReference with binaryBodyReference
lasalvavida Aug 24, 2016
ec3927a
Moved schema and examples out to global folders
lasalvavida Aug 24, 2016
e81a934
Fixed relative paths
lasalvavida Aug 24, 2016
18dabad
Missing periods
lasalvavida Aug 24, 2016
702cbcc
Per-feature properties for i3dm and pnts must be binary body references
lasalvavida Aug 25, 2016
9e84298
Only one type of bounding volume is allowed
lasalvavida Aug 25, 2016
8ade7ba
Made byte-alignment restriction more verbose
lasalvavida Aug 25, 2016
05cc8bc
Missed a dash
lasalvavida Aug 25, 2016
c362daf
Tweak
lasalvavida Aug 25, 2016
d48c5b5
Specify embedded
lasalvavida Aug 25, 2016
856ec21
Byte-alignment guarantee
lasalvavida Aug 25, 2016
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
71 changes: 71 additions & 0 deletions TileFormats/FeatureTable/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Feature Table

## Contributors

* Sean Lilley, [@lilleyse](https://twitter.com/lilleyse)
Copy link
Contributor

Choose a reason for hiding this comment

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

Add

Dan Bagnell, [@bagnell](https://github.com/bagnell)

The order can be Sean, you, Dan, and me.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'll make this change along with some other edits.

* Rob Taglang, [@lasalvavida](https://github.com/lasalvavida)
* Dan Bagnell, [@bagnell](https://github.com/bagnell)
* Patrick Cozzi, [@pjcozzi](https://twitter.com/pjcozzi)

## Overview

A _Feature Table_ describes position and appearance properties for each feature in a tile. The _Batch Table_ (TODO: link), on the other hand, contains per-feature application-specific metadata not necessarily used for rendering.

A Feature Table is used by the following tile formats:
* [Instanced 3D Model](../Instanced3DModel) (i3dm) - each model instance is a feature.
* [Point Cloud](../PointCloud) (pnts) - each point is a feature.
* [Vector](../VectorData) (vctr) - each point/polyline/polygon is a feature.

Per-feature properties are defined using tile-format-specific semantics defined in each tile format's specification. For example, in _Instanced 3D Model_, `SCALE_NON_UNIFORM` defines the non-uniform scale applied to each instance.

## Layout

A Feature Table is composed of two parts: a JSON header and an optional binary body. The JSON keys are tile-format-specific semantics, and the values can either be defined directly in the JSON, or refer to sections in the binary body.
The binary body is a binary buffer containing data referenced by the header. It is more efficient to store long numeric arrays in the binary body.

**Figure 1**: Feature Table layout

![feature table layout](figures/feature-table-layout.png)

When a tile format includes a Feature Table, the Feature Table immediately follows the header. The header will also contain `featureTableJSONByteLength` and `featureTableBinaryByteLength` `uint32` fields, which can be used to extract each respective part of the Feature Table.
Code for reading the Feature Table can be found in [Cesium3DTileFeatureTableResources.js](https://github.com/AnalyticalGraphicsInc/cesium/blob/3d-tiles/Source/Scene/Cesium3DTileFeatureTableResources.js) in the Cesium implementation of 3D Tiles.

## JSON Header

Feature Table values can be represented in the JSON header in three different ways.

1. A single JSON value. (e.g. `"INSTANCES_LENGTH" : 4`)
* This is common for global semantics like `"INSTANCES_LENGTH"`, which defines the number of model instances in an Instanced 3D Moel tile.
2. A JSON array of values. (e.g. `"POSITION" : [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]`)
* Feature values are always stored as a single, flat array, not an array of arrays. Above, each `POSITION` refers to a `float32[3]` data type so there are three features: `Feature 0's position`=`(1.0, 0.0, 0.0)`, `Feature 1's position`=`(0.0, 1.0, 0.0)`, `Feature 2's position`=`(0.0, 0.0, 1.0)`.
3. A reference to data in the binary body, denoted by an object with a `byteOffset` property. (e.g. `"SCALE" : { "byteOffset" : 24` } )
* `byteOffset` is a zero-based offset relative to the start of the binary body.

The only valid keys in the JSON header are the defined semantics by the tile format. Application-specific data should be stored in the Batch Table.

## Binary Body

When the JSON header includes a reference to the binary, the provided `byteOffset` is used to index into the data.

**Figure 2**: Indexing into the Feature Table binary body

![feature table binary index](figures/feature-table-binary-index.png)

Values can be retrieved using the number of features, `featuresLength`, the desired feature id, `featureId`, and the data type for the feature semantic.

For example, using the `POSITION` semantic, which has a `float32[3]` data type:

```javascript
var byteOffset = featureTableJSON.POSTION.byteOffset;

var positionArray = new Float32Array(featureTableBinary.buffer, byteOffset, featuresLength * 3); // There are three components for each POSITION feature.
var position = positionArray.subarray(featureId * 3, featureId * 3 + 3); // Using subarray creates a view into the array, and not a new array.
```

## Implementation Notes

In JavaScript, a `TypedArray` cannot be created on data unless it is byte-aligned to the data type.
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have to pad the JSON string as opposed to the start of the binary body?

I would like this spec to include language similar to this from b3dm:

The body section immediately follows the header section, and is composed of two fields: Batch Table and Binary glTF.

I guess in either padding case, this is still true.

Copy link
Contributor

Choose a reason for hiding this comment

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

Padding at the start of the binary body is not easily possible. When you add padding to the binary the byteOffset values in the JSON need to change, which then may extend the JSON length and breaks the alignment of the binary.

I believe this is the same reason why binary gltf appends whitespace to the JSON rather than padding the binary.

For example, a `Float32Array` must be stored in memory such that its data begins on a byte multiple of four since each `float` contains four bytes.

The string generated from the JSON header should be padded with space characters in order to ensure that the binary body is byte-aligned.
The binary body should also be padded if necessary when there is data following the Feature Table.
14 changes: 14 additions & 0 deletions TileFormats/FeatureTable/examples/i3dm.featureTable.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"INSTANCES_LENGTH" : 4,
"QUANTIZED_VOLUME_OFFSET" : [-250.0, 0.0, -250.0],
"QUANTIZED_VOLUME_SCALE" : [500.0, 0.0, 500.0],
"POSITION_QUANTIZED" : {
"byteOffset" : 0
},
"NORMAL_UP_OCT32P" : {
"byteOffset" : 24
},
"NORMAL_RIGHT_OCT32P" : {
"byteOffset" : 40
}
}
10 changes: 10 additions & 0 deletions TileFormats/FeatureTable/examples/pnts.featureTable.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"POINTS_LENGTH" : 4,
"RTC_CENTER" : [1215013.8, -4736316.7, 4081608.4],
"POSITION" : {
"byteOffset" : 0
},
"RGB" : {
"byteOffset" : 48
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
18 changes: 18 additions & 0 deletions TileFormats/FeatureTable/schema/featureTable.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema" : "http://json-schema.org/draft-04/schema#",
"id" : "featureTable.schema.json",
"title" : "Feature Table",
"type" : "object",
"description" : "A set of semantics containing per-tile and per-feature values defining the position and appearance properties for features in a tile.",
"patternProperties" : {
Copy link
Contributor

Choose a reason for hiding this comment

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

If a property is an object, does it have to have a byteOffset property?

For example, if a tile format wants to define a Feature Table with a global semantic like

"KEY" : {
   "some-property" : 0.0,
   "another-property" : [1, 2, 3]
}

Can it do so as the schema is written here? (It might, I just don't know v4).

I suggest that we let the schema be flexible (and note this in the Feature Table spec) and rely on each tile format to specifically scope what is valid. This will be forward-compatible as we and others add new tile formats.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Your example currently will fail since it doesn't have a byteOffset. Do you want to just make byteOffset optional?

Copy link
Contributor Author

@lasalvavida lasalvavida Aug 23, 2016

Choose a reason for hiding this comment

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

To elaborate, a semantic value is currently defined as either an object with a byteOffset referencing the binary, an array, or a single value, and I think we currently forbid using semantics not defined for a tile format, so if it is an object, I think you should always have a byteOffset.

Copy link
Contributor

Choose a reason for hiding this comment

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

I read that in the spec, but this schema doesn't, for example, explicitly disallow strings.

I would make the schema for the generic Feature Table as generic as possible. Basically all we can say is that if a key is an object, and that object has a byteOffset property, then byteOffset should be:

"type" : "integer",
"minimum" : 0

Then let each tile format specifically scope what is valid for its Feature Table. This is no more work for an implementation with our current tile formats, and allows future tile formats maximum flexibility to define their data structures.

".*" : {
"properties" : {
"byteOffset" : {
"type" : "integer",
"minimum" : 0
}
},
"required" : ["byteOffset"]
}
}
}
62 changes: 62 additions & 0 deletions TileFormats/FeatureTable/schema/i3dm.featureTable.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"$schema" : "http://json-schema.org/draft-04/schema#",
"id" : "i3dm.featureTable.schema.json",
"title" : "Instanced 3D Model Feature Table",
"type" : "object",
"description": "A set of Instanced 3D Model semantics containing per-tile and per-point values that define where and how to render instanced models.",
"allOf" : [
{
"$ref" : "featureTable.schema.json"
},
{
"properties": {
Copy link
Contributor

Choose a reason for hiding this comment

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

Each of these need to define the value values, e.g., is it a scalar or an array, min/max, etc.

"POSITION": {},
"POSITION_QUANTIZED": {},
"NORMAL_UP": {},
"NORMAL_RIGHT": {},
"NORMAL_UP_OCT32P": {},
"NORMAL_RIGHT_OCT32P": {},
"SCALE": {},
"SCALE_NON_UNIFORM": {},
"BATCH_ID": {},
"INSTANCES_LENGTH": {},
"QUANTIZED_VOLUME_OFFSET": {},
"QUANTIZED_VOLUME_SCALE": {}
},
"oneOf": [
{
"required": [
"POSITION"
]
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor whitespace here and throughout (but will save a level of indent), change lines like this to:

}, {

And above and throughout, can be like

[{

which are both what we do in JavaScript.

{
"required": [
"POSITION_QUANTIZED"
]
}
],
"dependencies": {
"POSITION_QUANTIZED": [
"QUANTIZED_VOLUME_OFFSET",
"QUANTIZED_VOLUME_SCALE"
],
"NORMAL_UP": [
"NORMAL_RIGHT"
],
"NORMAL_RIGHT": [
"NORMAL_UP"
],
"NORMAL_UP_OCT32P": [
"NORMAL_RIGHT_OCT32P"
],
"NORMAL_RIGHT_OCT32P": [
"NORMAL_UP_OCT32P"
]
},
"required": [
"INSTANCES_LENGTH"
],
"additionalProperties": false
}
]
}
49 changes: 49 additions & 0 deletions TileFormats/FeatureTable/schema/pnts.featureTable.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"$schema" : "http://json-schema.org/draft-04/schema#",
"id" : "pnts.featureTable.schema.json",
"title" : "Point Cloud Feature Table",
"type" : "object",
"description" : "A set of Point Cloud semantics containing per-tile and per-point values that define where and how to render points.",
"allOf" : [
{
"$ref" : "featureTable.schema.json"
},
{
"properties": {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment.

"POSITION": {},
"POSITION_QUANTIZED": {},
"RGBA": {},
"RGB": {},
"NORMAL": {},
"NORMAL_OCT16P": {},
"POINTS_LENGTH": {},
"RTC_CENTER": {},
"QUANTIZED_VOLUME_OFFSET": {},
"QUANTIZED_VOLUME_SCALE": {},
"CONSTANT_RGBA": {}
},
"anyOf": [
{
"required": [
"POSITION"
]
},
{
"required": [
"POSITION_QUANTIZED"
]
}
],
"dependencies": {
"POSITION_QUANTIZED": [
"QUANTIZED_VOLUME_OFFSET",
"QUANTIZED_VOLUME_SCALE"
]
},
"required": [
"POINTS_LENGTH"
],
"additionalProperties": false
}
]
}
2 changes: 1 addition & 1 deletion TileFormats/Instanced3DModel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ in the Cesium implementation of 3D Tiles.
## Feature Table

Contains values for `i3dm` semantics used to create instanced models.
[//]: # "TODO: Change this link to the feature table specification URL"
More information is available in the [Feature Table specification](../FeatureTable).

### Semantics

Expand Down
1 change: 1 addition & 0 deletions TileFormats/PointCloud/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Code for reading the header can be found in [Points3DModelTileContent.js](https:
## Feature Table

Contains per-tile and per-point values that define where and how to render points.
More information is available in the [Feature Table specification](../FeatureTable).

### Semantics

Expand Down
9 changes: 5 additions & 4 deletions schema/asset.schema.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
{
"$schema" : "http://json-schema.org/draft-03/schema",
"title" : "asset",
"$schema" : "http://json-schema.org/draft-04/schema",
"id" : "asset.schema.json",
"title" : "Asset",
"type" : "object",
"description" : "Metadata about the entire tileset.",
"properties" : {
"version" : {
"type" : "string",
"description" : "The 3D Tiles version. The version defines the JSON schema for tileset.json and the base set of tile formats.",
"required" : true
"description" : "The 3D Tiles version. The version defines the JSON schema for tileset.json and the base set of tile formats."
},
"tilesetVersion" : {
"type" : "string",
"description" : "Application-specific version of this tileset, e.g., for when an existing tileset is updated."
}
},
"required" : ["version"],
"additionalProperties" : false
}
5 changes: 3 additions & 2 deletions schema/boundingVolume.schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"$schema" : "http://json-schema.org/draft-03/schema",
"title" : "boundingVolume",
"$schema" : "http://json-schema.org/draft-04/schema",
Copy link
Contributor

Choose a reason for hiding this comment

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

In JSON schema v4, is there a way to say that only one of the three properties below can be present? I changed this in #123.

"id" : "boundingVolume.schema.json",
"title" : "Bounding Volume",
"type" : "object",
"description" : "A bounding volume that encloses a tile or its contents. At least one property is required. If more than one property is defined, the runtime can determine which to use.",
"properties" : {
Expand Down
12 changes: 6 additions & 6 deletions schema/properties.schema.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
{
"$schema" : "http://json-schema.org/draft-03/schema",
"title" : "properties",
"$schema" : "http://json-schema.org/draft-04/schema",
"id" : "properties.schema.json",
"title" : "Properties",
"type" : "object",
"description" : "A dictionary object of metadata about per-feature properties.",
"properties" : {
"maximum" : {
"type" : "number",
"description" : "The maximum value of this property of all the features in the tileset.",
"required" : true
"description" : "The maximum value of this property of all the features in the tileset."
},
"minimum" : {
"type" : "number",
"description" : "The minimum value of this property of all the features in the tileset.",
"required" : true
"description" : "The minimum value of this property of all the features in the tileset."
}
},
"required" : ["maximum", "minimum"],
"additionalProperties" : false
}
13 changes: 7 additions & 6 deletions schema/tile.content.schema.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
{
"$schema" : "http://json-schema.org/draft-03/schema",
"title" : "content",
"$schema" : "http://json-schema.org/draft-04/schema",
"id" : "tile.content.schema.json",
"title" : "Tile Content",
"type" : "object",
"description" : "Metadata about the tile's content and a link to the content.",
"properties" : {
"boundingVolume" : {
"extends" : { "$ref" : "boundingVolume.schema.json" },
"description" : "An optional bounding volume that tightly enclosing just the tile's contents. This is used for replacement refinement; tile.boundingVolume provides spatial coherence and tile.content.boundingVolume enables tight view frustum culling. When this is omitted, tile.boundingVolume is used."
"description" : "An optional bounding volume that tightly encloses just the tile's contents. This is used for replacement refinement; tile.boundingVolume provides spatial coherence and tile.content.boundingVolume enables tight view frustum culling. When this is omitted, tile.boundingVolume is used.",
"$ref" : "boundingVolume.schema.json"
},
"url" : {
"type" : "string",
"description" : "A string that points to the tile's contents with an absolute or relative url. When the url is relative, it is relative to the referring tileset.json. The file extension of content.url defines the tile format. The core 3D Tiles spec supports the following tile formats: Batched 3D Model (*.b3dm), Instanced 3D Model (*.i3dm), Composite (*.cmpt), and 3D Tiles TileSet (*.json)",
"required" : true
"description" : "A string that points to the tile's contents with an absolute or relative url. When the url is relative, it is relative to the referring tileset.json. The file extension of content.url defines the tile format. The core 3D Tiles spec supports the following tile formats: Batched 3D Model (*.b3dm), Instanced 3D Model (*.i3dm), Composite (*.cmpt), and 3D Tiles TileSet (*.json)"
}
},
"required" : ["url"],
"additionalProperties" : false
}
16 changes: 8 additions & 8 deletions schema/tile.schema.json
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
{
"$schema" : "http://json-schema.org/draft-03/schema",
"title" : "tile",
"$schema" : "http://json-schema.org/draft-04/schema",
"id" : "tile.schema.json",
"title" : "Tile",
"type" : "object",
"description" : "A tile in a 3D Tiles tileset.",
"properties" : {
"boundingVolume" : {
"extends" : { "$ref" : "boundingVolume.schema.json" },
"description" : "The bounding volume that encloses the tile.",
"required" : true
"$ref" : "boundingVolume.schema.json"
},
"geometricError" : {
"type" : "number",
"description" : "The error, in meters, introduced if this tile is rendered and its children are not. At runtime, the geometric error is used to compute Screen-Space Error (SSE), i.e., the error measured in pixels.",
"minimum" : 0,
"required" : true
"minimum" : 0
},
"refine" : {
"type" : "string",
"description" : "Specifies if additive or replacement refinement is used when traversing the tileset for rendering. This property is required for the root tile of a tileset; it is optional for all other tiles. The default is to inherit from the parent tile.",
"enum" : ["add", "replace"]
},
"content" : {
"extends" : { "$ref" : "tile.content.schema.json" },
"description" : "Metadata about the tile's content and a link to the content. When this is omitted the tile is just used for culling. This is required for leaf tiles."
"description" : "Metadata about the tile's content and a link to the content. When this is omitted the tile is just used for culling. This is required for leaf tiles.",
"$ref" : "tile.content.schema.json"
},
"children" : {
"type" : "array",
Expand All @@ -33,5 +32,6 @@
"uniqueItems" : true
}
},
"required" : ["boundingVolume", "geometricError"],
"additionalProperties" : false
}
Loading