feat(core): add camera view-frustum culling planes
This commit is contained in:
1 parent
f80aa78fc5
commit
9f43b35a13
2 files changed
+83
No files matched your search
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Math.h"
|
||||||
|
#include "Physics.h"
|
||||||
|
|
||||||
|
namespace vf {
|
||||||
|
|
||||||
|
struct Plane {
|
||||||
|
float nx = 0.0f, ny = 0.0f, nz = 0.0f, d = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Frustum {
|
||||||
|
public:
|
||||||
|
// Extracts the six clip planes from a view-projection matrix
|
||||||
|
// (Gribb and Hartmann). Planes point inward; a point is inside when its
|
||||||
|
// signed distance to every plane is non-negative.
|
||||||
|
static Frustum fromMatrix(const Mat4& viewProjection);
|
||||||
|
|
||||||
|
bool containsPoint(const Vec3& p) const;
|
||||||
|
bool intersectsAabb(const Aabb& box) const;
|
||||||
|
|
||||||
|
const Plane& plane(int i) const { return planes[i]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Plane planes[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vf
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#include "vf/Frustum.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace vf {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Plane normalized(float a, float b, float c, float d) {
|
||||||
|
float len = std::sqrt(a * a + b * b + c * c);
|
||||||
|
if (len <= 1e-8f) return Plane{a, b, c, d};
|
||||||
|
float inv = 1.0f / len;
|
||||||
|
return Plane{a * inv, b * inv, c * inv, d * inv};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Frustum Frustum::fromMatrix(const Mat4& vp) {
|
||||||
|
auto el = [&](int row, int col) { return vp.at(col, row); };
|
||||||
|
auto row = [&](int r) {
|
||||||
|
return std::array<float, 4>{el(r, 0), el(r, 1), el(r, 2), el(r, 3)};
|
||||||
|
};
|
||||||
|
auto r0 = row(0);
|
||||||
|
auto r1 = row(1);
|
||||||
|
auto r2 = row(2);
|
||||||
|
auto r3 = row(3);
|
||||||
|
|
||||||
|
Frustum f;
|
||||||
|
f.planes[0] = normalized(r3[0] + r0[0], r3[1] + r0[1], r3[2] + r0[2], r3[3] + r0[3]); // left
|
||||||
|
f.planes[1] = normalized(r3[0] - r0[0], r3[1] - r0[1], r3[2] - r0[2], r3[3] - r0[3]); // right
|
||||||
|
f.planes[2] = normalized(r3[0] + r1[0], r3[1] + r1[1], r3[2] + r1[2], r3[3] + r1[3]); // bottom
|
||||||
|
f.planes[3] = normalized(r3[0] - r1[0], r3[1] - r1[1], r3[2] - r1[2], r3[3] - r1[3]); // top
|
||||||
|
f.planes[4] = normalized(r3[0] + r2[0], r3[1] + r2[1], r3[2] + r2[2], r3[3] + r2[3]); // near
|
||||||
|
f.planes[5] = normalized(r3[0] - r2[0], r3[1] - r2[1], r3[2] - r2[2], r3[3] - r2[3]); // far
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Frustum::containsPoint(const Vec3& p) const {
|
||||||
|
for (const Plane& pl : planes)
|
||||||
|
if (pl.nx * p.x + pl.ny * p.y + pl.nz * p.z + pl.d < 0.0f) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Frustum::intersectsAabb(const Aabb& box) const {
|
||||||
|
for (const Plane& pl : planes) {
|
||||||
|
float px = pl.nx >= 0.0f ? box.max.x : box.min.x;
|
||||||
|
float py = pl.ny >= 0.0f ? box.max.y : box.min.y;
|
||||||
|
float pz = pl.nz >= 0.0f ? box.max.z : box.min.z;
|
||||||
|
if (pl.nx * px + pl.ny * py + pl.nz * pz + pl.d < 0.0f) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace vf
|
||||||
Reference in new issue
Block a user