<NME> meshes.md
<BEF> # Mesh representation of segmented object surfaces

If the `"mesh"` property is specified in the `info` JSON file for a `"segmentation"` volume, then a
triangular mesh representation of the surface of some or all segmented objects may be specified.
Each segmented object should correspond to a set of objects with the same non-zero integer label
value specified in the volume.

There are two supported mesh formats: a [multi-resolution mesh
format](#multi-resolution-mesh-format) in which each segmented object is represented at multiple
levels of detail using a octree decomposition, and a [legacy single-resolution
format](#legacy-single-resolution-mesh-format).

## Multi-resolution mesh format

The multi-resolution object surface meshes corresponding to a segmentation are represented as a
directory tree containing the following data:

- `info` file in JSON format specifying the
  [metadata](#multi-resolution-mesh-info-json-file-format).
- For each segment ID for which there is a mesh representation:
  - a ["manifest" file](#multi-resolution-mesh-manifest-file-format) that specifies the levels of
    detail and octree decomposition for the object;
  - a [mesh fragment data file](#multi-resolution-mesh-fragment-data-file-format) specifying an
    encoded mesh representation corresponding to each octree node.

The actual storage of the manifest and mesh fragment data depends on whether the unsharded or
[sharded](./sharded.md) format is used.

### Multi-resolution mesh info JSON file format

The `info` file is a JSON-format text file.  The root value must be a JSON object with the following
members:
- `"@type"`: Must be `"neuroglancer_multilod_draco"`.
- `"vertex_quantization_bits"`: Specifies the number of bits needed to represent each vertex
  position coordinate within a mesh fragment.  Must be `10` or `16`.
- `"transform"`: JSON array of 12 numbers specifying a 4x3 homogeneous coordinate transform from the
  "stored model" coordinate space to a "model" coordinate space.
- `"lod_scale_multiplier"`: Factor by which the `lod_scales` values in each `<segment-id>.index`
  file are multiplied.
- `"sharding"`: If specified, indicates that the mesh is stored using the [sharded
    format](./sharded.md).  Must be a [sharding specification](./sharded.md#sharding-specification).  If not
    specified, the unsharded storage representation is used.
- `"segment_properties"`: Optional.  If specified, it must be a string value specifying the name of
  the subdirectory containing a [segment properties](./segment_properties.md) representation.  Note
  that Neuroglancer only uses these segment properties if this mesh source is specified as a data
  source directly.  If it is specified indirectly via the `"mesh"` property in a [multi-scale
  volume](./volume.md), then you must instead specify the properties using use the
  `"segment_properties"` member in the volume's `info` file.

### Multi-resolution mesh manifest file format

For each segment ID for which there is a mesh representation, there is a binary "manifest" file in
the following format:
- `lod_scales`: `num_lods` float32le, specifies the scale in "stored model" spatial units
  corresponding to each level of detail.  Each scale value is multiplied by the
  `lod_scale_multiplier` value from the `info` JSON file.
- `vertex_offsets`: `num_lods*3` float32le, as a C order `[vertex_offsets, 3]` array specifying an
  offset (in the "stored model" coordinate space) to add to vertex positions for each level of
  detail.
- `num_fragments_per_lod`: `num_lods` uint32le, specifies the number of fragments (octree nodes) for
  corresponding to each level of detail.  Each scale value is multiplied by the
  `lod_scale_multiplier` value from the `info` JSON file.
- `vertex_offsets`: `num_lods*3` float32le, as a C order `[num_lods, 3]` array specifying an
  offset (in the "stored model" coordinate space) to add to vertex positions for each level of
  detail.
- `num_fragments_per_lod`: `num_lods` uint32le, specifies the number of fragments (octree nodes) for
  each level of detail.
- For each `lod` in the range `[0, num_lods)`:
  - `fragment_positions`: `num_fragments_per_lod[lod]*3` uint32le, C order `[3,
    numFragments_per_lod[lod]]` array specifying the `x`, `y`, and `z` coordinates of the octree
    nodes for the given `lod`.  The node positions must be in `x`, `y`, `z` Z-curve order.  The node
    corresponds to the axis-aligned bounding box within the "stored model" coordinate space with an
    origin of: `grid_origin + [x, y, z] * chunk_shape * (2**lod)` and a shape of `chunk_shape *
    (2**lod)`.
  - `fragment_offsets`: `num_fragments_per_lod[lod]` uint32le, specifies the size in bytes of the
    encoded mesh fragment in the [mesh fragment data
    file](#multi-resolution-mesh-fragment-data-file-format) corresponding to each octree node in the
    `fragment_positions` array.  The starting offset of the encoded mesh data corresponding to a
    given octree node is equal to the sum of all prior `fragment_offsets` values.
    
#### Unsharded storage of multi-resolution mesh manifest
    
If the unsharded format is used, the manifest for each segment is stored as a separate file within
the same directory as the `info` file under the name `<segment-id>.index`, where `<segment-id>` is
the base-10 string representation of the segment ID.

#### Sharded storage of multi-resolution mesh manifest

nodes specified in the manifest file, in the same order the nodes are specified in the index file,
starting with `lod` 0.  Each mesh fragment is a [Draco](https://google.github.io/draco/)-encoded
triangular mesh with a 3-component integer vertex position attribute.  Each position component `j`
must be in the range `[0, 2**vertex_quantization_bits)`, where a value of `x` corresponds to
`grid_origin[i] + chunk_shape[i] * (fragmentPosition[i] + x / (2**vertex_quantization_bits-1)) * (2**lod)`.  The
built-in Draco attribute quantization is not supported.

Each mesh fragment for `lod > 0` must be partitioned by a `2x2x2` grid such that no triangle crosses
a grid boundary (but may be incident to a grid boundary).
```

The built-in Draco attribute quantization is not supported.

Each mesh fragment for `lod > 0` must be partitioned by a `2x2x2` grid such that no triangle crosses
a grid boundary (but may be incident to a grid boundary).

#### Unsharded storage of multi-resolution mesh fragment data

If the unsharded format is used, the mesh mesh fragment data file is stored as a separate file
within the same directory as the `info` file under the name `<segment-id>`, where `<segment-id>` is
the base-10 string representation of the segment ID.  The HTTP server must support HTTP `Range`
requests for these files in order to allow individual fragment meshes to be retrieved.

#### Sharded storage of multi-resolution mesh fragment data

If the [sharded format](./sharded.md#sharded-format) is used, the mesh fragment data file is located immediately
before the manifest file in the same shard data file.  The starting offset within that shard data
file is not specified explicitly but may be computed from the starting offset of the manifest file
and the sum of the mesh fragment sizes specified in the manifest.

## Legacy single-resolution mesh format

In addition to the multi-resolution mesh format, an older single-resolution mesh format is also
supported.  This format is specified by either the absence of an `info` file in the mesh
subdirectory or an `info` file containing a JSON object with the following members:
- `"@type"`: Must be `"neuroglancer_legacy_mesh"`.

To specify a legacy single-resolution mesh dataset that lacks an `info` file as a Neuroglancer data
source, use the data source URL syntax `precomputed://FILE_URL#type=mesh`, where `FILE_URL` is the
URL to the directory containing the mesh data using any [supported file
protocol](../file_protocols.md).

The surface mesh representation for a given segmented object may be split into one or more separate
fragments (e.g. corresponding to subvolumes).

Within the mesh subdirectory, for each segmented object for which a surface representation is
available, there is a JSON-format metadata file named `<segment-id>:0`, where `<segment-id>` is
substituted with the base-10 string representation of the segment label value.  This metadata file
must contain an object with a `"fragments"` property specifying the filenames (relative to the mesh
subdirectory) containing the mesh data for each fragment.

This legacy mesh format does not support a [sharded storage representation](./sharded.md#sharded-format).

Each fragment file is specified in the following binary format:
- The file begins with a little-endian 32-bit unsigned integer `num_vertices` specifying the number
  of vertices.
- The `[x, y, z]` vertex positions (as nanometer offsets within the global coordinate frame) are
  stored as little-endian single precision/binary32 floating point values starting at an offset of
  `4` bytes from the start of the file (immediately after the `num_vertices` value) and ending at a
  byte offset of `4 + 4 * 3 * num_vertices`.  The x, y, and z components of the vertex positions are
  interleaved, i.e. `[x0, y0, z0, x1, y1, z1, ...]`.
- The number of triangles is inferred as the number of remaining bytes in the file after the vertex
  position data divided by 12 (the number of remaining bytes must be a multiple of 12).  The
  triangles are specified as an array of interleaved triplets `[a, b, c]` of vertex indices.  The
  vertex indices are encoded as little-endian 32-bit unsigned integers.

<MSG> docs(datasource/precomputed): further clarify mesh vertex interpretation

<DFF> @@ -54,7 +54,7 @@ the following format:
 - `lod_scales`: `num_lods` float32le, specifies the scale in "stored model" spatial units
   corresponding to each level of detail.  Each scale value is multiplied by the
   `lod_scale_multiplier` value from the `info` JSON file.
-- `vertex_offsets`: `num_lods*3` float32le, as a C order `[vertex_offsets, 3]` array specifying an
+- `vertex_offsets`: `num_lods*3` float32le, as a C order `[num_lods, 3]` array specifying an
   offset (in the "stored model" coordinate space) to add to vertex positions for each level of
   detail.
 - `num_fragments_per_lod`: `num_lods` uint32le, specifies the number of fragments (octree nodes) for
@@ -89,9 +89,17 @@ The mesh fragment data files consist of the concatenation of the encoded mesh da
 nodes specified in the manifest file, in the same order the nodes are specified in the index file,
 starting with `lod` 0.  Each mesh fragment is a [Draco](https://google.github.io/draco/)-encoded
 triangular mesh with a 3-component integer vertex position attribute.  Each position component `j`
-must be in the range `[0, 2**vertex_quantization_bits)`, where a value of `x` corresponds to
-`grid_origin[i] + chunk_shape[i] * (fragmentPosition[i] + x / (2**vertex_quantization_bits-1)) * (2**lod)`.  The
-built-in Draco attribute quantization is not supported.
+must be a value `x` in the range `[0, 2**vertex_quantization_bits)`, which corresponds to a "stored
+model" coordinate of:
+
+```
+grid_origin[j] +
+vertex_offsets[lod,j] +
+chunk_shape[j] * (2**lod) * (fragmentPosition[j] +
+                             x / ((2**vertex_quantization_bits)-1))
+```
+
+The built-in Draco attribute quantization is not supported.
 
 Each mesh fragment for `lod > 0` must be partitioned by a `2x2x2` grid such that no triangle crosses
 a grid boundary (but may be incident to a grid boundary).

{'commit': 'diff --git a/src/neuroglancer/datasource/precomputed/meshes.md b/src/neuroglancer/datasource/precomputed/meshes.md\nindex ba7286b..d6f82c0 100644\n--- a/src/neuroglancer/datasource/precomputed/meshes.md\n+++ b/src/neuroglancer/datasource/precomputed/meshes.md\n@@ -54,7 +54,7 @@ the following format:\n - `lod_scales`: `num_lods` float32le, specifies the scale in "stored model" spatial units\n   corresponding to each level of detail.  Each scale value is multiplied by the\n   `lod_scale_multiplier` value from the `info` JSON file.\n-- `vertex_offsets`: `num_lods*3` float32le, as a C order `[vertex_offsets, 3]` array specifying an\n+- `vertex_offsets`: `num_lods*3` float32le, as a C order `[num_lods, 3]` array specifying an\n   offset (in the "stored model" coordinate space) to add to vertex positions for each level of\n   detail.\n - `num_fragments_per_lod`: `num_lods` uint32le, specifies the number of fragments (octree nodes) for\n@@ -89,9 +89,17 @@ The mesh fragment data files consist of the concatenation of the encoded mesh da\n nodes specified in the manifest file, in the same order the nodes are specified in the index file,\n starting with `lod` 0.  Each mesh fragment is a [Draco](https://google.github.io/draco/)-encoded\n triangular mesh with a 3-component integer vertex position attribute.  Each position component `j`\n-must be in the range `[0, 2**vertex_quantization_bits)`, where a value of `x` corresponds to\n-`grid_origin[i] + chunk_shape[i] * (fragmentPosition[i] + x / (2**vertex_quantization_bits-1)) * (2**lod)`.  The\n-built-in Draco attribute quantization is not supported.\n+must be a value `x` in the range `[0, 2**vertex_quantization_bits)`, which corresponds to a "stored\n+model" coordinate of:\n+\n+```\n+grid_origin[j] +\n+vertex_offsets[lod,j] +\n+chunk_shape[j] * (2**lod) * (fragmentPosition[j] +\n+                             x / ((2**vertex_quantization_bits)-1))\n+```\n+\n+The built-in Draco attribute quantization is not supported.\n \n Each mesh fragment for `lod > 0` must be partitioned by a `2x2x2` grid such that no triangle crosses\n a grid boundary (but may be incident to a grid boundary).\n', 'commit_subject': 'docs(datasource/precomputed): further clarify mesh vertex interpretation', 'repo_name': 'google/neuroglancer', 'committer': {'name': 'Jeremy Maitin-Shepard', 'email': 'e349c33eb9031b46b70f51528427a078cdb06294@google.com', 'time_sec': '1588963547', 'tz_offset': '-420', 'date': {'seconds': '1588963547'}}, 'commit_tree': '1abcca2ce4499846b01c179d4705bbf1187f5d81', 'commit_message': 'docs(datasource/precomputed): further clarify mesh vertex interpretation\n', 'language_name': 'TypeScript', 'license': 'apache-2.0', 'hunks': '@@ -54,7 +54,7 @@ the following format:\n - `lod_scales`: `num_lods` float32le, specifies the scale in "stored model" spatial units\n   corresponding to each level of detail.  Each scale value is multiplied by the\n   `lod_scale_multiplier` value from the `info` JSON file.\n-- `vertex_offsets`: `num_lods*3` float32le, as a C order `[vertex_offsets, 3]` array specifying an\n+- `vertex_offsets`: `num_lods*3` float32le, as a C order `[num_lods, 3]` array specifying an\n   offset (in the "stored model" coordinate space) to add to vertex positions for each level of\n   detail.\n - `num_fragments_per_lod`: `num_lods` uint32le, specifies the number of fragments (octree nodes) for\n@@ -89,9 +89,17 @@ The mesh fragment data files consist of the concatenation of the encoded mesh da\n nodes specified in the manifest file, in the same order the nodes are specified in the index file,\n starting with `lod` 0.  Each mesh fragment is a [Draco](https://google.github.io/draco/)-encoded\n triangular mesh with a 3-component integer vertex position attribute.  Each position component `j`\n-must be in the range `[0, 2**vertex_quantization_bits)`, where a value of `x` corresponds to\n-`grid_origin[i] + chunk_shape[i] * (fragmentPosition[i] + x / (2**vertex_quantization_bits-1)) * (2**lod)`.  The\n-built-in Draco attribute quantization is not supported.\n+must be a value `x` in the range `[0, 2**vertex_quantization_bits)`, which corresponds to a "stored\n+model" coordinate of:\n+\n+```\n+grid_origin[j] +\n+vertex_offsets[lod,j] +\n+chunk_shape[j] * (2**lod) * (fragmentPosition[j] +\n+                             x / ((2**vertex_quantization_bits)-1))\n+```\n+\n+The built-in Draco attribute quantization is not supported.\n \n Each mesh fragment for `lod > 0` must be partitioned by a `2x2x2` grid such that no triangle crosses\n a grid boundary (but may be incident to a grid boundary).\n', 'addition_count': 12, 'deletion_count': 4, 'src_file': 'a/src/neuroglancer/datasource/precomputed/meshes.md', 'tgt_file': 'b/src/neuroglancer/datasource/precomputed/meshes.md', 'file_extension': '.md', 'before_file': '# Mesh representation of segmented object surfaces\n\nIf the `"mesh"` property is specified in the `info` JSON file for a `"segmentation"` volume, then a\ntriangular mesh representation of the surface of some or all segmented objects may be specified.\nEach segmented object should correspond to a set of objects with the same non-zero integer label\nvalue specified in the volume.\n\nThere are two supported mesh formats: a [multi-resolution mesh\nformat](#multi-resolution-mesh-format) in which each segmented object is represented at multiple\nlevels of detail using a octree decomposition, and a [legacy single-resolution\nformat](#legacy-single-resolution-mesh-format).\n\n## Multi-resolution mesh format\n\nThe multi-resolution object surface meshes corresponding to a segmentation are represented as a\ndirectory tree containing the following data:\n\n- `info` file in JSON format specifying the\n  [metadata](#multi-resolution-mesh-info-json-file-format).\n- For each segment ID for which there is a mesh representation:\n  - a ["manifest" file](#multi-resolution-mesh-manifest-file-format) that specifies the levels of\n    detail and octree decomposition for the object;\n  - a [mesh fragment data file](#multi-resolution-mesh-fragment-data-file-format) specifying an\n    encoded mesh representation corresponding to each octree node.\n\nThe actual storage of the manifest and mesh fragment data depends on whether the unsharded or\n[sharded](./sharded.md) format is used.\n\n### Multi-resolution mesh info JSON file format\n\nThe `info` file is a JSON-format text file.  The root value must be a JSON object with the following\nmembers:\n- `"@type"`: Must be `"neuroglancer_multilod_draco"`.\n- `"vertex_quantization_bits"`: Specifies the number of bits needed to represent each vertex\n  position coordinate within a mesh fragment.  Must be `10` or `16`.\n- `"transform"`: JSON array of 12 numbers specifying a 4x3 homogeneous coordinate transform from the\n  "stored model" coordinate space to a "model" coordinate space.\n- `"lod_scale_multiplier"`: Factor by which the `lod_scales` values in each `<segment-id>.index`\n  file are multiplied.\n- `"sharding"`: If specified, indicates that the mesh is stored using the [sharded\n    format](./sharded.md).  Must be a [sharding specification](./sharded.md#sharding-specification).  If not\n    specified, the unsharded storage representation is used.\n- `"segment_properties"`: Optional.  If specified, it must be a string value specifying the name of\n  the subdirectory containing a [segment properties](./segment_properties.md) representation.  Note\n  that Neuroglancer only uses these segment properties if this mesh source is specified as a data\n  source directly.  If it is specified indirectly via the `"mesh"` property in a [multi-scale\n  volume](./volume.md), then you must instead specify the properties using use the\n  `"segment_properties"` member in the volume\'s `info` file.\n\n### Multi-resolution mesh manifest file format\n\nFor each segment ID for which there is a mesh representation, there is a binary "manifest" file in\nthe following format:\n- `lod_scales`: `num_lods` float32le, specifies the scale in "stored model" spatial units\n  corresponding to each level of detail.  Each scale value is multiplied by the\n  `lod_scale_multiplier` value from the `info` JSON file.\n- `vertex_offsets`: `num_lods*3` float32le, as a C order `[vertex_offsets, 3]` array specifying an\n  offset (in the "stored model" coordinate space) to add to vertex positions for each level of\n  detail.\n- `num_fragments_per_lod`: `num_lods` uint32le, specifies the number of fragments (octree nodes) for\n  corresponding to each level of detail.  Each scale value is multiplied by the\n  `lod_scale_multiplier` value from the `info` JSON file.\n- `vertex_offsets`: `num_lods*3` float32le, as a C order `[num_lods, 3]` array specifying an\n  offset (in the "stored model" coordinate space) to add to vertex positions for each level of\n  detail.\n- `num_fragments_per_lod`: `num_lods` uint32le, specifies the number of fragments (octree nodes) for\n  each level of detail.\n- For each `lod` in the range `[0, num_lods)`:\n  - `fragment_positions`: `num_fragments_per_lod[lod]*3` uint32le, C order `[3,\n    numFragments_per_lod[lod]]` array specifying the `x`, `y`, and `z` coordinates of the octree\n    nodes for the given `lod`.  The node positions must be in `x`, `y`, `z` Z-curve order.  The node\n    corresponds to the axis-aligned bounding box within the "stored model" coordinate space with an\n    origin of: `grid_origin + [x, y, z] * chunk_shape * (2**lod)` and a shape of `chunk_shape *\n    (2**lod)`.\n  - `fragment_offsets`: `num_fragments_per_lod[lod]` uint32le, specifies the size in bytes of the\n    encoded mesh fragment in the [mesh fragment data\n    file](#multi-resolution-mesh-fragment-data-file-format) corresponding to each octree node in the\n    `fragment_positions` array.  The starting offset of the encoded mesh data corresponding to a\n    given octree node is equal to the sum of all prior `fragment_offsets` values.\n    \n#### Unsharded storage of multi-resolution mesh manifest\n    \nIf the unsharded format is used, the manifest for each segment is stored as a separate file within\nthe same directory as the `info` file under the name `<segment-id>.index`, where `<segment-id>` is\nthe base-10 string representation of the segment ID.\n\n#### Sharded storage of multi-resolution mesh manifest\n\nnodes specified in the manifest file, in the same order the nodes are specified in the index file,\nstarting with `lod` 0.  Each mesh fragment is a [Draco](https://google.github.io/draco/)-encoded\ntriangular mesh with a 3-component integer vertex position attribute.  Each position component `j`\nmust be in the range `[0, 2**vertex_quantization_bits)`, where a value of `x` corresponds to\n`grid_origin[i] + chunk_shape[i] * (fragmentPosition[i] + x / (2**vertex_quantization_bits-1)) * (2**lod)`.  The\nbuilt-in Draco attribute quantization is not supported.\n\nEach mesh fragment for `lod > 0` must be partitioned by a `2x2x2` grid such that no triangle crosses\na grid boundary (but may be incident to a grid boundary).\n```\n\nThe built-in Draco attribute quantization is not supported.\n\nEach mesh fragment for `lod > 0` must be partitioned by a `2x2x2` grid such that no triangle crosses\na grid boundary (but may be incident to a grid boundary).\n\n#### Unsharded storage of multi-resolution mesh fragment data\n\nIf the unsharded format is used, the mesh mesh fragment data file is stored as a separate file\nwithin the same directory as the `info` file under the name `<segment-id>`, where `<segment-id>` is\nthe base-10 string representation of the segment ID.  The HTTP server must support HTTP `Range`\nrequests for these files in order to allow individual fragment meshes to be retrieved.\n\n#### Sharded storage of multi-resolution mesh fragment data\n\nIf the [sharded format](./sharded.md#sharded-format) is used, the mesh fragment data file is located immediately\nbefore the manifest file in the same shard data file.  The starting offset within that shard data\nfile is not specified explicitly but may be computed from the starting offset of the manifest file\nand the sum of the mesh fragment sizes specified in the manifest.\n\n## Legacy single-resolution mesh format\n\nIn addition to the multi-resolution mesh format, an older single-resolution mesh format is also\nsupported.  This format is specified by either the absence of an `info` file in the mesh\nsubdirectory or an `info` file containing a JSON object with the following members:\n- `"@type"`: Must be `"neuroglancer_legacy_mesh"`.\n\nTo specify a legacy single-resolution mesh dataset that lacks an `info` file as a Neuroglancer data\nsource, use the data source URL syntax `precomputed://FILE_URL#type=mesh`, where `FILE_URL` is the\nURL to the directory containing the mesh data using any [supported file\nprotocol](../file_protocols.md).\n\nThe surface mesh representation for a given segmented object may be split into one or more separate\nfragments (e.g. corresponding to subvolumes).\n\nWithin the mesh subdirectory, for each segmented object for which a surface representation is\navailable, there is a JSON-format metadata file named `<segment-id>:0`, where `<segment-id>` is\nsubstituted with the base-10 string representation of the segment label value.  This metadata file\nmust contain an object with a `"fragments"` property specifying the filenames (relative to the mesh\nsubdirectory) containing the mesh data for each fragment.\n\nThis legacy mesh format does not support a [sharded storage representation](./sharded.md#sharded-format).\n\nEach fragment file is specified in the following binary format:\n- The file begins with a little-endian 32-bit unsigned integer `num_vertices` specifying the number\n  of vertices.\n- The `[x, y, z]` vertex positions (as nanometer offsets within the global coordinate frame) are\n  stored as little-endian single precision/binary32 floating point values starting at an offset of\n  `4` bytes from the start of the file (immediately after the `num_vertices` value) and ending at a\n  byte offset of `4 + 4 * 3 * num_vertices`.  The x, y, and z components of the vertex positions are\n  interleaved, i.e. `[x0, y0, z0, x1, y1, z1, ...]`.\n- The number of triangles is inferred as the number of remaining bytes in the file after the vertex\n  position data divided by 12 (the number of remaining bytes must be a multiple of 12).  The\n  triangles are specified as an array of interleaved triplets `[a, b, c]` of vertex indices.  The\n  vertex indices are encoded as little-endian 32-bit unsigned integers.\n', 'message': 'docs(datasource/precomputed): further clarify mesh vertex interpretation\n', 'author_name': 'Jeremy Maitin-Shepard', 'lang': 'md'}