/* * 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" #include "Range.hpp" #ifdef NEAR #undef NEAR #endif #ifdef FAR #undef FAR #endif namespace OpenVulkano::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 [[nodiscard]] 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; } [[nodiscard]] bool IsBoxVisible(const Math::Vector4f& minp, const Math::Vector4f& maxp) const { return IsBoxVisible(Math::Vector3f(minp), Math::Vector3f(maxp)); } [[nodiscard]] bool IsBoxVisible(const Range& range) const { return IsBoxVisible(range.min, range.max); } 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]; }; }