Skip to content

Commit effb99a

Browse files
committed
GltfModifier input/output, future-ify apply.
1 parent e6c63b3 commit effb99a

File tree

3 files changed

+141
-74
lines changed

3 files changed

+141
-74
lines changed

Cesium3DTilesSelection/include/Cesium3DTilesSelection/GltfModifier.h

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <CesiumAsync/AsyncSystem.h>
34
#include <CesiumAsync/Future.h>
45
#include <CesiumGltf/Model.h>
56

@@ -10,15 +11,47 @@
1011

1112
namespace CesiumAsync {
1213

13-
class AsyncSystem;
1414
class IAssetAccessor;
1515

1616
} // namespace CesiumAsync
1717

1818
namespace Cesium3DTilesSelection {
1919

20+
class Tile;
2021
class TilesetMetadata;
2122

23+
/**
24+
* @brief The input to the {@link GltfModifier::apply} function.
25+
*/
26+
struct GltfModifierInput {
27+
CesiumAsync::AsyncSystem asyncSystem;
28+
29+
std::shared_ptr<CesiumAsync::IAssetAccessor> pAssetAccessor;
30+
31+
std::shared_ptr<spdlog::logger> pLogger;
32+
33+
/**
34+
* @brief The model to be modified.
35+
*/
36+
const CesiumGltf::Model& previousModel;
37+
38+
/**
39+
* @brief The transformation of the model's coordinates to the tileset's
40+
* coordinate system.
41+
*/
42+
glm::dmat4 tileTransform;
43+
};
44+
45+
/**
46+
* @brief The output of the {@link GltfModifier::apply} function.
47+
*/
48+
struct GltfModifierOutput {
49+
/**
50+
* @brief The new, modified model.
51+
*/
52+
CesiumGltf::Model modifiedModel;
53+
};
54+
2255
/** Abstract class that allows modifying a glTF model after it has been loaded.
2356
* Modifications can include reorganizing the primitives, eg. merging or
2457
* splitting them. Merging primitives can lead to improved rendering
@@ -74,6 +107,7 @@ class GltfModifier {
74107
* @param pLogger The logger to which to log errors and warnings that occur
75108
* during preparation of the `GltfModifier`.
76109
* @param tilesetMetadata The metadata associated with the tileset.
110+
* @param rootTile The root tile of the tileset.
77111
* @returns A future that resolves when the `GltfModifier` is ready to modify
78112
* glTF instances for this tileset. Tileset loading will not proceed until
79113
* this future resolves. If the future rejects, tileset load will proceed but
@@ -83,7 +117,8 @@ class GltfModifier {
83117
const CesiumAsync::AsyncSystem& asyncSystem,
84118
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
85119
const std::shared_ptr<spdlog::logger>& pLogger,
86-
const TilesetMetadata& tilesetMetadata) = 0;
120+
const TilesetMetadata& tilesetMetadata,
121+
const Tile& rootTile) = 0;
87122

88123
/**
89124
* @brief When this modifier has been triggered at least once, this is the
@@ -93,18 +128,14 @@ class GltfModifier {
93128
* @param model Input model that may have to be processed
94129
* @param tileTransform Transformation of the model's tile.
95130
* See {@link Cesium3DTilesSelection::Tile::getTransform}.
96-
* @param rootTranslation Translation of the root tile of the tileset
97131
* @param modifiedModel Target of the transformation process. May be equal to
98132
* the input model.
99133
* @return True if any processing was done and the result placed in the
100134
* modifiedModel parameter, false when no processing was needed, in which case
101135
* the modifiedModel parameter was ignored.
102136
*/
103-
virtual bool apply(
104-
const CesiumGltf::Model& model,
105-
const glm::dmat4& tileTransform,
106-
const glm::dvec4& rootTranslation,
107-
CesiumGltf::Model& modifiedModel) = 0;
137+
virtual CesiumAsync::Future<std::optional<GltfModifierOutput>>
138+
apply(GltfModifierInput&& input) = 0;
108139

109140
private:
110141
/** The current version of the modifier, if it has ever been triggered.

Cesium3DTilesSelection/src/TilesetContentManager.cpp

Lines changed: 94 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,8 @@ CesiumAsync::Future<void> registerGltfModifier(
712712
contentManager.getExternals().asyncSystem,
713713
contentManager.getExternals().pAssetAccessor,
714714
contentManager.getExternals().pLogger,
715-
pExternal ? pExternal->metadata : TilesetMetadata())
715+
pExternal ? pExternal->metadata : TilesetMetadata(),
716+
*pRootTile)
716717
.catchInMainThread([&contentManager](std::exception&&) {
717718
// Disable the failed glTF modifier.
718719
contentManager.getExternals().pGltfModifier.reset();
@@ -1079,51 +1080,65 @@ void TilesetContentManager::loadTileContent(
10791080
if (_externals.pGltfModifier &&
10801081
_externals.pGltfModifier->getCurrentVersion().has_value() &&
10811082
tile.getState() == TileLoadState::Done) {
1082-
auto* renderContent = tile.getContent().getRenderContent();
1083-
if (renderContent &&
1084-
renderContent->getGltfModifierState() == GltfModifier::State::Idle &&
1085-
renderContent->getModel().version !=
1083+
TileRenderContent* pRenderContent = tile.getContent().getRenderContent();
1084+
if (pRenderContent &&
1085+
pRenderContent->getGltfModifierState() == GltfModifier::State::Idle &&
1086+
pRenderContent->getModel().version !=
10861087
_externals.pGltfModifier->getCurrentVersion()) {
1087-
renderContent->setGltfModifierState(GltfModifier::State::WorkerRunning);
1088-
glm::dvec4 rootTranslation = glm::dvec4(0., 0., 0., 1.);
1089-
if (this->_pRootTile)
1090-
rootTranslation = glm::column(this->_pRootTile->getTransform(), 3);
1091-
_externals.asyncSystem
1092-
.runInWorkerThread([pGltfModifier = _externals.pGltfModifier,
1093-
pPrepareRendererResources =
1094-
_externals.pPrepareRendererResources,
1095-
asyncSystem = _externals.asyncSystem,
1096-
&tile,
1097-
rendererOptions = tilesetOptions.rendererOptions,
1098-
rootTranslation] {
1099-
// already known as being non-null
1100-
auto* renderContent = tile.getContent().getRenderContent();
1101-
auto& initialModel = renderContent->getModel();
1102-
CesiumGltf::Model modifiedModel;
1103-
bool const wasModified = pGltfModifier->apply(
1104-
initialModel,
1105-
tile.getTransform(),
1106-
rootTranslation,
1107-
modifiedModel);
1108-
TileLoadResult tileLoadResult;
1109-
tileLoadResult.glTFUpAxis = [&](CesiumGltf::Model const& model) {
1110-
const auto it = model.extras.find("gltfUpAxis");
1111-
if (it == model.extras.end()) {
1112-
CESIUM_ASSERT(false);
1113-
return CesiumGeometry::Axis::Y;
1114-
}
1115-
return static_cast<CesiumGeometry::Axis>(
1116-
it->second.getSafeNumberOrDefault(1));
1117-
}(wasModified ? modifiedModel : initialModel);
1118-
tileLoadResult.contentKind =
1119-
std::move(wasModified ? modifiedModel : initialModel);
1120-
tileLoadResult.state = TileLoadResultState::Success;
1121-
return pPrepareRendererResources->prepareInLoadThread(
1122-
asyncSystem,
1123-
std::move(tileLoadResult),
1124-
tile.getTransform(),
1125-
rendererOptions);
1088+
pRenderContent->setGltfModifierState(GltfModifier::State::WorkerRunning);
1089+
1090+
const CesiumGltf::Model& previousModel = pRenderContent->getModel();
1091+
1092+
this->_externals.asyncSystem
1093+
.runInWorkerThread([asyncSystem = this->_externals.asyncSystem,
1094+
pAssetAccessor = this->_externals.pAssetAccessor,
1095+
pLogger = this->_externals.pLogger,
1096+
pGltfModifier = _externals.pGltfModifier,
1097+
&previousModel,
1098+
tileTransform = tile.getTransform()] {
1099+
return pGltfModifier->apply(GltfModifierInput{
1100+
.asyncSystem = asyncSystem,
1101+
.pAssetAccessor = pAssetAccessor,
1102+
.pLogger = pLogger,
1103+
.previousModel = previousModel,
1104+
.tileTransform = tileTransform});
11261105
})
1106+
.thenInWorkerThread(
1107+
[asyncSystem = this->_externals.asyncSystem,
1108+
&previousModel,
1109+
pPrepareRendererResources =
1110+
this->_externals.pPrepareRendererResources,
1111+
tileTransform = tile.getTransform(),
1112+
rendererOptions = tilesetOptions.rendererOptions](
1113+
std::optional<GltfModifierOutput>&& modified) {
1114+
const CesiumGltf::Model& model =
1115+
modified ? modified->modifiedModel : previousModel;
1116+
1117+
TileLoadResult tileLoadResult;
1118+
tileLoadResult.state = TileLoadResultState::Success;
1119+
1120+
const auto it = model.extras.find("gltfUpAxis");
1121+
if (it == model.extras.end()) {
1122+
CESIUM_ASSERT(false);
1123+
tileLoadResult.glTFUpAxis = CesiumGeometry::Axis::Y;
1124+
} else {
1125+
tileLoadResult.glTFUpAxis = static_cast<CesiumGeometry::Axis>(
1126+
it->second.getSafeNumberOrDefault(1));
1127+
}
1128+
1129+
if (modified) {
1130+
tileLoadResult.contentKind =
1131+
std::move(modified->modifiedModel);
1132+
} else {
1133+
tileLoadResult.contentKind = previousModel;
1134+
}
1135+
1136+
return pPrepareRendererResources->prepareInLoadThread(
1137+
asyncSystem,
1138+
std::move(tileLoadResult),
1139+
tileTransform,
1140+
rendererOptions);
1141+
})
11271142
.thenInMainThread(
11281143
[&tile,
11291144
// Keep the manager alive while the glTF modification is in
@@ -1243,7 +1258,10 @@ void TilesetContentManager::loadTileContent(
12431258
rootTranslation = glm::column(this->_pRootTile->getTransform(), 3);
12441259
}
12451260
pLoader->loadTileContent(loadInput)
1246-
.thenImmediately([tileLoadInfo = std::move(tileLoadInfo),
1261+
.thenImmediately([asyncSystem = this->_externals.asyncSystem,
1262+
pAssetAccessor = this->_externals.pAssetAccessor,
1263+
pLogger = this->_externals.pLogger,
1264+
tileLoadInfo = std::move(tileLoadInfo),
12471265
projections = std::move(projections),
12481266
rendererOptions = tilesetOptions.rendererOptions,
12491267
pGltfModifier = _externals.pGltfModifier,
@@ -1258,7 +1276,6 @@ void TilesetContentManager::loadTileContent(
12581276
// worker thread if the content is a render content
12591277
if (result.state == TileLoadResultState::Success) {
12601278
if (std::holds_alternative<CesiumGltf::Model>(result.contentKind)) {
1261-
auto asyncSystem = tileLoadInfo.asyncSystem;
12621279
// update root translation now it has been loaded:
12631280
if (isLoadingRootTile)
12641281
rootTranslation = glm::column(tileLoadInfo.tileTransform, 3);
@@ -1276,19 +1293,39 @@ void TilesetContentManager::loadTileContent(
12761293
// have been created, which is both inefficient and a cause
12771294
// of visual glitches (the model will appear briefly in its
12781295
// unmodified state before stabilizing)
1279-
auto& model =
1296+
const CesiumGltf::Model& model =
12801297
std::get<CesiumGltf::Model>(result.contentKind);
1281-
pGltfModifier->apply(
1282-
model,
1283-
tileLoadInfo.tileTransform,
1284-
rootTranslation,
1285-
model);
1298+
return pGltfModifier
1299+
->apply(GltfModifierInput{
1300+
.asyncSystem = tileLoadInfo.asyncSystem,
1301+
.pAssetAccessor = tileLoadInfo.pAssetAccessor,
1302+
.pLogger = tileLoadInfo.pLogger,
1303+
.previousModel = model,
1304+
.tileTransform = tileLoadInfo.tileTransform})
1305+
.thenInWorkerThread(
1306+
[result = std::move(result),
1307+
projections = std::move(projections),
1308+
tileLoadInfo = std::move(tileLoadInfo),
1309+
rendererOptions](
1310+
std::optional<GltfModifierOutput>&&
1311+
modified) mutable {
1312+
if (modified) {
1313+
result.contentKind =
1314+
std::move(modified->modifiedModel);
1315+
}
1316+
return postProcessContentInWorkerThread(
1317+
std::move(result),
1318+
std::move(projections),
1319+
std::move(tileLoadInfo),
1320+
rendererOptions);
1321+
});
1322+
} else {
1323+
return postProcessContentInWorkerThread(
1324+
std::move(result),
1325+
std::move(projections),
1326+
std::move(tileLoadInfo),
1327+
rendererOptions);
12861328
}
1287-
return postProcessContentInWorkerThread(
1288-
std::move(result),
1289-
std::move(projections),
1290-
std::move(tileLoadInfo),
1291-
rendererOptions);
12921329
});
12931330
}
12941331
}

Cesium3DTilesSelection/test/TestTilesetContentManager.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,23 +1875,22 @@ TEST_CASE("Test glTF modifier state machine") {
18751875
SimpleGltfModifier() {}
18761876

18771877
int applyCallCount = 0;
1878-
bool apply(
1879-
const CesiumGltf::Model& model,
1880-
const glm::dmat4& /*tileTransform*/,
1881-
const glm::dvec4& /*rootTranslation*/,
1882-
CesiumGltf::Model& out_model) override {
1878+
CesiumAsync::Future<std::optional<GltfModifierOutput>>
1879+
apply(GltfModifierInput&& input) override {
18831880
++applyCallCount;
1884-
out_model = model;
1885-
out_model.version = getCurrentVersion();
1886-
return true;
1881+
GltfModifierOutput output{.modifiedModel = input.previousModel};
1882+
output.modifiedModel.version = getCurrentVersion();
1883+
return input.asyncSystem.createResolvedFuture(
1884+
std::make_optional(std::move(output)));
18871885
}
18881886

18891887
int onRegisterCallCount = 0;
18901888
CesiumAsync::Future<void> onRegister(
18911889
const CesiumAsync::AsyncSystem& asyncSystem,
18921890
const std::shared_ptr<CesiumAsync::IAssetAccessor>&,
18931891
const std::shared_ptr<spdlog::logger>&,
1894-
const TilesetMetadata&) override {
1892+
const TilesetMetadata&,
1893+
const Tile&) override {
18951894
++onRegisterCallCount;
18961895
return asyncSystem.createResolvedFuture();
18971896
}

0 commit comments

Comments
 (0)