Skip to content

Commit

Permalink
Merge pull request #854 from CesiumGS/i3dm-2024
Browse files Browse the repository at this point in the history
Support 3D Tile I3dm legacy tile format
  • Loading branch information
j9liu committed May 29, 2024
2 parents e6883ad + ba68601 commit e1ed4db
Show file tree
Hide file tree
Showing 32 changed files with 1,825 additions and 225 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
- Added `getNodeTransform`, `setNodeTransform`, `removeUnusedTextures`, `removeUnusedSamplers`, `removeUnusedImages`, `removeUnusedAccessors`, `removeUnusedBufferViews`, and `compactBuffers` methods to `GltfUtilities`.
- Added `postprocessGltf` method to `GltfReader`.
- `Model::merge` now merges the `EXT_structural_metadata` and `EXT_mesh_features` extensions. It also now returns an `ErrorList`, used to report warnings and errors about the merge process.
- Added support for I3dm 3D Tile content files.

##### Fixes :wrench:

Expand Down
8 changes: 4 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ if (NOT DEFINED GLOB_USE_CONFIGURE_DEPENDS)
)
endif()

set(CESIUM_DEBUG_POSTFIX "d")
set(CESIUM_RELEASE_POSTFIX "")
set(CESIUM_DEBUG_POSTFIX "d" CACHE STRING "debug postfix for cesium native")
set(CESIUM_RELEASE_POSTFIX "" CACHE STRING "release postfix for cesium native")

set(CMAKE_DEBUG_POSTFIX ${CESIUM_DEBUG_POSTFIX})
set(CMAKE_RELEASE_POSTFIX ${CESIUM_RELEASE_POSTFIX})
Expand Down Expand Up @@ -161,8 +161,8 @@ endfunction()
add_subdirectory(extern EXCLUDE_FROM_ALL)

# These libraries override the debug postfix, so re-override it.
set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX ${CESIUM_DEBUG_POSTFIX})
set_target_properties(tinyxml2 PROPERTIES DEBUG_POSTFIX ${CESIUM_DEBUG_POSTFIX})
set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX "${CESIUM_DEBUG_POSTFIX}")
set_target_properties(tinyxml2 PROPERTIES DEBUG_POSTFIX "${CESIUM_DEBUG_POSTFIX}")

# Public Targets
add_subdirectory(CesiumUtility)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "GltfConverterResult.h"

#include <CesiumAsync/Future.h>
#include <CesiumGltf/Model.h>
#include <CesiumGltfReader/GltfReader.h>

Expand All @@ -10,9 +11,12 @@
#include <optional>

namespace Cesium3DTilesContent {
struct AssetFetcher;

struct B3dmToGltfConverter {
static GltfConverterResult convert(
static CesiumAsync::Future<GltfConverterResult> convert(
const gsl::span<const std::byte>& b3dmBinary,
const CesiumGltfReader::GltfReaderOptions& options);
const CesiumGltfReader::GltfReaderOptions& options,
const AssetFetcher& assetFetcher);
};
} // namespace Cesium3DTilesContent
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
#pragma once

#include <Cesium3DTilesContent/GltfConverterResult.h>
#include <CesiumAsync/Future.h>
#include <CesiumGltfReader/GltfReader.h>

#include <gsl/span>

#include <cstddef>

namespace Cesium3DTilesContent {
struct AssetFetcher;

struct BinaryToGltfConverter {
public:
static GltfConverterResult convert(
static CesiumAsync::Future<GltfConverterResult> convert(
const gsl::span<const std::byte>& gltfBinary,
const CesiumGltfReader::GltfReaderOptions& options);
const CesiumGltfReader::GltfReaderOptions& options,
const AssetFetcher& assetFetcher);

private:
static GltfConverterResult convertImmediate(
const gsl::span<const std::byte>& gltfBinary,
const CesiumGltfReader::GltfReaderOptions& options);
static CesiumGltfReader::GltfReader _gltfReader;
};
} // namespace Cesium3DTilesContent
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
#pragma once

#include <Cesium3DTilesContent/GltfConverterResult.h>
#include <CesiumAsync/Future.h>
#include <CesiumGltfReader/GltfReader.h>

#include <gsl/span>

#include <cstddef>

namespace Cesium3DTilesContent {
struct AssetFetcher;

struct CmptToGltfConverter {
static GltfConverterResult convert(
static CesiumAsync::Future<GltfConverterResult> convert(
const gsl::span<const std::byte>& cmptBinary,
const CesiumGltfReader::GltfReaderOptions& options);
const CesiumGltfReader::GltfReaderOptions& options,
const AssetFetcher& assetFetcher);
};
} // namespace Cesium3DTilesContent
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
#include <CesiumGltf/Model.h>
#include <CesiumUtility/ErrorList.h>

#include <glm/common.hpp>
#include <glm/gtx/quaternion.hpp>

#include <optional>
#include <string>
#include <vector>

namespace Cesium3DTilesContent {
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#pragma once

#include <Cesium3DTilesContent/GltfConverters.h>
#include <CesiumAsync/IAssetAccessor.h>
#include <CesiumAsync/IAssetRequest.h>
#include <CesiumGltf/AccessorView.h>
#include <CesiumGltf/PropertyTransformations.h>
#include <CesiumUtility/ErrorList.h>

#include <glm/fwd.hpp>
#include <rapidjson/document.h>

#include <cstdint>
#include <optional>
#include <vector>

namespace CesiumGltf {
class Model;
class Buffer;
} // namespace CesiumGltf

namespace Cesium3DTilesContent {

namespace GltfConverterUtility {
std::optional<uint32_t> parseOffsetForSemantic(
const rapidjson::Document& document,
const char* semantic,
CesiumUtility::ErrorList& errorList);

typedef bool (rapidjson::Value::*ValuePredicate)() const;

template <typename T> bool isValue(const rapidjson::Value& value);
template <typename T> T getValue(const rapidjson::Value& value);

template <typename T>
std::optional<T> getOptional(const rapidjson::Value& value) {
if (isValue<T>(value)) {
return std::make_optional(getValue<T>(value));
}
return {};
}

template <typename T>
std::optional<T>
getValue(const rapidjson::Document& document, const char* semantic) {
const auto valueIt = document.FindMember(semantic);
if (valueIt == document.MemberEnd() || !isValue<T>(valueIt->value)) {
return {};
}
return std::make_optional(getValue<T>(valueIt->value));
}

template <> inline bool isValue<bool>(const rapidjson::Value& value) {
return value.IsBool();
}

template <> inline bool getValue<bool>(const rapidjson::Value& value) {
return value.GetBool();
}

template <> inline bool isValue<uint32_t>(const rapidjson::Value& value) {
return value.IsUint();
}

template <> inline uint32_t getValue<uint32_t>(const rapidjson::Value& value) {
return value.GetUint();
}

bool validateJsonArrayValues(
const rapidjson::Value& arrayValue,
uint32_t expectedLength,
ValuePredicate predicate);

std::optional<glm::dvec3>
parseArrayValueDVec3(const rapidjson::Value& arrayValue);

std::optional<glm::dvec3>
parseArrayValueDVec3(const rapidjson::Document& document, const char* name);

int32_t
createBufferInGltf(CesiumGltf::Model& gltf, std::vector<std::byte> buffer = {});

int32_t createBufferViewInGltf(
CesiumGltf::Model& gltf,
const int32_t bufferId,
const int64_t byteLength,
const int64_t byteStride);

int32_t createAccessorInGltf(
CesiumGltf::Model& gltf,
const int32_t bufferViewId,
const int32_t componentType,
const int64_t count,
const std::string type);

/**
* Applies the given relative-to-center (RTC) translation to the transforms of
* all nodes in the glTF. This is useful in converting i3dm files, where the RTC
* translation must be applied to the model before the i3dm instance
* transform. It's also the 3D Tiles 1.1 "way" to do away with RTC and encode it
* directly in the glTF.
*/
void applyRtcToNodes(CesiumGltf::Model& gltf, const glm::dvec3& rtc);

template <typename GlmType, typename GLTFType>
GlmType toGlm(const GLTFType& gltfVal);

template <typename GlmType, typename ComponentType>
GlmType toGlm(const CesiumGltf::AccessorTypes::VEC3<ComponentType>& gltfVal) {
return GlmType(gltfVal.value[0], gltfVal.value[1], gltfVal.value[2]);
}

template <typename GlmType, typename ComponentType>
GlmType
toGlmQuat(const CesiumGltf::AccessorTypes::VEC4<ComponentType>& gltfVal) {
if constexpr (std::is_same<ComponentType, float>()) {
return GlmType(
gltfVal.value[3],
gltfVal.value[0],
gltfVal.value[1],
gltfVal.value[2]);
} else {
return GlmType(
CesiumGltf::normalize(gltfVal.value[3]),
CesiumGltf::normalize(gltfVal.value[0]),
CesiumGltf::normalize(gltfVal.value[1]),
CesiumGltf::normalize(gltfVal.value[2]));
}
}

} // namespace GltfConverterUtility
} // namespace Cesium3DTilesContent
58 changes: 50 additions & 8 deletions Cesium3DTilesContent/include/Cesium3DTilesContent/GltfConverters.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "Library.h"

#include <Cesium3DTilesContent/GltfConverterResult.h>
#include <CesiumAsync/Future.h>
#include <CesiumAsync/IAssetAccessor.h>
#include <CesiumGltfReader/GltfReader.h>

#include <gsl/span>
Expand All @@ -12,6 +14,39 @@
#include <string_view>

namespace Cesium3DTilesContent {

struct AssetFetcherResult {
std::vector<std::byte> bytes;
CesiumUtility::ErrorList errorList;
};

/**
* Object that makes a recursive request to fetch an asset, mostly for the
* benefit of i3dm files.
*/
struct CESIUM3DTILESCONTENT_API AssetFetcher {
AssetFetcher(
const CesiumAsync::AsyncSystem& asyncSystem_,
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor_,
const std::string& baseUrl_,
const glm::dmat4 tileTransform_,
const std::vector<CesiumAsync::IAssetAccessor::THeader>& requestHeaders_)
: asyncSystem(asyncSystem_),
pAssetAccessor(pAssetAccessor_),
baseUrl(baseUrl_),
tileTransform(tileTransform_),
requestHeaders(requestHeaders_) {}

CesiumAsync::Future<AssetFetcherResult>
get(const std::string& relativeUrl) const;

const CesiumAsync::AsyncSystem& asyncSystem;
const std::shared_ptr<CesiumAsync::IAssetAccessor> pAssetAccessor;
const std::string baseUrl;
glm::dmat4 tileTransform; // For ENU transforms in i3dm
const std::vector<CesiumAsync::IAssetAccessor::THeader>& requestHeaders;
};

/**
* @brief Creates {@link GltfConverterResult} objects from a
* a binary content.
Expand All @@ -32,9 +67,10 @@ class CESIUM3DTILESCONTENT_API GltfConverters {
* @brief A function pointer that can create a {@link GltfConverterResult} from a
* tile binary content.
*/
using ConverterFunction = GltfConverterResult (*)(
using ConverterFunction = CesiumAsync::Future<GltfConverterResult> (*)(
const gsl::span<const std::byte>& content,
const CesiumGltfReader::GltfReaderOptions& options);
const CesiumGltfReader::GltfReaderOptions& options,
const AssetFetcher& subprocessor);

/**
* @brief Register the given function for the given magic header.
Expand Down Expand Up @@ -117,13 +153,16 @@ class CESIUM3DTILESCONTENT_API GltfConverters {
* the converter.
* @param content The tile binary content that may contains the magic header
* to look up the converter and is used to convert to gltf model.
* @param options The {@link CesiumGltfReader::GltfReaderOptions} for how to read a glTF.
* @param options The {@link CesiumGltfReader::GltfReaderOptions} for how to
* read a glTF.
* @param assetFetcher An object that can perform recursive asset requests.
* @return The {@link GltfConverterResult} that stores the gltf model converted from the binary data.
*/
static GltfConverterResult convert(
static CesiumAsync::Future<GltfConverterResult> convert(
const std::string& filePath,
const gsl::span<const std::byte>& content,
const CesiumGltfReader::GltfReaderOptions& options);
const CesiumGltfReader::GltfReaderOptions& options,
const AssetFetcher& assetFetcher);

/**
* @brief Creates the {@link GltfConverterResult} from the given
Expand All @@ -142,12 +181,15 @@ class CESIUM3DTILESCONTENT_API GltfConverters {
*
* @param content The tile binary content that may contains the magic header
* to look up the converter and is used to convert to gltf model.
* @param options The {@link CesiumGltfReader::GltfReaderOptions} for how to read a glTF.
* @param options The {@link CesiumGltfReader::GltfReaderOptions} for how to
* read a glTF.
* @param assetFetcher An object that can perform recursive asset requests.
* @return The {@link GltfConverterResult} that stores the gltf model converted from the binary data.
*/
static GltfConverterResult convert(
static CesiumAsync::Future<GltfConverterResult> convert(
const gsl::span<const std::byte>& content,
const CesiumGltfReader::GltfReaderOptions& options);
const CesiumGltfReader::GltfReaderOptions& options,
const AssetFetcher& assetFetcher);

private:
static std::string toLowerCase(const std::string_view& str);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <Cesium3DTilesContent/GltfConverterResult.h>
#include <CesiumAsync/Future.h>
#include <CesiumGltf/Model.h>
#include <CesiumGltfReader/GltfReader.h>

#include <glm/mat4x4.hpp>
#include <gsl/span>

#include <optional>

namespace Cesium3DTilesContent {
struct AssetFetcher;

struct I3dmToGltfConverter {
static CesiumAsync::Future<GltfConverterResult> convert(
const gsl::span<const std::byte>& instancesBinary,
const CesiumGltfReader::GltfReaderOptions& options,
const AssetFetcher& assetFetcher);
};
} // namespace Cesium3DTilesContent
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "GltfConverterResult.h"

#include <CesiumAsync/Future.h>
#include <CesiumGltf/Model.h>
#include <CesiumGltfReader/GltfReader.h>

Expand All @@ -10,9 +11,12 @@
#include <optional>

namespace Cesium3DTilesContent {
struct AssetFetcher;

struct PntsToGltfConverter {
static GltfConverterResult convert(
static CesiumAsync::Future<GltfConverterResult> convert(
const gsl::span<const std::byte>& pntsBinary,
const CesiumGltfReader::GltfReaderOptions& options);
const CesiumGltfReader::GltfReaderOptions& options,
const AssetFetcher& assetFetcher);
};
} // namespace Cesium3DTilesContent
Loading

0 comments on commit e1ed4db

Please sign in to comment.