Deferred renderer: bucket objects by material

This commit is contained in:
Nikita Lisitsa 2020-12-11 17:40:28 +03:00
parent 82817304e2
commit 72e0681521

View file

@ -23,6 +23,48 @@
#include <map>
void hash_combine(std::size_t & seed, std::size_t value)
{
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
namespace std
{
template <typename T1, typename T2>
struct hash<std::tuple<T1, T2>>
{
std::hash<T1> h1;
std::hash<T2> h2;
std::size_t operator() (std::tuple<T1, T2> const & t) const
{
std::size_t h = 0;
hash_combine(h, h1(std::get<0>(t)));
hash_combine(h, h2(std::get<1>(t)));
return h;
}
};
template <typename T1, typename T2, typename T3>
struct hash<std::tuple<T1, T2, T3>>
{
std::hash<T1> h1;
std::hash<T2> h2;
std::hash<T3> h3;
std::size_t operator() (std::tuple<T1, T2, T3> const & t) const
{
std::size_t h = 0;
hash_combine(h, h1(std::get<0>(t)));
hash_combine(h, h2(std::get<1>(t)));
hash_combine(h, h3(std::get<2>(t)));
return h;
}
};
}
namespace psemek::gfx
{
@ -914,11 +956,13 @@ void main()
// Sort objects by mask & compute bbox
std::unordered_map<std::uint32_t, std::vector<std::size_t>> objects_by_mask;
std::unordered_map<std::tuple<std::uint32_t, material const *>, std::vector<std::size_t>> sorted_objects;
geom::box<float, 3> lit_bbox;
geom::box<float, 3> casts_shadow_bbox;
std::vector<bool> clipped_by_camera(objects.size());
for (std::size_t i = 0; i < objects.size(); ++i)
{
auto const & o = objects[i];
@ -933,51 +977,54 @@ void main()
if (o.mat->casts_shadow && o.mat->transparent)
throw std::runtime_error("Transparent objects cannot cast shadow");
objects_by_mask[mask(objects[i])].push_back(i);
sorted_objects[std::tuple{mask(o), o.mat}].push_back(i);
if (o.mat->lit) lit_bbox |= o.bbox;
if (o.mat->casts_shadow) casts_shadow_bbox |= o.bbox;
bool clipped = true;
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)
{
clipped = false;
break;
}
}
clipped_by_camera[i] = clipped;
}
auto render_all = [&](auto & program, auto && predicate, bool clip_by_camera = false)
{
for (auto const & p : objects_by_mask)
for (auto const & p : sorted_objects)
{
std::uint32_t mask = p.first;
if (p.second.empty()) continue;
std::uint32_t mask = std::get<0>(p.first);
if (!predicate(mask)) continue;
if (p.second.empty()) continue;
material const * mat = std::get<1>(p.first);
program["u_flag_mask"] = mask;
if (mask & O_UNIFORM_COLOR)
program["u_color"] = *(mat->color);
if (mask & O_TEXTURE_COLOR)
{
gl::ActiveTexture(gl::TEXTURE0);
mat->texture->bind();
}
program["u_material"] = geom::vector<float, 2>{mat->specular.intensity, mat->specular.shininess};
for (std::size_t i : p.second)
{
auto const & o = objects[i];
if (clip_by_camera)
{
bool clipped = true;
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)
{
clipped = false;
break;
}
}
if (clipped)
continue;
}
if (mask & O_UNIFORM_COLOR)
program["u_color"] = *o.mat->color;
if (mask & O_TEXTURE_COLOR)
{
gl::ActiveTexture(gl::TEXTURE0);
o.mat->texture->bind();
}
if (clip_by_camera && clipped_by_camera[i]) continue;
if (mask & O_PRE_TRANSFORM)
program["u_pre_transform"] = *o.pre_transform;
@ -985,8 +1032,6 @@ void main()
if (mask & O_POST_TRANSFORM)
program["u_post_transform"] = *o.post_transform;
program["u_material"] = geom::vector<float, 2>{o.mat->specular.intensity, o.mat->specular.shininess};
o.mesh->draw();
}
}