gltf_viewer: add --settings, prep for automation.

This commit is contained in:
Philip Rideout
2020-10-01 13:46:06 -07:00
parent 6658283617
commit fd142b9b84
7 changed files with 118 additions and 56 deletions

1
.gitignore vendored
View File

@@ -12,3 +12,4 @@ filament/docs/html/**
*tmp*.png
civetweb.txt
/TAGS
settings.json

View File

@@ -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};

View File

@@ -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]
}

View File

@@ -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); }

View File

@@ -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();

View File

@@ -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)

View File

@@ -34,6 +34,11 @@
#include <gltfio/FilamentAsset.h>
#include <gltfio/ResourceLoader.h>
#include <image/ColorTransform.h>
#include <imageio/ImageEncoder.h>
#include <viewer/Automation.h>
#include <viewer/SimpleViewer.h>
#include <camutils/Manipulator.h>
@@ -52,6 +57,7 @@
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#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=<path to JSON file>, -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=<camera mode>, -c <camera mode>\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<char> json(static_cast<unsigned long>(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;
}