mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
working on material baker
This commit is contained in:
parent
4965adbc2f
commit
94de0c12bc
13 changed files with 491 additions and 78 deletions
|
@ -1,7 +1,7 @@
|
|||
set(TARGET_NAME baking)
|
||||
setup_hifi_library(Concurrent)
|
||||
|
||||
link_hifi_libraries(shared graphics networking ktx image fbx)
|
||||
link_hifi_libraries(shared shaders graphics networking material-networking ktx image fbx)
|
||||
include_hifi_library_headers(gpu)
|
||||
include_hifi_library_headers(hfm)
|
||||
|
||||
|
|
118
libraries/baking/src/MaterialBaker.cpp
Normal file
118
libraries/baking/src/MaterialBaker.cpp
Normal file
|
@ -0,0 +1,118 @@
|
|||
//
|
||||
// MaterialBaker.cpp
|
||||
// libraries/baking/src
|
||||
//
|
||||
// Created by Sam Gondelman on 2/26/2019
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "MaterialBaker.h"
|
||||
|
||||
#include "QJsonObject"
|
||||
#include "QJsonDocument"
|
||||
|
||||
#include "MaterialBakingLoggingCategory.h"
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
MaterialBaker::MaterialBaker(const QString& materialData, bool isURL, const QString& bakedOutputDir) :
|
||||
_materialData(materialData),
|
||||
_isURL(isURL),
|
||||
_bakedOutputDir(bakedOutputDir)
|
||||
{
|
||||
}
|
||||
|
||||
void MaterialBaker::bake() {
|
||||
qDebug(material_baking) << "Material Baker" << _materialData << "bake starting";
|
||||
|
||||
// once our script is loaded, kick off a the processing
|
||||
connect(this, &MaterialBaker::originalMaterialLoaded, this, &MaterialBaker::processMaterial);
|
||||
|
||||
if (!_materialResource) {
|
||||
// first load the material (either locally or remotely)
|
||||
loadMaterial();
|
||||
} else {
|
||||
// we already have a material passed to us, use that
|
||||
if (_materialResource->isLoaded()) {
|
||||
emit originalMaterialLoaded();
|
||||
} else {
|
||||
connect(_materialResource.data(), &Resource::finished, this, &MaterialBaker::originalMaterialLoaded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialBaker::loadMaterial() {
|
||||
if (!_isURL) {
|
||||
qCDebug(material_baking) << "Loading local material" << _materialData;
|
||||
|
||||
_materialResource = NetworkMaterialResourcePointer(new NetworkMaterialResource());
|
||||
// TODO: add baseURL to allow these to reference relative files next to them
|
||||
_materialResource->parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromVariant(_materialData), QUrl());
|
||||
} else {
|
||||
qCDebug(material_baking) << "Downloading material" << _materialData;
|
||||
_materialResource = MaterialCache::instance().getMaterial(_materialData);
|
||||
}
|
||||
|
||||
if (_materialResource) {
|
||||
if (_materialResource->isLoaded()) {
|
||||
emit originalMaterialLoaded();
|
||||
} else {
|
||||
connect(_materialResource.data(), &Resource::finished, this, &MaterialBaker::originalMaterialLoaded);
|
||||
}
|
||||
} else {
|
||||
handleError("Error loading " + _materialData);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialBaker::processMaterial() {
|
||||
if (!_materialResource || _materialResource->parsedMaterials.networkMaterials.size() == 0) {
|
||||
handleError("Error processing " + _materialData);
|
||||
}
|
||||
|
||||
_numTexturesToLoad = _materialResource->parsedMaterials.networkMaterials.size();
|
||||
_numTexturesLoaded = 0;
|
||||
|
||||
for (auto networkMaterial : _materialResource->parsedMaterials.networkMaterials) {
|
||||
if (networkMaterial.second) {
|
||||
auto textureMaps = networkMaterial.second->getTextureMaps();
|
||||
for (auto textureMap : textureMaps) {
|
||||
if (textureMap.second && textureMap.second->getTextureSource()) {
|
||||
auto texture = textureMap.second->getTextureSource();
|
||||
graphics::Material::MapChannel mapChannel = textureMap.first;
|
||||
|
||||
qDebug() << "boop" << mapChannel << texture->getUrl();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialBaker::outputMaterial() {
|
||||
//if (_isURL) {
|
||||
// auto fileName = _materialData;
|
||||
// auto baseName = fileName.left(fileName.lastIndexOf('.'));
|
||||
// auto bakedFilename = baseName + BAKED_MATERIAL_EXTENSION;
|
||||
|
||||
// _bakedMaterialData = _bakedOutputDir + "/" + bakedFilename;
|
||||
|
||||
// QFile bakedFile;
|
||||
// bakedFile.setFileName(_bakedMaterialData);
|
||||
// if (!bakedFile.open(QIODevice::WriteOnly)) {
|
||||
// handleError("Error opening " + _bakedMaterialData + " for writing");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// bakedFile.write(outputMaterial);
|
||||
|
||||
// // Export successful
|
||||
// _outputFiles.push_back(_bakedMaterialData);
|
||||
// qCDebug(material_baking) << "Exported" << _materialData << "to" << _bakedMaterialData;
|
||||
//}
|
||||
|
||||
// emit signal to indicate the material baking is finished
|
||||
emit finished();
|
||||
}
|
58
libraries/baking/src/MaterialBaker.h
Normal file
58
libraries/baking/src/MaterialBaker.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// MaterialBaker.h
|
||||
// libraries/baking/src
|
||||
//
|
||||
// Created by Sam Gondelman on 2/26/2019
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_MaterialBaker_h
|
||||
#define hifi_MaterialBaker_h
|
||||
|
||||
#include "Baker.h"
|
||||
|
||||
#include "TextureBaker.h"
|
||||
|
||||
#include <material-networking/MaterialCache.h>
|
||||
|
||||
static const QString BAKED_MATERIAL_EXTENSION = ".baked.json";
|
||||
|
||||
class MaterialBaker : public Baker {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MaterialBaker(const QString& materialData, bool isURL, const QString& bakedOutputDir);
|
||||
|
||||
QString getMaterialData() const { return _materialData; }
|
||||
bool isURL() const { return _isURL; }
|
||||
QString getBakedMaterialData() const { return _bakedMaterialData; }
|
||||
|
||||
public slots:
|
||||
virtual void bake() override;
|
||||
|
||||
signals:
|
||||
void originalMaterialLoaded();
|
||||
|
||||
private slots:
|
||||
void processMaterial();
|
||||
void outputMaterial();
|
||||
|
||||
private:
|
||||
void loadMaterial();
|
||||
|
||||
QString _materialData;
|
||||
bool _isURL;
|
||||
|
||||
NetworkMaterialResourcePointer _materialResource;
|
||||
size_t _numTexturesToLoad { 0 };
|
||||
size_t _numTexturesLoaded { 0 };
|
||||
|
||||
QHash<QUrl, QSharedPointer<TextureBaker>> _textureBakers;
|
||||
|
||||
QString _bakedOutputDir;
|
||||
QString _bakedMaterialData;
|
||||
};
|
||||
|
||||
#endif // !hifi_MaterialBaker_h
|
14
libraries/baking/src/MaterialBakingLoggingCategory.cpp
Normal file
14
libraries/baking/src/MaterialBakingLoggingCategory.cpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// MaterialBakingLoggingCategory.cpp
|
||||
// libraries/baking/src
|
||||
//
|
||||
// Created by Sam Gondelman on 2/26/2019
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "MaterialBakingLoggingCategory.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(material_baking, "hifi.material-baking");
|
19
libraries/baking/src/MaterialBakingLoggingCategory.h
Normal file
19
libraries/baking/src/MaterialBakingLoggingCategory.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// MaterialBakingLoggingCategory.h
|
||||
// libraries/baking/src
|
||||
//
|
||||
// Created by Sam Gondelman on 2/26/2019
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_MaterialBakingLoggingCategory_h
|
||||
#define hifi_MaterialBakingLoggingCategory_h
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(material_baking)
|
||||
|
||||
#endif // hifi_MaterialBakingLoggingCategory_h
|
|
@ -96,6 +96,8 @@ namespace scriptable {
|
|||
|
||||
bool defaultFallthrough;
|
||||
std::unordered_map<uint, bool> propertyFallthroughs; // not actually exposed to script
|
||||
|
||||
graphics::MaterialKey key { 0 };
|
||||
};
|
||||
|
||||
/**jsdoc
|
||||
|
|
|
@ -364,20 +364,81 @@ namespace scriptable {
|
|||
obj.setProperty("model", material.model);
|
||||
|
||||
const QScriptValue FALLTHROUGH("fallthrough");
|
||||
obj.setProperty("opacity", material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_VAL_BIT) ? FALLTHROUGH : material.opacity);
|
||||
obj.setProperty("roughness", material.propertyFallthroughs.at(graphics::MaterialKey::GLOSSY_VAL_BIT) ? FALLTHROUGH : material.roughness);
|
||||
obj.setProperty("metallic", material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_VAL_BIT) ? FALLTHROUGH : material.metallic);
|
||||
obj.setProperty("scattering", material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_VAL_BIT) ? FALLTHROUGH : material.scattering);
|
||||
obj.setProperty("unlit", material.propertyFallthroughs.at(graphics::MaterialKey::UNLIT_VAL_BIT) ? FALLTHROUGH : material.unlit);
|
||||
obj.setProperty("emissive", material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_VAL_BIT) ? FALLTHROUGH : vec3ColorToScriptValue(engine, material.emissive));
|
||||
obj.setProperty("albedo", material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_VAL_BIT) ? FALLTHROUGH : vec3ColorToScriptValue(engine, material.albedo));
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_VAL_BIT)) {
|
||||
obj.setProperty("opacity", FALLTHROUGH);
|
||||
} else if (material.key.isTranslucentFactor()) {
|
||||
obj.setProperty("opacity", material.opacity);
|
||||
}
|
||||
|
||||
obj.setProperty("emissiveMap", material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_MAP_BIT) ? FALLTHROUGH : material.emissiveMap);
|
||||
obj.setProperty("albedoMap", material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_MAP_BIT) ? FALLTHROUGH : material.albedoMap);
|
||||
obj.setProperty("opacityMap", material.opacityMap);
|
||||
obj.setProperty("occlusionMap", material.propertyFallthroughs.at(graphics::MaterialKey::OCCLUSION_MAP_BIT) ? FALLTHROUGH : material.occlusionMap);
|
||||
obj.setProperty("lightmapMap", material.propertyFallthroughs.at(graphics::MaterialKey::LIGHTMAP_MAP_BIT) ? FALLTHROUGH : material.lightmapMap);
|
||||
obj.setProperty("scatteringMap", material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT) ? FALLTHROUGH : material.scatteringMap);
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::GLOSSY_VAL_BIT)) {
|
||||
obj.setProperty("roughness", FALLTHROUGH);
|
||||
} else if (material.key.isGlossy()) {
|
||||
obj.setProperty("roughness", material.roughness);
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_VAL_BIT)) {
|
||||
obj.setProperty("metallic", FALLTHROUGH);
|
||||
} else if (material.key.isMetallic()) {
|
||||
obj.setProperty("metallic", material.metallic);
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_VAL_BIT)) {
|
||||
obj.setProperty("scattering", FALLTHROUGH);
|
||||
} else if (material.key.isScattering()) {
|
||||
obj.setProperty("scattering", material.scattering);
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::UNLIT_VAL_BIT)) {
|
||||
obj.setProperty("unlit", FALLTHROUGH);
|
||||
} else if (material.key.isUnlit()) {
|
||||
obj.setProperty("unlit", material.unlit);
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_VAL_BIT)) {
|
||||
obj.setProperty("emissive", FALLTHROUGH);
|
||||
} else if (material.key.isEmissive()) {
|
||||
obj.setProperty("emissive", vec3ColorToScriptValue(engine, material.emissive));
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_VAL_BIT)) {
|
||||
obj.setProperty("albedo", FALLTHROUGH);
|
||||
} else if (material.key.isAlbedo()) {
|
||||
obj.setProperty("albedo", vec3ColorToScriptValue(engine, material.albedo));
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_MAP_BIT)) {
|
||||
obj.setProperty("emissiveMap", FALLTHROUGH);
|
||||
} else if (!material.emissiveMap.isEmpty()) {
|
||||
obj.setProperty("emissiveMap", material.emissiveMap);
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_MAP_BIT)) {
|
||||
obj.setProperty("albedoMap", FALLTHROUGH);
|
||||
} else if (!material.albedoMap.isEmpty()) {
|
||||
obj.setProperty("albedoMap", material.albedoMap);
|
||||
}
|
||||
|
||||
if (!material.opacityMap.isEmpty()) {
|
||||
obj.setProperty("opacityMap", material.opacityMap);
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::OCCLUSION_MAP_BIT)) {
|
||||
obj.setProperty("occlusionMap", FALLTHROUGH);
|
||||
} else if (!material.occlusionMap.isEmpty()) {
|
||||
obj.setProperty("occlusionMap", material.occlusionMap);
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::LIGHTMAP_MAP_BIT)) {
|
||||
obj.setProperty("lightmapMap", FALLTHROUGH);
|
||||
} else if (!material.lightmapMap.isEmpty()) {
|
||||
obj.setProperty("lightmapMap", material.lightmapMap);
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT)) {
|
||||
obj.setProperty("scatteringMap", FALLTHROUGH);
|
||||
} else if (!material.scatteringMap.isEmpty()) {
|
||||
obj.setProperty("scatteringMap", material.scatteringMap);
|
||||
}
|
||||
|
||||
// Only set one of each of these
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_MAP_BIT)) {
|
||||
|
|
|
@ -45,75 +45,80 @@ scriptable::ScriptableMaterial& scriptable::ScriptableMaterial::operator=(const
|
|||
defaultFallthrough = material.defaultFallthrough;
|
||||
propertyFallthroughs = material.propertyFallthroughs;
|
||||
|
||||
key = material.key;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPointer& material) :
|
||||
name(material->getName().c_str()),
|
||||
model(material->getModel().c_str()),
|
||||
opacity(material->getOpacity()),
|
||||
roughness(material->getRoughness()),
|
||||
metallic(material->getMetallic()),
|
||||
scattering(material->getScattering()),
|
||||
unlit(material->isUnlit()),
|
||||
emissive(material->getEmissive()),
|
||||
albedo(material->getAlbedo()),
|
||||
defaultFallthrough(material->getDefaultFallthrough()),
|
||||
propertyFallthroughs(material->getPropertyFallthroughs())
|
||||
{
|
||||
auto map = material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
emissiveMap = map->getTextureSource()->getUrl().toString();
|
||||
}
|
||||
scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPointer& material) {
|
||||
if (material) {
|
||||
name = material->getName().c_str();
|
||||
model = material->getModel().c_str();
|
||||
opacity = material->getOpacity();
|
||||
roughness = material->getRoughness();
|
||||
metallic = material->getMetallic();
|
||||
scattering = material->getScattering();
|
||||
unlit = material->isUnlit();
|
||||
emissive = material->getEmissive();
|
||||
albedo = material->getAlbedo();
|
||||
defaultFallthrough = material->getDefaultFallthrough();
|
||||
propertyFallthroughs = material->getPropertyFallthroughs();
|
||||
key = material->getKey();
|
||||
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::ALBEDO_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
albedoMap = map->getTextureSource()->getUrl().toString();
|
||||
if (map->useAlphaChannel()) {
|
||||
opacityMap = albedoMap;
|
||||
auto map = material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
emissiveMap = map->getTextureSource()->getUrl().toString();
|
||||
}
|
||||
}
|
||||
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
if (map->getTextureSource()->getType() == image::TextureUsage::Type::METALLIC_TEXTURE) {
|
||||
metallicMap = map->getTextureSource()->getUrl().toString();
|
||||
} else if (map->getTextureSource()->getType() == image::TextureUsage::Type::SPECULAR_TEXTURE) {
|
||||
specularMap = map->getTextureSource()->getUrl().toString();
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::ALBEDO_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
albedoMap = map->getTextureSource()->getUrl().toString();
|
||||
if (map->useAlphaChannel()) {
|
||||
opacityMap = albedoMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
if (map->getTextureSource()->getType() == image::TextureUsage::Type::ROUGHNESS_TEXTURE) {
|
||||
roughnessMap = map->getTextureSource()->getUrl().toString();
|
||||
} else if (map->getTextureSource()->getType() == image::TextureUsage::Type::GLOSS_TEXTURE) {
|
||||
glossMap = map->getTextureSource()->getUrl().toString();
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
if (map->getTextureSource()->getType() == image::TextureUsage::Type::METALLIC_TEXTURE) {
|
||||
metallicMap = map->getTextureSource()->getUrl().toString();
|
||||
} else if (map->getTextureSource()->getType() == image::TextureUsage::Type::SPECULAR_TEXTURE) {
|
||||
specularMap = map->getTextureSource()->getUrl().toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
if (map->getTextureSource()->getType() == image::TextureUsage::Type::NORMAL_TEXTURE) {
|
||||
normalMap = map->getTextureSource()->getUrl().toString();
|
||||
} else if (map->getTextureSource()->getType() == image::TextureUsage::Type::BUMP_TEXTURE) {
|
||||
bumpMap = map->getTextureSource()->getUrl().toString();
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
if (map->getTextureSource()->getType() == image::TextureUsage::Type::ROUGHNESS_TEXTURE) {
|
||||
roughnessMap = map->getTextureSource()->getUrl().toString();
|
||||
} else if (map->getTextureSource()->getType() == image::TextureUsage::Type::GLOSS_TEXTURE) {
|
||||
glossMap = map->getTextureSource()->getUrl().toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
occlusionMap = map->getTextureSource()->getUrl().toString();
|
||||
}
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
if (map->getTextureSource()->getType() == image::TextureUsage::Type::NORMAL_TEXTURE) {
|
||||
normalMap = map->getTextureSource()->getUrl().toString();
|
||||
} else if (map->getTextureSource()->getType() == image::TextureUsage::Type::BUMP_TEXTURE) {
|
||||
bumpMap = map->getTextureSource()->getUrl().toString();
|
||||
}
|
||||
}
|
||||
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::LIGHTMAP_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
lightmapMap = map->getTextureSource()->getUrl().toString();
|
||||
}
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
occlusionMap = map->getTextureSource()->getUrl().toString();
|
||||
}
|
||||
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
scatteringMap = map->getTextureSource()->getUrl().toString();
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::LIGHTMAP_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
lightmapMap = map->getTextureSource()->getUrl().toString();
|
||||
}
|
||||
|
||||
map = material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
scatteringMap = map->getTextureSource()->getUrl().toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ set(TARGET_NAME oven)
|
|||
|
||||
setup_hifi_project(Widgets Gui Concurrent)
|
||||
|
||||
link_hifi_libraries(networking shared image gpu ktx fbx hfm baking graphics)
|
||||
link_hifi_libraries(shared shaders image gpu ktx fbx hfm baking graphics networking material-networking)
|
||||
|
||||
setup_memory_debugger()
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "baking/BakerLibrary.h"
|
||||
#include "JSBaker.h"
|
||||
#include "TextureBaker.h"
|
||||
#include "MaterialBaker.h"
|
||||
|
||||
BakerCLI::BakerCLI(OvenCLIApplication* parent) : QObject(parent) {
|
||||
|
||||
|
@ -60,8 +61,8 @@ void BakerCLI::bakeFile(QUrl inputUrl, const QString& outputPath, const QString&
|
|||
_baker = std::unique_ptr<Baker> { new JSBaker(inputUrl, outputPath) };
|
||||
_baker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
} else if (type == MATERIAL_EXTENSION) {
|
||||
//_baker = std::unique_ptr<Baker> { new MaterialBaker(inputUrl, outputPath) };
|
||||
//_baker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
_baker = std::unique_ptr<Baker> { new MaterialBaker(inputUrl.toDisplayString(), true, outputPath) };
|
||||
_baker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
} else {
|
||||
// If the type doesn't match the above, we assume we have a texture, and the type specified is the
|
||||
// texture usage type (albedo, cubemap, normals, etc.)
|
||||
|
|
|
@ -187,8 +187,8 @@ void DomainBaker::addTextureBaker(const QString& property, const QString& url, i
|
|||
|
||||
// setup a texture baker for this URL, as long as we aren't baking a texture already
|
||||
if (!_textureBakers.contains(textureURL)) {
|
||||
// setup a baker for this texture
|
||||
|
||||
// setup a baker for this texture
|
||||
QSharedPointer<TextureBaker> textureBaker {
|
||||
new TextureBaker(textureURL, type, _contentOutputPath),
|
||||
&TextureBaker::deleteLater
|
||||
|
@ -220,16 +220,16 @@ void DomainBaker::addScriptBaker(const QString& property, const QString& url, QJ
|
|||
// grab a clean version of the URL without a query or fragment
|
||||
QUrl scriptURL = QUrl(url).adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);
|
||||
|
||||
// setup a texture baker for this URL, as long as we aren't baking a texture already
|
||||
// setup a script baker for this URL, as long as we aren't baking a texture already
|
||||
if (!_scriptBakers.contains(scriptURL)) {
|
||||
// setup a baker for this texture
|
||||
|
||||
// setup a baker for this script
|
||||
QSharedPointer<JSBaker> scriptBaker {
|
||||
new JSBaker(scriptURL, _contentOutputPath),
|
||||
&JSBaker::deleteLater
|
||||
};
|
||||
|
||||
// make sure our handler is called when the texture baker is done
|
||||
// make sure our handler is called when the script baker is done
|
||||
connect(scriptBaker.data(), &JSBaker::finished, this, &DomainBaker::handleFinishedScriptBaker);
|
||||
|
||||
// insert it into our bakers hash so we hold a strong pointer to it
|
||||
|
@ -243,11 +243,48 @@ void DomainBaker::addScriptBaker(const QString& property, const QString& url, QJ
|
|||
++_totalNumberOfSubBakes;
|
||||
}
|
||||
|
||||
// add this QJsonValueRef to our multi hash so that it can re-write the texture URL
|
||||
// add this QJsonValueRef to our multi hash so that it can re-write the script URL
|
||||
// to the baked version once the baker is complete
|
||||
_entitiesNeedingRewrite.insert(scriptURL, { property, jsonRef });
|
||||
}
|
||||
|
||||
void DomainBaker::addMaterialBaker(const QString& property, const QString& data, bool isURL, QJsonValueRef& jsonRef) {
|
||||
// grab a clean version of the URL without a query or fragment
|
||||
QString materialData;
|
||||
if (isURL) {
|
||||
materialData = QUrl(data).adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment).toDisplayString();
|
||||
} else {
|
||||
materialData = data;
|
||||
}
|
||||
|
||||
// setup a material baker for this URL, as long as we aren't baking a material already
|
||||
if (!_materialBakers.contains(materialData)) {
|
||||
|
||||
// setup a baker for this material
|
||||
QSharedPointer<MaterialBaker> materialBaker {
|
||||
new MaterialBaker(data, isURL, _contentOutputPath),
|
||||
&MaterialBaker::deleteLater
|
||||
};
|
||||
|
||||
// make sure our handler is called when the material baker is done
|
||||
connect(materialBaker.data(), &MaterialBaker::finished, this, &DomainBaker::handleFinishedMaterialBaker);
|
||||
|
||||
// insert it into our bakers hash so we hold a strong pointer to it
|
||||
_materialBakers.insert(materialData, materialBaker);
|
||||
|
||||
// move the baker to a worker thread and kickoff the bake
|
||||
materialBaker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
QMetaObject::invokeMethod(materialBaker.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 texture URL
|
||||
// to the baked version once the baker is complete
|
||||
_entitiesNeedingRewrite.insert(materialData, { property, jsonRef });
|
||||
}
|
||||
|
||||
// All the Entity Properties that can be baked
|
||||
// ***************************************************************************************
|
||||
|
||||
|
@ -348,7 +385,12 @@ void DomainBaker::enumerateEntities() {
|
|||
}
|
||||
|
||||
// Materials
|
||||
// TODO
|
||||
if (entity.contains(MATERIAL_URL_KEY)) {
|
||||
addMaterialBaker(MATERIAL_URL_KEY, entity[MATERIAL_URL_KEY].toString(), true, *it);
|
||||
}
|
||||
if (entity.contains(MATERIAL_DATA_KEY)) {
|
||||
addMaterialBaker(MATERIAL_DATA_KEY, entity[MATERIAL_URL_KEY].toString(), false, *it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -568,6 +610,91 @@ void DomainBaker::handleFinishedScriptBaker() {
|
|||
}
|
||||
}
|
||||
|
||||
void DomainBaker::handleFinishedMaterialBaker() {
|
||||
auto baker = qobject_cast<MaterialBaker*>(sender());
|
||||
|
||||
if (baker) {
|
||||
if (!baker->hasErrors()) {
|
||||
// this MaterialBaker is done and everything went according to plan
|
||||
qDebug() << "Re-writing entity references to" << baker->getMaterialData();
|
||||
|
||||
QString newDataOrURL;
|
||||
if (baker->isURL()) {
|
||||
newDataOrURL = _destinationPath.resolved(baker->getBakedMaterialData()).toDisplayString();
|
||||
} else {
|
||||
newDataOrURL = baker->getBakedMaterialData();
|
||||
}
|
||||
|
||||
// enumerate the QJsonRef values for the URL of this material from our multi hash of
|
||||
// entity objects needing a URL re-write
|
||||
for (auto propertyEntityPair : _entitiesNeedingRewrite.values(baker->getMaterialData())) {
|
||||
QString property = propertyEntityPair.first;
|
||||
// convert the entity QJsonValueRef to a QJsonObject so we can modify its URL
|
||||
auto entity = propertyEntityPair.second.toObject();
|
||||
|
||||
if (!property.contains(".")) {
|
||||
// grab the old URL
|
||||
QUrl oldURL = entity[property].toString();
|
||||
|
||||
// copy the fragment and query, and user info from the old material data
|
||||
if (baker->isURL()) {
|
||||
QUrl newURL = newDataOrURL;
|
||||
newURL.setQuery(oldURL.query());
|
||||
newURL.setFragment(oldURL.fragment());
|
||||
newURL.setUserInfo(oldURL.userInfo());
|
||||
|
||||
// set the new URL as the value in our temp QJsonObject
|
||||
entity[property] = newURL.toString();
|
||||
} else {
|
||||
entity[property] = newDataOrURL;
|
||||
}
|
||||
} else {
|
||||
// Group property
|
||||
QStringList propertySplit = property.split(".");
|
||||
assert(propertySplit.length() == 2);
|
||||
// grab the old URL
|
||||
auto oldObject = entity[propertySplit[0]].toObject();
|
||||
QUrl oldURL = oldObject[propertySplit[1]].toString();
|
||||
|
||||
// copy the fragment and query, and user info from the old material data
|
||||
if (baker->isURL()) {
|
||||
QUrl newURL = newDataOrURL;
|
||||
newURL.setQuery(oldURL.query());
|
||||
newURL.setFragment(oldURL.fragment());
|
||||
newURL.setUserInfo(oldURL.userInfo());
|
||||
|
||||
// set the new URL as the value in our temp QJsonObject
|
||||
oldObject[propertySplit[1]] = newURL.toString();
|
||||
entity[propertySplit[0]] = oldObject;
|
||||
} else {
|
||||
oldObject[propertySplit[1]] = newDataOrURL;
|
||||
entity[propertySplit[0]] = oldObject;
|
||||
}
|
||||
}
|
||||
|
||||
// replace our temp object with the value referenced by our QJsonValueRef
|
||||
propertyEntityPair.second = entity;
|
||||
}
|
||||
} else {
|
||||
// this material failed to bake - this doesn't fail the entire bake but we need to add
|
||||
// the errors from the material to our warnings
|
||||
_warningList << baker->getErrors();
|
||||
}
|
||||
|
||||
// remove the baked URL from the multi hash of entities needing a re-write
|
||||
_entitiesNeedingRewrite.remove(baker->getMaterialData());
|
||||
|
||||
// drop our shared pointer to this baker so that it gets cleaned up
|
||||
_materialBakers.remove(baker->getMaterialData());
|
||||
|
||||
// emit progress to tell listeners how many materials we have baked
|
||||
emit bakeProgress(++_completedSubBakes, _totalNumberOfSubBakes);
|
||||
|
||||
// check if this was the last material we needed to re-write and if we are done now
|
||||
checkIfRewritingComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void DomainBaker::checkIfRewritingComplete() {
|
||||
if (_entitiesNeedingRewrite.isEmpty()) {
|
||||
writeNewEntitiesFile();
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "ModelBaker.h"
|
||||
#include "TextureBaker.h"
|
||||
#include "JSBaker.h"
|
||||
#include "MaterialBaker.h"
|
||||
|
||||
class DomainBaker : public Baker {
|
||||
Q_OBJECT
|
||||
|
@ -40,6 +41,7 @@ private slots:
|
|||
void handleFinishedModelBaker();
|
||||
void handleFinishedTextureBaker();
|
||||
void handleFinishedScriptBaker();
|
||||
void handleFinishedMaterialBaker();
|
||||
|
||||
private:
|
||||
void setupOutputFolder();
|
||||
|
@ -62,6 +64,7 @@ private:
|
|||
QHash<QUrl, QSharedPointer<ModelBaker>> _modelBakers;
|
||||
QHash<QUrl, QSharedPointer<TextureBaker>> _textureBakers;
|
||||
QHash<QUrl, QSharedPointer<JSBaker>> _scriptBakers;
|
||||
QHash<QUrl, QSharedPointer<MaterialBaker>> _materialBakers;
|
||||
|
||||
QMultiHash<QUrl, std::pair<QString, QJsonValueRef>> _entitiesNeedingRewrite;
|
||||
|
||||
|
@ -71,6 +74,7 @@ private:
|
|||
void addModelBaker(const QString& property, const QString& url, QJsonValueRef& jsonRef);
|
||||
void addTextureBaker(const QString& property, const QString& url, image::TextureUsage::Type type, QJsonValueRef& jsonRef);
|
||||
void addScriptBaker(const QString& property, const QString& url, QJsonValueRef& jsonRef);
|
||||
void addMaterialBaker(const QString& property, const QString& data, bool isURL, QJsonValueRef& jsonRef);
|
||||
};
|
||||
|
||||
#endif // hifi_DomainBaker_h
|
||||
|
|
|
@ -63,6 +63,10 @@ void Oven::setupWorkerThreads(int numWorkerThreads) {
|
|||
}
|
||||
|
||||
QThread* Oven::getNextWorkerThread() {
|
||||
// FIXME: we assign these threads when we make the bakers, but if certain bakers finish quickly, we could end up
|
||||
// in a situation where threads have finished and others have tons of work queued. Instead of assigning them at initialization,
|
||||
// we should build a queue of bakers, and when threads finish, they can take the next available baker.
|
||||
|
||||
// Here we replicate some of the functionality of QThreadPool by giving callers an available worker thread to use.
|
||||
// We can't use QThreadPool because we want to put QObjects with signals/slots on these threads.
|
||||
// So instead we setup our own list of threads, up to one less than the ideal thread count
|
||||
|
|
Loading…
Reference in a new issue