diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index 0e2112b6c7..01e9896c35 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -32,13 +32,13 @@ Camera::Camera(const std::shared_ptr &renderer, // Make the frustum slightly bigger than the camera's view to ensure objects on the boundary get rendered float real_zoom = 0.7f * this->default_zoom_ratio * this->zoom; - frustum.Recalculate(this->viewport_size, - near_distance, - far_distance, - this->scene_pos, - cam_direction, - Eigen::Vector3f(0.0f, 1.0f, 0.0f), - real_zoom); + frustum.update(this->viewport_size, + near_distance, + far_distance, + this->scene_pos, + cam_direction, + Eigen::Vector3f(0.0f, 1.0f, 0.0f), + real_zoom); log::log(INFO << "Created new camera at position " << "(" << this->scene_pos[0] @@ -66,13 +66,13 @@ Camera::Camera(const std::shared_ptr &renderer, // Make the frustum slightly bigger than the camera's view to ensure objects on the boundary get rendered float real_zoom = 0.7f * this->default_zoom_ratio * this->zoom; - frustum.Recalculate(this->viewport_size, - near_distance, - far_distance, - this->scene_pos, - cam_direction, - Eigen::Vector3f(0.0f, 1.0f, 0.0f), - real_zoom); + frustum.update(this->viewport_size, + near_distance, + far_distance, + this->scene_pos, + cam_direction, + Eigen::Vector3f(0.0f, 1.0f, 0.0f), + real_zoom); log::log(INFO << "Created new camera at position " << "(" << this->scene_pos[0] @@ -129,14 +129,14 @@ void Camera::move_to(Eigen::Vector3f scene_pos) { this->moved = true; // Make the frustum slightly bigger than the camera's view to ensure objects on the boundary get rendered - float real_zoom = 0.7f * this->default_zoom_ratio * this->zoom; - frustum.Recalculate(viewport_size, - near_distance, - far_distance, - scene_pos, - cam_direction, - Eigen::Vector3f(0.0f, 1.0f, 0.0f), - real_zoom); + float real_zoom = 0.5f * this->default_zoom_ratio * this->zoom; + frustum.update(viewport_size, + near_distance, + far_distance, + scene_pos, + cam_direction, + Eigen::Vector3f(0.0f, 1.0f, 0.0f), + real_zoom); } void Camera::move_rel(Eigen::Vector3f direction, float delta) { diff --git a/libopenage/renderer/camera/frustum.cpp b/libopenage/renderer/camera/frustum.cpp index 03735247df..234dbe500a 100644 --- a/libopenage/renderer/camera/frustum.cpp +++ b/libopenage/renderer/camera/frustum.cpp @@ -29,13 +29,13 @@ Frustum::Frustum() : near_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)} { } -void Frustum::Recalculate(util::Vector2s &viewport_size, - float near_distance, - float far_distance, - Eigen::Vector3f &scene_pos, - Eigen::Vector3f cam_direction, - Eigen::Vector3f up_direction, - float real_zoom) { +void Frustum::update(util::Vector2s &viewport_size, + float near_distance, + float far_distance, + Eigen::Vector3f &scene_pos, + Eigen::Vector3f cam_direction, + Eigen::Vector3f up_direction, + float real_zoom) { // offsets are adjusted by zoom // this is the same calculation as for the projection matrix float halfscreenwidth = viewport_size[0] / 2; @@ -57,10 +57,10 @@ void Frustum::Recalculate(util::Vector2s &viewport_size, Eigen::Vector3f u = s.cross(f); u.normalize(); - Eigen::Vector3f near_position = scene_pos - direction * near_distance; + Eigen::Vector3f near_position = scene_pos + direction * near_distance; Eigen::Vector3f far_position = scene_pos + direction * far_distance; - // The frustum is a box with 8 points defining it (4 on the near plane, 4 on the far plane) + // The frustum is a cuboid box with 8 points defining it (4 on the near plane, 4 on the far plane) Eigen::Vector3f near_top_left = near_position - s * halfwidth + u * halfheight; Eigen::Vector3f near_top_right = near_position + s * halfwidth + u * halfheight; Eigen::Vector3f near_bottom_left = near_position - s * halfwidth - u * halfheight; @@ -72,11 +72,11 @@ void Frustum::Recalculate(util::Vector2s &viewport_size, Eigen::Vector3f far_bottom_right = far_position + s * halfwidth - u * halfheight; // The near and far planes are easiest to compute, as they should be in the direction of the camera - this->near_face_normal = -1.0f * cam_direction.normalized(); - this->far_face_normal = cam_direction.normalized(); + this->near_face_normal = cam_direction.normalized(); + this->far_face_normal = -1.0f * cam_direction.normalized(); - this->near_face_distance = this->near_face_normal.dot(near_position) * -1.0f; - this->far_face_distance = this->far_face_normal.dot(far_position) * -1.0f; + this->near_face_distance = this->near_face_normal.dot(near_position); + this->far_face_distance = this->far_face_normal.dot(far_position); // Each left, right, top, and bottom plane are defined by three points on the plane this->left_face_normal = (near_bottom_left - near_top_left).cross(far_bottom_left - near_bottom_left); @@ -95,7 +95,7 @@ void Frustum::Recalculate(util::Vector2s &viewport_size, this->bottom_face_distance = this->bottom_face_normal.dot(near_bottom_left); } -bool Frustum::is_in_frustum(Eigen::Vector3f &pos) const { +bool Frustum::in_frustum(Eigen::Vector3f &pos) const { // For each plane, if a point is behind one of the frustum planes, it is not within the frustum float distance; diff --git a/libopenage/renderer/camera/frustum.h b/libopenage/renderer/camera/frustum.h index bd87147177..d1d32ce296 100644 --- a/libopenage/renderer/camera/frustum.h +++ b/libopenage/renderer/camera/frustum.h @@ -14,19 +14,46 @@ namespace openage::renderer::camera { +/** + * Frustum for a camera. + * + * Used for frustum culling (https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling) + * in the renderer. + */ class Frustum { public: + /** + * Create a new frustum. + */ Frustum(); - void Recalculate(util::Vector2s &viewport_size, - float near_distance, - float far_distance, - Eigen::Vector3f &scene_pos, - Eigen::Vector3f cam_direction, - Eigen::Vector3f up_direction, - float real_zoom); + /** + * Update this frustum with the new camera parameters. + * + * @param viewport_size Size of the viewport (width x height). + * @param near_distance Near distance of the frustum. + * @param far_distance Far distance of the frustum. + * @param scene_pos Scene position of the camera. + * @param cam_direction Direction the camera is looking at. + * @param up_direction Up direction of the camera. + * @param real_zoom Zoom factor of the camera. + */ + void update(util::Vector2s &viewport_size, + float near_distance, + float far_distance, + Eigen::Vector3f &scene_pos, + Eigen::Vector3f cam_direction, + Eigen::Vector3f up_direction, + float real_zoom); - bool is_in_frustum(Eigen::Vector3f &pos) const; + /** + * Check whether a point in the scene is inside the frustum. + * + * @param scene_pos 3D scene coordinates. + * + * @return true if the point is inside the frustum, else false. + */ + bool in_frustum(Eigen::Vector3f &scene_pos) const; private: Eigen::Vector3f top_face_normal; diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp index da326a4faf..a33f89f152 100644 --- a/libopenage/renderer/stages/world/object.cpp +++ b/libopenage/renderer/stages/world/object.cpp @@ -225,10 +225,11 @@ void WorldObject::set_uniforms(std::vectorlayer_uniforms = std::move(uniforms); } -bool WorldObject::within_camera_frustum(const std::shared_ptr &camera) { - Eigen::Vector3f current_pos = this->position.get(this->last_update).to_world_space(); +bool WorldObject::within_camera_frustum(const std::shared_ptr &camera, + const time::time_t &time) { + Eigen::Vector3f current_pos = this->position.get(time).to_world_space(); auto frustum = camera->get_frustum(); - return frustum.is_in_frustum(current_pos); + return frustum.in_frustum(current_pos); } } // namespace openage::renderer::world diff --git a/libopenage/renderer/stages/world/object.h b/libopenage/renderer/stages/world/object.h index 17da70be75..cdad725ae8 100644 --- a/libopenage/renderer/stages/world/object.h +++ b/libopenage/renderer/stages/world/object.h @@ -133,7 +133,8 @@ class WorldObject { */ void set_uniforms(std::vector> &&uniforms); - bool within_camera_frustum(const std::shared_ptr &camera); + bool within_camera_frustum(const std::shared_ptr &camera, + const time::time_t &time); /** * Shader uniform IDs for setting uniform values. diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp index bfa745d19d..51ec4878d6 100644 --- a/libopenage/renderer/stages/world/render_stage.cpp +++ b/libopenage/renderer/stages/world/render_stage.cpp @@ -59,7 +59,7 @@ void WorldRenderStage::update() { std::unique_lock lock{this->mutex}; auto current_time = this->clock->get_real_time(); for (auto &obj : this->render_objects) { - if (not obj->within_camera_frustum(this->camera)) { + if (not obj->within_camera_frustum(this->camera, current_time)) { continue; }