Merge pull request #200 from CesiumGS/add-gltfupaxis-support

Add gltfupaxis support
This commit is contained in:
baothientran 2021-04-12 12:05:41 -04:00 committed by GitHub
commit 8b0041c452
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 276 additions and 2 deletions

View File

@ -4,6 +4,8 @@
- Gave glTFs created from quantized-mesh terrain tiles a more sensible material with a `metallicFactor` of 0.0 and a `roughnessFactor` of 1.0. Previously the default glTF material was used, which has a `metallicFactor` of 1.0, leading to an undesirable appearance.
- Reported zero-length images as non-errors as `BingMapsRasterOverlay` purposely requests that the Bing servers return a zero-length image for non-existent tiles.
- Added an `Axis` enum and `AxisTransforms` class for coordinate system transforms
- Added support for the legacy `gltfUpVector` string property in the `asset` part of tilesets. The up vector is read and passed as an `Axis` in the `extras["gltfUpVector"]` property, so that receivers may rotate the glTF model's up-vector to match the Z-up convention of 3D Tiles.
### v0.1.0 - 2021-03-30

View File

@ -9,6 +9,7 @@
#include "Cesium3DTiles/ViewUpdateResult.h"
#include "CesiumAsync/AsyncSystem.h"
#include "CesiumAsync/IAssetRequest.h"
#include "CesiumGeometry/Axis.h"
#include "CesiumGeometry/QuadtreeTileAvailability.h"
#include <atomic>
#include <memory>
@ -417,6 +418,19 @@ public:
return this->_supportsRasterOverlays;
}
/**
* @brief Returns the value indicating the glTF up-axis.
*
* This function is not supposed to be called by clients.
*
* The value indicates the axis, via 0=X, 1=Y, 2=Z.
*
* @return The value representing the axis
*/
CesiumGeometry::Axis getGltfUpAxis() const noexcept {
return this->_gltfUpAxis;
}
private:
/**
* @brief The result of traversing one branch of the tile hierarchy.
@ -713,6 +727,18 @@ private:
bool _supportsRasterOverlays;
/**
* @brief The axis that was declared as the "up-axis" for glTF content.
*
* The glTF specification mandates that the Y-axis is the "up"-axis, so the
* default value is {@link Axis::Y}. Older tilesets may contain a string
* property in the "assets" dictionary, named "gltfUpAxis", indicating a
* different up-axis. Although the "gltfUpAxis" property is no longer part of
* the 3D tiles specification, it is still considered for backward
* compatibility.
*/
CesiumGeometry::Axis _gltfUpAxis;
static void addTileToLoadQueue(
std::vector<LoadRecord>& loadQueue,
const ViewState& viewState,

View File

@ -6,6 +6,7 @@
#include "CesiumAsync/IAssetAccessor.h"
#include "CesiumAsync/IAssetResponse.h"
#include "CesiumAsync/ITaskProcessor.h"
#include "CesiumGeometry/Axis.h"
#include "TileUtilities.h"
#include "upsampleGltfForRasterOverlays.h"
@ -234,10 +235,12 @@ void Tile::loadContent() {
};
TileContentLoadInput loadInput(tileset.getExternals().pLogger, *this);
const CesiumGeometry::Axis gltfUpAxis = tileset.getGltfUpAxis();
std::move(maybeRequestFuture.value())
.thenInWorkerThread(
[loadInput = std::move(loadInput),
projections = std::move(projections),
gltfUpAxis,
pPrepareRendererResources =
tileset.getExternals().pPrepareRendererResources,
pLogger = tileset.getExternals().pLogger](
@ -287,6 +290,12 @@ void Tile::loadContent() {
void* pRendererResources = nullptr;
if (pContent->model) {
// TODO The `extras` are currently the only way to pass
// arbitrary information to the consumer, so the up-axis
// is stored here:
pContent->model.value().extras["gltfUpAxis"] = gltfUpAxis;
const BoundingVolume& boundingVolume =
loadInput.tileBoundingVolume;
Tile::generateTextureCoordinates(

View File

@ -9,6 +9,7 @@
#include "CesiumAsync/IAssetAccessor.h"
#include "CesiumAsync/IAssetResponse.h"
#include "CesiumAsync/ITaskProcessor.h"
#include "CesiumGeometry/Axis.h"
#include "CesiumGeometry/QuadtreeTileAvailability.h"
#include "CesiumGeospatial/GeographicProjection.h"
#include "CesiumUtility/JsonHelpers.h"
@ -57,7 +58,8 @@ Tileset::Tileset(
_loadedTiles(),
_overlays(*this),
_tileDataBytes(0),
_supportsRasterOverlays(false) {
_supportsRasterOverlays(false),
_gltfUpAxis(CesiumGeometry::Axis::Y) {
++this->_loadsInProgress;
this->_loadTilesetJson(url);
}
@ -508,6 +510,55 @@ void Tileset::_loadTilesetJson(
});
}
namespace {
/**
* @brief Obtains the up-axis that should be used for glTF content of the
* tileset.
*
* If the given tileset JSON does not contain an `asset.gltfUpAxis` string
* property, then the default value of CesiumGeometry::Axis::Y is returned.
*
* Otherwise, a warning is printed, saying that the `gltfUpAxis` property is
* not strictly compliant to the 3D tiles standard, and the return value
* will depend on the string value of this property, which may be "X", "Y", or
* "Z", case-insensitively, causing CesiumGeometry::Axis::X,
* CesiumGeometry::Axis::Y, or CesiumGeometry::Axis::Z to be returned,
* respectively.
*
* @param tileset The tileset JSON
* @return The up-axis to use for glTF content
*/
CesiumGeometry::Axis obtainGltfUpAxis(const rapidjson::Document& tileset) {
auto assetIt = tileset.FindMember("asset");
if (assetIt == tileset.MemberEnd()) {
return CesiumGeometry::Axis::Y;
}
const rapidjson::Value& assetJson = assetIt->value;
auto gltfUpAxisIt = assetJson.FindMember("gltfUpAxis");
if (gltfUpAxisIt == assetJson.MemberEnd()) {
return CesiumGeometry::Axis::Y;
}
SPDLOG_WARN("The tileset contains a gltfUpAxis property. "
"This property is not part of the specification. "
"All glTF content should use the Y-axis as the up-axis.");
const rapidjson::Value& gltfUpAxisJson = gltfUpAxisIt->value;
auto gltfUpAxisString = std::string(gltfUpAxisJson.GetString());
if (gltfUpAxisString == "X" || gltfUpAxisString == "x") {
return CesiumGeometry::Axis::X;
}
if (gltfUpAxisString == "Y" || gltfUpAxisString == "y") {
return CesiumGeometry::Axis::Y;
}
if (gltfUpAxisString == "Z" || gltfUpAxisString == "z") {
return CesiumGeometry::Axis::Z;
}
SPDLOG_WARN("Unknown gltfUpAxis: {}, using default (Y)", gltfUpAxisString);
return CesiumGeometry::Axis::Y;
}
} // namespace
/*static*/ Tileset::LoadResult Tileset::_handleTilesetResponse(
std::shared_ptr<IAssetRequest>&& pRequest,
std::unique_ptr<TileContext>&& pContext,
@ -547,6 +598,8 @@ void Tileset::_loadTilesetJson(
return LoadResult{std::move(pContext), nullptr, false};
}
pContext->pTileset->_gltfUpAxis = obtainGltfUpAxis(tileset);
std::unique_ptr<Tile> pRootTile = std::make_unique<Tile>();
pRootTile->setContext(pContext.get());

View File

@ -0,0 +1,26 @@
#pragma once
#include "CesiumGeometry/Library.h"
namespace CesiumGeometry {
/**
* @brief An enum describing the x, y, and z axes
*/
enum CESIUMGEOMETRY_API Axis {
/**
* @brief The x-axis
*/
X,
/**
* @brief The y-axis
*/
Y,
/**
* @brief The z-axis
*/
Z
};
} // namespace CesiumGeometry

View File

@ -0,0 +1,50 @@
#pragma once
#include "CesiumGeometry/Library.h"
#include <glm/mat3x3.hpp>
namespace CesiumGeometry {
/**
* @brief Coordinate system conversion matrices
*/
struct CESIUMGEOMETRY_API AxisTransforms final {
/**
* @brief A matrix to convert from y-up to z-up orientation,
* by rotating about PI/2 around the x-axis
*/
static const glm::dmat4 Y_UP_TO_Z_UP;
/**
* @brief A matrix to convert from z-up to y-up orientation,
* by rotating about -PI/2 around the x-axis
*/
static const glm::dmat4 Z_UP_TO_Y_UP;
/**
* @brief A matrix to convert from x-up to z-up orientation,
* by rotating about -PI/2 around the y-axis
*/
static const glm::dmat4 X_UP_TO_Z_UP;
/**
* @brief A matrix to convert from z-up to x-up orientation,
* by rotating about PI/2 around the y-axis
*/
static const glm::dmat4 Z_UP_TO_X_UP;
/**
* @brief A matrix to convert from x-up to y-up orientation,
* by rotating about PI/2 around the z-axis
*/
static const glm::dmat4 X_UP_TO_Y_UP;
/**
* @brief A matrix to convert from y-up to x-up orientation,
* by rotating about -PI/2 around the z-axis
*/
static const glm::dmat4 Y_UP_TO_X_UP;
};
} // namespace CesiumGeometry

View File

@ -1,6 +1,6 @@
#pragma once
#include "CesiumGeometry/OctreeTileID.h"
#include "CesiumGeometry/Library.h"
namespace CesiumGeometry {

View File

@ -0,0 +1,65 @@
#include "CesiumGeometry/AxisTransforms.h"
#include <glm/mat3x3.hpp>
namespace CesiumGeometry {
namespace {
// Initialize with a function instead of inline to avoid an
// internal compiler error in MSVC v14.27.29110.
glm::dmat4 createYupToZup() {
return glm::dmat4(
glm::dvec4(1.0, 0.0, 0.0, 0.0),
glm::dvec4(0.0, 0.0, 1.0, 0.0),
glm::dvec4(0.0, -1.0, 0.0, 0.0),
glm::dvec4(0.0, 0.0, 0.0, 1.0));
}
glm::dmat4 createZupToYup() {
return glm::dmat4(
glm::dvec4(1.0, 0.0, 0.0, 0.0),
glm::dvec4(0.0, 0.0, -1.0, 0.0),
glm::dvec4(0.0, 1.0, 0.0, 0.0),
glm::dvec4(0.0, 0.0, 0.0, 1.0));
}
glm::dmat4 createXupToZup() {
return glm::dmat4(
glm::dvec4(0.0, 0.0, 1.0, 0.0),
glm::dvec4(0.0, 1.0, 0.0, 0.0),
glm::dvec4(-1.0, 0.0, 0.0, 0.0),
glm::dvec4(0.0, 0.0, 0.0, 1.0));
}
glm::dmat4 createZupToXup() {
return glm::dmat4(
glm::dvec4(0.0, 0.0, -1.0, 0.0),
glm::dvec4(0.0, 1.0, 0.0, 0.0),
glm::dvec4(1.0, 0.0, 0.0, 0.0),
glm::dvec4(0.0, 0.0, 0.0, 1.0));
}
glm::dmat4 createXupToYup() {
return glm::dmat4(
glm::dvec4(0.0, 1.0, 0.0, 0.0),
glm::dvec4(-1.0, 0.0, 0.0, 0.0),
glm::dvec4(0.0, 0.0, 1.0, 0.0),
glm::dvec4(0.0, 0.0, 0.0, 1.0));
}
glm::dmat4 createYupToXup() {
return glm::dmat4(
glm::dvec4(0.0, -1.0, 0.0, 0.0),
glm::dvec4(1.0, 0.0, 0.0, 0.0),
glm::dvec4(0.0, 0.0, 1.0, 0.0),
glm::dvec4(0.0, 0.0, 0.0, 1.0));
}
} // namespace
const glm::dmat4 AxisTransforms::Y_UP_TO_Z_UP = createYupToZup();
const glm::dmat4 AxisTransforms::Z_UP_TO_Y_UP = createZupToYup();
const glm::dmat4 AxisTransforms::X_UP_TO_Z_UP = createXupToZup();
const glm::dmat4 AxisTransforms::Z_UP_TO_X_UP = createZupToXup();
const glm::dmat4 AxisTransforms::X_UP_TO_Y_UP = createXupToYup();
const glm::dmat4 AxisTransforms::Y_UP_TO_X_UP = createYupToXup();
} // namespace CesiumGeometry

View File

@ -0,0 +1,43 @@
#include "CesiumGeometry/AxisTransforms.h"
#include "CesiumUtility/Math.h"
#include "catch2/catch.hpp"
TEST_CASE("AxisTransforms convert the axes correctly") {
glm::dvec4 X_AXIS{1.0, 0.0, 0.0, 0.0};
glm::dvec4 Y_AXIS{0.0, 1.0, 0.0, 0.0};
glm::dvec4 Z_AXIS{0.0, 0.0, 1.0, 0.0};
SECTION("Y_UP_TO_Z_UP transforms X to X, Y to -Z, and Z to Y") {
REQUIRE(X_AXIS * CesiumGeometry::AxisTransforms::Y_UP_TO_Z_UP == X_AXIS);
REQUIRE(Y_AXIS * CesiumGeometry::AxisTransforms::Y_UP_TO_Z_UP == -Z_AXIS);
REQUIRE(Z_AXIS * CesiumGeometry::AxisTransforms::Y_UP_TO_Z_UP == Y_AXIS);
}
SECTION("Z_UP_TO_Y_UP transforms X to X, Y to Z, and Z to -Y") {
REQUIRE(X_AXIS * CesiumGeometry::AxisTransforms::Z_UP_TO_Y_UP == X_AXIS);
REQUIRE(Y_AXIS * CesiumGeometry::AxisTransforms::Z_UP_TO_Y_UP == Z_AXIS);
REQUIRE(Z_AXIS * CesiumGeometry::AxisTransforms::Z_UP_TO_Y_UP == -Y_AXIS);
}
SECTION("X_UP_TO_Z_UP transforms X to -Z, Y to Y, and Z to X") {
REQUIRE(X_AXIS * CesiumGeometry::AxisTransforms::X_UP_TO_Z_UP == -Z_AXIS);
REQUIRE(Y_AXIS * CesiumGeometry::AxisTransforms::X_UP_TO_Z_UP == Y_AXIS);
REQUIRE(Z_AXIS * CesiumGeometry::AxisTransforms::X_UP_TO_Z_UP == X_AXIS);
}
SECTION("Z_UP_TO_X_UP transforms X to Z, Y to Y, and Z to -X") {
REQUIRE(X_AXIS * CesiumGeometry::AxisTransforms::Z_UP_TO_X_UP == Z_AXIS);
REQUIRE(Y_AXIS * CesiumGeometry::AxisTransforms::Z_UP_TO_X_UP == Y_AXIS);
REQUIRE(Z_AXIS * CesiumGeometry::AxisTransforms::Z_UP_TO_X_UP == -X_AXIS);
}
SECTION("X_UP_TO_Y_UP transforms X to -Y, Y to X, and Z to Z") {
REQUIRE(X_AXIS * CesiumGeometry::AxisTransforms::X_UP_TO_Y_UP == -Y_AXIS);
REQUIRE(Y_AXIS * CesiumGeometry::AxisTransforms::X_UP_TO_Y_UP == X_AXIS);
REQUIRE(Z_AXIS * CesiumGeometry::AxisTransforms::X_UP_TO_Y_UP == Z_AXIS);
}
SECTION("Y_UP_TO_X_UP transforms X to Y, Y to -X, and Z to Z") {
REQUIRE(X_AXIS * CesiumGeometry::AxisTransforms::Y_UP_TO_X_UP == Y_AXIS);
REQUIRE(Y_AXIS * CesiumGeometry::AxisTransforms::Y_UP_TO_X_UP == -X_AXIS);
REQUIRE(Z_AXIS * CesiumGeometry::AxisTransforms::Y_UP_TO_X_UP == Z_AXIS);
}
}