Files
OpenVulkano/openVulkanoCpp/Scene/Camera.hpp
2021-08-27 11:19:11 +02:00

210 lines
4.7 KiB
C++

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "Node.hpp"
#include "Math/Math.hpp"
namespace openVulkanoCpp::Scene
{
class Camera : public Node
{
protected:
Math::Matrix4f m_viewProjection{1}, m_view{1}, m_projection{1};
float m_nearPlane, m_farPlane, m_width, m_height;
Camera() : m_nearPlane(0), m_farPlane(0), m_width(0), m_height(0) {}
Camera(float width, float height, float nearPlane, float farPlane)
: m_nearPlane(nearPlane), m_farPlane(farPlane), m_width(width), m_height(height)
{
}
~Camera() override = default;
public:
void Init(float width, float height, float nearPlane, float farPlane)
{
m_width = width;
m_height = height;
m_nearPlane = nearPlane;
m_farPlane = farPlane;
Node::Init();
UpdateProjectionMatrix();
}
virtual void SetSize(const float width, const float height)
{
if (m_width == width && m_height == height) return;
m_width = width;
m_height = height;
UpdateProjectionMatrix();
}
void SetNearPlane(float nearPlane)
{
m_nearPlane = nearPlane;
}
void SetFarPlane(float farPlane)
{
m_farPlane = farPlane;
}
[[nodiscard]] float NearPlane() const
{
return m_nearPlane;
}
[[nodiscard]] float FarPlane() const
{
return m_farPlane;
}
virtual void UpdateProjectionMatrix() = 0;
void UpdateViewProjectionMatrix()
{
//TODO this should be done based on the clipspace used by the rendering api
// In vulkan the screen space is defined as y=0=top and y=1=bottom and thus the coordinate have to be flipped
m_viewProjection = m_projection * Math::Matrix4f(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) * m_view;
}
void UpdateWorldMatrix(const Math::Matrix4f& parentWorldMat) override
{
Node::UpdateWorldMatrix(parentWorldMat);
m_view = Math::Utils::inverse(GetWorldMatrix());
UpdateViewProjectionMatrix();
}
void SetViewMatrix(const Math::Matrix4f& view)
{
SetMatrix(Math::Utils::inverse(view));
}
[[nodiscard]] const Math::Matrix4f& GetViewProjectionMatrix() const
{
return m_viewProjection;
}
[[nodiscard]] Math::Vector4f GetPosition() const
{
return GetWorldMatrix()[3];
}
[[nodiscard]] Math::Vector3f GetRightVector() const
{
return Math::Utils::transpose(m_view)[0];
}
[[nodiscard]] Math::Vector3f GetViewDirection() const
{
return Math::Utils::transpose(m_view)[2];
}
};
class PerspectiveCamera : public Camera
{
protected:
float m_fov = 0, m_aspect = 0;
public:
PerspectiveCamera() = default;
~PerspectiveCamera() override = default;
PerspectiveCamera(float fovDegrees, float nearPlane = 0.1f, float farPlane = 1000.0f, float width = 16, float height = 9)
: Camera()
{
Init(fovDegrees, width, height, nearPlane, farPlane);
PerspectiveCamera::UpdateProjectionMatrix();
}
void Init(float fovDegrees, float nearPlane, float farPlane)
{
Init(fovDegrees, 16, 9, nearPlane, farPlane);
}
void Init(float fovDegrees, float width, float height, float nearPlane, float farPlane)
{
m_fov = Math::Utils::radians(fovDegrees);
m_aspect = width / height;
Camera::Init(width, height, nearPlane, farPlane);
}
void SetSize(const float width, const float height) override
{
m_aspect = width / height;
Camera::SetSize(width, height);
}
void SetAspect(const float aspect)
{
m_aspect = aspect;
Camera::SetSize(aspect, 1);
}
void SetFovX(const float fov)
{
SetFov(2.0f * atanf(tanf(fov * 0.5f) * m_aspect));
}
void SetFovXRad(const float fov)
{
SetFovRad(2.0f * atanf(tanf(fov * 0.5f) * m_aspect));
}
void SetFov(const float fov)
{
SetFovRad(Math::Utils::radians(fov));
}
void SetFovRad(const float fov)
{
m_fov = fov;
}
[[nodiscard]] float GetFov() const
{
return Math::Utils::degrees(m_fov);
}
[[nodiscard]] float GetFovX() const
{
return 2.0f * atanf(tanf(GetFov() * 0.5f) * m_aspect);
}
[[nodiscard]] float GetFovRad() const
{
return m_fov;
}
[[nodiscard]] float GetFovXRad() const
{
return 2.0f * atanf(tanf(m_fov * 0.5f) * m_aspect);
}
void UpdateProjectionMatrix() final
{
m_projection = Math::Utils::perspectiveRH_ZO(m_fov, m_aspect, m_nearPlane, m_farPlane);
UpdateViewProjectionMatrix();
}
};
class OrthographicCamera : public Camera
{
public:
void UpdateProjectionMatrix() final
{
const float widthHalf = m_width * 0.5f, heightHalf = m_height * 0.5f;
m_projection = Math::Utils::orthoRH_ZO(-widthHalf, widthHalf, -heightHalf, heightHalf, m_nearPlane, m_farPlane);
UpdateViewProjectionMatrix();
}
};
}