1
0
forked from 0ad/0ad

Adds basic tests for BuildCameraRay and uses viewport instead of renderer for width and height.

This was SVN commit r25085.
This commit is contained in:
Vladislav Belov 2021-03-19 17:39:34 +00:00
parent 30432574fa
commit c4d5729c73
3 changed files with 91 additions and 23 deletions

View File

@ -187,9 +187,11 @@ void CCamera::GetViewQuad(float dist, Quad& quad) const
void CCamera::BuildCameraRay(int px, int py, CVector3D& origin, CVector3D& dir) const
{
ENSURE(m_ProjType == ProjectionType::PERSPECTIVE || m_ProjType == ProjectionType::ORTHO);
// Coordinates relative to the camera plane.
const float dx = static_cast<float>(px) / g_Renderer.GetWidth();
const float dy = 1.0f - static_cast<float>(py) / g_Renderer.GetHeight();
const float dx = static_cast<float>(px) / m_ViewPort.m_Width;
const float dy = 1.0f - static_cast<float>(py) / m_ViewPort.m_Height;
Quad points;
GetViewQuad(m_FarPlane, points);
@ -199,14 +201,21 @@ void CCamera::BuildCameraRay(int px, int py, CVector3D& origin, CVector3D& dir)
point = m_Orientation.Transform(point);
// Get world space position of mouse point at the far clipping plane.
CVector3D basisX = points[1] - points[0];
CVector3D basisY = points[3] - points[0];
CVector3D targetPoint = points[0] + (basisX * dx) + (basisY * dy);
const CVector3D basisX = points[1] - points[0];
const CVector3D basisY = points[3] - points[0];
origin = m_Orientation.GetTranslation();
// Build direction for the camera origin to the target point.
dir = targetPoint - origin;
if (m_ProjType == ProjectionType::PERSPECTIVE)
{
// Build direction for the camera origin to the target point.
origin = m_Orientation.GetTranslation();
CVector3D targetPoint = points[0] + (basisX * dx) + (basisY * dy);
dir = targetPoint - origin;
}
else if (m_ProjType == ProjectionType::ORTHO)
{
origin = m_Orientation.GetTranslation() + (basisX * (dx - 0.5f)) + (basisY * (dy - 0.5f));
dir = m_Orientation.GetIn();
}
dir.Normalize();
}
@ -218,8 +227,8 @@ void CCamera::GetScreenCoordinates(const CVector3D& world, float& x, float& y) c
x = screenspace.X / screenspace.W;
y = screenspace.Y / screenspace.W;
x = (x + 1) * 0.5f * g_Renderer.GetWidth();
y = (1 - y) * 0.5f * g_Renderer.GetHeight();
x = (x + 1) * 0.5f * m_ViewPort.m_Width;
y = (1 - y) * 0.5f * m_ViewPort.m_Height;
}
CVector3D CCamera::GetWorldCoordinates(int px, int py, bool aboveWater) const

View File

@ -85,10 +85,8 @@ class CCamera
// Returns a quad of view in camera space at given distance from camera.
void GetViewQuad(float dist, Quad& quad) const;
// Build a ray passing through the screen coordinate (px, py) and the camera
/////////////////////////////////////////////////////////////////////////////////////////
// BuildCameraRay: calculate origin and ray direction of a ray through
// the pixel (px,py) on the screen
// Builds a ray passing through the screen coordinate (px, py), calculates
// origin and direction of the ray.
void BuildCameraRay(int px, int py, CVector3D& origin, CVector3D& dir) const;
// General helpers that seem to fit here

View File

@ -126,15 +126,18 @@ public:
std::fabs(p1.m_Norm.Z - p2.m_Norm.Z) < EPS;
}
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);
}
void CompareQuads(const CCamera::Quad& quad, const CCamera::Quad& expectedQuad)
{
const float EPS = 1e-4f;
for (size_t index = 0; index < expectedQuad.size(); ++index)
{
TS_ASSERT_DELTA(quad[index].X, expectedQuad[index].X, EPS);
TS_ASSERT_DELTA(quad[index].Y, expectedQuad[index].Y, EPS);
TS_ASSERT_DELTA(quad[index].Z, expectedQuad[index].Z, EPS);
}
CompareVectors(quad[index], expectedQuad[index], EPS);
}
void CompareQuadsInWorldSpace(const CCamera& camera, const CCamera::Quad& quad, const CCamera::Quad& expectedQuad)
@ -145,9 +148,7 @@ public:
// Transform quad points from camera space to world space.
CVector3D point = camera.GetOrientation().Transform(quad[index]);
TS_ASSERT_DELTA(point.X, expectedQuad[index].X, EPS);
TS_ASSERT_DELTA(point.Y, expectedQuad[index].Y, EPS);
TS_ASSERT_DELTA(point.Z, expectedQuad[index].Z, EPS);
CompareVectors(point, expectedQuad[index], EPS);
}
}
@ -280,4 +281,64 @@ public:
};
CompareQuadsInWorldSpace(camera, farQuad, expectedWorldSpaceFarQuad);
}
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);
}
}
};