246 lines
6.1 KiB
C++
246 lines
6.1 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"
|
|
#include "Math/Frustum.hpp"
|
|
#include <array>
|
|
|
|
namespace openVulkanoCpp::Scene
|
|
{
|
|
class Camera : public Node
|
|
{
|
|
public:
|
|
ICloseable* renderCamera = nullptr;
|
|
static constexpr inline size_t SIZE = sizeof(Math::Matrix4f) * 3 + sizeof(Math::Vector4f) + sizeof(float) * 8 + 16;
|
|
static constexpr inline DescriptorSetLayoutBinding DESCRIPTOR_SET_LAYOUT_BINDING = { 0, DescriptorSetLayoutBinding::Type::TYPE_UNIFORM_BUFFER_DYNAMIC, 1, ShaderProgramType::ALL_GRAPHICS };
|
|
|
|
protected:
|
|
Math::Matrix4f m_viewProjection{1}, m_view{1}, m_projection{1};
|
|
Math::Vector4f m_camPosition{};
|
|
float m_nearPlane, m_farPlane, m_width, m_height;
|
|
float m_fov = 0, m_aspect = 0, m_scaleFactor = 0, m_perPixelScaleFactor = 0;
|
|
std::array<uint8_t, 16> m_userData{};
|
|
|
|
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
|
|
{
|
|
//if (renderCamera) renderCamera->Close();
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
public:
|
|
void* GetData() { return &m_viewProjection; }
|
|
|
|
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_camPosition = GetWorldMatrix()[3];
|
|
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]] const Math::Vector4f& GetPosition() const
|
|
{
|
|
return m_camPosition;
|
|
}
|
|
|
|
[[nodiscard]] Math::Vector3f GetRightVector() const
|
|
{
|
|
return Math::Utils::transpose(m_view)[0];
|
|
}
|
|
|
|
[[nodiscard]] Math::Vector3f GetViewDirection() const
|
|
{
|
|
return Math::Utils::transpose(m_view)[2];
|
|
}
|
|
|
|
[[nodiscard]] Math::Frustum GetFrustum() const
|
|
{
|
|
return {m_viewProjection};
|
|
}
|
|
|
|
/**
|
|
* The 16 byte of user data can be used to transmit additional data about the camera to the shader.
|
|
* @return reference to the custom data array
|
|
*/
|
|
[[nodiscard]] std::array<uint8_t, 16>& GetUserData() { return m_userData; }
|
|
|
|
[[nodiscard]] float GetPixelScaleFactor() const { return m_perPixelScaleFactor; }
|
|
};
|
|
|
|
class PerspectiveCamera : public Camera
|
|
{
|
|
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);
|
|
m_scaleFactor = 2 * std::tan(m_fov * 0.5f);
|
|
m_perPixelScaleFactor = m_height / m_scaleFactor;
|
|
}
|
|
|
|
[[nodiscard]] int GetPixelPerMeter(float distance) const
|
|
{
|
|
return static_cast<int>(m_perPixelScaleFactor / distance);
|
|
}
|
|
|
|
void SetSize(const float width, const float height) override
|
|
{
|
|
m_aspect = width / height;
|
|
Camera::SetSize(width, height);
|
|
m_perPixelScaleFactor = m_height / m_scaleFactor;
|
|
}
|
|
|
|
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;
|
|
m_scaleFactor = 2 * std::tan(m_fov * 0.5f);
|
|
m_perPixelScaleFactor = m_height / m_scaleFactor;
|
|
}
|
|
|
|
[[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();
|
|
}
|
|
};
|
|
}
|
|
|