Commit d110615e authored by Johannes Braun's avatar Johannes Braun
Browse files

A Bunch of decluttering and removal of unnecessary Stuff.

parent 1ff107d9
......@@ -28,7 +28,6 @@
#include <core/rendering/mesh_renderer.h>
#include <core/rendering/gbuffer.h>
#include <core/rendering/light_manager.h>
#include <core/rendering/texture_renderer.h>
#endif //!__GLARE_INCLUDE_CORE
\ No newline at end of file
#include <core/state.h>
#include <core/res/resources.h>
#include <core/objects/skybox.h>
#include <components/PlayerController.h>
#include <raytrace/tracer/pathtracer.h>
using namespace glare;
int main(int argc, char* argv[])
{
// Initialize engine from settings xml
core::state::initialize(files::asset("/preferences/default.xml"));
// Load a scene and attach it to the constant root
core::state::graph_root->attach(core::Resources::getInstance().getColladaFile(files::asset("meshes/scenery/cbox.dae")));
// Create a skybox
core::state::skybox->reset(core::Skybox::collectFilesFrom(files::asset("textures/ryfjallet/")));
// Add a PlayerController to move around
core::state::camera->getOwner()->makeComponent<component::PlayerController>();
// Create a Pathtracer and all needed stuff for it from the graph
auto pathtracer = std::make_unique<raytrace::Pathtracer>(core::state::graph_root);
// Render the scene with the pathtracer
core::state::mainLoop([&pathtracer](double delta) {
pathtracer->renderToScreen(core::state::window->getWidth(), core::state::window->getHeight());
});
}
\ No newline at end of file
#include <util/files.h>
#include <util/console.h>
#include <core/state.h>
#include <core/audio/sound_source.h>
#include <core/objects/skybox.h>
#include <core/rendering/gbuffer.h>
#include <core/res/resources.h>
#include <raytrace/tracer/pathtracer.h>
#include <components/FramerateCounter.h>
#include <components/PlayerController.h>
using namespace glare;
enum class RayGeneratorMode
{
eGBuffer = 0,
eDefault = 1
};
enum class RenderMode
{
eLines = 0,
eRaw = 1,
eGBuffer = 2,
ePathtrace = 3
};
// Default paths for easy change access
const fs::path engine_settings_path = files::asset("/preferences/default.xml");
const fs::path pathtracer_settings_path = files::asset("/preferences/pathtracer_default.xml");
const fs::path skybox_files_path = files::asset("/textures/ryfjallet/");
const fs::path env_audio_path = files::asset("/audio/env.wav");
const fs::path startup_scene_path = files::asset("/meshes/scenery/cbox.dae");
// My little all-enclosing pathtracer pointer
std::unique_ptr<raytrace::Pathtracer> pathtracer = nullptr;
// Some Application states
fs::path current_scene_root = startup_scene_path.parent_path();
RenderMode render_mode = RenderMode::eGBuffer;
RayGeneratorMode ray_generator_mode = RayGeneratorMode::eDefault;
// All functions used in here
void keyPress(controls::Key key, controls::KeyMods mods);
void loadScene(const fs::path& path, float scale = 1.f);
void drawDebugGui();
// Implementation
int main(int argc, char* argv[])
{
core::state::initialize(engine_settings_path);
core::Callbacks::addKeyDownCallback("main_application", keyPress);
// Create a skybox from cube map.
core::state::skybox->reset(core::Skybox::collectFilesFrom(skybox_files_path));
// Load the pre-determined startup scene
loadScene(startup_scene_path, 1.f);
// Make some ambient sound source
al::listenerf(al::ListenerParam::eGain, 0.02f);
auto audio_buffer = core::Resources::getInstance().getAudioBuffer(env_audio_path);
auto environment_source = core::state::graph_root->makeComponent<core::SoundSource>(audio_buffer->id());
environment_source->setLooping(true);
environment_source->play();
// Initialize an empty pathtracer
pathtracer = std::make_unique<raytrace::Pathtracer>();
pathtracer->loadSettings(pathtracer_settings_path);
// For debug purposes, add a frame rate counter to the root node, which will never be deleted/removed on runtime if not explicitly told so.
core::state::graph_root->makeComponent<component::FramerateCounter>();
core::state::mainLoop([&](double delta)
{
switch (render_mode)
{
case RenderMode::eLines:
{
gl::polygonMode(gl::Face::eFrontAndBack, gl::PolygonMode::eLine);
bool cull = gl::isEnabled(gl::EnableParameter::eCullFace);
gl::setEnabled(gl::EnableParameter::eCullFace, false);
if (core::state::graph_root)
core::state::graph_root->draw();
gl::setEnabled(gl::EnableParameter::eCullFace, cull);
gl::polygonMode(gl::Face::eFrontAndBack, gl::PolygonMode::eFill);
}
break;
case RenderMode::eRaw:
{
if (core::state::graph_root)
core::state::graph_root->draw();
}
break;
case RenderMode::eGBuffer:
{
core::state::gbuffer->activate();
if (core::state::graph_root)
core::state::graph_root->draw();
core::state::gbuffer->draw();
}
break;
case RenderMode::ePathtrace:
{
// If it's not manually initialized via the GUI button, initialize the Pathtracer here.
if (pathtracer->collector())
pathtracer->renderToScreen(core::state::window->getWidth(), core::state::window->getHeight());
else
pathtracer->reload(core::state::graph_root);
}
break;
}
drawDebugGui();
});
}
void keyPress(controls::Key key, controls::KeyMods mods)
{
switch (key) {
case controls::Key::e1: render_mode = RenderMode::eLines; break;
case controls::Key::e2: render_mode = RenderMode::eRaw; break;
case controls::Key::e3: render_mode = RenderMode::eGBuffer; break;
case controls::Key::e4: render_mode = RenderMode::ePathtrace; break;
default: break;
}
}
void loadScene(const fs::path& path, float scale)
{
// Ain't no need for the last scene anymore.
core::state::graph_root->clearChildren();
//Initialize some scene graph from an obj file
if (auto scene = core::Resources::getInstance().getColladaFile(path, scale))
{
core::state::graph_root->attach(scene);
}
else
{
core::state::quit();
console::prompt("Scene could not be loaded: " + path.string() + ". Press [ENTER] to exit.", 1);
}
std::shared_ptr<core::GraphNode> cam_node = core::state::graph_root->findFirstWithComponent<core::Camera>();
if (cam_node)
{
//If there are any cameras in the collada file, take the first one.
core::state::camera = cam_node->getComponent<core::Camera>();
}
else
{
//Add a camera to render from
cam_node = std::make_shared<core::GraphNode>("custom_camera");
cam_node->addComponent(core::state::camera);
core::state::graph_root->attach(cam_node);
}
//Attach a PlayerController to the current main camera, so we can fly around in the scene.
cam_node->makeComponent<component::PlayerController>();
// Reload Pathtracer if used.
if (pathtracer && pathtracer->collector())
pathtracer->reload(core::state::graph_root);
}
void drawDebugGui()
{
// Debug Window
ImGui::Begin("Debug", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
// Render Mode
ImGui::BeginNamedGroup("Render Mode");
{
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
int render_state = int(render_mode);
if (ImGui::Combo("", &render_state, { "OpenGL Wireframe", "OpenGL Raw Color", "OpenGL GBuffer", "Pathtracing" }))
render_mode = RenderMode(render_state);
ImGui::PopItemWidth();
}
ImGui::EndNamedGroup();
if (pathtracer->collector()) {
ImGui::Spacing();
ImGui::Title("Scene Settings");
ImGui::TextWrapped("By default, a transformation or mesh update will trigger a pathtracer sample count reset. If you want to limit this to explicit settings changes and camera movements, uncheck the following option.");
bool collector_active = pathtracer->collector()->isActive();
if (ImGui::Checkbox("Reset on scene update", &collector_active))
pathtracer->collector()->setActive(collector_active);
ImGui::Spacing();
if (ImGui::CollapsingHeader("Sampling and Performance"))
{
ImGui::BeginNamedGroup("Ray Generator");
int raygenstate = int(ray_generator_mode);
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
if (ImGui::Combo("", &raygenstate, { "GBuffer", "Default (BVH)" })) {
ray_generator_mode = RayGeneratorMode(raygenstate);
switch (ray_generator_mode)
{
case RayGeneratorMode::eDefault:
pathtracer->setGenerator(std::make_shared<raytrace::RayGeneratorDefault>());
break;
case RayGeneratorMode::eGBuffer:
pathtracer->setGenerator(std::make_shared<raytrace::RayGeneratorGBuffer>());
break;
default:
break;
}
}
ImGui::PopItemWidth();
ImGui::EndNamedGroup();
ImGui::Spacing();
ImGui::BeginNamedGroup("Samples");
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
ImGui::ProgressBar(pathtracer->currentSample() / float(pathtracer->getMaxSamples()), ImVec2(-1, 0),
("Current: " + std::to_string(pathtracer->currentSample()) + " of " + std::to_string(pathtracer->getMaxSamples())).c_str());
ImGui::PopItemWidth();
ImGui::Spacing();
int max_samples = pathtracer->getMaxSamples();
if (ImGui::DragInt("Maximum", &max_samples, 10, 1, 50000))
pathtracer->setMaxSamples(max_samples);
int spfr = pathtracer->getSamplesPerFrame();
if (ImGui::DragInt("per frame", &spfr, 0.1f, 1, 10))
pathtracer->setSamplesPerFrame(spfr);
ImGui::EndNamedGroup();
ImGui::Spacing();
ImGui::BeginNamedGroup("Bounces");
ImGui::TextWrapped("The global bounce limit clamps down all effect-dependant bounce limits to a unified maximum value.");
int bounces = pathtracer->getBounces();
if (ImGui::DragInt("Global Limit", &bounces, 0.1f, 0, 15))
pathtracer->setBounces(bounces);
ImGui::Spacing();
if (ImGui::TreeNode("Bounce Thresholds"))
{
// Let's keep this function locally near to the only place it's being used.
static auto effectBounces = [](const std::string &label, raytrace::EffectType effect)
{
int val = pathtracer->getEffectBounces(effect);
if (ImGui::DragInt(label.c_str(), &val, 0.1f, 0, 15))
pathtracer->setEffectBounces(effect, uint8_t(val));
};
effectBounces("Diffuse", raytrace::EffectType::eDiffuse);
effectBounces("Translucent", raytrace::EffectType::eTranslucent);
effectBounces("Reflective", raytrace::EffectType::eReflection);
effectBounces("Refractive", raytrace::EffectType::eRefraction);
effectBounces("Transparency", raytrace::EffectType::eTransparent);
effectBounces("Emissive", raytrace::EffectType::eEmissive);
ImGui::TreePop();
}
ImGui::EndNamedGroup();
ImGui::TextWrapped("The direct clamp setting will lead to the primary ray result color being clamped down to a set maximum. That means each color component will be clamped. The same applies to the \"clamp indirect\" setting for non-primary bounces.");
float clamp_direct = pathtracer->getClampDirect();
if (ImGui::DragFloat("Clamp Direct", &clamp_direct, 0.1f, 0.0f, 100.f))
pathtracer->setClampDirect(clamp_direct);
float clamp_indirect = pathtracer->getClampIndirect();
if (ImGui::DragFloat("Clamp Indirect", &clamp_indirect, 0.1f, 0.0f, 100.f))
pathtracer->setClampIndirect(clamp_indirect);
}
if (ImGui::CollapsingHeader("Linespace Thresholds"))
{
ImGui::Title("PDF Thresholds");
ImGui::TextWrapped("The following threshold values will determine as of which accumulated PDF value the Line Space should be used instead of the BVH.");
{
float acc = pathtracer->getAccuracyThreshold();
if (ImGui::DragFloat("Direct", &acc, 0.001f, 0.0f, 1.f))
pathtracer->setAccuracyThreshold(acc);
float shd = pathtracer->getShadowThreshold();
if (ImGui::DragFloat("Shadow", &shd, 0.001f, 0.0f, 1.f))
pathtracer->setShadowThreshold(shd);
}
ImGui::Title("Distance Threshold");
ImGui::TextWrapped("Works like a level of detail slider. This is the maximum path length with which the BVH should be used.");
{
float dt = pathtracer->getDistanceThreshold();
if (ImGui::DragFloat("Distance", &dt, 0.1f, 0.0f, 10000.f))
pathtracer->setDistanceThreshold(dt);
}
ImGui::Title("Bounce Thresholds");
ImGui::TextWrapped("The following threshold values will determine as of which bounce the Line Space should be used instead of the BVH. This can vary for every kind of effect.");
{
// Let's keep this function locally near to the only place it's being used.
static auto bounceControl = [](const std::string &label, raytrace::EffectType effect)
{
int val = pathtracer->getLinespaceBounceThreshold(effect);
if (ImGui::DragInt(label.c_str(), &val, 0.1f, 0, pathtracer->getEffectBounces(effect)))
pathtracer->setLinespaceBounceThresholds(effect, uint8_t(val));
};
bounceControl("Diffuse", raytrace::EffectType::eDiffuse);
bounceControl("Translucent", raytrace::EffectType::eTranslucent);
bounceControl("Reflective", raytrace::EffectType::eReflection);
bounceControl("Refractive", raytrace::EffectType::eRefraction);
bounceControl("Transparence", raytrace::EffectType::eTransparent);
bounceControl("Emissive", raytrace::EffectType::eEmissive);
}
}
ImGui::Spacing();
ImGui::Title("Save Render as...");
if (ImGui::FeatureButton("32bit HDR", ImVec2(ImGui::GetContentRegionAvailWidth() / 2, 0)))
pathtracer->saveRender(files::asset("/screenshots/render.hdr"));
ImGui::SameLine();
if (ImGui::FeatureButton("8bit PNG", ImVec2(ImGui::GetContentRegionAvailWidth(), 0)))
pathtracer->saveRender(files::asset("/screenshots/render.png"));
}
else if (ImGui::FeatureButton("Initialize Pathtracer", ImVec2(ImGui::GetContentRegionAvailWidth(), 0)))
{
pathtracer->reload(core::state::graph_root);
}
ImGui::Separator();
ImGui::Title("General Settings");
static int vsync = 0;
vsync = int(core::state::window->getVSync());
if (ImGui::Combo("VSync", &vsync, { "None", "60 FPS", "30 FPS", "20 FPS" }))
core::state::window->setVSync(VSync(vsync));
ImGui::Separator();
ImGui::Title("Controls");
ImGui::TitledDescription("Right Click", "Grab cursor, enables looking around. Right click again to release it.");
ImGui::TitledDescription("W/S", "Fly along the looking direction.");
ImGui::TitledDescription("A/D", "Fly along the horizontal perpendiculat to the looking direction.");
ImGui::TitledDescription("E", "Fly towards the relative up-direction.");
ImGui::TitledDescription("Q", "Fly towards the relative down-direction.");
ImGui::TitledDescription("1, 2, 3", "Toggle rendering mode.");
ImGui::End();
//Scene selection Window
ImGui::Begin("Scenes", nullptr, ImVec2(200, 300));
ImGui::Title(current_scene_root.string().c_str());
static float import_scale = 1.f;
ImGui::DragFloat("Scale", &import_scale, 0.01f, 0.01f, 100.0f);
ImGui::BeginGroup();
// Go to parent directory
if (ImGui::Button("..", ImVec2(ImGui::GetContentRegionAvailWidth(), 32)))
current_scene_root = current_scene_root.parent_path();
for (auto& p : fs::directory_iterator(current_scene_root)) {
fs::path path = p;
// Either draw directory button or...
if (is_directory(path) && ImGui::Button(path.filename().string().c_str(), ImVec2(ImGui::GetContentRegionAvailWidth(), 40)))
current_scene_root = path;
// ... draw a button which loads a dae file.
else if (path.extension() == ".dae" && ImGui::FeatureButton(path.filename().string().c_str(), ImVec2(ImGui::GetContentRegionAvailWidth(), 32)))
loadScene(path, import_scale);
}
ImGui::EndGroup();
ImGui::End();
}
\ No newline at end of file
#include "pathtracer_app.h"
int main(int argc, char* argv[])
{
glare::PathtracerApp app;
app.run(argc, argv);
return 0;
}
#include "pathtracer_app.h"
#include <components/Rotator.h>
#include <components/PlayerController.h>
#include <components/FramerateCounter.h>
#include <core/audio/sound_buffer.h>
#include <core/audio/sound_source.h>
#include <core/res/resources.h>
#include <util/openal.h>
#include <util/console.h>
namespace glare
{
PathtracerApp::PathtracerApp() : app::Application() {}
void PathtracerApp::onStart(const Arguments& arguments)
{
m_current_scene_root = files::asset("/meshes/scenery/");
//Create a skybox from cube map.
skybox().reset(core::Skybox::collectFilesFrom(files::asset("/textures/ryfjallet/")));
//initializeScene(m_current_scene_root / "TY_Plane.dae", 1.f);
//initializeScene(m_current_scene_root / "dragn.dae", 1.f);
//initializeScene(m_current_scene_root / "benchmark_stfd_bunny_diff.dae", 1.f);
initializeScene(m_current_scene_root / "cbox.dae", 1.f);
al::listenerf(al::ListenerParam::eGain, 0.02f);
auto audio_buffer = core::Resources::getInstance().getAudioBuffer(files::asset("/audio/env.wav"));
auto environment_source = core::state::graph_root->makeComponent<core::SoundSource>(audio_buffer->id());
environment_source->setLooping(true);
environment_source->play();
}
void PathtracerApp::onGui()
{
drawDebugWindow();
drawSceneSelector();
}
void PathtracerApp::onKeyPress(controls::Key key, controls::KeyMods mods)
{
switch (key) {
case controls::Key::e1: return setRenderMode(app::RenderMode::eLines);
case controls::Key::e2: return setRenderMode(app::RenderMode::eRaw);
case controls::Key::e3: return setRenderMode(app::RenderMode::eGBuffer);
case controls::Key::e4: return setRenderMode(app::RenderMode::ePathtrace);
default: break;
}
}
void PathtracerApp::initializeScene(fs::path path, float scale)
{
//Initialize some scene graph from an obj file
if (!(core::state::graph_root = core::Resources::getInstance().getColladaFile(path, scale)))
{
core::state::quit();
glfwTerminate();
Log_Error << "Scene could not be loaded: " << path;
console::prompt(1);
}
std::shared_ptr<core::GraphNode> cam_node = core::state::graph_root->findFirstWithComponent<core::Camera>();
if (cam_node)
{
//If there are any cameras in the collada file, take the first one.
core::state::camera = cam_node->getComponent<core::Camera>();
}
else
{
//Add a camera to render from
cam_node = std::make_shared<core::GraphNode>("custom_camera");
cam_node->addComponent(core::state::camera);
core::state::graph_root->attach(cam_node);
}
cam_node->makeComponent<component::PlayerController>();
core::state::graph_root->makeComponent<component::FramerateCounter>();
#define DEBUG__ADD_ROTATOR
#ifdef DEBUG__ADD_ROTATOR
if (auto node = core::state::graph_root->findFirstWithName("#Suzanne-mesh")) {
node->addComponent(std::make_shared<component::Rotator>());
}
#endif
}
void PathtracerApp::drawControlItem(std::string title, std::string description)
{
ImGui::Title(title.c_str());
ImGui::SameLine();
ImGui::TextWrapped(description.c_str());
}
void PathtracerApp::drawDebugWindow()
{
ImGui::Begin("Debug", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
// Render Mode
ImGui::BeginNamedGroup("Render Mode");
{
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
int render_state = int(renderMode());
if (ImGui::Combo("", &render_state, { "OpenGL Wireframe", "OpenGL Raw Color", "OpenGL GBuffer", "Pathtracing" }))
setRenderMode(app::RenderMode(render_state));
ImGui::PopItemWidth();
}
ImGui::EndNamedGroup();
if (pathtracerAvailable()) {
ImGui::Spacing();
ImGui::Title("Scene Settings");
ImGui::TextWrapped("By default, a transformation or mesh update will trigger a pathtracer sample count reset. If you want to limit this to explicit settings changes and camera movements, uncheck the following option.");
bool collector_active = pathtracer().collector()->isActive();
if (ImGui::Checkbox("Reset on scene update", &collector_active))
pathtracer().collector()->setActive(collector_active);
ImGui::Spacing();
if (ImGui::CollapsingHeader("Sampling and Performance"))
{
ImGui::BeginNamedGroup("Ray Generator");
int raygenstate = int(m_ray_gen_state);
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
if (ImGui::Combo("", &raygenstate, { "GBuffer", "Default (BVH)" })) {
m_ray_gen_state = AppRayGenState(raygenstate);
switch (m_ray_gen_state)
{
case AppRayGenState::eDefault:
pathtracer().setGenerator(std::make_shared<raytrace::RayGeneratorDefault>());
break;
case AppRayGenState::eGBuffer:
pathtracer().setGenerator(std::make_shared<raytrace::RayGeneratorGBuffer>());
break;
default:
break;
}
}
ImGui::PopItemWidth();
ImGui::EndNamedGroup();
ImGui::Spacing();
ImGui::BeginNamedGroup("Samples");
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
ImGui::ProgressBar(pathtracer().currentSample() / float(pathtracer().getMaxSamples()), ImVec2(-1, 0),
("Current: " + std::to_string(pathtracer().currentSample()) + " of " + std::to_string(pathtracer().getMaxSamples())).c_str());
ImGui::PopItemWidth();
ImGui::Spacing();
int max_samples = pathtracer().getMaxSamples();
if (ImGui::DragInt("Maximum", &max_samples, 10, 1, 50000))
pathtracer().setMaxSamples(max_samples);
int spfr = pathtracer().getSamplesPerFrame();
if (ImGui::DragInt("per frame", &spfr, 0.1f, 1, 10))
pathtracer().setSamplesPerFrame(spfr);