Explorar el Código

Frustum and tests, refactor plane tests

Kajetan Johannes Hammerle hace 2 semanas
padre
commit
f96bc947c4
Se han modificado 8 ficheros con 230 adiciones y 18 borrados
  1. 3 3
      CMakeLists.txt
  2. 28 0
      include/core/Frustum.h
  3. 1 1
      include/core/Plane.h
  4. 113 0
      src/Frustum.c
  5. 1 1
      src/Plane.c
  6. 1 1
      test/Main.c
  7. 74 0
      test/modules/FrustumTests.c
  8. 9 12
      test/modules/PlaneTests.c

+ 3 - 3
CMakeLists.txt

@@ -6,6 +6,7 @@ set(CMAKE_C_STANDARD 23)
 set(SRC
     "src/Box.c"
     "src/Buffer.c"
+    "src/Frustum.c"
     "src/Logger.c"
     "src/Matrix.c"
     "src/Plane.c"
@@ -16,7 +17,6 @@ set(SRC
     "src/Vector.c"
     "src/View.c"
     #"src/BitArray.cpp"
-    #"src/Frustum.cpp"
 )
 
 set(SRC_TESTS
@@ -24,6 +24,7 @@ set(SRC_TESTS
     "test/Test.c"
     "test/modules/BoxTests.c"
     "test/modules/BufferTests.c"
+    "test/modules/FrustumTests.c"
     "test/modules/MatrixTests.c"
     "test/modules/PlaneTests.c"
     "test/modules/QuaternionTests.c"
@@ -34,7 +35,6 @@ set(SRC_TESTS
     "test/modules/ViewTests.c"
     #"test/modules/BitArrayTests.cpp"
     #"test/modules/ComponentsTests.cpp"
-    #"test/modules/FrustumTests.cpp"
     #"test/modules/HashMapTests.cpp"
     #"test/modules/LinkedListTests.cpp"
     #"test/modules/ListTests.cpp"
@@ -99,6 +99,7 @@ target_sources(core PUBLIC
         ./include/core/Box.h
         ./include/core/Buffer.h
         ./include/core/Check.h
+        ./include/core/Frustum.h
         ./include/core/Logger.h
         ./include/core/Matrix.h
         ./include/core/Plane.h
@@ -110,7 +111,6 @@ target_sources(core PUBLIC
         ./include/core/View.h
 #        ./include/core/BitArray.hpp
 #        ./include/core/Components.hpp
-#        ./include/core/Frustum.hpp
 #        ./include/core/HashMap.hpp
 #        ./include/core/LinkedList.hpp
 #        ./include/core/List.hpp

+ 28 - 0
include/core/Frustum.h

@@ -0,0 +1,28 @@
+#ifndef CORE_FRUSTUM_H
+#define CORE_FRUSTUM_H
+
+#include "core/Matrix.h"
+#include "core/Plane.h"
+
+typedef struct {
+    CoreMatrix projection;
+    CorePlane planes[6];
+    float tan;
+    float nearClip;
+    float farClip;
+} CoreFrustum;
+
+CoreFrustum* coreInitFrustum(CoreFrustum* f, float fieldOfView, float nearClip,
+                             float farClip);
+const CoreMatrix* coreUpdateProjection(CoreFrustum* f,
+                                       const CoreIntVector2* size);
+void coreUpdateFrustumPlanes(CoreFrustum* f, const CoreVector3* pos,
+                             const CoreVector3* right, const CoreVector3* up,
+                             const CoreVector3* front,
+                             const CoreIntVector2* size);
+bool coreIsInsideFrustum(const CoreFrustum* f, const CoreVector3* pos);
+bool coreIsInsideFrustumRadius(const CoreFrustum* f, const CoreVector3* pos,
+                               float radius);
+size_t coreToStringFrustum(const CoreFrustum* f, char* buffer, size_t n);
+
+#endif

+ 1 - 1
include/core/Plane.h

@@ -11,7 +11,7 @@ typedef struct {
 #define CORE_PLANE ((CorePlane){0})
 CorePlane* coreInitPlane(CorePlane* p, const CoreVector3* a,
                          const CoreVector3* b, const CoreVector3* c);
-float coreGetSignedDistance(CorePlane* p, const CoreVector3* v);
+float coreSignedDistance(const CorePlane* p, const CoreVector3* v);
 size_t coreToStringPlane(const CorePlane* p, char* buffer, size_t n);
 
 #endif

+ 113 - 0
src/Frustum.c

@@ -0,0 +1,113 @@
+#include "core/Frustum.h"
+
+#include <math.h>
+#include <stdio.h>
+
+#include "core/Utility.h"
+
+#define CV30 (&(CoreVector3){0})
+#define CV4(a, b, c, d) ((CoreVector4){{a, b, c, d}})
+
+CoreFrustum* coreInitFrustum(CoreFrustum* f, float fieldOfView, float nearClip,
+                             float farClip) {
+    for(size_t i = 0; i < CORE_ARRAY_LENGTH(f->planes); i++) {
+        f->planes[i] = (CorePlane){0};
+    }
+    f->tan = tanf(coreDegreeToRadian(fieldOfView) * 0.5f);
+    f->nearClip = nearClip;
+    f->farClip = farClip;
+
+    float diff = 1.0f / (nearClip - farClip);
+    f->projection.data[0] = CV4(0.0f, 0.0f, 0.0f, 0.0f);
+    f->projection.data[1] = CV4(0.0f, 1.0f / f->tan, 0.0f, 0.0f);
+    f->projection.data[2] = CV4(0.0f, 0.0f, (nearClip + farClip) * diff,
+                                (2.0f * nearClip * farClip) * diff);
+    f->projection.data[3] = CV4(0.0f, 0.0f, -1.0f, 0.0f);
+    return f;
+}
+
+const CoreMatrix* coreUpdateProjection(CoreFrustum* f,
+                                       const CoreIntVector2* size) {
+    f->projection.data[0] =
+        CV4((float)size->data[1] / (f->tan * (float)size->data[0]), 0.0f, 0.0f,
+            0.0f);
+    return &f->projection;
+}
+
+void coreUpdateFrustumPlanes(CoreFrustum* f, const CoreVector3* pos,
+                             const CoreVector3* right, const CoreVector3* up,
+                             const CoreVector3* front,
+                             const CoreIntVector2* size) {
+    float aspect = (float)size->data[0] / (float)size->data[1];
+
+    float hNearHeight = f->tan * f->nearClip;
+    float hNearWidth = hNearHeight * aspect;
+
+    float hFarHeight = f->tan * f->farClip;
+    float hFarWidth = hFarHeight * aspect;
+
+    CoreVector3 fCenter;
+    coreAddV3(&fCenter, pos, coreMulV3F(CV30, front, f->farClip));
+    CoreVector3 upFar;
+    coreMulV3F(&upFar, up, hFarHeight);
+    CoreVector3 rightFar;
+    coreMulV3F(&rightFar, right, hFarWidth);
+
+    CoreVector3 fTopLeft;
+    coreAddV3(&fTopLeft, &fCenter, coreSubV3(CV30, &upFar, &rightFar));
+    CoreVector3 fTopRight;
+    coreAddV3(&fTopRight, &fCenter, coreAddV3(CV30, &upFar, &rightFar));
+    CoreVector3 fBottomRight;
+    coreSubV3(&fBottomRight, &fCenter, coreSubV3(CV30, &upFar, &rightFar));
+
+    CoreVector3 nCenter;
+    coreAddV3(&nCenter, pos, coreMulV3F(CV30, front, f->nearClip));
+    CoreVector3 upNear;
+    coreMulV3F(&upNear, up, hNearHeight);
+    CoreVector3 rightNear;
+    coreMulV3F(&rightNear, right, hNearWidth);
+
+    CoreVector3 nTopLeft;
+    coreAddV3(&nTopLeft, &nCenter, coreSubV3(CV30, &upNear, &rightNear));
+    CoreVector3 nBottomLeft;
+    coreSubV3(&nBottomLeft, &nCenter, coreAddV3(CV30, &upNear, &rightNear));
+    CoreVector3 nBottomRight;
+    coreSubV3(&nBottomRight, &nCenter, coreSubV3(CV30, &upNear, &rightNear));
+
+    coreInitPlane(f->planes + 0, &nBottomRight, &nTopLeft,
+                  &nBottomLeft); // n plane
+    coreInitPlane(f->planes + 1, &fTopRight, &fBottomRight,
+                  &fTopLeft); // f plane
+    coreInitPlane(f->planes + 2, &nBottomRight, &nBottomLeft,
+                  &fBottomRight); // bottom plane
+    coreInitPlane(f->planes + 3, &fTopLeft, &nTopLeft, &fTopRight); // top plane
+    coreInitPlane(f->planes + 4, &nBottomLeft, &nTopLeft,
+                  &fTopLeft); // left plane
+    coreInitPlane(f->planes + 5, &fBottomRight, &fTopRight,
+                  &nBottomRight); // right plane
+}
+
+bool coreIsInsideFrustum(const CoreFrustum* f, const CoreVector3* pos) {
+    for(size_t i = 0; i < CORE_ARRAY_LENGTH(f->planes); i++) {
+        if(coreSignedDistance(f->planes + i, pos) < 0.0f) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool coreIsInsideFrustumRadius(const CoreFrustum* f, const CoreVector3* pos,
+                               float radius) {
+    for(size_t i = 0; i < CORE_ARRAY_LENGTH(f->planes); i++) {
+        if(coreSignedDistance(f->planes + i, pos) < -radius) {
+            return false;
+        }
+    }
+    return true;
+}
+
+size_t coreToStringFrustum(const CoreFrustum* f, char* buffer, size_t n) {
+    int w = snprintf(buffer, n, "(tan = %.3f, nearClip = %.3f, farClip = %.3f)",
+                     (double)f->tan, (double)f->nearClip, (double)f->farClip);
+    return w < 0 ? 0 : (size_t)w;
+}

+ 1 - 1
src/Plane.c

@@ -12,7 +12,7 @@ CorePlane* coreInitPlane(CorePlane* p, const CoreVector3* a,
     return p;
 }
 
-float coreGetSignedDistance(CorePlane* p, const CoreVector3* v) {
+float coreSignedDistance(const CorePlane* p, const CoreVector3* v) {
     return coreDotV3(&p->abc, v) + p->d;
 }
 

+ 1 - 1
test/Main.c

@@ -33,7 +33,6 @@ int main(int argAmount, const char** args) {
 
     // coreTestBitArray();
     // coreTestComponents();
-    // coreTestFrustum();
     // coreTestHashMap(light);
     // coreTestLinkedList(light);
     // coreTestList(light);
@@ -42,6 +41,7 @@ int main(int argAmount, const char** args) {
     // coreTestStack(light);
     coreTestBox();
     coreTestBuffer(light);
+    coreTestFrustum();
     coreTestMatrix();
     coreTestPlane();
     coreTestQuaternion();

+ 74 - 0
test/modules/FrustumTests.c

@@ -0,0 +1,74 @@
+#include "../Tests.h"
+#include "core/Frustum.h"
+
+#define CV3(a, b, c) (&(CoreVector3){{a, b, c}})
+
+static void testToString() {
+    CoreFrustum f = {0};
+    coreInitFrustum(&f, 60.0f, 0.1f, 1000.0f);
+    char buffer[128];
+    coreToStringFrustum(&f, buffer, sizeof(buffer));
+    CORE_TEST_STRING("(tan = 0.577, nearClip = 0.100, farClip = 1000.000)",
+                     buffer);
+}
+
+static void testPointIsInside() {
+    CoreIntVector2 size = {{200, 100}};
+    CoreFrustum f = {0};
+    coreInitFrustum(&f, 60.0f, 0.1f, 1000.0f);
+    coreUpdateFrustumPlanes(&f, CV3(0, 0, 0), CV3(1, 0, 0), CV3(0, 1, 0),
+                            CV3(0, 0, 1), &size);
+
+    CORE_TEST_TRUE(coreIsInsideFrustum(&f, CV3(0, 0, 5)));
+    CORE_TEST_FALSE(coreIsInsideFrustum(&f, CV3(0, 0, 1004)));
+    CORE_TEST_FALSE(coreIsInsideFrustum(&f, CV3(0, 0, -5)));
+    CORE_TEST_FALSE(coreIsInsideFrustum(&f, CV3(0, 50, 5)));
+    CORE_TEST_FALSE(coreIsInsideFrustum(&f, CV3(0, -50, 5)));
+    CORE_TEST_FALSE(coreIsInsideFrustum(&f, CV3(50, 0, 5)));
+    CORE_TEST_FALSE(coreIsInsideFrustum(&f, CV3(-50, 0, 5)));
+}
+
+static void testSphereIsInside() {
+    CoreIntVector2 size = {{200, 100}};
+    CoreFrustum f = {0};
+    coreInitFrustum(&f, 60.0f, 0.1f, 1000.0f);
+    coreUpdateFrustumPlanes(&f, CV3(0, 0, 0), CV3(1, 0, 0), CV3(0, 1, 0),
+                            CV3(0, 0, 1), &size);
+
+    CORE_TEST_TRUE(coreIsInsideFrustumRadius(&f, CV3(0, 0, 5), 3));
+    CORE_TEST_FALSE(coreIsInsideFrustumRadius(&f, CV3(0, 0, 1004), 3));
+    CORE_TEST_FALSE(coreIsInsideFrustumRadius(&f, CV3(0, 0, -5), 3));
+    CORE_TEST_FALSE(coreIsInsideFrustumRadius(&f, CV3(0, 50, 5), 3));
+    CORE_TEST_FALSE(coreIsInsideFrustumRadius(&f, CV3(0, -50, 5), 3));
+    CORE_TEST_FALSE(coreIsInsideFrustumRadius(&f, CV3(50, 0, 5), 3));
+    CORE_TEST_FALSE(coreIsInsideFrustumRadius(&f, CV3(-50, 0, 5), 3));
+
+    CORE_TEST_TRUE(coreIsInsideFrustumRadius(&f, CV3(0, 0, 5), 3));
+    CORE_TEST_TRUE(coreIsInsideFrustumRadius(&f, CV3(0, 0, 1004), 50));
+    CORE_TEST_TRUE(coreIsInsideFrustumRadius(&f, CV3(0, 0, -5), 50));
+    CORE_TEST_TRUE(coreIsInsideFrustumRadius(&f, CV3(0, 50, 5), 50));
+    CORE_TEST_TRUE(coreIsInsideFrustumRadius(&f, CV3(0, -50, 5), 50));
+    CORE_TEST_TRUE(coreIsInsideFrustumRadius(&f, CV3(50, 0, 5), 50));
+    CORE_TEST_TRUE(coreIsInsideFrustumRadius(&f, CV3(-50, 0, 5), 50));
+}
+
+static void testUpdateProjection() {
+    CoreFrustum f = {0};
+    coreInitFrustum(&f, 60.0f, 0.1f, 1000.0f);
+    const CoreMatrix* m =
+        coreUpdateProjection(&f, &(CoreIntVector2){{400, 300}});
+    char buffer[128];
+    coreToStringMatrix(m, buffer, sizeof(buffer));
+    CORE_TEST_STRING("[[1.299, 0.000, 0.000, 0.000], "
+                     "[0.000, 1.732, 0.000, 0.000], "
+                     "[0.000, 0.000, -1.000, -0.200], "
+                     "[0.000, 0.000, -1.000, 0.000]]",
+                     buffer);
+}
+
+void coreTestFrustum() {
+    testToString();
+    testPointIsInside();
+    testSphereIsInside();
+    testUpdateProjection();
+}

+ 9 - 12
test/modules/PlaneTests.c

@@ -14,26 +14,23 @@ static void testToString1() {
 
 static void testToString2() {
     CorePlane p = CORE_PLANE;
-    coreInitPlane(&p, CV3(3.0f, 6.0f, 8.0f), CV3(7.0f, 6.0f, 2.0f),
-                  CV3(4.0f, 4.0f, 4.0f));
+    coreInitPlane(&p, CV3(3, 6, 8), CV3(7, 6, 2), CV3(4, 4, 4));
     char buffer[128];
     coreToStringPlane(&p, buffer, sizeof(buffer));
     CORE_TEST_STRING("(-0.684 x + 0.570 y + -0.456 z + 2.279)", buffer);
 }
 
 static void testSignedDistance() {
-    CoreVector3 a = {{3.0f, 6.0f, 8.0f}};
-    CoreVector3 b = {{7.0f, 6.0f, 2.0f}};
-    CoreVector3 c = {{4.0f, 4.0f, 4.0f}};
+    CoreVector3 a = {{3, 6, 8}};
+    CoreVector3 b = {{7, 6, 2}};
+    CoreVector3 c = {{4, 4, 4}};
     CorePlane p = CORE_PLANE;
     coreInitPlane(&p, &a, &b, &c);
-    CORE_TEST_FLOAT(0.0f, coreGetSignedDistance(&p, &a), eps);
-    CORE_TEST_FLOAT(0.0f, coreGetSignedDistance(&p, &b), eps);
-    CORE_TEST_FLOAT(0.0f, coreGetSignedDistance(&p, &c), eps);
-    CORE_TEST_FLOAT(-1.13960576f,
-                    coreGetSignedDistance(&p, CV3(5.0f, 8.0f, 10.0f)), eps);
-    CORE_TEST_FLOAT(0.911684612f,
-                    coreGetSignedDistance(&p, CV3(3.0f, 2.0f, 1.0f)), eps);
+    CORE_TEST_FLOAT(0.0f, coreSignedDistance(&p, &a), eps);
+    CORE_TEST_FLOAT(0.0f, coreSignedDistance(&p, &b), eps);
+    CORE_TEST_FLOAT(0.0f, coreSignedDistance(&p, &c), eps);
+    CORE_TEST_FLOAT(-1.13960576f, coreSignedDistance(&p, CV3(5, 8, 10)), eps);
+    CORE_TEST_FLOAT(0.911684612f, coreSignedDistance(&p, CV3(3, 2, 1)), eps);
 }
 
 void coreTestPlane() {