diff --git a/libs/gfx/source/renderer/deferred.cpp b/libs/gfx/source/renderer/deferred.cpp index 3e54578e..eb2a15fa 100644 --- a/libs/gfx/source/renderer/deferred.cpp +++ b/libs/gfx/source/renderer/deferred.cpp @@ -23,6 +23,48 @@ #include +void hash_combine(std::size_t & seed, std::size_t value) +{ + seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2); +} + +namespace std +{ + + template + struct hash> + { + std::hash h1; + std::hash h2; + + std::size_t operator() (std::tuple 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 + struct hash> + { + std::hash h1; + std::hash h2; + std::hash h3; + + std::size_t operator() (std::tuple 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> objects_by_mask; + std::unordered_map, std::vector> sorted_objects; geom::box lit_bbox; geom::box casts_shadow_bbox; + std::vector 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{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{o.mat->specular.intensity, o.mat->specular.shininess}; - o.mesh->draw(); } }