Deferred renderer: add proper frustum culling

This commit is contained in:
Nikita Lisitsa 2020-12-12 20:49:50 +03:00
parent 59888bd5eb
commit 0cf44f532a

View file

@ -20,6 +20,9 @@
#include <psemek/geom/contains.hpp>
#include <psemek/cg/convex_hull_2d/graham.hpp>
#include <psemek/cg/body/frustum.hpp>
#include <psemek/cg/body/box.hpp>
#include <psemek/cg/convex/separation.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/hash.hpp>
@ -966,20 +969,7 @@ void main()
auto const camera_position = opts.camera->position();
auto const camera_direction = opts.camera->direction();
geom::point<float, 3> camera_frustum_vertices[8];
for (int i = 0; i < 8; ++i)
{
geom::vector<float, 4> p;
p[0] = (i & 1) ? 1.f : -1.f;
p[1] = (i & 2) ? 1.f : -1.f;
p[2] = (i & 4) ? 1.f : -1.f;
p[3] = 1.f;
geom::gauss(camera_transform, p);
camera_frustum_vertices[i] = geom::as_point(p);
}
cg::frustum<float, 3> camera_frustum(camera_transform);
// Sort objects by mask & compute bbox
@ -994,7 +984,7 @@ void main()
std::unordered_map<std::tuple<std::uint32_t, material const *>, objects_bucket> buckets;
geom::box<float, 3> bbox;
bool contains_near_clip = false;
float camera_distance = -std::numeric_limits<float>::infinity();
float camera_separation;
};
geom::box<float, 3> all_bbox;
@ -1052,16 +1042,11 @@ void main()
{
b.bbox = geom::expand(b.bbox, b.bbox.dimensions() / 64.f);
float dist = -std::numeric_limits<float>::infinity();
for (int c = 0; c < 8; ++c)
{
dist = std::max(dist, dot(b.bbox.corner(c & 1, (c & 2) >> 1, (c & 4) >> 1) - camera_position, camera_direction));
}
b.camera_distance = dist;
b.camera_separation = cg::separation(camera_frustum, cg::box{b.bbox}).second;
b.contains_near_clip = true;
for (int i = 0; i < 4; ++i)
b.contains_near_clip &= geom::contains(b.bbox, camera_frustum_vertices[i]);
b.contains_near_clip &= geom::contains(b.bbox, camera_frustum.vertices[i]);
for (auto & p : b.buckets)
{
@ -1078,7 +1063,7 @@ void main()
{
auto const & b = bins.data()[bi];
if (clip_by_camera && b.camera_distance < 0.f) continue;
if (clip_by_camera && b.camera_separation > 0.f) continue;
bool const bin_use_occlusion = clip_by_camera && !b.contains_near_clip && !b.buckets.empty() && use_occlusion;
@ -1248,7 +1233,7 @@ void main()
if (b.buckets.empty()) continue;
if (b.contains_near_clip) continue;
if (b.camera_distance < 0.f) continue;
if (b.camera_separation > 0.f) continue;
impl().occlusion_pass_program["u_box_min"] = geom::vector{b.bbox[0].min, b.bbox[1].min, b.bbox[2].min};
impl().occlusion_pass_program["u_box_max"] = geom::vector{b.bbox[0].max, b.bbox[1].max, b.bbox[2].max};