gltf_viewer: add --settings, prep for automation.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,3 +12,4 @@ filament/docs/html/**
|
||||
*tmp*.png
|
||||
civetweb.txt
|
||||
/TAGS
|
||||
settings.json
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user