Skip to content

Commit

Permalink
Add tests for Frustum and fix bugs associated with it
Browse files Browse the repository at this point in the history
  • Loading branch information
jameshball committed Feb 11, 2024
1 parent 2c7d639 commit 8ff283a
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 23 deletions.
111 changes: 94 additions & 17 deletions Source/TestMain.cpp
Original file line number Diff line number Diff line change
@@ -1,39 +1,116 @@
#include <JuceHeader.h>
#include "shape/Point.h"
#include "obj/Frustum.h"

class MyTest : public juce::UnitTest {
class FrustumTest : public juce::UnitTest {
public:
MyTest() : juce::UnitTest("Foobar testing") {}
FrustumTest() : juce::UnitTest("Frustum Culling") {}

void runTest() override {
beginTest("Part 1");
double focalLength = 1;
double ratio = 1;
double nearDistance = 0.1;
double farDistance = 100;

expect(true);
Frustum frustum(focalLength, ratio, nearDistance, farDistance);
frustum.setCameraOrigin(Point(0, 0, -focalLength));

beginTest("Part 2");
beginTest("Focal Plane Frustum In-Bounds");

expect(true);
}
};
// Focal plane is at z = 0
Point points[][2] = {
{Point(0, 0, 0), Point(0, 0, 0)},
{Point(1, 1, 0), Point(1, 1, 0)},
{Point(-1, -1, 0), Point(-1, -1, 0)},
{Point(1, -1, 0), Point(1, -1, 0)},
{Point(-1, 1, 0), Point(-1, 1, 0)},
{Point(0.5, 0.5, 0), Point(0.5, 0.5, 0)},
};

class MyTest2 : public juce::UnitTest {
public:
MyTest2() : juce::UnitTest("Foobar testing 2") {}
testFrustumClippedEqualsExpected(points, frustum, 6);

void runTest() override {
beginTest("Part A");
beginTest("Focal Plane Frustum Out-Of-Bounds");

// Focal plane is at z = 0
Point points2[][2] = {
{Point(1.1, 1.1, 0), Point(1, 1, 0)},
{Point(-1.1, -1.1, 0), Point(-1, -1, 0)},
{Point(1.1, -1.1, 0), Point(1, -1, 0)},
{Point(-1.1, 1.1, 0), Point(-1, 1, 0)},
{Point(1.1, 0.5, 0), Point(1, 0.5, 0)},
{Point(-1.1, 0.5, 0), Point(-1, 0.5, 0)},
{Point(0.5, -1.1, 0), Point(0.5, -1, 0)},
{Point(0.5, 1.1, 0), Point(0.5, 1, 0)},
{Point(10, 10, 0), Point(1, 1, 0)},
{Point(-10, -10, 0), Point(-1, -1, 0)},
{Point(10, -10, 0), Point(1, -1, 0)},
{Point(-10, 10, 0), Point(-1, 1, 0)},
};

testFrustumClippedEqualsExpected(points2, frustum, 12);

beginTest("Behind Camera Out-Of-Bounds");

double minZWorldCoords = -focalLength + nearDistance;

Point points3[][2] = {
{Point(0, 0, -focalLength), Point(0, 0, minZWorldCoords)},
{Point(0, 0, -100), Point(0, 0, minZWorldCoords)},
{Point(0.5, 0.5, -focalLength), Point(0.1, 0.1, minZWorldCoords)},
{Point(10, -10, -focalLength), Point(0.1, -0.1, minZWorldCoords)},
{Point(-0.5, 0.5, -100), Point(-0.1, 0.1, minZWorldCoords)},
{Point(-10, 10, -100), Point(-0.1, 0.1, minZWorldCoords)},
};

expect(true);
testFrustumClippedEqualsExpected(points3, frustum, 6);

beginTest("Part B");
beginTest("3D Point Out-Of-Bounds");

Point points4[] = {
Point(1, 1, -0.1),
Point(-1, -1, -0.1),
Point(1, -1, -0.1),
Point(-1, 1, -0.1),
Point(0.5, 0.5, minZWorldCoords),
};

testFrustumClipOccurs(points4, frustum, 5);
}

Point project(Point& p, double focalLength) {
return Point(
p.x * focalLength / p.z,
p.y * focalLength / p.z,
0
);
}

juce::String errorMessage(Point& actual, Point& expected) {
return "Expected: " + expected.toString() + " Got: " + actual.toString();
}

void testFrustumClippedEqualsExpected(Point points[][2], Frustum& frustum, int length) {
for (int i = 0; i < length; i++) {
Point p = points[i][0];
frustum.clipToFrustum(p);
expect(p == points[i][1], errorMessage(p, points[i][1]));
}
}

expect(true);
void testFrustumClipOccurs(Point points[], Frustum& frustum, int length) {
for (int i = 0; i < length; i++) {
Point p = points[i];
frustum.clipToFrustum(p);
expect(p != points[i], errorMessage(p, points[i]));
}
}
};

static MyTest2 test2;
static FrustumTest frustumTest;

int main(int argc, char* argv[]) {
juce::UnitTestRunner runner;
runner.setAssertOnFailure(false);

runner.runAllTests();

Expand Down
5 changes: 5 additions & 0 deletions Source/audio/PerspectiveEffect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,13 @@ Point PerspectiveEffect::apply(int index, Point input, const std::vector<double>
Point p = Point(x3, y3, z3);

Frustum frustum = Frustum(focalLength, 1.0, 0.1, 1000);
Point origin = Point(0, 0, -focalLength - depth);
frustum.setCameraOrigin(origin);
frustum.clipToFrustum(p);

// need to convert point from world space to camera space before projecting
p = p - origin;

return Point(
(1 - effectScale) * input.x + effectScale * (p.x * focalLength / p.z),
(1 - effectScale) * input.y + effectScale * (p.y * focalLength / p.z),
Expand Down
7 changes: 3 additions & 4 deletions Source/obj/Frustum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ void Frustum::setCameraInternals(float focalLength, float ratio, float nearDista
this->farDistance = farDistance;

// compute width and height of the near section
float fov = 2 * std::atan(1 / (focalLength * 2));
origin = Point(0, 0, -focalLength);
float fov = 2 * std::atan(1 / focalLength);
tang = (float) std::tan(fov * 0.5);
height = nearDistance * tang;
width = height * ratio;
Expand All @@ -29,7 +28,7 @@ void Frustum::clipToFrustum(Point &p) {

// compute and test the Y coordinate
pcy = v.innerProduct(Y);
aux = pcz * tang;
aux = std::abs(pcz * tang);
pcy = juce::jlimit(-aux, aux, pcy);

// compute and test the X coordinate
Expand All @@ -42,5 +41,5 @@ void Frustum::clipToFrustum(Point &p) {
Point y = Y * pcy;
Point z = Z * pcz;

p = x + y + z;
p = x + y + z + origin;
}
5 changes: 4 additions & 1 deletion Source/obj/Frustum.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class Frustum {
public:
float ratio, nearDistance, farDistance, width, height, tang;

Point origin = Point(0, 0, 0);
Point origin = Point(0, 0, -1);

Point X = Point(1, 0, 0);
Point Y = Point(0, 1, 0);
Expand All @@ -20,6 +20,9 @@ class Frustum {
}
~Frustum() {};

void setCameraOrigin(Point& p) {
origin = p;
}
void setCameraInternals(float fov, float ratio, float nearD, float farD);
void clipToFrustum(Point &p);
};
14 changes: 14 additions & 0 deletions Source/shape/Point.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "Point.h"

double Point::EPSILON = 0.0001;

Point::Point() : x(0), y(0), z(0) {}

Point::Point(double val) : x(val), y(val), z(0) {}
Expand Down Expand Up @@ -78,6 +80,14 @@ Point& Point::operator=(const Point& other) {
return *this;
}

bool Point::operator==(const Point& other) {
return std::abs(x - other.x) < EPSILON && std::abs(y - other.y) < EPSILON && std::abs(z - other.z) < EPSILON;
}

bool Point::operator!=(const Point& other) {
return !(*this == other);
}

Point Point::operator+(const Point& other) {
return Point(x + other.x, y + other.y, z + other.z);
}
Expand All @@ -97,3 +107,7 @@ Point Point::operator*(const Point& other) {
Point Point::operator*(double scalar) {
return Point(x * scalar, y * scalar, z * scalar);
}

std::string Point::toString() {
return std::string("(" + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z) + ")");
}
6 changes: 5 additions & 1 deletion Source/shape/Point.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ class Point : public Shape {
void normalize();
double innerProduct(Point& other);

// copy assignment operator
std::string toString();

Point& operator=(const Point& other);
bool operator==(const Point& other);
bool operator!=(const Point& other);
Point operator+(const Point& other);
Point operator-(const Point& other);
Point operator-();
Expand All @@ -33,4 +36,5 @@ class Point : public Shape {

double x, y, z;

static double EPSILON;
};

0 comments on commit 8ff283a

Please sign in to comment.