Skip to content

Commit

Permalink
Merge pull request #1691 from EdvinLndh/add_camera_boundaries
Browse files Browse the repository at this point in the history
Renderer: Added camera boundaries to CameraManager and clamping #1682.
  • Loading branch information
heinezen authored Nov 7, 2024
2 parents d023a2f + a3376ca commit 2170ff5
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 48 deletions.
1 change: 1 addition & 0 deletions copying.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ _the openage authors_ are:
| Michael Seibt | RoboSchmied | github à roboschmie dawt de |
| Nikhil Ghosh | NikhilGhosh75 | nghosh606 à gmail dawt com |
| Edvin Lindholm | EdvinLndh | edvinlndh à gmail dawt com |
| Jeremiah Morgan | jere8184 | jeremiahmorgan dawt bham à outlook dawt com |

If you're a first-time committer, add yourself to the above list. This is not
just for legal reasons, but also to keep an overview of all those nicknames.
Expand Down
10 changes: 10 additions & 0 deletions libopenage/presenter/presenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,17 @@ void Presenter::init_graphics(bool debug) {
this->camera->resize(w, h);
});

// Camera manager
this->camera_manager = std::make_shared<renderer::camera::CameraManager>(this->camera);
// TODO: Make boundaries dynamic based on map size.
this->camera_manager->set_camera_boundaries(
renderer::camera::CameraBoundaries{
renderer::camera::X_BOUND_MIN,
renderer::camera::X_BOUND_MAX,
renderer::camera::Y_BOUND_MIN,
renderer::camera::Y_BOUND_MAX,
renderer::camera::Z_BOUND_MIN,
renderer::camera::Z_BOUND_MAX});

// Skybox
this->skybox_renderer = std::make_shared<renderer::skybox::SkyboxRenderStage>(
Expand Down
1 change: 1 addition & 0 deletions libopenage/renderer/camera/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_sources(libopenage
boundaries.cpp
camera.cpp
definitions.cpp
frustum_2d.cpp
Expand Down
9 changes: 9 additions & 0 deletions libopenage/renderer/camera/boundaries.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2024-2024 the openage authors. See copying.md for legal info.

#include "boundaries.h"


namespace openage::renderer::camera {


} // namespace openage::renderer::camera
25 changes: 25 additions & 0 deletions libopenage/renderer/camera/boundaries.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2024-2024 the openage authors. See copying.md for legal info.

#pragma once

namespace openage::renderer::camera {

/**
* Defines boundaries for the camera's view.
*/
struct CameraBoundaries {
/// The minimum boundary for the camera's X-coordinate.
float x_min;
/// The maximum boundary for the camera's X-coordinate.
float x_max;
/// The minimum boundary for the camera's Y-coordinate.
float y_min;
/// The maximum boundary for the camera's Y-coordinate.
float y_max;
/// The minimum boundary for the camera's Z-coordinate.
float z_min;
/// The maximum boundary for the camera's Z-coordinate.
float z_max;
};

} // namespace openage::renderer::camera
78 changes: 42 additions & 36 deletions libopenage/renderer/camera/camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,38 +61,7 @@ Camera::Camera(const std::shared_ptr<Renderer> &renderer,
}

void Camera::look_at_scene(Eigen::Vector3f scene_pos) {
if (scene_pos[1] > this->scene_pos[1]) {
// TODO: camera can't look at a position that's
// higher than it's own position
}

// TODO: Although the below method should be faster, calculating and adding the direction
// vector from scene_pos to new_pos may be easier to understand
// i.e. new_pos = scene_pos + b/sin(30) * direction_vec

// due to the fixed angle, the centered scene position
// and the new camera position form a right triangle.
//
// c - + new camera pos
// - |b
// center +------+
// a
//
// we can calculate the new camera position via the offset a
// using the angle and length of side b.
auto y_delta = this->scene_pos[1] - scene_pos[1]; // b (vertical distance)
auto xz_distance = y_delta * std::numbers::sqrt3; // a (horizontal distance); a = b * (cos(30°) / sin(30°))

// get x and z offsets
// the camera is pointed diagonally to the negative x and z axis
// a is the length of the diagonal from camera.xz to scene_pos.xz
// so the x and z offest are sides of a square with the same diagonal
auto side_length = xz_distance / std::numbers::sqrt2;
auto new_pos = Eigen::Vector3f(
scene_pos[0] + side_length,
this->scene_pos[1], // height unchanged
scene_pos[2] + side_length);

auto new_pos = calc_look_at(scene_pos);
this->move_to(new_pos);
}

Expand All @@ -102,15 +71,17 @@ void Camera::look_at_coord(coord::scene3 coord_pos) {
this->look_at_scene(scene_pos);
}

void Camera::move_to(Eigen::Vector3f scene_pos) {
// TODO: Check and set bounds for where the camera can go and check them here
void Camera::move_to(Eigen::Vector3f scene_pos, const CameraBoundaries &camera_boundaries) {
scene_pos[0] = std::clamp(scene_pos[0], camera_boundaries.x_min, camera_boundaries.x_max);
scene_pos[1] = std::clamp(scene_pos[1], camera_boundaries.y_min, camera_boundaries.y_max);
scene_pos[2] = std::clamp(scene_pos[2], camera_boundaries.z_min, camera_boundaries.z_max);

this->scene_pos = scene_pos;
this->moved = true;
}

void Camera::move_rel(Eigen::Vector3f direction, float delta) {
this->move_to(this->scene_pos + (direction * delta));
void Camera::move_rel(Eigen::Vector3f direction, float delta, const CameraBoundaries &camera_boundaries) {
this->move_to(this->scene_pos + (direction * delta), camera_boundaries);
}

void Camera::set_zoom(float zoom) {
Expand Down Expand Up @@ -292,8 +263,43 @@ void Camera::init_uniform_buffer(const std::shared_ptr<Renderer> &renderer) {
this->uniform_buffer = renderer->add_uniform_buffer(ubo_info);
}

Eigen::Vector3f Camera::calc_look_at(Eigen::Vector3f target) {
if (target[1] > this->scene_pos[1]) {
// TODO: camera can't look at a position that's
// higher than it's own position
}

// TODO: Although the below method should be faster, calculating and adding the direction
// vector from scene_pos to new_pos may be easier to understand
// i.e. new_pos = scene_pos + b/sin(30) * direction_vec

// due to the fixed angle, the centered scene position
// and the new camera position form a right triangle.
//
// c - + new camera pos
// - |b
// center +------+
// a
//
// we can calculate the new camera position via the offset a
// using the angle and length of side b.
auto y_delta = this->scene_pos[1] - target[1]; // b (vertical distance)
auto xz_distance = y_delta * std::numbers::sqrt3; // a (horizontal distance); a = b * (cos(30°) / sin(30°))

// get x and z offsets
// the camera is pointed diagonally to the negative x and z axis
// a is the length of the diagonal from camera.xz to scene_pos.xz
// so the x and z offest are sides of a square with the same diagonal
auto side_length = xz_distance / std::numbers::sqrt2;
return Eigen::Vector3f(
target[0] + side_length,
this->scene_pos[1], // height unchanged
target[2] + side_length);
}

inline float Camera::get_real_zoom_factor() const {
return 0.5f * this->default_zoom_ratio * this->zoom;
}


} // namespace openage::renderer::camera
20 changes: 17 additions & 3 deletions libopenage/renderer/camera/camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@

#include <cmath>
#include <cstddef>
#include <limits>
#include <memory>
#include <optional>

#include <eigen3/Eigen/Dense>

#include "coord/pixel.h"
#include "coord/scene.h"
#include "util/vector.h"

#include "renderer/camera/boundaries.h"
#include "renderer/camera/definitions.h"
#include "renderer/camera/frustum_2d.h"
#include "renderer/camera/frustum_3d.h"
Expand Down Expand Up @@ -83,18 +86,21 @@ class Camera {
* Move the camera position in the direction of a given vector.
*
* @param scene_pos New 3D position of the camera in the scene.
* @param camera_boundaries 3D boundaries for the camera.
*/
void move_to(Eigen::Vector3f scene_pos);
void move_to(Eigen::Vector3f scene_pos, const CameraBoundaries &camera_boundaries = DEFAULT_CAM_BOUNDARIES);

/**
* Move the camera position in the direction of a given vector.
* Move the camera position in the direction of a given vector taking the
* camera boundaries into account.
*
* @param direction Direction vector. Added to the current position.
* @param delta Delta for controlling the amount by which the camera is moved. The
* value is multiplied with the directional vector before its applied to
* the positional vector.
* @param camera_boundaries 3D boundaries for the camera.
*/
void move_rel(Eigen::Vector3f direction, float delta = 1.0f);
void move_rel(Eigen::Vector3f direction, float delta = 1.0f, const CameraBoundaries &camera_boundaries = DEFAULT_CAM_BOUNDARIES);

/**
* Set the zoom level of the camera. Values smaller than 1.0f let the
Expand Down Expand Up @@ -200,6 +206,7 @@ class Camera {
*/
const Frustum3d get_frustum_3d() const;


private:
/**
* Create the uniform buffer for the camera.
Expand All @@ -208,6 +215,13 @@ class Camera {
*/
void init_uniform_buffer(const std::shared_ptr<Renderer> &renderer);

/**
* Calculates the camera's position needed to center its view on the given target.
*
* @param target The target position in the 3D scene the camera should focus on.
*/
Eigen::Vector3f calc_look_at(Eigen::Vector3f target);

/**
* Get the zoom factor applied to the camera projection.
*
Expand Down
21 changes: 21 additions & 0 deletions libopenage/renderer/camera/definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
#pragma once

#include <eigen3/Eigen/Dense>
#include <limits>

#include "renderer/camera/boundaries.h"

namespace openage::renderer::camera {

Expand Down Expand Up @@ -58,4 +60,23 @@ static constexpr float DEFAULT_MAX_ZOOM_OUT = 64.0f;
*/
static constexpr float DEFAULT_ZOOM_RATIO = 1.0f / 49;

static constexpr CameraBoundaries DEFAULT_CAM_BOUNDARIES{
std::numeric_limits<float>::lowest(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::lowest(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::lowest(),
std::numeric_limits<float>::max()};

/**
* Constant values for the camera bounds (based on current fix terrain grid of 20x20).
* TODO: Make boundaries dynamic based on map size.
*/
static constexpr float X_BOUND_MIN = 12.25f;
static constexpr float X_BOUND_MAX = 32.25f;
static constexpr float Y_BOUND_MIN = 0.0f;
static constexpr float Y_BOUND_MAX = 20.0f;
static constexpr float Z_BOUND_MIN = -8.25f;
static constexpr float Z_BOUND_MAX = 12.25f;

} // namespace openage::renderer::camera
12 changes: 12 additions & 0 deletions libopenage/renderer/demo/demo_3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ void renderer_demo_3(const util::Path &path) {
// it is updated each frame before the render stages
auto cam_manager = std::make_shared<renderer::camera::CameraManager>(camera);

// Set boundaries for camera movement in the scene
// this restricts camera movement to the area defined by the boundaries
// i.e. the map terrain in this case
cam_manager->set_camera_boundaries(
camera::CameraBoundaries{
12.25f,
22.25f,
0.0f,
20.0f,
2.25f,
12.25f});

// Render stages
// every stage use a different subrenderer that manages renderables,
// shaders, textures & more.
Expand Down
22 changes: 14 additions & 8 deletions libopenage/renderer/stages/camera/manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
#include "manager.h"

#include <eigen3/Eigen/Dense>
#include <numbers>

#include "renderer/camera/camera.h"
#include "renderer/uniform_buffer.h"
#include "renderer/uniform_input.h"

namespace openage::renderer::camera {

CameraManager::CameraManager(const std::shared_ptr<renderer::camera::Camera> &camera) :
CameraManager::CameraManager(const std::shared_ptr<renderer::camera::Camera> &camera,
const CameraBoundaries &camera_boundaries) :
camera{camera},
move_motion_directions{static_cast<int>(MoveDirection::NONE)},
zoom_motion_direction{static_cast<int>(ZoomDirection::NONE)},
move_motion_speed{0.2f},
zoom_motion_speed{0.05f} {
zoom_motion_speed{0.05f},
camera_boundaries{camera_boundaries} {
this->uniforms = this->camera->get_uniform_buffer()->new_uniform_input(
"view",
camera->get_view_matrix(),
Expand All @@ -33,18 +35,18 @@ void CameraManager::move_frame(MoveDirection direction, float speed) {
case MoveDirection::LEFT:
// half the speed because the relationship between forward/back and
// left/right is 1:2 in our ortho projection.
this->camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, 1.0f), speed / 2);
this->camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, 1.0f), speed / 2, this->camera_boundaries);
break;
case MoveDirection::RIGHT:
// half the speed because the relationship between forward/back and
// left/right is 1:2 in our ortho projection.
this->camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, -1.0f), speed / 2);
this->camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, -1.0f), speed / 2, this->camera_boundaries);
break;
case MoveDirection::FORWARD:
this->camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, -1.0f), speed);
this->camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, -1.0f), speed, this->camera_boundaries);
break;
case MoveDirection::BACKWARD:
this->camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, 1.0f), speed);
this->camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, 1.0f), speed, this->camera_boundaries);
break;

default:
Expand All @@ -66,6 +68,10 @@ void CameraManager::zoom_frame(ZoomDirection direction, float speed) {
}
}

void CameraManager::set_camera_boundaries(const CameraBoundaries &camera_boundaries) {
this->camera_boundaries = camera_boundaries;
}

void CameraManager::update_motion() {
if (this->move_motion_directions != static_cast<int>(MoveDirection::NONE)) {
Eigen::Vector3f move_dir{0.0f, 0.0f, 0.0f};
Expand All @@ -83,7 +89,7 @@ void CameraManager::update_motion() {
move_dir += Eigen::Vector3f(1.0f, 0.0f, 1.0f);
}

this->camera->move_rel(move_dir, this->move_motion_speed);
this->camera->move_rel(move_dir, this->move_motion_speed, this->camera_boundaries);
}

if (this->zoom_motion_direction != static_cast<int>(ZoomDirection::NONE)) {
Expand Down
Loading

0 comments on commit 2170ff5

Please sign in to comment.