mirror of
https://github.com/MadeOfJelly/MushMachine.git
synced 2025-04-16 16:32:59 +02:00
236 lines
5.7 KiB
C++
236 lines
5.7 KiB
C++
#include "./camera_3d.hpp"
|
|
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
#include <tracy/Tracy.hpp>
|
|
|
|
namespace MM::OpenGL {
|
|
|
|
Camera3D::Camera3D(void) {
|
|
updateView();
|
|
}
|
|
|
|
void Camera3D::setOrthographic(void) {
|
|
ortho = true;
|
|
_projection = glm::ortho(
|
|
-horizontalViewPortSize / 2,
|
|
horizontalViewPortSize / 2,
|
|
-horizontalViewPortSize / (screenRatio * 2),
|
|
horizontalViewPortSize / (screenRatio * 2),
|
|
nearPlane,
|
|
farPlane
|
|
);
|
|
}
|
|
|
|
void Camera3D::setPerspective(void) {
|
|
ortho = false;
|
|
_projection = glm::perspective(fov, screenRatio, nearPlane, farPlane);
|
|
}
|
|
|
|
void Camera3D::updateView(void) {
|
|
roll = glm::mod(roll, 2*glm::pi<float>());
|
|
|
|
if (ortho) {
|
|
_view = glm::mat4(1);
|
|
|
|
_view = glm::rotate(_view, roll, glm::vec3{0.f, 0.f, 1.f});
|
|
|
|
auto tmp_trans = glm::mat4(1);
|
|
tmp_trans[3] = glm::vec4(-translation.x, -translation.y, 0.f, 1.f);
|
|
_view = _view * tmp_trans;
|
|
//_view[3] = glm::vec4(-translation.x, -translation.y, 0.f, 1.f);
|
|
////_view[3] = glm::vec4(-translation.x, -translation.y, 1.0f, 1.f);
|
|
//_view = glm::translate(_view, glm::vec3{-translation.x, -translation.y, -1.f});
|
|
|
|
//_view = glm::inverse(_view);
|
|
|
|
_view[2][2] = -1.f;
|
|
|
|
// TODO: please fix me
|
|
} else {
|
|
pitch = glm::clamp(pitch, -(glm::pi<float>()/2 - 0.00001f), glm::pi<float>()/2 - 0.00001f);
|
|
yaw = glm::mod(yaw, 2*glm::pi<float>());
|
|
|
|
glm::vec3 front = getViewDir();
|
|
|
|
_view = glm::lookAt(translation, translation + front, up);
|
|
}
|
|
}
|
|
|
|
glm::mat4 Camera3D::getViewProjection() const {
|
|
return _projection * _view;
|
|
}
|
|
|
|
glm::mat4 Camera3D::getView() const {
|
|
return _view;
|
|
}
|
|
|
|
glm::mat4 Camera3D::getProjection() const {
|
|
return _projection;
|
|
}
|
|
|
|
glm::vec3 Camera3D::getViewDir(void) const {
|
|
glm::vec3 front {0,0,0};
|
|
{ // TODO: optimize
|
|
if (up.y != 0.f) {
|
|
// if y up/down
|
|
front.x += up.y * glm::cos(pitch) * glm::cos(-yaw); // TODO: y is yaw inverted??
|
|
front.y += up.y * glm::sin(pitch);
|
|
front.z += up.y * glm::cos(pitch) * glm::sin(-yaw);
|
|
}
|
|
if (up.z != 0.f) {
|
|
// if z up/down
|
|
front.x += up.z * glm::cos(pitch) * glm::cos(yaw);
|
|
front.y += up.z * glm::cos(pitch) * glm::sin(yaw);
|
|
front.z += up.z * glm::sin(pitch);
|
|
}
|
|
}
|
|
|
|
front = glm::normalize(front);
|
|
|
|
return front;
|
|
}
|
|
|
|
std::array<glm::vec4, 6> Camera3D::getFrustumPlanes(void) const {
|
|
ZoneScopedN("Camera3D::getFrustumPlanes")
|
|
|
|
std::array<glm::vec4, 6> planes;
|
|
|
|
glm::mat4 wvp = getViewProjection();
|
|
|
|
// see:
|
|
// https://stackoverflow.com/questions/11770262/glm-calculating-the-frustum-from-the-projection-matrix
|
|
// http://web.archive.org/web/20120531231005/http://crazyjoke.free.fr/doc/3D/plane%20extraction.pdf
|
|
|
|
#ifdef LEFT_HANDED
|
|
// left handed
|
|
{
|
|
// Left clipping plane
|
|
planes[0].x = wvp[0][3] + wvp[0][0];
|
|
planes[0].y = wvp[1][3] + wvp[1][0];
|
|
planes[0].z = wvp[2][3] + wvp[2][0];
|
|
planes[0].w = wvp[3][3] + wvp[3][0];
|
|
|
|
// Right clipping plane
|
|
planes[1].x = wvp[0][3] - wvp[0][0];
|
|
planes[1].y = wvp[1][3] - wvp[1][0];
|
|
planes[1].z = wvp[2][3] - wvp[2][0];
|
|
planes[1].w = wvp[3][3] - wvp[3][0];
|
|
|
|
// Top clipping
|
|
planes[2].x = wvp[0][3] - wvp[0][1];
|
|
planes[2].y = wvp[1][3] - wvp[1][1];
|
|
planes[2].z = wvp[2][3] - wvp[2][1];
|
|
planes[2].w = wvp[3][3] - wvp[3][1];
|
|
|
|
// Bottom clipping plane
|
|
planes[3].x = wvp[0][3] + wvp[0][1];
|
|
planes[3].y = wvp[1][3] + wvp[1][1];
|
|
planes[3].z = wvp[2][3] + wvp[2][1];
|
|
planes[3].w = wvp[3][3] + wvp[3][1];
|
|
|
|
// Near clipping plane
|
|
planes[4].x = wvp[0][2];
|
|
planes[4].y = wvp[1][2];
|
|
planes[4].z = wvp[2][2];
|
|
planes[4].w = wvp[3][2];
|
|
|
|
// Far clipping
|
|
planes[5].x = wvp[0][3] - wvp[0][2];
|
|
planes[5].y = wvp[1][3] - wvp[1][2];
|
|
planes[5].z = wvp[2][3] - wvp[2][2];
|
|
planes[5].w = wvp[3][3] - wvp[3][2];
|
|
}
|
|
#else
|
|
// right handed
|
|
{
|
|
// Left clipping plane
|
|
planes[0].x = wvp[0][3] + wvp[0][0];
|
|
planes[0].y = wvp[1][3] + wvp[1][0];
|
|
planes[0].z = wvp[2][3] + wvp[2][0];
|
|
planes[0].w = wvp[3][3] + wvp[3][0];
|
|
|
|
// Right clipping plane
|
|
planes[1].x = wvp[0][3] - wvp[0][0];
|
|
planes[1].y = wvp[1][3] - wvp[1][0];
|
|
planes[1].z = wvp[2][3] - wvp[2][0];
|
|
planes[1].w = wvp[3][3] - wvp[3][0];
|
|
|
|
// Top clipping plane
|
|
planes[2].x = wvp[0][3] - wvp[0][1];
|
|
planes[2].y = wvp[1][3] - wvp[1][1];
|
|
planes[2].z = wvp[2][3] - wvp[2][1];
|
|
planes[2].w = wvp[3][3] - wvp[3][1];
|
|
|
|
// Bottom clipping plane
|
|
planes[3].x = wvp[0][3] + wvp[0][1];
|
|
planes[3].y = wvp[1][3] + wvp[1][1];
|
|
planes[3].z = wvp[2][3] + wvp[2][1];
|
|
planes[3].w = wvp[3][3] + wvp[3][1];
|
|
|
|
// Near clipping plane
|
|
planes[4].x = wvp[0][3] + wvp[0][2];
|
|
planes[4].y = wvp[1][3] + wvp[1][2];
|
|
planes[4].z = wvp[2][3] + wvp[2][2];
|
|
planes[4].w = wvp[3][3] + wvp[3][2];
|
|
|
|
// Far clipping plane
|
|
planes[5].x = wvp[0][3] - wvp[0][2];
|
|
planes[5].y = wvp[1][3] - wvp[1][2];
|
|
planes[5].z = wvp[2][3] - wvp[2][2];
|
|
planes[5].w = wvp[3][3] - wvp[3][2];
|
|
}
|
|
#endif
|
|
|
|
// normalize
|
|
for (size_t i = 0; i < 6; i++) {
|
|
planes[i] = glm::normalize(planes[i]);
|
|
}
|
|
|
|
return planes;
|
|
}
|
|
|
|
// example use:
|
|
// const glm::vec4 screen {
|
|
// (
|
|
// glm::vec2{mouse_pos.x, window_size.y - mouse_pos.y}
|
|
// / (glm::vec2{window_size.x, window_size.y} * 0.5f)
|
|
// )
|
|
// - glm::vec2{1.f, 1.f}
|
|
// , 1.f, 1.f
|
|
// };
|
|
glm::vec4 Camera3D::screenToWorld(const glm::vec4& screen) const {
|
|
return glm::inverse(getViewProjection()) * screen;
|
|
}
|
|
|
|
template<typename T>
|
|
static T dot34(glm::vec<3, T> lhs, glm::vec<4, T> rhs) {
|
|
return glm::dot(lhs, glm::vec<3, T>(rhs)) + rhs.w;
|
|
}
|
|
|
|
bool in_frustum_aabb(
|
|
const std::array<glm::vec4, 6>& frustum,
|
|
const std::array<glm::vec3, 8>& aabb
|
|
) {
|
|
// test each plane
|
|
for (int i = 0; i < 6; i++) {
|
|
bool inside = false; // inside current plane
|
|
|
|
for (int j = 0; j < 8; j++) {
|
|
if (dot34(aabb[j], frustum[i]) >= 0) { // == for on plane
|
|
inside = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!inside) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // MM::Rendering
|
|
|