2021-03-16 23:42:29 +01:00
|
|
|
/* Copyright (C) 2021 Wildfire Games.
|
2019-05-29 22:12:41 +02:00
|
|
|
* This file is part of 0 A.D.
|
|
|
|
*
|
|
|
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* 0 A.D. is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "lib/self_test.h"
|
|
|
|
|
|
|
|
#include "graphics/Camera.h"
|
|
|
|
#include "maths/MathUtil.h"
|
2021-05-15 15:33:36 +02:00
|
|
|
#include "maths/Vector2D.h"
|
2019-05-29 22:12:41 +02:00
|
|
|
#include "maths/Vector3D.h"
|
2021-05-15 15:33:36 +02:00
|
|
|
#include "maths/Vector4D.h"
|
2019-05-29 22:12:41 +02:00
|
|
|
|
2019-05-30 19:27:55 +02:00
|
|
|
#include <cmath>
|
2019-05-29 22:12:41 +02:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
class TestCamera : public CxxTest::TestSuite
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void test_frustum_perspective()
|
|
|
|
{
|
|
|
|
SViewPort viewPort;
|
|
|
|
viewPort.m_X = 0;
|
|
|
|
viewPort.m_Y = 0;
|
|
|
|
viewPort.m_Width = 512;
|
|
|
|
viewPort.m_Height = 512;
|
|
|
|
|
|
|
|
CCamera camera;
|
|
|
|
camera.SetViewPort(viewPort);
|
|
|
|
camera.LookAlong(
|
|
|
|
CVector3D(0.0f, 0.0f, 0.0f),
|
|
|
|
CVector3D(0.0f, 0.0f, 1.0f),
|
|
|
|
CVector3D(0.0f, 1.0f, 0.0f)
|
|
|
|
);
|
2019-06-27 00:54:05 +02:00
|
|
|
camera.SetPerspectiveProjection(1.0f, 101.0f, DEGTORAD(90.0f));
|
2021-03-18 00:03:35 +01:00
|
|
|
TS_ASSERT_EQUALS(camera.GetProjectionType(), CCamera::ProjectionType::PERSPECTIVE);
|
2019-05-29 22:12:41 +02:00
|
|
|
camera.UpdateFrustum();
|
|
|
|
|
|
|
|
const float sqrt2 = sqrtf(2.0f) / 2.0f;
|
|
|
|
const std::vector<CPlane> expectedPlanes = {
|
|
|
|
CVector4D(sqrt2, 0.0f, sqrt2, 0.0f),
|
|
|
|
CVector4D(-sqrt2, 0.0f, sqrt2, 0.0f),
|
|
|
|
CVector4D(0.0f, sqrt2, sqrt2, 0.0f),
|
|
|
|
CVector4D(0.0f, -sqrt2, sqrt2, 0.0f),
|
|
|
|
CVector4D(0.0f, 0.0f, -1.0f, 101.0f),
|
|
|
|
CVector4D(0.0f, 0.0f, 1.0f, -1.0f),
|
|
|
|
};
|
|
|
|
CheckFrustumPlanes(camera.GetFrustum(), expectedPlanes);
|
|
|
|
}
|
|
|
|
|
2019-06-05 21:55:37 +02:00
|
|
|
void test_frustum_ortho()
|
|
|
|
{
|
|
|
|
SViewPort viewPort;
|
|
|
|
viewPort.m_X = 0;
|
|
|
|
viewPort.m_Y = 0;
|
|
|
|
viewPort.m_Width = 512;
|
|
|
|
viewPort.m_Height = 512;
|
|
|
|
|
|
|
|
CCamera camera;
|
|
|
|
camera.SetViewPort(viewPort);
|
|
|
|
camera.LookAlong(
|
|
|
|
CVector3D(0.0f, 0.0f, 0.0f),
|
|
|
|
CVector3D(0.0f, 0.0f, 1.0f),
|
|
|
|
CVector3D(0.0f, 1.0f, 0.0f)
|
2019-07-25 01:08:02 +02:00
|
|
|
);
|
2019-06-05 21:55:37 +02:00
|
|
|
CMatrix3D projection;
|
|
|
|
projection.SetOrtho(-10.0f, 10.0f, -10.0f, 10.0f, -10.0f, 10.0f);
|
|
|
|
camera.SetProjection(projection);
|
2021-03-18 00:03:35 +01:00
|
|
|
TS_ASSERT_EQUALS(camera.GetProjectionType(), CCamera::ProjectionType::CUSTOM);
|
2019-06-05 21:55:37 +02:00
|
|
|
camera.UpdateFrustum();
|
|
|
|
|
|
|
|
const std::vector<CPlane> expectedPlanes = {
|
|
|
|
CVector4D(1.0f, 0.0f, 0.0f, 10.0f),
|
|
|
|
CVector4D(-1.0f, 0.0f, 0.0f, 10.0f),
|
|
|
|
CVector4D(0.0f, 1.0f, 0.0f, 10.0f),
|
|
|
|
CVector4D(0.0f, -1.0f, 0.0f, 10.0f),
|
|
|
|
CVector4D(0.0f, 0.0f, 1.0f, 10.0f),
|
|
|
|
CVector4D(0.0f, 0.0f, -1.0f, 10.0f)
|
|
|
|
};
|
|
|
|
CheckFrustumPlanes(camera.GetFrustum(), expectedPlanes);
|
|
|
|
}
|
|
|
|
|
2019-05-29 22:12:41 +02:00
|
|
|
// Order of planes is unknown. So use interactive checker.
|
|
|
|
void CheckFrustumPlanes(const CFrustum& frustum, const std::vector<CPlane>& expectedPlanes)
|
|
|
|
{
|
|
|
|
TS_ASSERT_EQUALS(frustum.GetNumPlanes(), expectedPlanes.size());
|
|
|
|
std::set<size_t> indices;
|
|
|
|
for (size_t i = 0; i < expectedPlanes.size(); ++i)
|
|
|
|
indices.insert(i);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < frustum.GetNumPlanes(); ++i)
|
|
|
|
{
|
|
|
|
bool found = false;
|
|
|
|
for (size_t j : indices)
|
|
|
|
{
|
|
|
|
if (EqualPlanes(frustum[i], expectedPlanes[j]))
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
indices.erase(j);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-06-05 21:55:37 +02:00
|
|
|
if (!found)
|
|
|
|
TS_FAIL(frustum[i]);
|
2019-05-29 22:12:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EqualPlanes(const CPlane& p1, const CPlane& p2) const
|
|
|
|
{
|
|
|
|
const float EPS = 1e-3f;
|
2019-05-30 19:27:55 +02:00
|
|
|
if (std::fabs(p1.m_Dist - p2.m_Dist) >= EPS)
|
2019-05-29 22:12:41 +02:00
|
|
|
return false;
|
|
|
|
return
|
2019-05-30 19:27:55 +02:00
|
|
|
std::fabs(p1.m_Norm.X - p2.m_Norm.X) < EPS &&
|
|
|
|
std::fabs(p1.m_Norm.Y - p2.m_Norm.Y) < EPS &&
|
|
|
|
std::fabs(p1.m_Norm.Z - p2.m_Norm.Z) < EPS;
|
2019-05-29 22:12:41 +02:00
|
|
|
}
|
2019-07-25 01:08:02 +02:00
|
|
|
|
2021-03-19 18:39:34 +01:00
|
|
|
void CompareVectors(const CVector3D& vector1, const CVector3D& vector2, const float EPS)
|
|
|
|
{
|
|
|
|
TS_ASSERT_DELTA(vector1.X, vector2.X, EPS);
|
|
|
|
TS_ASSERT_DELTA(vector1.Y, vector2.Y, EPS);
|
|
|
|
TS_ASSERT_DELTA(vector1.Z, vector2.Z, EPS);
|
|
|
|
}
|
|
|
|
|
2021-03-16 23:42:29 +01:00
|
|
|
void CompareQuads(const CCamera::Quad& quad, const CCamera::Quad& expectedQuad)
|
2020-04-29 20:41:53 +02:00
|
|
|
{
|
2020-11-26 23:28:50 +01:00
|
|
|
const float EPS = 1e-4f;
|
2021-03-16 23:42:29 +01:00
|
|
|
for (size_t index = 0; index < expectedQuad.size(); ++index)
|
2021-03-19 18:39:34 +01:00
|
|
|
CompareVectors(quad[index], expectedQuad[index], EPS);
|
2020-04-29 20:41:53 +02:00
|
|
|
}
|
|
|
|
|
2021-03-16 23:42:29 +01:00
|
|
|
void CompareQuadsInWorldSpace(const CCamera& camera, const CCamera::Quad& quad, const CCamera::Quad& expectedQuad)
|
|
|
|
{
|
|
|
|
const float EPS = 1e-4f;
|
|
|
|
for (size_t index = 0; index < expectedQuad.size(); ++index)
|
|
|
|
{
|
|
|
|
// Transform quad points from camera space to world space.
|
|
|
|
CVector3D point = camera.GetOrientation().Transform(quad[index]);
|
|
|
|
|
2021-03-19 18:39:34 +01:00
|
|
|
CompareVectors(point, expectedQuad[index], EPS);
|
2021-03-16 23:42:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_perspective_plane_points()
|
2019-07-25 01:08:02 +02:00
|
|
|
{
|
|
|
|
SViewPort viewPort;
|
|
|
|
viewPort.m_X = 0;
|
|
|
|
viewPort.m_Y = 0;
|
|
|
|
viewPort.m_Width = 512;
|
|
|
|
viewPort.m_Height = 512;
|
|
|
|
|
|
|
|
CCamera camera;
|
|
|
|
camera.SetViewPort(viewPort);
|
2021-03-16 23:42:29 +01:00
|
|
|
camera.LookAt(
|
|
|
|
CVector3D(10.0f, 20.0f, 10.0f),
|
|
|
|
CVector3D(10.0f, 10.0f, 20.0f),
|
|
|
|
CVector3D(0.0f, 1.0f, 1.0f).Normalized()
|
2019-07-25 01:08:02 +02:00
|
|
|
);
|
|
|
|
camera.SetPerspectiveProjection(1.0f, 101.0f, DEGTORAD(90.0f));
|
|
|
|
|
|
|
|
CCamera::Quad quad;
|
|
|
|
|
|
|
|
// Zero distance point is the origin of all camera rays,
|
2021-03-18 00:03:35 +01:00
|
|
|
// so all plane points should stay there.
|
2019-07-25 01:08:02 +02:00
|
|
|
camera.GetViewQuad(0.0f, quad);
|
|
|
|
for (const CVector3D& point : quad)
|
|
|
|
TS_ASSERT_EQUALS(point, CVector3D(0.0f, 0.0f, 0.0f));
|
|
|
|
|
2021-03-16 23:42:29 +01:00
|
|
|
// Points lying on the near plane.
|
|
|
|
CCamera::Quad expectedNearQuad = {
|
|
|
|
CVector3D(-1.0f, -1.0f, 1.0f),
|
|
|
|
CVector3D(1.0f, -1.0f, 1.0f),
|
|
|
|
CVector3D(1.0f, 1.0f, 1.0f),
|
|
|
|
CVector3D(-1.0f, 1.0f, 1.0f)
|
|
|
|
};
|
|
|
|
CCamera::Quad nearQuad;
|
|
|
|
camera.GetViewQuad(camera.GetNearPlane(), nearQuad);
|
|
|
|
CompareQuads(nearQuad, expectedNearQuad);
|
|
|
|
|
|
|
|
CCamera::Quad expectedWorldSpaceNearQuad = {
|
|
|
|
CVector3D(9.0f, 18.5857868f, 10.0f),
|
|
|
|
CVector3D(11.0f, 18.5857868f, 10.0f),
|
|
|
|
CVector3D(11.0f, 20.0f, 11.4142132f),
|
|
|
|
CVector3D(9.0f, 20.0f, 11.4142132f)
|
|
|
|
};
|
|
|
|
CompareQuadsInWorldSpace(camera, nearQuad, expectedWorldSpaceNearQuad);
|
|
|
|
|
2019-07-25 01:08:02 +02:00
|
|
|
// Points lying on the far plane.
|
|
|
|
CCamera::Quad expectedFarQuad = {
|
|
|
|
CVector3D(-101.0f, -101.0f, 101.0f),
|
|
|
|
CVector3D(101.0f, -101.0f, 101.0f),
|
|
|
|
CVector3D(101.0f, 101.0f, 101.0f),
|
|
|
|
CVector3D(-101.0f, 101.0f, 101.0f)
|
|
|
|
};
|
2021-03-16 23:42:29 +01:00
|
|
|
CCamera::Quad farQuad;
|
|
|
|
camera.GetViewQuad(camera.GetFarPlane(), farQuad);
|
|
|
|
CompareQuads(farQuad, expectedFarQuad);
|
|
|
|
|
|
|
|
CCamera::Quad expectedWorldSpaceFarQuad = {
|
|
|
|
CVector3D(-91.0000153f, -122.8355865f, 10.0f),
|
|
|
|
CVector3D(111.0000153f, -122.8355865f, 10.0f),
|
|
|
|
CVector3D(111.0000153f, 20.0f, 152.8355865f),
|
|
|
|
CVector3D(-91.0000153f, 20.0f, 152.8355865f)
|
|
|
|
};
|
|
|
|
CompareQuadsInWorldSpace(camera, farQuad, expectedWorldSpaceFarQuad);
|
2019-07-25 01:08:02 +02:00
|
|
|
}
|
2021-03-18 00:03:35 +01:00
|
|
|
|
|
|
|
void test_ortho_plane_points()
|
|
|
|
{
|
|
|
|
SViewPort viewPort;
|
|
|
|
viewPort.m_X = 0;
|
|
|
|
viewPort.m_Y = 0;
|
|
|
|
viewPort.m_Width = 512;
|
|
|
|
viewPort.m_Height = 512;
|
|
|
|
|
|
|
|
CCamera camera;
|
|
|
|
camera.SetViewPort(viewPort);
|
|
|
|
camera.LookAt(
|
|
|
|
CVector3D(10.0f, 20.0f, 10.0f),
|
|
|
|
CVector3D(10.0f, 10.0f, 20.0f),
|
|
|
|
CVector3D(0.0f, 1.0f, 1.0f).Normalized()
|
|
|
|
);
|
|
|
|
camera.SetOrthoProjection(2.0f, 128.0f, 10.0f);
|
|
|
|
|
|
|
|
// Zero distance is the origin plane of all camera rays,
|
|
|
|
// so all plane points should stay there.
|
|
|
|
CCamera::Quad quad;
|
|
|
|
camera.GetViewQuad(0.0f, quad);
|
|
|
|
for (const CVector3D& point : quad)
|
|
|
|
{
|
|
|
|
constexpr float EPS = 1e-4f;
|
|
|
|
TS_ASSERT_DELTA(point.Z, 0.0f, EPS);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Points lying on the near plane.
|
|
|
|
CCamera::Quad expectedNearQuad = {
|
|
|
|
CVector3D(-5.0f, -5.0f, 2.0f),
|
|
|
|
CVector3D(5.0f, -5.0f, 2.0f),
|
|
|
|
CVector3D(5.0f, 5.0f, 2.0f),
|
|
|
|
CVector3D(-5.0f, 5.0f, 2.0f)
|
|
|
|
};
|
|
|
|
CCamera::Quad nearQuad;
|
|
|
|
camera.GetViewQuad(camera.GetNearPlane(), nearQuad);
|
|
|
|
CompareQuads(nearQuad, expectedNearQuad);
|
|
|
|
|
|
|
|
CCamera::Quad expectedWorldSpaceNearQuad = {
|
|
|
|
CVector3D(4.9999995f, 15.0502520f, 7.8786793f),
|
|
|
|
CVector3D(15.0f, 15.0502520f, 7.8786793f),
|
|
|
|
CVector3D(15.0f, 22.1213207f, 14.9497480f),
|
|
|
|
CVector3D(4.9999995f, 22.1213207f, 14.9497480f)
|
|
|
|
};
|
|
|
|
CompareQuadsInWorldSpace(camera, nearQuad, expectedWorldSpaceNearQuad);
|
|
|
|
|
|
|
|
// Points lying on the far plane.
|
|
|
|
CCamera::Quad expectedFarQuad = {
|
|
|
|
CVector3D(-5.0f, -5.0f, 128.0f),
|
|
|
|
CVector3D(5.0f, -5.0f, 128.0f),
|
|
|
|
CVector3D(5.0f, 5.0f, 128.0f),
|
|
|
|
CVector3D(-5.0f, 5.0f, 128.0f)
|
|
|
|
};
|
|
|
|
CCamera::Quad farQuad;
|
|
|
|
camera.GetViewQuad(camera.GetFarPlane(), farQuad);
|
|
|
|
CompareQuads(farQuad, expectedFarQuad);
|
|
|
|
|
|
|
|
CCamera::Quad expectedWorldSpaceFarQuad = {
|
|
|
|
CVector3D(4.9999995f, -74.0452118f, 96.9741364f),
|
|
|
|
CVector3D(15.0f, -74.0452118f, 96.9741364f),
|
|
|
|
CVector3D(15.0f, -66.9741364f, 104.0452118f),
|
|
|
|
CVector3D(4.9999995f, -66.9741364f, 104.0452118f)
|
|
|
|
};
|
|
|
|
CompareQuadsInWorldSpace(camera, farQuad, expectedWorldSpaceFarQuad);
|
|
|
|
}
|
2021-03-19 18:39:34 +01:00
|
|
|
|
|
|
|
void test_perspective_screen_rays()
|
|
|
|
{
|
|
|
|
const float EPS = 1e-4f;
|
|
|
|
const std::vector<SViewPort> viewPorts = {
|
|
|
|
SViewPort{0, 0, 512, 512},
|
|
|
|
SViewPort{0, 0, 1024, 768},
|
|
|
|
SViewPort{0, 0, 1440, 2536},
|
|
|
|
};
|
|
|
|
for (const SViewPort& viewPort : viewPorts)
|
|
|
|
{
|
|
|
|
const CVector3D cameraPosition(10.0f, 20.0f, 10.0f);
|
|
|
|
const CVector3D cameraDirection(CVector3D(0.0f, -1.0f, 1.0f).Normalized());
|
|
|
|
CCamera camera;
|
|
|
|
camera.SetViewPort(viewPort);
|
|
|
|
camera.LookAt(
|
|
|
|
cameraPosition,
|
|
|
|
cameraPosition + cameraDirection * 10.0f,
|
|
|
|
CVector3D(0.0f, 1.0f, 1.0f).Normalized()
|
|
|
|
);
|
|
|
|
camera.SetPerspectiveProjection(1.0f, 101.0f, DEGTORAD(90.0f));
|
|
|
|
|
|
|
|
CVector3D origin, dir;
|
|
|
|
camera.BuildCameraRay(viewPort.m_Width / 2, viewPort.m_Height / 2, origin, dir);
|
|
|
|
const CVector3D expectedOrigin = cameraPosition;
|
|
|
|
const CVector3D expectedDir = cameraDirection;
|
|
|
|
CompareVectors(origin, expectedOrigin, EPS);
|
|
|
|
CompareVectors(dir, expectedDir, EPS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_ortho_screen_rays()
|
|
|
|
{
|
|
|
|
const float EPS = 1e-4f;
|
|
|
|
const std::vector<SViewPort> viewPorts = {
|
|
|
|
SViewPort{0, 0, 512, 512},
|
|
|
|
SViewPort{0, 0, 1024, 768},
|
|
|
|
SViewPort{0, 0, 1440, 2536},
|
|
|
|
};
|
|
|
|
for (const SViewPort& viewPort : viewPorts)
|
|
|
|
{
|
|
|
|
const CVector3D cameraPosition(10.0f, 20.0f, 10.0f);
|
|
|
|
const CVector3D cameraDirection(CVector3D(0.0f, -1.0f, 1.0f).Normalized());
|
|
|
|
CCamera camera;
|
|
|
|
camera.SetViewPort(viewPort);
|
|
|
|
camera.LookAt(
|
|
|
|
cameraPosition,
|
|
|
|
cameraPosition + cameraDirection * 10.0f,
|
|
|
|
CVector3D(0.0f, 1.0f, 1.0f).Normalized()
|
|
|
|
);
|
|
|
|
camera.SetOrthoProjection(2.0f, 128.0f, 10.0f);
|
|
|
|
|
|
|
|
CVector3D origin, dir;
|
|
|
|
camera.BuildCameraRay(viewPort.m_Width / 2, viewPort.m_Height / 2, origin, dir);
|
|
|
|
const CVector3D expectedOrigin = cameraPosition;
|
|
|
|
const CVector3D expectedDir = cameraDirection;
|
|
|
|
CompareVectors(origin, expectedOrigin, EPS);
|
|
|
|
CompareVectors(dir, expectedDir, EPS);
|
|
|
|
}
|
|
|
|
}
|
2021-05-15 15:33:36 +02:00
|
|
|
|
|
|
|
void CompareBoundingBoxes(const CBoundingBoxAligned& bb1, const CBoundingBoxAligned& bb2)
|
|
|
|
{
|
|
|
|
constexpr float EPS = 1e-3f;
|
|
|
|
CompareVectors(bb1[0], bb2[0], EPS);
|
|
|
|
CompareVectors(bb1[1], bb2[1], EPS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_viewport_bounds_perspective()
|
|
|
|
{
|
|
|
|
SViewPort viewPort;
|
|
|
|
viewPort.m_X = 0;
|
|
|
|
viewPort.m_Y = 0;
|
|
|
|
viewPort.m_Width = 512;
|
|
|
|
viewPort.m_Height = 512;
|
|
|
|
|
|
|
|
CCamera camera;
|
|
|
|
camera.SetViewPort(viewPort);
|
|
|
|
camera.LookAlong(
|
|
|
|
CVector3D(0.0f, 0.0f, 0.0f),
|
|
|
|
CVector3D(0.0f, 0.0f, 1.0f),
|
|
|
|
CVector3D(0.0f, 1.0f, 0.0f)
|
|
|
|
);
|
|
|
|
camera.SetPerspectiveProjection(1.0f, 101.0f, DEGTORAD(90.0f));
|
|
|
|
camera.UpdateFrustum();
|
|
|
|
|
|
|
|
struct TestCase
|
|
|
|
{
|
|
|
|
CBoundingBoxAligned worldSpaceBoundingBox;
|
|
|
|
CBoundingBoxAligned expectedViewPortBoundingBox;
|
|
|
|
};
|
|
|
|
const TestCase testCases[] = {
|
|
|
|
// Box is in front of the camera.
|
|
|
|
{
|
|
|
|
{{-1.0f, 0.0f, 5.0f}, {1.0f, 0.0f, 7.0f}},
|
|
|
|
{{-0.2f, 0.0f, 0.616f}, {0.2f, 0.0f, 0.731429f}}
|
|
|
|
},
|
|
|
|
// Box is out of the camera view.
|
|
|
|
{
|
|
|
|
{{-10.0f, -1.0f, 5.0f}, {-8.0f, 1.0f, 7.0f}},
|
|
|
|
{}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{{-1.0f, -10.0f, 5.0f}, {1.0f, -8.0f, 7.0f}},
|
|
|
|
{}
|
|
|
|
},
|
|
|
|
// Box is in the bottom part of the camera view.
|
|
|
|
{
|
|
|
|
{{-1.0f, -3.0f, 5.0f}, {1.0f, -3.0f, 7.0f}},
|
|
|
|
{{-0.2f, -0.6f, 0.616f}, {0.2f, -0.428571f, 0.731429f}}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{{-1.0f, -3.0f, 0.0f}, {1.0f, -3.0f, 7.0f}},
|
|
|
|
{{-1.0f, -3.0f, -1.0f}, {1.0f, -0.428571f, 0.731429f}}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{{-1.0f, -3.0f, -7.0f}, {1.0f, -3.0f, 7.0f}},
|
|
|
|
{{-1.0f, -3.0f, -1.0f}, {1.0f, -0.428571f, 0.731429f}}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const TestCase& testCase : testCases)
|
|
|
|
{
|
|
|
|
TS_ASSERT(testCase.worldSpaceBoundingBox[0].X <= testCase.worldSpaceBoundingBox[1].X);
|
|
|
|
TS_ASSERT(testCase.worldSpaceBoundingBox[0].Y <= testCase.worldSpaceBoundingBox[1].Y);
|
|
|
|
TS_ASSERT(testCase.worldSpaceBoundingBox[0].Z <= testCase.worldSpaceBoundingBox[1].Z);
|
|
|
|
|
|
|
|
const CBoundingBoxAligned result =
|
|
|
|
camera.GetBoundsInViewPort(testCase.worldSpaceBoundingBox);
|
|
|
|
if (testCase.expectedViewPortBoundingBox.IsEmpty())
|
|
|
|
{
|
|
|
|
TS_ASSERT(result.IsEmpty());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
CompareBoundingBoxes(result, testCase.expectedViewPortBoundingBox);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-15 15:47:48 +02:00
|
|
|
void test_viewport_bounds_ortho()
|
|
|
|
{
|
|
|
|
SViewPort viewPort;
|
|
|
|
viewPort.m_X = 0;
|
|
|
|
viewPort.m_Y = 0;
|
|
|
|
viewPort.m_Width = 512;
|
|
|
|
viewPort.m_Height = 512;
|
|
|
|
|
|
|
|
CCamera camera;
|
|
|
|
camera.SetViewPort(viewPort);
|
|
|
|
camera.LookAlong(
|
|
|
|
CVector3D(0.0f, 0.0f, 0.0f),
|
|
|
|
CVector3D(0.0f, 0.0f, 1.0f),
|
|
|
|
CVector3D(0.0f, 1.0f, 0.0f)
|
|
|
|
);
|
|
|
|
camera.SetOrthoProjection(1.0f, 101.0f, 2.0f);
|
|
|
|
camera.UpdateFrustum();
|
|
|
|
|
|
|
|
struct TestCase
|
|
|
|
{
|
|
|
|
CBoundingBoxAligned worldSpaceBoundingBox;
|
|
|
|
CBoundingBoxAligned expectedViewPortBoundingBox;
|
|
|
|
};
|
|
|
|
const TestCase testCases[] = {
|
|
|
|
// A box is in front of the camera.
|
|
|
|
{
|
|
|
|
{{-1.0f, 0.0f, 5.0f}, {1.0f, 0.0f, 7.0f}},
|
|
|
|
{{-1.0f, 0.0f, -1.1599f}, {1.0f, 0.0f,-1.1200f}}
|
|
|
|
},
|
|
|
|
// A box is out of the camera view.
|
|
|
|
{
|
|
|
|
{{-10.0f, -1.0f, 5.0f}, {-8.0f, 1.0f, 7.0f}},
|
|
|
|
{}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{{-1.0f, -10.0f, 5.0f}, {1.0f, -8.0f, 7.0f}},
|
|
|
|
{}
|
|
|
|
},
|
|
|
|
// The camera is inside a box.
|
|
|
|
{
|
|
|
|
{{-1.0f, 0.0f, -7.0f}, {1.0f, 0.0f, 7.0f}},
|
|
|
|
{{-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}}
|
|
|
|
},
|
|
|
|
// A box intersects with the near plane.
|
|
|
|
{
|
|
|
|
{{-1.0f, 0.0f, 0.5f}, {1.0f, 0.0f, 7.0f}},
|
|
|
|
{{-1.0f, 0.0f, -1.1599f}, {1.0f, 0.0f, -1.1599f}}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const TestCase& testCase : testCases)
|
|
|
|
{
|
|
|
|
TS_ASSERT(testCase.worldSpaceBoundingBox[0].X <= testCase.worldSpaceBoundingBox[1].X);
|
|
|
|
TS_ASSERT(testCase.worldSpaceBoundingBox[0].Y <= testCase.worldSpaceBoundingBox[1].Y);
|
|
|
|
TS_ASSERT(testCase.worldSpaceBoundingBox[0].Z <= testCase.worldSpaceBoundingBox[1].Z);
|
|
|
|
|
|
|
|
const CBoundingBoxAligned result =
|
|
|
|
camera.GetBoundsInViewPort(testCase.worldSpaceBoundingBox);
|
|
|
|
if (testCase.expectedViewPortBoundingBox.IsEmpty())
|
|
|
|
{
|
|
|
|
TS_ASSERT(result.IsEmpty());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
CompareBoundingBoxes(result, testCase.expectedViewPortBoundingBox);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-29 22:12:41 +02:00
|
|
|
};
|