kopia lustrzana https://github.com/jameshball/osci-render
134 wiersze
4.3 KiB
C++
134 wiersze
4.3 KiB
C++
#include <JuceHeader.h>
|
|
#include "obj/Camera.h"
|
|
#include "mathter/Common/Approx.hpp"
|
|
|
|
class FrustumTest : public juce::UnitTest {
|
|
public:
|
|
FrustumTest() : juce::UnitTest("Frustum Culling") {}
|
|
|
|
void runTest() override {
|
|
double focalLength = 1;
|
|
|
|
Camera camera;
|
|
camera.setFocalLength(focalLength);
|
|
Vec3 position = Vec3(0, 0, -focalLength);
|
|
camera.setPosition(position);
|
|
Frustum frustum = camera.getFrustum();
|
|
|
|
beginTest("Focal Plane Frustum In-Bounds");
|
|
|
|
// Focal plane is at z = 0
|
|
Vec3 vecs[] = {
|
|
Vec3(0, 0, 0), Vec3(0, 0, 0),
|
|
Vec3(1, 1, 0), Vec3(1, 1, 0),
|
|
Vec3(-1, -1, 0), Vec3(-1, -1, 0),
|
|
Vec3(1, -1, 0), Vec3(1, -1, 0),
|
|
Vec3(-1, 1, 0), Vec3(-1, 1, 0),
|
|
Vec3(0.5, 0.5, 0), Vec3(0.5, 0.5, 0),
|
|
};
|
|
|
|
testFrustumClippedEqualsExpected(vecs, camera, 6);
|
|
|
|
beginTest("Focal Plane Frustum Out-Of-Bounds");
|
|
|
|
// Focal plane is at z = 0
|
|
Vec3 vecs2[] = {
|
|
Vec3(1.1, 1.1, 0), Vec3(1, 1, 0),
|
|
Vec3(-1.1, -1.1, 0), Vec3(-1, -1, 0),
|
|
Vec3(1.1, -1.1, 0), Vec3(1, -1, 0),
|
|
Vec3(-1.1, 1.1, 0), Vec3(-1, 1, 0),
|
|
Vec3(1.1, 0.5, 0), Vec3(1, 0.5, 0),
|
|
Vec3(-1.1, 0.5, 0), Vec3(-1, 0.5, 0),
|
|
Vec3(0.5, -1.1, 0), Vec3(0.5, -1, 0),
|
|
Vec3(0.5, 1.1, 0), Vec3(0.5, 1, 0),
|
|
Vec3(10, 10, 0), Vec3(1, 1, 0),
|
|
Vec3(-10, -10, 0), Vec3(-1, -1, 0),
|
|
Vec3(10, -10, 0), Vec3(1, -1, 0),
|
|
Vec3(-10, 10, 0), Vec3(-1, 1, 0),
|
|
};
|
|
|
|
testFrustumClippedEqualsExpected(vecs2, camera, 12);
|
|
|
|
beginTest("Behind Camera Out-Of-Bounds");
|
|
|
|
double minZWorldCoords = -focalLength + camera.getFrustum().nearDistance;
|
|
|
|
Vec3 vecs3[] = {
|
|
Vec3(0, 0, -focalLength), Vec3(0, 0, minZWorldCoords),
|
|
Vec3(0, 0, -100), Vec3(0, 0, minZWorldCoords),
|
|
Vec3(0.5, 0.5, -focalLength), Vec3(0.1, 0.1, minZWorldCoords),
|
|
Vec3(10, -10, -focalLength), Vec3(0.1, -0.1, minZWorldCoords),
|
|
Vec3(-0.5, 0.5, -100), Vec3(-0.1, 0.1, minZWorldCoords),
|
|
Vec3(-10, 10, -100), Vec3(-0.1, 0.1, minZWorldCoords),
|
|
};
|
|
|
|
testFrustumClippedEqualsExpected(vecs3, camera, 6);
|
|
|
|
beginTest("3D Point Out-Of-Bounds");
|
|
|
|
Vec3 vecs4[] = {
|
|
Vec3(1, 1, -0.1),
|
|
Vec3(-1, -1, -0.1),
|
|
Vec3(1, -1, -0.1),
|
|
Vec3(-1, 1, -0.1),
|
|
Vec3(0.5, 0.5, minZWorldCoords),
|
|
};
|
|
|
|
testFrustumClipOccurs(vecs4, camera, 5);
|
|
}
|
|
|
|
Vec3 project(Vec3& p, double focalLength) {
|
|
return Vec3(
|
|
p.x * focalLength / p.z,
|
|
p.y * focalLength / p.z,
|
|
0
|
|
);
|
|
}
|
|
|
|
juce::String vec3ToString(Vec3& p) {
|
|
return "(" + juce::String(p.x) + ", " + juce::String(p.y) + ", " + juce::String(p.z) + ")";
|
|
}
|
|
|
|
juce::String errorMessage(Vec3& actual, Vec3& expected) {
|
|
return "Expected: " + vec3ToString(expected) + ", Actual: " + vec3ToString(actual);
|
|
}
|
|
|
|
void testFrustumClippedEqualsExpected(Vec3 vecs[], Camera& camera, int length) {
|
|
for (int i = 0; i < length; i++) {
|
|
Vec3 p = vecs[2 * i];
|
|
p = camera.toCameraSpace(p);
|
|
camera.getFrustum().clipToFrustum(p);
|
|
p = camera.toWorldSpace(p);
|
|
expect(mathter::AlmostEqual(p, vecs[2 * i + 1]), errorMessage(p, vecs[2 * i + 1]));
|
|
}
|
|
}
|
|
|
|
void testFrustumClipOccurs(Vec3 vecs[], Camera& camera, int length) {
|
|
for (int i = 0; i < length; i++) {
|
|
Vec3 p = vecs[i];
|
|
p = camera.toCameraSpace(p);
|
|
camera.getFrustum().clipToFrustum(p);
|
|
p = camera.toWorldSpace(p);
|
|
expect(!mathter::AlmostEqual(p, vecs[i]), errorMessage(p, vecs[i]));
|
|
}
|
|
}
|
|
};
|
|
|
|
static FrustumTest frustumTest;
|
|
|
|
int main(int argc, char* argv[]) {
|
|
juce::UnitTestRunner runner;
|
|
runner.setAssertOnFailure(false);
|
|
|
|
runner.runAllTests();
|
|
|
|
for (int i = 0; i < runner.getNumResults(); ++i) {
|
|
const juce::UnitTestRunner::TestResult* result = runner.getResult(i);
|
|
if (result->failures > 0) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|