diff --git a/include/limitless/instances/instance_builder.hpp b/include/limitless/instances/instance_builder.hpp index f0d0e2f6..2eddb59e 100644 --- a/include/limitless/instances/instance_builder.hpp +++ b/include/limitless/instances/instance_builder.hpp @@ -3,8 +3,8 @@ #include #include #include +#include #include -#include "decal_instance.hpp" namespace Limitless { class instance_builder_exception : public std::runtime_error { @@ -12,18 +12,25 @@ namespace Limitless { using std::runtime_error::runtime_error; }; + /** + * + */ class Instance::Builder { private: - std::shared_ptr model_; - std::shared_ptr effect_; - + /** + * Instance data + */ glm::quat rotation_ {1.0f, 0.0f, 0.0f, 0.0f}; glm::vec3 position_ {0.0f}; glm::vec3 scale_ {1.0f}; bool cast_shadow_ {true}; std::optional bounding_box_ {}; uint8_t decal_mask {0xFF}; - uint8_t decal_proj_mask {0xFF}; + + /** + * Model data + */ + std::shared_ptr model_; class MaterialChange { public: @@ -37,6 +44,9 @@ namespace Limitless { std::vector> attachments; + /** + * Skeletal data + */ class SocketAttachment { public: std::string bone_name; @@ -44,6 +54,16 @@ namespace Limitless { }; std::vector bone_attachments; + /** + * Effect data + */ + std::shared_ptr effect_; + + /** + * Decal + */ + uint8_t decal_proj_mask {0xFF}; + void initialize(Instance& instance); void initialize(const std::shared_ptr& instance); public: @@ -154,5 +174,10 @@ namespace Limitless { * */ std::shared_ptr asDecal(); + + /** + * + */ + std::shared_ptr asTerrain(); }; } \ No newline at end of file diff --git a/include/limitless/renderer/instance_renderer.hpp b/include/limitless/renderer/instance_renderer.hpp index 9dac6fc1..1d16879b 100644 --- a/include/limitless/renderer/instance_renderer.hpp +++ b/include/limitless/renderer/instance_renderer.hpp @@ -41,6 +41,10 @@ namespace Limitless { * Renders only visible subset of InstancedInstance instances from frustum culling */ void renderVisibleInstancedInstance(InstancedInstance& instance, const DrawParameters& drawp); + /** + * Renders only visible MeshInstances of terrain + */ + void renderVisibleTerrain(TerrainInstance& instance, const DrawParameters& drawp); void renderVisible(Instance& instance, const DrawParameters& drawp); public: void update(Scene& scene, Camera& camera); diff --git a/include/limitless/util/frustum_culling.hpp b/include/limitless/util/frustum_culling.hpp index fa3e1835..ae870657 100644 --- a/include/limitless/util/frustum_culling.hpp +++ b/include/limitless/util/frustum_culling.hpp @@ -5,14 +5,25 @@ namespace Limitless { class FrustumCulling { private: - // contains visible array of instances + /** + * Contains visible array of simple instances + */ std::vector> visible; - // contains visible array of model instances for each instanced instance - std::map>> visible_model_instanced; + + /** + * Contains visible array of model instances for each instanced instance + */ + std::map>> visible_instances_of_instanced_instances; + + /** + * Contains visible MeshInstances of TerrainInstance + */ + std::map>> visible_meshes_of_terrain_instances; public: void update(Scene& scene, Camera& camera) { visible.clear(); - visible_model_instanced.clear(); + visible_instances_of_instanced_instances.clear(); + visible_meshes_of_terrain_instances.clear(); const auto frustum = Frustum::fromCamera(camera); @@ -22,11 +33,23 @@ namespace Limitless { for (auto& i: instanced.getInstances()) { if (frustum.intersects(*i)) { - visible_model_instanced[instance->getId()].emplace_back(i); + visible_instances_of_instanced_instances[instance->getId()].emplace_back(i); + } + } + + if (visible_instances_of_instanced_instances.count(instance->getId()) != 0) { + visible.emplace_back(instance); + } + } else if (instance->getInstanceType() == InstanceType::Terrain) { + auto& terrain = static_cast(*instance); //NOLINT + + for (auto& [_, mesh_instance] : terrain.getMeshes()) { + if (frustum.intersects(mesh_instance.getMesh()->getBoundingBox())) { + visible_meshes_of_terrain_instances[instance->getId()].emplace_back(mesh_instance); } } - if (visible_model_instanced.count(instance->getId()) != 0) { + if (visible_meshes_of_terrain_instances.count(instance->getId()) != 0) { visible.emplace_back(instance); } } else { @@ -37,7 +60,8 @@ namespace Limitless { } } - const Instances& getVisibleInstances() const noexcept { return visible; } - const std::vector>& getVisibleModelInstanced(const InstancedInstance& instance) const noexcept { return visible_model_instanced.at(instance.getId()); } + [[nodiscard]] const Instances& getVisibleInstances() const noexcept { return visible; } + [[nodiscard]] const std::vector>& getVisibleModelInstanced(const InstancedInstance& instance) const noexcept { return visible_instances_of_instanced_instances.at(instance.getId()); } + const std::vector>& getVisibleTerrainMeshes(const TerrainInstance& instance) const noexcept { return visible_meshes_of_terrain_instances.at(instance.getId()); } }; } \ No newline at end of file diff --git a/src/limitless/instances/instance_builder.cpp b/src/limitless/instances/instance_builder.cpp index 3044aa03..597037f6 100644 --- a/src/limitless/instances/instance_builder.cpp +++ b/src/limitless/instances/instance_builder.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include using namespace Limitless; @@ -213,3 +215,7 @@ Instance::Builder &Instance::Builder::decal_projection_mask(uint8_t mask) { decal_proj_mask = mask; return *this; } + +std::shared_ptr Instance::Builder::asTerrain() { + return std::shared_ptr(); +} diff --git a/src/limitless/renderer/instance_renderer.cpp b/src/limitless/renderer/instance_renderer.cpp index 215bcacf..1fab9be6 100644 --- a/src/limitless/renderer/instance_renderer.cpp +++ b/src/limitless/renderer/instance_renderer.cpp @@ -45,19 +45,6 @@ void InstanceRenderer::render(SkeletalInstance& instance, const DrawParameters& return; } - for (const auto& [_, mesh]: instance.getMeshes()) { - // skip mesh if blending is different - if (mesh.getMaterial()->getBlending() != drawp.blending) { - return; - } - - // set render state: shaders, material, blending, etc - setRenderState(mesh, drawp, {InstanceType::Model, instance.getFinalMatrix(), instance.getDecalMask()}); - - // draw vertices - mesh.getMesh()->draw(); - } - instance.getBoneBuffer()->bindBase(drawp.ctx.getIndexedBuffers().getBindingPoint(IndexedBuffer::Type::ShaderStorage, "bone_buffer")); for (const auto& [_, mesh]: instance.getMeshes()) { @@ -128,6 +115,27 @@ void InstanceRenderer::renderVisibleInstancedInstance(InstancedInstance& instanc render(instance, drawp); } +void InstanceRenderer::renderVisibleTerrain(TerrainInstance &instance, const DrawParameters &drawp) { + if (instance.isHidden()) { + return; + } + + for (const auto& mref: frustum_culling.getVisibleTerrainMeshes(instance)) { + auto& mesh = mref.get(); + + // skip mesh if blending is different + if (mesh.getMaterial()->getBlending() != drawp.blending) { + return; + } + + // set render state: shaders, material, blending, etc + setRenderState(mesh, drawp, {InstanceType::Terrain, instance.getFinalMatrix(), instance.getDecalMask()}); + + // draw vertices + mesh.getMesh()->draw(); + } +} + void InstanceRenderer::render(InstancedInstance &instance, const DrawParameters &drawp) { if (instance.isHidden()) { return; @@ -162,7 +170,7 @@ void InstanceRenderer::renderVisible(Instance &instance, const DrawParameters &d case InstanceType::SkeletalInstanced: break; //NOLINT case InstanceType::Effect: break; //NOLINT case InstanceType::Decal: break; //NOLINT - case InstanceType::Terrain: render(static_cast(instance), drawp); break; //NOLINT + case InstanceType::Terrain: renderVisibleTerrain(static_cast(instance), drawp); break; //NOLINT } }