From ad6a87052a135d7a75df8c601c5c8ee56f5e2b9c Mon Sep 17 00:00:00 2001 From: Nikhil Ghosh Date: Thu, 25 Apr 2024 23:14:02 -0400 Subject: [PATCH 01/32] Fixed bug with opening files with \r on windows --- libopenage/renderer/resources/parser/common.cpp | 8 +++++++- libopenage/renderer/resources/parser/parse_sprite.cpp | 4 ++-- libopenage/renderer/resources/parser/parse_terrain.cpp | 4 ++-- libopenage/renderer/resources/parser/parse_texture.cpp | 9 +++++++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/libopenage/renderer/resources/parser/common.cpp b/libopenage/renderer/resources/parser/common.cpp index 30fa97118c..ab6a1b205f 100644 --- a/libopenage/renderer/resources/parser/common.cpp +++ b/libopenage/renderer/resources/parser/common.cpp @@ -20,7 +20,13 @@ TextureData parse_texture(const std::vector &args) { texture.texture_id = std::stoul(args[1]); // Call substr() to get rid of the quotes - texture.path = args[2].substr(1, args[2].size() - 2); + // If the line ends in a carriage return, remove it as well + if (args[2][args[2].size() - 1] == '\r') { + texture.path = args[2].substr(1, args[2].size() - 3); + } + else { + texture.path = args[2].substr(1, args[2].size() - 2); + } return texture; } diff --git a/libopenage/renderer/resources/parser/parse_sprite.cpp b/libopenage/renderer/resources/parser/parse_sprite.cpp index 9ea4afac1c..0974f98342 100644 --- a/libopenage/renderer/resources/parser/parse_sprite.cpp +++ b/libopenage/renderer/resources/parser/parse_sprite.cpp @@ -195,8 +195,8 @@ Animation2dInfo parse_sprite_file(const util::Path &file, })}; for (auto line : lines) { - // Skip empty lines and comments - if (line.empty() || line.substr(0, 1) == "#") { + // Skip empty lines, lines with carriage returns, and comments + if (line.empty() || line.substr(0, 1) == "#" || line[0] == '\r') { continue; } std::vector args{util::split(line, ' ')}; diff --git a/libopenage/renderer/resources/parser/parse_terrain.cpp b/libopenage/renderer/resources/parser/parse_terrain.cpp index 4330606091..26dc77f10b 100644 --- a/libopenage/renderer/resources/parser/parse_terrain.cpp +++ b/libopenage/renderer/resources/parser/parse_terrain.cpp @@ -200,8 +200,8 @@ TerrainInfo parse_terrain_file(const util::Path &file, })}; for (auto line : lines) { - // Skip empty lines and comments - if (line.empty() || line.substr(0, 1) == "#") { + // Skip empty lines, lines with carriage returns, and comments + if (line.empty() || line.substr(0, 1) == "#" || line[0] == '\r') { continue; } std::vector args{util::split(line, ' ')}; diff --git a/libopenage/renderer/resources/parser/parse_texture.cpp b/libopenage/renderer/resources/parser/parse_texture.cpp index 7da91211f4..a0af8d6f73 100644 --- a/libopenage/renderer/resources/parser/parse_texture.cpp +++ b/libopenage/renderer/resources/parser/parse_texture.cpp @@ -56,6 +56,11 @@ std::string parse_imagefile(const std::vector &args) { // it should result in an error if wrongly used here. // Call substr() to get rid of the quotes + // If the line ends in a carriage return, remove it as well + if (args[1][args[1].size() - 1] == '\r') { + return args[1].substr(1, args[1].size() - 3); + } + return args[1].substr(1, args[1].size() - 2); } @@ -179,8 +184,8 @@ Texture2dInfo parse_texture_file(const util::Path &file) { })}; for (auto line : lines) { - // Skip empty lines and comments - if (line.empty() || line.substr(0, 1) == "#") { + // Skip empty lines, lines with carriage returns, and comments + if (line.empty() || line.substr(0, 1) == "#" || line[0] == '\r') { continue; } std::vector args{util::split(line, ' ')}; From 07e7c62408460d4da33ee7b2907eebd1c7f635bf Mon Sep 17 00:00:00 2001 From: Nikhil Ghosh Date: Thu, 25 Apr 2024 23:14:54 -0400 Subject: [PATCH 02/32] Implemented frustum culling --- libopenage/renderer/camera/CMakeLists.txt | 1 + libopenage/renderer/camera/camera.cpp | 30 +++- libopenage/renderer/camera/camera.h | 24 ++- libopenage/renderer/camera/frustum.cpp | 165 ++++++++++++++++++ libopenage/renderer/camera/frustum.h | 46 +++++ libopenage/renderer/stages/world/object.cpp | 9 + libopenage/renderer/stages/world/object.h | 2 + .../renderer/stages/world/render_stage.cpp | 6 + 8 files changed, 279 insertions(+), 4 deletions(-) create mode 100644 libopenage/renderer/camera/frustum.cpp create mode 100644 libopenage/renderer/camera/frustum.h diff --git a/libopenage/renderer/camera/CMakeLists.txt b/libopenage/renderer/camera/CMakeLists.txt index f4ae421320..43a49cc1c7 100644 --- a/libopenage/renderer/camera/CMakeLists.txt +++ b/libopenage/renderer/camera/CMakeLists.txt @@ -1,3 +1,4 @@ add_sources(libopenage camera.cpp + frustum.cpp ) diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index 884aceca1b..d43d30b102 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -25,11 +25,15 @@ Camera::Camera(const std::shared_ptr &renderer, moved{true}, zoom_changed{true}, view{Eigen::Matrix4f::Identity()}, - proj{Eigen::Matrix4f::Identity()} { + proj{Eigen::Matrix4f::Identity()}, + frustum_culling{false} { this->look_at_scene(Eigen::Vector3f(0.0f, 0.0f, 0.0f)); this->init_uniform_buffer(renderer); + 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); + log::log(INFO << "Created new camera at position " << "(" << this->scene_pos[0] << ", " << this->scene_pos[1] @@ -41,7 +45,8 @@ Camera::Camera(const std::shared_ptr &renderer, Eigen::Vector3f scene_pos, float zoom, float max_zoom_out, - float default_zoom_ratio) : + float default_zoom_ratio, + bool frustum_culling) : scene_pos{scene_pos}, viewport_size{viewport_size}, zoom{zoom}, @@ -51,9 +56,13 @@ Camera::Camera(const std::shared_ptr &renderer, zoom_changed{true}, viewport_changed{true}, view{Eigen::Matrix4f::Identity()}, - proj{Eigen::Matrix4f::Identity()} { + proj{Eigen::Matrix4f::Identity()}, + frustum_culling{frustum_culling} { this->init_uniform_buffer(renderer); + 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); + log::log(INFO << "Created new camera at position " << "(" << this->scene_pos[0] << ", " << this->scene_pos[1] @@ -107,6 +116,9 @@ void Camera::move_to(Eigen::Vector3f scene_pos) { this->scene_pos = scene_pos; this->moved = true; + + 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); } void Camera::move_rel(Eigen::Vector3f direction, float delta) { @@ -274,4 +286,16 @@ void Camera::init_uniform_buffer(const std::shared_ptr &renderer) { this->uniform_buffer = renderer->add_uniform_buffer(ubo_info); } +bool Camera::using_frustum_culling() const { + return this->frustum_culling; +} + +bool Camera::is_in_frustum(Eigen::Vector3f pos) const{ + if (!this->frustum_culling) { + return true; + } + + return frustum.is_in_frustum(pos); +} + } // namespace openage::renderer::camera diff --git a/libopenage/renderer/camera/camera.h b/libopenage/renderer/camera/camera.h index c8c5c23076..56fdccef8a 100644 --- a/libopenage/renderer/camera/camera.h +++ b/libopenage/renderer/camera/camera.h @@ -12,6 +12,8 @@ #include "coord/scene.h" #include "util/vector.h" +#include "frustum.h" + namespace openage::renderer { class Renderer; class UniformBuffer; @@ -30,6 +32,9 @@ static const Eigen::Vector3f cam_direction{ -1 * (std::sqrt(6.f) / 4), }; +static const float near_distance = 0.01f; +static const float far_distance = 100.0f; + /** * Camera for selecting what part of the ingame world is displayed. * @@ -58,13 +63,15 @@ class Camera { * @param zoom Zoom level of the camera (defaults to 1.0f). * @param max_zoom_out Maximum zoom out level (defaults to 64.0f). * @param default_zoom_ratio Default zoom level calibration (defaults to (1.0f / 49)). + * @param frustum_culling Is frustum culling enables (defaults to false). */ Camera(const std::shared_ptr &renderer, util::Vector2s viewport_size, Eigen::Vector3f scene_pos, float zoom = 1.0f, float max_zoom_out = 64.0f, - float default_zoom_ratio = 1.0f / 49); + float default_zoom_ratio = 1.0f / 49, + bool frustum_culling = false); ~Camera() = default; /** @@ -188,6 +195,10 @@ class Camera { */ const std::shared_ptr &get_uniform_buffer() const; + bool using_frustum_culling() const; + + bool is_in_frustum(Eigen::Vector3f pos) const; + private: /** * Create the uniform buffer for the camera. @@ -281,6 +292,17 @@ class Camera { * Uniform buffer for the camera matrices. */ std::shared_ptr uniform_buffer; + + /** + * Is frustum culling enabled? If true, + */ + bool frustum_culling; + + /** + * The frustum used to cull objects + * Will be recalculated regardless of whether frustum culling is enabled + */ + Frustum frustum; }; } // namespace camera diff --git a/libopenage/renderer/camera/frustum.cpp b/libopenage/renderer/camera/frustum.cpp new file mode 100644 index 0000000000..d79058f411 --- /dev/null +++ b/libopenage/renderer/camera/frustum.cpp @@ -0,0 +1,165 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#include "frustum.h" + +#include +#include +#include +#include + +#include "coord/pixel.h" +#include "coord/scene.h" +#include "renderer/renderer.h" +#include "renderer/resources/buffer_info.h" + +namespace openage::renderer::camera { + +/* + Eigen::Vector3f top_face_normal; + float top_face_distance; + + Eigen::Vector3f bottom_face_normal; + float bottom_face_distance; + + Eigen::Vector3f right_face_normal; + float right_face_distance; + + Eigen::Vector3f left_face_normal; + float left_face_distance; + + Eigen::Vector3f far_face_normal; + float far_face_distance; + + Eigen::Vector3f near_face_normal; + float near_face_distance; +*/ + +Frustum::Frustum() : + top_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, + top_face_distance{0.0f}, + bottom_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, + bottom_face_distance{0.0f}, + right_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, + right_face_distance{0.0f}, + left_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, + left_face_distance{0.0f}, + far_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, + far_face_distance{0.0f}, + near_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, + near_face_distance{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) { + // offsets are adjusted by zoom + // this is the same calculation as for the projection matrix + float halfscreenwidth = viewport_size[0] / 2; + float halfscreenheight = viewport_size[1] / 2; + + float halfwidth = halfscreenwidth * real_zoom; + float halfheight = halfscreenheight * real_zoom; + + Eigen::Vector3f direction = cam_direction.normalized(); + Eigen::Vector3f eye = scene_pos; + Eigen::Vector3f center = scene_pos + direction; + + // calculate up (u) and right (s) vectors for camera + // these define the camera plane in 3D space that the input + Eigen::Vector3f f = center - eye; + f.normalize(); + Eigen::Vector3f s = f.cross(up_direction); + s.normalize(); + Eigen::Vector3f u = s.cross(f); + u.normalize(); + + Eigen::Vector3f near_position = scene_pos - direction * near_distance; + Eigen::Vector3f far_position = scene_pos + direction * far_distance; + + 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; + Eigen::Vector3f near_bottom_right = near_position + s * halfwidth - u * halfheight; + + Eigen::Vector3f far_top_left = far_position - s * halfwidth + u * halfheight; + Eigen::Vector3f far_top_right = far_position + s * halfwidth + u * halfheight; + Eigen::Vector3f far_bottom_left = far_position - s * halfwidth - u * halfheight; + Eigen::Vector3f far_bottom_right = far_position + s * halfwidth - u * halfheight; + + this->near_face_normal = -1.0f * cam_direction.normalized(); + this->far_face_normal = 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->left_face_normal = (near_bottom_left - near_top_left).cross(far_bottom_left - near_bottom_left); + this->right_face_normal = (far_bottom_right - near_bottom_right).cross(near_bottom_right - near_top_right); + this->top_face_normal = (near_top_right - near_top_left).cross(near_top_left - far_top_left); + this->bottom_face_normal = (near_bottom_left - far_bottom_left).cross(near_bottom_right - near_bottom_left); + + log::log(INFO << "Compute near and far points"); + log::log(INFO << "Near Top Left: " << near_top_left[0] << ", " << near_top_left[1] << ", " << near_top_left[2]); + log::log(INFO << "Near Top Right: " << near_top_right[0] << ", " << near_top_right[1] << ", " << near_top_right[2]); + log::log(INFO << "Near Bottom Left: " << near_bottom_left[0] << ", " << near_bottom_left[1] << ", " << near_bottom_left[2]); + log::log(INFO << "Near Bottom Right: " << near_bottom_right[0] << ", " << near_bottom_right[1] << ", " << near_bottom_right[2]); + log::log(INFO << "Far Top Left: " << far_top_left[0] << ", " << far_top_left[1] << ", " << far_top_left[2]); + log::log(INFO << "Far Top Right: " << far_top_right[0] << ", " << far_top_right[1] << ", " << far_top_right[2]); + log::log(INFO << "Far Bottom Left: " << far_bottom_left[0] << ", " << far_bottom_left[1] << ", " << far_bottom_left[2]); + log::log(INFO << "Far Bottom Right: " << far_bottom_right[0] << ", " << far_bottom_right[1] << ", " << far_bottom_right[2]); + + this->left_face_normal.normalize(); + this->right_face_normal.normalize(); + this->top_face_normal.normalize(); + this->bottom_face_normal.normalize(); + + this->left_face_distance = 1.f * this->left_face_normal.dot(near_bottom_left); + this->right_face_distance = 1.f * this->right_face_normal.dot(far_bottom_right); + this->top_face_distance = 1.f * this->top_face_normal.dot(near_top_right); + this->bottom_face_distance = 1.f * this->bottom_face_normal.dot(near_bottom_left); + + log::log(INFO << "Computed Frustum with planes \n" + << "Top: <" << this->top_face_normal[0] << ", " << this->top_face_normal[1] << ", " << this->top_face_normal[2] << ">, " << this->top_face_distance << "\n" + << "Bottom: <" << this->bottom_face_normal[0] << ", " << this->bottom_face_normal[1] << ", " << this->bottom_face_normal[2] << ">, " << this->bottom_face_distance << "\n" + << "Left: <" << this->left_face_normal[0] << ", " << this->left_face_normal[1] << ", " << this->left_face_normal[2] << ">, " << this->left_face_distance << "\n" + << "Right: <" << this->right_face_normal[0] << ", " << this->right_face_normal[1] << ", " << this->right_face_normal[2] << ">, " << this->right_face_distance << "\n" + << "Far: <" << this->far_face_normal[0] << ", " << this->far_face_normal[1] << ", " << this->far_face_normal[2] << ">, " << this->far_face_distance << "\n" + << "Near: <" << this->near_face_normal[0] << ", " << this->near_face_normal[1] << ", " << this->near_face_normal[2] << ">, " << this->near_face_distance << "\n" + ); +} + +bool Frustum::is_in_frustum(Eigen::Vector3f& pos) const { + float distance; + + distance = this->top_face_normal.dot(pos) - this->top_face_distance; + if (distance < 0) { + return false; + } + + distance = this->bottom_face_normal.dot(pos) - this->bottom_face_distance; + if (distance < 0) { + return false; + } + + distance = this->left_face_normal.dot(pos) - this->left_face_distance; + if (distance < 0) { + return false; + } + + distance = this->right_face_normal.dot(pos) - this->right_face_distance; + if (distance < 0) { + return false; + } + + distance = this->far_face_normal.dot(pos) - this->far_face_distance; + if (distance < 0) { + return false; + } + + distance = this->bottom_face_normal.dot(pos) - this->bottom_face_distance; + if (distance < 0) { + return false; + } + + return true; +} + +} \ No newline at end of file diff --git a/libopenage/renderer/camera/frustum.h b/libopenage/renderer/camera/frustum.h new file mode 100644 index 0000000000..8dfe9372c5 --- /dev/null +++ b/libopenage/renderer/camera/frustum.h @@ -0,0 +1,46 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#pragma once + +#include +#include +#include + +#include + +#include "coord/pixel.h" +#include "coord/scene.h" +#include "util/vector.h" + +namespace openage::renderer::camera { + +class Frustum +{ +public: + 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); + + bool is_in_frustum(Eigen::Vector3f& pos) const; + +private: + Eigen::Vector3f top_face_normal; + float top_face_distance; + + Eigen::Vector3f bottom_face_normal; + float bottom_face_distance; + + Eigen::Vector3f right_face_normal; + float right_face_distance; + + Eigen::Vector3f left_face_normal; + float left_face_distance; + + Eigen::Vector3f far_face_normal; + float far_face_distance; + + Eigen::Vector3f near_face_normal; + float near_face_distance; + +}; +} // namespace openage::renderer::camera diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp index 3b9edd6d3d..d8d9120c69 100644 --- a/libopenage/renderer/stages/world/object.cpp +++ b/libopenage/renderer/stages/world/object.cpp @@ -224,4 +224,13 @@ void WorldObject::set_uniforms(std::vectorlayer_uniforms = std::move(uniforms); } +bool WorldObject::within_camera_frustum(const std::shared_ptr &camera) { + if (!camera->using_frustum_culling()) { + return true; + } + + Eigen::Vector3f current_pos = this->position.get(this->last_update).to_world_space(); + return camera->is_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 c5e0aa8197..17da70be75 100644 --- a/libopenage/renderer/stages/world/object.h +++ b/libopenage/renderer/stages/world/object.h @@ -133,6 +133,8 @@ class WorldObject { */ void set_uniforms(std::vector> &&uniforms); + bool within_camera_frustum(const std::shared_ptr &camera); + /** * 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 05827eb645..08bb7c7a8d 100644 --- a/libopenage/renderer/stages/world/render_stage.cpp +++ b/libopenage/renderer/stages/world/render_stage.cpp @@ -59,6 +59,10 @@ void WorldRenderStage::update() { std::unique_lock lock{this->mutex}; auto current_time = this->clock->get_real_time(); for (auto &obj : this->render_objects) { + if (!obj->within_camera_frustum(this->camera)) { + continue; + } + obj->fetch_updates(current_time); if (obj->is_changed()) { if (obj->requires_renderable()) { @@ -96,6 +100,8 @@ void WorldRenderStage::update() { } obj->update_uniforms(current_time); } + + std::cout << this->render_pass->renderables.size() << std::flush; } void WorldRenderStage::resize(size_t width, size_t height) { From e463962edab570b43bca5b7b1993fe4f2bef4475 Mon Sep 17 00:00:00 2001 From: Nikhil Ghosh Date: Thu, 25 Apr 2024 23:15:14 -0400 Subject: [PATCH 03/32] Implemented stresstest 1 --- libopenage/renderer/demo/CMakeLists.txt | 1 + libopenage/renderer/demo/stresstest_1.cpp | 222 ++++++++++++++++++++++ libopenage/renderer/demo/stresstest_1.h | 16 ++ libopenage/renderer/demo/tests.cpp | 6 +- 4 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 libopenage/renderer/demo/stresstest_1.cpp create mode 100644 libopenage/renderer/demo/stresstest_1.h diff --git a/libopenage/renderer/demo/CMakeLists.txt b/libopenage/renderer/demo/CMakeLists.txt index 24a5c20d84..aaa30bc906 100644 --- a/libopenage/renderer/demo/CMakeLists.txt +++ b/libopenage/renderer/demo/CMakeLists.txt @@ -6,6 +6,7 @@ add_sources(libopenage demo_4.cpp demo_5.cpp stresstest_0.cpp + stresstest_1.cpp tests.cpp util.cpp ) diff --git a/libopenage/renderer/demo/stresstest_1.cpp b/libopenage/renderer/demo/stresstest_1.cpp new file mode 100644 index 0000000000..05a357a2ef --- /dev/null +++ b/libopenage/renderer/demo/stresstest_1.cpp @@ -0,0 +1,222 @@ +// Copyright 2023-2023 the openage authors. See copying.md for legal info. + +#include "stresstest_1.h" + +#include + +#include "coord/tile.h" +#include "renderer/camera/camera.h" +#include "renderer/gui/integration/public/gui_application_with_logger.h" +#include "renderer/opengl/window.h" +#include "renderer/render_factory.h" +#include "renderer/resources/assets/asset_manager.h" +#include "renderer/resources/shader_source.h" +#include "renderer/stages/camera/manager.h" +#include "renderer/stages/screen/render_stage.h" +#include "renderer/stages/skybox/render_stage.h" +#include "renderer/stages/terrain/render_entity.h" +#include "renderer/stages/terrain/render_stage.h" +#include "renderer/stages/world/render_entity.h" +#include "renderer/stages/world/render_stage.h" +#include "renderer/uniform_buffer.h" +#include "time/clock.h" +#include "util/fps.h" + +namespace openage::renderer::tests { +void renderer_stresstest_1(const util::Path &path) { + auto qtapp = std::make_shared(); + + auto window = std::make_shared("openage renderer test", 1024, 768, true); + auto renderer = window->make_renderer(); + + // Clock required by world renderer for timing animation frames + auto clock = std::make_shared(); + + // Camera + // our viewport into the game world + // on this one, enable frustum culling + auto camera = std::make_shared(renderer, + window->get_size(), + Eigen::Vector3f{17.0f, 10.0f, 7.0f}, + 1.f, + 64.f, + 1.f / 49.f, + true); + auto cam_unifs = camera->get_uniform_buffer()->create_empty_input(); + cam_unifs->update( + "view", + camera->get_view_matrix(), + "proj", + camera->get_projection_matrix()); + camera->get_uniform_buffer()->update_uniforms(cam_unifs); + + // Render stages + // every stage use a different subrenderer that manages renderables, + // shaders, textures & more. + std::vector> + render_passes{}; + + // TODO: Make this optional for subrenderers? + auto asset_manager = std::make_shared( + renderer, + path["assets"]["test"]); + + // Renders the background + auto skybox_renderer = std::make_shared( + window, + renderer, + path["assets"]["shaders"]); + skybox_renderer->set_color(1.0f, 0.5f, 0.0f, 1.0f); // orange color + + // Renders the terrain in 3D + auto terrain_renderer = std::make_shared( + window, + renderer, + camera, + path["assets"]["shaders"], + asset_manager, + clock); + + // Renders units/buildings/other objects + auto world_renderer = std::make_shared( + window, + renderer, + camera, + path["assets"]["shaders"], + asset_manager, + clock); + + // Store the render passes of the renderers + // The order is important as its also the order in which they + // are rendered and drawn onto the screen. + render_passes.push_back(skybox_renderer->get_render_pass()); + render_passes.push_back(terrain_renderer->get_render_pass()); + render_passes.push_back(world_renderer->get_render_pass()); + + // Final output on screen has its own subrenderer + // It takes the outputs of all previous render passes + // and blends them together + auto screen_renderer = std::make_shared( + window, + renderer, + path["assets"]["shaders"]); + std::vector> targets{}; + for (auto &pass : render_passes) { + targets.push_back(pass->get_target()); + } + screen_renderer->set_render_targets(targets); + + window->add_resize_callback([&](size_t, size_t, double /*scale*/) { + // Acquire the render targets for all previous passes + std::vector> targets{}; + for (size_t i = 0; i < render_passes.size() - 1; ++i) { + targets.push_back(render_passes[i]->get_target()); + } + screen_renderer->set_render_targets(targets); + }); + + render_passes.push_back(screen_renderer->get_render_pass()); + + // Create some entities to populate the scene + auto render_factory = std::make_shared(terrain_renderer, world_renderer); + + // Fill a 10x10 terrain grid with height values + auto terrain_size = util::Vector2s{10, 10}; + std::vector> tiles{}; + tiles.reserve(terrain_size[0] * terrain_size[1]); + for (size_t i = 0; i < terrain_size[0] * terrain_size[1]; ++i) { + tiles.emplace_back(0.0f, "./textures/test_terrain.terrain"); + } + + // Create entity for terrain rendering + auto terrain0 = render_factory->add_terrain_render_entity(terrain_size, + coord::tile_delta{0, 0}); + + // send the terrain data to the terrain renderer + terrain0->update(terrain_size, tiles); + + std::vector> render_entities{}; + auto add_world_entity = [&](const coord::phys3 initial_pos, + const time::time_t time) { + const auto animation_path = "./textures/test_tank_mirrored.sprite"; + + auto position = curve::Continuous{nullptr, 0, "", nullptr, coord::phys3(0, 0, 0)}; + position.set_insert(time, initial_pos); + position.set_insert(time + 1, initial_pos + coord::phys3_delta{0, 4, 0}); + position.set_insert(time + 2, initial_pos + coord::phys3_delta{4, 8, 0}); + position.set_insert(time + 3, initial_pos + coord::phys3_delta{8, 8, 0}); + position.set_insert(time + 4, initial_pos + coord::phys3_delta{12, 4, 0}); + position.set_insert(time + 5, initial_pos + coord::phys3_delta{12, 0, 0}); + position.set_insert(time + 6, initial_pos + coord::phys3_delta{12, -4, 0}); + position.set_insert(time + 7, initial_pos + coord::phys3_delta{4, -4, 0}); + position.set_insert(time + 8, initial_pos); + + auto angle = curve::Segmented{nullptr, 0}; + angle.set_insert(time, coord::phys_angle_t::from_int(315)); + angle.set_insert_jump(time + 1, coord::phys_angle_t::from_int(315), coord::phys_angle_t::from_int(270)); + angle.set_insert_jump(time + 2, coord::phys_angle_t::from_int(270), coord::phys_angle_t::from_int(225)); + angle.set_insert_jump(time + 3, coord::phys_angle_t::from_int(225), coord::phys_angle_t::from_int(180)); + angle.set_insert_jump(time + 4, coord::phys_angle_t::from_int(180), coord::phys_angle_t::from_int(135)); + angle.set_insert_jump(time + 5, coord::phys_angle_t::from_int(135), coord::phys_angle_t::from_int(90)); + angle.set_insert_jump(time + 6, coord::phys_angle_t::from_int(90), coord::phys_angle_t::from_int(45)); + angle.set_insert_jump(time + 7, coord::phys_angle_t::from_int(45), coord::phys_angle_t::from_int(0)); + angle.set_insert_jump(time + 8, coord::phys_angle_t::from_int(0), coord::phys_angle_t::from_int(315)); + + auto entity = render_factory->add_world_render_entity(); + entity->update(render_entities.size(), + position, + angle, + animation_path, + time); + render_entities.push_back(entity); + }; + + // Stop after 8000 entities + size_t entity_limit = 8000; + + clock->start(); + + util::FrameCounter timer; + + add_world_entity(coord::phys3(0.0f, 10.0f, 0.0f), clock->get_time()); + time::time_t next_entity = clock->get_real_time() + 0.1; + while (render_entities.size() <= entity_limit) { + // Print FPS + timer.frame(); + std::cout + << "Entities: " << render_entities.size() + << " -- " + << "FPS: " << timer.fps << "\r" << std::flush; + + qtapp->process_events(); + + // Advance time + clock->update_time(); + auto current_time = clock->get_real_time(); + if (current_time > next_entity) { + add_world_entity(coord::phys3(0.0f, 10.0f, 0.0f), clock->get_time()); + add_world_entity(coord::phys3(-1.f, 9.0f, 0.0f), clock->get_time()); + next_entity = current_time + 0.1; + } + + // Update the renderables of the subrenderers + terrain_renderer->update(); + world_renderer->update(); + + // Draw everything + for (auto &pass : render_passes) { + renderer->render(pass); + } + + renderer->check_error(); + + // Display final output on screen + window->update(); + } + + clock->stop(); + log::log(MSG(info) << "Stopped after rendering " << render_entities.size() << " entities"); + + window->close(); +} +} \ No newline at end of file diff --git a/libopenage/renderer/demo/stresstest_1.h b/libopenage/renderer/demo/stresstest_1.h new file mode 100644 index 0000000000..260296201f --- /dev/null +++ b/libopenage/renderer/demo/stresstest_1.h @@ -0,0 +1,16 @@ +// Copyright 2023-2023 the openage authors. See copying.md for legal info. + +#pragma once + +#include "util/path.h" + +namespace openage::renderer::tests { + +/** + * Stresstest for the renderer's frustum culling feature. + * + * @param path Path to the openage asset directory. + */ +void renderer_stresstest_1(const util::Path &path); + +} \ No newline at end of file diff --git a/libopenage/renderer/demo/tests.cpp b/libopenage/renderer/demo/tests.cpp index 95f6bd40af..30961a6c95 100644 --- a/libopenage/renderer/demo/tests.cpp +++ b/libopenage/renderer/demo/tests.cpp @@ -12,7 +12,7 @@ #include "renderer/demo/demo_4.h" #include "renderer/demo/demo_5.h" #include "renderer/demo/stresstest_0.h" - +#include "renderer/demo/stresstest_1.h" namespace openage::renderer::tests { @@ -53,7 +53,9 @@ OAAPI void renderer_stresstest(int demo_id, const util::Path &path) { case 0: renderer_stresstest_0(path); break; - + case 1: + renderer_stresstest_1(path); + break; default: log::log(MSG(err) << "Unknown renderer stresstest requested: " << demo_id << "."); break; From 84fa57bc485c1c5ac7027dea05234ab3e71f46b6 Mon Sep 17 00:00:00 2001 From: Nikhil Ghosh Date: Thu, 25 Apr 2024 23:32:55 -0400 Subject: [PATCH 04/32] Added additional comments to the frustum culling logic --- libopenage/renderer/camera/camera.cpp | 3 ++ libopenage/renderer/camera/camera.h | 3 +- libopenage/renderer/camera/frustum.cpp | 51 ++++---------------------- 3 files changed, 13 insertions(+), 44 deletions(-) diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index d43d30b102..fd94c2ce57 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -31,6 +31,7 @@ Camera::Camera(const std::shared_ptr &renderer, this->init_uniform_buffer(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); @@ -60,6 +61,7 @@ Camera::Camera(const std::shared_ptr &renderer, frustum_culling{frustum_culling} { this->init_uniform_buffer(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); @@ -117,6 +119,7 @@ void Camera::move_to(Eigen::Vector3f scene_pos) { this->scene_pos = 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); } diff --git a/libopenage/renderer/camera/camera.h b/libopenage/renderer/camera/camera.h index 56fdccef8a..bc4959f589 100644 --- a/libopenage/renderer/camera/camera.h +++ b/libopenage/renderer/camera/camera.h @@ -294,7 +294,8 @@ class Camera { std::shared_ptr uniform_buffer; /** - * Is frustum culling enabled? If true, + * Is frustum culling enabled? If true, perform frustum culling. + * If false, all frustum checks will return true */ bool frustum_culling; diff --git a/libopenage/renderer/camera/frustum.cpp b/libopenage/renderer/camera/frustum.cpp index d79058f411..459cc7226c 100644 --- a/libopenage/renderer/camera/frustum.cpp +++ b/libopenage/renderer/camera/frustum.cpp @@ -14,26 +14,6 @@ namespace openage::renderer::camera { -/* - Eigen::Vector3f top_face_normal; - float top_face_distance; - - Eigen::Vector3f bottom_face_normal; - float bottom_face_distance; - - Eigen::Vector3f right_face_normal; - float right_face_distance; - - Eigen::Vector3f left_face_normal; - float left_face_distance; - - Eigen::Vector3f far_face_normal; - float far_face_distance; - - Eigen::Vector3f near_face_normal; - float near_face_distance; -*/ - Frustum::Frustum() : top_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, top_face_distance{0.0f}, @@ -75,6 +55,7 @@ void Frustum::Recalculate(util::Vector2s &viewport_size, float near_distance, fl 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) 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; @@ -85,48 +66,32 @@ void Frustum::Recalculate(util::Vector2s &viewport_size, float near_distance, fl Eigen::Vector3f far_bottom_left = far_position - s * halfwidth - u * halfheight; 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_distance = this->near_face_normal.dot(near_position) * -1.0f; this->far_face_distance = this->far_face_normal.dot(far_position) * -1.0f; + // 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); this->right_face_normal = (far_bottom_right - near_bottom_right).cross(near_bottom_right - near_top_right); this->top_face_normal = (near_top_right - near_top_left).cross(near_top_left - far_top_left); this->bottom_face_normal = (near_bottom_left - far_bottom_left).cross(near_bottom_right - near_bottom_left); - log::log(INFO << "Compute near and far points"); - log::log(INFO << "Near Top Left: " << near_top_left[0] << ", " << near_top_left[1] << ", " << near_top_left[2]); - log::log(INFO << "Near Top Right: " << near_top_right[0] << ", " << near_top_right[1] << ", " << near_top_right[2]); - log::log(INFO << "Near Bottom Left: " << near_bottom_left[0] << ", " << near_bottom_left[1] << ", " << near_bottom_left[2]); - log::log(INFO << "Near Bottom Right: " << near_bottom_right[0] << ", " << near_bottom_right[1] << ", " << near_bottom_right[2]); - log::log(INFO << "Far Top Left: " << far_top_left[0] << ", " << far_top_left[1] << ", " << far_top_left[2]); - log::log(INFO << "Far Top Right: " << far_top_right[0] << ", " << far_top_right[1] << ", " << far_top_right[2]); - log::log(INFO << "Far Bottom Left: " << far_bottom_left[0] << ", " << far_bottom_left[1] << ", " << far_bottom_left[2]); - log::log(INFO << "Far Bottom Right: " << far_bottom_right[0] << ", " << far_bottom_right[1] << ", " << far_bottom_right[2]); - this->left_face_normal.normalize(); this->right_face_normal.normalize(); this->top_face_normal.normalize(); this->bottom_face_normal.normalize(); - this->left_face_distance = 1.f * this->left_face_normal.dot(near_bottom_left); - this->right_face_distance = 1.f * this->right_face_normal.dot(far_bottom_right); - this->top_face_distance = 1.f * this->top_face_normal.dot(near_top_right); - this->bottom_face_distance = 1.f * this->bottom_face_normal.dot(near_bottom_left); - - log::log(INFO << "Computed Frustum with planes \n" - << "Top: <" << this->top_face_normal[0] << ", " << this->top_face_normal[1] << ", " << this->top_face_normal[2] << ">, " << this->top_face_distance << "\n" - << "Bottom: <" << this->bottom_face_normal[0] << ", " << this->bottom_face_normal[1] << ", " << this->bottom_face_normal[2] << ">, " << this->bottom_face_distance << "\n" - << "Left: <" << this->left_face_normal[0] << ", " << this->left_face_normal[1] << ", " << this->left_face_normal[2] << ">, " << this->left_face_distance << "\n" - << "Right: <" << this->right_face_normal[0] << ", " << this->right_face_normal[1] << ", " << this->right_face_normal[2] << ">, " << this->right_face_distance << "\n" - << "Far: <" << this->far_face_normal[0] << ", " << this->far_face_normal[1] << ", " << this->far_face_normal[2] << ">, " << this->far_face_distance << "\n" - << "Near: <" << this->near_face_normal[0] << ", " << this->near_face_normal[1] << ", " << this->near_face_normal[2] << ">, " << this->near_face_distance << "\n" - ); + this->left_face_distance = this->left_face_normal.dot(near_bottom_left); + this->right_face_distance = this->right_face_normal.dot(far_bottom_right); + this->top_face_distance = this->top_face_normal.dot(near_top_right); + this->bottom_face_distance = this->bottom_face_normal.dot(near_bottom_left); } bool Frustum::is_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; distance = this->top_face_normal.dot(pos) - this->top_face_distance; From 94f9a46ebeccf09b128ac77197a1c6327efd8dc9 Mon Sep 17 00:00:00 2001 From: Nikhil Ghosh Date: Fri, 26 Apr 2024 12:03:07 -0400 Subject: [PATCH 05/32] Fixed styling --- libopenage/renderer/camera/frustum.cpp | 2 +- libopenage/renderer/demo/stresstest_1.cpp | 4 ++-- libopenage/renderer/demo/stresstest_1.h | 4 ++-- libopenage/renderer/resources/parser/parse_sprite.h | 2 +- libopenage/renderer/resources/parser/parse_terrain.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libopenage/renderer/camera/frustum.cpp b/libopenage/renderer/camera/frustum.cpp index 459cc7226c..fb22e69988 100644 --- a/libopenage/renderer/camera/frustum.cpp +++ b/libopenage/renderer/camera/frustum.cpp @@ -14,7 +14,7 @@ namespace openage::renderer::camera { -Frustum::Frustum() : +Frustum::Frustum() : top_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, top_face_distance{0.0f}, bottom_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, diff --git a/libopenage/renderer/demo/stresstest_1.cpp b/libopenage/renderer/demo/stresstest_1.cpp index 05a357a2ef..85a60196bd 100644 --- a/libopenage/renderer/demo/stresstest_1.cpp +++ b/libopenage/renderer/demo/stresstest_1.cpp @@ -1,4 +1,4 @@ -// Copyright 2023-2023 the openage authors. See copying.md for legal info. +// Copyright 2024-2024 the openage authors. See copying.md for legal info. #include "stresstest_1.h" @@ -219,4 +219,4 @@ void renderer_stresstest_1(const util::Path &path) { window->close(); } -} \ No newline at end of file +} diff --git a/libopenage/renderer/demo/stresstest_1.h b/libopenage/renderer/demo/stresstest_1.h index 260296201f..a2dbde6136 100644 --- a/libopenage/renderer/demo/stresstest_1.h +++ b/libopenage/renderer/demo/stresstest_1.h @@ -1,4 +1,4 @@ -// Copyright 2023-2023 the openage authors. See copying.md for legal info. +// Copyright 2024-2024 the openage authors. See copying.md for legal info. #pragma once @@ -13,4 +13,4 @@ namespace openage::renderer::tests { */ void renderer_stresstest_1(const util::Path &path); -} \ No newline at end of file +} diff --git a/libopenage/renderer/resources/parser/parse_sprite.h b/libopenage/renderer/resources/parser/parse_sprite.h index b2021190b3..5f989f5aa3 100644 --- a/libopenage/renderer/resources/parser/parse_sprite.h +++ b/libopenage/renderer/resources/parser/parse_sprite.h @@ -1,4 +1,4 @@ -// Copyright 2021-2023 the openage authors. See copying.md for legal info. +// Copyright 2021-2024 the openage authors. See copying.md for legal info. #pragma once diff --git a/libopenage/renderer/resources/parser/parse_terrain.h b/libopenage/renderer/resources/parser/parse_terrain.h index 6aad27ce6e..ea5c582f38 100644 --- a/libopenage/renderer/resources/parser/parse_terrain.h +++ b/libopenage/renderer/resources/parser/parse_terrain.h @@ -1,4 +1,4 @@ -// Copyright 2023-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #pragma once From e62b1b962a0641b0070b57f4e727c67bcd6ccde4 Mon Sep 17 00:00:00 2001 From: Nikhil Ghosh Date: Fri, 26 Apr 2024 12:16:40 -0400 Subject: [PATCH 06/32] Fixed various checks --- libopenage/renderer/camera/frustum.cpp | 2 +- libopenage/renderer/demo/tests.cpp | 2 +- libopenage/renderer/resources/parser/common.cpp | 2 +- libopenage/renderer/resources/parser/parse_texture.cpp | 2 +- libopenage/renderer/stages/world/render_stage.cpp | 2 -- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libopenage/renderer/camera/frustum.cpp b/libopenage/renderer/camera/frustum.cpp index fb22e69988..912cf97a5b 100644 --- a/libopenage/renderer/camera/frustum.cpp +++ b/libopenage/renderer/camera/frustum.cpp @@ -127,4 +127,4 @@ bool Frustum::is_in_frustum(Eigen::Vector3f& pos) const { return true; } -} \ No newline at end of file +} diff --git a/libopenage/renderer/demo/tests.cpp b/libopenage/renderer/demo/tests.cpp index 30961a6c95..c997a06763 100644 --- a/libopenage/renderer/demo/tests.cpp +++ b/libopenage/renderer/demo/tests.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2015-2024 the openage authors. See copying.md for legal info. #include "tests.h" diff --git a/libopenage/renderer/resources/parser/common.cpp b/libopenage/renderer/resources/parser/common.cpp index ab6a1b205f..483c2cb0dd 100644 --- a/libopenage/renderer/resources/parser/common.cpp +++ b/libopenage/renderer/resources/parser/common.cpp @@ -1,4 +1,4 @@ -// Copyright 2023-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #include "common.h" diff --git a/libopenage/renderer/resources/parser/parse_texture.cpp b/libopenage/renderer/resources/parser/parse_texture.cpp index a0af8d6f73..c3d90fa30a 100644 --- a/libopenage/renderer/resources/parser/parse_texture.cpp +++ b/libopenage/renderer/resources/parser/parse_texture.cpp @@ -1,4 +1,4 @@ -// Copyright 2021-2023 the openage authors. See copying.md for legal info. +// Copyright 2021-2024 the openage authors. See copying.md for legal info. #include "parse_texture.h" diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp index 08bb7c7a8d..816203b9d8 100644 --- a/libopenage/renderer/stages/world/render_stage.cpp +++ b/libopenage/renderer/stages/world/render_stage.cpp @@ -100,8 +100,6 @@ void WorldRenderStage::update() { } obj->update_uniforms(current_time); } - - std::cout << this->render_pass->renderables.size() << std::flush; } void WorldRenderStage::resize(size_t width, size_t height) { From d70ae7fe1e773a300bdf7cf8c291a37f2eff8c53 Mon Sep 17 00:00:00 2001 From: Nikhil Ghosh Date: Fri, 26 Apr 2024 12:25:01 -0400 Subject: [PATCH 07/32] Added name to mailmap --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 300076fb84..fbf10ad63f 100644 --- a/.mailmap +++ b/.mailmap @@ -20,3 +20,4 @@ Tobias Feldballe Tobias Feldballe Jonas Borchelt Derek Frogget <114030121+derekfrogget@users.noreply.github.com> +Nikhil Ghosh \ No newline at end of file From 03da156788eb98506b26701a6979de6003fb1ee8 Mon Sep 17 00:00:00 2001 From: Nikhil Ghosh Date: Fri, 26 Apr 2024 12:34:20 -0400 Subject: [PATCH 08/32] Added name to copying.md --- copying.md | 1 + 1 file changed, 1 insertion(+) diff --git a/copying.md b/copying.md index 13124fb993..46c28990b4 100644 --- a/copying.md +++ b/copying.md @@ -153,6 +153,7 @@ _the openage authors_ are: | Astitva Kamble | askastitva | astitvakamble5 à gmail dawt com | | Haoyang Bi | AyiStar | ayistar à outlook dawt com | | Michael Seibt | RoboSchmied | github à roboschmie dawt de | +| Nikhil Ghosh | NikhilGhosh75 | nghosh606 à gmail 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. From 87a21a831e088c3289c47e523ecb4ecf7bb62085 Mon Sep 17 00:00:00 2001 From: heinezen Date: Sat, 13 Jul 2024 14:56:10 +0200 Subject: [PATCH 09/32] renderer: Fix imports and windows settings. --- libopenage/renderer/demo/stresstest_1.cpp | 29 ++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/libopenage/renderer/demo/stresstest_1.cpp b/libopenage/renderer/demo/stresstest_1.cpp index 85a60196bd..8e2e2887f9 100644 --- a/libopenage/renderer/demo/stresstest_1.cpp +++ b/libopenage/renderer/demo/stresstest_1.cpp @@ -9,6 +9,7 @@ #include "renderer/gui/integration/public/gui_application_with_logger.h" #include "renderer/opengl/window.h" #include "renderer/render_factory.h" +#include "renderer/render_pass.h" #include "renderer/resources/assets/asset_manager.h" #include "renderer/resources/shader_source.h" #include "renderer/stages/camera/manager.h" @@ -24,9 +25,15 @@ namespace openage::renderer::tests { void renderer_stresstest_1(const util::Path &path) { - auto qtapp = std::make_shared(); - - auto window = std::make_shared("openage renderer test", 1024, 768, true); + auto qtapp = std::make_shared(); + + // Create the window and renderer + window_settings settings; + settings.width = 1024; + settings.height = 768; + settings.vsync = false; + settings.debug = true; + auto window = std::make_shared("openage renderer test", settings); auto renderer = window->make_renderer(); // Clock required by world renderer for timing animation frames @@ -38,10 +45,10 @@ void renderer_stresstest_1(const util::Path &path) { auto camera = std::make_shared(renderer, window->get_size(), Eigen::Vector3f{17.0f, 10.0f, 7.0f}, - 1.f, - 64.f, - 1.f / 49.f, - true); + 1.f, + 64.f, + 1.f / 49.f, + true); auto cam_unifs = camera->get_uniform_buffer()->create_empty_input(); cam_unifs->update( "view", @@ -50,7 +57,7 @@ void renderer_stresstest_1(const util::Path &path) { camera->get_projection_matrix()); camera->get_uniform_buffer()->update_uniforms(cam_unifs); - // Render stages + // Render stages // every stage use a different subrenderer that manages renderables, // shaders, textures & more. std::vector> @@ -135,7 +142,7 @@ void renderer_stresstest_1(const util::Path &path) { // send the terrain data to the terrain renderer terrain0->update(terrain_size, tiles); - std::vector> render_entities{}; + std::vector> render_entities{}; auto add_world_entity = [&](const coord::phys3 initial_pos, const time::time_t time) { const auto animation_path = "./textures/test_tank_mirrored.sprite"; @@ -195,7 +202,7 @@ void renderer_stresstest_1(const util::Path &path) { auto current_time = clock->get_real_time(); if (current_time > next_entity) { add_world_entity(coord::phys3(0.0f, 10.0f, 0.0f), clock->get_time()); - add_world_entity(coord::phys3(-1.f, 9.0f, 0.0f), clock->get_time()); + add_world_entity(coord::phys3(-1.f, 9.0f, 0.0f), clock->get_time()); next_entity = current_time + 0.1; } @@ -219,4 +226,4 @@ void renderer_stresstest_1(const util::Path &path) { window->close(); } -} +} // namespace openage::renderer::tests From c3805cd49fea6f4e0d6a9df50055c774d49996f1 Mon Sep 17 00:00:00 2001 From: heinezen Date: Sat, 13 Jul 2024 14:58:52 +0200 Subject: [PATCH 10/32] Fix name parsing in copying.md --- buildsystem/codecompliance/authors.py | 4 ++-- copying.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/buildsystem/codecompliance/authors.py b/buildsystem/codecompliance/authors.py index 502e3b2648..98b3a50e18 100644 --- a/buildsystem/codecompliance/authors.py +++ b/buildsystem/codecompliance/authors.py @@ -1,4 +1,4 @@ -# Copyright 2014-2023 the openage authors. See copying.md for legal info. +# Copyright 2014-2024 the openage authors. See copying.md for legal info. """ Checks whether all authors are properly listed in copying.md. @@ -39,7 +39,7 @@ def get_author_emails_copying_md(): """ with open("copying.md", encoding='utf8') as fobj: for line in fobj: - match = re.match("^.*\\|[^|]*\\|[^|]*\\|([^|]+)\\|.*$", line) + match = re.match(r"^.*\|[^|]*\|[^|]*\|([^|]+)\|.*$", line) if not match: continue diff --git a/copying.md b/copying.md index 46c28990b4..fb6501bab0 100644 --- a/copying.md +++ b/copying.md @@ -153,7 +153,7 @@ _the openage authors_ are: | Astitva Kamble | askastitva | astitvakamble5 à gmail dawt com | | Haoyang Bi | AyiStar | ayistar à outlook dawt com | | Michael Seibt | RoboSchmied | github à roboschmie dawt de | -| Nikhil Ghosh | NikhilGhosh75 | nghosh606 à gmail dawt com +| Nikhil Ghosh | NikhilGhosh75 | nghosh606 à gmail 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. From 94461652347df8418f55ad032e7cb4bf529e1808 Mon Sep 17 00:00:00 2001 From: heinezen Date: Sat, 13 Jul 2024 16:08:31 +0200 Subject: [PATCH 11/32] renderer: Fix camera unifs for stresstest 1. --- libopenage/renderer/demo/stresstest_1.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libopenage/renderer/demo/stresstest_1.cpp b/libopenage/renderer/demo/stresstest_1.cpp index 8e2e2887f9..9a113eb85d 100644 --- a/libopenage/renderer/demo/stresstest_1.cpp +++ b/libopenage/renderer/demo/stresstest_1.cpp @@ -54,7 +54,14 @@ void renderer_stresstest_1(const util::Path &path) { "view", camera->get_view_matrix(), "proj", - camera->get_projection_matrix()); + camera->get_projection_matrix(), + "inv_zoom", + 1.0f / camera->get_zoom()); + auto viewport_size = camera->get_viewport_size(); + Eigen::Vector2f viewport_size_vec{ + 1.0f / static_cast(viewport_size[0]), + 1.0f / static_cast(viewport_size[1])}; + cam_unifs->update("inv_viewport_size", viewport_size_vec); camera->get_uniform_buffer()->update_uniforms(cam_unifs); // Render stages From acc9c96907c730b4d42c4a14b32903fe5d8abf6e Mon Sep 17 00:00:00 2001 From: heinezen Date: Sat, 13 Jul 2024 16:09:06 +0200 Subject: [PATCH 12/32] renderer: Get frustum from camera. --- libopenage/renderer/camera/camera.cpp | 45 +++-- libopenage/renderer/camera/camera.h | 21 +- libopenage/renderer/camera/frustum.cpp | 189 +++++++++--------- libopenage/renderer/camera/frustum.h | 46 ++--- libopenage/renderer/demo/stresstest_1.cpp | 3 +- libopenage/renderer/stages/world/object.cpp | 8 +- .../renderer/stages/world/render_stage.cpp | 2 +- 7 files changed, 159 insertions(+), 155 deletions(-) diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index fd94c2ce57..0e2112b6c7 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -25,15 +25,20 @@ Camera::Camera(const std::shared_ptr &renderer, moved{true}, zoom_changed{true}, view{Eigen::Matrix4f::Identity()}, - proj{Eigen::Matrix4f::Identity()}, - frustum_culling{false} { + proj{Eigen::Matrix4f::Identity()} { this->look_at_scene(Eigen::Vector3f(0.0f, 0.0f, 0.0f)); this->init_uniform_buffer(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.Recalculate(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] @@ -46,8 +51,7 @@ Camera::Camera(const std::shared_ptr &renderer, Eigen::Vector3f scene_pos, float zoom, float max_zoom_out, - float default_zoom_ratio, - bool frustum_culling) : + float default_zoom_ratio) : scene_pos{scene_pos}, viewport_size{viewport_size}, zoom{zoom}, @@ -57,13 +61,18 @@ Camera::Camera(const std::shared_ptr &renderer, zoom_changed{true}, viewport_changed{true}, view{Eigen::Matrix4f::Identity()}, - proj{Eigen::Matrix4f::Identity()}, - frustum_culling{frustum_culling} { + proj{Eigen::Matrix4f::Identity()} { this->init_uniform_buffer(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.Recalculate(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] @@ -121,7 +130,13 @@ void Camera::move_to(Eigen::Vector3f scene_pos) { // 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); + frustum.Recalculate(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) { @@ -289,16 +304,8 @@ void Camera::init_uniform_buffer(const std::shared_ptr &renderer) { this->uniform_buffer = renderer->add_uniform_buffer(ubo_info); } -bool Camera::using_frustum_culling() const { - return this->frustum_culling; -} - -bool Camera::is_in_frustum(Eigen::Vector3f pos) const{ - if (!this->frustum_culling) { - return true; - } - - return frustum.is_in_frustum(pos); +Frustum Camera::get_frustum() const { + return this->frustum; } } // namespace openage::renderer::camera diff --git a/libopenage/renderer/camera/camera.h b/libopenage/renderer/camera/camera.h index bc4959f589..26bebd7e60 100644 --- a/libopenage/renderer/camera/camera.h +++ b/libopenage/renderer/camera/camera.h @@ -12,7 +12,7 @@ #include "coord/scene.h" #include "util/vector.h" -#include "frustum.h" +#include "renderer/camera/frustum.h" namespace openage::renderer { class Renderer; @@ -63,15 +63,13 @@ class Camera { * @param zoom Zoom level of the camera (defaults to 1.0f). * @param max_zoom_out Maximum zoom out level (defaults to 64.0f). * @param default_zoom_ratio Default zoom level calibration (defaults to (1.0f / 49)). - * @param frustum_culling Is frustum culling enables (defaults to false). */ Camera(const std::shared_ptr &renderer, util::Vector2s viewport_size, Eigen::Vector3f scene_pos, float zoom = 1.0f, float max_zoom_out = 64.0f, - float default_zoom_ratio = 1.0f / 49, - bool frustum_culling = false); + float default_zoom_ratio = 1.0f / 49); ~Camera() = default; /** @@ -195,9 +193,12 @@ class Camera { */ const std::shared_ptr &get_uniform_buffer() const; - bool using_frustum_culling() const; - - bool is_in_frustum(Eigen::Vector3f pos) const; + /** + * Get a frustum object for this camera. + * + * @return Frustum object. + */ + Frustum get_frustum() const; private: /** @@ -293,12 +294,6 @@ class Camera { */ std::shared_ptr uniform_buffer; - /** - * Is frustum culling enabled? If true, perform frustum culling. - * If false, all frustum checks will return true - */ - bool frustum_culling; - /** * The frustum used to cull objects * Will be recalculated regardless of whether frustum culling is enabled diff --git a/libopenage/renderer/camera/frustum.cpp b/libopenage/renderer/camera/frustum.cpp index 912cf97a5b..03735247df 100644 --- a/libopenage/renderer/camera/frustum.cpp +++ b/libopenage/renderer/camera/frustum.cpp @@ -15,116 +15,121 @@ namespace openage::renderer::camera { Frustum::Frustum() : - top_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, - top_face_distance{0.0f}, - bottom_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, - bottom_face_distance{0.0f}, - right_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, - right_face_distance{0.0f}, - left_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, - left_face_distance{0.0f}, - far_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, - far_face_distance{0.0f}, - near_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, - near_face_distance{0.0f} -{ + top_face_distance{0.0f}, + bottom_face_distance{0.0f}, + right_face_distance{0.0f}, + left_face_distance{0.0f}, + far_face_distance{0.0f}, + near_face_distance{0.0f}, + top_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, + bottom_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, + right_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, + left_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, + far_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, + 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) { - // offsets are adjusted by zoom +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) { + // offsets are adjusted by zoom // this is the same calculation as for the projection matrix float halfscreenwidth = viewport_size[0] / 2; float halfscreenheight = viewport_size[1] / 2; - float halfwidth = halfscreenwidth * real_zoom; + float halfwidth = halfscreenwidth * real_zoom; float halfheight = halfscreenheight * real_zoom; - Eigen::Vector3f direction = cam_direction.normalized(); - Eigen::Vector3f eye = scene_pos; + Eigen::Vector3f direction = cam_direction.normalized(); + Eigen::Vector3f eye = scene_pos; Eigen::Vector3f center = scene_pos + direction; - // calculate up (u) and right (s) vectors for camera + // calculate up (u) and right (s) vectors for camera // these define the camera plane in 3D space that the input - Eigen::Vector3f f = center - eye; + Eigen::Vector3f f = center - eye; f.normalize(); Eigen::Vector3f s = f.cross(up_direction); s.normalize(); Eigen::Vector3f u = s.cross(f); u.normalize(); - 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) - 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; - Eigen::Vector3f near_bottom_right = near_position + s * halfwidth - u * halfheight; - - Eigen::Vector3f far_top_left = far_position - s * halfwidth + u * halfheight; - Eigen::Vector3f far_top_right = far_position + s * halfwidth + u * halfheight; - Eigen::Vector3f far_bottom_left = far_position - s * halfwidth - u * halfheight; - 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_distance = this->near_face_normal.dot(near_position) * -1.0f; - this->far_face_distance = this->far_face_normal.dot(far_position) * -1.0f; - - // 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); - this->right_face_normal = (far_bottom_right - near_bottom_right).cross(near_bottom_right - near_top_right); - this->top_face_normal = (near_top_right - near_top_left).cross(near_top_left - far_top_left); - this->bottom_face_normal = (near_bottom_left - far_bottom_left).cross(near_bottom_right - near_bottom_left); - - this->left_face_normal.normalize(); - this->right_face_normal.normalize(); - this->top_face_normal.normalize(); - this->bottom_face_normal.normalize(); - - this->left_face_distance = this->left_face_normal.dot(near_bottom_left); - this->right_face_distance = this->right_face_normal.dot(far_bottom_right); - this->top_face_distance = this->top_face_normal.dot(near_top_right); - this->bottom_face_distance = this->bottom_face_normal.dot(near_bottom_left); + 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) + 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; + Eigen::Vector3f near_bottom_right = near_position + s * halfwidth - u * halfheight; + + Eigen::Vector3f far_top_left = far_position - s * halfwidth + u * halfheight; + Eigen::Vector3f far_top_right = far_position + s * halfwidth + u * halfheight; + Eigen::Vector3f far_bottom_left = far_position - s * halfwidth - u * halfheight; + 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_distance = this->near_face_normal.dot(near_position) * -1.0f; + this->far_face_distance = this->far_face_normal.dot(far_position) * -1.0f; + + // 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); + this->right_face_normal = (far_bottom_right - near_bottom_right).cross(near_bottom_right - near_top_right); + this->top_face_normal = (near_top_right - near_top_left).cross(near_top_left - far_top_left); + this->bottom_face_normal = (near_bottom_left - far_bottom_left).cross(near_bottom_right - near_bottom_left); + + this->left_face_normal.normalize(); + this->right_face_normal.normalize(); + this->top_face_normal.normalize(); + this->bottom_face_normal.normalize(); + + this->left_face_distance = this->left_face_normal.dot(near_bottom_left); + this->right_face_distance = this->right_face_normal.dot(far_bottom_right); + this->top_face_distance = this->top_face_normal.dot(near_top_right); + this->bottom_face_distance = this->bottom_face_normal.dot(near_bottom_left); } -bool Frustum::is_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; - - distance = this->top_face_normal.dot(pos) - this->top_face_distance; - if (distance < 0) { - return false; - } - - distance = this->bottom_face_normal.dot(pos) - this->bottom_face_distance; - if (distance < 0) { - return false; - } - - distance = this->left_face_normal.dot(pos) - this->left_face_distance; - if (distance < 0) { - return false; - } - - distance = this->right_face_normal.dot(pos) - this->right_face_distance; - if (distance < 0) { - return false; - } - - distance = this->far_face_normal.dot(pos) - this->far_face_distance; - if (distance < 0) { - return false; - } - - distance = this->bottom_face_normal.dot(pos) - this->bottom_face_distance; - if (distance < 0) { - return false; - } - - return true; +bool Frustum::is_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; + + distance = this->top_face_normal.dot(pos) - this->top_face_distance; + if (distance < 0) { + return false; + } + + distance = this->bottom_face_normal.dot(pos) - this->bottom_face_distance; + if (distance < 0) { + return false; + } + + distance = this->left_face_normal.dot(pos) - this->left_face_distance; + if (distance < 0) { + return false; + } + + distance = this->right_face_normal.dot(pos) - this->right_face_distance; + if (distance < 0) { + return false; + } + + distance = this->far_face_normal.dot(pos) - this->far_face_distance; + if (distance < 0) { + return false; + } + + distance = this->bottom_face_normal.dot(pos) - this->bottom_face_distance; + if (distance < 0) { + return false; + } + + return true; } -} +} // namespace openage::renderer::camera diff --git a/libopenage/renderer/camera/frustum.h b/libopenage/renderer/camera/frustum.h index 8dfe9372c5..bd87147177 100644 --- a/libopenage/renderer/camera/frustum.h +++ b/libopenage/renderer/camera/frustum.h @@ -14,33 +14,33 @@ namespace openage::renderer::camera { -class Frustum -{ +class Frustum { public: - 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); + 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); - bool is_in_frustum(Eigen::Vector3f& pos) const; + bool is_in_frustum(Eigen::Vector3f &pos) const; private: - Eigen::Vector3f top_face_normal; - float top_face_distance; - - Eigen::Vector3f bottom_face_normal; - float bottom_face_distance; - - Eigen::Vector3f right_face_normal; - float right_face_distance; - - Eigen::Vector3f left_face_normal; - float left_face_distance; - - Eigen::Vector3f far_face_normal; - float far_face_distance; - - Eigen::Vector3f near_face_normal; - float near_face_distance; - + Eigen::Vector3f top_face_normal; + Eigen::Vector3f bottom_face_normal; + Eigen::Vector3f right_face_normal; + Eigen::Vector3f left_face_normal; + Eigen::Vector3f far_face_normal; + Eigen::Vector3f near_face_normal; + + float top_face_distance; + float bottom_face_distance; + float right_face_distance; + float left_face_distance; + float far_face_distance; + float near_face_distance; }; } // namespace openage::renderer::camera diff --git a/libopenage/renderer/demo/stresstest_1.cpp b/libopenage/renderer/demo/stresstest_1.cpp index 9a113eb85d..99e6e253ef 100644 --- a/libopenage/renderer/demo/stresstest_1.cpp +++ b/libopenage/renderer/demo/stresstest_1.cpp @@ -47,8 +47,7 @@ void renderer_stresstest_1(const util::Path &path) { Eigen::Vector3f{17.0f, 10.0f, 7.0f}, 1.f, 64.f, - 1.f / 49.f, - true); + 1.f / 49.f); auto cam_unifs = camera->get_uniform_buffer()->create_empty_input(); cam_unifs->update( "view", diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp index d8d9120c69..da326a4faf 100644 --- a/libopenage/renderer/stages/world/object.cpp +++ b/libopenage/renderer/stages/world/object.cpp @@ -11,6 +11,7 @@ #include #include "renderer/camera/camera.h" +#include "renderer/camera/frustum.h" #include "renderer/definitions.h" #include "renderer/resources/animation/angle_info.h" #include "renderer/resources/animation/animation_info.h" @@ -225,12 +226,9 @@ void WorldObject::set_uniforms(std::vector &camera) { - if (!camera->using_frustum_culling()) { - return true; - } - Eigen::Vector3f current_pos = this->position.get(this->last_update).to_world_space(); - return camera->is_in_frustum(current_pos); + auto frustum = camera->get_frustum(); + return frustum.is_in_frustum(current_pos); } } // namespace openage::renderer::world diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp index 816203b9d8..bfa745d19d 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 (!obj->within_camera_frustum(this->camera)) { + if (not obj->within_camera_frustum(this->camera)) { continue; } From 34cc059308fc8023cc9eb4d55d5b840824eb8a94 Mon Sep 17 00:00:00 2001 From: heinezen Date: Sun, 14 Jul 2024 13:34:39 +0200 Subject: [PATCH 13/32] renderer: Fix object position fetching. Needed the current `time` for getting the correct position. --- libopenage/renderer/camera/camera.cpp | 44 +++++++++---------- libopenage/renderer/camera/frustum.cpp | 28 ++++++------ libopenage/renderer/camera/frustum.h | 43 ++++++++++++++---- libopenage/renderer/stages/world/object.cpp | 7 +-- libopenage/renderer/stages/world/object.h | 3 +- .../renderer/stages/world/render_stage.cpp | 2 +- 6 files changed, 78 insertions(+), 49 deletions(-) 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; } From 5f95f219ce57c35ba2befdeb1abc019bc456ebde Mon Sep 17 00:00:00 2001 From: heinezen Date: Sun, 14 Jul 2024 17:16:02 +0200 Subject: [PATCH 14/32] renderer: Fix position curve in stresstest 1. --- libopenage/renderer/demo/stresstest_1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libopenage/renderer/demo/stresstest_1.cpp b/libopenage/renderer/demo/stresstest_1.cpp index 99e6e253ef..6ec2887503 100644 --- a/libopenage/renderer/demo/stresstest_1.cpp +++ b/libopenage/renderer/demo/stresstest_1.cpp @@ -160,7 +160,7 @@ void renderer_stresstest_1(const util::Path &path) { position.set_insert(time + 3, initial_pos + coord::phys3_delta{8, 8, 0}); position.set_insert(time + 4, initial_pos + coord::phys3_delta{12, 4, 0}); position.set_insert(time + 5, initial_pos + coord::phys3_delta{12, 0, 0}); - position.set_insert(time + 6, initial_pos + coord::phys3_delta{12, -4, 0}); + position.set_insert(time + 6, initial_pos + coord::phys3_delta{8, -4, 0}); position.set_insert(time + 7, initial_pos + coord::phys3_delta{4, -4, 0}); position.set_insert(time + 8, initial_pos); From 69841ad5bb8209d15fd509fa5156fa2182806da7 Mon Sep 17 00:00:00 2001 From: heinezen Date: Sun, 14 Jul 2024 17:30:13 +0200 Subject: [PATCH 15/32] etc: Fix time pretty print for Keyframe. --- etc/gdb_pretty/printers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/gdb_pretty/printers.py b/etc/gdb_pretty/printers.py index 0dfac99af5..1a7803619f 100644 --- a/etc/gdb_pretty/printers.py +++ b/etc/gdb_pretty/printers.py @@ -276,7 +276,7 @@ def children(self): """ Get the displayed children of the keyframe. """ - yield ('time', self.__val['time']) + yield ('time', self.__val['timestamp']) yield ('value', self.__val['value']) From 0df247c69cee6bb5c84e3b7eda8b949301f6f5f3 Mon Sep 17 00:00:00 2001 From: heinezen Date: Sun, 14 Jul 2024 17:30:55 +0200 Subject: [PATCH 16/32] renderer: Resize frustum to exact camera boundaries. --- libopenage/renderer/camera/camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index 01e9896c35..f0eb67a29c 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -65,7 +65,7 @@ Camera::Camera(const std::shared_ptr &renderer, this->init_uniform_buffer(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; + float real_zoom = 0.5f * this->default_zoom_ratio * this->zoom; frustum.update(this->viewport_size, near_distance, far_distance, From 189d9162fd33bcbc9da6e4949f2c33097c12a821 Mon Sep 17 00:00:00 2001 From: heinezen Date: Sun, 14 Jul 2024 17:31:31 +0200 Subject: [PATCH 17/32] renderer: Fetch updates before checking that object is in frustrum. --- libopenage/renderer/stages/world/render_stage.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp index 51ec4878d6..2e70776c18 100644 --- a/libopenage/renderer/stages/world/render_stage.cpp +++ b/libopenage/renderer/stages/world/render_stage.cpp @@ -59,11 +59,12 @@ void WorldRenderStage::update() { std::unique_lock lock{this->mutex}; auto current_time = this->clock->get_real_time(); for (auto &obj : this->render_objects) { + obj->fetch_updates(current_time); + if (not obj->within_camera_frustum(this->camera, current_time)) { continue; } - obj->fetch_updates(current_time); if (obj->is_changed()) { if (obj->requires_renderable()) { auto layer_positions = obj->get_layer_positions(current_time); From f114994dfd6eaf6667fbbe1375f523fbb1ff4411 Mon Sep 17 00:00:00 2001 From: heinezen Date: Mon, 15 Jul 2024 00:05:01 +0200 Subject: [PATCH 18/32] renderer: Move camera constants to different file. --- libopenage/coord/pixel.cpp | 6 ++- libopenage/pathfinding/demo/demo_0.cpp | 3 +- libopenage/renderer/camera/CMakeLists.txt | 1 + libopenage/renderer/camera/camera.cpp | 51 +++++++++++--------- libopenage/renderer/camera/camera.h | 33 ++++++------- libopenage/renderer/camera/definitions.cpp | 9 ++++ libopenage/renderer/camera/definitions.h | 56 ++++++++++++++++++++++ 7 files changed, 115 insertions(+), 44 deletions(-) create mode 100644 libopenage/renderer/camera/definitions.cpp create mode 100644 libopenage/renderer/camera/definitions.h diff --git a/libopenage/coord/pixel.cpp b/libopenage/coord/pixel.cpp index c7dac5f815..a480cba2dc 100644 --- a/libopenage/coord/pixel.cpp +++ b/libopenage/coord/pixel.cpp @@ -1,9 +1,11 @@ -// Copyright 2016-2023 the openage authors. See copying.md for legal info. +// Copyright 2016-2024 the openage authors. See copying.md for legal info. #include "pixel.h" #include "coord/phys.h" #include "renderer/camera/camera.h" +#include "renderer/camera/definitions.h" + namespace openage { namespace coord { @@ -54,7 +56,7 @@ phys3 input::to_phys3(const std::shared_ptr &camera) c scene3 input::to_scene3(const std::shared_ptr &camera) const { // Use raycasting to find the position // Direction and origin point are fetched from the camera - auto cam_dir = renderer::camera::cam_direction; + auto cam_dir = renderer::camera::CAM_DIRECTION; auto ray_origin = camera->get_input_pos(*this); // xz plane that we want to intersect with diff --git a/libopenage/pathfinding/demo/demo_0.cpp b/libopenage/pathfinding/demo/demo_0.cpp index da7ae17492..bcf4cca945 100644 --- a/libopenage/pathfinding/demo/demo_0.cpp +++ b/libopenage/pathfinding/demo/demo_0.cpp @@ -10,6 +10,7 @@ #include "pathfinding/flow_field.h" #include "pathfinding/integration_field.h" #include "renderer/camera/camera.h" +#include "renderer/camera/definitions.h" #include "renderer/gui/integration/public/gui_application_with_logger.h" #include "renderer/opengl/window.h" #include "renderer/render_pass.h" @@ -313,7 +314,7 @@ void RenderManager0::hide_vectors() { std::pair RenderManager0::select_tile(double x, double y) { auto grid_plane_normal = Eigen::Vector3f{0, 1, 0}; auto grid_plane_point = Eigen::Vector3f{0, 0, 0}; - auto camera_direction = renderer::camera::cam_direction; + auto camera_direction = renderer::camera::CAM_DIRECTION; auto camera_position = camera->get_input_pos( coord::input(x, y)); diff --git a/libopenage/renderer/camera/CMakeLists.txt b/libopenage/renderer/camera/CMakeLists.txt index 43a49cc1c7..a3ffbd067f 100644 --- a/libopenage/renderer/camera/CMakeLists.txt +++ b/libopenage/renderer/camera/CMakeLists.txt @@ -1,4 +1,5 @@ add_sources(libopenage camera.cpp + definitions.cpp frustum.cpp ) diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index f0eb67a29c..5b43bc1bb5 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -19,9 +19,9 @@ Camera::Camera(const std::shared_ptr &renderer, util::Vector2s viewport_size) : scene_pos{Eigen::Vector3f(0.0f, 10.0f, 0.0f)}, viewport_size{viewport_size}, - zoom{1.0f}, - max_zoom_out{64.0f}, - default_zoom_ratio{1.0f / 49}, + zoom{DEFAULT_ZOOM}, + max_zoom_out{DEFAULT_MAX_ZOOM_OUT}, + default_zoom_ratio{DEFAULT_ZOOM_RATIO}, moved{true}, zoom_changed{true}, view{Eigen::Matrix4f::Identity()}, @@ -31,12 +31,12 @@ Camera::Camera(const std::shared_ptr &renderer, this->init_uniform_buffer(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; + float real_zoom = get_zoom_factor(); frustum.update(this->viewport_size, - near_distance, - far_distance, + DEFAULT_NEAR_DISTANCE, + DEFAULT_FAR_DISTANCE, this->scene_pos, - cam_direction, + CAM_DIRECTION, Eigen::Vector3f(0.0f, 1.0f, 0.0f), real_zoom); @@ -65,12 +65,12 @@ Camera::Camera(const std::shared_ptr &renderer, this->init_uniform_buffer(renderer); // Make the frustum slightly bigger than the camera's view to ensure objects on the boundary get rendered - float real_zoom = 0.5f * this->default_zoom_ratio * this->zoom; + float real_zoom = this->get_zoom_factor(); frustum.update(this->viewport_size, - near_distance, - far_distance, + DEFAULT_NEAR_DISTANCE, + DEFAULT_FAR_DISTANCE, this->scene_pos, - cam_direction, + CAM_DIRECTION, Eigen::Vector3f(0.0f, 1.0f, 0.0f), real_zoom); @@ -129,12 +129,12 @@ 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.5f * this->default_zoom_ratio * this->zoom; + float real_zoom = this->get_zoom_factor(); frustum.update(viewport_size, - near_distance, - far_distance, + DEFAULT_NEAR_DISTANCE, + DEFAULT_FAR_DISTANCE, scene_pos, - cam_direction, + CAM_DIRECTION, Eigen::Vector3f(0.0f, 1.0f, 0.0f), real_zoom); } @@ -179,7 +179,7 @@ const Eigen::Matrix4f &Camera::get_view_matrix() { return this->view; } - auto direction = cam_direction.normalized(); + auto direction = CAM_DIRECTION.normalized(); Eigen::Vector3f eye = this->scene_pos; Eigen::Vector3f center = this->scene_pos + direction; // look in the direction of the camera @@ -227,7 +227,7 @@ const Eigen::Matrix4f &Camera::get_projection_matrix() { float halfheight = this->viewport_size[1] / 2; // get zoom level - float real_zoom = 0.5f * this->default_zoom_ratio * this->zoom; + float real_zoom = this->get_zoom_factor(); // zoom by narrowing or widening viewport around focus point. // narrow viewport => zoom in (projected area gets *smaller* while screen size stays the same) @@ -240,10 +240,11 @@ const Eigen::Matrix4f &Camera::get_projection_matrix() { Eigen::Matrix4f mat = Eigen::Matrix4f::Identity(); mat(0, 0) = 2.0f / (right - left); mat(1, 1) = 2.0f / (top - bottom); - mat(2, 2) = -2.0f / (1000.0f - (-1.0f)); // clip near and far planes (TODO: necessary?) + mat(2, 2) = -2.0f / (DEFAULT_FAR_DISTANCE - DEFAULT_NEAR_DISTANCE); // clip near and far planes (TODO: necessary?) mat(0, 3) = -(right + left) / (right - left); mat(1, 3) = -(top + bottom) / (top - bottom); - mat(2, 3) = -(1000.0f + (-1.0f)) / (1000.0f - (-1.0f)); // clip near and far planes (TODO: necessary?) + mat(2, 3) = -(DEFAULT_FAR_DISTANCE + DEFAULT_NEAR_DISTANCE) + / (DEFAULT_FAR_DISTANCE - DEFAULT_NEAR_DISTANCE); // clip near and far planes (TODO: necessary?) // Cache matrix for subsequent calls this->proj = mat; @@ -261,7 +262,7 @@ Eigen::Vector3f Camera::get_input_pos(const coord::input &coord) const { // calculate up (u) and right (s) vectors for camera // these define the camera plane in 3D space that the input // coord exists on - auto direction = cam_direction.normalized(); + auto direction = CAM_DIRECTION.normalized(); Eigen::Vector3f eye = this->scene_pos; Eigen::Vector3f center = this->scene_pos + direction; Eigen::Vector3f up = Eigen::Vector3f(0.0f, 1.0f, 0.0f); @@ -277,7 +278,7 @@ Eigen::Vector3f Camera::get_input_pos(const coord::input &coord) const { // this is the same calculation as for the projection matrix float halfwidth = this->viewport_size[0] / 2; float halfheight = this->viewport_size[1] / 2; - float real_zoom = 0.5f * this->default_zoom_ratio * this->zoom; + float real_zoom = this->get_zoom_factor(); // calculate x and y offset on the camera plane relative to the camera position float x = +(2.0f * coord.x / this->viewport_size[0] - 1) * (halfwidth * real_zoom); @@ -293,6 +294,10 @@ const std::shared_ptr &Camera::get_uniform_buffer() con return this->uniform_buffer; } +Frustum Camera::get_frustum() const { + return this->frustum; +} + void Camera::init_uniform_buffer(const std::shared_ptr &renderer) { resources::UBOInput view_input{"view", resources::ubo_input_t::M4F32}; resources::UBOInput proj_input{"proj", resources::ubo_input_t::M4F32}; @@ -304,8 +309,8 @@ void Camera::init_uniform_buffer(const std::shared_ptr &renderer) { this->uniform_buffer = renderer->add_uniform_buffer(ubo_info); } -Frustum Camera::get_frustum() const { - return this->frustum; +inline float Camera::get_zoom_factor() const { + return 0.5f * this->default_zoom_ratio * this->zoom; } } // namespace openage::renderer::camera diff --git a/libopenage/renderer/camera/camera.h b/libopenage/renderer/camera/camera.h index 26bebd7e60..e1fd0f0f44 100644 --- a/libopenage/renderer/camera/camera.h +++ b/libopenage/renderer/camera/camera.h @@ -12,6 +12,7 @@ #include "coord/scene.h" #include "util/vector.h" +#include "renderer/camera/definitions.h" #include "renderer/camera/frustum.h" namespace openage::renderer { @@ -20,21 +21,6 @@ class UniformBuffer; namespace camera { -/** - * Camera direction (= where it looks at). - * Uses a dimetric perspective like in AoE with the (fixed) angles - * yaw = -135 degrees - * pitch = -30 degrees - */ -static const Eigen::Vector3f cam_direction{ - -1 * (std::sqrt(6.f) / 4), - -0.5f, - -1 * (std::sqrt(6.f) / 4), -}; - -static const float near_distance = 0.01f; -static const float far_distance = 100.0f; - /** * Camera for selecting what part of the ingame world is displayed. * @@ -67,9 +53,9 @@ class Camera { Camera(const std::shared_ptr &renderer, util::Vector2s viewport_size, Eigen::Vector3f scene_pos, - float zoom = 1.0f, - float max_zoom_out = 64.0f, - float default_zoom_ratio = 1.0f / 49); + float zoom = DEFAULT_ZOOM, + float max_zoom_out = DEFAULT_MAX_ZOOM_OUT, + float default_zoom_ratio = DEFAULT_ZOOM_RATIO); ~Camera() = default; /** @@ -208,6 +194,17 @@ class Camera { */ void init_uniform_buffer(const std::shared_ptr &renderer); + /** + * Get the zoom factor applied to the camera projection. + * + * The zoom factor is calculated as + * + * zoom * zoom_ratio * 0.5f + * + * @return Zoom factor for projection. + */ + inline float get_zoom_factor() const; + /** * Position in the 3D scene. */ diff --git a/libopenage/renderer/camera/definitions.cpp b/libopenage/renderer/camera/definitions.cpp new file mode 100644 index 0000000000..9011323855 --- /dev/null +++ b/libopenage/renderer/camera/definitions.cpp @@ -0,0 +1,9 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#include "definitions.h" + +namespace openage::renderer::camera { + +// this file is intentionally empty + +} // namespace openage::renderer::camera diff --git a/libopenage/renderer/camera/definitions.h b/libopenage/renderer/camera/definitions.h new file mode 100644 index 0000000000..3ce6aa4f22 --- /dev/null +++ b/libopenage/renderer/camera/definitions.h @@ -0,0 +1,56 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#pragma once + +#include + + +namespace openage::renderer::camera { + +/** + * Camera direction (= where it looks at). + * Uses a dimetric perspective like in AoE with the (fixed) angles + * yaw = -135 degrees + * pitch = -30 degrees + */ +static const Eigen::Vector3f CAM_DIRECTION{ + -1 * (std::sqrt(6.f) / 4), + -0.5f, + -1 * (std::sqrt(6.f) / 4), +}; + +/** + * Default near distance of the camera. + * + * Determines how close objects can be to the camera before they are not rendered anymore. + */ +static constexpr float DEFAULT_NEAR_DISTANCE = 0.01f; + +/** + * Default far distance of the camera. + * + * Determines how far objects can be from the camera before they are not rendered anymore. + */ +static constexpr float DEFAULT_FAR_DISTANCE = 100.0f; + +/** + * Default zoom level of the camera. + */ +static constexpr float DEFAULT_ZOOM = 1.0f; + +/** + * Maximum zoom out level of the camera. + */ +static constexpr float DEFAULT_MAX_ZOOM_OUT = 64.0f; + +/** + * Default zoom ratio. + * + * This adjusts the zoom level of the camera to the size of sprites in the game, + * so that 1 pixel in a sprite == 1 pixel on the screen. + * + * 1.0f / 49 is the default value for the AoE2 sprites. + */ +static constexpr float DEFAULT_ZOOM_RATIO = 1.0f / 49; + +} // namespace openage::renderer::camera From f3365cf8cb7b30852fe23ade23bcb82c0cf79209 Mon Sep 17 00:00:00 2001 From: heinezen Date: Mon, 15 Jul 2024 00:51:29 +0200 Subject: [PATCH 19/32] renderer: Construct frustum with parameters. --- libopenage/renderer/camera/camera.cpp | 49 +++++------ libopenage/renderer/camera/camera.h | 8 +- libopenage/renderer/camera/definitions.h | 5 ++ libopenage/renderer/camera/frustum.cpp | 62 +++++++------ libopenage/renderer/camera/frustum.h | 88 ++++++++++++++++--- libopenage/renderer/stages/world/object.cpp | 6 +- libopenage/renderer/stages/world/object.h | 14 ++- .../renderer/stages/world/render_stage.cpp | 4 +- 8 files changed, 157 insertions(+), 79 deletions(-) diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index 5b43bc1bb5..309b29737c 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -25,21 +25,18 @@ Camera::Camera(const std::shared_ptr &renderer, moved{true}, zoom_changed{true}, view{Eigen::Matrix4f::Identity()}, - proj{Eigen::Matrix4f::Identity()} { + proj{Eigen::Matrix4f::Identity()}, + frustum{this->viewport_size, + DEFAULT_NEAR_DISTANCE, + DEFAULT_FAR_DISTANCE, + this->scene_pos, + CAM_DIRECTION, + Eigen::Vector3f(0.0f, 1.0f, 0.0f), + this->get_zoom_factor()} { this->look_at_scene(Eigen::Vector3f(0.0f, 0.0f, 0.0f)); this->init_uniform_buffer(renderer); - // Make the frustum slightly bigger than the camera's view to ensure objects on the boundary get rendered - float real_zoom = get_zoom_factor(); - frustum.update(this->viewport_size, - DEFAULT_NEAR_DISTANCE, - DEFAULT_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] << ", " << this->scene_pos[1] @@ -61,19 +58,16 @@ Camera::Camera(const std::shared_ptr &renderer, zoom_changed{true}, viewport_changed{true}, view{Eigen::Matrix4f::Identity()}, - proj{Eigen::Matrix4f::Identity()} { + proj{Eigen::Matrix4f::Identity()}, + frustum{this->viewport_size, + DEFAULT_NEAR_DISTANCE, + DEFAULT_FAR_DISTANCE, + this->scene_pos, + CAM_DIRECTION, + Eigen::Vector3f(0.0f, 1.0f, 0.0f), + this->get_zoom_factor()} { this->init_uniform_buffer(renderer); - // Make the frustum slightly bigger than the camera's view to ensure objects on the boundary get rendered - float real_zoom = this->get_zoom_factor(); - frustum.update(this->viewport_size, - DEFAULT_NEAR_DISTANCE, - DEFAULT_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] << ", " << this->scene_pos[1] @@ -128,15 +122,14 @@ void Camera::move_to(Eigen::Vector3f scene_pos) { this->scene_pos = 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 = this->get_zoom_factor(); + // Update frustum frustum.update(viewport_size, DEFAULT_NEAR_DISTANCE, DEFAULT_FAR_DISTANCE, scene_pos, CAM_DIRECTION, Eigen::Vector3f(0.0f, 1.0f, 0.0f), - real_zoom); + this->get_zoom_factor()); } void Camera::move_rel(Eigen::Vector3f direction, float delta) { @@ -183,7 +176,7 @@ const Eigen::Matrix4f &Camera::get_view_matrix() { Eigen::Vector3f eye = this->scene_pos; Eigen::Vector3f center = this->scene_pos + direction; // look in the direction of the camera - Eigen::Vector3f up = Eigen::Vector3f(0.0f, 1.0f, 0.0f); + Eigen::Vector3f up = CAM_UP; Eigen::Vector3f f = center - eye; f.normalize(); @@ -265,7 +258,7 @@ Eigen::Vector3f Camera::get_input_pos(const coord::input &coord) const { auto direction = CAM_DIRECTION.normalized(); Eigen::Vector3f eye = this->scene_pos; Eigen::Vector3f center = this->scene_pos + direction; - Eigen::Vector3f up = Eigen::Vector3f(0.0f, 1.0f, 0.0f); + Eigen::Vector3f up = CAM_UP; Eigen::Vector3f f = center - eye; f.normalize(); @@ -294,7 +287,7 @@ const std::shared_ptr &Camera::get_uniform_buffer() con return this->uniform_buffer; } -Frustum Camera::get_frustum() const { +const Frustum &Camera::get_frustum() const { return this->frustum; } diff --git a/libopenage/renderer/camera/camera.h b/libopenage/renderer/camera/camera.h index e1fd0f0f44..8fc72b2a72 100644 --- a/libopenage/renderer/camera/camera.h +++ b/libopenage/renderer/camera/camera.h @@ -24,6 +24,9 @@ namespace camera { /** * Camera for selecting what part of the ingame world is displayed. * + * The camera uses orthographic projection as it is primarily used for + * 2D rendering. + * * TODO: Vulkan version. */ class Camera { @@ -184,7 +187,7 @@ class Camera { * * @return Frustum object. */ - Frustum get_frustum() const; + const Frustum &get_frustum() const; private: /** @@ -292,8 +295,7 @@ class Camera { std::shared_ptr uniform_buffer; /** - * The frustum used to cull objects - * Will be recalculated regardless of whether frustum culling is enabled + * Frustum (viewing volume) for culling rendering objects. */ Frustum frustum; }; diff --git a/libopenage/renderer/camera/definitions.h b/libopenage/renderer/camera/definitions.h index 3ce6aa4f22..9586239a2f 100644 --- a/libopenage/renderer/camera/definitions.h +++ b/libopenage/renderer/camera/definitions.h @@ -19,6 +19,11 @@ static const Eigen::Vector3f CAM_DIRECTION{ -1 * (std::sqrt(6.f) / 4), }; +/** + * Camera up vector. + */ +static const Eigen::Vector3f CAM_UP{0.0f, 1.0f, 0.0f}; + /** * Default near distance of the camera. * diff --git a/libopenage/renderer/camera/frustum.cpp b/libopenage/renderer/camera/frustum.cpp index 234dbe500a..661672206a 100644 --- a/libopenage/renderer/camera/frustum.cpp +++ b/libopenage/renderer/camera/frustum.cpp @@ -14,39 +14,40 @@ namespace openage::renderer::camera { -Frustum::Frustum() : - top_face_distance{0.0f}, - bottom_face_distance{0.0f}, - right_face_distance{0.0f}, - left_face_distance{0.0f}, - far_face_distance{0.0f}, - near_face_distance{0.0f}, - top_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, - bottom_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, - right_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, - left_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, - far_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)}, - near_face_normal{Eigen::Vector3f(0.0f, 0.0f, 0.0f)} { +Frustum::Frustum(const util::Vector2s &viewport_size, + const float near_distance, + const float far_distance, + const Eigen::Vector3f &camera_pos, + const Eigen::Vector3f &cam_direction, + const Eigen::Vector3f &up_direction, + const float zoom_factor) { + this->update(viewport_size, + near_distance, + far_distance, + camera_pos, + cam_direction, + up_direction, + zoom_factor); } -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) { +void Frustum::update(const util::Vector2s &viewport_size, + const float near_distance, + const float far_distance, + const Eigen::Vector3f &camera_pos, + const Eigen::Vector3f &cam_direction, + const Eigen::Vector3f &up_direction, + const float zoom_factor) { // offsets are adjusted by zoom // this is the same calculation as for the projection matrix float halfscreenwidth = viewport_size[0] / 2; float halfscreenheight = viewport_size[1] / 2; - float halfwidth = halfscreenwidth * real_zoom; - float halfheight = halfscreenheight * real_zoom; + float halfwidth = halfscreenwidth * zoom_factor; + float halfheight = halfscreenheight * zoom_factor; Eigen::Vector3f direction = cam_direction.normalized(); - Eigen::Vector3f eye = scene_pos; - Eigen::Vector3f center = scene_pos + direction; + Eigen::Vector3f eye = camera_pos; + Eigen::Vector3f center = camera_pos + direction; // calculate up (u) and right (s) vectors for camera // these define the camera plane in 3D space that the input @@ -57,8 +58,9 @@ void Frustum::update(util::Vector2s &viewport_size, Eigen::Vector3f u = s.cross(f); u.normalize(); - Eigen::Vector3f near_position = scene_pos + direction * near_distance; - Eigen::Vector3f far_position = scene_pos + direction * far_distance; + // calculate distance of the camera position to the near and far plane + Eigen::Vector3f near_position = camera_pos + direction * near_distance; + Eigen::Vector3f far_position = camera_pos + direction * far_distance; // 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; @@ -67,7 +69,7 @@ void Frustum::update(util::Vector2s &viewport_size, Eigen::Vector3f near_bottom_right = near_position + s * halfwidth - u * halfheight; Eigen::Vector3f far_top_left = far_position - s * halfwidth + u * halfheight; - Eigen::Vector3f far_top_right = far_position + s * halfwidth + u * halfheight; + // Eigen::Vector3f far_top_right = far_position + s * halfwidth + u * halfheight; // unused Eigen::Vector3f far_bottom_left = far_position - s * halfwidth - u * halfheight; Eigen::Vector3f far_bottom_right = far_position + s * halfwidth - u * halfheight; @@ -75,6 +77,7 @@ void Frustum::update(util::Vector2s &viewport_size, this->near_face_normal = cam_direction.normalized(); this->far_face_normal = -1.0f * cam_direction.normalized(); + // The distance of the plane from the origin is the dot product of the normal and a point on the plane this->near_face_distance = this->near_face_normal.dot(near_position); this->far_face_distance = this->far_face_normal.dot(far_position); @@ -84,18 +87,21 @@ void Frustum::update(util::Vector2s &viewport_size, this->top_face_normal = (near_top_right - near_top_left).cross(near_top_left - far_top_left); this->bottom_face_normal = (near_bottom_left - far_bottom_left).cross(near_bottom_right - near_bottom_left); + // for orthographic projection, the normal of left/right should equal -s/s + // and the normal of top/bottom should equal u/-u this->left_face_normal.normalize(); this->right_face_normal.normalize(); this->top_face_normal.normalize(); this->bottom_face_normal.normalize(); + // calculate the distance of the planes to the origin this->left_face_distance = this->left_face_normal.dot(near_bottom_left); this->right_face_distance = this->right_face_normal.dot(far_bottom_right); this->top_face_distance = this->top_face_normal.dot(near_top_right); this->bottom_face_distance = this->bottom_face_normal.dot(near_bottom_left); } -bool Frustum::in_frustum(Eigen::Vector3f &pos) const { +bool Frustum::in_frustum(const 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 d1d32ce296..32ae5cb820 100644 --- a/libopenage/renderer/camera/frustum.h +++ b/libopenage/renderer/camera/frustum.h @@ -15,17 +15,35 @@ namespace openage::renderer::camera { /** - * Frustum for a camera. + * Frustum for a camera. The frustum is defined by 6 planes (top, bottom, right, left, far, near) that + * define the viewing volume of the camera. * * Used for frustum culling (https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling) * in the renderer. + * + * As the openage camera uses orthographic projection, the frustum is a box, i.e. plane opposite + * to each other are parallel. */ class Frustum { public: /** * Create a new frustum. + * + * @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 camera_pos Scene position of the camera. + * @param cam_direction Direction the camera is looking at. + * @param up_direction Up direction of the camera. + * @param zoom_factor Zoom factor of the camera. */ - Frustum(); + Frustum(const util::Vector2s &viewport_size, + const float near_distance, + const float far_distance, + const Eigen::Vector3f &camera_pos, + const Eigen::Vector3f &cam_direction, + const Eigen::Vector3f &up_direction, + const float zoom_factor); /** * Update this frustum with the new camera parameters. @@ -33,18 +51,18 @@ class Frustum { * @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 camera_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. + * @param zoom_factor 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); + void update(const util::Vector2s &viewport_size, + const float near_distance, + const float far_distance, + const Eigen::Vector3f &camera_pos, + const Eigen::Vector3f &cam_direction, + const Eigen::Vector3f &up_direction, + const float zoom_factor); /** * Check whether a point in the scene is inside the frustum. @@ -53,21 +71,67 @@ class Frustum { * * @return true if the point is inside the frustum, else false. */ - bool in_frustum(Eigen::Vector3f &scene_pos) const; + bool in_frustum(const Eigen::Vector3f &scene_pos) const; private: + /** + * Normal vector of the top face. + */ Eigen::Vector3f top_face_normal; + + /** + * Normal vector of the bottom face. + */ Eigen::Vector3f bottom_face_normal; + + /** + * Normal vector of the right face. + */ Eigen::Vector3f right_face_normal; + + /** + * Normal vector of the left face. + */ Eigen::Vector3f left_face_normal; + + /** + * Normal vector of the far face. + */ Eigen::Vector3f far_face_normal; + + /** + * Normal vector of the near face. + */ Eigen::Vector3f near_face_normal; + /** + * Shortest distance from the top face to the scene origin. + */ float top_face_distance; + + /** + * Shortest distance from the bottom face to the scene origin. + */ float bottom_face_distance; + + /** + * Shortest distance from the right face to the scene origin. + */ float right_face_distance; + + /** + * Shortest distance from the left face to the scene origin. + */ float left_face_distance; + + /** + * Shortest distance from the far face to the scene origin. + */ float far_face_distance; + + /** + * Shortest distance from the near face to the scene origin. + */ float near_face_distance; }; } // namespace openage::renderer::camera diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp index a33f89f152..d099e2451a 100644 --- a/libopenage/renderer/stages/world/object.cpp +++ b/libopenage/renderer/stages/world/object.cpp @@ -10,7 +10,6 @@ #include -#include "renderer/camera/camera.h" #include "renderer/camera/frustum.h" #include "renderer/definitions.h" #include "renderer/resources/animation/angle_info.h" @@ -225,10 +224,9 @@ void WorldObject::set_uniforms(std::vectorlayer_uniforms = std::move(uniforms); } -bool WorldObject::within_camera_frustum(const std::shared_ptr &camera, - const time::time_t &time) { +bool WorldObject::is_visible(const camera::Frustum &frustum, + const time::time_t &time) { Eigen::Vector3f current_pos = this->position.get(time).to_world_space(); - auto frustum = camera->get_frustum(); return frustum.in_frustum(current_pos); } diff --git a/libopenage/renderer/stages/world/object.h b/libopenage/renderer/stages/world/object.h index cdad725ae8..63a07696eb 100644 --- a/libopenage/renderer/stages/world/object.h +++ b/libopenage/renderer/stages/world/object.h @@ -20,7 +20,7 @@ namespace openage::renderer { class UniformInput; namespace camera { -class Camera; +class Frustum; } namespace resources { @@ -133,8 +133,16 @@ class WorldObject { */ void set_uniforms(std::vector> &&uniforms); - bool within_camera_frustum(const std::shared_ptr &camera, - const time::time_t &time); + /** + * Check whether the object is visible in the camera view. + * + * @param frustum Camera frustum for culling. + * @param time Current simulation time. + * + * @return true if the object is visible, else false. + */ + bool is_visible(const camera::Frustum &frustum, + 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 2e70776c18..1b3608885b 100644 --- a/libopenage/renderer/stages/world/render_stage.cpp +++ b/libopenage/renderer/stages/world/render_stage.cpp @@ -3,6 +3,7 @@ #include "render_stage.h" #include "renderer/camera/camera.h" +#include "renderer/camera/frustum.h" #include "renderer/opengl/context.h" #include "renderer/render_pass.h" #include "renderer/render_target.h" @@ -58,10 +59,11 @@ void WorldRenderStage::add_render_entity(const std::shared_ptrmutex}; auto current_time = this->clock->get_real_time(); + auto &camera_frustum = this->camera->get_frustum(); for (auto &obj : this->render_objects) { obj->fetch_updates(current_time); - if (not obj->within_camera_frustum(this->camera, current_time)) { + if (not obj->is_visible(camera_frustum, current_time)) { continue; } From d88fb47b7049f0d95470561cb62fd506e742762a Mon Sep 17 00:00:00 2001 From: heinezen Date: Mon, 15 Jul 2024 22:57:55 +0200 Subject: [PATCH 20/32] renderer: Rename Frustum class to Frustum3d. --- libopenage/renderer/camera/CMakeLists.txt | 2 +- libopenage/renderer/camera/camera.cpp | 2 +- libopenage/renderer/camera/camera.h | 8 ++--- .../camera/{frustum.cpp => frustum_3d.cpp} | 32 +++++++++---------- .../camera/{frustum.h => frustum_3d.h} | 21 ++++++------ libopenage/renderer/stages/world/object.cpp | 4 +-- libopenage/renderer/stages/world/object.h | 4 +-- .../renderer/stages/world/render_stage.cpp | 4 +-- 8 files changed, 39 insertions(+), 38 deletions(-) rename libopenage/renderer/camera/{frustum.cpp => frustum_3d.cpp} (90%) rename libopenage/renderer/camera/{frustum.h => frustum_3d.h} (85%) diff --git a/libopenage/renderer/camera/CMakeLists.txt b/libopenage/renderer/camera/CMakeLists.txt index a3ffbd067f..e639bc75fa 100644 --- a/libopenage/renderer/camera/CMakeLists.txt +++ b/libopenage/renderer/camera/CMakeLists.txt @@ -1,5 +1,5 @@ add_sources(libopenage camera.cpp definitions.cpp - frustum.cpp + frustum_3d.cpp ) diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index 309b29737c..383c2124d6 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -287,7 +287,7 @@ const std::shared_ptr &Camera::get_uniform_buffer() con return this->uniform_buffer; } -const Frustum &Camera::get_frustum() const { +const Frustum3d &Camera::get_frustum_3d() const { return this->frustum; } diff --git a/libopenage/renderer/camera/camera.h b/libopenage/renderer/camera/camera.h index 8fc72b2a72..6791a6b8d8 100644 --- a/libopenage/renderer/camera/camera.h +++ b/libopenage/renderer/camera/camera.h @@ -13,7 +13,7 @@ #include "util/vector.h" #include "renderer/camera/definitions.h" -#include "renderer/camera/frustum.h" +#include "renderer/camera/frustum_3d.h" namespace openage::renderer { class Renderer; @@ -183,11 +183,11 @@ class Camera { const std::shared_ptr &get_uniform_buffer() const; /** - * Get a frustum object for this camera. + * Get a 3D frustum object for this camera. * * @return Frustum object. */ - const Frustum &get_frustum() const; + const Frustum3d &get_frustum_3d() const; private: /** @@ -297,7 +297,7 @@ class Camera { /** * Frustum (viewing volume) for culling rendering objects. */ - Frustum frustum; + Frustum3d frustum; }; } // namespace camera diff --git a/libopenage/renderer/camera/frustum.cpp b/libopenage/renderer/camera/frustum_3d.cpp similarity index 90% rename from libopenage/renderer/camera/frustum.cpp rename to libopenage/renderer/camera/frustum_3d.cpp index 661672206a..f4dddc9f27 100644 --- a/libopenage/renderer/camera/frustum.cpp +++ b/libopenage/renderer/camera/frustum_3d.cpp @@ -1,6 +1,6 @@ // Copyright 2024-2024 the openage authors. See copying.md for legal info. -#include "frustum.h" +#include "frustum_3d.h" #include #include @@ -14,13 +14,13 @@ namespace openage::renderer::camera { -Frustum::Frustum(const util::Vector2s &viewport_size, - const float near_distance, - const float far_distance, - const Eigen::Vector3f &camera_pos, - const Eigen::Vector3f &cam_direction, - const Eigen::Vector3f &up_direction, - const float zoom_factor) { +Frustum3d::Frustum3d(const util::Vector2s &viewport_size, + const float near_distance, + const float far_distance, + const Eigen::Vector3f &camera_pos, + const Eigen::Vector3f &cam_direction, + const Eigen::Vector3f &up_direction, + const float zoom_factor) { this->update(viewport_size, near_distance, far_distance, @@ -30,13 +30,13 @@ Frustum::Frustum(const util::Vector2s &viewport_size, zoom_factor); } -void Frustum::update(const util::Vector2s &viewport_size, - const float near_distance, - const float far_distance, - const Eigen::Vector3f &camera_pos, - const Eigen::Vector3f &cam_direction, - const Eigen::Vector3f &up_direction, - const float zoom_factor) { +void Frustum3d::update(const util::Vector2s &viewport_size, + const float near_distance, + const float far_distance, + const Eigen::Vector3f &camera_pos, + const Eigen::Vector3f &cam_direction, + const Eigen::Vector3f &up_direction, + const float zoom_factor) { // offsets are adjusted by zoom // this is the same calculation as for the projection matrix float halfscreenwidth = viewport_size[0] / 2; @@ -101,7 +101,7 @@ void Frustum::update(const util::Vector2s &viewport_size, this->bottom_face_distance = this->bottom_face_normal.dot(near_bottom_left); } -bool Frustum::in_frustum(const Eigen::Vector3f &pos) const { +bool Frustum3d::in_frustum(const 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_3d.h similarity index 85% rename from libopenage/renderer/camera/frustum.h rename to libopenage/renderer/camera/frustum_3d.h index 32ae5cb820..d777a0d403 100644 --- a/libopenage/renderer/camera/frustum.h +++ b/libopenage/renderer/camera/frustum_3d.h @@ -15,8 +15,9 @@ namespace openage::renderer::camera { /** - * Frustum for a camera. The frustum is defined by 6 planes (top, bottom, right, left, far, near) that - * define the viewing volume of the camera. + * Frustum for culling objects outside of a camera viewcone in 3D space. The frustum + * is defined by 6 planes (top, bottom, right, left, far, near) that define the boundaries + * of the viewing volume of the camera. * * Used for frustum culling (https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling) * in the renderer. @@ -24,7 +25,7 @@ namespace openage::renderer::camera { * As the openage camera uses orthographic projection, the frustum is a box, i.e. plane opposite * to each other are parallel. */ -class Frustum { +class Frustum3d { public: /** * Create a new frustum. @@ -37,13 +38,13 @@ class Frustum { * @param up_direction Up direction of the camera. * @param zoom_factor Zoom factor of the camera. */ - Frustum(const util::Vector2s &viewport_size, - const float near_distance, - const float far_distance, - const Eigen::Vector3f &camera_pos, - const Eigen::Vector3f &cam_direction, - const Eigen::Vector3f &up_direction, - const float zoom_factor); + Frustum3d(const util::Vector2s &viewport_size, + const float near_distance, + const float far_distance, + const Eigen::Vector3f &camera_pos, + const Eigen::Vector3f &cam_direction, + const Eigen::Vector3f &up_direction, + const float zoom_factor); /** * Update this frustum with the new camera parameters. diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp index d099e2451a..93ef82f4d2 100644 --- a/libopenage/renderer/stages/world/object.cpp +++ b/libopenage/renderer/stages/world/object.cpp @@ -10,7 +10,7 @@ #include -#include "renderer/camera/frustum.h" +#include "renderer/camera/frustum_3d.h" #include "renderer/definitions.h" #include "renderer/resources/animation/angle_info.h" #include "renderer/resources/animation/animation_info.h" @@ -224,7 +224,7 @@ void WorldObject::set_uniforms(std::vectorlayer_uniforms = std::move(uniforms); } -bool WorldObject::is_visible(const camera::Frustum &frustum, +bool WorldObject::is_visible(const camera::Frustum3d &frustum, const time::time_t &time) { Eigen::Vector3f current_pos = this->position.get(time).to_world_space(); return frustum.in_frustum(current_pos); diff --git a/libopenage/renderer/stages/world/object.h b/libopenage/renderer/stages/world/object.h index 63a07696eb..9576d906c9 100644 --- a/libopenage/renderer/stages/world/object.h +++ b/libopenage/renderer/stages/world/object.h @@ -20,7 +20,7 @@ namespace openage::renderer { class UniformInput; namespace camera { -class Frustum; +class Frustum3d; } namespace resources { @@ -141,7 +141,7 @@ class WorldObject { * * @return true if the object is visible, else false. */ - bool is_visible(const camera::Frustum &frustum, + bool is_visible(const camera::Frustum3d &frustum, const time::time_t &time); /** diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp index 1b3608885b..85378aef09 100644 --- a/libopenage/renderer/stages/world/render_stage.cpp +++ b/libopenage/renderer/stages/world/render_stage.cpp @@ -3,7 +3,7 @@ #include "render_stage.h" #include "renderer/camera/camera.h" -#include "renderer/camera/frustum.h" +#include "renderer/camera/frustum_3d.h" #include "renderer/opengl/context.h" #include "renderer/render_pass.h" #include "renderer/render_target.h" @@ -59,7 +59,7 @@ void WorldRenderStage::add_render_entity(const std::shared_ptrmutex}; auto current_time = this->clock->get_real_time(); - auto &camera_frustum = this->camera->get_frustum(); + auto &camera_frustum = this->camera->get_frustum_3d(); for (auto &obj : this->render_objects) { obj->fetch_updates(current_time); From 6926049672cd274bdf39f2743555880dc1013139 Mon Sep 17 00:00:00 2001 From: heinezen Date: Tue, 16 Jul 2024 02:35:34 +0200 Subject: [PATCH 21/32] renderer: 2D Frustum implementation. --- libopenage/renderer/camera/CMakeLists.txt | 1 + libopenage/renderer/camera/frustum_2d.cpp | 63 +++++++++++++++ libopenage/renderer/camera/frustum_2d.h | 79 +++++++++++++++++++ libopenage/renderer/camera/frustum_3d.cpp | 9 --- libopenage/renderer/camera/frustum_3d.h | 7 +- .../renderer/resources/texture_subinfo.h | 2 +- 6 files changed, 145 insertions(+), 16 deletions(-) create mode 100644 libopenage/renderer/camera/frustum_2d.cpp create mode 100644 libopenage/renderer/camera/frustum_2d.h diff --git a/libopenage/renderer/camera/CMakeLists.txt b/libopenage/renderer/camera/CMakeLists.txt index e639bc75fa..aea6391e7a 100644 --- a/libopenage/renderer/camera/CMakeLists.txt +++ b/libopenage/renderer/camera/CMakeLists.txt @@ -1,5 +1,6 @@ add_sources(libopenage camera.cpp definitions.cpp + frustum_2d.cpp frustum_3d.cpp ) diff --git a/libopenage/renderer/camera/frustum_2d.cpp b/libopenage/renderer/camera/frustum_2d.cpp new file mode 100644 index 0000000000..38c1ff537c --- /dev/null +++ b/libopenage/renderer/camera/frustum_2d.cpp @@ -0,0 +1,63 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#include "frustum_2d.h" + + +namespace openage::renderer::camera { + +Frustum2d::Frustum2d(const util::Vector2s &viewport_size, + const Eigen::Matrix4f &view_matrix, + const Eigen::Matrix4f &projection_matrix, + const float zoom_factor) { + this->update(viewport_size, view_matrix, projection_matrix, zoom_factor); +} + +void Frustum2d::update(const util::Vector2s &viewport_size, + const Eigen::Matrix4f &view_matrix, + const Eigen::Matrix4f &projection_matrix, + const float zoom_factor) { + this->inv_viewport_size = {1.0f / viewport_size[0], 1.0f / viewport_size[1]}; + this->inv_zoom_factor = 1.0f / zoom_factor; + + // calculate the transformation matrix + this->transform_matrix = projection_matrix * view_matrix; +} + +bool Frustum2d::in_frustum(const Eigen::Vector3f &scene_pos, + const float scalefactor, + const Eigen::Vector4i &boundaries) const { + // calculate the position of the scene object in screen space + Eigen::Vector4f screen_pos = this->transform_matrix * Eigen::Vector4f(scene_pos[0], scene_pos[1], scene_pos[2], 1.0f); + float x_ndc = screen_pos[0]; + float y_ndc = screen_pos[1]; + + float zoom_scale = scalefactor * this->inv_zoom_factor; + + // Scale the boundaries by the zoom factor + Eigen::Vector4f scaled_boundaries{boundaries[0] * zoom_scale * this->inv_viewport_size[0], + boundaries[1] * zoom_scale * this->inv_viewport_size[0], + boundaries[2] * zoom_scale * this->inv_viewport_size[1], + boundaries[3] * zoom_scale * this->inv_viewport_size[1]}; + float left_bound = scaled_boundaries[0]; + float right_bound = scaled_boundaries[1]; + float top_bound = scaled_boundaries[2]; + float bottom_bound = scaled_boundaries[3]; + + // check if the object boundaries are inside the frustum + if (x_ndc - left_bound > 1.0f) { + return false; + } + if (x_ndc + right_bound < -1.0f) { + return false; + } + if (y_ndc + top_bound < -1.0f) { + return false; + } + if (y_ndc - bottom_bound > 1.0f) { + return false; + } + + return true; +} + +} // namespace openage::renderer::camera diff --git a/libopenage/renderer/camera/frustum_2d.h b/libopenage/renderer/camera/frustum_2d.h new file mode 100644 index 0000000000..16cb2e8548 --- /dev/null +++ b/libopenage/renderer/camera/frustum_2d.h @@ -0,0 +1,79 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "util/vector.h" + +namespace openage::renderer::camera { + +/** + * Frustum for culling objects outside of a camera view in 2D screen space. + * This frustum object should be used for sprite culling as sprites do not exist in 3D world space. + * They are directly projected and reszied to the screen space. + * + * Used for frustum culling (https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling) + * in the renderer. + */ +class Frustum2d { +public: + /** + * Create a new 2D frustum. + * + * @param viewport_size Size of the camera viewport (width x height). + * @param view_matrix View matrix of the camera. + * @param projection_matrix Projection matrix of the camera. + * @param zoom_factor Zoom factor of the camera. + */ + Frustum2d(const util::Vector2s &viewport_size, + const Eigen::Matrix4f &view_matrix, + const Eigen::Matrix4f &projection_matrix, + const float zoom_factor); + + /** + * Update the frustum with new camera parameters. + * + * @param viewport_size Size of the camera viewport (width x height). + * @param view_matrix View matrix of the camera. + * @param projection_matrix Projection matrix of the camera. + * @param zoom_factor Zoom factor of the camera. + */ + void update(const util::Vector2s &viewport_size, + const Eigen::Matrix4f &view_matrix, + const Eigen::Matrix4f &projection_matrix, + const float zoom_factor); + + /** + * Check if a scene object is inside the frustum. + * + * @param scene_pos 3D scene coordinates. + * @param scalefactor Scale factor of the animation. + * @param boundaries Boundaries of the animation (in pixels): left, right, top, bottom. + * + * @return true if the object is inside the frustum, false otherwise. + */ + bool in_frustum(const Eigen::Vector3f &scene_pos, + const float scalefactor, + const Eigen::Vector4i &boundaries) const; + +private: + /** + * Camera transformation matrix. + * + * Pre-calculated from view and projection matrix. + */ + Eigen::Matrix4f transform_matrix; + + /** + * Viewport size of the camera (width x height). + */ + Eigen::Vector2f inv_viewport_size; + + /** + * Zoom factor of the camera. + */ + float inv_zoom_factor; +}; + +} // namespace openage::renderer::camera diff --git a/libopenage/renderer/camera/frustum_3d.cpp b/libopenage/renderer/camera/frustum_3d.cpp index f4dddc9f27..0f4b9bb340 100644 --- a/libopenage/renderer/camera/frustum_3d.cpp +++ b/libopenage/renderer/camera/frustum_3d.cpp @@ -2,15 +2,6 @@ #include "frustum_3d.h" -#include -#include -#include -#include - -#include "coord/pixel.h" -#include "coord/scene.h" -#include "renderer/renderer.h" -#include "renderer/resources/buffer_info.h" namespace openage::renderer::camera { diff --git a/libopenage/renderer/camera/frustum_3d.h b/libopenage/renderer/camera/frustum_3d.h index d777a0d403..789b7f1064 100644 --- a/libopenage/renderer/camera/frustum_3d.h +++ b/libopenage/renderer/camera/frustum_3d.h @@ -2,16 +2,11 @@ #pragma once -#include -#include -#include - #include -#include "coord/pixel.h" -#include "coord/scene.h" #include "util/vector.h" + namespace openage::renderer::camera { /** diff --git a/libopenage/renderer/resources/texture_subinfo.h b/libopenage/renderer/resources/texture_subinfo.h index c4114f0fd3..85a0899861 100644 --- a/libopenage/renderer/resources/texture_subinfo.h +++ b/libopenage/renderer/resources/texture_subinfo.h @@ -71,7 +71,7 @@ class Texture2dSubInfo { const Eigen::Vector4f &get_tile_params() const; /** - * Get the anchor parameters of the subtexture center. Used in the model matrix + * Get the anchor parameters of the subtexture center. Used in the shader * to calculate the offset position for displaying the subtexture inside * the OpenGL viewport. * From 0c0efa6b306d158a20b7bb5fc2ea825e78dd2995 Mon Sep 17 00:00:00 2001 From: heinezen Date: Thu, 18 Jul 2024 07:47:06 +0200 Subject: [PATCH 22/32] renderer: Get max bounds for animations. --- libopenage/renderer/camera/frustum_2d.cpp | 2 +- libopenage/renderer/camera/frustum_2d.h | 2 +- .../resources/animation/animation_info.cpp | 47 ++++++++++++++++++- .../resources/animation/animation_info.h | 30 +++++++++++- .../renderer/resources/texture_subinfo.cpp | 4 +- .../renderer/resources/texture_subinfo.h | 4 +- libopenage/renderer/stages/world/object.cpp | 2 +- 7 files changed, 81 insertions(+), 10 deletions(-) diff --git a/libopenage/renderer/camera/frustum_2d.cpp b/libopenage/renderer/camera/frustum_2d.cpp index 38c1ff537c..9e862165ca 100644 --- a/libopenage/renderer/camera/frustum_2d.cpp +++ b/libopenage/renderer/camera/frustum_2d.cpp @@ -25,7 +25,7 @@ void Frustum2d::update(const util::Vector2s &viewport_size, bool Frustum2d::in_frustum(const Eigen::Vector3f &scene_pos, const float scalefactor, - const Eigen::Vector4i &boundaries) const { + const util::Vector4i &boundaries) const { // calculate the position of the scene object in screen space Eigen::Vector4f screen_pos = this->transform_matrix * Eigen::Vector4f(scene_pos[0], scene_pos[1], scene_pos[2], 1.0f); float x_ndc = screen_pos[0]; diff --git a/libopenage/renderer/camera/frustum_2d.h b/libopenage/renderer/camera/frustum_2d.h index 16cb2e8548..68e9686fcb 100644 --- a/libopenage/renderer/camera/frustum_2d.h +++ b/libopenage/renderer/camera/frustum_2d.h @@ -55,7 +55,7 @@ class Frustum2d { */ bool in_frustum(const Eigen::Vector3f &scene_pos, const float scalefactor, - const Eigen::Vector4i &boundaries) const; + const util::Vector4i &boundaries) const; private: /** diff --git a/libopenage/renderer/resources/animation/animation_info.cpp b/libopenage/renderer/resources/animation/animation_info.cpp index 0f309a6fa7..64939a3f56 100644 --- a/libopenage/renderer/resources/animation/animation_info.cpp +++ b/libopenage/renderer/resources/animation/animation_info.cpp @@ -1,7 +1,12 @@ -// Copyright 2021-2023 the openage authors. See copying.md for legal info. +// Copyright 2021-2024 the openage authors. See copying.md for legal info. #include "animation_info.h" +#include "renderer/resources/animation/angle_info.h" +#include "renderer/resources/animation/frame_info.h" +#include "renderer/resources/texture_info.h" + + namespace openage::renderer::resources { Animation2dInfo::Animation2dInfo(const float scalefactor, @@ -9,7 +14,36 @@ Animation2dInfo::Animation2dInfo(const float scalefactor, std::vector &layers) : scalefactor{scalefactor}, texture_infos{textures}, - layers{layers} {} + layers{layers}, + max_bounds{} { + // Calculate max bounds + for (auto &layer : this->layers) { + for (size_t i = 0; i < layer.get_angle_count(); ++i) { + auto &angle = layer.get_angle(i); + for (size_t j = 0; j < angle->get_frame_count(); ++j) { + auto &frame = angle->get_frame(j); + auto tex_idx = frame->get_texture_idx(); + auto subtex_idx = frame->get_subtexture_idx(); + + auto &tex = this->texture_infos.at(tex_idx); + auto &subtex = tex->get_subtex_info(subtex_idx); + + auto subtex_size = subtex.get_size(); + auto anchor_pos = subtex.get_anchor_pos(); + + int left_margin = anchor_pos.x(); + int right_margin = subtex_size.x() - anchor_pos.x(); + int top_margin = anchor_pos.y(); + int bottom_margin = subtex_size.y() - anchor_pos.y(); + + this->max_bounds[0] = std::max(this->max_bounds[0], left_margin); + this->max_bounds[1] = std::max(this->max_bounds[1], right_margin); + this->max_bounds[2] = std::max(this->max_bounds[2], top_margin); + this->max_bounds[3] = std::max(this->max_bounds[3], bottom_margin); + } + } + } +} float Animation2dInfo::get_scalefactor() const { return this->scalefactor; @@ -31,4 +65,13 @@ const LayerInfo &Animation2dInfo::get_layer(size_t idx) const { return this->layers.at(idx); } +const util::Vector4i &Animation2dInfo::get_max_bounds() const { + return this->max_bounds; +} + +const util::Vector2s Animation2dInfo::get_max_size() const { + return {this->max_bounds[0] + this->max_bounds[1], + this->max_bounds[2] + this->max_bounds[3]}; +} + } // namespace openage::renderer::resources diff --git a/libopenage/renderer/resources/animation/animation_info.h b/libopenage/renderer/resources/animation/animation_info.h index be53acb180..1e778d892e 100644 --- a/libopenage/renderer/resources/animation/animation_info.h +++ b/libopenage/renderer/resources/animation/animation_info.h @@ -1,4 +1,4 @@ -// Copyright 2021-2023 the openage authors. See copying.md for legal info. +// Copyright 2021-2024 the openage authors. See copying.md for legal info. #pragma once @@ -7,6 +7,7 @@ #include #include "renderer/resources/animation/layer_info.h" +#include "util/vector.h" namespace openage::renderer::resources { @@ -79,6 +80,25 @@ class Animation2dInfo { */ const LayerInfo &get_layer(size_t idx) const; + /** + * Get the maximum boundaries for all frames in the animation. + * + * This represents the maximum distance from the anchor point to the + * left, right, top, bottom edges of the frames (in pixels). + * + * @return Boundaries of the animation (in pixels): [left, right, top, bottom] + */ + const util::Vector4i &get_max_bounds() const; + + /** + * Get the maximum size for all frames in the animation. + * + * This represents the maximum width and height of the frames (in pixels). + * + * @return Size of the animation (in pixels): [width, height] + */ + const util::Vector2s get_max_size() const; + private: /** * Scaling factor of the animation across all layers at default zoom level. @@ -94,6 +114,14 @@ class Animation2dInfo { * Layer information. */ std::vector layers; + + /** + * Maximum boundaries for all frames in the animation. + * + * This represents the maximum distance from the anchor point to the + * left, right, top, bottom edges of the frames (in pixels). + */ + util::Vector4i max_bounds; }; } // namespace openage::renderer::resources diff --git a/libopenage/renderer/resources/texture_subinfo.cpp b/libopenage/renderer/resources/texture_subinfo.cpp index d5c2168c4e..047becc76d 100644 --- a/libopenage/renderer/resources/texture_subinfo.cpp +++ b/libopenage/renderer/resources/texture_subinfo.cpp @@ -1,4 +1,4 @@ -// Copyright 2013-2023 the openage authors. See copying.md for legal info. +// Copyright 2013-2024 the openage authors. See copying.md for legal info. #include "texture_subinfo.h" @@ -38,7 +38,7 @@ const Eigen::Vector2i &Texture2dSubInfo::get_anchor_pos() const { return this->anchor_pos; } -const Eigen::Vector4f &Texture2dSubInfo::get_tile_params() const { +const Eigen::Vector4f &Texture2dSubInfo::get_subtex_coords() const { return this->tile_params; } diff --git a/libopenage/renderer/resources/texture_subinfo.h b/libopenage/renderer/resources/texture_subinfo.h index 85a0899861..70b1d039f3 100644 --- a/libopenage/renderer/resources/texture_subinfo.h +++ b/libopenage/renderer/resources/texture_subinfo.h @@ -53,7 +53,7 @@ class Texture2dSubInfo { const Eigen::Vector2 &get_size() const; /** - * Get the position of the subtexture anchor. + * Get the position of the subtexture anchor (origin == top left). * * @return Anchor coordinates as 2-dimensional Eigen vector: (x, y) */ @@ -68,7 +68,7 @@ class Texture2dSubInfo { * * @return Tile parameters as 4-dimensional Eigen vector: (x, y, width, height) */ - const Eigen::Vector4f &get_tile_params() const; + const Eigen::Vector4f &get_subtex_coords() const; /** * Get the anchor parameters of the subtexture center. Used in the shader diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp index 93ef82f4d2..35e541c322 100644 --- a/libopenage/renderer/stages/world/object.cpp +++ b/libopenage/renderer/stages/world/object.cpp @@ -143,7 +143,7 @@ void WorldObject::update_uniforms(const time::time_t &time) { layer_unifs->update(this->tex, texture); // Subtexture coordinates.inside texture - auto coords = tex_info->get_subtex_info(subtex_idx).get_tile_params(); + auto coords = tex_info->get_subtex_info(subtex_idx).get_subtex_coords(); layer_unifs->update(this->tile_params, coords); // Animation scale factor From 7391bc2c2af58fab1c503d2c9bd7873325cafed6 Mon Sep 17 00:00:00 2001 From: heinezen Date: Thu, 18 Jul 2024 07:47:22 +0200 Subject: [PATCH 23/32] renderer: Create 2D frustum for sprites. --- libopenage/renderer/camera/camera.cpp | 62 +++++++++++++++++---------- libopenage/renderer/camera/camera.h | 18 +++++++- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index 383c2124d6..7af5b3f761 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -26,13 +26,17 @@ Camera::Camera(const std::shared_ptr &renderer, zoom_changed{true}, view{Eigen::Matrix4f::Identity()}, proj{Eigen::Matrix4f::Identity()}, - frustum{this->viewport_size, - DEFAULT_NEAR_DISTANCE, - DEFAULT_FAR_DISTANCE, - this->scene_pos, - CAM_DIRECTION, - Eigen::Vector3f(0.0f, 1.0f, 0.0f), - this->get_zoom_factor()} { + frustum_2d{this->viewport_size, + this->get_view_matrix(), + this->get_projection_matrix(), + this->get_zoom_factor()}, + frustum_3d{this->viewport_size, + DEFAULT_NEAR_DISTANCE, + DEFAULT_FAR_DISTANCE, + this->scene_pos, + CAM_DIRECTION, + Eigen::Vector3f(0.0f, 1.0f, 0.0f), + this->get_zoom_factor()} { this->look_at_scene(Eigen::Vector3f(0.0f, 0.0f, 0.0f)); this->init_uniform_buffer(renderer); @@ -59,13 +63,17 @@ Camera::Camera(const std::shared_ptr &renderer, viewport_changed{true}, view{Eigen::Matrix4f::Identity()}, proj{Eigen::Matrix4f::Identity()}, - frustum{this->viewport_size, - DEFAULT_NEAR_DISTANCE, - DEFAULT_FAR_DISTANCE, - this->scene_pos, - CAM_DIRECTION, - Eigen::Vector3f(0.0f, 1.0f, 0.0f), - this->get_zoom_factor()} { + frustum_2d{this->viewport_size, + this->get_view_matrix(), + this->get_projection_matrix(), + this->get_zoom_factor()}, + frustum_3d{this->viewport_size, + DEFAULT_NEAR_DISTANCE, + DEFAULT_FAR_DISTANCE, + this->scene_pos, + CAM_DIRECTION, + Eigen::Vector3f(0.0f, 1.0f, 0.0f), + this->get_zoom_factor()} { this->init_uniform_buffer(renderer); log::log(INFO << "Created new camera at position " @@ -122,14 +130,18 @@ void Camera::move_to(Eigen::Vector3f scene_pos) { this->scene_pos = scene_pos; this->moved = true; - // Update frustum - frustum.update(viewport_size, - DEFAULT_NEAR_DISTANCE, - DEFAULT_FAR_DISTANCE, - scene_pos, - CAM_DIRECTION, - Eigen::Vector3f(0.0f, 1.0f, 0.0f), - this->get_zoom_factor()); + // Update frustums + this->frustum_2d.update(viewport_size, + view, + proj, + this->get_zoom_factor()); + this->frustum_3d.update(viewport_size, + DEFAULT_NEAR_DISTANCE, + DEFAULT_FAR_DISTANCE, + scene_pos, + CAM_DIRECTION, + Eigen::Vector3f(0.0f, 1.0f, 0.0f), + this->get_zoom_factor()); } void Camera::move_rel(Eigen::Vector3f direction, float delta) { @@ -287,8 +299,12 @@ const std::shared_ptr &Camera::get_uniform_buffer() con return this->uniform_buffer; } +const Frustum2d &Camera::get_frustum_2d() const { + return this->frustum_2d; +} + const Frustum3d &Camera::get_frustum_3d() const { - return this->frustum; + return this->frustum_3d; } void Camera::init_uniform_buffer(const std::shared_ptr &renderer) { diff --git a/libopenage/renderer/camera/camera.h b/libopenage/renderer/camera/camera.h index 6791a6b8d8..3cec10da16 100644 --- a/libopenage/renderer/camera/camera.h +++ b/libopenage/renderer/camera/camera.h @@ -13,8 +13,10 @@ #include "util/vector.h" #include "renderer/camera/definitions.h" +#include "renderer/camera/frustum_2d.h" #include "renderer/camera/frustum_3d.h" + namespace openage::renderer { class Renderer; class UniformBuffer; @@ -182,6 +184,13 @@ class Camera { */ const std::shared_ptr &get_uniform_buffer() const; + /** + * Get a 2D frustum object for this camera. + * + * @return Frustum object. + */ + const Frustum2d &get_frustum_2d() const; + /** * Get a 3D frustum object for this camera. * @@ -295,9 +304,14 @@ class Camera { std::shared_ptr uniform_buffer; /** - * Frustum (viewing volume) for culling rendering objects. + * 2D frustum (viewbox) for culling rendering objects. + */ + Frustum2d frustum_2d; + + /** + * 3D frustum (viewing volume) for culling rendering objects. */ - Frustum3d frustum; + Frustum3d frustum_3d; }; } // namespace camera From 769154b76f61441f9b3b96494e3f044d57cdda91 Mon Sep 17 00:00:00 2001 From: heinezen Date: Thu, 18 Jul 2024 08:03:16 +0200 Subject: [PATCH 24/32] renderer: Replace 3D frustum with 2D frustum in world renderer. --- libopenage/renderer/stages/world/object.cpp | 9 ++++++--- libopenage/renderer/stages/world/object.h | 4 ++-- libopenage/renderer/stages/world/render_stage.cpp | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp index 35e541c322..04bb27e391 100644 --- a/libopenage/renderer/stages/world/object.cpp +++ b/libopenage/renderer/stages/world/object.cpp @@ -10,7 +10,7 @@ #include -#include "renderer/camera/frustum_3d.h" +#include "renderer/camera/frustum_2d.h" #include "renderer/definitions.h" #include "renderer/resources/animation/angle_info.h" #include "renderer/resources/animation/animation_info.h" @@ -224,10 +224,13 @@ void WorldObject::set_uniforms(std::vectorlayer_uniforms = std::move(uniforms); } -bool WorldObject::is_visible(const camera::Frustum3d &frustum, +bool WorldObject::is_visible(const camera::Frustum2d &frustum, const time::time_t &time) { Eigen::Vector3f current_pos = this->position.get(time).to_world_space(); - return frustum.in_frustum(current_pos); + auto animation_info = this->animation_info.get(time); + return frustum.in_frustum(current_pos, + animation_info->get_scalefactor(), + animation_info->get_max_bounds()); } } // namespace openage::renderer::world diff --git a/libopenage/renderer/stages/world/object.h b/libopenage/renderer/stages/world/object.h index 9576d906c9..1302733954 100644 --- a/libopenage/renderer/stages/world/object.h +++ b/libopenage/renderer/stages/world/object.h @@ -20,7 +20,7 @@ namespace openage::renderer { class UniformInput; namespace camera { -class Frustum3d; +class Frustum2d; } namespace resources { @@ -141,7 +141,7 @@ class WorldObject { * * @return true if the object is visible, else false. */ - bool is_visible(const camera::Frustum3d &frustum, + bool is_visible(const camera::Frustum2d &frustum, const time::time_t &time); /** diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp index 85378aef09..4f3354a1fa 100644 --- a/libopenage/renderer/stages/world/render_stage.cpp +++ b/libopenage/renderer/stages/world/render_stage.cpp @@ -59,7 +59,7 @@ void WorldRenderStage::add_render_entity(const std::shared_ptrmutex}; auto current_time = this->clock->get_real_time(); - auto &camera_frustum = this->camera->get_frustum_3d(); + auto &camera_frustum = this->camera->get_frustum_2d(); for (auto &obj : this->render_objects) { obj->fetch_updates(current_time); From d7a8e5bddb5c849ab8676e58148eaccf7ce84127 Mon Sep 17 00:00:00 2001 From: heinezen Date: Thu, 18 Jul 2024 08:50:48 +0200 Subject: [PATCH 25/32] renderer: Use correct zoom value for 2D frustum. --- libopenage/renderer/camera/camera.cpp | 22 +++++++++++----------- libopenage/renderer/camera/camera.h | 8 +++++++- libopenage/renderer/camera/frustum_2d.cpp | 22 +++++++++++----------- libopenage/renderer/camera/frustum_2d.h | 8 ++++---- 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index 7af5b3f761..94cd87c00e 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -29,14 +29,14 @@ Camera::Camera(const std::shared_ptr &renderer, frustum_2d{this->viewport_size, this->get_view_matrix(), this->get_projection_matrix(), - this->get_zoom_factor()}, + this->get_zoom()}, frustum_3d{this->viewport_size, DEFAULT_NEAR_DISTANCE, DEFAULT_FAR_DISTANCE, this->scene_pos, CAM_DIRECTION, Eigen::Vector3f(0.0f, 1.0f, 0.0f), - this->get_zoom_factor()} { + this->get_real_zoom_factor()} { this->look_at_scene(Eigen::Vector3f(0.0f, 0.0f, 0.0f)); this->init_uniform_buffer(renderer); @@ -66,14 +66,14 @@ Camera::Camera(const std::shared_ptr &renderer, frustum_2d{this->viewport_size, this->get_view_matrix(), this->get_projection_matrix(), - this->get_zoom_factor()}, + this->get_zoom()}, frustum_3d{this->viewport_size, DEFAULT_NEAR_DISTANCE, DEFAULT_FAR_DISTANCE, this->scene_pos, CAM_DIRECTION, Eigen::Vector3f(0.0f, 1.0f, 0.0f), - this->get_zoom_factor()} { + this->get_real_zoom_factor()} { this->init_uniform_buffer(renderer); log::log(INFO << "Created new camera at position " @@ -132,16 +132,16 @@ void Camera::move_to(Eigen::Vector3f scene_pos) { // Update frustums this->frustum_2d.update(viewport_size, - view, - proj, - this->get_zoom_factor()); + this->get_view_matrix(), + this->get_projection_matrix(), + this->get_zoom()); this->frustum_3d.update(viewport_size, DEFAULT_NEAR_DISTANCE, DEFAULT_FAR_DISTANCE, scene_pos, CAM_DIRECTION, Eigen::Vector3f(0.0f, 1.0f, 0.0f), - this->get_zoom_factor()); + this->get_real_zoom_factor()); } void Camera::move_rel(Eigen::Vector3f direction, float delta) { @@ -232,7 +232,7 @@ const Eigen::Matrix4f &Camera::get_projection_matrix() { float halfheight = this->viewport_size[1] / 2; // get zoom level - float real_zoom = this->get_zoom_factor(); + float real_zoom = this->get_real_zoom_factor(); // zoom by narrowing or widening viewport around focus point. // narrow viewport => zoom in (projected area gets *smaller* while screen size stays the same) @@ -283,7 +283,7 @@ Eigen::Vector3f Camera::get_input_pos(const coord::input &coord) const { // this is the same calculation as for the projection matrix float halfwidth = this->viewport_size[0] / 2; float halfheight = this->viewport_size[1] / 2; - float real_zoom = this->get_zoom_factor(); + float real_zoom = this->get_real_zoom_factor(); // calculate x and y offset on the camera plane relative to the camera position float x = +(2.0f * coord.x / this->viewport_size[0] - 1) * (halfwidth * real_zoom); @@ -318,7 +318,7 @@ void Camera::init_uniform_buffer(const std::shared_ptr &renderer) { this->uniform_buffer = renderer->add_uniform_buffer(ubo_info); } -inline float Camera::get_zoom_factor() const { +inline float Camera::get_real_zoom_factor() const { return 0.5f * this->default_zoom_ratio * this->zoom; } diff --git a/libopenage/renderer/camera/camera.h b/libopenage/renderer/camera/camera.h index 3cec10da16..e92c345be6 100644 --- a/libopenage/renderer/camera/camera.h +++ b/libopenage/renderer/camera/camera.h @@ -139,6 +139,8 @@ class Camera { /** * Get the current zoom level of the camera. * + * Determines the scale of rendered objects. + * * @return Zoom level. */ float get_zoom() const; @@ -213,9 +215,13 @@ class Camera { * * zoom * zoom_ratio * 0.5f * + * Note that this zoom factor should NOT be used for sprite scaling, but + * only for 3D projection matrix calculations. For sprite scaling, use + * \p get_zoom() . + * * @return Zoom factor for projection. */ - inline float get_zoom_factor() const; + inline float get_real_zoom_factor() const; /** * Position in the 3D scene. diff --git a/libopenage/renderer/camera/frustum_2d.cpp b/libopenage/renderer/camera/frustum_2d.cpp index 9e862165ca..0eba531745 100644 --- a/libopenage/renderer/camera/frustum_2d.cpp +++ b/libopenage/renderer/camera/frustum_2d.cpp @@ -8,16 +8,16 @@ namespace openage::renderer::camera { Frustum2d::Frustum2d(const util::Vector2s &viewport_size, const Eigen::Matrix4f &view_matrix, const Eigen::Matrix4f &projection_matrix, - const float zoom_factor) { - this->update(viewport_size, view_matrix, projection_matrix, zoom_factor); + const float zoom) { + this->update(viewport_size, view_matrix, projection_matrix, zoom); } void Frustum2d::update(const util::Vector2s &viewport_size, const Eigen::Matrix4f &view_matrix, const Eigen::Matrix4f &projection_matrix, - const float zoom_factor) { + const float zoom) { this->inv_viewport_size = {1.0f / viewport_size[0], 1.0f / viewport_size[1]}; - this->inv_zoom_factor = 1.0f / zoom_factor; + this->inv_zoom_factor = 1.0f / zoom; // calculate the transformation matrix this->transform_matrix = projection_matrix * view_matrix; @@ -27,9 +27,9 @@ bool Frustum2d::in_frustum(const Eigen::Vector3f &scene_pos, const float scalefactor, const util::Vector4i &boundaries) const { // calculate the position of the scene object in screen space - Eigen::Vector4f screen_pos = this->transform_matrix * Eigen::Vector4f(scene_pos[0], scene_pos[1], scene_pos[2], 1.0f); - float x_ndc = screen_pos[0]; - float y_ndc = screen_pos[1]; + Eigen::Vector4f clip_pos = this->transform_matrix * Eigen::Vector4f(scene_pos[0], scene_pos[1], scene_pos[2], 1.0f); + float x_ndc = clip_pos[0]; + float y_ndc = clip_pos[1]; float zoom_scale = scalefactor * this->inv_zoom_factor; @@ -44,16 +44,16 @@ bool Frustum2d::in_frustum(const Eigen::Vector3f &scene_pos, float bottom_bound = scaled_boundaries[3]; // check if the object boundaries are inside the frustum - if (x_ndc - left_bound > 1.0f) { + if (x_ndc - left_bound >= 1.0f) { return false; } - if (x_ndc + right_bound < -1.0f) { + if (x_ndc + right_bound <= -1.0f) { return false; } - if (y_ndc + top_bound < -1.0f) { + if (y_ndc + top_bound <= -1.0f) { return false; } - if (y_ndc - bottom_bound > 1.0f) { + if (y_ndc - bottom_bound >= 1.0f) { return false; } diff --git a/libopenage/renderer/camera/frustum_2d.h b/libopenage/renderer/camera/frustum_2d.h index 68e9686fcb..21bcd9c7e3 100644 --- a/libopenage/renderer/camera/frustum_2d.h +++ b/libopenage/renderer/camera/frustum_2d.h @@ -24,12 +24,12 @@ class Frustum2d { * @param viewport_size Size of the camera viewport (width x height). * @param view_matrix View matrix of the camera. * @param projection_matrix Projection matrix of the camera. - * @param zoom_factor Zoom factor of the camera. + * @param zoom Zoom of the camera. */ Frustum2d(const util::Vector2s &viewport_size, const Eigen::Matrix4f &view_matrix, const Eigen::Matrix4f &projection_matrix, - const float zoom_factor); + const float zoom); /** * Update the frustum with new camera parameters. @@ -37,12 +37,12 @@ class Frustum2d { * @param viewport_size Size of the camera viewport (width x height). * @param view_matrix View matrix of the camera. * @param projection_matrix Projection matrix of the camera. - * @param zoom_factor Zoom factor of the camera. + * @param zoom Zoom of the camera. */ void update(const util::Vector2s &viewport_size, const Eigen::Matrix4f &view_matrix, const Eigen::Matrix4f &projection_matrix, - const float zoom_factor); + const float zoom); /** * Check if a scene object is inside the frustum. From 33021dc71710d3d00416ed1bef70d24334a178ba Mon Sep 17 00:00:00 2001 From: heinezen Date: Fri, 19 Jul 2024 01:05:25 +0200 Subject: [PATCH 26/32] renderer: Zig-zag movement in and out of camera view in stressttest 1. --- libopenage/renderer/demo/stresstest_1.cpp | 44 +++++++++++------------ 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/libopenage/renderer/demo/stresstest_1.cpp b/libopenage/renderer/demo/stresstest_1.cpp index 6ec2887503..72c21b5686 100644 --- a/libopenage/renderer/demo/stresstest_1.cpp +++ b/libopenage/renderer/demo/stresstest_1.cpp @@ -155,25 +155,25 @@ void renderer_stresstest_1(const util::Path &path) { auto position = curve::Continuous{nullptr, 0, "", nullptr, coord::phys3(0, 0, 0)}; position.set_insert(time, initial_pos); - position.set_insert(time + 1, initial_pos + coord::phys3_delta{0, 4, 0}); - position.set_insert(time + 2, initial_pos + coord::phys3_delta{4, 8, 0}); - position.set_insert(time + 3, initial_pos + coord::phys3_delta{8, 8, 0}); - position.set_insert(time + 4, initial_pos + coord::phys3_delta{12, 4, 0}); - position.set_insert(time + 5, initial_pos + coord::phys3_delta{12, 0, 0}); - position.set_insert(time + 6, initial_pos + coord::phys3_delta{8, -4, 0}); - position.set_insert(time + 7, initial_pos + coord::phys3_delta{4, -4, 0}); + position.set_insert(time + 1, initial_pos + coord::phys3_delta{5, 0, 0}); + position.set_insert(time + 2, initial_pos + coord::phys3_delta{12, -2, 0}); + position.set_insert(time + 3, initial_pos + coord::phys3_delta{5, 5, 0}); + position.set_insert(time + 4, initial_pos + coord::phys3_delta{12, 12, 0}); + position.set_insert(time + 5, initial_pos + coord::phys3_delta{5, 9, 0}); + position.set_insert(time + 6, initial_pos + coord::phys3_delta{-2, 12, 0}); + position.set_insert(time + 7, initial_pos + coord::phys3_delta{0, 5, 0}); position.set_insert(time + 8, initial_pos); auto angle = curve::Segmented{nullptr, 0}; - angle.set_insert(time, coord::phys_angle_t::from_int(315)); - angle.set_insert_jump(time + 1, coord::phys_angle_t::from_int(315), coord::phys_angle_t::from_int(270)); - angle.set_insert_jump(time + 2, coord::phys_angle_t::from_int(270), coord::phys_angle_t::from_int(225)); - angle.set_insert_jump(time + 3, coord::phys_angle_t::from_int(225), coord::phys_angle_t::from_int(180)); - angle.set_insert_jump(time + 4, coord::phys_angle_t::from_int(180), coord::phys_angle_t::from_int(135)); - angle.set_insert_jump(time + 5, coord::phys_angle_t::from_int(135), coord::phys_angle_t::from_int(90)); - angle.set_insert_jump(time + 6, coord::phys_angle_t::from_int(90), coord::phys_angle_t::from_int(45)); - angle.set_insert_jump(time + 7, coord::phys_angle_t::from_int(45), coord::phys_angle_t::from_int(0)); - angle.set_insert_jump(time + 8, coord::phys_angle_t::from_int(0), coord::phys_angle_t::from_int(315)); + angle.set_insert(time, coord::phys_angle_t::from_int(225)); + angle.set_insert_jump(time + 1, coord::phys_angle_t::from_int(225), coord::phys_angle_t::from_int(210)); + angle.set_insert_jump(time + 2, coord::phys_angle_t::from_int(210), coord::phys_angle_t::from_int(0)); + angle.set_insert_jump(time + 3, coord::phys_angle_t::from_int(0), coord::phys_angle_t::from_int(270)); + angle.set_insert_jump(time + 4, coord::phys_angle_t::from_int(270), coord::phys_angle_t::from_int(60)); + angle.set_insert_jump(time + 5, coord::phys_angle_t::from_int(60), coord::phys_angle_t::from_int(45)); + angle.set_insert_jump(time + 6, coord::phys_angle_t::from_int(45), coord::phys_angle_t::from_int(120)); + angle.set_insert_jump(time + 7, coord::phys_angle_t::from_int(120), coord::phys_angle_t::from_int(135)); + angle.set_insert_jump(time + 8, coord::phys_angle_t::from_int(135), coord::phys_angle_t::from_int(225)); auto entity = render_factory->add_world_render_entity(); entity->update(render_entities.size(), @@ -184,15 +184,14 @@ void renderer_stresstest_1(const util::Path &path) { render_entities.push_back(entity); }; - // Stop after 8000 entities - size_t entity_limit = 8000; + // Stop after 1000 entities + size_t entity_limit = 1000; clock->start(); util::FrameCounter timer; - add_world_entity(coord::phys3(0.0f, 10.0f, 0.0f), clock->get_time()); - time::time_t next_entity = clock->get_real_time() + 0.1; + time::time_t next_entity = clock->get_real_time(); while (render_entities.size() <= entity_limit) { // Print FPS timer.frame(); @@ -207,9 +206,8 @@ void renderer_stresstest_1(const util::Path &path) { clock->update_time(); auto current_time = clock->get_real_time(); if (current_time > next_entity) { - add_world_entity(coord::phys3(0.0f, 10.0f, 0.0f), clock->get_time()); - add_world_entity(coord::phys3(-1.f, 9.0f, 0.0f), clock->get_time()); - next_entity = current_time + 0.1; + add_world_entity(coord::phys3(0.5, 0.5, 0.0f), clock->get_time()); + next_entity = current_time + 0.05; } // Update the renderables of the subrenderers From 04bf89e5c4de21efedc95432e36976cc597bad65 Mon Sep 17 00:00:00 2001 From: heinezen Date: Fri, 19 Jul 2024 01:14:09 +0200 Subject: [PATCH 27/32] renderer: Construct camera frustumson the fly. --- libopenage/renderer/camera/camera.cpp | 56 +++++++-------------------- libopenage/renderer/camera/camera.h | 14 +------ 2 files changed, 17 insertions(+), 53 deletions(-) diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp index 94cd87c00e..f70efbee64 100644 --- a/libopenage/renderer/camera/camera.cpp +++ b/libopenage/renderer/camera/camera.cpp @@ -25,18 +25,7 @@ Camera::Camera(const std::shared_ptr &renderer, moved{true}, zoom_changed{true}, view{Eigen::Matrix4f::Identity()}, - proj{Eigen::Matrix4f::Identity()}, - frustum_2d{this->viewport_size, - this->get_view_matrix(), - this->get_projection_matrix(), - this->get_zoom()}, - frustum_3d{this->viewport_size, - DEFAULT_NEAR_DISTANCE, - DEFAULT_FAR_DISTANCE, - this->scene_pos, - CAM_DIRECTION, - Eigen::Vector3f(0.0f, 1.0f, 0.0f), - this->get_real_zoom_factor()} { + proj{Eigen::Matrix4f::Identity()} { this->look_at_scene(Eigen::Vector3f(0.0f, 0.0f, 0.0f)); this->init_uniform_buffer(renderer); @@ -62,18 +51,7 @@ Camera::Camera(const std::shared_ptr &renderer, zoom_changed{true}, viewport_changed{true}, view{Eigen::Matrix4f::Identity()}, - proj{Eigen::Matrix4f::Identity()}, - frustum_2d{this->viewport_size, - this->get_view_matrix(), - this->get_projection_matrix(), - this->get_zoom()}, - frustum_3d{this->viewport_size, - DEFAULT_NEAR_DISTANCE, - DEFAULT_FAR_DISTANCE, - this->scene_pos, - CAM_DIRECTION, - Eigen::Vector3f(0.0f, 1.0f, 0.0f), - this->get_real_zoom_factor()} { + proj{Eigen::Matrix4f::Identity()} { this->init_uniform_buffer(renderer); log::log(INFO << "Created new camera at position " @@ -129,19 +107,6 @@ void Camera::move_to(Eigen::Vector3f scene_pos) { this->scene_pos = scene_pos; this->moved = true; - - // Update frustums - this->frustum_2d.update(viewport_size, - this->get_view_matrix(), - this->get_projection_matrix(), - this->get_zoom()); - this->frustum_3d.update(viewport_size, - DEFAULT_NEAR_DISTANCE, - DEFAULT_FAR_DISTANCE, - scene_pos, - CAM_DIRECTION, - Eigen::Vector3f(0.0f, 1.0f, 0.0f), - this->get_real_zoom_factor()); } void Camera::move_rel(Eigen::Vector3f direction, float delta) { @@ -299,12 +264,21 @@ const std::shared_ptr &Camera::get_uniform_buffer() con return this->uniform_buffer; } -const Frustum2d &Camera::get_frustum_2d() const { - return this->frustum_2d; +const Frustum2d Camera::get_frustum_2d() { + return {this->viewport_size, + this->get_view_matrix(), + this->get_projection_matrix(), + this->get_zoom()}; } -const Frustum3d &Camera::get_frustum_3d() const { - return this->frustum_3d; +const Frustum3d Camera::get_frustum_3d() const { + return {this->viewport_size, + DEFAULT_NEAR_DISTANCE, + DEFAULT_FAR_DISTANCE, + this->scene_pos, + CAM_DIRECTION, + CAM_UP, + this->get_real_zoom_factor()}; } void Camera::init_uniform_buffer(const std::shared_ptr &renderer) { diff --git a/libopenage/renderer/camera/camera.h b/libopenage/renderer/camera/camera.h index e92c345be6..eccb5b40e6 100644 --- a/libopenage/renderer/camera/camera.h +++ b/libopenage/renderer/camera/camera.h @@ -191,14 +191,14 @@ class Camera { * * @return Frustum object. */ - const Frustum2d &get_frustum_2d() const; + const Frustum2d get_frustum_2d(); /** * Get a 3D frustum object for this camera. * * @return Frustum object. */ - const Frustum3d &get_frustum_3d() const; + const Frustum3d get_frustum_3d() const; private: /** @@ -308,16 +308,6 @@ class Camera { * Uniform buffer for the camera matrices. */ std::shared_ptr uniform_buffer; - - /** - * 2D frustum (viewbox) for culling rendering objects. - */ - Frustum2d frustum_2d; - - /** - * 3D frustum (viewing volume) for culling rendering objects. - */ - Frustum3d frustum_3d; }; } // namespace camera From 8edeb9d79a4c10ff327de99b1081f683efe26067 Mon Sep 17 00:00:00 2001 From: heinezen Date: Fri, 19 Jul 2024 01:43:15 +0200 Subject: [PATCH 28/32] renderer: Skip scaled vector creation in frustum. --- libopenage/renderer/camera/frustum_2d.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/libopenage/renderer/camera/frustum_2d.cpp b/libopenage/renderer/camera/frustum_2d.cpp index 0eba531745..3c5e123d82 100644 --- a/libopenage/renderer/camera/frustum_2d.cpp +++ b/libopenage/renderer/camera/frustum_2d.cpp @@ -33,15 +33,11 @@ bool Frustum2d::in_frustum(const Eigen::Vector3f &scene_pos, float zoom_scale = scalefactor * this->inv_zoom_factor; - // Scale the boundaries by the zoom factor - Eigen::Vector4f scaled_boundaries{boundaries[0] * zoom_scale * this->inv_viewport_size[0], - boundaries[1] * zoom_scale * this->inv_viewport_size[0], - boundaries[2] * zoom_scale * this->inv_viewport_size[1], - boundaries[3] * zoom_scale * this->inv_viewport_size[1]}; - float left_bound = scaled_boundaries[0]; - float right_bound = scaled_boundaries[1]; - float top_bound = scaled_boundaries[2]; - float bottom_bound = scaled_boundaries[3]; + // Scale the boundaries by the zoom factor and the viewport size + float left_bound = boundaries[0] * zoom_scale * this->inv_viewport_size[0]; + float right_bound = boundaries[1] * zoom_scale * this->inv_viewport_size[0]; + float top_bound = boundaries[2] * zoom_scale * this->inv_viewport_size[1]; + float bottom_bound = boundaries[3] * zoom_scale * this->inv_viewport_size[1]; // check if the object boundaries are inside the frustum if (x_ndc - left_bound >= 1.0f) { From b457b877ec25b3e919f5ee2dbbef547453c6dc87 Mon Sep 17 00:00:00 2001 From: heinezen Date: Fri, 19 Jul 2024 02:12:39 +0200 Subject: [PATCH 29/32] renderer: Inclide model matrix in 2D frustum check. --- libopenage/renderer/camera/frustum_2d.cpp | 3 ++- libopenage/renderer/camera/frustum_2d.h | 2 ++ libopenage/renderer/stages/world/object.cpp | 2 ++ libopenage/renderer/stages/world/render_stage.cpp | 4 ++-- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libopenage/renderer/camera/frustum_2d.cpp b/libopenage/renderer/camera/frustum_2d.cpp index 3c5e123d82..614b2b74a2 100644 --- a/libopenage/renderer/camera/frustum_2d.cpp +++ b/libopenage/renderer/camera/frustum_2d.cpp @@ -24,10 +24,11 @@ void Frustum2d::update(const util::Vector2s &viewport_size, } bool Frustum2d::in_frustum(const Eigen::Vector3f &scene_pos, + const Eigen::Matrix4f &model_matrix, const float scalefactor, const util::Vector4i &boundaries) const { // calculate the position of the scene object in screen space - Eigen::Vector4f clip_pos = this->transform_matrix * Eigen::Vector4f(scene_pos[0], scene_pos[1], scene_pos[2], 1.0f); + Eigen::Vector4f clip_pos = this->transform_matrix * model_matrix * scene_pos.homogeneous(); float x_ndc = clip_pos[0]; float y_ndc = clip_pos[1]; diff --git a/libopenage/renderer/camera/frustum_2d.h b/libopenage/renderer/camera/frustum_2d.h index 21bcd9c7e3..3403d72a43 100644 --- a/libopenage/renderer/camera/frustum_2d.h +++ b/libopenage/renderer/camera/frustum_2d.h @@ -48,12 +48,14 @@ class Frustum2d { * Check if a scene object is inside the frustum. * * @param scene_pos 3D scene coordinates. + * @param model_matrix Model matrix of the object. * @param scalefactor Scale factor of the animation. * @param boundaries Boundaries of the animation (in pixels): left, right, top, bottom. * * @return true if the object is inside the frustum, false otherwise. */ bool in_frustum(const Eigen::Vector3f &scene_pos, + const Eigen::Matrix4f &model_matrix, const float scalefactor, const util::Vector4i &boundaries) const; diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp index 04bb27e391..d4629f866b 100644 --- a/libopenage/renderer/stages/world/object.cpp +++ b/libopenage/renderer/stages/world/object.cpp @@ -226,9 +226,11 @@ void WorldObject::set_uniforms(std::vectorget_model_matrix(); Eigen::Vector3f current_pos = this->position.get(time).to_world_space(); auto animation_info = this->animation_info.get(time); return frustum.in_frustum(current_pos, + model_matrix, animation_info->get_scalefactor(), animation_info->get_max_bounds()); } diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp index 4f3354a1fa..d699d1ac33 100644 --- a/libopenage/renderer/stages/world/render_stage.cpp +++ b/libopenage/renderer/stages/world/render_stage.cpp @@ -70,14 +70,14 @@ void WorldRenderStage::update() { if (obj->is_changed()) { if (obj->requires_renderable()) { auto layer_positions = obj->get_layer_positions(current_time); - Eigen::Matrix4f model_m = obj->get_model_matrix(); + static const Eigen::Matrix4f model_matrix = obj->get_model_matrix(); std::vector> transform_unifs; for (auto layer_pos : layer_positions) { // Set uniforms that don't change or are not changed often auto layer_unifs = this->display_shader->new_uniform_input( "model", - model_m, + model_matrix, "flip_x", false, "flip_y", From e97a9448a3235dfb678c8e13c24cf42e1e5bb72b Mon Sep 17 00:00:00 2001 From: heinezen Date: Fri, 19 Jul 2024 02:55:53 +0200 Subject: [PATCH 30/32] renderer: Enable frustum culling with flag in world stage. --- libopenage/renderer/demo/stresstest_1.cpp | 3 +++ libopenage/renderer/stages/world/render_stage.cpp | 5 ++++- libopenage/renderer/stages/world/render_stage.h | 9 ++++++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libopenage/renderer/demo/stresstest_1.cpp b/libopenage/renderer/demo/stresstest_1.cpp index 72c21b5686..ac6177f819 100644 --- a/libopenage/renderer/demo/stresstest_1.cpp +++ b/libopenage/renderer/demo/stresstest_1.cpp @@ -99,6 +99,9 @@ void renderer_stresstest_1(const util::Path &path) { asset_manager, clock); + // Enable frustum culling + renderer::world::WorldRenderStage::ENABLE_FRUSTUM_CULLING = true; + // Store the render passes of the renderers // The order is important as its also the order in which they // are rendered and drawn onto the screen. diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp index d699d1ac33..0434f3cf07 100644 --- a/libopenage/renderer/stages/world/render_stage.cpp +++ b/libopenage/renderer/stages/world/render_stage.cpp @@ -19,6 +19,8 @@ namespace openage::renderer::world { +bool WorldRenderStage::ENABLE_FRUSTUM_CULLING = false; + WorldRenderStage::WorldRenderStage(const std::shared_ptr &window, const std::shared_ptr &renderer, const std::shared_ptr &camera, @@ -63,7 +65,8 @@ void WorldRenderStage::update() { for (auto &obj : this->render_objects) { obj->fetch_updates(current_time); - if (not obj->is_visible(camera_frustum, current_time)) { + if (WorldRenderStage::ENABLE_FRUSTUM_CULLING + and not obj->is_visible(camera_frustum, current_time)) { continue; } diff --git a/libopenage/renderer/stages/world/render_stage.h b/libopenage/renderer/stages/world/render_stage.h index e22399180b..e6ae39c094 100644 --- a/libopenage/renderer/stages/world/render_stage.h +++ b/libopenage/renderer/stages/world/render_stage.h @@ -39,6 +39,11 @@ class WorldObject; */ class WorldRenderStage { public: + /** + * Enable or disable frustum culling (default = false). + */ + static bool ENABLE_FRUSTUM_CULLING; + /** * Create a new render stage for the game world. * @@ -95,9 +100,7 @@ class WorldRenderStage { * @param height Height of the FBO. * @param shaderdir Directory containg the shader source files. */ - void initialize_render_pass(size_t width, - size_t height, - const util::Path &shaderdir); + void initialize_render_pass(size_t width, size_t height, const util::Path &shaderdir); /** * Fetch the uniform IDs for the uniforms of the world shader from OpenGL From a608d26eb6edaf14e539c32588da3b8421f39d55 Mon Sep 17 00:00:00 2001 From: heinezen Date: Sun, 21 Jul 2024 17:59:51 +0200 Subject: [PATCH 31/32] renderer: Enable GL_LINE_LOOP vertex primitive. --- libopenage/renderer/opengl/lookup.h | 3 ++- libopenage/renderer/resources/mesh_data.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libopenage/renderer/opengl/lookup.h b/libopenage/renderer/opengl/lookup.h index e399e98399..a137101482 100644 --- a/libopenage/renderer/opengl/lookup.h +++ b/libopenage/renderer/opengl/lookup.h @@ -1,4 +1,4 @@ -// Copyright 2018-2023 the openage authors. See copying.md for legal info. +// Copyright 2018-2024 the openage authors. See copying.md for legal info. // Lookup tables for translating between OpenGL-specific values and generic renderer values, // as well as mapping things like type sizes within OpenGL. @@ -137,6 +137,7 @@ static constexpr auto GL_PRIMITIVE = datastructure::create_const_map Date: Fri, 19 Jul 2024 14:13:11 +0200 Subject: [PATCH 32/32] renderer: Frustum culling demo. --- assets/test/shaders/demo_6_2d.frag.glsl | 37 ++ assets/test/shaders/demo_6_2d.vert.glsl | 83 ++++ assets/test/shaders/demo_6_2d_frame.frag.glsl | 7 + assets/test/shaders/demo_6_2d_frame.vert.glsl | 58 +++ assets/test/shaders/demo_6_3d.frag.glsl | 13 + assets/test/shaders/demo_6_3d.vert.glsl | 24 + assets/test/shaders/demo_6_display.frag.glsl | 10 + assets/test/shaders/demo_6_display.vert.glsl | 10 + libopenage/renderer/demo/CMakeLists.txt | 1 + libopenage/renderer/demo/demo_0.cpp | 2 +- libopenage/renderer/demo/demo_0.h | 2 +- libopenage/renderer/demo/demo_1.cpp | 2 +- libopenage/renderer/demo/demo_1.h | 2 +- libopenage/renderer/demo/demo_2.cpp | 2 +- libopenage/renderer/demo/demo_2.h | 2 +- libopenage/renderer/demo/demo_3.cpp | 2 +- libopenage/renderer/demo/demo_3.h | 3 +- libopenage/renderer/demo/demo_4.h | 2 +- libopenage/renderer/demo/demo_6.cpp | 428 ++++++++++++++++++ libopenage/renderer/demo/demo_6.h | 101 +++++ libopenage/renderer/demo/tests.cpp | 5 + 21 files changed, 786 insertions(+), 10 deletions(-) create mode 100644 assets/test/shaders/demo_6_2d.frag.glsl create mode 100644 assets/test/shaders/demo_6_2d.vert.glsl create mode 100644 assets/test/shaders/demo_6_2d_frame.frag.glsl create mode 100644 assets/test/shaders/demo_6_2d_frame.vert.glsl create mode 100644 assets/test/shaders/demo_6_3d.frag.glsl create mode 100644 assets/test/shaders/demo_6_3d.vert.glsl create mode 100644 assets/test/shaders/demo_6_display.frag.glsl create mode 100644 assets/test/shaders/demo_6_display.vert.glsl create mode 100644 libopenage/renderer/demo/demo_6.cpp create mode 100644 libopenage/renderer/demo/demo_6.h diff --git a/assets/test/shaders/demo_6_2d.frag.glsl b/assets/test/shaders/demo_6_2d.frag.glsl new file mode 100644 index 0000000000..c4beb1dd8e --- /dev/null +++ b/assets/test/shaders/demo_6_2d.frag.glsl @@ -0,0 +1,37 @@ +#version 330 + +in vec2 vert_uv; + +layout(location=0) out vec4 col; + +uniform sampler2D tex; + +// position (top left corner) and size: (x, y, width, height) +uniform vec4 tile_params; + +vec2 uv = vec2( + vert_uv.x * tile_params.z + tile_params.x, + vert_uv.y * tile_params.w + tile_params.y +); + +void main() { + vec4 tex_val = texture(tex, uv); + int alpha = int(round(tex_val.a * 255)); + switch (alpha) { + case 0: + col = tex_val; + discard; + case 254: + col = vec4(1.0f, 0.0f, 0.0f, 1.0f); + break; + case 252: + col = vec4(0.0f, 1.0f, 0.0f, 1.0f); + break; + case 250: + col = vec4(0.0f, 0.0f, 1.0f, 1.0f); + break; + default: + col = tex_val; + break; + } +} diff --git a/assets/test/shaders/demo_6_2d.vert.glsl b/assets/test/shaders/demo_6_2d.vert.glsl new file mode 100644 index 0000000000..6a17baf834 --- /dev/null +++ b/assets/test/shaders/demo_6_2d.vert.glsl @@ -0,0 +1,83 @@ +#version 330 + +layout(location=0) in vec2 v_position; +layout(location=1) in vec2 uv; + +out vec2 vert_uv; + +// camera parameters for transforming the object position +// and scaling the subtex to the correct size +layout (std140) uniform camera { + // view matrix (world to view space) + mat4 view; + // projection matrix (view to clip space) + mat4 proj; + // inverse zoom factor (1.0 / zoom) + // high zoom = upscale subtex + // low zoom = downscale subtex + float inv_zoom; + // inverse viewport size (1.0 / viewport size) + vec2 inv_viewport_size; +}; + +// position of the object in world space +uniform vec3 obj_world_position; + +// parameters for scaling and moving the subtex +// to the correct position in clip space + +// animation scalefactor +// scales the vertex positions so that they +// match the subtex dimensions +// +// high animation scale = downscale subtex +// low animation scale = upscale subtex +uniform float scale; + +// size of the subtex (in pixels) +uniform vec2 subtex_size; + +// offset of the subtex anchor point +// from the subtex center (in pixels) +// used to move the subtex so that the anchor point +// is at the object position +uniform vec2 anchor_offset; + +void main() { + // translate the position of the object from world space to clip space + // this is the position where we want to draw the subtex in 2D + vec4 obj_clip_pos = proj * view * vec4(obj_world_position, 1.0); + + // subtex has to be scaled to account for the zoom factor + // and the animation scale factor. essentially this is (animation scale / zoom). + float zoom_scale = scale * inv_zoom; + + // Scale the subtex vertices + // we have to account for the viewport size to get the correct dimensions + // and then scale the subtex to the zoom factor to get the correct size + vec2 vert_scale = zoom_scale * subtex_size * inv_viewport_size; + + // Scale the anchor offset with the same method as above + // to get the correct anchor position in the viewport + vec2 anchor_scale = zoom_scale * anchor_offset * inv_viewport_size; + + // offset the clip position by the offset of the subtex anchor + // imagine this as pinning the subtex to the object position at the subtex anchor point + obj_clip_pos += vec4(anchor_scale.x, anchor_scale.y, 0.0, 0.0); + + // create a move matrix for positioning the vertices + // uses the vert scale and the transformed object position in clip space + mat4 move = mat4(vert_scale.x, 0.0, 0.0, 0.0, + 0.0, vert_scale.y, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + obj_clip_pos.x, obj_clip_pos.y, obj_clip_pos.z, 1.0); + + // calculate the final vertex position + gl_Position = move * vec4(v_position, 0.0, 1.0); + + // flip y axis because OpenGL uses bottom-left as its origin + float uv_x = uv.x; + float uv_y = 1.0 - uv.y; + + vert_uv = vec2(uv_x, uv_y); +} diff --git a/assets/test/shaders/demo_6_2d_frame.frag.glsl b/assets/test/shaders/demo_6_2d_frame.frag.glsl new file mode 100644 index 0000000000..c67ca484cc --- /dev/null +++ b/assets/test/shaders/demo_6_2d_frame.frag.glsl @@ -0,0 +1,7 @@ +#version 330 + +out vec4 col; + +void main() { + col = vec4(1.0, 0.0, 0.0, 0.8); +} diff --git a/assets/test/shaders/demo_6_2d_frame.vert.glsl b/assets/test/shaders/demo_6_2d_frame.vert.glsl new file mode 100644 index 0000000000..8d7d13b6be --- /dev/null +++ b/assets/test/shaders/demo_6_2d_frame.vert.glsl @@ -0,0 +1,58 @@ +#version 330 + +layout(location=0) in vec2 v_position; + +// camera parameters for transforming the object position +// and scaling the subtex to the correct size +layout (std140) uniform camera { + // view matrix (world to view space) + mat4 view; + // projection matrix (view to clip space) + mat4 proj; + // inverse zoom factor (1.0 / zoom) + float inv_zoom; + // inverse viewport size (1.0 / viewport size) + vec2 inv_viewport_size; +}; + +// position of the object in world space +uniform vec3 obj_world_position; + +// parameters for scaling and moving the subtex +// to the correct position in clip space + +// animation scalefactor +// scales the vertex positions so that they +// match the subtex dimensions +// +// high animation scale = downscale subtex +// low animation scale = upscale subtex +uniform float scale; + +// size of the frame (in pixels) +uniform vec2 frame_size; + +void main() { + // translate the position of the object from world space to clip space + // this is the position where we want to draw the subtex in 2D + vec4 obj_clip_pos = proj * view * vec4(obj_world_position, 1.0); + + // subtex has to be scaled to account for the zoom factor + // and the animation scale factor. essentially this is (animation scale / zoom). + float zoom_scale = scale * inv_zoom; + + // Scale the subtex vertices + // we have to account for the viewport size to get the correct dimensions + // and then scale the frame to the zoom factor to get the correct size + vec2 vert_scale = zoom_scale * frame_size * inv_viewport_size; + + // create a move matrix for positioning the vertices + // uses the vert scale and the transformed object position in clip space + mat4 move = mat4(vert_scale.x, 0.0, 0.0, 0.0, + 0.0, vert_scale.y, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + obj_clip_pos.x, obj_clip_pos.y, obj_clip_pos.z, 1.0); + + // calculate the final vertex position + gl_Position = move * vec4(v_position, 0.0, 1.0); +} diff --git a/assets/test/shaders/demo_6_3d.frag.glsl b/assets/test/shaders/demo_6_3d.frag.glsl new file mode 100644 index 0000000000..f2d3c71bd8 --- /dev/null +++ b/assets/test/shaders/demo_6_3d.frag.glsl @@ -0,0 +1,13 @@ +#version 330 + +in vec2 tex_pos; + +layout(location=0) out vec4 out_col; + +uniform sampler2D tex; + +void main() +{ + vec4 tex_val = texture(tex, tex_pos); + out_col = tex_val; +} diff --git a/assets/test/shaders/demo_6_3d.vert.glsl b/assets/test/shaders/demo_6_3d.vert.glsl new file mode 100644 index 0000000000..95a552dcd6 --- /dev/null +++ b/assets/test/shaders/demo_6_3d.vert.glsl @@ -0,0 +1,24 @@ +#version 330 + +layout (location = 0) in vec3 position; +layout (location = 1) in vec2 uv; + +out vec2 tex_pos; + +// camera parameters for transforming the object position +// and scaling the subtex to the correct size +layout (std140) uniform camera { + // view matrix (world to view space) + mat4 view; + // projection matrix (view to clip space) + mat4 proj; + // inverse zoom factor (1.0 / zoom) + float inv_zoom; + // inverse viewport size (1.0 / viewport size) + vec2 inv_viewport_size; +}; + +void main() { + gl_Position = proj * view * vec4(position, 1.0); + tex_pos = vec2(uv.x, 1.0 - uv.y); +} diff --git a/assets/test/shaders/demo_6_display.frag.glsl b/assets/test/shaders/demo_6_display.frag.glsl new file mode 100644 index 0000000000..a6732d0c7f --- /dev/null +++ b/assets/test/shaders/demo_6_display.frag.glsl @@ -0,0 +1,10 @@ +#version 330 + +uniform sampler2D color_texture; + +in vec2 v_uv; +out vec4 col; + +void main() { + col = texture(color_texture, v_uv); +} diff --git a/assets/test/shaders/demo_6_display.vert.glsl b/assets/test/shaders/demo_6_display.vert.glsl new file mode 100644 index 0000000000..072e5d80b0 --- /dev/null +++ b/assets/test/shaders/demo_6_display.vert.glsl @@ -0,0 +1,10 @@ +#version 330 + +layout(location=0) in vec2 position; +layout(location=1) in vec2 uv; +out vec2 v_uv; + +void main() { + gl_Position = vec4(position, 0.0, 1.0); + v_uv = uv; +} diff --git a/libopenage/renderer/demo/CMakeLists.txt b/libopenage/renderer/demo/CMakeLists.txt index aaa30bc906..fb93e5279b 100644 --- a/libopenage/renderer/demo/CMakeLists.txt +++ b/libopenage/renderer/demo/CMakeLists.txt @@ -5,6 +5,7 @@ add_sources(libopenage demo_3.cpp demo_4.cpp demo_5.cpp + demo_6.cpp stresstest_0.cpp stresstest_1.cpp tests.cpp diff --git a/libopenage/renderer/demo/demo_0.cpp b/libopenage/renderer/demo/demo_0.cpp index d82eb62381..38fd467d0b 100644 --- a/libopenage/renderer/demo/demo_0.cpp +++ b/libopenage/renderer/demo/demo_0.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2024 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #include "demo_0.h" diff --git a/libopenage/renderer/demo/demo_0.h b/libopenage/renderer/demo/demo_0.h index 4cdb1d831b..7ea7e68f19 100644 --- a/libopenage/renderer/demo/demo_0.h +++ b/libopenage/renderer/demo/demo_0.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #pragma once diff --git a/libopenage/renderer/demo/demo_1.cpp b/libopenage/renderer/demo/demo_1.cpp index 1ecd7815a1..23dfdfa67b 100644 --- a/libopenage/renderer/demo/demo_1.cpp +++ b/libopenage/renderer/demo/demo_1.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2024 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #include "demo_1.h" diff --git a/libopenage/renderer/demo/demo_1.h b/libopenage/renderer/demo/demo_1.h index 6b1c3168ee..d978603040 100644 --- a/libopenage/renderer/demo/demo_1.h +++ b/libopenage/renderer/demo/demo_1.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #pragma once diff --git a/libopenage/renderer/demo/demo_2.cpp b/libopenage/renderer/demo/demo_2.cpp index 7f6f398e12..e615d238ba 100644 --- a/libopenage/renderer/demo/demo_2.cpp +++ b/libopenage/renderer/demo/demo_2.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2024 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #include "demo_2.h" diff --git a/libopenage/renderer/demo/demo_2.h b/libopenage/renderer/demo/demo_2.h index 077f61ac33..211e5e9310 100644 --- a/libopenage/renderer/demo/demo_2.h +++ b/libopenage/renderer/demo/demo_2.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #pragma once diff --git a/libopenage/renderer/demo/demo_3.cpp b/libopenage/renderer/demo/demo_3.cpp index 23de242fd7..408e699196 100644 --- a/libopenage/renderer/demo/demo_3.cpp +++ b/libopenage/renderer/demo/demo_3.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2024 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #include "demo_3.h" diff --git a/libopenage/renderer/demo/demo_3.h b/libopenage/renderer/demo/demo_3.h index fda210acbd..9eec5dc74c 100644 --- a/libopenage/renderer/demo/demo_3.h +++ b/libopenage/renderer/demo/demo_3.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #pragma once @@ -10,7 +10,6 @@ namespace openage::renderer::tests { * Show off the render stages in the level 2 renderer and the camera * system. * - Window creation - * - Loading shaders * - Creating a camera * - Initializing the level 2 render stages: skybox, terrain, world, screen * - Adding renderables to the render stages via the render factory diff --git a/libopenage/renderer/demo/demo_4.h b/libopenage/renderer/demo/demo_4.h index 7c80e947e1..c3ce3ad4b5 100644 --- a/libopenage/renderer/demo/demo_4.h +++ b/libopenage/renderer/demo/demo_4.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #pragma once diff --git a/libopenage/renderer/demo/demo_6.cpp b/libopenage/renderer/demo/demo_6.cpp new file mode 100644 index 0000000000..038bb0240e --- /dev/null +++ b/libopenage/renderer/demo/demo_6.cpp @@ -0,0 +1,428 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#include "demo_6.h" + +#include + +#include "curve/continuous.h" +#include "curve/segmented.h" +#include "renderer/camera/camera.h" +#include "renderer/camera/frustum_2d.h" +#include "renderer/camera/frustum_3d.h" +#include "renderer/gui/integration/public/gui_application_with_logger.h" +#include "renderer/opengl/window.h" +#include "renderer/render_pass.h" +#include "renderer/renderer.h" +#include "renderer/resources/animation/angle_info.h" +#include "renderer/resources/animation/frame_info.h" +#include "renderer/resources/animation/layer_info.h" +#include "renderer/resources/parser/parse_sprite.h" +#include "renderer/resources/parser/parse_terrain.h" +#include "renderer/resources/shader_source.h" +#include "renderer/resources/texture_info.h" +#include "renderer/shader_program.h" +#include "renderer/texture.h" +#include "renderer/uniform_buffer.h" +#include "time/clock.h" +#include "util/path.h" +#include "util/vector.h" + + +namespace openage::renderer::tests { + +void renderer_demo_6(const util::Path &path) { + auto render_mgr = RenderManagerDemo6{path}; + + // Create render objects + auto renderables_2d = render_mgr.create_2d_obj(); + auto renderables_3d = render_mgr.create_3d_obj(); + auto renderables_frame = render_mgr.create_frame_obj(); + + // Add objects to the render passes + render_mgr.obj_2d_pass->add_renderables(std::move(renderables_2d)); + render_mgr.obj_3d_pass->add_renderables({renderables_3d}); + render_mgr.frame_pass->add_renderables(std::move(renderables_frame)); + + render_mgr.window->add_key_callback([&](const QKeyEvent &ev) { + if (ev.type() == QEvent::KeyPress) { + auto key = ev.key(); + + // move_frame moves the camera in the specified direction in the next drawn frame + switch (key) { + case Qt::Key_W: { // forward + render_mgr.camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, -1.0f), 0.25f); + } break; + case Qt::Key_A: { // left + render_mgr.camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, 1.0f), 0.25f); + } break; + case Qt::Key_S: { // back + render_mgr.camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, 1.0f), 0.25f); + } break; + case Qt::Key_D: { // right + render_mgr.camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, -1.0f), 0.25f); + } break; + default: + break; + } + + auto new_cam_unifs = render_mgr.camera->get_uniform_buffer()->new_uniform_input( + "view", + render_mgr.camera->get_view_matrix(), + "proj", + render_mgr.camera->get_projection_matrix()); + render_mgr.camera->get_uniform_buffer()->update_uniforms(new_cam_unifs); + + auto frustum_camera = *render_mgr.camera; + auto half_cam_size = util::Vector2s{render_mgr.camera->get_viewport_size()[0] * 0.7, + render_mgr.camera->get_viewport_size()[1] * 0.7}; + frustum_camera.resize(half_cam_size[0], half_cam_size[1]); + auto frustum_2d = frustum_camera.get_frustum_2d(); + frustum_2d.update(frustum_camera.get_viewport_size(), + frustum_camera.get_view_matrix(), + frustum_camera.get_projection_matrix(), + frustum_camera.get_zoom()); + + auto renderables_2d = render_mgr.create_2d_obj(); + std::vector renderables_in_frustum{}; + for (size_t i = 0; i < render_mgr.obj_2d_positions.size(); ++i) { + auto pos = render_mgr.obj_2d_positions.at(i); + bool in_frustum = frustum_2d.in_frustum(pos.to_world_space(), + Eigen::Matrix4f::Identity(), + render_mgr.animation_2d_info.get_scalefactor(), + render_mgr.animation_2d_info.get_max_bounds()); + if (in_frustum) { + renderables_in_frustum.push_back(renderables_2d.at(i)); + } + } + render_mgr.obj_2d_pass->clear_renderables(); + render_mgr.obj_2d_pass->add_renderables(std::move(renderables_in_frustum)); + } + }); + + render_mgr.run(); +} + +RenderManagerDemo6::RenderManagerDemo6(const util::Path &path) : + path{path} { + this->setup(); +} + +void RenderManagerDemo6::run() { + while (not window->should_close()) { + this->qtapp->process_events(); + + // Draw everything + renderer->render(this->obj_3d_pass); + renderer->render(this->obj_2d_pass); + renderer->render(this->frame_pass); + renderer->render(this->display_pass); + + // Display final output on screen + this->window->update(); + } +} + +const std::vector RenderManagerDemo6::create_2d_obj() { + std::vector renderables; + for (auto scene_pos : this->obj_2d_positions) { + // Create renderable for 2D animation + auto scale = this->animation_2d_info.get_scalefactor(); + auto tex_id = this->animation_2d_info.get_layer(0).get_angle(0)->get_frame(0)->get_texture_idx(); + auto subtex_id = this->animation_2d_info.get_layer(0).get_angle(0)->get_frame(0)->get_subtexture_idx(); + auto subtex = this->animation_2d_info.get_texture(tex_id)->get_subtex_info(subtex_id); + auto subtex_size = subtex.get_size(); + Eigen::Vector2f subtex_size_vec{ + static_cast(subtex_size[0]), + static_cast(subtex_size[1])}; + auto anchor_params = subtex.get_anchor_params(); + auto anchor_params_vec = Eigen::Vector2f{ + static_cast(anchor_params[0]), + static_cast(anchor_params[1])}; + auto tile_params = subtex.get_subtex_coords(); + auto animation_2d_unifs = this->obj_2d_shader->new_uniform_input( + "obj_world_position", + scene_pos.to_world_space(), + "scale", + scale, + "subtex_size", + subtex_size_vec, + "anchor_offset", + anchor_params_vec, + "tex", + this->obj_2d_texture, + "tile_params", + tile_params); + auto quad = this->renderer->add_mesh_geometry(resources::MeshData::make_quad()); + Renderable animation_2d_obj{ + animation_2d_unifs, + quad, + true, + true, + }; + + renderables.push_back(animation_2d_obj); + } + + return renderables; +} + +const renderer::Renderable RenderManagerDemo6::create_3d_obj() { + auto terrain_tex_info = this->terrain_3d_info.get_texture(0); + auto terrain_tex_data = resources::Texture2dData{*terrain_tex_info}; + this->obj_3d_texture = this->renderer->add_texture(terrain_tex_data); + + // Create renderable for terrain + auto terrain_unifs = this->obj_3d_shader->new_uniform_input( + "tex", + this->obj_3d_texture); + std::vector terrain_pos{}; + terrain_pos.push_back({-25, -25, 0}); + terrain_pos.push_back({25, -25, 0}); + terrain_pos.push_back({-25, 25, 0}); + terrain_pos.push_back({25, 25, 0}); + std::vector terrain_verts{}; + for (size_t i = 0; i < terrain_pos.size(); ++i) { + auto scene_pos = terrain_pos.at(i).to_world_space(); + terrain_verts.push_back(scene_pos[0]); + terrain_verts.push_back(scene_pos[1]); + terrain_verts.push_back(scene_pos[2]); + terrain_verts.push_back(0.0f + i / 2); + terrain_verts.push_back(0.0f + i % 2); + } + auto vert_info = resources::VertexInputInfo{ + {resources::vertex_input_t::V3F32, resources::vertex_input_t::V2F32}, + resources::vertex_layout_t::AOS, + resources::vertex_primitive_t::TRIANGLE_STRIP, + }; + std::vector vert_data(terrain_verts.size() * sizeof(float)); + std::memcpy(vert_data.data(), terrain_verts.data(), vert_data.size()); + auto terrain_mesh = resources::MeshData{std::move(vert_data), vert_info}; + auto terrain_geometry = this->renderer->add_mesh_geometry(terrain_mesh); + Renderable terrain_obj{ + terrain_unifs, + terrain_geometry, + true, + true, + }; + + return terrain_obj; +} + +const std::vector RenderManagerDemo6::create_frame_obj() { + std::vector renderables; + for (auto scene_pos : this->obj_2d_positions) { + // Create renderable for frame + std::array frame_verts{-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f}; + std::vector frame_vert_data(frame_verts.size() * sizeof(float)); + std::memcpy(frame_vert_data.data(), frame_verts.data(), frame_vert_data.size()); + auto frame_vert_info = resources::VertexInputInfo{ + {resources::vertex_input_t::V2F32}, + resources::vertex_layout_t::AOS, + resources::vertex_primitive_t::LINE_LOOP, + }; + auto frame_mesh = resources::MeshData{std::move(frame_vert_data), frame_vert_info}; + auto frame_geometry = this->renderer->add_mesh_geometry(frame_mesh); + + auto scale = this->animation_2d_info.get_scalefactor(); + auto max_frame_size = this->animation_2d_info.get_max_size(); + auto frame_size = Eigen::Vector2f{ + static_cast(max_frame_size[0]), + static_cast(max_frame_size[1])}; + auto frame_unifs = this->frame_shader->new_uniform_input( + "obj_world_position", + scene_pos.to_world_space(), + "scale", + scale, + "frame_size", + frame_size); + Renderable frame_obj{ + frame_unifs, + frame_geometry, + true, + true, + }; + + renderables.push_back(frame_obj); + } + + return renderables; +} + +void RenderManagerDemo6::setup() { + this->qtapp = std::make_shared(); + + // Create the window and renderer + window_settings settings; + settings.width = 1024; + settings.height = 768; + settings.debug = true; + this->window = std::make_shared("openage renderer test", settings); + this->renderer = window->make_renderer(); + + this->load_shaders(); + this->load_assets(); + this->create_camera(); + this->create_render_passes(); +} + +void RenderManagerDemo6::load_shaders() { + // Shader + auto shaderdir = this->path / "assets" / "test" / "shaders"; + + /* Shader for 3D objects*/ + auto obj_vshader_file = (shaderdir / "demo_6_3d.vert.glsl").open(); + auto obj_vshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::vertex, + obj_vshader_file.read()); + obj_vshader_file.close(); + + auto obj_fshader_file = (shaderdir / "demo_6_3d.frag.glsl").open(); + auto obj_fshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::fragment, + obj_fshader_file.read()); + obj_fshader_file.close(); + + /* Shader for 2D animations */ + auto obj_2d_vshader_file = (shaderdir / "demo_6_2d.vert.glsl").open(); + auto obj_2d_vshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::vertex, + obj_2d_vshader_file.read()); + obj_2d_vshader_file.close(); + + auto obj_2d_fshader_file = (shaderdir / "demo_6_2d.frag.glsl").open(); + auto obj_2d_fshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::fragment, + obj_2d_fshader_file.read()); + obj_2d_fshader_file.close(); + + /* Shader for frames */ + auto frame_vshader_file = (shaderdir / "demo_6_2d_frame.vert.glsl").open(); + auto frame_vshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::vertex, + frame_vshader_file.read()); + frame_vshader_file.close(); + + auto frame_fshader_file = (shaderdir / "demo_6_2d_frame.frag.glsl").open(); + auto frame_fshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::fragment, + frame_fshader_file.read()); + frame_fshader_file.close(); + + /* Shader for rendering to the screen */ + auto display_vshader_file = (shaderdir / "demo_6_display.vert.glsl").open(); + auto display_vshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::vertex, + display_vshader_file.read()); + display_vshader_file.close(); + + auto display_fshader_file = (shaderdir / "demo_6_display.frag.glsl").open(); + auto display_fshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::fragment, + display_fshader_file.read()); + display_fshader_file.close(); + + // Create shader programs + this->obj_3d_shader = this->renderer->add_shader({obj_vshader_src, obj_fshader_src}); + this->obj_2d_shader = this->renderer->add_shader({obj_2d_vshader_src, obj_2d_fshader_src}); + this->frame_shader = this->renderer->add_shader({frame_vshader_src, frame_fshader_src}); + this->display_shader = this->renderer->add_shader({display_vshader_src, display_fshader_src}); +} + +void RenderManagerDemo6::load_assets() { + // Load assets + auto animation_2d_path = this->path / "assets" / "test" / "textures" / "test_tank.sprite"; + this->animation_2d_info = resources::parser::parse_sprite_file(animation_2d_path); + + auto tex_info = this->animation_2d_info.get_texture(0); + auto tex_data = resources::Texture2dData{*tex_info}; + this->obj_2d_texture = this->renderer->add_texture(tex_data); + + // Load assets + auto terrain_path = this->path / "assets" / "test" / "textures" / "test_terrain.terrain"; + this->terrain_3d_info = resources::parser::parse_terrain_file(terrain_path); +} + +void RenderManagerDemo6::create_camera() { + // Camera + this->camera = std::make_shared(renderer, window->get_size()); + this->camera->set_zoom(2.0f); + + // Bind the camera uniform buffer to the shaders + obj_3d_shader->bind_uniform_buffer("camera", this->camera->get_uniform_buffer()); + obj_2d_shader->bind_uniform_buffer("camera", this->camera->get_uniform_buffer()); + frame_shader->bind_uniform_buffer("camera", this->camera->get_uniform_buffer()); + + // Update the camera uniform buffer + auto camera_unifs = camera->get_uniform_buffer()->new_uniform_input( + "view", + this->camera->get_view_matrix(), + "proj", + this->camera->get_projection_matrix(), + "inv_zoom", + 1.0f / this->camera->get_zoom()); + auto viewport_size = this->camera->get_viewport_size(); + Eigen::Vector2f viewport_size_vec{ + 1.0f / static_cast(viewport_size[0]), + 1.0f / static_cast(viewport_size[1])}; + camera_unifs->update("inv_viewport_size", viewport_size_vec); + this->camera->get_uniform_buffer()->update_uniforms(camera_unifs); +} + +void RenderManagerDemo6::create_render_passes() { + // Create render passes + auto window_size = window->get_size(); + auto color_texture0 = renderer->add_texture(resources::Texture2dInfo(window_size[0], + window_size[1], + resources::pixel_format::rgba8)); + auto fbo0 = renderer->create_texture_target({color_texture0}); + this->obj_3d_pass = renderer->add_render_pass({}, fbo0); + + auto color_texture1 = renderer->add_texture(resources::Texture2dInfo(window_size[0], + window_size[1], + resources::pixel_format::rgba8)); + auto fbo1 = renderer->create_texture_target({color_texture1}); + this->obj_2d_pass = renderer->add_render_pass({}, fbo1); + + auto color_texture2 = renderer->add_texture(resources::Texture2dInfo(window_size[0], + window_size[1], + resources::pixel_format::rgba8)); + auto fbo2 = renderer->create_texture_target({color_texture2}); + this->frame_pass = renderer->add_render_pass({}, fbo2); + + // Create render pass for rendering to screen + auto quad = renderer->add_mesh_geometry(resources::MeshData::make_quad()); + auto color_texture0_unif = display_shader->new_uniform_input("color_texture", color_texture0); + Renderable display_obj_3d{ + color_texture0_unif, + quad, + true, + true, + }; + auto color_texture1_unif = display_shader->new_uniform_input("color_texture", color_texture1); + Renderable display_obj_2d{ + color_texture1_unif, + quad, + true, + true, + }; + auto color_texture2_unif = display_shader->new_uniform_input("color_texture", color_texture2); + Renderable display_obj_frame{ + color_texture2_unif, + quad, + true, + true, + }; + this->display_pass = renderer->add_render_pass( + {display_obj_3d, display_obj_2d, display_obj_frame}, + renderer->get_display_target()); +} + +} // namespace openage::renderer::tests diff --git a/libopenage/renderer/demo/demo_6.h b/libopenage/renderer/demo/demo_6.h new file mode 100644 index 0000000000..7c5d3052c5 --- /dev/null +++ b/libopenage/renderer/demo/demo_6.h @@ -0,0 +1,101 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "coord/scene.h" +#include "renderer/renderable.h" +#include "renderer/resources/animation/animation_info.h" +#include "renderer/resources/terrain/terrain_info.h" +#include "util/path.h" + + +namespace openage::renderer { +class RenderPass; +class Renderer; +class ShaderProgram; +class Texture2d; + +namespace camera { +class Camera; +} + +namespace gui { +class GuiApplicationWithLogger; +} + +namespace opengl { +class GlWindow; +} + +namespace tests { + +/** + * Show the usage of frustum culling in the renderer. + * - Window creation + * - Loading shaders + * - Creating a camera + * - 2D and 3D frustum retrieval + * - Manipulating the frustum + * - Rendering objects with frustum culling + * + * @param path Path to the openage asset directory. + */ +void renderer_demo_6(const util::Path &path); + + +class RenderManagerDemo6 { +public: + RenderManagerDemo6(const util::Path &path); + void run(); + + const std::vector create_2d_obj(); + const renderer::Renderable create_3d_obj(); + const std::vector create_frame_obj(); + + std::shared_ptr qtapp; + + std::shared_ptr window; + + std::shared_ptr camera; + + std::shared_ptr obj_2d_pass; + std::shared_ptr obj_3d_pass; + std::shared_ptr frame_pass; + std::shared_ptr display_pass; + + const std::array obj_2d_positions = { + coord::scene3{0, 0, 0}, + coord::scene3{-4, -4, 0}, + coord::scene3{4, 4, 0}, + coord::scene3{-2, 3, 0}, + coord::scene3{3, -2, 0}, + }; + + resources::Animation2dInfo animation_2d_info; + resources::TerrainInfo terrain_3d_info; + +private: + void setup(); + + void load_shaders(); + void load_assets(); + void create_camera(); + void create_render_passes(); + + util::Path path; + + std::shared_ptr renderer; + + std::shared_ptr obj_2d_shader; + std::shared_ptr obj_3d_shader; + std::shared_ptr frame_shader; + std::shared_ptr display_shader; + + std::shared_ptr obj_2d_texture; + std::shared_ptr obj_3d_texture; +}; + +} // namespace tests +} // namespace openage::renderer diff --git a/libopenage/renderer/demo/tests.cpp b/libopenage/renderer/demo/tests.cpp index c997a06763..d3fb0e3c21 100644 --- a/libopenage/renderer/demo/tests.cpp +++ b/libopenage/renderer/demo/tests.cpp @@ -11,6 +11,7 @@ #include "renderer/demo/demo_3.h" #include "renderer/demo/demo_4.h" #include "renderer/demo/demo_5.h" +#include "renderer/demo/demo_6.h" #include "renderer/demo/stresstest_0.h" #include "renderer/demo/stresstest_1.h" @@ -42,6 +43,10 @@ void renderer_demo(int demo_id, const util::Path &path) { renderer_demo_5(path); break; + case 6: + renderer_demo_6(path); + break; + default: log::log(MSG(err) << "Unknown renderer demo requested: " << demo_id << "."); break;