diff --git a/include/Engine/Core/Frustum.h b/include/Engine/Core/Frustum.h new file mode 100644 index 00000000..c2d83b23 --- /dev/null +++ b/include/Engine/Core/Frustum.h @@ -0,0 +1,77 @@ +#ifndef Frustum_h__ +#define Frustum_h__ + +#include "../GLM.h" +#include "AABB.h" +#include + +//A frustum defined by 6 planes. +struct Frustum +{ + //Contains points P in: dot(normal, P) + d = 0 + struct Plane + { + glm::vec3 Normal; + float Distance; + }; + + enum class Output + { + Inside, + Outside, + Intersects + }; + Plane Planes[6]; + + Frustum() = default; + Frustum(glm::mat4x4 viewProjMatrix) + { + //Order: Right, left, top, bottom, far, near. + int sign = 1; + for (int i = 0; i < 6; ++i) { + sign = -sign; + int index = i / 2; + Plane& plane = Planes[i]; + plane.Normal.x = viewProjMatrix[0].w + sign * viewProjMatrix[0][index]; + plane.Normal.y = viewProjMatrix[1].w + sign * viewProjMatrix[1][index]; + plane.Normal.z = viewProjMatrix[2].w + sign * viewProjMatrix[2][index]; + plane.Distance = viewProjMatrix[3].w + sign * viewProjMatrix[3][index]; + float divByNormalLength = 1.0f / glm::length(plane.Normal); + plane.Normal *= divByNormalLength; + plane.Distance *= divByNormalLength; + } + } + + Output VsAABB(const AABB& box) const + { + const glm::vec3& maxCorner = box.MaxCorner(); + const glm::vec3& minCorner = box.MinCorner(); + bool completelyInside = true; + for (const Plane& p : Planes) { + bool anyWasInside = false; + bool anyWasOutside = false; + //If points are on both sides of the plane, we can stop. + for (int i = 0; i < 8 && (!anyWasInside || !anyWasOutside); ++i) { + std::bitset<3> bits(i); + glm::vec3 corner; + corner.x = bits.test(0) ? maxCorner.x : minCorner.x; + corner.y = bits.test(1) ? maxCorner.y : minCorner.y; + corner.z = bits.test(2) ? maxCorner.z : minCorner.z; + if (glm::dot(p.Normal, corner) > -p.Distance) { + anyWasInside = true; + } else { + anyWasOutside = true; + } + } + if (!anyWasInside) { + return Output::Outside; + } + if (anyWasOutside) { + completelyInside = false; + } + } + return completelyInside ? Output::Inside : Output::Intersects; + } +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index e0165cef..49a8b045 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -6,6 +6,7 @@ #include "../Common.h" #include "AABB.h" +#include "Frustum.h" //Fwd declarations. class Ray; @@ -41,8 +42,8 @@ public: //The type Box must be AABB, or inherit from AABB. template void ObjectsInSameRegion(const Box& box, std::vector& outObjects); - //Get the objects that are inside the frustum defined by the viewProjection matrix, the objects are put in outObjects. - void ObjectsInFrustum(const glm::mat4x4& viewProj, std::vector& outObjects); + //Get the objects that are inside the frustum, the objects are put in outObjects. + void ObjectsInFrustum(const Frustum& frustum, std::vector& outObjects); //Empty the tree of all objects, static and dynamic. void ClearObjects(); //Empty the tree of all dynamic objects. Static objects remain in the tree. @@ -71,56 +72,6 @@ struct Output float CollideDistance; }; -//Contains points P in: dot(normal, P) + d = 0 -struct Plane -{ - glm::vec3 Normal; - float Distance; -}; - -//A frustum defined by 6 planes. -struct Frustum -{ - enum Output - { - Inside, - Outside, - Intersects - }; - Plane Planes[6]; - - Output VsAABB(const AABB& box) const - { - const glm::vec3& maxCorner = box.MaxCorner(); - const glm::vec3& minCorner = box.MinCorner(); - bool completelyInside = true; - for (const Plane& p : Planes) { - bool anyWasInside = false; - bool anyWasOutside = false; - //If points are on both sides of the plane, we can stop. - for (int i = 0; i < 8 && (!anyWasInside || !anyWasOutside); ++i) { - std::bitset<3> bits(i); - glm::vec3 corner; - corner.x = bits.test(0) ? maxCorner.x : minCorner.x; - corner.y = bits.test(1) ? maxCorner.y : minCorner.y; - corner.z = bits.test(2) ? maxCorner.z : minCorner.z; - if (glm::dot(p.Normal, corner) > p.Distance) { - anyWasInside = true; - } else { - anyWasOutside = true; - } - } - if (!anyWasInside) { - return Outside; - } - if (anyWasOutside) { - completelyInside = false; - } - } - return completelyInside ? Inside : Intersects; - } -}; - struct ContainedObject { ContainedObject() @@ -210,23 +161,9 @@ void Octree::ObjectsInSameRegion(const Box& box, std::vector& outObjects) } template -void Octree::ObjectsInFrustum(const glm::mat4x4& viewProj, std::vector& outObjects) +void Octree::ObjectsInFrustum(const Frustum& frustum, std::vector& outObjects) { falsifyObjectChecks(); - OctSpace::Frustum frustum; - //Order: Right, left, top, bottom, far, near. - for (int i = 0; i < 6; ++i) { - int sign = 2 * (i % 2) - 1; - int index = i / 2; - OctSpace::Plane& plane = frustum.Planes[i]; - plane.Normal.x = viewProj[0].w + sign * viewProj[0][index]; - plane.Normal.y = viewProj[1].w + sign * viewProj[1][index]; - plane.Normal.z = viewProj[2].w + sign * viewProj[2][index]; - plane.Distance = viewProj[3].w + sign * viewProj[3][index]; - float divByNormalLength = 1.0f / glm::length(plane.Normal); - plane.Normal *= divByNormalLength; - plane.Distance *= divByNormalLength; - } m_Root->ObjectsInFrustum(frustum, outObjects, false); } @@ -311,14 +248,14 @@ void OctSpace::Child::ObjectsInFrustum(const Frustum& frustum, std::vector& o { if (hasChildren()) { for (const Child* c : m_Children) { - Frustum::Output out = Frustum::Inside; + Frustum::Output out = Frustum::Output::Inside; if (!takeAllDontTest) { out = frustum.VsAABB(c->m_Box); - if (out == Frustum::Outside) { + if (out == Frustum::Output::Outside) { continue; } } - c->ObjectsInFrustum(frustum, outObjects, out == Frustum::Inside); + c->ObjectsInFrustum(frustum, outObjects, out == Frustum::Output::Inside); } } else { size_t startIndex = outObjects.size(); @@ -326,7 +263,7 @@ void OctSpace::Child::ObjectsInFrustum(const Frustum& frustum, std::vector& o outObjects.resize(outObjects.size() + m_StaticObjIndices.size() + m_DynamicObjIndices.size()); for (size_t i = 0; i < m_StaticObjIndices.size(); ++i) { ContainedObject& obj = m_StaticObjectsRef[m_StaticObjIndices[i]]; - if (obj.Checked || !frustum.VsAABB(obj.Box)) { + if (obj.Checked || frustum.VsAABB(*obj.Box) == Frustum::Output::Outside) { ++numDuplicates; } else { obj.Checked = true; @@ -335,7 +272,7 @@ void OctSpace::Child::ObjectsInFrustum(const Frustum& frustum, std::vector& o } for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) { ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]]; - if (obj.Checked || !frustum.VsAABB(obj.Box)) { + if (obj.Checked || frustum.VsAABB(*obj.Box) == Frustum::Output::Outside) { ++numDuplicates; } else { obj.Checked = true; diff --git a/include/Engine/Rendering/RenderSystem.h b/include/Engine/Rendering/RenderSystem.h index e4e6475a..44088913 100644 --- a/include/Engine/Rendering/RenderSystem.h +++ b/include/Engine/Rendering/RenderSystem.h @@ -31,9 +31,6 @@ private: const IRenderer* m_Renderer; RenderFrame* m_RenderFrame; Camera* m_Camera; - Camera* m_LastCullCamera; - Camera** m_FrustumCamPtr; - EntityWrapper frustumEntity; World* m_World; EntityWrapper m_CurrentCamera = EntityWrapper::Invalid; EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; diff --git a/src/Engine/Rendering/RenderSystem.cpp b/src/Engine/Rendering/RenderSystem.cpp index 9d7e7530..26eea7f2 100644 --- a/src/Engine/Rendering/RenderSystem.cpp +++ b/src/Engine/Rendering/RenderSystem.cpp @@ -1,5 +1,6 @@ #include "Rendering/RenderSystem.h" #include "Collision/Collision.h" +#include "Core/Frustum.h" RenderSystem::RenderSystem(World* world, EventBroker* eventBroker, const IRenderer* renderer, RenderFrame* renderFrame, Octree* frustumCullOctree) : System(world, eventBroker) @@ -13,31 +14,15 @@ RenderSystem::RenderSystem(World* world, EventBroker* eventBroker, const IRender EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &RenderSystem::OnPlayerSpawned); m_Camera = new Camera((float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, glm::radians(45.f), 0.01f, 5000.f); - m_LastCullCamera = new Camera(*m_Camera); - m_FrustumCamPtr = &m_Camera; } RenderSystem::~RenderSystem() { delete m_Camera; - delete m_LastCullCamera; } bool RenderSystem::OnSetCamera(Events::SetCamera& e) { - //Right now, lets set the camera to cull away stuff if it is connected to a player. - //TODO: This won't work with spectators, or death anim. - if (e.CameraEntity.FirstParentWithComponent("Player").Valid()) { - m_FrustumCamPtr = &m_Camera; - LOG_INFO("Setting frustum to new camera."); - } else if (e.CameraEntity != m_CurrentCamera) { - //If the camera has no parents, i.e. a free camera, - //then we cull from the last camera, so we can see if the culling works. - //Copy the camera into the last frustum camera, without allocating new memory. - new ((void*)m_LastCullCamera) Camera(*m_Camera); - m_FrustumCamPtr = &m_LastCullCamera; - LOG_INFO("New camera, frustum remains at old camera."); - } ComponentWrapper cTransform = e.CameraEntity["Transform"]; ComponentWrapper cCamera = e.CameraEntity["Camera"]; m_Camera->SetFOV((double)cCamera["FOV"]); @@ -58,55 +43,15 @@ bool RenderSystem::isChildOfCurrentCamera(EntityWrapper entity) return entity == m_CurrentCamera || entity.IsChildOf(m_CurrentCamera); } -float frustrumTODO = 0.f; - void RenderSystem::fillModels(std::list>& opaqueJobs, std::list>& transparentJobs) { - if (!frustumEntity.Valid() && m_World->GetComponentPools().size() > 0) { - frustumEntity = EntityWrapper(m_World, m_World->CreateEntity()); - m_World->AttachComponent(frustumEntity.ID, "Transform"); - m_World->AttachComponent(frustumEntity.ID, "Model"); - frustumEntity["Model"]["Resource"] = "Models/Core/UnitCube.mesh"; - } - + Frustum frustum(m_Camera->ProjectionMatrix() * m_Camera->ViewMatrix()); std::vector seenEntities; - //m_Octree->ObjectsInFrustum((*m_FrustumCamPtr)->ProjectionMatrix() * (*m_FrustumCamPtr)->ViewMatrix(), seenEntities); + m_Octree->ObjectsInFrustum(frustum, seenEntities); - glm::mat4x4 viewProj = (*m_FrustumCamPtr)->ProjectionMatrix() * (*m_FrustumCamPtr)->ViewMatrix(); - OctSpace::Frustum frustum; - //Order: Right, left, top, bottom, far, near. - int sign = 1; - for (int i = 0; i < 6; ++i) { - sign = -sign; - int index = i / 2; - OctSpace::Plane& plane = frustum.Planes[i]; - plane.Normal.x = viewProj[0].w + sign * viewProj[0][index]; - plane.Normal.y = viewProj[1].w + sign * viewProj[1][index]; - plane.Normal.z = viewProj[2].w + sign * viewProj[2][index]; - plane.Distance = viewProj[3].w + sign * viewProj[3][index]; - float divByNormalLength = 1.0f / glm::length(plane.Normal); - plane.Normal *= divByNormalLength; - plane.Distance *= divByNormalLength; - } - if (frustumEntity.Valid()) { - int planeI = 0; - glm::vec3 pos = (*m_FrustumCamPtr)->Position() + frustrumTODO * (*m_FrustumCamPtr)->Forward(); - float dist = glm::dot(frustum.Planes[planeI].Normal, pos) + frustum.Planes[planeI].Distance; - frustumEntity["Transform"]["Position"] = pos - dist * frustum.Planes[planeI].Normal; - frustumEntity["Transform"]["Scale"] = glm::vec3(0.15f); - } - if (++frustrumTODO > 75) { - frustrumTODO = 0.f; - } - - //for (auto& seenEntity : seenEntities) { - // EntityWrapper entity = seenEntity.Entity; - // ComponentWrapper cModel = entity["Model"]; - auto models = m_World->GetComponents("Model"); - if (models == nullptr) { - return; - } - for (auto& cModel : *models) { + for (auto& seenEntity : seenEntities) { + EntityWrapper entity = seenEntity.Entity; + ComponentWrapper cModel = entity["Model"]; bool visible = cModel["Visible"]; if (!visible) { continue; @@ -116,8 +61,6 @@ void RenderSystem::fillModels(std::list>& opaqueJobs, continue; } - EntityWrapper entity = EntityWrapper(m_World, cModel.EntityID); - // Only render children of a camera if that camera is currently active if (isChildOfACamera(entity) && !isChildOfCurrentCamera(entity)) { continue; @@ -128,15 +71,6 @@ void RenderSystem::fillModels(std::list>& opaqueJobs, continue; } - if (entity.HasComponent("AABB")) { - OctSpace::Frustum::Output o = frustum.VsAABB(*Collision::EntityAbsoluteAABB(entity)); - if (o == OctSpace::Frustum::Outside && entity != frustumEntity) { - resource = "Models/Core/UnitRaptor.mesh"; - } - } else if (entity != frustumEntity){ - resource = "Models/Core/Error.mesh"; - } - Model* model; try { model = ResourceManager::Load<::Model, true>(resource); diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 669e48d0..1124f2e4 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -100,7 +100,7 @@ Game::Game(int argc, char* argv[]) ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision, "Collidable"); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeTrigger, "Player"); - m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeFrustrumCulling, "Model"); + m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeFrustrumCulling, "Model"); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel);