Commit 219dcceb authored by unknown's avatar unknown
Browse files

Added BVH containing all objects

parent 23e43008
assets/screenshots/render.png

3.16 MB | W: | H:

assets/screenshots/render.png

972 KB | W: | H:

assets/screenshots/render.png
assets/screenshots/render.png
assets/screenshots/render.png
assets/screenshots/render.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -146,10 +146,23 @@ struct Mesh
mat4 normal_matrix;
};
struct TraceProperties
{
float accuracy_importance;
float shadow_importance;
//Just to give the struct a good padding
uint prop_unused_01;
uint prop_unused_02;
};
struct Trace
{
Ray ray;
Hit hit;
//Additional properties for BVH-LS-Hybrid
TraceProperties properties;
};
struct Photon
......
......@@ -13,6 +13,16 @@ STD_BUFFER_R mesh_buffer
Mesh b_meshes[];
};
STD_BUFFER_R object_bvh_buffer
{
BVHNode b_object_nodes[];
};
STD_BUFFER_R object_bvh_id_buffer
{
uint b_object_ids[];
};
STD_BUFFER_R material_buffer
{
Material b_materials[];
......
......@@ -6,16 +6,26 @@
uniform bool u_use_ls;
#define USE_OBJECT_BVH true ||
//#define USE_OBJECT_BVH false &&
bool objectsTraverse(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);
bool nearestIntersection(const in Ray ray, inout Hit hit, bool force_bvh = false)
{
if(!force_bvh && u_use_ls){
//if(USE_OBJECT_BVH b_meshes.length() < 20){
// #ifdef USE_OBJECT_BVH
/*float t_min = FLT_MAX;
return objectsTraverse(ray, false, FLT_MAX, hit, t_min, force_bvh);*/
// }
if(!force_bvh){
float current_t = FLT_MAX;
float min_t = FLT_MAX;
bool hits = false;
for (int i = 0; i < b_meshes.length(); ++i)
{
Mesh mesh = b_meshes[i];
hits = bool(int(hits) | int(ls__traverse(mesh, ray__makeMeshLocal(ray, mesh), false, FLT_MAX, hit, min_t)));
hits = bool(int(hits) | int(ls__traverse(mesh, ray__makeMeshLocal(ray, mesh), false, current_t, hit, min_t)));
}
return hits;
......@@ -33,11 +43,19 @@ bool nearestIntersection(const in Ray ray, inout Hit hit, bool force_bvh = false
return hits;
}
// #endif
}
bool intersectsAny(const in Ray ray, const in float max_distance, bool force_bvh = false)
{
if(!force_bvh && u_use_ls){
// #ifdef USE_OBJECT_BVH
//if(USE_OBJECT_BVH b_meshes.length() < 20){
/*float t_min = max_distance;
Hit unused_hit;
return objectsTraverse(ray, true, max_distance, unused_hit, t_min, force_bvh);*/
// #else
//}
if(!force_bvh){
Hit unused_hit;
float current_t = max_distance;
for (int i = 0; i < b_meshes.length(); ++i)
......@@ -60,6 +78,118 @@ bool intersectsAny(const in Ray ray, const in float max_distance, bool force_bvh
}
return false;
}
// #endif
}
Bounds getObjectNodeBounds(int index)
{
return b_object_nodes[index].bounds;
}
bool objectsTraverse(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 = intersectsRayBounds(ray, getObjectNodeBounds(0), max_distance);
bool hit_triangle = false;
int current_node = 0;
int bitstack = 0;
while (hit_scene)
{
if (b_object_nodes[current_node].type == 0) //Inner node.
{
int id_left = int(b_object_nodes[current_node].left_idx);
bool hit_left = intersectsRayBounds(ray, getObjectNodeBounds(id_left), max_distance);
int id_right = int(b_object_nodes[current_node].right_idx);
bool hit_right = intersectsRayBounds(ray, getObjectNodeBounds(id_right), max_distance);
//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(b_object_nodes[current_node].left_idx);
int end = int(b_object_nodes[current_node].right_idx);
for (int i = start; i <= end; i++)
{
const Mesh mesh = b_meshes[b_object_ids[i]];
if(force_bvh)
{
if(bvh__traverse(mesh, ray__makeMeshLocal(ray, mesh), use_first, max_dist, hit, t_min)){
hit_triangle = true;
if (use_first)
{
return true;
}
}
}
else
{
if(ls__traverse(mesh, ray__makeMeshLocal(ray, mesh), use_first, max_dist, 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)
{
return hit_triangle;
}
current_node = int(b_object_nodes[current_node].parent);
bitstack = bitstack >> 1;
}
//Use other (right) sibling from the left child of the branched tree node.
current_node = int(b_object_nodes[b_object_nodes[current_node].parent].right_idx);
bitstack = bitstack ^ 1;
}
return hit_triangle;
}
#endif //__GL_MESH_DATASTRUCTURE
\ No newline at end of file
......@@ -19,6 +19,7 @@ uniform struct
void generate(int id);
void trace(int id);
void resetImportance(int id);
void main()
{
......@@ -30,6 +31,7 @@ void main()
generate(id);
trace(id);
resetImportance(id);
}
void generate(int id)
......@@ -41,4 +43,10 @@ void trace(int id)
{
bool intersects = nearestIntersection(b_traces[id].ray, b_traces[id].hit, true);
b_traces[id].hit.barycentric.x = mix(-1, b_traces[id].hit.barycentric.x, int(intersects));
}
void resetImportance(int id)
{
b_traces[id].properties.accuracy_importance = 1.f;
b_traces[id].properties.shadow_importance = 1.f;
}
\ No newline at end of file
......@@ -13,6 +13,12 @@ layout(rgba32f) uniform readonly image2D u_gbuffer_texture_01;
layout(local_size_variable) in;
void resetImportance(uint id)
{
b_traces[id].properties.accuracy_importance = 1.f;
b_traces[id].properties.shadow_importance = 1.f;
}
void main()
{
uint id = gl_GlobalInvocationID.x;
......@@ -32,5 +38,7 @@ void main()
b_traces[id].hit.triangle = uint(texel_01.z);
b_traces[id].hit.mesh = uint(texel_01.w);
}
resetImportance(id);
}
}
\ No newline at end of file
......@@ -24,11 +24,15 @@ uniform struct
#include <raytracer/environment.glh>
#include <bsdf/bsdf.glh>
const float c_color_scale_factor = 100.f;
const float c_inv_color_scale_factor = 1 / c_color_scale_factor;
layout(local_size_variable) in;
//Global properties for all mesh-local Line Spaces.
uniform struct LinespaceProperties
{
float accuracy_quality;
float shadow_quality;
} u_linespace_properties;
//In this texture, the colors will all just be added up. The final render target color is then the
//color value of this texture divided by the current sample count.
layout(rgba32f) volatile uniform image2D u_color_store;
......@@ -41,7 +45,7 @@ bool shade(int id, inout vec3 weight)
//Sample environment when not hitting anything.
if(hit__isNotValid(hit))
{
imageAdd(u_color_store, ivec2(ray.px, ray.py), max(vec4(c_inv_color_scale_factor * environment__sample(ray.direction.xyz).xyz * weight, 1), vec4(0,0,0,0)));
imageAdd(u_color_store, ivec2(ray.px, ray.py), max(vec4(environment__sample(ray.direction.xyz).xyz * weight, 1), vec4(0,0,0,0)));
return false;
}
......@@ -60,13 +64,13 @@ bool shade(int id, inout vec3 weight)
if(out_ray.direction == vec3(0))
{
// Treat as emissive material.
imageAdd(u_color_store, ivec2(ray.px, ray.py), max(vec4(c_inv_color_scale_factor * weight * light_influence, 1.f), vec4(0)));
imageAdd(u_color_store, ivec2(ray.px, ray.py), max(vec4(weight * light_influence, 1.f), vec4(0)));
hit__invalidate(b_traces[id].hit);
return false;
}
//Add ambient color
imageAdd(u_color_store, ivec2(ray.px, ray.py), max(vec4(c_inv_color_scale_factor * vec3(0.0f) * light_influence * weight * ONE_OVER_PI, 1), vec4(0)));
imageAdd(u_color_store, ivec2(ray.px, ray.py), max(vec4( vec3(0.0f) * light_influence * weight * ONE_OVER_PI, 1), vec4(0)));
if (b_lights.length() > 0) {
//Select random light... well... at least if there are any.
......@@ -76,13 +80,13 @@ bool shade(int id, inout vec3 weight)
Ray shadow_test;
shadow_test.origin = vertex.position.xyz + 1e-5*vertex.normal.xyz;
shadow_test.direction = normalize((light.position.xyz + randUniformSphere(random_sample)*light.data[0]) - vertex.position.xyz);
if (!intersectsAny(shadow_test, distance(light.position, vertex.position + 1e-5*vertex.normal)))
if (!intersectsAny(shadow_test, distance(light.position, vertex.position + 1e-5*vertex.normal), b_traces[id].properties.shadow_importance > (1-u_linespace_properties.shadow_quality)))
{
//TODO: only point light for now.
float angle = abs(dot(shadow_test.direction, vertex.normal.xyz));
float dist = distance(light.position, vertex.position);
float attenuation = 1 / (light.constant + dist*light.linear + pow(dist, 2)*light.quadratic);
imageAdd(u_color_store, ivec2(ray.px, ray.py), max(vec4(c_inv_color_scale_factor * weight * light.color.rgb * light_influence * angle * attenuation, 1.f), vec4(0)));
imageAdd(u_color_store, ivec2(ray.px, ray.py), max(vec4( weight * light.color.rgb * light_influence * angle * attenuation, 1.f), vec4(0)));
}
}
......@@ -93,6 +97,8 @@ bool shade(int id, inout vec3 weight)
return false;
}
b_traces[id].properties.accuracy_importance *= pdf;
b_traces[id].properties.shadow_importance *= pdf;
b_traces[id].ray = out_ray;
weight *= reflectance * abs(dot(out_ray.direction, vertex.normal.xyz)) / pdf;
return true;
......@@ -100,7 +106,7 @@ bool shade(int id, inout vec3 weight)
bool trace(int id)
{
bool intersects = nearestIntersection(b_traces[id].ray, b_traces[id].hit);
bool intersects = nearestIntersection(b_traces[id].ray, b_traces[id].hit, b_traces[id].properties.accuracy_importance > (1-u_linespace_properties.accuracy_quality));
b_traces[id].hit.barycentric.x = mix(-1, b_traces[id].hit.barycentric.x, int(intersects));
return intersects;
}
......@@ -132,6 +138,6 @@ void main()
imageStore(
u_render_target,
ivec2(b_traces[id].ray.px, b_traces[id].ray.py),
c_color_scale_factor * imageLoad(u_color_store, ivec2(b_traces[id].ray.px, b_traces[id].ray.py)) / (u_render_config.current_sample+1)
imageLoad(u_color_store, ivec2(b_traces[id].ray.px, b_traces[id].ray.py)) / (u_render_config.current_sample+1)
);
}
\ No newline at end of file
......@@ -13,6 +13,8 @@ uniform samplerCube environment;
uniform vec3 camera_position;
uniform mat4 u_view;
uniform mat4 u_projection;
uniform uint u_samples;
uniform struct {
sampler2DMS diffuse;
sampler2DMS normals;
......@@ -25,19 +27,13 @@ uniform struct {
} u_gbuffer;
uniform struct {
bool available;
sampler2DMS map;
mat4 matrix;
vec2 size;
uint samples;
bool available;
} u_shadow_map;
//uniform sampler2DMS u_shadow_map;
//uniform mat4 u_shadow_matrix;
//uniform vec2 u_shadow_map_size;
uniform uint u_samples;
layout(location = 0) out vec4 out_final_color;
float calculateShadowMapDarkening(const in vec4 position) {
......@@ -47,17 +43,16 @@ float calculateShadowMapDarkening(const in vec4 position) {
vec4 shadow_coord = u_shadow_map.matrix * position; // clip coordinates, light space
vec3 shadow_coord_normalized = shadow_coord.xyz / shadow_coord.w; // normalised device coordinates, light space
float shadow_value = 0;
float shadow_value = 1.f;
for (int i = 0; i < u_shadow_map.samples; ++i) {
float shadow_map_depth = texelFetch(u_shadow_map.map, ivec2(shadow_coord_normalized.xy*u_shadow_map.size), i).r * 1000.f;
bool is_shadow = shadow_map_depth < (shadow_coord_normalized.z*1000.f - 0.5f);
bool is_shadow = (shadow_map_depth < (shadow_coord_normalized.z*1000.f - 0.5f));
shadow_value += is_shadow ? 1 : 0;
}
shadow_value /= float(u_shadow_map.samples);
darkening = (shadow_coord_normalized.x < 1.f && shadow_coord_normalized.x > 0.f && shadow_coord_normalized.y < 1.f && shadow_coord_normalized.y > 0.f) ? (1 - shadow_value) : 1.f;
}
......
<settings>
<item name="fxaa">0</item>
<item name="window_size_x">1600</item>
<item name="window_size_y">900</item>
<item name="vsync">1</item>
<item name="window_size_x">800</item>
<item name="window_size_y">600</item>
<item name="vsync">0</item>
<item name="msaa_samples">4</item>
</settings>
\ No newline at end of file
......@@ -49,12 +49,15 @@ namespace glare
//Create a skybox from cube map.
m_skybox = std::make_shared<core::Skybox>(core::Skybox::collectFilesFrom(core::asset("/textures/ryfjallet/")));
float lsprop_accuracy = 0.5f;
float lsprop_shadow = 0.2f;
// BENCHMARKS
//initializeScene(m_current_scene_root / "benchmark_single_quad_diff.dae", 1.f);
//initializeScene(m_current_scene_root / "benchmark_single_cube_diff.dae", 1.f);
//initializeScene(m_current_scene_root / "benchmark_suzanne_x1_diff.dae", 1.f);
//initializeScene(m_current_scene_root / "benchmark_suzanne_x2_diff.dae", 1.f);
//initializeScene(m_current_scene_root / "benchmark_stfd_bunny_diff.dae", 1.f);
initializeScene(m_current_scene_root / "benchmark_stfd_bunny_diff.dae", 1.f);
//initializeScene(m_current_scene_root / "benchmark_stfd_armadillo_diff.dae", 1.f);
//initializeScene(m_current_scene_root / "benchmark_stfd_dragon_diff.dae", 1.f);
//initializeScene(m_current_scene_root / "benchmark_stfd_asian_dragon_diff.dae", 1.f);
......@@ -77,7 +80,7 @@ namespace glare
//initializeScene(m_current_scene_root / "artifact_suzanne_x2_emissive.dae", 1.f);
//initializeScene(m_current_scene_root / "artifact_suzanne_x2_transparent.dae", 1.f);
initializeScene(m_current_scene_root / "ball.dae", 1.f);
//initializeScene(m_current_scene_root / "drugun.dae", 1.f);
initializeRenderRequirements();
initializeAdvanced();
initializeGUI();
......@@ -116,21 +119,24 @@ namespace glare
case AppRenderState::eLineSpace:
case AppRenderState::ePathtracer:
{
core::ClockGL::instance().start();
auto &&rt_texture = m_raytracer->render(m_config.window_width, m_config.window_height);
auto &&rt_texture = m_raytracer->render(m_config.window_width, m_config.window_height, lsprop_accuracy, lsprop_shadow);
m_texture_renderer_default->draw(rt_texture);
Log_Info << "Render took: " << (core::ClockGL::instance().end()/1000000.f);
}
break;
}
ImGui::Begin("Linespace Settings");
ImGui::SliderFloat("Accuracy Q", &lsprop_accuracy, 0, 1);
ImGui::SliderFloat("Shadow Q", &lsprop_shadow, 0, 1);
ImGui::End();
drawDebugWindow();
drawSceneSelector();
ImGui::Render();
core::LightManager::getInstance().clear();
Log_Info << "Render took Blaaa: " << core::Time::deltaTime() * 1000.f;
});
}
......@@ -168,9 +174,9 @@ namespace glare
cam_node->makeComponent<component::PlayerController>();
m_scene_root->makeComponent<component::FramerateCounter>();
#define DEBUG__ADD_ROTATOR_x
#define DEBUG__ADD_ROTATOR
#ifdef DEBUG__ADD_ROTATOR
if (auto &&node = m_scene_root->findFirstWithName("#Suzanne_001-mesh")) {
if (auto &&node = m_scene_root->findFirstWithName("#Suzanne-mesh")) {
node->addComponent(std::make_shared<component::Rotator>());
}
#endif
......
This diff is collapsed.
#include <glare_core>
#include <glare_advanced>
#include <glare_io>
using namespace glare;
int main(int argc, char* argv[])
{
io::Arguments arguments(argc, argv);
std::string mask_asset_path = arguments.get("o", 0, std::string(""));
advanced::LineSpaceMaskMode mask_mode = arguments.has("ns") ? advanced::LineSpaceMaskMode::eNonSymmetrical : advanced::LineSpaceMaskMode::eSymmetrical;
unsigned mask_resolution_min = arguments.get("r", 0, 1);
unsigned mask_resolution_max = arguments.get("r", 1, 16);
bool check_after = arguments.get("check", 0, false);
advanced::LineSpaceMaskGenerator::generate(mask_mode, math::Range<unsigned>(mask_resolution_min, mask_resolution_max), mask_asset_path, check_after);
quitPromptDefault(0);
return 0;
}
\ No newline at end of file
......@@ -410,7 +410,7 @@ namespace glare
bool LocalBVH::anyIntersection(const math::Ray &ray, float max_distance) const
{
math::Hit hit;
math::Hit hit;
float current_t = max_distance;
float tmp;
return traverse(ray, hit, true, max_distance, current_t, false, hit, tmp);
......@@ -418,117 +418,117 @@ namespace glare
bool LocalBVH::traverse(const math::Ray &ray, math::Hit &hit, bool any, float max_distance, float &t_min, bool also_farthest, math::Hit &hit_farthest, float &t_max) const
{
float t = 0;
// Check once the AABB for the whole scene
bool hit_scene = Intersections::intersects(ray, m_nodes[0].bounds, max_distance);
bool hit_triangle = false;
int current_node = 0;
int bitstack = 0;
//if (hit_scene){
while (hit_scene)
{
if (m_nodes[current_node].type == BVHNodeType::eInner) //Inner node.
{
int id_left = int(m_nodes[current_node].left_idx);
bool hit_left = Intersections::intersects(ray, m_nodes[id_left].bounds, max_distance);
int id_right = int(m_nodes[current_node].right_idx);
bool hit_right = Intersections::intersects(ray, m_nodes[id_right].bounds, max_distance);
//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(m_nodes[current_node].left_idx);
int end = int(m_nodes[current_node].right_idx);
float u, v;
for (int i = start; i <= end; i++)
{
math::Triangle triangle;
triangle.a = m_vertices->operator[](m_triangles->operator[](i).indices[0]).position;
triangle.b = m_vertices->operator[](m_triangles->operator[](i).indices[1]).position;
triangle.c = m_vertices->operator[](m_triangles->operator[](i).indices[2]).position;
if (Intersections::intersects(ray, triangle, t, u, v))
{
if (t < t_min && t < max_distance) //test for ray_length
{
t_min = t;
hit_triangle = true;
if (any)
{
return true;
}
hit.barycentric = glm::vec2(u, v);
hit.triangle = i;
hit.mesh = 0;
}
if (also_farthest && t > t_max) {
t_max = t;
hit_farthest.barycentric = glm::vec2(u, v);
hit_farthest.triangle = i;
hit_farthest.mesh = 0;
}
}
}
}
//Backtrace on bitstack until we find a branching point (where bit value is 1)
while ((bitstack & 1) == 0)
{
//Empty bitstack
if (bitstack == 0)
{
return hit_triangle;
}
current_node = int(m_nodes[current_node].parent);
bitstack = bitstack >> 1;