From fd142b9b84dd371e1ae344af19dcdacdca601d87 Mon Sep 17 00:00:00 2001 From: Philip Rideout Date: Thu, 1 Oct 2020 13:46:06 -0700 Subject: [PATCH] gltf_viewer: add --settings, prep for automation. --- .gitignore | 1 + libs/viewer/include/viewer/Settings.h | 10 ++- libs/viewer/src/Automation.cpp | 2 +- libs/viewer/src/Settings.cpp | 37 +++++++++ libs/viewer/src/SimpleViewer.cpp | 12 +-- samples/CMakeLists.txt | 2 +- samples/gltf_viewer.cpp | 110 ++++++++++++++++---------- 7 files changed, 118 insertions(+), 56 deletions(-) diff --git a/.gitignore b/.gitignore index adc1544963..b40cdadf16 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ filament/docs/html/** *tmp*.png civetweb.txt /TAGS +settings.json diff --git a/libs/viewer/include/viewer/Settings.h b/libs/viewer/include/viewer/Settings.h index aaefb07402..b5b02b6f06 100644 --- a/libs/viewer/include/viewer/Settings.h +++ b/libs/viewer/include/viewer/Settings.h @@ -51,6 +51,12 @@ using VignetteOptions = filament::View::VignetteOptions; // - This function writes warnings and error messages into the utils log. bool readJson(const char* jsonChunk, size_t size, Settings* out); +// Pushes all properties to a Filament View modulo the immutable ones (e.g. ColorGrading). +void applySettings(const ViewSettings& settings, View* dest); + +// Creates a new ColorGrading object based on the given settings. +ColorGrading* createColorGrading(const ColorGradingSettings& settings, Engine* engine); + // Generates human-readable JSON strings from settings objects. std::string writeJson(const AmbientOcclusionOptions& in); std::string writeJson(const BloomOptions& in); @@ -68,8 +74,8 @@ struct ColorGradingSettings { bool enabled = true; filament::ColorGrading::QualityLevel quality = filament::ColorGrading::QualityLevel::MEDIUM; ToneMapping toneMapping = ToneMapping::ACES_LEGACY; - int temperature = 0; - int tint = 0; + float temperature = 0; + float tint = 0; math::float3 outRed{1.0f, 0.0f, 0.0f}; math::float3 outGreen{0.0f, 1.0f, 0.0f}; math::float3 outBlue{0.0f, 0.0f, 1.0f}; diff --git a/libs/viewer/src/Automation.cpp b/libs/viewer/src/Automation.cpp index c16adcf8a0..79673c6b39 100644 --- a/libs/viewer/src/Automation.cpp +++ b/libs/viewer/src/Automation.cpp @@ -50,7 +50,7 @@ static const char* DEFAULT_AUTOMATION = R"TXT([ "view.dithering": ["NONE", "TEMPORAL"], "view.sampleCount": [1, 4], "view.taa.enabled": [false, true], - "view.antiAliasing": ["FXAA", "NONE"], + "view.antiAliasing": ["NONE", "FXAA"], "view.ssao.enabled": [false, true], "view.bloom.enabled": [false, true] } diff --git a/libs/viewer/src/Settings.cpp b/libs/viewer/src/Settings.cpp index ed5065671e..0314137f2d 100644 --- a/libs/viewer/src/Settings.cpp +++ b/libs/viewer/src/Settings.cpp @@ -613,6 +613,43 @@ bool readJson(const char* jsonChunk, size_t size, Settings* out) { return i >= 0; } +void applySettings(const ViewSettings& settings, View* dest) { + dest->setSampleCount(settings.sampleCount); + dest->setAntiAliasing(settings.antiAliasing); + dest->setTemporalAntiAliasingOptions(settings.taa); + dest->setAmbientOcclusionOptions(settings.ssao); + dest->setBloomOptions(settings.bloom); + dest->setFogOptions(settings.fog); + dest->setDepthOfFieldOptions(settings.dof); + dest->setVignetteOptions(settings.vignette); + dest->setDithering(settings.dithering); + dest->setRenderQuality(settings.renderQuality); + dest->setDynamicLightingOptions(settings.dynamicLighting.zLightNear, + settings.dynamicLighting.zLightFar); + dest->setShadowType(settings.shadowType); + dest->setPostProcessingEnabled(settings.postProcessingEnabled); +} + +ColorGrading* createColorGrading(const ColorGradingSettings& settings, Engine* engine) { + return ColorGrading::Builder() + .quality(settings.quality) + .whiteBalance(settings.temperature, settings.tint) + .channelMixer(settings.outRed, settings.outGreen, settings.outBlue) + .shadowsMidtonesHighlights( + Color::toLinear(settings.shadows), + Color::toLinear(settings.midtones), + Color::toLinear(settings.highlights), + settings.ranges + ) + .slopeOffsetPower(settings.slope, settings.offset, settings.power) + .contrast(settings.contrast) + .vibrance(settings.vibrance) + .saturation(settings.saturation) + .curves(settings.gamma, settings.midPoint, settings.scale) + .toneMapping(settings.toneMapping) + .build(*engine); +} + static std::string writeJson(bool v) { return v ? "true" : "false"; } static std::string writeJson(float v) { return std::to_string(v); } static std::string writeJson(int v) { return std::to_string(v); } diff --git a/libs/viewer/src/SimpleViewer.cpp b/libs/viewer/src/SimpleViewer.cpp index 2cfb7fd117..c64745a9b5 100644 --- a/libs/viewer/src/SimpleViewer.cpp +++ b/libs/viewer/src/SimpleViewer.cpp @@ -368,13 +368,9 @@ void SimpleViewer::updateUserInterface() { ImGui::Unindent(); } - mView->setDithering(mViewSettings.dithering); - mView->setAntiAliasing(mViewSettings.antiAliasing); - mView->setSampleCount(mViewSettings.sampleCount); - mView->setAmbientOcclusionOptions(mViewSettings.ssao); - mView->setBloomOptions(mViewSettings.bloom); - mView->setFogOptions(mViewSettings.fog); - mView->setTemporalAntiAliasingOptions(mViewSettings.taa); + // At this point, all View settings have been modified, + // so we can now push them into the Filament View. + applySettings(mViewSettings, mView); if (mEnableSunlight) { mScene->addEntity(mSunlight); @@ -400,8 +396,6 @@ void SimpleViewer::updateUserInterface() { lm.setShadowCaster(ci, mEnableShadows); }); - mView->setShadowType(mViewSettings.shadowType); - if (mAsset != nullptr) { if (ImGui::CollapsingHeader("Hierarchy")) { ImGui::Indent(); diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index feb27bbc5f..fafa17407a 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -240,7 +240,7 @@ if (NOT ANDROID) # Sample app specific target_link_libraries(frame_generator PRIVATE imageio) - target_link_libraries(gltf_viewer PRIVATE gltf-resources gltfio viewer) + target_link_libraries(gltf_viewer PRIVATE gltf-resources gltfio viewer imageio) target_link_libraries(gltf_instances PRIVATE gltf-resources gltfio viewer) target_link_libraries(hellopbr PRIVATE filameshio suzanne-resources) target_link_libraries(sample_cloth PRIVATE filameshio) diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp index 87b4364b11..b5f1ff0a9d 100644 --- a/samples/gltf_viewer.cpp +++ b/samples/gltf_viewer.cpp @@ -34,6 +34,11 @@ #include #include +#include + +#include + +#include #include #include @@ -52,6 +57,7 @@ #include #include +#include #include #include "generated/resources/gltf_viewer.h" @@ -61,6 +67,7 @@ using namespace filament::math; using namespace filament::viewer; using namespace gltfio; +using namespace image; using namespace utils; struct App { @@ -91,9 +98,6 @@ struct App { sRGBColor backgroundColor = { 0.0f }; } viewOptions; - View::DepthOfFieldOptions dofOptions; - View::VignetteOptions vignetteOptions; - struct Scene { Entity groundPlane; VertexBuffer* groundVertexBuffer; @@ -111,6 +115,9 @@ struct App { // 0 is the default "free camera". Additional cameras come from the gltf file. int currentCamera = 0; + + std::string messageBoxText; + std::string settingsFile; }; static const char* DEFAULT_IBL = "default_env"; @@ -132,6 +139,8 @@ static void printUsage(char* name) { " Do not scale the model to fit into a unit cube\n\n" " --recompute-aabb, -r\n" " Ignore the min/max attributes in the glTF file\n\n" + " --settings=, -t\n" + " Apply the settings in the given JSON file.\n\n" " --ubershader, -u\n" " Enable ubershaders (improves load time, adds shader complexity)\n\n" " --camera=, -c \n" @@ -151,7 +160,7 @@ static void printUsage(char* name) { } static int handleCommandLineArguments(int argc, char* argv[], App* app) { - static constexpr const char* OPTSTR = "ha:i:usc:r"; + static constexpr const char* OPTSTR = "ha:i:usc:rt:"; static const struct option OPTIONS[] = { { "help", no_argument, nullptr, 'h' }, { "api", required_argument, nullptr, 'a' }, @@ -160,6 +169,7 @@ static int handleCommandLineArguments(int argc, char* argv[], App* app) { { "actual-size", no_argument, nullptr, 's' }, { "camera", required_argument, nullptr, 'c' }, { "recompute-aabb", no_argument, nullptr, 'r' }, + { "settings", optional_argument, nullptr, 't' }, { nullptr, 0, nullptr, 0 } }; int opt; @@ -203,6 +213,12 @@ static int handleCommandLineArguments(int argc, char* argv[], App* app) { case 'r': app->recomputeAabb = true; break; + case 't': + if (arg.empty()) { + arg = "settings.json"; + } + app->settingsFile = arg; + break; } } return optind; @@ -213,6 +229,19 @@ static std::ifstream::pos_type getFileSize(const char* filename) { return in.tellg(); } +static bool loadSettings(const char* filename, Settings* out) { + auto contentSize = getFileSize(filename); + if (contentSize <= 0) { + return false; + } + std::ifstream in(filename, std::ifstream::binary | std::ifstream::in); + std::vector json(static_cast(contentSize)); + if (!in.read(json.data(), contentSize)) { + return false; + } + return readJson(json.data(), contentSize, out); +} + static void createGroundPlane(Engine* engine, Scene* scene, App& app) { auto& em = EntityManager::get(); Material* shadowMaterial = Material::Builder() @@ -402,8 +431,8 @@ static void colorGradingUI(App& app) { colorGrading.toneMapping = (decltype(colorGrading.toneMapping)) toneMapping; if (ImGui::CollapsingHeader("White balance")) { - ImGui::SliderInt("Temperature", &colorGrading.temperature, -100, 100); - ImGui::SliderInt("Tint", &colorGrading.tint, -100, 100); + ImGui::SliderFloat("Temperature", &colorGrading.temperature, -1.0f, 1.0f); + ImGui::SliderFloat("Tint", &colorGrading.tint, -1.0f, 1.0f); } if (ImGui::CollapsingHeader("Channel mixer")) { pushSliderColors(0.0f / 7.0f); @@ -633,6 +662,18 @@ int main(int argc, char** argv) { app.engine = engine; app.names = new NameComponentManager(EntityManager::get()); app.viewer = new SimpleViewer(engine, scene, view, 410); + + if (app.settingsFile.size() > 0) { + Settings settings; + bool success = loadSettings(app.settingsFile.c_str(), &settings); + if (success) { + std::cout << "Loaded settings from " << app.settingsFile << std::endl; + app.viewer->getViewSettings() = settings.view; + } else { + std::cerr << "Failed to load settings from " << app.settingsFile << std::endl; + } + } + app.materials = (app.materialSource == GENERATE_SHADERS) ? createMaterialGenerator(engine) : createUbershaderLoader(engine); app.loader = AssetLoader::create({engine, app.materials, app.names }); @@ -675,21 +716,23 @@ int main(int argc, char** argv) { } if (ImGui::CollapsingHeader("Camera")) { + ViewSettings& settings = app.viewer->getViewSettings(); + ImGui::Indent(); ImGui::SliderFloat("Focal length (mm)", &FilamentApp::get().getCameraFocalLength(), 16.0f, 90.0f); ImGui::SliderFloat("Aperture", &app.viewOptions.cameraAperture, 1.0f, 32.0f); ImGui::SliderFloat("Speed (1/s)", &app.viewOptions.cameraSpeed, 1000.0f, 1.0f); ImGui::SliderFloat("ISO", &app.viewOptions.cameraISO, 25.0f, 6400.0f); - ImGui::Checkbox("DoF", &app.dofOptions.enabled); - ImGui::SliderFloat("Focus distance", &app.dofOptions.focusDistance, 0.0f, 30.0f); - ImGui::SliderFloat("Blur scale", &app.dofOptions.cocScale, 0.1f, 10.0f); + ImGui::Checkbox("DoF", &settings.dof.enabled); + ImGui::SliderFloat("Focus distance", &settings.dof.focusDistance, 0.0f, 30.0f); + ImGui::SliderFloat("Blur scale", &settings.dof.cocScale, 0.1f, 10.0f); if (ImGui::CollapsingHeader("Vignette")) { - ImGui::Checkbox("Enabled##vignetteEnabled", &app.vignetteOptions.enabled); - ImGui::SliderFloat("Mid point", &app.vignetteOptions.midPoint, 0.0f, 1.0f); - ImGui::SliderFloat("Roundness", &app.vignetteOptions.roundness, 0.0f, 1.0f); - ImGui::SliderFloat("Feather", &app.vignetteOptions.feather, 0.0f, 1.0f); - ImGui::ColorEdit3("Color##vignetteColor", &app.vignetteOptions.color.r); + ImGui::Checkbox("Enabled##vignetteEnabled", &settings.vignette.enabled); + ImGui::SliderFloat("Mid point", &settings.vignette.midPoint, 0.0f, 1.0f); + ImGui::SliderFloat("Roundness", &settings.vignette.roundness, 0.0f, 1.0f); + ImGui::SliderFloat("Feather", &settings.vignette.feather, 0.0f, 1.0f); + ImGui::ColorEdit3("Color##vignetteColor", &settings.vignette.color.r); } const utils::Entity* cameras = app.asset->getCameraEntities(); @@ -721,11 +764,15 @@ int main(int argc, char** argv) { } colorGradingUI(app); - }); - // Leave FXAA enabled but we also enable MSAA for a nice result. The wireframe looks - // much better with MSAA enabled. - view->setSampleCount(4); + if (ImGui::BeginPopupModal("MessageBox", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("%s", app.messageBoxText.c_str()); + if (ImGui::Button("OK", ImVec2(120, 0))) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + }); }; auto cleanup = [&app](Engine* engine, View*, Scene*) { @@ -805,9 +852,6 @@ int main(int argc, char** argv) { 1.0f / app.viewOptions.cameraSpeed, app.viewOptions.cameraISO); - view->setDepthOfFieldOptions(app.dofOptions); - view->setVignetteOptions(app.vignetteOptions); - app.scene.groundMaterial->setDefaultParameter( "strength", app.viewOptions.groundShadowStrength); @@ -828,28 +872,8 @@ int main(int argc, char** argv) { // An inefficient but simple way of detecting change is to serialize to JSON, then // do a string comparison. if (writeJson(options) != writeJson(app.lastColorGradingOptions)) { - ColorGrading *colorGrading = ColorGrading::Builder() - .quality(options.quality) - .whiteBalance(options.temperature / 100.0f, options.tint / 100.0f) - .channelMixer(options.outRed, options.outGreen, options.outBlue) - .shadowsMidtonesHighlights( - Color::toLinear(options.shadows), - Color::toLinear(options.midtones), - Color::toLinear(options.highlights), - options.ranges - ) - .slopeOffsetPower(options.slope, options.offset, options.power) - .contrast(options.contrast) - .vibrance(options.vibrance) - .saturation(options.saturation) - .curves(options.gamma, options.midPoint, options.scale) - .toneMapping(options.toneMapping) - .build(*engine); - - if (app.colorGrading) { - engine->destroy(app.colorGrading); - } - + ColorGrading *colorGrading = createColorGrading(options, engine); + engine->destroy(app.colorGrading); app.colorGrading = colorGrading; app.lastColorGradingOptions = options; }