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

Feature Table Specification #118

merged 38 commits into from
Aug 26, 2016

Conversation

lasalvavida
Copy link
Contributor

@lasalvavida lasalvavida commented Aug 22, 2016

Feature Table specification document.


This may vary between implementations, but in javascript, a `TypedArray` cannot be created on data unless it is byte-aligned.
This means that 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 data types used in 3D Tiles have a maximum length of four bytes, so padding to a multiple of four will work for all cases, since smaller types with lengths of one and two will also be byte-aligned.
Copy link
Contributor

Choose a reason for hiding this comment

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

We support doubles too.

Copy link
Contributor

Choose a reason for hiding this comment

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

At least, maybe not yet but potentially.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, I'll make this less specific.

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 22, 2016

@lasalvavida @lilleyse when you open spec PRs, please include a link like https://github.com/lasalvavida/3d-tiles/tree/feature-table/TileFormats/FeatureTable


## 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.

@lilleyse
Copy link
Contributor

Check out my note here which may be relevant to this PR: #22 (comment)

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 22, 2016

Made some tweaks in 877ffb9

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 22, 2016

feature-table-layout.png

  • Change featureTableJSON to JSON header
  • Change featureTableBinary to binary body

feature-table-binary-index.png

  • Change featureTableJSON to JSON header
  • Change featureTableBinary to binary body

In the context of this spec, the featureTable prefix is not needed and not consistent with the spec's text.

Keep featureTableBinaryByteLength since I imagine that is from the tile's header (explicitly mention that in the text).

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 22, 2016

JSON Header

Include an complete-ish example like the tile format specs have.

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 22, 2016

Create a JSON schema for the JSON header. It should be pretty small, but we need to be precise, e.g., right now byteOffset isn't really defined well. What data type is it? Can it be negative? Is it required? To ensure consistent implementations, we need to be precise.

For JSON schema examples, see

Use JSON Schema 3. You will not be able to represent all requirements/relationships, but others can be put in the description and the spec's text.

Make the schema a subdirectory of this new directory and include a link to it from the spec.

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 22, 2016

Add reference to this in Pnts when #116 gets merged.

Merge in master and you can do this.


## 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.

@lasalvavida
Copy link
Contributor Author

lasalvavida commented Aug 22, 2016

@pjcozzi Is there a particular reason we are tied to v3 of the json-schema spec? I haven't found a way to define that POSITION is required unless POSITION_QUANTIZED is present and vice-versa in v3 of the spec, but it's pretty easy to do in v4 with the anyOf keyword. https://github.com/json-schema/json-schema/wiki/anyOf,-allOf,-oneOf,-not

featureTable.schema.json

{
    "$schema" : "http://json-schema.org/draft-04/schema",
    "title" : "featureTable",
    "type" : "object",
    "description" : "A set of tile-format-specific semantics defining behavior for each feature in a tile.",
    "patternProperties" : {
        ".*" : {
            "properties" : {
                "byteOffset" : {
                    "type" : "integer",
                    "minimum" : 0           
                }
            },
            "required" : ["byteOffset"]
        }
    }
}

i3dm.featureTable.schema.json

{
  "$schema": "http://json-schema.org/draft-04/schema",
  "title": "i3dm featureTable",
  "type": "object",
  "description": "A set of Instanced3DModel semantics defining behavior for each instance.",
  "extends": { "$ref" : "featureTable.schema.json" },
  "properties": {
    "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": {}
  },
  "anyOf" : [
    {
      "required": ["POSITION"]
    },
    {
      "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"
    ]
  },
  "additionalProperties" : false
}

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 22, 2016

@pjcozzi Is there a particular reason we are tied to v3 of the json-schema spec?

Tooling. There are more tools for v3 than v4, e.g., like this tool we wrote: https://github.com/AnalyticalGraphicsInc/wetzel

With that said, the v4 features look handy and we actually don't have that much JSON schema for 3D Tiles (we are definitely not updating glTF to v4 right now). If you want to update all of the 3D Tiles JSON schema to v4 right now, go for it, but please stay focused on the end goal of 3D Tiles and don't get too caught up in schema land. I have been there.

@lasalvavida
Copy link
Contributor Author

Sounds good to me. Changes should be pretty minimal for the schema we already have.

@lasalvavida
Copy link
Contributor Author

This should be ready for a look.

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 23, 2016

Made some tweaks in d161ccb.

"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.

"$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.

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 24, 2016

If we're going to explicitly forbid it, should the Cesium implementation throw an exception if the values are in the JSON?

The validator, CesiumGS/3d-tiles-validator#5, would do full validation. The runtime could just throw an exception if the semantic is not an object with a byteOffset.

Each semantic should also be explicit that it needs to be binary.

@lasalvavida
Copy link
Contributor Author

Updated

@@ -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.

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 25, 2016

Very nice, @lasalvavida.

@lilleyse can you do a final read and merge? That will also help you prep for the Batch Table spec.

@lasalvavida
Copy link
Contributor Author

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.

The schema has now been updated to reflect this.

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 25, 2016

The schema has now been updated to reflect this.

Nice!

@lilleyse
Copy link
Contributor

Everything looks good to me. This will be good to go after clarifying the byte alignment for the embedded glTF.

@lasalvavida
Copy link
Contributor Author

Made the edit, let me know what you think.

@lilleyse
Copy link
Contributor

Add a note that this is suggested to keep proper btye alignment for the embedded glTF for the b3dm and i3dm formats.

@lasalvavida
Copy link
Contributor Author

Updated

@lilleyse
Copy link
Contributor

Looks good to me, @pjcozzi do you want to do a quick read? Then I can merge.

@@ -70,4 +70,4 @@ In JavaScript, a `TypedArray` cannot be created on data unless it is byte-aligne
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.
The binary body should also be padded to a multiple of eight bytes. This ensures byte-alignment for the embedded glTF in Batched 3D Models and Instanced 3D Models.
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we sure about this? I thought the guarantees would be:

  • Typed arrays in the Feature Table's binary body are byte-aligned to the size of their component type, e.g., 4 bytes for
    float.
  • Typed arrays in the Batch Table's binary body are byte-aligned to the size of their component type, e.g., 4 bytes for float.
  • In b3dm and i3dm (put the wording in their specs), the Binary glTF is 8-byte aligned, so glTF's byte-alignment guarantees can be meet with respect to the tile's entire arraybuffer.

@lasalvavida
Copy link
Contributor Author

Updated. Is that better?

@lasalvavida
Copy link
Contributor Author

lasalvavida commented Aug 25, 2016

Actually I'm not sure about this now. For the i3dm it works fine since the header is 32 bytes. For batched it's only 20 right now. If you don't have a batch table to pad, how are you supposed to start it on a multiple of 8?

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 26, 2016

Actually I'm not sure about this now. For the i3dm it works fine since the header is 32 bytes. For batched it's only 20 right now. If you don't have a batch table to pad, how are you supposed to start it on a multiple of 8?

Good catch. I hate to say that the header (both b3dm and i3dm) need an explicit gltfOffset to allow "padding the header" (or really anything). @lilleyse do you have a better suggestion?

Also, on the implementation side, I would like to merge all breaking b3dm changes in one PR since b3dm is so widely used.

@lasalvavida
Copy link
Contributor Author

We could make it implicit that if there's no batch table, the glTF starts at the next multiple of 8 (24)

@lasalvavida
Copy link
Contributor Author

Or alternatively pad the beginning and read until you hit the glTF magic.

@lilleyse
Copy link
Contributor

Well the simplest thing to do right now is nothing since the b3dm header is about to change to 24 bytes.

@lasalvavida
Copy link
Contributor Author

Alrighty, then this is probably good to merge, unless anyone has anything else?

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 26, 2016

Nice, big progress here!

@pjcozzi pjcozzi merged commit 77ec38a into CesiumGS:master Aug 26, 2016
@pjcozzi pjcozzi deleted the feature-table branch August 26, 2016 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants