Deferred renderer: sort objects by distance to camera

This commit is contained in:
Nikita Lisitsa 2020-12-11 17:51:04 +03:00
parent 72e0681521
commit f4908f2368

View file

@ -956,12 +956,18 @@ void main()
// Sort objects by mask & compute bbox // Sort objects by mask & compute bbox
std::unordered_map<std::tuple<std::uint32_t, material const *>, std::vector<std::size_t>> sorted_objects; struct objects_bucket
{
std::vector<std::size_t> objects;
std::size_t first_visible;
};
std::unordered_map<std::tuple<std::uint32_t, material const *>, objects_bucket> buckets;
geom::box<float, 3> lit_bbox; geom::box<float, 3> lit_bbox;
geom::box<float, 3> casts_shadow_bbox; geom::box<float, 3> casts_shadow_bbox;
std::vector<bool> clipped_by_camera(objects.size()); std::vector<float> camera_distance(objects.size());
for (std::size_t i = 0; i < objects.size(); ++i) for (std::size_t i = 0; i < objects.size(); ++i)
{ {
@ -977,29 +983,31 @@ void main()
if (o.mat->casts_shadow && o.mat->transparent) if (o.mat->casts_shadow && o.mat->transparent)
throw std::runtime_error("Transparent objects cannot cast shadow"); throw std::runtime_error("Transparent objects cannot cast shadow");
sorted_objects[std::tuple{mask(o), o.mat}].push_back(i); buckets[std::tuple{mask(o), o.mat}].objects.push_back(i);
if (o.mat->lit) lit_bbox |= o.bbox; if (o.mat->lit) lit_bbox |= o.bbox;
if (o.mat->casts_shadow) casts_shadow_bbox |= o.bbox; if (o.mat->casts_shadow) casts_shadow_bbox |= o.bbox;
bool clipped = true; float dist = -std::numeric_limits<float>::infinity();
for (int c = 0; c < 8; ++c) for (int c = 0; c < 8; ++c)
{ {
if (dot(o.bbox.corner(c & 1, (c & 2) >> 1, (c & 4) >> 1) - camera_position, camera_direction) > 0.f) dist = std::max(dist, dot(o.bbox.corner(c & 1, (c & 2) >> 1, (c & 4) >> 1) - camera_position, camera_direction));
{
clipped = false;
break;
}
} }
clipped_by_camera[i] = clipped; camera_distance[i] = dist;
}
for (auto & p : buckets)
{
std::sort(p.second.objects.begin(), p.second.objects.end(), [&](auto i, auto j){ return camera_distance[i] < camera_distance[j]; });
p.second.first_visible = std::partition_point(p.second.objects.begin(), p.second.objects.end(), [&](auto i){ return camera_distance[i] < 0.f; }) - p.second.objects.begin();
} }
auto render_all = [&](auto & program, auto && predicate, bool clip_by_camera = false) auto render_all = [&](auto & program, auto && predicate, bool clip_by_camera = false)
{ {
for (auto const & p : sorted_objects) for (auto const & p : buckets)
{ {
if (p.second.empty()) continue; if (p.second.objects.empty()) continue;
std::uint32_t mask = std::get<0>(p.first); std::uint32_t mask = std::get<0>(p.first);
@ -1020,11 +1028,9 @@ void main()
program["u_material"] = geom::vector<float, 2>{mat->specular.intensity, mat->specular.shininess}; program["u_material"] = geom::vector<float, 2>{mat->specular.intensity, mat->specular.shininess};
for (std::size_t i : p.second) for (std::size_t i = (clip_by_camera ? p.second.first_visible : 0); i < p.second.objects.size(); ++i)
{ {
auto const & o = objects[i]; auto const & o = objects[p.second.objects[i]];
if (clip_by_camera && clipped_by_camera[i]) continue;
if (mask & O_PRE_TRANSFORM) if (mask & O_PRE_TRANSFORM)
program["u_pre_transform"] = *o.pre_transform; program["u_pre_transform"] = *o.pre_transform;