From b748deb1e1e91c3177af65e1c778454f6afd1585 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 9 Feb 2016 10:05:49 +0100 Subject: [PATCH 1/8] WIP FrustumCulling, most code added but not working now. --- include/Engine/Core/Octree.h | 117 ++++++++++++++++++++++++ include/Engine/Rendering/RenderSystem.h | 7 +- src/Engine/Rendering/RenderSystem.cpp | 53 ++++++++++- src/Game/Game.cpp | 10 +- 4 files changed, 179 insertions(+), 8 deletions(-) diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index 907d5736..d97d644b 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -2,6 +2,7 @@ #define Octree_h__ #include +#include #include "../Common.h" #include "AABB.h" @@ -40,6 +41,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); //Empty the tree of all objects, static and dynamic. void ClearObjects(); //Empty the tree of all dynamic objects. Static objects remain in the tree. @@ -68,6 +71,56 @@ 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() @@ -97,6 +150,8 @@ struct Child void AddStaticObject(const AABB& box); template void ObjectsInSameRegion(const Box& box, std::vector& outObjects) const; + template + void ObjectsInFrustum(const Frustum& frustum, std::vector& outObjects, bool takeAllDontTest) const; void ClearObjects(); void ClearDynamicObjects(); bool RayCollides(const Ray& ray, Output& data) const; @@ -154,6 +209,26 @@ void Octree::ObjectsInSameRegion(const Box& box, std::vector& outObjects) m_Root->ObjectsInSameRegion(box, outObjects); } +template +void Octree::ObjectsInFrustum(const glm::mat4x4& viewProj, std::vector& outObjects) +{ + falsifyObjectChecks(); + OctSpace::Frustum frustum; + 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); +} + template void Octree::ClearObjects() { @@ -230,4 +305,46 @@ void OctSpace::Child::ObjectsInSameRegion(const Box& box, std::vector& outObj } } +template +void OctSpace::Child::ObjectsInFrustum(const Frustum& frustum, std::vector& outObjects, bool takeAllDontTest) const +{ + if (hasChildren()) { + for (const Child* c : m_Children) { + Frustum::Output out = Frustum::Inside; + if (!takeAllDontTest) { + out = frustum.VsAABB(c->m_Box); + if (out == Frustum::Outside) { + continue; + } + } + c->ObjectsInFrustum(frustum, outObjects, out == Frustum::Inside); + } + } else { + size_t startIndex = outObjects.size(); + int numDuplicates = 0; + 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)) { + ++numDuplicates; + } else { + obj.Checked = true; + outObjects[startIndex + i - numDuplicates] = *static_cast(obj.Box.get()); + } + } + for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) { + ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]]; + if (obj.Checked || !frustum.VsAABB(obj.Box)) { + ++numDuplicates; + } else { + obj.Checked = true; + outObjects[startIndex + i - numDuplicates] = *static_cast(obj.Box.get()); + } + } + for (size_t i = 0; i < numDuplicates; ++i) { + outObjects.pop_back(); + } + } +} + #endif \ No newline at end of file diff --git a/include/Engine/Rendering/RenderSystem.h b/include/Engine/Rendering/RenderSystem.h index d64147b9..d404c56a 100644 --- a/include/Engine/Rendering/RenderSystem.h +++ b/include/Engine/Rendering/RenderSystem.h @@ -16,11 +16,13 @@ #include "PointLightJob.h" #include "../Core/Transform.h" #include "../Core/EPlayerSpawned.h" +#include "../Core/Octree.h" +#include "../Collision/EntityAABB.h" class RenderSystem : public ImpureSystem { public: - RenderSystem(World* world, EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame); + RenderSystem(World* world, EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame, Octree* frustumCullOctree); ~RenderSystem(); virtual void Update(double dt) override; @@ -29,9 +31,12 @@ private: const IRenderer* m_Renderer; RenderFrame* m_RenderFrame; Camera* m_Camera; + Camera* m_LastCullCamera; + Camera** m_FrustumCamPtr; World* m_World; EntityWrapper m_CurrentCamera = EntityWrapper::Invalid; EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; + Octree* m_Octree; EventRelay m_ESetCamera; bool OnSetCamera(Events::SetCamera &event); diff --git a/src/Engine/Rendering/RenderSystem.cpp b/src/Engine/Rendering/RenderSystem.cpp index eaecf99e..d57e263a 100644 --- a/src/Engine/Rendering/RenderSystem.cpp +++ b/src/Engine/Rendering/RenderSystem.cpp @@ -1,21 +1,26 @@ #include "Rendering/RenderSystem.h" +#include "Collision/Collision.h" -RenderSystem::RenderSystem(World* world, EventBroker* eventBroker, const IRenderer* renderer, RenderFrame* renderFrame) +RenderSystem::RenderSystem(World* world, EventBroker* eventBroker, const IRenderer* renderer, RenderFrame* renderFrame, Octree* frustumCullOctree) : System(world, eventBroker) , m_Renderer(renderer) , m_RenderFrame(renderFrame) , m_World(world) + , m_Octree(frustumCullOctree) { EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &RenderSystem::OnSetCamera); EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &RenderSystem::OnInputCommand); 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) @@ -28,6 +33,17 @@ bool RenderSystem::OnSetCamera(Events::SetCamera& e) m_Camera->SetPosition(cTransform["Position"]); m_Camera->SetOrientation(glm::quat((const glm::vec3&)cTransform["Orientation"])); m_CurrentCamera = e.CameraEntity; + //Right now, lets set the camera to cull away stuff if it is connected to anything. + //TODO: This won't work with spectators, or death anim. + if (m_CurrentCamera.Parent().Valid()) { + //Copy the camera into the last frustum camera, without allocating new memory. + new ((void*)m_LastCullCamera) Camera(*m_Camera); + m_FrustumCamPtr = &m_Camera; + } else { + //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. + m_FrustumCamPtr = &m_LastCullCamera; + } return true; } @@ -42,11 +58,33 @@ bool RenderSystem::isChildOfCurrentCamera(EntityWrapper entity) void RenderSystem::fillModels(std::list>& opaqueJobs, std::list>& transparentJobs) { + + std::vector seenEntities; + //m_Octree->ObjectsInFrustum((*m_FrustumCamPtr)->ProjectionMatrix() * (*m_FrustumCamPtr)->ViewMatrix(), seenEntities); + //m_Octree->ObjectsInFrustum((*m_FrustumCamPtr)->ViewMatrix() * (*m_FrustumCamPtr)->ProjectionMatrix(), seenEntities); + + glm::mat4x4 viewProj = (*m_FrustumCamPtr)->ViewMatrix() * (*m_FrustumCamPtr)->ProjectionMatrix(); + OctSpace::Frustum frustum; + 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; + } + + //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) { bool visible = cModel["Visible"]; if (!visible) { @@ -57,7 +95,7 @@ void RenderSystem::fillModels(std::list>& opaqueJobs, continue; } - EntityWrapper entity(m_World, cModel.EntityID); + EntityWrapper entity = EntityWrapper(m_World, cModel.EntityID); // Only render children of a camera if that camera is currently active if (isChildOfACamera(entity) && !isChildOfCurrentCamera(entity)) { @@ -69,6 +107,15 @@ 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) { + continue; + } + } else { + continue; + } + Model* model; try { model = ResourceManager::Load<::Model, true>(resource); diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 0c92271d..d3c2eb57 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -75,9 +75,10 @@ Game::Game(int argc, char* argv[]) // Create Octrees - m_OctreeCollision = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); - m_OctreeTrigger = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); - m_OctreeFrustrumCulling = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); + AABB boxContainingTheWorld(glm::vec3(-300), glm::vec3(300)); + m_OctreeCollision = new Octree(boxContainingTheWorld, 4); + m_OctreeTrigger = new Octree(boxContainingTheWorld, 4); + m_OctreeFrustrumCulling = new Octree(boxContainingTheWorld, 4); // Create system pipeline m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker); @@ -99,6 +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_SystemPipeline->AddSystem(updateOrderLevel); @@ -107,7 +109,7 @@ Game::Game(int argc, char* argv[]) m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeTrigger); ++updateOrderLevel; - m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame); + m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame, m_OctreeFrustrumCulling); ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame); From b30891aecdbd9886d4f876d01b8cad91d41b6eb2 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 9 Feb 2016 15:00:30 +0100 Subject: [PATCH 2/8] WIP, debugging code added, still not working. --- include/Engine/Core/Octree.h | 27 ++++----- include/Engine/Rendering/RenderSystem.h | 1 + src/Engine/Rendering/RenderSystem.cpp | 73 ++++++++++++++++--------- 3 files changed, 62 insertions(+), 39 deletions(-) diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index d97d644b..e0165cef 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -74,8 +74,8 @@ struct Output //Contains points P in: dot(normal, P) + d = 0 struct Plane { - glm::vec3 normal; - float distance; + glm::vec3 Normal; + float Distance; }; //A frustum defined by 6 planes. @@ -87,14 +87,14 @@ struct Frustum Outside, Intersects }; - Plane planes[6]; + 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) { + for (const Plane& p : Planes) { bool anyWasInside = false; bool anyWasOutside = false; //If points are on both sides of the plane, we can stop. @@ -104,7 +104,7 @@ struct Frustum 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) { + if (glm::dot(p.Normal, corner) > p.Distance) { anyWasInside = true; } else { anyWasOutside = true; @@ -214,17 +214,18 @@ void Octree::ObjectsInFrustum(const glm::mat4x4& viewProj, std::vector& ou { 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; + 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); } diff --git a/include/Engine/Rendering/RenderSystem.h b/include/Engine/Rendering/RenderSystem.h index d404c56a..e4e6475a 100644 --- a/include/Engine/Rendering/RenderSystem.h +++ b/include/Engine/Rendering/RenderSystem.h @@ -33,6 +33,7 @@ private: 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 d57e263a..9d7e7530 100644 --- a/src/Engine/Rendering/RenderSystem.cpp +++ b/src/Engine/Rendering/RenderSystem.cpp @@ -25,6 +25,19 @@ RenderSystem::~RenderSystem() 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"]); @@ -33,17 +46,6 @@ bool RenderSystem::OnSetCamera(Events::SetCamera& e) m_Camera->SetPosition(cTransform["Position"]); m_Camera->SetOrientation(glm::quat((const glm::vec3&)cTransform["Orientation"])); m_CurrentCamera = e.CameraEntity; - //Right now, lets set the camera to cull away stuff if it is connected to anything. - //TODO: This won't work with spectators, or death anim. - if (m_CurrentCamera.Parent().Valid()) { - //Copy the camera into the last frustum camera, without allocating new memory. - new ((void*)m_LastCullCamera) Camera(*m_Camera); - m_FrustumCamPtr = &m_Camera; - } else { - //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. - m_FrustumCamPtr = &m_LastCullCamera; - } return true; } @@ -56,26 +58,45 @@ 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"; + } std::vector seenEntities; //m_Octree->ObjectsInFrustum((*m_FrustumCamPtr)->ProjectionMatrix() * (*m_FrustumCamPtr)->ViewMatrix(), seenEntities); - //m_Octree->ObjectsInFrustum((*m_FrustumCamPtr)->ViewMatrix() * (*m_FrustumCamPtr)->ProjectionMatrix(), seenEntities); - glm::mat4x4 viewProj = (*m_FrustumCamPtr)->ViewMatrix() * (*m_FrustumCamPtr)->ProjectionMatrix(); + 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) { - int sign = 2 * (i % 2) - 1; + 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; + 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) { @@ -109,11 +130,11 @@ void RenderSystem::fillModels(std::list>& opaqueJobs, if (entity.HasComponent("AABB")) { OctSpace::Frustum::Output o = frustum.VsAABB(*Collision::EntityAbsoluteAABB(entity)); - if (o == OctSpace::Frustum::Outside) { - continue; + if (o == OctSpace::Frustum::Outside && entity != frustumEntity) { + resource = "Models/Core/UnitRaptor.mesh"; } - } else { - continue; + } else if (entity != frustumEntity){ + resource = "Models/Core/Error.mesh"; } Model* model; From 239a8e7a6a38616614f9f09aa5a44dfab95b23e7 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 9 Feb 2016 17:12:23 +0100 Subject: [PATCH 3/8] Frustum culling should be working. --- include/Engine/Core/Frustum.h | 77 +++++++++++++++++++++++ include/Engine/Core/Octree.h | 81 +++---------------------- include/Engine/Rendering/RenderSystem.h | 3 - src/Engine/Rendering/RenderSystem.cpp | 78 ++---------------------- src/Game/Game.cpp | 2 +- 5 files changed, 93 insertions(+), 148 deletions(-) create mode 100644 include/Engine/Core/Frustum.h 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); From eec59a40c842c17f2386836841ce0a6a1963d0e4 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 9 Feb 2016 17:19:39 +0100 Subject: [PATCH 4/8] Nitpicks. --- include/Engine/Core/Octree.h | 1 - src/Game/Game.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index 49a8b045..6bdea4d3 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -2,7 +2,6 @@ #define Octree_h__ #include -#include #include "../Common.h" #include "AABB.h" diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 1124f2e4..d32eb2ba 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -75,6 +75,7 @@ Game::Game(int argc, char* argv[]) // Create Octrees + // TODO: Perhaps the world bounds should be set in some non-arbitrary way instead of this. AABB boxContainingTheWorld(glm::vec3(-300), glm::vec3(300)); m_OctreeCollision = new Octree(boxContainingTheWorld, 4); m_OctreeTrigger = new Octree(boxContainingTheWorld, 4); From 7140b740b5dc06d0ff122413093d9ba88af09972 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 9 Feb 2016 19:20:04 +0100 Subject: [PATCH 5/8] Models/Collideables/etc. won't need a AABB component anymore, if it has a Model component. In addition, they should take rotation into account, i.e it doesn't have to be axis-aligned. --- include/Engine/Collision/Collision.h | 2 - include/Engine/Rendering/Model.h | 5 +- src/Engine/Collision/Collision.cpp | 71 ++++++++++++----------- src/Engine/Collision/FillOctreeSystem.cpp | 6 -- src/Engine/Collision/TriggerSystem.cpp | 5 -- src/Engine/Rendering/Model.cpp | 9 +++ 6 files changed, 51 insertions(+), 47 deletions(-) diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index 6d16e090..6e4858b2 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -78,8 +78,6 @@ bool AABBVsAABB(const AABB& a, const AABB& b); //Also outputs the minimum translation that box [a] would need in order to resolve collision. bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation); -//Attaches an AABB which contains all vertices in the entitys Model. -bool AttachAABBComponentFromModel(EntityWrapper entity); // Calculates an absolute AABB from an entity AABB component boost::optional EntityAbsoluteAABB(EntityWrapper& entity); diff --git a/include/Engine/Rendering/Model.h b/include/Engine/Rendering/Model.h index f751a8cc..1f5231e2 100644 --- a/include/Engine/Rendering/Model.h +++ b/include/Engine/Rendering/Model.h @@ -4,6 +4,7 @@ #include "Rendering/RawModelCustom.h" //#include "Rendering/RawModelAssimp.h" #include "../OpenGL.h" +#include "Core/AABB.h" class Model : public ThreadUnsafeResource { @@ -17,13 +18,15 @@ public: const std::vector& MaterialGroups() const { return m_RawModel->MaterialGroups; } const glm::mat4& Matrix() const { return m_RawModel->m_Matrix; } const std::vector& Vertices() const { return m_RawModel->m_Vertices; } + const AABB& Box() const { return m_Box; } GLuint VAO; GLuint ElementBuffer; RawModel* m_RawModel; private: - + AABB m_Box; + GLuint VertexBuffer; GLuint NormalBuffer; GLuint TangentNormalsBuffer; diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index b150d667..db2319c7 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -1,4 +1,5 @@ #include +#include #include "Collision/Collision.h" #include "Engine/GLM.h" @@ -564,45 +565,49 @@ bool AABBvsTriangles(const AABB& box, return hit; } -bool AttachAABBComponentFromModel(EntityWrapper entity) -{ - if (!entity.HasComponent("Model")) { - return false; - } - //Derive AABB from model - RawModel* model; - try { - model = ResourceManager::Load(entity["Model"]["Resource"]); - } catch (const std::exception&) { - return false; - } - - glm::vec3 mini(INFINITY); - glm::vec3 maxi(-INFINITY); - for (const auto& v : model->m_Vertices) { - mini = glm::min(mini, v.Position); - maxi = glm::max(maxi, v.Position); - } - - entity.AttachComponent("AABB"); - entity["AABB"]["Origin"] = 0.5f * (maxi + mini); - entity["AABB"]["Size"] = maxi - mini; - return true; -} - boost::optional EntityAbsoluteAABB(EntityWrapper& entity) { - if (!entity.HasComponent("AABB")) { + AABB modelSpaceBox; + if (entity.HasComponent("AABB")) { + ComponentWrapper& cAABB = entity["AABB"]; + modelSpaceBox = EntityAABB::FromOriginSize((glm::vec3)cAABB["Origin"], (glm::vec3)cAABB["Size"]); + } else if (entity.HasComponent("Model")) { + Model* model; + std::string res = entity["Model"]["Resource"]; + if (res.empty()) { + return boost::none; + } + try { + model = ResourceManager::Load<::Model, true>(res); + } catch (const Resource::StillLoadingException&) { + return boost::none; + } catch (const std::exception&) { + return boost::none; + } + modelSpaceBox = model->Box(); + } else { return boost::none; } - ComponentWrapper& cAABB = entity["AABB"]; - glm::vec3 absPosition = Transform::AbsolutePosition(entity.World, entity.ID); - glm::vec3 absScale = Transform::AbsoluteScale(entity.World, entity.ID); - glm::vec3 origin = absPosition + (glm::vec3)cAABB["Origin"]; - glm::vec3 size = (glm::vec3)cAABB["Size"] * absScale; + glm::mat4 modelMat = Transform::AbsoluteTransformation(entity); + glm::vec3 mini(INFINITY); + glm::vec3 maxi(-INFINITY); + glm::vec3 maxCorner = modelSpaceBox.MaxCorner(); + glm::vec3 minCorner = modelSpaceBox.MinCorner(); + for (int i = 0; i < 8; ++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; + corner = Transform::TransformPoint(corner, modelMat); + mini = glm::min(mini, corner); + maxi = glm::max(maxi, corner); + } + + EntityAABB aabb; + aabb = AABB(mini, maxi); - EntityAABB aabb = EntityAABB::FromOriginSize(origin, size); aabb.Entity = entity; return aabb; diff --git a/src/Engine/Collision/FillOctreeSystem.cpp b/src/Engine/Collision/FillOctreeSystem.cpp index 8c03b5c2..a727eb86 100644 --- a/src/Engine/Collision/FillOctreeSystem.cpp +++ b/src/Engine/Collision/FillOctreeSystem.cpp @@ -7,12 +7,6 @@ void FillOctreeSystem::Update(double dt) void FillOctreeSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) { - if (!entity.HasComponent("AABB")) { - //Derive AABB from model. - if (!Collision::AttachAABBComponentFromModel(entity)) { - return; - } - } boost::optional absoluteAABB = Collision::EntityAbsoluteAABB(entity); if (absoluteAABB) { m_Octree->AddDynamicObject(*absoluteAABB); diff --git a/src/Engine/Collision/TriggerSystem.cpp b/src/Engine/Collision/TriggerSystem.cpp index adc778e5..21a47721 100644 --- a/src/Engine/Collision/TriggerSystem.cpp +++ b/src/Engine/Collision/TriggerSystem.cpp @@ -5,11 +5,6 @@ void TriggerSystem::UpdateComponent(EntityWrapper& triggerEntity, ComponentWrapper& cTrigger, double dt) { - // The trigger *should* have a bounding box, or something, to test against so it can be triggered. - // If it doesn't, add one as big as the model for now, then size can be modified in editor if necessary. - if (!triggerEntity.HasComponent("AABB")) { - Collision::AttachAABBComponentFromModel(triggerEntity); - } boost::optional triggerBox = Collision::EntityAbsoluteAABB(triggerEntity); if (!triggerBox) { return; diff --git a/src/Engine/Rendering/Model.cpp b/src/Engine/Rendering/Model.cpp index cf4923a3..a61cf8e3 100644 --- a/src/Engine/Rendering/Model.cpp +++ b/src/Engine/Rendering/Model.cpp @@ -64,6 +64,15 @@ Model::Model(std::string fileName) GLERROR("GLEW: BufferFail5"); //CreateBuffers(); + + glm::vec3 mini(INFINITY); + glm::vec3 maxi(-INFINITY); + for (const auto& v : m_RawModel->m_Vertices) { + mini = glm::min(mini, v.Position); + maxi = glm::max(maxi, v.Position); + } + + m_Box = AABB(maxi, mini); } Model::~Model() From a93ccecfeb41bcdaccfffd0e6b4d9a52f6e83c6d Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 9 Feb 2016 19:23:12 +0100 Subject: [PATCH 6/8] Debug test code. --- src/Engine/Collision/Collision.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index db2319c7..a20ae4d3 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -568,10 +568,10 @@ bool AABBvsTriangles(const AABB& box, boost::optional EntityAbsoluteAABB(EntityWrapper& entity) { AABB modelSpaceBox; - if (entity.HasComponent("AABB")) { + /*if (entity.HasComponent("AABB")) { ComponentWrapper& cAABB = entity["AABB"]; modelSpaceBox = EntityAABB::FromOriginSize((glm::vec3)cAABB["Origin"], (glm::vec3)cAABB["Size"]); - } else if (entity.HasComponent("Model")) { + } else */if (entity.HasComponent("Model")) { Model* model; std::string res = entity["Model"]["Resource"]; if (res.empty()) { @@ -584,6 +584,7 @@ boost::optional EntityAbsoluteAABB(EntityWrapper& entity) } catch (const std::exception&) { return boost::none; } + entity.AttachComponent("AABB"); modelSpaceBox = model->Box(); } else { return boost::none; @@ -609,7 +610,8 @@ boost::optional EntityAbsoluteAABB(EntityWrapper& entity) aabb = AABB(mini, maxi); aabb.Entity = entity; - + (glm::vec3&)entity["AABB"]["Origin"] = aabb.Origin(); + (glm::vec3&)entity["AABB"]["Size"] = aabb.Size(); return aabb; } From ecfacee5876ad73a5fc4daa1746914390b2db8ae Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 9 Feb 2016 19:33:28 +0100 Subject: [PATCH 7/8] Undo debug test code. --- src/Engine/Collision/Collision.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index a20ae4d3..c0c27190 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -568,10 +568,10 @@ bool AABBvsTriangles(const AABB& box, boost::optional EntityAbsoluteAABB(EntityWrapper& entity) { AABB modelSpaceBox; - /*if (entity.HasComponent("AABB")) { + if (entity.HasComponent("AABB")) { ComponentWrapper& cAABB = entity["AABB"]; modelSpaceBox = EntityAABB::FromOriginSize((glm::vec3)cAABB["Origin"], (glm::vec3)cAABB["Size"]); - } else */if (entity.HasComponent("Model")) { + } else if (entity.HasComponent("Model")) { Model* model; std::string res = entity["Model"]["Resource"]; if (res.empty()) { @@ -584,7 +584,6 @@ boost::optional EntityAbsoluteAABB(EntityWrapper& entity) } catch (const std::exception&) { return boost::none; } - entity.AttachComponent("AABB"); modelSpaceBox = model->Box(); } else { return boost::none; @@ -610,8 +609,6 @@ boost::optional EntityAbsoluteAABB(EntityWrapper& entity) aabb = AABB(mini, maxi); aabb.Entity = entity; - (glm::vec3&)entity["AABB"]["Origin"] = aabb.Origin(); - (glm::vec3&)entity["AABB"]["Size"] = aabb.Size(); return aabb; } From d65ce805a502f82b45e92e116148b794442ce6a8 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Wed, 10 Feb 2016 10:53:25 +0100 Subject: [PATCH 8/8] FrustumOctree has its own system, won't cull away explosion effects. --- .../Collision/FillFrustumOctreeSystem.h | 25 +++++++++++++++++++ include/Engine/Collision/FillOctreeSystem.h | 4 +-- .../Collision/FillFrustumOctreeSystem.cpp | 21 ++++++++++++++++ src/Game/Game.cpp | 3 ++- 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 include/Engine/Collision/FillFrustumOctreeSystem.h create mode 100644 src/Engine/Collision/FillFrustumOctreeSystem.cpp diff --git a/include/Engine/Collision/FillFrustumOctreeSystem.h b/include/Engine/Collision/FillFrustumOctreeSystem.h new file mode 100644 index 00000000..f7f1413c --- /dev/null +++ b/include/Engine/Collision/FillFrustumOctreeSystem.h @@ -0,0 +1,25 @@ +#ifndef FillFrustumOctreeSystem_h__ +#define FillFrustumOctreeSystem_h__ + +#include "../Core/System.h" +#include "../Core/Octree.h" +#include "Collision.h" +#include "EntityAABB.h" + +class FillFrustumOctreeSystem : public ImpureSystem, public PureSystem +{ +public: + FillFrustumOctreeSystem(World* world, EventBroker* eventBroker, Octree* octree) + : System(world, eventBroker) + , PureSystem("Model") + , m_Octree(octree) + { } + + virtual void Update(double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override; + +private: + Octree* m_Octree; +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Collision/FillOctreeSystem.h b/include/Engine/Collision/FillOctreeSystem.h index 9fd87b94..3bacccac 100644 --- a/include/Engine/Collision/FillOctreeSystem.h +++ b/include/Engine/Collision/FillOctreeSystem.h @@ -1,5 +1,5 @@ -#ifndef CollidableOctreeSystem_h__ -#define CollidableOctreeSystem_h__ +#ifndef FillOctreeSystem_h__ +#define FillOctreeSystem_h__ #include "../Core/System.h" #include "../Core/Octree.h" diff --git a/src/Engine/Collision/FillFrustumOctreeSystem.cpp b/src/Engine/Collision/FillFrustumOctreeSystem.cpp new file mode 100644 index 00000000..f02a30f1 --- /dev/null +++ b/src/Engine/Collision/FillFrustumOctreeSystem.cpp @@ -0,0 +1,21 @@ +#include "Collision/FillFrustumOctreeSystem.h" + +void FillFrustumOctreeSystem::Update(double dt) +{ + m_Octree->ClearDynamicObjects(); +} + +void FillFrustumOctreeSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) +{ + if (entity.HasComponent("ExplosionEffect")) { + //TODO: Fix hack, get real box by using shader equation. + EntityAABB aabb = AABB(glm::vec3(-300), glm::vec3(300)); + aabb.Entity = entity; + m_Octree->AddDynamicObject(aabb); + } else { + boost::optional absoluteAABB = Collision::EntityAbsoluteAABB(entity); + if (absoluteAABB) { + m_Octree->AddDynamicObject(*absoluteAABB); + } + } +} \ No newline at end of file diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index d32eb2ba..0f836c6f 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -1,5 +1,6 @@ #include "Game.h" #include "Collision/FillOctreeSystem.h" +#include "Collision/FillFrustumOctreeSystem.h" #include "Collision/EntityAABB.h" #include "Collision/TriggerSystem.h" #include "Collision/CollisionSystem.h" @@ -101,7 +102,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); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel);