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

Several improvements for graph editing (Not crashing as often anymore)

parent 7c53a4a7
......@@ -142,8 +142,8 @@ BSDFResult computeLambert(const in SampledMaterial sampled_material, const in Ra
BSDFResult lambert_result;
lambert_result.evaluation = (1-sampled_material.metallic)*sampled_material.base * ONE_OVER_PI;
lambert_result.generated_ray = ray_in;
lambert_result.generated_ray.direction = normalize(localToWorld(randCosineHemisphere(random.x, random.y), normal));
lambert_result.probability_density = abs(dot(vec4(lambert_result.generated_ray.direction, 0), vertex.normal)) * ONE_OVER_PI;
lambert_result.generated_ray.direction = localToWorld(randCosineHemisphere(random.x, random.y), vertex.normal.xyz);
lambert_result.probability_density = abs(dot(lambert_result.generated_ray.direction, vertex.normal.xyz)) * ONE_OVER_PI;
lambert_result.radiance = (1-sampled_material.metallic)*sampled_material.base * ONE_OVER_PI;
lambert_result.bsdf_id = eDiffuse;
// offset by newly generated direction
......@@ -192,7 +192,7 @@ BSDFResult computeBSDF(const in Material material, const in vec2 random, const i
const float ior_out = enters ? sampled_material.ior : 1;
// Russian roulette.
const float roulette_random = rand(int(12301 * random.x + 99373 * random.y));
const float roulette_random = rand(int(12301 * random.x + random.y));
const bool emits = roulette_random < k_e;
const bool reflects = roulette_random < k_s || (k_t > 0 && roulette_random < k_s + k_t && isTotalReflection(ior_in, ior_out, incoming, hemisphere_sample.micro_normal));
const bool transmits = roulette_random < k_s + k_t;
......
......@@ -8,6 +8,7 @@
#include <pathtracer/data/mesh_bvh.glsl>
#include <pathtracer/data/mesh_linespace.glsl>
uniform bool use_global_bvh;
bool traverseObjects(const in Ray ray, const in bool use_first, const in float max_distance, inout Hit hit, inout float t_min, bool force_bvh = false);
......@@ -26,111 +27,146 @@ bool intersectsAny(const in Ray ray, const in float max_distance, bool force_bvh
bool traverseObjects(const in Ray ray, const in bool use_first, const in float max_distance, inout Hit hit, inout float t_min, bool force_bvh = false)
{
float t = t_min;
float max_dist = max_distance;
// Check once the AABB for the whole scene
bool hit_scene = global_bvh_nodes_data.length() != 0 && ray.intersectsBounds(global_bvh_nodes_data[0].bounds, max_distance);
bool hit_triangle = false;
int current_node = 0;
int bitstack = 0;
Hit unused;
while (hit_scene)
if(!use_global_bvh)
{
if (global_bvh_nodes_data[current_node].type == 0) //Inner node.
float current_t = t_min;
bool hit_triangle = false;
Hit unused;
for(int i=0; i<meshes_data.length(); ++i)
{
int id_left = int(global_bvh_nodes_data[current_node].left_idx);
bool hit_left = ray.intersectsBounds(global_bvh_nodes_data[id_left].bounds, max_distance);
int id_right = int(global_bvh_nodes_data[current_node].right_idx);
bool hit_right = ray.intersectsBounds(global_bvh_nodes_data[id_right].bounds, max_distance);
//both hit
if (hit_left && hit_right)
const Mesh mesh = meshes_data[i];
if(force_bvh)
{
// shift bitstack and mark as branched, so we can use the marker
// when backtracking to stop here and use the right child.
bitstack = bitstack << 1;
current_node = id_left;
bitstack = bitstack | 1;
continue;
}
// only left hit
else if (hit_left && !hit_right)
{
// Not branching here, the other sibling-check won't be needed here.
bitstack = bitstack << 1;
current_node = id_left;
continue;
if(mesh.traverseBVH(ray.makeRelative(mesh), use_first, current_t, false, hit, unused, t_min)){
hit_triangle = true;
if (use_first)
{
return true;
}
}
}
// only right hit
else if (!hit_left && hit_right)
else
{
// Not branching here, the other sibling-check won't be needed here.
bitstack = bitstack << 1;
current_node = id_right;
continue;
if(mesh.traverseLineSpace(ray.makeRelative(mesh), use_first, current_t, hit, t_min)){
hit_triangle = true;
if (use_first)
{
return true;
}
}
}
}
else
return hit_triangle;
}
else
{
float t = t_min;
float max_dist = max_distance;
// Check once the AABB for the whole scene
bool hit_scene = global_bvh_nodes_data.length() != 0 && ray.intersectsBounds(global_bvh_nodes_data[0].bounds, max_distance);
bool hit_triangle = false;
int current_node = 0;
int bitstack = 0;
Hit unused;
while (hit_scene)
{
//Is leaf
// intersect ray with primitives.
//shorten ray if closer intersection found.
//intersect triangles
if (global_bvh_nodes_data[current_node].type == 0) //Inner node.
{
int id_left = int(global_bvh_nodes_data[current_node].left_idx);
bool hit_left = ray.intersectsBounds(global_bvh_nodes_data[id_left].bounds, max_distance);
int start = int(global_bvh_nodes_data[current_node].left_idx);
int end = int(global_bvh_nodes_data[current_node].right_idx);
int id_right = int(global_bvh_nodes_data[current_node].right_idx);
bool hit_right = ray.intersectsBounds(global_bvh_nodes_data[id_right].bounds, max_distance);
for (int i = start; i <= end; i++)
//both hit
if (hit_left && hit_right)
{
// shift bitstack and mark as branched, so we can use the marker
// when backtracking to stop here and use the right child.
bitstack = bitstack << 1;
current_node = id_left;
bitstack = bitstack | 1;
continue;
}
// only left hit
else if (hit_left && !hit_right)
{
// Not branching here, the other sibling-check won't be needed here.
bitstack = bitstack << 1;
current_node = id_left;
continue;
}
// only right hit
else if (!hit_left && hit_right)
{
// Not branching here, the other sibling-check won't be needed here.
bitstack = bitstack << 1;
current_node = id_right;
continue;
}
}
else
{
//Is leaf
// intersect ray with primitives.
//shorten ray if closer intersection found.
//intersect triangles
int start = int(global_bvh_nodes_data[current_node].left_idx);
int end = int(global_bvh_nodes_data[current_node].right_idx);
float current_t = t_min;
const Mesh mesh = meshes_data[i];
if(force_bvh)
for (int i = start; i <= end; i++)
{
if(mesh.traverseBVH(ray.makeRelative(mesh), use_first, current_t, false, hit, unused, t_min)){
hit_triangle = true;
if (use_first)
{
return true;
const Mesh mesh = meshes_data[i];
if(force_bvh)
{
if(mesh.traverseBVH(ray.makeRelative(mesh), use_first, current_t, false, hit, unused, t_min)){
hit_triangle = true;
if (use_first)
{
return true;
}
}
}
}
else
{
if(mesh.traverseLineSpace(ray.makeRelative(mesh), use_first, current_t, hit, t_min)){
hit_triangle = true;
if (use_first)
{
return true;
else
{
if(mesh.traverseLineSpace(ray.makeRelative(mesh), use_first, current_t, hit, t_min)){
hit_triangle = true;
if (use_first)
{
return true;
}
}
}
}
}
}
}
//Backtrace on bitstack until we find a branching point (where bit value is 1)
while ((bitstack & 1) == 0)
{
//Empty bitstack
if (bitstack == 0)
//Backtrace on bitstack until we find a branching point (where bit value is 1)
while ((bitstack & 1) == 0)
{
return hit_triangle;
//Empty bitstack
if (bitstack == 0)
{
return hit_triangle;
}
current_node = int(global_bvh_nodes_data[current_node].parent);
bitstack = bitstack >> 1;
}
current_node = int(global_bvh_nodes_data[current_node].parent);
bitstack = bitstack >> 1;
//Use other (right) sibling from the left child of the branched tree node.
current_node = int(global_bvh_nodes_data[global_bvh_nodes_data[current_node].parent].right_idx);
bitstack = bitstack ^ 1;
}
//Use other (right) sibling from the left child of the branched tree node.
current_node = int(global_bvh_nodes_data[global_bvh_nodes_data[current_node].parent].right_idx);
bitstack = bitstack ^ 1;
return hit_triangle;
}
return hit_triangle;
}
#endif //INCLUDE_PATHTRACER_DATASTRUCTURE_GLSL
......@@ -121,7 +121,8 @@ bool shade(int id, inout vec3 radiance, uint bounce, out uint bsdf_id)
// generate a random sample on each bounce so there won't be any notifiable patterns
const vec2 base_random = vec2(ray.px, ray.py) - ivec2(floor(ray.px), floor(ray.py));
const ivec2 img_size = u_render_target.imageSize();
vec2 random_sample = rand2D(random_seed + int(id + base_random.x * 60337 + base_random.y * 27487) + int(bounce), img_size.x * img_size.y);
const int img_dimen = img_size.x * img_size.y;
vec2 random_sample = rand2D((random_seed + int(id))%img_dimen, img_size.x * img_size.y);
BSDFResult bsdf_result = material.computeBSDF(random_sample, vertex, ray);
......
......@@ -46,7 +46,8 @@ void depthOfField(const in Camera camera, inout Ray ray, const in vec2 random)
Ray getRayFromPixel(const in Camera camera, const in vec2 pixel, const in vec2 sub_pixel, const in vec2 pixel_count)
{
// Take a direction jittering that is different from the subpixel offset. Otherwise it will result in weirdness.
const vec2 directional_offset = rand2D(int(pixel.x + pixel.y * pixel_count.x), int(pixel_count.x*pixel_count.y));
const int img_dimen = int(pixel_count.x*pixel_count.y);
const vec2 directional_offset = rand2D((int(pixel.x + pixel.y * pixel_count.x)+int(sub_pixel.x* 1209 + sub_pixel.y* 129199))%img_dimen, img_dimen);
Ray ray;
ray.origin = camera.position;
......
......@@ -26,8 +26,8 @@ void on_scroll(double xoffset, double yoffset)
int main(int argc, char* argv[])
{
core::state::initialize(files::asset("/preferences/default.xml"));
core::Callbacks::addScrollCallback("main", on_scroll);
core::Context::createAsCurrent(files::asset("/preferences/default.xml"));
core::Context::current().callbacks().addScrollCallback("main", on_scroll);
auto texture_renderer = core::DefaultTextureRenderers::makeCenterTextureRenderer();
texture_renderer->addPreDrawCallback([](const core::Program& program)
......@@ -42,7 +42,7 @@ int main(int argc, char* argv[])
core::Program heatmap_generator(files::shader("/heatmap/heatmap.comp"));
core::state::mainLoop([&texture_renderer, &image, &heatmap_other_image, &heatmap, &heatmap_generator]()
core::Context::current().loop([&texture_renderer, &image, &heatmap_other_image, &heatmap, &heatmap_generator]()
{
static int current_tab = 0;
......
......@@ -143,7 +143,6 @@ void loadScene(const fs::path& path, float scale)
if(!had_player_controller)
cam_node->makeComponent<component::PlayerController>();
// Reload Pathtracer if used.
if (pathtracer && pathtracer->collector())
pathtracer->reload(core::Context::current().graph());
......@@ -293,7 +292,9 @@ void drawSceneWindow()
else if (path.extension() == ".dae" && ImGui::FeatureButton(path.filename().string().c_str(), ImVec2(ImGui::GetContentRegionAvailWidth(), 32)))
{
if (selected_node)
{
selected_node->attach(core::Collada().load(path, import_scale));
}
}
}
ImGui::PopStyleVar();
......@@ -471,6 +472,14 @@ void drawSettingsWindow()
bool collector_active = pathtracer->collector()->isActive();
if (ImGui::Checkbox("Reset on scene update", &collector_active))
pathtracer->collector()->setActive(collector_active);
ImGui::Spacing();
auto format = static_cast<int>(pathtracer->collector()->getSceneFormat());
if (ImGui::Combo("", &format, { "Default", "Global BVH" }))
{
pathtracer->collector()->setSceneFormat(static_cast<raytrace::SceneFormat>(format));
pathtracer->reset();
}
}
break;
case 1:
......
#include <iostream>
#include <string>
#include <cassert>
#include <functional>
template<>
struct prop
{
};
#include <util/property.h>
int main()
{
Property<unsigned> uiprop1([](const auto& val) {
std::cout << "Changed val to " << val << '\n';
});
Property<unsigned> uiprop2([]() {
std::cout << "Changed val!\n";
});
uiprop1 = 201;
uiprop2 = uiprop1 + 20;
system("pause");
return 0;
......
......@@ -203,7 +203,7 @@ namespace glare::core
if (m_current_context == this)
m_current_context = nullptr;
m_contexts.erase(id());
m_messages->lock();
//m_messages->lock();
m_window.close();
//m_graph_root->clearChildren();
//messaging::Handler::getInstance().unlock();
......
......@@ -53,6 +53,7 @@ namespace glare::raytrace
void CameraCollector::apply(core::Program &program)
{
program.uniformStruct("u_camera", m_cameras[m_active_camera]);
if(!m_cameras.empty())
program.uniformStruct("u_camera", m_cameras[m_active_camera]);
}
}
......@@ -63,7 +63,7 @@ namespace glare::raytrace
if (update_materials) {
m_material_buffer.upload(m_materials, gl::BufferUsage::eDynamicRead);
if(m_material_buffer.size() != 0)
if (m_material_buffer.size() != 0)
m_material_buffer.makeResident(gl::Access::eReadOnly);
}
......@@ -72,12 +72,23 @@ namespace glare::raytrace
}
}
void MeshCollector::setUseBVH(bool use)
{
m_use_bvh = use;
}
bool MeshCollector::usesBVH() const
{
return m_use_bvh;
}
void MeshCollector::apply(core::Program &program)
{
program.storageBuffer("mesh_buffer", m_mesh_buffer);
program.storageBuffer("object_bvh_buffer", m_global_bvh.buffer());
program.storageBuffer("object_bvh_id_buffer", m_bvh_id_buffer);
program.storageBuffer("material_buffer", m_material_buffer);
program.uniform("use_global_bvh", m_use_bvh);
}
void MeshCollector::collectMeshRenderer(std::shared_ptr<core::MeshDrawable> mesh_renderer)
......@@ -89,7 +100,7 @@ namespace glare::raytrace
});
// Don't rebuild LocalCollector when having an instanced mesh.
if( it != m_local_collectors.end())
if (it != m_local_collectors.end())
m_local_collectors.emplace(static_cast<size_t>(mesh_renderer->renderer()->id()), InstancedCollector{ mesh_renderer->renderer()->owner()->computeWorldTransform(), (*it).second.collector });
else
m_local_collectors.emplace(static_cast<size_t>(mesh_renderer->renderer()->id()), InstancedCollector{ mesh_renderer->renderer()->owner()->computeWorldTransform(), std::make_shared<LocalCollector>(*mesh_renderer, std::make_shared<LocalBVH>()) });
......@@ -123,8 +134,6 @@ namespace glare::raytrace
void MeshCollector::assign()
{
const core::ClockMicros timer;
std::vector<unsigned> mesh_ids(m_local_collectors.size());
int c = 0;
......@@ -133,14 +142,17 @@ namespace glare::raytrace
mesh_ids[c++] = static_cast<unsigned>(collector_pair.first);
}
m_global_bvh.build(mesh_ids, [&](int id)
if (usesBVH())
{
const size_t mesh_id = mesh_ids[id];
return m_local_collectors[mesh_id].transform * m_local_collectors[mesh_id].collector->bounds().center();
}, [&](int id, math::Bounds& bounds) {
const auto &collector = m_local_collectors[mesh_ids[id]];
bounds.expand(collector.collector->bounds(), collector.transform);
});
m_global_bvh.build(mesh_ids, [&](int id)
{
const size_t mesh_id = mesh_ids[id];
return m_local_collectors[mesh_id].transform * m_local_collectors[mesh_id].collector->bounds().center();
}, [&](int id, math::Bounds& bounds) {
const auto &collector = m_local_collectors[mesh_ids[id]];
bounds.expand(collector.collector->bounds(), collector.transform);
});
}
m_bvh_id_buffer.upload(mesh_ids, gl::BufferUsage::eDynamicRead);
m_meshes.resize(mesh_ids.size());
......
......@@ -35,6 +35,9 @@ namespace glare::raytrace
const std::map<size_t, InstancedCollector>& localCollectors() const;
const std::map<size_t, size_t>& idMapping() const;
void setUseBVH(bool use);
bool usesBVH() const;
private:
void collectMeshRenderer(std::shared_ptr<core::MeshDrawable> mesh_renderer);
void collectMeshTransform(std::shared_ptr<core::MeshDrawable> mesh_renderer);
......@@ -52,6 +55,8 @@ namespace glare::raytrace
std::vector<Mesh> m_meshes;
std::vector<Material> m_materials;
bool m_use_bvh = false;
BVH<unsigned> m_global_bvh;
};
}
......
......@@ -34,6 +34,14 @@ namespace glare::raytrace
collect(scene_root);
}
void SceneCollector::setSceneFormat(SceneFormat format)
{
m_format = format;
setDirty(DirtyFlags::eMeshTransform);
std::static_pointer_cast<MeshCollector>(m_units["mesh_collector"])->setUseBVH(m_format == SceneFormat::eBVH);
collect();
}
SceneCollector::~SceneCollector()
{
if (core::Context::hasCurrentContext() && !core::Context::current().window().isClosing())
......@@ -52,8 +60,8 @@ namespace glare::raytrace
// tag -> setdirty and submit change, all on condition that...
m_evaluators.at(id).evaluate(*this, message);
if (m_scene_root)
collect();
//if (m_scene_root)
// collect();
}
void SceneCollector::collect(std::shared_ptr<core::SceneNode> scene_root)
......@@ -63,7 +71,7 @@ namespace glare::raytrace
m_scene_root = scene_root;
}
if (!m_dirty_flags || (!scene_root && !m_scene_root))
if (!m_is_active || !m_dirty_flags || (!scene_root && !m_scene_root))
return;
for (auto &unit : m_units)
......
......@@ -26,6 +26,12 @@ namespace glare::raytrace
eAll = ~0
};
enum class SceneFormat
{
eDefault = 0,
eBVH
};
class SceneCollector : public msg::Observer
{
public:
......@@ -50,11 +56,19 @@ namespace glare::raytrace
return *(std::static_pointer_cast<TUnit>(m_units.at(name)));
}
void setSceneFormat(SceneFormat format);
SceneFormat getSceneFormat() const
{
return m_format;
}
private:
struct TagEvaluator;
std::map<uint32_t, TagEvaluator> m_evaluators;
SceneFormat m_format = SceneFormat::eDefault;
math::Flags m_dirty_flags;
std::map<std::string, std::shared_ptr<CollectorUnit>> m_units;
std::shared_ptr<core::SceneNode> m_scene_root;
......
......@@ -148,6 +148,7 @@ namespace glare::raytrace
if (m_render_config.current_sample == 0)
{
m_collector->collect();
gl::clearTextureImage(color_storage->id(), 0, gl::TextureFormat::eRGBA, gl::Type::eFloat, glm::value_ptr(glm::vec4(0)));
}
......@@ -214,7 +215,6 @@ namespace glare::raytrace
void Pathtracer::initialize(std::shared_ptr<SceneCollector> collector)
{
m_collector = collector;
m_collector->collect();
m_skybox = core::Context::current().skybox();
reset();
......
......@@ -9,6 +9,7 @@
#include <core/graph/scene_node.h>
#include <core/objects/skybox.h>
#include <util/messages.h>
#include <util/property.h>
#include <raytrace/data/global_collector.h>
#include "raygenerator.h"
......
#ifndef INCLUDE_PROPERTY_H
#define INCLUDE_PROPERTY_H
#include <functional>
template<typename T>
struct Property
{
using type = T;
using callback_type = std::function<void(const T& value)>;
Property(T val, callback_type callback) : m_value(std::move(val)), m_callback(callback) {}
Property(callback_type callback) : Property(T(), callback) {}
Property(T val, std::function<void()> callback) : m_value(std::move(val)), m_callback([callback](const auto&) { callback(); }) {}
Property(std::function<void()> callback) : Property(T(), [callback](const auto&) { callback(); }) {}
void set(T value) { m_value = std::move(value); m_callback(m_value); }
const T& get() const { return m_value; }
const T& operator=(T value)
{
set(std::move(value));
return m_value;
}
operator const T&()
{
return get();
}