diff --git a/libraries/image/src/image/CubeMap.cpp b/libraries/image/src/image/CubeMap.cpp index 1b337e5b81..a8aba0454c 100644 --- a/libraries/image/src/image/CubeMap.cpp +++ b/libraries/image/src/image/CubeMap.cpp @@ -501,7 +501,7 @@ void CubeMap::generateGGXSamples(GGXSamples& data, float roughness, const int re } void CubeMap::convolveForGGX(CubeMap& output, const std::atomic& abortProcessing) const { - // This should match fragment.glsl values, too + // This should match the value in the getMipLevelFromRoughness function (LightAmbient.slh) static const float ROUGHNESS_1_MIP_RESOLUTION = 1.5f; static const size_t MAX_SAMPLE_COUNT = 4000; diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index e99cf90e0b..53a76e3b0f 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -105,9 +105,9 @@ TextureUsage::TextureLoader TextureUsage::getTextureLoaderForType(Type type, con return image::TextureUsage::createCubeTextureFromImage; case AMBIENT_TEXTURE: if (options.value("generateIrradiance", true).toBool()) { - return image::TextureUsage::createCubeTextureAndIrradianceFromImage; + return image::TextureUsage::createAmbientCubeTextureAndIrradianceFromImage; } else { - return image::TextureUsage::createCubeTextureFromImage; + return image::TextureUsage::createAmbientCubeTextureFromImage; } case BUMP_TEXTURE: return image::TextureUsage::createNormalTextureFromBumpImage; @@ -188,12 +188,12 @@ gpu::TexturePointer TextureUsage::createCubeTextureFromImage(QImage&& srcImage, return processCubeTextureColorFromImage(std::move(srcImage), srcImageName, compress, target, CUBE_DEFAULT, abortProcessing); } -gpu::TexturePointer TextureUsage::createGGXConvolvedCubeTextureFromImage(QImage&& image, const std::string& srcImageName, +gpu::TexturePointer TextureUsage::createAmbientCubeTextureFromImage(QImage&& image, const std::string& srcImageName, bool compress, gpu::BackendTarget target, const std::atomic& abortProcessing) { return processCubeTextureColorFromImage(std::move(image), srcImageName, compress, target, CUBE_GGX_CONVOLVE, abortProcessing); } -gpu::TexturePointer TextureUsage::createGGXConvolvedCubeTextureAndIrradianceFromImage(QImage&& image, const std::string& srcImageName, +gpu::TexturePointer TextureUsage::createAmbientCubeTextureAndIrradianceFromImage(QImage&& image, const std::string& srcImageName, bool compress, gpu::BackendTarget target, const std::atomic& abortProcessing) { return processCubeTextureColorFromImage(std::move(image), srcImageName, compress, target, CUBE_GENERATE_IRRADIANCE | CUBE_GGX_CONVOLVE, abortProcessing); } diff --git a/libraries/image/src/image/Image.h b/libraries/image/src/image/Image.h index 4df7674e08..237dfcc6e7 100644 --- a/libraries/image/src/image/Image.h +++ b/libraries/image/src/image/Image.h @@ -78,10 +78,10 @@ gpu::TexturePointer createCubeTextureFromImage(QImage&& image, const std::string bool compress, gpu::BackendTarget target, const std::atomic& abortProcessing); gpu::TexturePointer createCubeTextureAndIrradianceFromImage(QImage&& image, const std::string& srcImageName, bool compress, gpu::BackendTarget target, const std::atomic& abortProcessing); -gpu::TexturePointer createGGXConvolvedCubeTextureFromImage(QImage&& image, const std::string& srcImageName, - bool compress, gpu::BackendTarget target, const std::atomic& abortProcessing); -gpu::TexturePointer createGGXConvolvedCubeTextureAndIrradianceFromImage(QImage&& image, const std::string& srcImageName, - bool compress, gpu::BackendTarget target, const std::atomic& abortProcessing); +gpu::TexturePointer createAmbientCubeTextureFromImage(QImage&& image, const std::string& srcImageName, + bool compress, gpu::BackendTarget target, const std::atomic& abortProcessing); +gpu::TexturePointer createAmbientCubeTextureAndIrradianceFromImage(QImage&& image, const std::string& srcImageName, + bool compress, gpu::BackendTarget target, const std::atomic& abortProcessing); gpu::TexturePointer createLightmapTextureFromImage(QImage&& image, const std::string& srcImageName, bool compress, gpu::BackendTarget target, const std::atomic& abortProcessing); gpu::TexturePointer process2DTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, bool compress, diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index b936060741..2b19101653 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -642,8 +642,6 @@ void RenderDeferred::run(const RenderContextPointer& renderContext, const Inputs config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage()); } - - void DefaultLightingSetup::run(const RenderContextPointer& renderContext) { if (!_defaultLight || !_defaultBackground) { @@ -655,21 +653,21 @@ void DefaultLightingSetup::run(const RenderContextPointer& renderContext) { defaultSkyboxURL, image::TextureUsage::SKY_TEXTURE); } - if (!_defaultSkyboxAmbientTexture) { + if (!_defaultAmbientNetworkTexture) { PROFILE_RANGE(render, "Process Default Ambient map"); - _defaultSkyboxAmbientTexture = DependencyManager::get()->getTexture( + _defaultAmbientNetworkTexture = DependencyManager::get()->getTexture( defaultSkyboxURL, image::TextureUsage::AMBIENT_TEXTURE); } if (_defaultSkyboxNetworkTexture && _defaultSkyboxNetworkTexture->isLoaded() && _defaultSkyboxNetworkTexture->getGPUTexture()) { - _defaultSkybox->setCubemap(_defaultSkyboxAmbientTexture); + _defaultSkybox->setCubemap(_defaultSkyboxNetworkTexture->getGPUTexture()); } else { // Don't do anything until the skybox has loaded return; } - if (_defaultSkyboxAmbientTexture && _defaultSkyboxAmbientTexture->isLoaded() && _defaultSkyboxAmbientTexture->getGPUTexture()) { - _defaultSkyboxAmbientTexture = _defaultSkyboxAmbientTexture->getGPUTexture(); + if (_defaultAmbientNetworkTexture && _defaultAmbientNetworkTexture->isLoaded() && _defaultAmbientNetworkTexture->getGPUTexture()) { + _defaultAmbientTexture = _defaultAmbientNetworkTexture->getGPUTexture(); } else { // Don't do anything until the ambient box has been loaded return; @@ -688,8 +686,8 @@ void DefaultLightingSetup::run(const RenderContextPointer& renderContext) { lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset::OLD_TOWN_SQUARE); lp->setAmbientIntensity(0.5f); - lp->setAmbientMap(_defaultSkyboxAmbientTexture); - auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance(); + lp->setAmbientMap(_defaultAmbientTexture); + auto irradianceSH = _defaultAmbientTexture->getIrradiance(); if (irradianceSH) { lp->setAmbientSphere((*irradianceSH)); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index f4935000ef..1cc6ca4767 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -212,7 +212,8 @@ protected: HazeStage::Index _defaultHazeID{ HazeStage::INVALID_INDEX }; graphics::SkyboxPointer _defaultSkybox { new ProceduralSkybox() }; NetworkTexturePointer _defaultSkyboxNetworkTexture; - gpu::TexturePointer _defaultSkyboxAmbientTexture; + NetworkTexturePointer _defaultAmbientNetworkTexture; + gpu::TexturePointer _defaultAmbientTexture; }; #endif // hifi_DeferredLightingEffect_h diff --git a/libraries/render-utils/src/LightAmbient.slh b/libraries/render-utils/src/LightAmbient.slh index 4ea9c0cd4c..0c7130b110 100644 --- a/libraries/render-utils/src/LightAmbient.slh +++ b/libraries/render-utils/src/LightAmbient.slh @@ -36,6 +36,13 @@ vec3 fresnelSchlickAmbient(vec3 fresnelColor, float ndotd, float gloss) { <$declareSkyboxMap()$> <@endif@> +float getMipLevelFromRoughness(float roughness, float lodCount) { + // This should match the value in the CubeMap::convolveForGGX method (CubeMap.cpp) + float ROUGHNESS_1_MIP_RESOLUTION = 1.5; + float deltaLod = lodCount - ROUGHNESS_1_MIP_RESOLUTION; + return (sqrt(6.0*roughness+0.25)-0.5)*deltaLod*0.5; +} + vec3 evalAmbientSpecularIrradiance(LightAmbient ambient, SurfaceData surface, vec3 lightDir) { vec3 specularLight; <@if supportIfAmbientMapElseAmbientSphere@> @@ -43,10 +50,10 @@ vec3 evalAmbientSpecularIrradiance(LightAmbient ambient, SurfaceData surface, ve <@endif@> <@if supportAmbientMap@> { - float levels = getLightAmbientMapNumMips(ambient); - float m = 12.0 / (1.0+11.0*surface.roughness); - float lod = levels - m; + float levelCount = getLightAmbientMapNumMips(ambient); + float lod = getMipLevelFromRoughness(surface.roughness, levelCount); lod = max(lod, 0.0); + specularLight = evalSkyboxLight(lightDir, lod).xyz; } <@endif@> diff --git a/tools/oven/src/ui/SkyboxBakeWidget.cpp b/tools/oven/src/ui/SkyboxBakeWidget.cpp index 113346c5e7..2bea38b571 100644 --- a/tools/oven/src/ui/SkyboxBakeWidget.cpp +++ b/tools/oven/src/ui/SkyboxBakeWidget.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,15 @@ void SkyboxBakeWidget::setupUI() { // start a new row for next component ++rowIndex; + // setup a section to enable Ambient map baking + _ambientMapBox = new QCheckBox("Bake ambient map(s)"); + _ambientMapBox->setChecked(false); + + gridLayout->addWidget(_ambientMapBox, rowIndex, 1); + + // start a new row for next component + ++rowIndex; + // setup a section to choose the output directory QLabel* outputDirectoryLabel = new QLabel("Output Directory"); @@ -176,51 +186,67 @@ void SkyboxBakeWidget::bakeButtonClicked() { // if the URL doesn't have a scheme, assume it is a local file if (skyboxToBakeURL.scheme() != "http" && skyboxToBakeURL.scheme() != "https" && skyboxToBakeURL.scheme() != "ftp") { - skyboxToBakeURL.setScheme("file"); + skyboxToBakeURL = QUrl::fromLocalFile(fileURLString); } // everything seems to be in place, kick off a bake for this skybox now - auto baker = std::unique_ptr { - new TextureBaker(skyboxToBakeURL, image::TextureUsage::SKY_TEXTURE, outputDirectory.absolutePath()) - }; + addBaker(new TextureBaker(skyboxToBakeURL, image::TextureUsage::SKY_TEXTURE, outputDirectory.absolutePath()), + outputDirectory); - // move the baker to a worker thread - baker->moveToThread(Oven::instance().getNextWorkerThread()); + if (_ambientMapBox->isChecked()) { + QString ambientMapBaseFilename; + QString urlPath = skyboxToBakeURL.path(); + auto urlParts = urlPath.split('.'); - // invoke the bake method on the baker thread - QMetaObject::invokeMethod(baker.get(), "bake"); + urlParts.front() += "-ambient"; + ambientMapBaseFilename = QUrl(urlParts.front()).fileName(); - // make sure we hear about the results of this baker when it is done - connect(baker.get(), &TextureBaker::finished, this, &SkyboxBakeWidget::handleFinishedBaker); - - // add a pending row to the results window to show that this bake is in process - auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); - auto resultsRow = resultsWindow->addPendingResultRow(skyboxToBakeURL.fileName(), outputDirectory); - - // keep a unique_ptr to this baker - // and remember the row that represents it in the results table - _bakers.emplace_back(std::move(baker), resultsRow); + // we need to bake the corresponding ambient map too + addBaker(new TextureBaker(skyboxToBakeURL, image::TextureUsage::AMBIENT_TEXTURE, outputDirectory.absolutePath(), QString(), ambientMapBaseFilename), + outputDirectory); + } } } +void SkyboxBakeWidget::addBaker(TextureBaker* baker, const QDir& outputDirectory) { + auto textureBaker = std::unique_ptr{ baker }; + + // move the textureBaker to a worker thread + textureBaker->moveToThread(Oven::instance().getNextWorkerThread()); + + // invoke the bake method on the textureBaker thread + QMetaObject::invokeMethod(textureBaker.get(), "bake"); + + // make sure we hear about the results of this textureBaker when it is done + connect(textureBaker.get(), &TextureBaker::finished, this, &SkyboxBakeWidget::handleFinishedBaker); + + // add a pending row to the results window to show that this bake is in process + auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); + auto resultsRow = resultsWindow->addPendingResultRow(baker->getBaseFilename(), outputDirectory); + + // keep a unique_ptr to this textureBaker + // and remember the row that represents it in the results table + _bakers.emplace_back(std::move(textureBaker), resultsRow); +} + void SkyboxBakeWidget::handleFinishedBaker() { - if (auto baker = qobject_cast(sender())) { + if (auto textureBaker = qobject_cast(sender())) { // add the results of this bake to the results window - auto it = std::find_if(_bakers.begin(), _bakers.end(), [baker](const BakerRowPair& value) { - return value.first.get() == baker; + auto it = std::find_if(_bakers.begin(), _bakers.end(), [textureBaker](const BakerRowPair& value) { + return value.first.get() == textureBaker; }); if (it != _bakers.end()) { auto resultRow = it->second; auto resultsWindow = OvenGUIApplication::instance()->getMainWindow()->showResultsWindow(); - if (baker->hasErrors()) { - resultsWindow->changeStatusForRow(resultRow, baker->getErrors().join("\n")); + if (textureBaker->hasErrors()) { + resultsWindow->changeStatusForRow(resultRow, textureBaker->getErrors().join("\n")); } else { resultsWindow->changeStatusForRow(resultRow, "Success"); } - // drop our strong pointer to the baker now that we are done with it + // drop our strong pointer to the textureBaker now that we are done with it _bakers.erase(it); } } diff --git a/tools/oven/src/ui/SkyboxBakeWidget.h b/tools/oven/src/ui/SkyboxBakeWidget.h index f00ab07f33..f560964649 100644 --- a/tools/oven/src/ui/SkyboxBakeWidget.h +++ b/tools/oven/src/ui/SkyboxBakeWidget.h @@ -21,6 +21,7 @@ #include "BakeWidget.h" class QLineEdit; +class QCheckBox; class SkyboxBakeWidget : public BakeWidget { Q_OBJECT @@ -42,9 +43,12 @@ private: QLineEdit* _selectionLineEdit; QLineEdit* _outputDirLineEdit; + QCheckBox* _ambientMapBox; Setting::Handle _exportDirectory; Setting::Handle _selectionStartDirectory; + + void addBaker(TextureBaker* baker, const QDir& outputDir); }; #endif // hifi_SkyboxBakeWidget_h