-
Notifications
You must be signed in to change notification settings - Fork 245
Add an ellipsoid tileset loader for flat terrain generation #908
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
Merged
Merged
Changes from 5 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
8eb874b
add ellipsoid tileset loader
jqntn 160490a
fix conversion errors
jqntn 785e988
add proper geographic projection
jqntn d2ed4b9
add proper root tiles handling
jqntn fa2eb23
tidy createModel method
jqntn 90a7856
Merge branch 'main' of github.com:CesiumGS/cesium-native into ellipso…
azrogers 2647667
Fit loader with latest ellipsoid changes
azrogers d6902a8
Added CHANGES.md
azrogers 25534c3
Merge remote-tracking branch 'origin/main' into ellipsoid-tileset-loader
jqntn 9305c00
rm using namespace from header
jqntn 7c6bad9
rm unused includes
jqntn 5040669
properly declare parameter as unused
jqntn 25bd258
make geometry error computation consistent
jqntn 782c892
add necessary metadata in gltf model
jqntn 2a06b1d
add doc comments
jqntn b986b0b
Merge branch 'main' of github.com:CesiumGS/cesium-native into ellipso…
azrogers 3cef22e
Update CHANGES.md
azrogers f0e6b1f
Remove duplicated changes
azrogers File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
61 changes: 61 additions & 0 deletions
61
Cesium3DTilesSelection/include/Cesium3DTilesSelection/EllipsoidTilesetLoader.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| #pragma once | ||
|
|
||
| #include <Cesium3DTilesSelection/Tile.h> | ||
| #include <Cesium3DTilesSelection/TileLoadResult.h> | ||
| #include <Cesium3DTilesSelection/Tileset.h> | ||
| #include <Cesium3DTilesSelection/TilesetContentLoader.h> | ||
| #include <Cesium3DTilesSelection/TilesetExternals.h> | ||
| #include <Cesium3DTilesSelection/TilesetOptions.h> | ||
| #include <CesiumAsync/Future.h> | ||
| #include <CesiumGeometry/QuadtreeTileID.h> | ||
| #include <CesiumGeometry/QuadtreeTilingScheme.h> | ||
| #include <CesiumGeospatial/BoundingRegion.h> | ||
| #include <CesiumGeospatial/Ellipsoid.h> | ||
| #include <CesiumGeospatial/GeographicProjection.h> | ||
| #include <CesiumGltf/Model.h> | ||
|
|
||
| #include <glm/fwd.hpp> | ||
|
|
||
| #include <cstdint> | ||
| #include <memory> | ||
| #include <vector> | ||
|
|
||
| using namespace CesiumGltf; | ||
| using namespace CesiumAsync; | ||
| using namespace CesiumUtility; | ||
| using namespace CesiumGeometry; | ||
| using namespace CesiumGeospatial; | ||
|
|
||
| namespace Cesium3DTilesSelection { | ||
| class EllipsoidTilesetLoader : public TilesetContentLoader { | ||
jqntn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| public: | ||
| EllipsoidTilesetLoader(const Ellipsoid& ellipsoid = Ellipsoid::WGS84); | ||
|
|
||
| static std::unique_ptr<Tileset> createTileset( | ||
| const TilesetExternals& externals, | ||
| const Ellipsoid& ellipsoid = Ellipsoid::WGS84, | ||
| const TilesetOptions& options = TilesetOptions{}); | ||
|
|
||
| Future<TileLoadResult> loadTileContent(const TileLoadInput& input) override; | ||
| TileChildrenResult createTileChildren(const Tile& tile) override; | ||
|
|
||
| private: | ||
| struct Geometry { | ||
| std::vector<uint16_t> indices; | ||
| std::vector<glm::vec3> vertices; | ||
| std::vector<glm::vec3> normals; | ||
| }; | ||
|
|
||
| void createChildTile( | ||
| const Tile& parent, | ||
| std::vector<Tile>& children, | ||
| const QuadtreeTileID& childID) const; | ||
|
|
||
| BoundingRegion createBoundingRegion(const QuadtreeTileID& quadtreeID) const; | ||
| Geometry createGeometry(const Tile& tile) const; | ||
| Model createModel(const Geometry& geometry) const; | ||
|
|
||
| GeographicProjection _projection; | ||
| QuadtreeTilingScheme _tilingScheme; | ||
| }; | ||
| } // namespace Cesium3DTilesSelection | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,274 @@ | ||
| #include <Cesium3DTilesContent/ImplicitTilingUtilities.h> | ||
| #include <Cesium3DTilesSelection/EllipsoidTilesetLoader.h> | ||
| #include <Cesium3DTilesSelection/Tile.h> | ||
| #include <Cesium3DTilesSelection/TileContent.h> | ||
| #include <Cesium3DTilesSelection/TileLoadResult.h> | ||
| #include <Cesium3DTilesSelection/TileRefine.h> | ||
| #include <Cesium3DTilesSelection/Tileset.h> | ||
| #include <Cesium3DTilesSelection/TilesetContentLoader.h> | ||
| #include <Cesium3DTilesSelection/TilesetExternals.h> | ||
| #include <Cesium3DTilesSelection/TilesetOptions.h> | ||
jqntn marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| #include <CesiumAsync/Future.h> | ||
| #include <CesiumGeometry/Axis.h> | ||
| #include <CesiumGeometry/QuadtreeTileID.h> | ||
| #include <CesiumGeometry/QuadtreeTilingScheme.h> | ||
| #include <CesiumGeospatial/BoundingRegion.h> | ||
| #include <CesiumGeospatial/Cartographic.h> | ||
| #include <CesiumGeospatial/Ellipsoid.h> | ||
| #include <CesiumGeospatial/GeographicProjection.h> | ||
| #include <CesiumGeospatial/GlobeRectangle.h> | ||
| #include <CesiumGeospatial/calcQuadtreeMaxGeometricError.h> | ||
| #include <CesiumGltf/Accessor.h> | ||
| #include <CesiumGltf/AccessorSpec.h> | ||
| #include <CesiumGltf/Buffer.h> | ||
| #include <CesiumGltf/BufferCesium.h> | ||
| #include <CesiumGltf/BufferView.h> | ||
| #include <CesiumGltf/Mesh.h> | ||
| #include <CesiumGltf/MeshPrimitive.h> | ||
| #include <CesiumGltf/Model.h> | ||
| #include <CesiumGltf/Node.h> | ||
| #include <CesiumGltf/Scene.h> | ||
jqntn marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| #include <glm/detail/type_vec3.hpp> | ||
| #include <glm/ext/matrix_transform.hpp> | ||
| #include <glm/fwd.hpp> | ||
|
|
||
| #include <cstddef> | ||
| #include <cstdint> | ||
| #include <cstring> | ||
| #include <memory> | ||
| #include <optional> | ||
| #include <type_traits> | ||
| #include <variant> | ||
| #include <vector> | ||
|
|
||
| using namespace Cesium3DTilesContent; | ||
|
|
||
| namespace Cesium3DTilesSelection { | ||
| EllipsoidTilesetLoader::EllipsoidTilesetLoader(const Ellipsoid& ellipsoid) | ||
| : _projection(ellipsoid), | ||
| _tilingScheme( | ||
| _projection.project(_projection.MAXIMUM_GLOBE_RECTANGLE), | ||
| 2, | ||
| 1) {} | ||
|
|
||
| /*static*/ std::unique_ptr<Tileset> EllipsoidTilesetLoader::createTileset( | ||
| const TilesetExternals& externals, | ||
| const Ellipsoid& ellipsoid, | ||
| const TilesetOptions& options) { | ||
| std::unique_ptr<EllipsoidTilesetLoader> pCustomLoader = | ||
| std::make_unique<EllipsoidTilesetLoader>(ellipsoid); | ||
| std::unique_ptr<Tile> pRootTile = | ||
| std::make_unique<Tile>(pCustomLoader.get(), TileEmptyContent{}); | ||
|
|
||
| pRootTile->setRefine(TileRefine::Replace); | ||
| pRootTile->setUnconditionallyRefine(); | ||
|
|
||
| std::vector<Tile> children; | ||
| uint32_t rootTilesX = pCustomLoader->_tilingScheme.getRootTilesX(); | ||
| children.reserve(rootTilesX); | ||
|
|
||
| for (uint32_t x = 0; x < rootTilesX; x++) { | ||
| pCustomLoader->createChildTile( | ||
| *pRootTile, | ||
| children, | ||
| QuadtreeTileID{0, x, 0}); | ||
| } | ||
|
|
||
| pRootTile->createChildTiles(std::move(children)); | ||
|
|
||
| return std::make_unique<Tileset>( | ||
| externals, | ||
| std::move(pCustomLoader), | ||
| std::move(pRootTile), | ||
| options); | ||
| } | ||
|
|
||
| Future<TileLoadResult> | ||
| EllipsoidTilesetLoader::loadTileContent(const TileLoadInput& input) { | ||
| return input.asyncSystem.createResolvedFuture(TileLoadResult{ | ||
| createModel(createGeometry(input.tile)), | ||
| Axis::Z, | ||
| std::nullopt, | ||
| std::nullopt, | ||
| std::nullopt, | ||
| nullptr, | ||
| {}, | ||
| TileLoadResultState::Success}); | ||
| } | ||
|
|
||
| TileChildrenResult | ||
| EllipsoidTilesetLoader::createTileChildren(const Tile& tile) { | ||
| const QuadtreeTileID* pParentID = | ||
| std::get_if<QuadtreeTileID>(&tile.getTileID()); | ||
|
|
||
| if (pParentID) { | ||
| std::vector<Tile> children; | ||
| QuadtreeChildren childIDs = | ||
| ImplicitTilingUtilities::getChildren(*pParentID); | ||
| children.reserve(childIDs.size()); | ||
|
|
||
| for (const QuadtreeTileID& childID : childIDs) { | ||
| createChildTile(tile, children, childID); | ||
| } | ||
|
|
||
| return TileChildrenResult{ | ||
| std::move(children), | ||
| TileLoadResultState::Success}; | ||
| } | ||
|
|
||
| return TileChildrenResult{{}, TileLoadResultState::Failed}; | ||
| } | ||
|
|
||
| void EllipsoidTilesetLoader::createChildTile( | ||
| const Tile& parent, | ||
| std::vector<Tile>& children, | ||
| const QuadtreeTileID& childID) const { | ||
| BoundingRegion boundingRegion = createBoundingRegion(childID); | ||
| const GlobeRectangle& globeRectangle = boundingRegion.getRectangle(); | ||
|
|
||
| Tile& child = children.emplace_back(parent.getLoader()); | ||
| child.setTileID(childID); | ||
| child.setRefine(parent.getRefine()); | ||
| child.setTransform(glm::translate( | ||
| glm::dmat4x4(1.0), | ||
| _projection.getEllipsoid().cartographicToCartesian( | ||
| globeRectangle.getNorthwest()))); | ||
| child.setBoundingVolume(boundingRegion); | ||
| child.setGeometricError( | ||
| 6.0 * calcQuadtreeMaxGeometricError(_projection.getEllipsoid()) * | ||
jqntn marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| globeRectangle.computeWidth()); | ||
| } | ||
|
|
||
| BoundingRegion EllipsoidTilesetLoader::createBoundingRegion( | ||
| const QuadtreeTileID& quadtreeID) const { | ||
| return BoundingRegion( | ||
| _projection.unproject(_tilingScheme.tileToRectangle(quadtreeID)), | ||
| 0.0, | ||
| 0.0, | ||
| _projection.getEllipsoid()); | ||
| } | ||
|
|
||
| EllipsoidTilesetLoader::Geometry | ||
| EllipsoidTilesetLoader::createGeometry(const Tile& tile) const { | ||
| static constexpr uint16_t resolution = 24; | ||
|
|
||
| std::vector<uint16_t> indices(6 * (resolution - 1) * (resolution - 1)); | ||
| std::vector<glm::vec3> vertices(resolution * resolution); | ||
| std::vector<glm::vec3> normals(vertices.size()); | ||
|
|
||
| const Ellipsoid& ellipsoid = _projection.getEllipsoid(); | ||
| const GlobeRectangle& rectangle = | ||
| std::get<BoundingRegion>(tile.getBoundingVolume()).getRectangle(); | ||
|
|
||
| double west = rectangle.getWest(); | ||
| double east = rectangle.getEast(); | ||
| double north = rectangle.getNorth(); | ||
| double south = rectangle.getSouth(); | ||
|
|
||
| double lonStep = (east - west) / (resolution - 1); | ||
| double latStep = (south - north) / (resolution - 1); | ||
|
|
||
| glm::dmat4 inverseTransform = glm::inverse(tile.getTransform()); | ||
|
|
||
| for (uint16_t x = 0; x < resolution; x++) { | ||
| double longitude = (lonStep * x) + west; | ||
| for (uint16_t y = 0; y < resolution; y++) { | ||
| double latitude = (latStep * y) + north; | ||
| Cartographic cartographic(longitude, latitude); | ||
|
|
||
| uint16_t index = static_cast<uint16_t>((resolution * x) + y); | ||
| vertices[index] = glm::dvec3( | ||
| inverseTransform * | ||
| glm::dvec4(ellipsoid.cartographicToCartesian(cartographic), 1.0)); | ||
| normals[index] = ellipsoid.geodeticSurfaceNormal(cartographic); | ||
|
|
||
| if (x < resolution - 1 && y < resolution - 1) { | ||
| uint16_t a = index + 1; | ||
| uint16_t b = index + resolution; | ||
| uint16_t c = b + 1; | ||
| indices.insert(indices.end(), {b, index, a, b, a, c}); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return Geometry{std::move(indices), std::move(vertices), std::move(normals)}; | ||
| } | ||
|
|
||
| Model EllipsoidTilesetLoader::createModel(const Geometry& geometry) const { | ||
| const std::vector<uint16_t>& indices = geometry.indices; | ||
| const std::vector<glm::vec3>& vertices = geometry.vertices; | ||
| const std::vector<glm::vec3>& normals = geometry.normals; | ||
|
|
||
| size_t indicesSize = indices.size() * sizeof(uint16_t); | ||
| size_t verticesSize = vertices.size() * sizeof(glm::vec3); | ||
| size_t normalsSize = verticesSize; | ||
|
|
||
| Model model; | ||
jqntn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| model.buffers.resize(1); | ||
| model.bufferViews.resize(3); | ||
| model.accessors.resize(3); | ||
| model.materials.resize(1); | ||
| model.meshes.resize(1); | ||
| model.scenes.resize(1); | ||
| model.nodes.resize(1); | ||
|
|
||
| model.meshes[0].primitives.resize(1); | ||
| model.scenes[0].nodes.emplace_back(0); | ||
| model.nodes[0].mesh = 0; | ||
|
|
||
| std::vector<std::byte>& buffer = model.buffers[0].cesium.data; | ||
| buffer.resize(indicesSize + verticesSize + normalsSize); | ||
| std::memcpy(buffer.data(), indices.data(), indicesSize); | ||
| std::memcpy(buffer.data() + indicesSize, vertices.data(), verticesSize); | ||
| std::memcpy( | ||
| buffer.data() + indicesSize + verticesSize, | ||
| normals.data(), | ||
| normalsSize); | ||
|
|
||
| BufferView& bufferViewIndices = model.bufferViews[0]; | ||
| bufferViewIndices.buffer = 0; | ||
| bufferViewIndices.byteOffset = 0; | ||
| bufferViewIndices.byteLength = static_cast<int64_t>(indicesSize); | ||
| bufferViewIndices.target = BufferView::Target::ELEMENT_ARRAY_BUFFER; | ||
|
|
||
| BufferView& bufferViewVertices = model.bufferViews[1]; | ||
| bufferViewVertices.buffer = 0; | ||
| bufferViewVertices.byteOffset = static_cast<int64_t>(indicesSize); | ||
| bufferViewVertices.byteLength = static_cast<int64_t>(verticesSize); | ||
| bufferViewVertices.target = BufferView::Target::ARRAY_BUFFER; | ||
|
|
||
| BufferView& bufferViewNormals = model.bufferViews[2]; | ||
| bufferViewNormals.buffer = 0; | ||
| bufferViewNormals.byteOffset = | ||
| static_cast<int64_t>(indicesSize + verticesSize); | ||
| bufferViewNormals.byteLength = static_cast<int64_t>(normalsSize); | ||
| bufferViewNormals.target = BufferView::Target::ARRAY_BUFFER; | ||
|
|
||
| Accessor& accessorIndices = model.accessors[0]; | ||
| accessorIndices.bufferView = 0; | ||
| accessorIndices.count = static_cast<int64_t>(indices.size()); | ||
| accessorIndices.componentType = Accessor::ComponentType::UNSIGNED_SHORT; | ||
| accessorIndices.type = Accessor::Type::SCALAR; | ||
|
|
||
| Accessor& accessorVertices = model.accessors[1]; | ||
| accessorVertices.bufferView = 1; | ||
| accessorVertices.count = static_cast<int64_t>(vertices.size()); | ||
| accessorVertices.componentType = Accessor::ComponentType::FLOAT; | ||
| accessorVertices.type = Accessor::Type::VEC3; | ||
|
|
||
| Accessor& accessorNormals = model.accessors[2]; | ||
| accessorNormals.bufferView = 2; | ||
| accessorNormals.count = static_cast<int64_t>(normals.size()); | ||
| accessorNormals.componentType = Accessor::ComponentType::FLOAT; | ||
| accessorNormals.type = Accessor::Type::VEC3; | ||
|
|
||
| MeshPrimitive& primitive = model.meshes[0].primitives[0]; | ||
| primitive.attributes["POSITION"] = 1; | ||
| primitive.attributes["NORMAL"] = 2; | ||
| primitive.indices = 0; | ||
| primitive.material = 0; | ||
|
|
||
| return model; | ||
| } | ||
| } // namespace Cesium3DTilesSelection | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.