mirror of
https://github.com/lubosz/overte.git
synced 2025-04-09 08:22:30 +02:00
add skybox baking to DomainBaker
This commit is contained in:
parent
cbd6f6417c
commit
7bc69e6eda
5 changed files with 152 additions and 36 deletions
|
@ -32,6 +32,8 @@ public:
|
|||
|
||||
const QUrl& getTextureURL() const { return _textureURL; }
|
||||
|
||||
const QString& getDestinationFilePath() const { return _destinationFilePath; }
|
||||
|
||||
public slots:
|
||||
virtual void bake() override;
|
||||
|
||||
|
|
|
@ -134,7 +134,9 @@ void DomainBaker::loadLocalFile() {
|
|||
}
|
||||
}
|
||||
|
||||
static const QString ENTITY_MODEL_URL_KEY = "modelURL";
|
||||
const QString ENTITY_MODEL_URL_KEY = "modelURL";
|
||||
const QString ENTITY_SKYBOX_KEY = "skybox";
|
||||
const QString ENTITY_SKYBOX_URL_KEY = "url";
|
||||
|
||||
void DomainBaker::enumerateEntities() {
|
||||
qDebug() << "Enumerating" << _entities.size() << "entities from domain";
|
||||
|
@ -144,7 +146,7 @@ void DomainBaker::enumerateEntities() {
|
|||
if (it->isObject()) {
|
||||
auto entity = it->toObject();
|
||||
|
||||
// check if this is an entity with a model URL
|
||||
// check if this is an entity with a model URL or is a skybox texture
|
||||
if (entity.contains(ENTITY_MODEL_URL_KEY)) {
|
||||
// grab a QUrl for the model URL
|
||||
QUrl modelURL { entity[ENTITY_MODEL_URL_KEY].toString() };
|
||||
|
@ -160,7 +162,7 @@ void DomainBaker::enumerateEntities() {
|
|||
modelURL = modelURL.adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);
|
||||
|
||||
// setup an FBXBaker for this URL, as long as we don't already have one
|
||||
if (!_bakers.contains(modelURL)) {
|
||||
if (!_modelBakers.contains(modelURL)) {
|
||||
QSharedPointer<FBXBaker> baker {
|
||||
new FBXBaker(modelURL, _contentOutputPath, []() -> QThread* {
|
||||
return qApp->getNextWorkerThread();
|
||||
|
@ -168,31 +170,76 @@ void DomainBaker::enumerateEntities() {
|
|||
};
|
||||
|
||||
// make sure our handler is called when the baker is done
|
||||
connect(baker.data(), &Baker::finished, this, &DomainBaker::handleFinishedBaker);
|
||||
connect(baker.data(), &Baker::finished, this, &DomainBaker::handleFinishedModelBaker);
|
||||
|
||||
// insert it into our bakers hash so we hold a strong pointer to it
|
||||
_bakers.insert(modelURL, baker);
|
||||
_modelBakers.insert(modelURL, baker);
|
||||
|
||||
// move the baker to the baker thread
|
||||
// and kickoff the bake
|
||||
baker->moveToThread(qApp->getFBXBakerThread());
|
||||
QMetaObject::invokeMethod(baker.data(), "bake");
|
||||
|
||||
// keep track of the total number of baking entities
|
||||
++_totalNumberOfSubBakes;
|
||||
}
|
||||
|
||||
// add this QJsonValueRef to our multi hash so that we can easily re-write
|
||||
// the model URL to the baked version once the baker is complete
|
||||
_entitiesNeedingRewrite.insert(modelURL, *it);
|
||||
++_totalNumberOfEntities;
|
||||
}
|
||||
} else if (entity.contains(ENTITY_SKYBOX_KEY)
|
||||
&& entity[ENTITY_SKYBOX_KEY].toObject().contains(ENTITY_SKYBOX_URL_KEY)) {
|
||||
// we have a URL to a skybox, grab it
|
||||
QUrl skyboxURL { entity[ENTITY_SKYBOX_KEY].toObject()[ENTITY_SKYBOX_URL_KEY].toString() };
|
||||
|
||||
auto skyboxFileName = skyboxURL.fileName();
|
||||
|
||||
static const QStringList BAKEABLE_SKYBOX_EXTENSIONS { ".jpg" };
|
||||
auto completeLowerExtension = skyboxFileName.mid(skyboxFileName.indexOf('.')).toLower();
|
||||
|
||||
if (BAKEABLE_SKYBOX_EXTENSIONS.contains(completeLowerExtension)) {
|
||||
// grab a clean version of the URL without a query or fragment
|
||||
skyboxURL = skyboxURL.adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);
|
||||
|
||||
// setup a texture baker for this URL, as long as we aren't baking a skybox already
|
||||
if (!_skyboxBakers.contains(skyboxURL)) {
|
||||
// figure out the path for this baked skybox
|
||||
auto skyboxFileName = skyboxURL.fileName();
|
||||
auto bakedSkyboxFileName = skyboxFileName.left(skyboxFileName.indexOf('.')) + BAKED_TEXTURE_EXT;
|
||||
auto bakedTextureDestination = QDir(_contentOutputPath).absoluteFilePath(bakedSkyboxFileName);
|
||||
|
||||
QSharedPointer<TextureBaker> skyboxBaker {
|
||||
new TextureBaker(skyboxURL, gpu::CUBE_TEXTURE, bakedTextureDestination)
|
||||
};
|
||||
|
||||
// make sure our handler is called when the skybox baker is done
|
||||
connect(skyboxBaker.data(), &TextureBaker::finished, this, &DomainBaker::handleFinishedSkyboxBaker);
|
||||
|
||||
// insert it into our bakers hash so we hold a strong pointer to it
|
||||
_skyboxBakers.insert(skyboxURL, skyboxBaker);
|
||||
|
||||
// move the baker to a worker thread and kickoff the bake
|
||||
skyboxBaker->moveToThread(qApp->getNextWorkerThread());
|
||||
QMetaObject::invokeMethod(skyboxBaker.data(), "bake");
|
||||
|
||||
// keep track of the total number of baking entities
|
||||
++_totalNumberOfSubBakes;
|
||||
}
|
||||
|
||||
// add this QJsonValueRef to our multi hash so that it can re-write the skybox URL
|
||||
// to the baked version once the baker is complete
|
||||
_entitiesNeedingRewrite.insert(skyboxURL, *it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit progress now to say we're just starting
|
||||
emit bakeProgress(0, _totalNumberOfEntities);
|
||||
emit bakeProgress(0, _totalNumberOfSubBakes);
|
||||
}
|
||||
|
||||
void DomainBaker::handleFinishedBaker() {
|
||||
void DomainBaker::handleFinishedModelBaker() {
|
||||
auto baker = qobject_cast<FBXBaker*>(sender());
|
||||
|
||||
if (baker) {
|
||||
|
@ -226,27 +273,27 @@ void DomainBaker::handleFinishedBaker() {
|
|||
const QString ENTITY_ANIMATION_KEY = "animation";
|
||||
const QString ENTITIY_ANIMATION_URL_KEY = "url";
|
||||
|
||||
if (entity.contains(ENTITY_ANIMATION_KEY)
|
||||
&& entity[ENTITY_ANIMATION_KEY].toObject().contains(ENTITIY_ANIMATION_URL_KEY)) {
|
||||
auto animationValue = entity[ENTITY_ANIMATION_KEY];
|
||||
auto animationObject = animationValue.toObject();
|
||||
if (entity.contains(ENTITY_ANIMATION_KEY)) {
|
||||
auto animationObject = entity[ENTITY_ANIMATION_KEY].toObject();
|
||||
|
||||
// grab the old animation URL
|
||||
QUrl oldAnimationURL { animationObject[ENTITIY_ANIMATION_URL_KEY].toString() };
|
||||
if (animationObject.contains(ENTITIY_ANIMATION_URL_KEY)) {
|
||||
// grab the old animation URL
|
||||
QUrl oldAnimationURL { animationObject[ENTITIY_ANIMATION_URL_KEY].toString() };
|
||||
|
||||
// check if its stripped down version matches our stripped down model URL
|
||||
if (oldAnimationURL.matches(oldModelURL, QUrl::RemoveUserInfo | QUrl::RemoveQuery | QUrl::RemoveFragment)) {
|
||||
// the animation URL matched the old model URL, so make the animation URL point to the baked FBX
|
||||
// with its original query and fragment
|
||||
auto newAnimationURL = _destinationPath.resolved(baker->getBakedFBXRelativePath());
|
||||
newAnimationURL.setQuery(oldAnimationURL.query());
|
||||
newAnimationURL.setFragment(oldAnimationURL.fragment());
|
||||
newAnimationURL.setUserInfo(oldAnimationURL.userInfo());
|
||||
// check if its stripped down version matches our stripped down model URL
|
||||
if (oldAnimationURL.matches(oldModelURL, QUrl::RemoveUserInfo | QUrl::RemoveQuery | QUrl::RemoveFragment)) {
|
||||
// the animation URL matched the old model URL, so make the animation URL point to the baked FBX
|
||||
// with its original query and fragment
|
||||
auto newAnimationURL = _destinationPath.resolved(baker->getBakedFBXRelativePath());
|
||||
newAnimationURL.setQuery(oldAnimationURL.query());
|
||||
newAnimationURL.setFragment(oldAnimationURL.fragment());
|
||||
newAnimationURL.setUserInfo(oldAnimationURL.userInfo());
|
||||
|
||||
animationObject[ENTITIY_ANIMATION_URL_KEY] = newAnimationURL.toString();
|
||||
animationObject[ENTITIY_ANIMATION_URL_KEY] = newAnimationURL.toString();
|
||||
|
||||
// replace the animation object referenced by the QJsonValueRef
|
||||
animationValue = animationObject;
|
||||
// replace the animation object in the entity object
|
||||
entity[ENTITY_ANIMATION_KEY] = animationObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,7 +302,7 @@ void DomainBaker::handleFinishedBaker() {
|
|||
}
|
||||
} else {
|
||||
// this model failed to bake - this doesn't fail the entire bake but we need to add
|
||||
// the errors from the model to our errors
|
||||
// the errors from the model to our warnings
|
||||
_warningList << baker->getErrors();
|
||||
}
|
||||
|
||||
|
@ -263,16 +310,78 @@ void DomainBaker::handleFinishedBaker() {
|
|||
_entitiesNeedingRewrite.remove(baker->getFBXUrl());
|
||||
|
||||
// drop our shared pointer to this baker so that it gets cleaned up
|
||||
_bakers.remove(baker->getFBXUrl());
|
||||
_modelBakers.remove(baker->getFBXUrl());
|
||||
|
||||
// emit progress to tell listeners how many models we have baked
|
||||
emit bakeProgress(_totalNumberOfEntities - _entitiesNeedingRewrite.keys().size(), _totalNumberOfEntities);
|
||||
emit bakeProgress(++_completedSubBakes, _totalNumberOfSubBakes);
|
||||
|
||||
// check if this was the last model we needed to re-write and if we are done now
|
||||
checkIfRewritingComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void DomainBaker::handleFinishedSkyboxBaker() {
|
||||
auto baker = qobject_cast<TextureBaker*>(sender());
|
||||
|
||||
if (baker) {
|
||||
if (!baker->hasErrors()) {
|
||||
// this FBXBaker is done and everything went according to plan
|
||||
qDebug() << "Re-writing entity references to" << baker->getTextureURL();
|
||||
|
||||
// enumerate the QJsonRef values for the URL of this FBX from our multi hash of
|
||||
// entity objects needing a URL re-write
|
||||
for (QJsonValueRef entityValue : _entitiesNeedingRewrite.values(baker->getTextureURL())) {
|
||||
// convert the entity QJsonValueRef to a QJsonObject so we can modify its URL
|
||||
auto entity = entityValue.toObject();
|
||||
|
||||
if (entity.contains(ENTITY_SKYBOX_KEY)) {
|
||||
auto skyboxObject = entity[ENTITY_SKYBOX_KEY].toObject();
|
||||
|
||||
if (skyboxObject.contains(ENTITY_SKYBOX_URL_KEY)) {
|
||||
// grab the old skybox URL
|
||||
QUrl oldSkyboxURL { skyboxObject[ENTITY_SKYBOX_URL_KEY].toString() };
|
||||
|
||||
// the animation URL matched the old model URL, so make the animation URL point to the baked FBX
|
||||
// with its original query and fragment
|
||||
|
||||
auto bakedSkyboxFileName = QFileInfo(baker->getDestinationFilePath()).fileName();
|
||||
|
||||
auto newSkyboxURL = _destinationPath.resolved(bakedSkyboxFileName);
|
||||
newSkyboxURL.setQuery(oldSkyboxURL.query());
|
||||
newSkyboxURL.setFragment(oldSkyboxURL.fragment());
|
||||
newSkyboxURL.setUserInfo(oldSkyboxURL.userInfo());
|
||||
|
||||
skyboxObject[ENTITY_SKYBOX_URL_KEY] = newSkyboxURL.toString();
|
||||
|
||||
// replace the skybox object referenced by the entity object
|
||||
entity[ENTITY_SKYBOX_KEY] = skyboxObject;
|
||||
}
|
||||
}
|
||||
|
||||
// replace our temp object with the value referenced by our QJsonValueRef
|
||||
entityValue = entity;
|
||||
}
|
||||
} else {
|
||||
// this skybox failed to bake - this doesn't fail the entire bake but we need to add the errors from
|
||||
// the model to our warnings
|
||||
_warningList << baker->getWarnings();
|
||||
}
|
||||
|
||||
// remove the baked URL from the multi hash of entities needing a re-write
|
||||
_entitiesNeedingRewrite.remove(baker->getTextureURL());
|
||||
|
||||
// drop our shared pointer to this baker so that it gets cleaned up
|
||||
_skyboxBakers.remove(baker->getTextureURL());
|
||||
|
||||
// emit progress to tell listeners how many models we have baked
|
||||
emit bakeProgress(++_completedSubBakes, _totalNumberOfSubBakes);
|
||||
|
||||
// check if this was the last model we needed to re-write and if we are done now
|
||||
checkIfRewritingComplete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DomainBaker::checkIfRewritingComplete() {
|
||||
if (_entitiesNeedingRewrite.isEmpty()) {
|
||||
writeNewEntitiesFile();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <Baker.h>
|
||||
#include <FBXBaker.h>
|
||||
#include <TextureBaker.h>
|
||||
|
||||
class DomainBaker : public Baker {
|
||||
Q_OBJECT
|
||||
|
@ -31,11 +32,12 @@ public:
|
|||
|
||||
signals:
|
||||
void allModelsFinished();
|
||||
void bakeProgress(int modelsBaked, int modelsTotal);
|
||||
void bakeProgress(int baked, int total);
|
||||
|
||||
private slots:
|
||||
virtual void bake() override;
|
||||
void handleFinishedBaker();
|
||||
void handleFinishedModelBaker();
|
||||
void handleFinishedSkyboxBaker();
|
||||
|
||||
private:
|
||||
void setupOutputFolder();
|
||||
|
@ -53,10 +55,13 @@ private:
|
|||
|
||||
QJsonArray _entities;
|
||||
|
||||
QHash<QUrl, QSharedPointer<FBXBaker>> _bakers;
|
||||
QHash<QUrl, QSharedPointer<FBXBaker>> _modelBakers;
|
||||
QHash<QUrl, QSharedPointer<TextureBaker>> _skyboxBakers;
|
||||
|
||||
QMultiHash<QUrl, QJsonValueRef> _entitiesNeedingRewrite;
|
||||
|
||||
int _totalNumberOfEntities { 0 };
|
||||
int _totalNumberOfSubBakes { 0 };
|
||||
int _completedSubBakes { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_DomainBaker_h
|
||||
|
|
|
@ -233,7 +233,7 @@ void DomainBakeWidget::bakeButtonClicked() {
|
|||
}
|
||||
}
|
||||
|
||||
void DomainBakeWidget::handleBakerProgress(int modelsBaked, int modelsTotal) {
|
||||
void DomainBakeWidget::handleBakerProgress(int baked, int total) {
|
||||
if (auto baker = qobject_cast<DomainBaker*>(sender())) {
|
||||
// add the results of this bake to the results window
|
||||
auto it = std::find_if(_bakers.begin(), _bakers.end(), [baker](const BakerRowPair& value) {
|
||||
|
@ -244,9 +244,9 @@ void DomainBakeWidget::handleBakerProgress(int modelsBaked, int modelsTotal) {
|
|||
auto resultRow = it->second;
|
||||
auto resultsWindow = qApp->getMainWindow()->showResultsWindow();
|
||||
|
||||
int percentage = roundf(float(modelsBaked) / float(modelsTotal) * 100.0f);
|
||||
int percentage = roundf(float(baked) / float(total) * 100.0f);
|
||||
|
||||
auto statusString = QString("Baking - %1 of %2 models baked - %3%").arg(modelsBaked).arg(modelsTotal).arg(percentage);
|
||||
auto statusString = QString("Baking - %1 of %2 - %3%").arg(baked).arg(total).arg(percentage);
|
||||
resultsWindow->changeStatusForRow(resultRow, statusString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ private slots:
|
|||
|
||||
void outputDirectoryChanged(const QString& newDirectory);
|
||||
|
||||
void handleBakerProgress(int modelsBaked, int modelsTotal);
|
||||
void handleBakerProgress(int baked, int total);
|
||||
void handleFinishedBaker();
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in a new issue