]> git.localhorst.tv Git - blank.git/blobdiff - src/geometry/geometry.cpp
faster chunk culling test
[blank.git] / src / geometry / geometry.cpp
index ff28d2e0602c041abcac485099dae79915ab9951..1e84fbb9068d1749fbe5a3edcc81519aa7718e87 100644 (file)
@@ -4,6 +4,8 @@
 #include "rotation.hpp"
 
 #include <limits>
+#include <ostream>
+#include <glm/gtx/io.hpp>
 #include <glm/gtx/matrix_cross_product.hpp>
 #include <glm/gtx/optimum_pow.hpp>
 #include <glm/gtx/transform.hpp>
@@ -32,13 +34,21 @@ glm::mat3 find_rotation(const glm::vec3 &a, const glm::vec3 &b) noexcept {
                        return glm::mat3(glm::rotate(PI, axis));
                }
        }
-       float mv = length_squared(v);
+       float mv = length2(v);
        float c = dot(a, b);
        float f = (1 - c) / mv;
        glm::mat3 vx(matrixCross3(v));
        return glm::mat3(1.0f) + vx + (pow2(vx) * f);
 }
 
+std::ostream &operator <<(std::ostream &out, const AABB &box) {
+       return out << "AABB(" << box.min << ", " << box.max << ')';
+}
+
+std::ostream &operator <<(std::ostream &out, const Ray &ray) {
+       return out << "Ray(" << ray.orig << ", " << ray.dir << ')';
+}
+
 bool Intersection(
        const Ray &ray,
        const AABB &aabb,
@@ -127,13 +137,22 @@ bool Intersection(
                glm::vec3(b_m * glm::vec4(b_box.max.x, b_box.max.y, b_box.max.z, 1)),
        };
 
-       glm::vec3 axes[6] = {
-               glm::vec3(a_m * glm::vec4(1, 0, 0, 0)),
-               glm::vec3(a_m * glm::vec4(0, 1, 0, 0)),
-               glm::vec3(a_m * glm::vec4(0, 0, 1, 0)),
-               glm::vec3(b_m * glm::vec4(1, 0, 0, 0)),
-               glm::vec3(b_m * glm::vec4(0, 1, 0, 0)),
-               glm::vec3(b_m * glm::vec4(0, 0, 1, 0)),
+       glm::vec3 axes[15] = {
+               glm::vec3(a_m[0]),
+               glm::vec3(a_m[1]),
+               glm::vec3(a_m[2]),
+               glm::vec3(b_m[0]),
+               glm::vec3(b_m[1]),
+               glm::vec3(b_m[2]),
+               normalize(cross(glm::vec3(a_m[0]), glm::vec3(b_m[0]))),
+               normalize(cross(glm::vec3(a_m[0]), glm::vec3(b_m[1]))),
+               normalize(cross(glm::vec3(a_m[0]), glm::vec3(b_m[2]))),
+               normalize(cross(glm::vec3(a_m[1]), glm::vec3(b_m[0]))),
+               normalize(cross(glm::vec3(a_m[1]), glm::vec3(b_m[1]))),
+               normalize(cross(glm::vec3(a_m[1]), glm::vec3(b_m[2]))),
+               normalize(cross(glm::vec3(a_m[2]), glm::vec3(b_m[0]))),
+               normalize(cross(glm::vec3(a_m[2]), glm::vec3(b_m[1]))),
+               normalize(cross(glm::vec3(a_m[2]), glm::vec3(b_m[2]))),
        };
 
        depth = std::numeric_limits<float>::infinity();
@@ -141,6 +160,11 @@ bool Intersection(
 
        int cur_axis = 0;
        for (const glm::vec3 &axis : axes) {
+               if (any(isnan(axis))) {
+                       // can result from the cross products if A and B have parallel axes
+                       ++cur_axis;
+                       continue;
+               }
                float a_min = std::numeric_limits<float>::infinity();
                float a_max = -std::numeric_limits<float>::infinity();
                for (const glm::vec3 &corner : a_corners) {
@@ -173,6 +197,21 @@ bool Intersection(
 }
 
 
+std::ostream &operator <<(std::ostream &out, const Plane &plane) {
+       return out << "Plane(" << plane.normal << ", " << plane.dist << ')';
+}
+
+std::ostream &operator <<(std::ostream &out, const Frustum &frustum) {
+       return out << "Frustum(" << std::endl
+               << "\tleft:   " << frustum.plane[0] << std::endl
+               << "\tright:  " << frustum.plane[1] << std::endl
+               << "\tbottom: " << frustum.plane[2] << std::endl
+               << "\ttop:    " << frustum.plane[3] << std::endl
+               << "\tnear:   " << frustum.plane[4] << std::endl
+               << "\tfar:    " << frustum.plane[5] << std::endl
+               << ')';
+}
+
 bool CullTest(const AABB &box, const glm::mat4 &MVP) noexcept {
        // transform corners into clip space
        glm::vec4 corners[8] = {
@@ -185,21 +224,19 @@ bool CullTest(const AABB &box, const glm::mat4 &MVP) noexcept {
                { box.max.x, box.max.y, box.min.z, 1.0f },
                { box.max.x, box.max.y, box.max.z, 1.0f },
        };
+
+       // check how many corners lie outside
+       int hits[6] = { 0, 0, 0, 0, 0, 0 };
        for (glm::vec4 &corner : corners) {
                corner = MVP * corner;
+               // replacing this with *= 1/w is effectively more expensive
                corner /= corner.w;
-       }
-
-       int hits[6] = { 0, 0, 0, 0, 0, 0 };
-
-       // check how many corners lie outside
-       for (const glm::vec4 &corner : corners) {
-               if (corner.x >  1.0f) ++hits[0];
-               if (corner.x < -1.0f) ++hits[1];
-               if (corner.y >  1.0f) ++hits[2];
-               if (corner.y < -1.0f) ++hits[3];
-               if (corner.z >  1.0f) ++hits[4];
-               if (corner.z < -1.0f) ++hits[5];
+               hits[0] += (corner.x >  1.0f);
+               hits[1] += (corner.x < -1.0f);
+               hits[2] += (corner.y >  1.0f);
+               hits[3] += (corner.y < -1.0f);
+               hits[4] += (corner.z >  1.0f);
+               hits[5] += (corner.z < -1.0f);
        }
 
        // if all corners are outside any given clip plane, the test is true
@@ -211,4 +248,18 @@ bool CullTest(const AABB &box, const glm::mat4 &MVP) noexcept {
        return false;
 }
 
+bool CullTest(const AABB &box, const Frustum &frustum) noexcept {
+       for (const Plane &plane : frustum.plane) {
+               const glm::vec3 np(
+                       ((plane.normal.x > 0.0f) ? box.max.x : box.min.x),
+                       ((plane.normal.y > 0.0f) ? box.max.y : box.min.y),
+                       ((plane.normal.z > 0.0f) ? box.max.z : box.min.z)
+               );
+               const float dp = dot(plane.normal, np);
+               // cull if nearest point is on the "outside" side of the plane
+               if (dp < -plane.dist) return true;
+       }
+       return false;
+}
+
 }