Start working on fixed timestep
Frame interprelation still needs to be done to make a slow TPS look smooth
This commit is contained in:
parent
ce8886ade1
commit
78ef93bcf5
|
@ -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"
|
||||
---
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
36
src/game.cpp
36
src/game.cpp
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue