#include "./camera_3d.hpp" #include #include 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()); 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()/2 - 0.00001f), glm::pi()/2 - 0.00001f); yaw = glm::mod(yaw, 2*glm::pi()); 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 Camera3D::getFrustumPlanes(void) const { ZoneScopedN("Camera3D::getFrustumPlanes") std::array 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 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& frustum, const std::array& 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