Start working on fixed timestep

Frame interprelation still needs to be done to make a slow TPS look smooth
This commit is contained in:
SeanOMik 2022-10-14 23:17:22 -04:00
parent ce8886ade1
commit 78ef93bcf5
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
13 changed files with 133 additions and 49 deletions

View File

@ -35,5 +35,9 @@ CheckOptions:
value: "NULL"
- key: readability-magic-numbers
value: "0"
- key: cppcoreguidelines-avoid-magic-numbers
value: "0"
- key: cppcoreguidelines-non-private-member-variables-in-classes
value: "0"
---

View File

@ -70,11 +70,12 @@ int main(int argc, char *argv[]) {
// Create a renderer
auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader, camera);
renderer->initialize();
game.add_renderable(renderer);
//game.add_renderable(renderer);
// Create a Scene and give it the renderer
auto scene = std::make_shared<se::Scene>(renderer);
game.add_event(scene);
//game.add_event(scene);
game.add_renderable(scene);
se::ecs::Entity other_e = scene->create_entity();
other_e.add_component<se::ModelComponent>("examples/dev_testing/resources/transparent_window.fbx",
@ -95,6 +96,7 @@ int main(int argc, char *argv[]) {
se::ecs::Entity brick_e = scene->create_entity();
brick_e.add_component<se::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx");
brick_e.add_component<se::RotatingComponent>();
auto &brick_transf = brick_e.add_component<se::TransformComponent>();
brick_transf.translate(6.f, -0.5f, 1.f);

View File

@ -10,10 +10,21 @@
#include <glm/glm.hpp>
namespace simpleengine {
namespace gfx {
class Renderer;
}
class Camera : public simpleengine::Event {
friend gfx::Renderer;
private:
GLFWwindow* window;
glm::vec3 last_position;
glm::vec3 last_rotation;
glm::mat4 last_view_matrix;
glm::vec3 last_camera_front;
public:
glm::vec3 position;
glm::vec3 rotation;
gfx::Shader shader;

View File

@ -1,5 +1,6 @@
#pragma once
//#include "simpleengine/scene.h"
#include <glm/ext/matrix_transform.hpp>
#include <glm/glm.hpp>
@ -9,14 +10,18 @@ namespace simpleengine {
*
*/
class TransformComponent {
friend class Scene;
private:
// This is the transform from the last render loop. The renderer uses this for frame interprelation
glm::mat4 last_transform_matrix;
public:
glm::mat4 transform_matrix;
TransformComponent() : transform_matrix(glm::mat4(1.f)) {
TransformComponent() : transform_matrix(1.f), last_transform_matrix(1.f) {
}
TransformComponent(glm::mat4 transform_matrix) : transform_matrix(transform_matrix) {
TransformComponent(glm::mat4 transform_matrix) : transform_matrix(transform_matrix), last_transform_matrix(1.f) {
}

View File

@ -42,8 +42,8 @@ namespace simpleengine {
void update(const float& delta_time);
void handle_input(const float& delta_time);
void render_window(const float& delta_time);
void render_items(const float& delta_time);
void render_window(const float& interpolate_alpha, const float& delta_time);
void render_items(const float& interpolate_alpha, const float& delta_time);
void exit();
int run();
@ -63,8 +63,13 @@ namespace simpleengine {
// FPS related stuff
void update_enabled_vsync() const;
void limit_framerate(const float& delta_time) const; // Triggered at the end of a draw to help limit the FPS to `fps_limit`.
int fps_limit;
bool enable_vsync;
int fps_limit = -1;
bool enable_vsync = true;
int max_engine_tps = 60; // The maximum engine TPS
double tps_accumulator = 0.f;
//int engine_ticks_second = 0; // The amount of ticks in a second
//double last_sec_engine_tick; // The time of the last second
float get_delta_time();

View File

@ -23,7 +23,7 @@ namespace simpleengine::gfx {
shader.unuse();
}
virtual void render() override {
virtual void render(const float& interpolate_alpha, const float& frame_time) override {
}
};

View File

@ -17,9 +17,10 @@ namespace simpleengine::gfx {
public:
RenderingType rendering_type;
gfx::Mesh* rendering_mesh;
glm::mat4 last_transform_mat;
glm::mat4 transform_mat;
RenderingJob(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 position);
RenderingJob(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 last_pos, glm::mat4 position);
};
class Renderer : public simpleengine::Renderable {
@ -43,7 +44,7 @@ namespace simpleengine::gfx {
void enable_debug();
virtual void sort_jobs();
virtual void queue_job(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 position);
virtual void queue_job(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 last_position, glm::mat4 position);
virtual void queue_job(RenderingJob job);
virtual void create_job_buffers(RenderingJob& job);
@ -52,7 +53,7 @@ namespace simpleengine::gfx {
virtual void update(const float& delta_time) override;
virtual void render() override;
virtual void render(const float& interpolate_alpha, const float& frame_time) override;
/**
* @brief Renders a single job.
@ -61,8 +62,8 @@ namespace simpleengine::gfx {
* @return true if the job was rendered successfully.
* @return false if there was an error when trying to render the job.
*/
virtual bool render_job(const RenderingJob& job);
virtual void render_job_queue(std::queue<RenderingJob>& queue);
virtual void render_job_queue(std::map<float, RenderingJob, std::greater<>>& queue);
virtual bool render_job(const float& interpolate_alpha, const RenderingJob& job);
virtual void render_job_queue(const float& interpolate_alpha, std::queue<RenderingJob>& queue);
virtual void render_job_queue(const float& interpolate_alpha, std::map<float, RenderingJob, std::greater<>>& queue);
};
}

View File

@ -14,6 +14,6 @@ namespace simpleengine {
Renderable() = default;
virtual ~Renderable() = default;
virtual void render() = 0;
virtual void render(const float& interpolate_alpha, const float& frame_time) = 0;
};
}

View File

@ -9,6 +9,7 @@
#include <memory>
#include <GLFW/glfw3.h>
#include <unordered_map>
#include <vector>
#include <entt/entt.hpp>
@ -18,16 +19,21 @@ namespace simpleengine {
class Entity;
}
class Scene : public simpleengine::Event {
//class Scene : public simpleengine::Event {
class Scene : public simpleengine::Renderable {
protected:
entt::registry registry;
std::shared_ptr<gfx::Renderer> renderer;
// Last transform matrixes for all entities.
std::unordered_map<uint32_t, glm::mat4> last_transforms;
public:
Scene(std::shared_ptr<gfx::Renderer> renderer);
ecs::Entity create_entity();
virtual void update(const float& delta_time) override;
virtual void render(const float& interpolate_alpha, const float& frame_time) override;
virtual void destroy() override;
};

View File

@ -26,7 +26,7 @@ struct Material {
bool has_specular_map;
sampler2D specular_map;
bool has_normal_map;
sampler2D normal_map;

View File

@ -19,7 +19,7 @@
simpleengine::Game::Game(int w, int h, const std::string& window_name, const int& gl_profile, const int& major_version,
const int& minor_version, const bool& resizeable, const int& forward_compat) : window_resizeable(resizeable),
enable_vsync(true), fps_limit(-1) {
tps_accumulator(0.f) {
initialize(gl_profile, major_version, minor_version, window_resizeable, forward_compat);
// Create a window
@ -45,6 +45,8 @@ simpleengine::Game::Game(int w, int h, const std::string& window_name, const int
}
enable_default_gl_options();
last_frame_time = std::chrono::high_resolution_clock::now();
}
void simpleengine::Game::enable_default_gl_options() const {
@ -105,6 +107,10 @@ void simpleengine::Game::update_enabled_vsync() const {
}
}
void simpleengine::Game::handle_input(const float& delta_time) {
// TODO
}
void simpleengine::Game::update(const float& delta_time) {
handle_input(delta_time);
@ -114,19 +120,15 @@ void simpleengine::Game::update(const float& delta_time) {
}
}
void simpleengine::Game::handle_input(const float& delta_time) {
// TODO
}
void simpleengine::Game::render_window(const float& delta_time) {
void simpleengine::Game::render_window(const float& interpolate_alpha, const float& delta_time) {
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
render_items(delta_time);
render_items(interpolate_alpha, delta_time);
}
void simpleengine::Game::render_items(const float& delta_time) {
void simpleengine::Game::render_items(const float& interpolate_alpha, const float& delta_time) {
for (const std::shared_ptr<Renderable>& renderable : renderable_events) {
renderable->render();
renderable->render(interpolate_alpha, delta_time);
}
}
@ -155,12 +157,24 @@ int simpleengine::Game::run() {
while (!glfwWindowShouldClose(window)) {
// Get delta time first thing
float delta_time = get_delta_time();
//std::cout << "Delta time: " << delta_time << std::endl;
// Poll input events
glfwPollEvents();
update(delta_time);
render_window(delta_time);
const double max_delta_time = 0.5;
tps_accumulator += delta_time;
while (tps_accumulator >= max_delta_time) {
update(max_delta_time);
tps_accumulator -= max_delta_time;
}
const double interpolate_alpha = tps_accumulator / max_delta_time;
render_window(interpolate_alpha, delta_time);
// End draw
glfwSwapBuffers(window);

View File

@ -13,11 +13,13 @@
#include <glm/geometric.hpp>
#include <stdexcept>
#include <glm/gtx/string_cast.hpp>
namespace simpleengine::gfx {
void create_mesh_buffers(simpleengine::gfx::Mesh &mesh);
RenderingJob::RenderingJob(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position)
: rendering_type(rendering_type), rendering_mesh(&mesh), transform_mat(position) {}
RenderingJob::RenderingJob(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 last_pos, glm::mat4 position)
: rendering_type(rendering_type), rendering_mesh(&mesh), last_transform_mat(last_pos), transform_mat(position) {}
Renderer::Renderer(GLFWwindow *window, gfx::Shader shader, std::shared_ptr<Camera> camera)
: window(window), shader(shader), camera(camera)/* , transparent_render_queue(CameraDistanceComparator(camera)) */ {}
@ -50,8 +52,8 @@ namespace simpleengine::gfx {
// std::sort()
}
void Renderer::queue_job(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position) {
RenderingJob job(rendering_type, mesh, position);
void Renderer::queue_job(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 last_position, glm::mat4 position) {
RenderingJob job(rendering_type, mesh, last_position, position);
this->queue_job(job);
}
@ -135,10 +137,37 @@ namespace simpleengine::gfx {
} */
}
bool Renderer::render_job(const RenderingJob &job) {
glm::mat4 lerp(glm::mat4 a, glm::mat4 b, float alpha) {
//return a * (1.f - alpha) + b * alpha;
glm::quat rot0 = glm::quat_cast(a);
glm::quat rot1= glm::quat_cast(b);
glm::quat finalRot = glm::slerp(rot0, rot1, alpha);
glm::mat4 finalMat = glm::mat4_cast(finalRot);
finalMat[3] = a[3] * (1 - alpha) + b[3] * alpha;
return finalMat;
}
bool Renderer::render_job(const float& interpolate_alpha, const RenderingJob &job) {
Mesh *mesh = job.rendering_mesh;
shader.set_uniform_matrix_4f("u_transform_matrix", job.transform_mat);
/* glm::mat4 transform_mat = job.transform_mat * interpolate_alpha +
job.last_transform_mat * (1.f - interpolate_alpha); */
//glm::mat4 transform_mat = lerp(job.transform_mat, job.last_transform_mat, interpolate_alpha);
glm::mat4 transform_mat = lerp(job.last_transform_mat, job.transform_mat, interpolate_alpha);
std::cout << "Last transform: " << glm::to_string(job.last_transform_mat) << std::endl <<
"Current Transform: " << glm::to_string(job.transform_mat) << std::endl <<
"Lerp: " << glm::to_string(transform_mat) << std::endl << std::endl;
//std::cout << "Current: " << job.transform_mat[3]
shader.set_uniform_matrix_4f("u_transform_matrix", transform_mat);
//shader.set_uniform_matrix_4f("u_transform_matrix", job.transform_mat);
std::optional<Material> &material = mesh->material;
@ -196,12 +225,12 @@ namespace simpleengine::gfx {
return true;
}
void Renderer::render_job_queue(std::queue<RenderingJob> &rendering_queue) {
void Renderer::render_job_queue(const float& interpolate_alpha, std::queue<RenderingJob> &rendering_queue) {
while (!rendering_queue.empty()) {
// Get the job from the queue, we'll remove it after we render.
RenderingJob &job = rendering_queue.front();
bool res = this->render_job(job);
bool res = this->render_job(interpolate_alpha, job);
if (res) {
// Now we'll remove the job from the queue.
@ -210,19 +239,19 @@ namespace simpleengine::gfx {
}
}
void Renderer::render_job_queue(std::map<float, RenderingJob, std::greater<>>& rendering_queue) {
void Renderer::render_job_queue(const float& interpolate_alpha, std::map<float, RenderingJob, std::greater<>>& rendering_queue) {
// Render each job then clear the queue
for (const auto& it : rendering_queue) {
this->render_job(it.second);
this->render_job(interpolate_alpha, it.second);
}
rendering_queue.clear();
}
void Renderer::render() {
void Renderer::render(const float& interpolate_alpha, const float& frame_time) {
check_if_initialized();
// Render other (opaque) objects first
render_job_queue(other_render_queue);
render_job_queue(interpolate_alpha, other_render_queue);
// Render transparent objects
std::map<float, RenderingJob, std::greater<>> transparent_jobs;
@ -235,6 +264,6 @@ namespace simpleengine::gfx {
transparent_render_queue.pop();
}
render_job_queue(transparent_jobs);
render_job_queue(interpolate_alpha, transparent_jobs);
}
} // namespace simpleengine::gfx

View File

@ -16,30 +16,37 @@ namespace simpleengine {
}
void Scene::update(const float& delta_time) {
// Rotate the model
registry.view<TransformComponent, RotatingComponent>().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) {
transform.rotate(rotating.rate * delta_time, rotating.rotation_axis);
});
}
void Scene::render(const float& interpolate_alpha, const float& frame_time) {
// Is there a way these can be grouped?
registry.view<const TransformComponent, ModelComponent>().each([this](const TransformComponent& transform, ModelComponent& model_component) {
registry.view<TransformComponent, ModelComponent>().each([this](TransformComponent& transform, ModelComponent& model_component) {
for (auto& mesh : model_component.model.meshes) {
auto rendering_type = gfx::RenderingType::RendType_OPAQUE;
if (mesh.material) {
rendering_type = mesh.material->rendering_type;
}
renderer->queue_job(gfx::RenderingJob(rendering_type, mesh, transform.transform_matrix));
renderer->queue_job(gfx::RenderingJob(rendering_type, mesh, transform.last_transform_matrix, transform.transform_matrix));
transform.last_transform_matrix = transform.transform_matrix; // Update last transform
}
});
registry.view<const TransformComponent, MeshComponent>().each([this](const TransformComponent& transform, MeshComponent& mesh_component) {
registry.view<TransformComponent, MeshComponent>().each([this](TransformComponent& transform, MeshComponent& mesh_component) {
auto rendering_type = gfx::RenderingType::RendType_OPAQUE;
if (mesh_component.mesh.material) {
rendering_type = mesh_component.mesh.material->rendering_type;
}
renderer->queue_job(gfx::RenderingJob(rendering_type, mesh_component.mesh, transform.transform_matrix));
renderer->queue_job(gfx::RenderingJob(rendering_type, mesh_component.mesh, transform.last_transform_matrix, transform.transform_matrix));
transform.last_transform_matrix = transform.transform_matrix; // Update last transform
});
registry.view<TransformComponent, RotatingComponent>().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) {
transform.rotate(rotating.rate * delta_time, rotating.rotation_axis);
});
renderer->render(interpolate_alpha, frame_time);
}
void Scene::destroy() {