1
0
forked from 0ad/0ad

Adds ortho projection type and its test.

This was SVN commit r25073.
This commit is contained in:
Vladislav Belov 2021-03-17 23:03:35 +00:00
parent e7612e8fed
commit 92f94e25c6
5 changed files with 114 additions and 27 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -35,7 +35,6 @@
#include "renderer/WaterManager.h"
CCamera::CCamera()
: m_NearPlane(0.0f), m_FarPlane(0.0f), m_FOV(0.0f), m_ProjType(CUSTOM)
{
// Set viewport to something anything should handle, but should be initialised
// to window size before use.
@ -49,7 +48,7 @@ CCamera::~CCamera() = default;
void CCamera::SetProjection(const CMatrix3D& matrix)
{
m_ProjType = CUSTOM;
m_ProjType = ProjectionType::CUSTOM;
m_ProjMat = matrix;
}
@ -58,16 +57,32 @@ void CCamera::SetProjectionFromCamera(const CCamera& camera)
m_ProjType = camera.m_ProjType;
m_NearPlane = camera.m_NearPlane;
m_FarPlane = camera.m_FarPlane;
if (m_ProjType == PERSPECTIVE)
if (m_ProjType == ProjectionType::PERSPECTIVE)
{
m_FOV = camera.m_FOV;
}
else if (m_ProjType == ProjectionType::ORTHO)
{
m_OrthoScale = camera.m_OrthoScale;
}
m_ProjMat = camera.m_ProjMat;
}
void CCamera::SetOrthoProjection(float nearp, float farp, float scale)
{
m_ProjType = ProjectionType::ORTHO;
m_NearPlane = nearp;
m_FarPlane = farp;
m_OrthoScale = scale;
const float halfHeight = 0.5f * m_OrthoScale;
const float halfWidth = halfHeight * GetAspectRatio();
m_ProjMat.SetOrtho(-halfWidth, halfWidth, -halfHeight, halfHeight, m_NearPlane, m_FarPlane);
}
void CCamera::SetPerspectiveProjection(float nearp, float farp, float fov)
{
m_ProjType = PERSPECTIVE;
m_ProjType = ProjectionType::PERSPECTIVE;
m_NearPlane = nearp;
m_FarPlane = farp;
m_FOV = fov;
@ -151,8 +166,9 @@ float CCamera::GetAspectRatio() const
void CCamera::GetViewQuad(float dist, Quad& quad) const
{
ENSURE(m_ProjType == PERSPECTIVE);
const float y = dist * tanf(m_FOV * 0.5f);
ENSURE(m_ProjType == ProjectionType::PERSPECTIVE || m_ProjType == ProjectionType::ORTHO);
const float y = m_ProjType == ProjectionType::PERSPECTIVE ? dist * tanf(m_FOV * 0.5f) : m_OrthoScale * 0.5f;
const float x = y * GetAspectRatio();
quad[0].X = -x;
@ -214,7 +230,6 @@ CVector3D CCamera::GetWorldCoordinates(int px, int py, bool aboveWater) const
BuildCameraRay(px, py, origin, dir);
bool gotTerrain = tracer.RayIntersect(origin, dir, x, z, terrainPoint);
if (!aboveWater)
@ -351,9 +366,9 @@ CVector3D CCamera::GetFocus() const
}
}
void CCamera::LookAt(const CVector3D& camera, const CVector3D& target, const CVector3D& up)
void CCamera::LookAt(const CVector3D& camera, const CVector3D& focus, const CVector3D& up)
{
CVector3D delta = target - camera;
CVector3D delta = focus - camera;
LookAlong(camera, delta, up);
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -44,9 +44,10 @@ class CCamera
// Represents camera viewport or frustum side in 3D space.
using Quad = std::array<CVector3D, 4>;
enum ProjectionType
enum class ProjectionType
{
CUSTOM,
ORTHO,
PERSPECTIVE,
};
@ -58,6 +59,7 @@ class CCamera
CMatrix3D GetViewProjection() const { return m_ProjMat * m_Orientation.GetInverse(); }
void SetProjection(const CMatrix3D& matrix);
void SetProjectionFromCamera(const CCamera& camera);
void SetOrthoProjection(float nearp, float farp, float scale);
void SetPerspectiveProjection(float nearp, float farp, float fov);
ProjectionType GetProjectionType() const { return m_ProjType; }
@ -78,6 +80,7 @@ class CCamera
float GetNearPlane() const { return m_NearPlane; }
float GetFarPlane() const { return m_FarPlane; }
float GetFOV() const { return m_FOV; }
float GetOrthoScale() const { return m_OrthoScale; }
// Returns a quad of view in camera space at given distance from camera.
void GetViewQuad(float dist, Quad& quad) const;
@ -102,10 +105,10 @@ class CCamera
CVector3D GetFocus() const;
// Build an orientation matrix from camera position, camera focus point, and up-vector
void LookAt(const CVector3D& camera, const CVector3D& orientation, const CVector3D& up);
void LookAt(const CVector3D& camera, const CVector3D& focus, const CVector3D& up);
// Build an orientation matrix from camera position, camera orientation, and up-vector
void LookAlong(const CVector3D& camera, CVector3D focus, CVector3D up);
void LookAlong(const CVector3D& camera, CVector3D orientation, CVector3D up);
/**
* Render: Renders the camera's frustum in world space.
@ -123,15 +126,18 @@ class CCamera
private:
CMatrix3D m_ProjMat;
ProjectionType m_ProjType;
ProjectionType m_ProjType = ProjectionType::CUSTOM;
float m_NearPlane = 0.0f;
float m_FarPlane = 0.0f;
union
{
float m_FOV;
float m_OrthoScale;
};
SViewPort m_ViewPort;
float m_NearPlane;
float m_FarPlane;
float m_FOV;
SViewPort m_ViewPort;
CFrustum m_ViewFrustum;
CFrustum m_ViewFrustum;
};
#endif // INCLUDED_CAMERA

View File

@ -43,7 +43,7 @@ public:
CVector3D(0.0f, 1.0f, 0.0f)
);
camera.SetPerspectiveProjection(1.0f, 101.0f, DEGTORAD(90.0f));
TS_ASSERT_EQUALS(camera.GetProjectionType(), CCamera::PERSPECTIVE);
TS_ASSERT_EQUALS(camera.GetProjectionType(), CCamera::ProjectionType::PERSPECTIVE);
camera.UpdateFrustum();
const float sqrt2 = sqrtf(2.0f) / 2.0f;
@ -76,7 +76,7 @@ public:
CMatrix3D projection;
projection.SetOrtho(-10.0f, 10.0f, -10.0f, 10.0f, -10.0f, 10.0f);
camera.SetProjection(projection);
TS_ASSERT_EQUALS(camera.GetProjectionType(), CCamera::CUSTOM);
TS_ASSERT_EQUALS(camera.GetProjectionType(), CCamera::ProjectionType::CUSTOM);
camera.UpdateFrustum();
const std::vector<CPlane> expectedPlanes = {
@ -171,7 +171,7 @@ public:
CCamera::Quad quad;
// Zero distance point is the origin of all camera rays,
// so all plane points should be stay there.
// so all plane points should stay there.
camera.GetViewQuad(0.0f, quad);
for (const CVector3D& point : quad)
TS_ASSERT_EQUALS(point, CVector3D(0.0f, 0.0f, 0.0f));
@ -214,4 +214,70 @@ public:
};
CompareQuadsInWorldSpace(camera, farQuad, expectedWorldSpaceFarQuad);
}
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);
}
};

View File

@ -389,7 +389,7 @@ void WriteBigScreenshot(const VfsPath& extension, int tiles, int tileWidth, int
for (int tile_x = 0; tile_x < tiles; ++tile_x)
{
// Adjust the camera to render the appropriate region
if (oldCamera.GetProjectionType() == CCamera::PERSPECTIVE)
if (oldCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE)
{
projection.SetPerspectiveTile(oldCamera.GetFOV(), aspectRatio, oldCamera.GetNearPlane(), oldCamera.GetFarPlane(), tiles, tile_x, tile_y);
}

View File

@ -927,7 +927,7 @@ void CRenderer::ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAlign
WaterManager& wm = m->waterManager;
CMatrix3D projection;
if (m_ViewCamera.GetProjectionType() == CCamera::PERSPECTIVE)
if (m_ViewCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE)
{
const float aspectRatio = 1.0f;
// Expand fov slightly since ripples can reflect parts of the scene that
@ -972,7 +972,7 @@ void CRenderer::ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAlign
WaterManager& wm = m->waterManager;
CMatrix3D projection;
if (m_ViewCamera.GetProjectionType() == CCamera::PERSPECTIVE)
if (m_ViewCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE)
{
const float aspectRatio = 1.0f;
// Expand fov slightly since ripples can reflect parts of the scene that