{"id":13678919,"url":"https://github.com/CesiumGS/quantized-mesh","last_synced_at":"2025-04-29T15:33:47.578Z","repository":{"id":49882173,"uuid":"46749585","full_name":"CesiumGS/quantized-mesh","owner":"CesiumGS","description":"Specification for streaming massive terrain datasets for 3D visualization.","archived":false,"fork":false,"pushed_at":"2021-07-16T20:00:36.000Z","size":25,"stargazers_count":241,"open_issues_count":9,"forks_count":41,"subscribers_count":34,"default_branch":"main","last_synced_at":"2024-11-10T22:07:41.992Z","etag":null,"topics":["cesium","specification","terrain"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CesiumGS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-23T21:38:22.000Z","updated_at":"2024-11-06T04:55:26.000Z","dependencies_parsed_at":"2022-09-21T17:12:43.233Z","dependency_job_id":null,"html_url":"https://github.com/CesiumGS/quantized-mesh","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CesiumGS%2Fquantized-mesh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CesiumGS%2Fquantized-mesh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CesiumGS%2Fquantized-mesh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CesiumGS%2Fquantized-mesh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CesiumGS","download_url":"https://codeload.github.com/CesiumGS/quantized-mesh/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224179216,"owners_count":17269027,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cesium","specification","terrain"],"created_at":"2024-08-02T13:00:59.906Z","updated_at":"2024-11-11T21:31:54.443Z","avatar_url":"https://github.com/CesiumGS.png","language":null,"funding_links":[],"categories":["Terrain"],"sub_categories":[],"readme":"# quantized-mesh-1.0 terrain format\n\nHave a question? Discuss the quantized-mesh specification on the [Cesium community forum](https://community.cesium.com/).\n\nA terrain tileset in quantized-mesh-1.0 format is a simple multi-resolution quadtree pyramid of meshes. All tiles have the extension .terrain. So, if the Tiles URL for a tileset is:\n\n```\nhttp://example.com/tiles\n```\n\nThen the two root files of the pyramid are found at these URLs:\n\n* (-180 deg, -90 deg) - (0 deg, 90 deg) - http://example.com/tiles/0/0/0.terrain\n* (0 deg, -90 deg) - (180 deg, 90 deg) - http://example.com/tiles/0/1/0.terrain\n\nThe eight tiles at the next level are found at these URLs:\n\n* (-180 deg, -90 deg) - (-90 deg, 0 deg) - http://example.com/tiles/1/0/0.terrain\n* (-90 deg, -90 deg) - (0 deg, 0 deg) - http://example.com/tiles/1/1/0.terrain\n* (0 deg, -90 deg) - (90 deg, 0 deg) - http://example.com/tiles/1/2/0.terrain\n* (90 deg, -90 deg) - (180 deg, 0 deg) - http://example.com/tiles/1/3/0.terrain\n* (-180 deg, 0 deg) - (-90 deg, 90 deg) - http://example.com/tiles/1/0/1.terrain\n* (-90 deg, 0 deg) - (0 deg, 90 deg) - http://example.com/tiles/1/1/1.terrain\n* (0 deg, 0 deg) - (90 deg, 90 deg) - http://example.com/tiles/1/2/1.terrain\n* (90 deg, 0 deg) - (180 deg, 90 deg) - http://example.com/tiles/1/3/1.terrain\n\nWhen requesting tiles, be sure to include the following HTTP header in the request:\n```\nAccept: application/vnd.quantized-mesh,application/octet-stream;q=0.9\n```\n\nOtherwise, some servers may return a different representation of the tile than the one described here.\n\nEach tile is a specially-encoded triangle mesh where vertices overlap their neighbors at tile edges. In other words, at the root, the eastern-most vertices in the western tile have the same longitude as the western-most vertices in the eastern tile.\n\nTerrain tiles are served gzipped. Once extracted, tiles are little-endian, binary data. The first part of the file is a header with the following format. Doubles are IEEE 754 64-bit floating-point numbers, and Floats are IEEE 754 32-bit floating-point numbers.\n\n```C++\nstruct QuantizedMeshHeader\n{\n    // The center of the tile in Earth-centered Fixed coordinates.\n    double CenterX;\n    double CenterY;\n    double CenterZ;\n\n    // The minimum and maximum heights in the area covered by this tile.\n    // The minimum may be lower and the maximum may be higher than\n    // the height of any vertex in this tile in the case that the min/max vertex\n    // was removed during mesh simplification, but these are the appropriate\n    // values to use for analysis or visualization.\n    float MinimumHeight;\n    float MaximumHeight;\n\n    // The tile’s bounding sphere.  The X,Y,Z coordinates are again expressed\n    // in Earth-centered Fixed coordinates, and the radius is in meters.\n    double BoundingSphereCenterX;\n    double BoundingSphereCenterY;\n    double BoundingSphereCenterZ;\n    double BoundingSphereRadius;\n\n    // The horizon occlusion point, expressed in the ellipsoid-scaled Earth-centered Fixed frame.\n    // If this point is below the horizon, the entire tile is below the horizon.\n    // See http://cesiumjs.org/2013/04/25/Horizon-culling/ for more information.\n    double HorizonOcclusionPointX;\n    double HorizonOcclusionPointY;\n    double HorizonOcclusionPointZ;\n};\n```\n\nImmediately following the header is the vertex data. An `unsigned int` is a 32-bit unsigned integer and an `unsigned short` is a 16-bit unsigned integer.\n\n```C++\nstruct VertexData\n{\n    unsigned int vertexCount;\n    unsigned short u[vertexCount];\n    unsigned short v[vertexCount];\n    unsigned short height[vertexCount];\n};\n```\n\nThe `vertexCount` field indicates the size of the three arrays that follow. The three arrays contain the delta from the previous value that is then zig-zag encoded in order to make small integers, regardless of their sign, use a small number of bits. Decoding a value is straightforward:\n\n```javascript\nvar u = 0;\nvar v = 0;\nvar height = 0;\n\nfunction zigZagDecode(value) {\n    return (value \u003e\u003e 1) ^ (-(value \u0026 1));\n}\n\nfor (i = 0; i \u003c vertexCount; ++i) {\n    u += zigZagDecode(uBuffer[i]);\n    v += zigZagDecode(vBuffer[i]);\n    height += zigZagDecode(heightBuffer[i]);\n\n    uBuffer[i] = u;\n    vBuffer[i] = v;\n    heightBuffer[i] = height;\n}\n```\n\nOnce decoded, the meaning of a value in each array is as follows:\n\n| Field | Meaning |\n| ----- | ------- |\n| u | The horizontal coordinate of the vertex in the tile. When the u value is 0, the vertex is on the Western edge of the tile. When the value is 32767, the vertex is on the Eastern edge of the tile. For other values, the vertex's longitude is a linear interpolation between the longitudes of the Western and Eastern edges of the tile. |\n| v | The vertical coordinate of the vertex in the tile. When the v value is 0, the vertex is on the Southern edge of the tile. When the value is 32767, the vertex is on the Northern edge of the tile. For other values, the vertex's latitude is a linear interpolation between the latitudes of the Southern and Nothern edges of the tile. |\n| height | The height of the vertex in the tile. When the height value is 0, the vertex's height is equal to the minimum height within the tile, as specified in the tile's header. When the value is 32767, the vertex's height is equal to the maximum height within the tile. For other values, the vertex's height is a linear interpolation between the minimum and maximum heights. |\n\nImmediately following the vertex data is the index data. Indices specify how the vertices are linked together into triangles. If tile has more than 65536 vertices, the tile uses the `IndexData32` structure to encode indices. Otherwise, it uses the `IndexData16` structure.\n\nTo enforce proper byte alignment, padding is added before the IndexData to ensure 2 byte alignment for `IndexData16` and 4 byte alignment for `IndexData32`.\n\n```C++\nstruct IndexData16\n{\n    unsigned int triangleCount;\n    unsigned short indices[triangleCount * 3];\n}\n\nstruct IndexData32\n{\n    unsigned int triangleCount;\n    unsigned int indices[triangleCount * 3];\n}\n```\n\nIndices are encoded using the high water mark encoding from [webgl-loader](https://code.google.com/p/webgl-loader/). Indices are decoded as follows:\n\n```javascript\nvar highest = 0;\nfor (var i = 0; i \u003c indices.length; ++i) {\n    var code = indices[i];\n    indices[i] = highest - code;\n    if (code === 0) {\n        ++highest;\n    }\n}\n```\n\nEach triplet of indices specifies one triangle to be rendered, in counter-clockwise winding order. Following the triangle indices is four more lists of indices:\n\n```C++\nstruct EdgeIndices16\n{\n    unsigned int westVertexCount;\n    unsigned short westIndices[westVertexCount];\n\n    unsigned int southVertexCount;\n    unsigned short southIndices[southVertexCount];\n\n    unsigned int eastVertexCount;\n    unsigned short eastIndices[eastVertexCount];\n\n    unsigned int northVertexCount;\n    unsigned short northIndices[northVertexCount];\n}\n\nstruct EdgeIndices32\n{\n    unsigned int westVertexCount;\n    unsigned int westIndices[westVertexCount];\n\n    unsigned int southVertexCount;\n    unsigned int southIndices[southVertexCount];\n\n    unsigned int eastVertexCount;\n    unsigned int eastIndices[eastVertexCount];\n\n    unsigned int northVertexCount;\n    unsigned int northIndices[northVertexCount];\n}\n```\n\nThese index lists enumerate the vertices that are on the edges of the tile. It is helpful to know which vertices are on the edges in order to add skirts to hide cracks between adjacent levels of detail.\n\n## Tiling Scheme and Coordinate System\n\nBy default, the data is tiled according to the [Tile Map Service (TMS)](http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification) layout and global-geodetic system. These defaults can be varied by specifying the `projection` and `scheme`.\n\nAllowed values for the projection are `EPSG:3857` ([Web Mercator](https://en.wikipedia.org/wiki/Web_Mercator_projection) as used by Google Maps) and `EPSG:4326` (Lat/Lng coordinates in the [Global-Geodetic System](https://en.wikipedia.org/wiki/World_Geodetic_System)). It is worth noting that the `EPSG3857` projection has only 1 tile at the root (zoom level 0) while `EPSG:4326` has 2.\n\nThe options for the tiling scheme are `tms` and `slippyMap`. The Y coordinates are numbered from the south northwards (eg. latitudes) in the `tms` standard whereas `slippyMap` coordinates have their origin at top left (NW).\n\nFor Cesium terrain layers these options can be set in the `layer.json` manifest file. If not specified, they default\nto `EPSG:4326` and `tms`.\n\n## Extensions\nExtension data may follow to supplement the quantized-mesh with additional information. Each extension begins with an `ExtensionHeader`, consisting of a unique identifier and the size of the extension data in bytes. An `unsigned char` is a 8-bit unsigned integer.\n\n```C++\nstruct ExtensionHeader\n{\n    unsigned char extensionId;\n    unsigned int extensionLength;\n}\n```\n\nAs new extensions are defined, they will be assigned a unique identifier. If no extensions are defined for the tileset, an `ExtensionHeader` will not included in the quanitzed-mesh. Multiple extensions may be appended to the quantized-mesh data, where ordering of each extension is determined by the server.\n\nMultiple extensions may be requested by the client by delimiting extension names with a `-`. For example, a client can request vertex normals and watermask using the following Accept header:\n\n```\nAccept : 'application/vnd.quantized-mesh;extensions=octvertexnormals-watermask'\n```\n\nThe following extensions may be defined for a quantized-mesh:\n\n### Terrain Lighting\n\n__Name:__ Oct-Encoded Per-Vertex Normals\n\n__Id:__ 1\n\n__Description:__ Adds per vertex lighting attributes to the quantized-mesh. Each vertex normal uses oct-encoding to compress the traditional x, y, z 96-bit floating point unit vector into an x,y 16-bit representation. The 'oct' encoding is described in \"A Survey of Efficient Representations of Independent Unit Vectors\", Cigolle et al 2014: http://jcgt.org/published/0003/02/01/\n\n__Data Definition:__\n```C++\nstruct OctEncodedVertexNormals\n{\n    unsigned char xy[vertexCount * 2];\n}\n```\n\n__Requesting:__ For oct-encoded per-vertex normals to be included in the quantized-mesh, the client must request this extension by using the following HTTP Header:\n```\nAccept : 'application/vnd.quantized-mesh;extensions=octvertexnormals'\n```\n\n__Comments:__ The original implementation of this extension was requested using the extension name `vertexnormals`. The `vertexnormals` extension identifier is deprecated and implementations must now request vertex normals by adding `octvertexnormals` in the request header extensions parameter, as shown above.\n\n### Water Mask\n__Name:__ Water Mask\n\n__Id:__ 2\n\n__Description:__ Adds coastline data used for rendering water effects. The water mask is either 1 byte, in the case that the tile is all land or all water, or it is `256 * 256 * 1 = 65536` bytes if the tile has a mix of land and water. Each mask value is 0 for land and 255 for water. Values in the mask are defined from north-to-south, west-to-east; the first byte in the mask defines the watermask value for the northwest corner of the tile. Values between 0 and 255 are allowed as well in order to support anti-aliasing of the coastline.\n\n__Data Definition:__\n\nA Terrain Tile covered entirely by land or water is defined by a single byte.\n```C++\nstruct WaterMask\n{\n    unsigned char mask;\n}\n```\n\nA Terrain Tile containing a mix of land and water define a 256 x 256 grid of height values.\n\n```C++\nstruct WaterMask\n{\n    unsigned char mask[256 * 256];\n}\n```\n\n__Requesting:__ For the watermask to be included in the quantized-mesh, the client must request this extension by using the following HTTP Header:\n```\nAccept : 'application/vnd.quantized-mesh;extensions=watermask'\n```\n\n### Metadata\n__Name:__ Metadata\n\n__Id:__ 4\n\n__Description:__ Adds a JSON object to each tile that can store extra information about the tile. Potential uses include storing the what type of land is in the tile (eg. forest, desert, etc) or availability of child tiles.\n\n__Data Definition:__\n\n```C++\nstruct Metadata\n{\n    unsigned int jsonLength;\n    char json[jsonLength];\n}\n```\n\n__Requesting:__ For the metadata to be included in the quantized-mesh, the client must request this extension by using the following HTTP Header:\n```\nAccept : 'application/vnd.quantized-mesh;extensions=metadata'\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCesiumGS%2Fquantized-mesh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FCesiumGS%2Fquantized-mesh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCesiumGS%2Fquantized-mesh/lists"}