From 097613f34bb0ff82beb3d6da53d85c8e658f774f Mon Sep 17 00:00:00 2001 From: GeorgH93 Date: Sun, 31 Jan 2021 03:28:21 +0100 Subject: [PATCH] Add Frustum class --- openVulkanoCpp/Math/Frustum.hpp | 141 ++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 openVulkanoCpp/Math/Frustum.hpp diff --git a/openVulkanoCpp/Math/Frustum.hpp b/openVulkanoCpp/Math/Frustum.hpp new file mode 100644 index 0000000..0526b55 --- /dev/null +++ b/openVulkanoCpp/Math/Frustum.hpp @@ -0,0 +1,141 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "Math.hpp" + +namespace openVulkanoCpp::Math +{ + class Frustum + { + enum Planes + { + LEFT = 0, + RIGHT, + BOTTOM, + TOP, + NEAR, + FAR, + COUNT, + COMBINATIONS = COUNT * (COUNT - 1) / 2 + }; + + public: + Frustum() + {} + + // m = ProjectionMatrix * ViewMatrix + Frustum(Math::Matrix4f m) + { + m = Math::Utils::transpose(m); + m_planes[LEFT] = m[3] + m[0]; + m_planes[RIGHT] = m[3] - m[0]; + m_planes[BOTTOM] = m[3] + m[1]; + m_planes[TOP] = m[3] - m[1]; + m_planes[NEAR] = m[3] + m[2]; + m_planes[FAR] = m[3] - m[2]; + + Math::Vector3f crosses[COMBINATIONS] = { + Math::Utils::cross(Math::Vector3f(m_planes[LEFT]), Math::Vector3f(m_planes[RIGHT])), + Math::Utils::cross(Math::Vector3f(m_planes[LEFT]), Math::Vector3f(m_planes[BOTTOM])), + Math::Utils::cross(Math::Vector3f(m_planes[LEFT]), Math::Vector3f(m_planes[TOP])), + Math::Utils::cross(Math::Vector3f(m_planes[LEFT]), Math::Vector3f(m_planes[NEAR])), + Math::Utils::cross(Math::Vector3f(m_planes[LEFT]), Math::Vector3f(m_planes[FAR])), + Math::Utils::cross(Math::Vector3f(m_planes[RIGHT]), Math::Vector3f(m_planes[BOTTOM])), + Math::Utils::cross(Math::Vector3f(m_planes[RIGHT]), Math::Vector3f(m_planes[TOP])), + Math::Utils::cross(Math::Vector3f(m_planes[RIGHT]), Math::Vector3f(m_planes[NEAR])), + Math::Utils::cross(Math::Vector3f(m_planes[RIGHT]), Math::Vector3f(m_planes[FAR])), + Math::Utils::cross(Math::Vector3f(m_planes[BOTTOM]), Math::Vector3f(m_planes[TOP])), + Math::Utils::cross(Math::Vector3f(m_planes[BOTTOM]), Math::Vector3f(m_planes[NEAR])), + Math::Utils::cross(Math::Vector3f(m_planes[BOTTOM]), Math::Vector3f(m_planes[FAR])), + Math::Utils::cross(Math::Vector3f(m_planes[TOP]), Math::Vector3f(m_planes[NEAR])), + Math::Utils::cross(Math::Vector3f(m_planes[TOP]), Math::Vector3f(m_planes[FAR])), + Math::Utils::cross(Math::Vector3f(m_planes[NEAR]), Math::Vector3f(m_planes[FAR])) + }; + + m_points[0] = Intersection(crosses); + m_points[1] = Intersection(crosses); + m_points[2] = Intersection(crosses); + m_points[3] = Intersection(crosses); + m_points[4] = Intersection(crosses); + m_points[5] = Intersection(crosses); + m_points[6] = Intersection(crosses); + m_points[7] = Intersection(crosses); + + } + + // http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm + bool IsBoxVisible(const Math::Vector3f& minp, const Math::Vector3f& maxp) const + { // http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm + // check box outside/inside of frustum + for (int i = 0; i < COUNT; i++) + { + if ((Math::Utils::dot(m_planes[i], Math::Vector4f(minp.x, minp.y, minp.z, 1.0f)) < 0.0) && + (Math::Utils::dot(m_planes[i], Math::Vector4f(maxp.x, minp.y, minp.z, 1.0f)) < 0.0) && + (Math::Utils::dot(m_planes[i], Math::Vector4f(minp.x, maxp.y, minp.z, 1.0f)) < 0.0) && + (Math::Utils::dot(m_planes[i], Math::Vector4f(maxp.x, maxp.y, minp.z, 1.0f)) < 0.0) && + (Math::Utils::dot(m_planes[i], Math::Vector4f(minp.x, minp.y, maxp.z, 1.0f)) < 0.0) && + (Math::Utils::dot(m_planes[i], Math::Vector4f(maxp.x, minp.y, maxp.z, 1.0f)) < 0.0) && + (Math::Utils::dot(m_planes[i], Math::Vector4f(minp.x, maxp.y, maxp.z, 1.0f)) < 0.0) && + (Math::Utils::dot(m_planes[i], Math::Vector4f(maxp.x, maxp.y, maxp.z, 1.0f)) < 0.0)) + { + return false; + } + } + + // check frustum outside/inside box + int out; + out = 0; + for (int i = 0; i < 8; i++) out += ((m_points[i].x > maxp.x) ? 1 : 0); + if (out == 8) return false; + out = 0; + for (int i = 0; i < 8; i++) out += ((m_points[i].x < minp.x) ? 1 : 0); + if (out == 8) return false; + out = 0; + for (int i = 0; i < 8; i++) out += ((m_points[i].y > maxp.y) ? 1 : 0); + if (out == 8) return false; + out = 0; + for (int i = 0; i < 8; i++) out += ((m_points[i].y < minp.y) ? 1 : 0); + if (out == 8) return false; + out = 0; + for (int i = 0; i < 8; i++) out += ((m_points[i].z > maxp.z) ? 1 : 0); + if (out == 8) return false; + out = 0; + for (int i = 0; i < 8; i++) out += ((m_points[i].z < minp.z) ? 1 : 0); + if (out == 8) return false; + + return true; + } + + bool IsBoxVisible(const Math::Vector4f& minp, const Math::Vector4f& maxp) const + { + return IsBoxVisible(Math::Vector3f(minp), Math::Vector3f(maxp)); + } + + private: + template + struct ij2k + { + enum + { + k = i * (9 - i) / 2 + j - 1 + }; + }; + + template + Math::Vector3f Intersection(const Math::Vector3f* crosses) const + { + float D = Math::Utils::dot(Math::Vector3f(m_planes[a]), crosses[ij2k::k]); + Math::Vector3f res = Math::Matrix3f(crosses[ij2k::k], -crosses[ij2k::k], crosses[ij2k::k]) * + Math::Vector3f(m_planes[a].w, m_planes[b].w, m_planes[c].w); + return res * (-1.0f / D); + } + + Math::Vector4f m_planes[COUNT]; + Math::Vector3f m_points[8]; + }; +}