-
Notifications
You must be signed in to change notification settings - Fork 470
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
Changes from 11 commits
567ddcf
a3b0804
0dcb9a0
4cf46ee
877ffb9
32eeef4
3558daa
1d5040b
d627dcb
d161ccb
53481cb
eca2eff
61dbe26
dac1be0
57d4974
1b78e6c
21978df
a053922
662462f
e362488
ae362a2
fe8c394
06b1305
519f006
024a45e
16a9447
f46d4ad
6c0cfc9
ec3927a
e81a934
18dabad
702cbcc
9e84298
8ade7ba
05cc8bc
c362daf
d48c5b5
856ec21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# Feature Table | ||
|
||
## Contributors | ||
|
||
* Sean Lilley, [@lilleyse](https://twitter.com/lilleyse) | ||
* 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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
I guess in either padding case, this is still true. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 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. |
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 | ||
} | ||
} |
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 | ||
} | ||
} |
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" : { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If a property is an object, does it have to have a For example, if a tile format wants to define a Feature Table with a global semantic like
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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your example currently will fail since it doesn't have a There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
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"] | ||
} | ||
} | ||
} |
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": { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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" | ||
] | ||
}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
} | ||
] | ||
} |
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": { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
} | ||
] | ||
} |
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 | ||
} |
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", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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" : { | ||
|
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 | ||
} |
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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add
The order can be Sean, you, Dan, and me.
There was a problem hiding this comment.
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.