Skip to content

Commit

Permalink
Move more functionality to Cesium3DTilesContent.
Browse files Browse the repository at this point in the history
  • Loading branch information
kring committed Nov 2, 2023
1 parent a71a982 commit c561b64
Show file tree
Hide file tree
Showing 52 changed files with 469 additions and 437 deletions.
2 changes: 2 additions & 0 deletions Cesium3DTilesContent/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ target_link_libraries(Cesium3DTilesContent
PUBLIC
CesiumAsync
CesiumGeometry
CesiumGeospatial
CesiumGltf
CesiumGltfReader
CesiumUtility
)

install(TARGETS Cesium3DTilesContent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace Cesium3DTilesSelection {
* header. Based on this header or the file extension of the network response,
* the loader that will be used for processing the input can be looked up.
*/
class CESIUM3DTILESSELECTION_API GltfConverters {
class CESIUM3DTILESCONTENT_API GltfConverters {
public:
/**
* @brief A function pointer that can create a {@link GltfConverterResult} from a
Expand Down
96 changes: 96 additions & 0 deletions Cesium3DTilesContent/include/Cesium3DTilesContent/GltfUtilities.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#pragma once

#include "Library.h"

#include <CesiumGeospatial/BoundingRegion.h>
#include <CesiumGeospatial/GlobeRectangle.h>

#include <glm/fwd.hpp>

#include <string_view>
#include <vector>

namespace CesiumGltf {
struct Model;
}

namespace Cesium3DTilesSelection {
/**
* A collection of utility functions that are used to process and transform a
* gltf model
*/
struct CESIUM3DTILESCONTENT_API GltfUtilities {
/**
* @brief Applies the glTF's RTC_CENTER, if any, to the given transform.
*
* If the glTF has a `CESIUM_RTC` extension, this function will multiply the
* given matrix with the (translation) matrix that is created from the
* `RTC_CENTER` in the. If the given model does not have this extension, then
* this function will return the `rootTransform` unchanged.
*
* @param model The glTF model
* @param rootTransform The matrix that will be multiplied with the transform
* @return The result of multiplying the `RTC_CENTER` with the
* `rootTransform`.
*/
static glm::dmat4x4 applyRtcCenter(
const CesiumGltf::Model& gltf,
const glm::dmat4x4& rootTransform);

/**
* @brief Applies the glTF's `gltfUpAxis`, if any, to the given transform.
*
* By default, the up-axis of a glTF model will the the Y-axis.
*
* If the tileset that contained the model had the `asset.gltfUpAxis` string
* property, then the information about the up-axis has been stored in as a
* number property called `gltfUpAxis` in the `extras` of the given model.
*
* Depending on whether this value is `CesiumGeometry::Axis::X`, `Y`, or `Z`,
* the given matrix will be multiplied with a matrix that converts the
* respective axis to be the Z-axis, as required by the 3D Tiles standard.
*
* @param model The glTF model
* @param rootTransform The matrix that will be multiplied with the transform
* @return The result of multiplying the `rootTransform` with the
* `gltfUpAxis`.
*/
static glm::dmat4x4 applyGltfUpAxisTransform(
const CesiumGltf::Model& model,
const glm::dmat4x4& rootTransform);

/**
* @brief Computes a bounding region from the vertex positions in a glTF
* model.
*
* If the glTF model spans the anti-meridian, the west and east longitude
* values will be in the usual -PI to PI range, but east will have a smaller
* value than west.
*
* If the glTF contains no geometry, the returned region's rectangle
* will be {@link GlobeRectangle::EMPTY}, its minimum height will be 1.0, and
* its maximum height will be -1.0 (the minimum will be greater than the
* maximum).
*
* @param gltf The model.
* @param transform The transform from model coordinates to ECEF coordinates.
* @return The computed bounding region.
*/
static CesiumGeospatial::BoundingRegion computeBoundingRegion(
const CesiumGltf::Model& gltf,
const glm::dmat4& transform);

/**
* @brief Parse the copyright field of a glTF model and return the individual
* credits.
*
* Credits are read from the glTF's asset.copyright field. This method assumes
* that individual credits are separated by semicolons.
*
* @param gltf The model.
* @return The credits from the glTF.
*/
static std::vector<std::string_view>
parseGltfCopyright(const CesiumGltf::Model& gltf);
};
} // namespace Cesium3DTilesSelection
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

/**
* @brief Classes that support the 3D Tiles tile content types.
* @brief Classes that support loading and converting 3D Tiles tile content.
*/
namespace Cesium3DTilesContent {}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#pragma once

#include <Cesium3DTilesSelection/BoundingVolume.h>
#include <Cesium3DTilesSelection/Library.h>
#include <Cesium3DTilesSelection/TileID.h>
#include "Library.h"

#include <CesiumGeometry/QuadtreeTileID.h>
#include <CesiumGeometry/QuadtreeTileRectangularRange.h>
#include <CesiumGeospatial/BoundingRegion.h>
#include <CesiumGltf/Model.h>
#include <CesiumUtility/ErrorList.h>

#include <gsl/span>
#include <rapidjson/document.h>

#include <cstddef>
Expand All @@ -31,12 +33,12 @@ struct QuantizedMeshLoadResult {
std::optional<CesiumGltf::Model> model;

/**
* @brief An improved bounding volume for this tile.
* @brief An improved bounding region for this tile.
*
* If this is available, then it is more accurate than the one the tile used
* originally.
*/
std::optional<BoundingVolume> updatedBoundingVolume{};
std::optional<CesiumGeospatial::BoundingRegion> updatedBoundingVolume{};

/**
* @brief Available quadtree tiles discovered as a result of loading this
Expand All @@ -63,7 +65,7 @@ struct QuantizedMeshMetadataResult {
/**
* @brief Loads `quantized-mesh-1.0` terrain data.
*/
class CESIUM3DTILESSELECTION_API QuantizedMeshLoader final {
class CESIUM3DTILESCONTENT_API QuantizedMeshLoader final {
public:
/**
* @brief Create a {@link QuantizedMeshLoadResult} from the given data.
Expand All @@ -75,8 +77,8 @@ class CESIUM3DTILESSELECTION_API QuantizedMeshLoader final {
* @return The {@link QuantizedMeshLoadResult}
*/
static QuantizedMeshLoadResult load(
const TileID& tileID,
const BoundingVolume& tileBoundingVolume,
const CesiumGeometry::QuadtreeTileID& tileID,
const CesiumGeospatial::BoundingRegion& tileBoundingVolume,
const std::string& url,
const gsl::span<const std::byte>& data,
bool enableWaterMask);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#pragma once

#include <Cesium3DTilesSelection/TilesetExternals.h>
#include <CesiumAsync/Future.h>
#include <CesiumAsync/IAssetAccessor.h>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ namespace Cesium3DTilesSelection {
* any {@link Tileset} is loaded. It will register loaders for the
* different types of tiles that can be encountered.
*/
CESIUM3DTILESSELECTION_API void registerAllTileContentTypes();
CESIUM3DTILESCONTENT_API void registerAllTileContentTypes();

} // namespace Cesium3DTilesSelection
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "CmptToGltfConverter.h"

#include <Cesium3DTilesSelection/GltfConverters.h>
#include <Cesium3DTilesContent/CmptToGltfConverter.h>
#include <Cesium3DTilesContent/GltfConverters.h>

#include <spdlog/fmt/fmt.h>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include <Cesium3DTilesSelection/GltfConverters.h>
#include <Cesium3DTilesContent/GltfConverters.h>

#include <spdlog/spdlog.h>

Expand Down
153 changes: 153 additions & 0 deletions Cesium3DTilesContent/src/GltfUtilities.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#include <Cesium3DTilesContent/GltfUtilities.h>
#include <Cesium3DTilesContent/SkirtMeshMetadata.h>
#include <CesiumGeometry/Axis.h>
#include <CesiumGeometry/Transforms.h>
#include <CesiumGeospatial/BoundingRegionBuilder.h>
#include <CesiumGltf/AccessorView.h>
#include <CesiumGltf/ExtensionCesiumRTC.h>

#include <vector>

namespace Cesium3DTilesSelection {
/*static*/ glm::dmat4x4 GltfUtilities::applyRtcCenter(
const CesiumGltf::Model& gltf,
const glm::dmat4x4& rootTransform) {
const CesiumGltf::ExtensionCesiumRTC* cesiumRTC =
gltf.getExtension<CesiumGltf::ExtensionCesiumRTC>();
if (cesiumRTC == nullptr) {
return rootTransform;
}
const std::vector<double>& rtcCenter = cesiumRTC->center;
if (rtcCenter.size() != 3) {
return rootTransform;
}
const double x = rtcCenter[0];
const double y = rtcCenter[1];
const double z = rtcCenter[2];
const glm::dmat4x4 rtcTransform(
glm::dvec4(1.0, 0.0, 0.0, 0.0),
glm::dvec4(0.0, 1.0, 0.0, 0.0),
glm::dvec4(0.0, 0.0, 1.0, 0.0),
glm::dvec4(x, y, z, 1.0));
return rootTransform * rtcTransform;
}

/*static*/ glm::dmat4x4 GltfUtilities::applyGltfUpAxisTransform(
const CesiumGltf::Model& model,
const glm::dmat4x4& rootTransform) {
auto gltfUpAxisIt = model.extras.find("gltfUpAxis");
if (gltfUpAxisIt == model.extras.end()) {
// The default up-axis of glTF is the Y-axis, and no other
// up-axis was specified. Transform the Y-axis to the Z-axis,
// to match the 3D Tiles specification
return rootTransform * CesiumGeometry::Transforms::Y_UP_TO_Z_UP;
}
const CesiumUtility::JsonValue& gltfUpAxis = gltfUpAxisIt->second;
int gltfUpAxisValue = static_cast<int>(gltfUpAxis.getSafeNumberOrDefault(1));
if (gltfUpAxisValue == static_cast<int>(CesiumGeometry::Axis::X)) {
return rootTransform * CesiumGeometry::Transforms::X_UP_TO_Z_UP;
} else if (gltfUpAxisValue == static_cast<int>(CesiumGeometry::Axis::Y)) {
return rootTransform * CesiumGeometry::Transforms::Y_UP_TO_Z_UP;
} else if (gltfUpAxisValue == static_cast<int>(CesiumGeometry::Axis::Z)) {
// No transform required
}
return rootTransform;
}

/*static*/ CesiumGeospatial::BoundingRegion
GltfUtilities::computeBoundingRegion(
const CesiumGltf::Model& gltf,
const glm::dmat4& transform) {
glm::dmat4 rootTransform = transform;
rootTransform = applyRtcCenter(gltf, rootTransform);
rootTransform = applyGltfUpAxisTransform(gltf, rootTransform);

// When computing the tile's bounds, ignore tiles that are less than 1/1000th
// of a tile width from the North or South pole. Longitudes cannot be trusted
// at such extreme latitudes.
CesiumGeospatial::BoundingRegionBuilder computedBounds;

gltf.forEachPrimitiveInScene(
-1,
[&rootTransform, &computedBounds](
const CesiumGltf::Model& gltf_,
const CesiumGltf::Node& /*node*/,
const CesiumGltf::Mesh& /*mesh*/,
const CesiumGltf::MeshPrimitive& primitive,
const glm::dmat4& nodeTransform) {
auto positionIt = primitive.attributes.find("POSITION");
if (positionIt == primitive.attributes.end()) {
return;
}

const int positionAccessorIndex = positionIt->second;
if (positionAccessorIndex < 0 ||
positionAccessorIndex >= static_cast<int>(gltf_.accessors.size())) {
return;
}

const glm::dmat4 fullTransform = rootTransform * nodeTransform;

const CesiumGltf::AccessorView<glm::vec3> positionView(
gltf_,
positionAccessorIndex);
if (positionView.status() != CesiumGltf::AccessorViewStatus::Valid) {
return;
}

std::optional<SkirtMeshMetadata> skirtMeshMetadata =
SkirtMeshMetadata::parseFromGltfExtras(primitive.extras);
int64_t vertexBegin, vertexEnd;
if (skirtMeshMetadata.has_value()) {
vertexBegin = skirtMeshMetadata->noSkirtVerticesBegin;
vertexEnd = skirtMeshMetadata->noSkirtVerticesBegin +
skirtMeshMetadata->noSkirtVerticesCount;
} else {
vertexBegin = 0;
vertexEnd = positionView.size();
}

for (int64_t i = vertexBegin; i < vertexEnd; ++i) {
// Get the ECEF position
const glm::vec3 position = positionView[i];
const glm::dvec3 positionEcef =
glm::dvec3(fullTransform * glm::dvec4(position, 1.0));

// Convert it to cartographic
std::optional<CesiumGeospatial::Cartographic> cartographic =
CesiumGeospatial::Ellipsoid::WGS84.cartesianToCartographic(
positionEcef);
if (!cartographic) {
continue;
}

computedBounds.expandToIncludePosition(*cartographic);
}
});

return computedBounds.toRegion();
}

std::vector<std::string_view>
GltfUtilities::parseGltfCopyright(const CesiumGltf::Model& gltf) {
std::vector<std::string_view> result;
if (gltf.asset.copyright) {
const std::string_view copyright = *gltf.asset.copyright;
if (copyright.size() > 0) {
size_t start = 0;
size_t end;
size_t ltrim;
size_t rtrim;
do {
ltrim = copyright.find_first_not_of(" \t", start);
end = copyright.find(';', ltrim);
rtrim = copyright.find_last_not_of(" \t", end - 1);
result.emplace_back(copyright.substr(ltrim, rtrim - ltrim + 1));
start = end + 1;
} while (end != std::string::npos);
}
}

return result;
}
} // namespace Cesium3DTilesSelection
Loading

0 comments on commit c561b64

Please sign in to comment.