Skip to content

Commit

Permalink
Zephyr: Renderer: implement preliminary camera support
Browse files Browse the repository at this point in the history
  • Loading branch information
fleroviux committed May 4, 2024
1 parent f4b9e25 commit 234dc72
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 10 deletions.
24 changes: 23 additions & 1 deletion app/next/src/main_window.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

#include <zephyr/renderer/backend/render_backend_ogl.hpp>
#include <zephyr/renderer/backend/render_backend_vk.hpp>
#include <zephyr/renderer/component/mesh.hpp>
#include <zephyr/renderer/component/camera.hpp>

#include "gltf_loader.hpp"
#include "main_window.hpp"
Expand Down Expand Up @@ -39,6 +39,9 @@ namespace zephyr {
void MainWindow::MainLoop() {
SDL_Event event{};

f32 euler_x = 0.0f;
f32 euler_y = 0.0f;

while(true) {
while(SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT) {
Expand All @@ -63,6 +66,21 @@ namespace zephyr {
}
}

const u8* key_state = SDL_GetKeyboardState(nullptr);

Vector3& camera_position = m_camera_node->GetTransform().GetPosition();
const f32 delta_p = 0.075f;
const f32 delta_r = 0.01f;
if(key_state[SDL_SCANCODE_W]) camera_position -= m_camera_node->GetTransform().GetLocal().Z().XYZ() * delta_p;
if(key_state[SDL_SCANCODE_S]) camera_position += m_camera_node->GetTransform().GetLocal().Z().XYZ() * delta_p;
if(key_state[SDL_SCANCODE_A]) camera_position -= m_camera_node->GetTransform().GetLocal().X().XYZ() * delta_p;
if(key_state[SDL_SCANCODE_D]) camera_position += m_camera_node->GetTransform().GetLocal().X().XYZ() * delta_p;
if(key_state[SDL_SCANCODE_LEFT]) euler_y += delta_r;
if(key_state[SDL_SCANCODE_RIGHT]) euler_y -= delta_r;
if(key_state[SDL_SCANCODE_UP]) euler_x += delta_r;
if(key_state[SDL_SCANCODE_DOWN]) euler_x -= delta_r;
m_camera_node->GetTransform().GetRotation().SetFromEuler(euler_x, euler_y, 0.0f);

RenderFrame();
}
}
Expand Down Expand Up @@ -125,6 +143,10 @@ namespace zephyr {
void MainWindow::CreateScene() {
m_scene_root = SceneNode::New();

m_camera_node = m_scene_root->CreateChild("RenderCamera");
m_camera_node->CreateComponent<PerspectiveCameraComponent>(45.0f, 16.f / 9.f, 0.01f, 100.f);
m_camera_node->GetTransform().GetPosition() = {0.f, 0.f, 5.f};

GLTFLoader gltf_loader{};
std::shared_ptr<SceneNode> gltf_scene_1 = gltf_loader.Parse("models/DamagedHelmet/DamagedHelmet.gltf");
gltf_scene_1->GetTransform().GetPosition() = {1.0f, 0.0f, -5.0f};
Expand Down
1 change: 1 addition & 0 deletions app/next/src/main_window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ namespace zephyr {

std::unique_ptr<RenderEngine> m_render_engine{};
std::shared_ptr<SceneNode> m_scene_root{};
std::shared_ptr<SceneNode> m_camera_node{};
std::shared_ptr<SceneNode> m_behemoth_scene{};

u64 m_frame{};
Expand Down
1 change: 1 addition & 0 deletions zephyr/renderer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ set(HEADERS_PUBLIC
include/zephyr/renderer/backend/render_backend.hpp
include/zephyr/renderer/backend/render_backend_ogl.hpp
include/zephyr/renderer/backend/render_backend_vk.hpp
include/zephyr/renderer/component/camera.hpp
include/zephyr/renderer/component/mesh.hpp
include/zephyr/renderer/engine/geometry_cache.hpp
include/zephyr/renderer/resource/geometry.hpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ namespace zephyr {
virtual void DestroyRenderGeometry(RenderGeometry* geometry) = 0;

/// Just a quick thing for testing the rendering.
virtual void Render(const Matrix4& projection, std::span<const RenderObject> render_objects) = 0;
virtual void Render(const Matrix4& view_projection, std::span<const RenderObject> render_objects) = 0;

/// Start rendering the next frame.
virtual void SwapBuffers() = 0;
Expand Down
102 changes: 102 additions & 0 deletions zephyr/renderer/include/zephyr/renderer/component/camera.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@

#pragma once

#include <zephyr/math/frustum.hpp>
#include <zephyr/math/matrix4.hpp>
#include <zephyr/scene/component.hpp>
#include <zephyr/float.hpp>

namespace zephyr {

class PerspectiveCameraComponent : public Component {
public:
PerspectiveCameraComponent(f32 field_of_view, f32 aspect_ratio, f32 near, f32 far) {
Setup(field_of_view, aspect_ratio, near, far);
}

void Setup(f32 field_of_view, f32 aspect_ratio, f32 near, f32 far) {
m_field_of_view = field_of_view;
m_aspect_ratio = aspect_ratio;
m_near = near;
m_far = far;
m_needs_update = true;
}

[[nodiscard]] const Matrix4& GetProjectionMatrix() const {
if(m_needs_update) {
UpdateProjectionMatrixAndFrustum();
}
return m_projection_matrix;
}

[[nodiscard]] const Frustum& GetFrustum() const {
if(m_needs_update) {
UpdateProjectionMatrixAndFrustum();
}
return m_frustum;
}

[[nodiscard]] f32 GetFieldOfView() const {
return m_field_of_view;
}

void SetFieldOfView(f32 field_of_view) {
m_field_of_view = field_of_view;
m_needs_update = true;
}

[[nodiscard]] f32 GetAspectRatio() const {
return m_aspect_ratio;
}

void SetAspectRatio(f32 aspect_ratio) {
m_aspect_ratio = aspect_ratio;
m_needs_update = true;
}

[[nodiscard]] f32 GetNear() const {
return m_near;
}

void SetNear(f32 near) {
m_near = near;
m_needs_update = true;
}

[[nodiscard]] f32 GetFar() const {
return m_far;
}

void SetFar(f32 far) {
m_far = far;
m_needs_update = true;
}

private:
void UpdateProjectionMatrixAndFrustum() const {
m_projection_matrix = Matrix4::PerspectiveVK(m_field_of_view, m_aspect_ratio, m_near, m_far);

const f32 x = 1.f / m_projection_matrix.X().X();
const f32 y = 1.f / m_projection_matrix.Y().Y();

m_frustum.SetPlane(Frustum::Side::NZ, Plane{Vector3{ 0, 0, -1}, -m_near});
m_frustum.SetPlane(Frustum::Side::PZ, Plane{Vector3{ 0, 0, 1}, -m_far });
m_frustum.SetPlane(Frustum::Side::NX, Plane{Vector3{ 1 , 0, -x}.Normalize(), 0});
m_frustum.SetPlane(Frustum::Side::PX, Plane{Vector3{-1 , 0, -x}.Normalize(), 0});
m_frustum.SetPlane(Frustum::Side::NY, Plane{Vector3{ 0, 1, -y}.Normalize(), 0});
m_frustum.SetPlane(Frustum::Side::PY, Plane{Vector3{ 0, -1, -y}.Normalize(), 0});

m_needs_update = false;
}

f32 m_field_of_view{};
f32 m_aspect_ratio{};
f32 m_near{};
f32 m_far{};

mutable bool m_needs_update{};
mutable Matrix4 m_projection_matrix{};
mutable Frustum m_frustum{};
};

} // namespace zephyr
5 changes: 5 additions & 0 deletions zephyr/renderer/include/zephyr/renderer/render_engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ namespace zephyr {
};
std::vector<GameThreadRenderObject> m_game_thread_render_objects;

struct RenderCamera {
Matrix4 view;
Matrix4 projection;
} m_render_camera{};

std::vector<RenderObject> m_render_objects;
};

Expand Down
4 changes: 2 additions & 2 deletions zephyr/renderer/src/backend/opengl/render_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,14 @@ namespace zephyr {
delete geometry;
}

void Render(const Matrix4& projection, std::span<const RenderObject> render_objects) override {
void Render(const Matrix4& view_projection, std::span<const RenderObject> render_objects) override {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glUseProgram(m_gl_shader_program);

glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_gl_ubo);
glNamedBufferSubData(m_gl_ubo, 0, sizeof(Matrix4), &projection);
glNamedBufferSubData(m_gl_ubo, 0, sizeof(Matrix4), &view_projection);

for(const RenderObject& render_object : render_objects) {
glNamedBufferSubData(m_gl_ubo, sizeof(Matrix4), sizeof(Matrix4), &render_object.local_to_world);
Expand Down
4 changes: 2 additions & 2 deletions zephyr/renderer/src/backend/vulkan/render_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ namespace zephyr {
ZEPHYR_PANIC("unimplemented");
}

void Render(const Matrix4& projection, std::span<const RenderObject> render_objects) override {
void Render(const Matrix4& view_projection, std::span<const RenderObject> render_objects) override {
const VkClearValue clear_value{
.color = VkClearColorValue{
.float32 = {0.01f, 0.01f, 0.01f, 1.0f}
Expand All @@ -95,7 +95,7 @@ namespace zephyr {

vkCmdBeginRenderPass(m_vk_command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(m_vk_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_vk_pipeline);
vkCmdPushConstants(m_vk_command_buffer, m_vk_pipeline_layout, VK_SHADER_STAGE_ALL, 0u, sizeof(Matrix4), &projection);
vkCmdPushConstants(m_vk_command_buffer, m_vk_pipeline_layout, VK_SHADER_STAGE_ALL, 0u, sizeof(Matrix4), &view_projection);

for(const RenderObject& render_object : render_objects) {
vkCmdPushConstants(m_vk_command_buffer, m_vk_pipeline_layout, VK_SHADER_STAGE_ALL, sizeof(Matrix4), sizeof(Matrix4), &render_object.local_to_world);
Expand Down
17 changes: 13 additions & 4 deletions zephyr/renderer/src/render_engine.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

#include <zephyr/renderer/component/camera.hpp>
#include <zephyr/renderer/component/mesh.hpp>
#include <zephyr/renderer/render_engine.hpp>
#include <fmt/format.h>
Expand All @@ -22,8 +23,10 @@ namespace zephyr {
// Instruct the geometry cache to evict geometries which had been deleted in the submitted frame.
m_geometry_cache.CommitPendingDeleteTaskList();

// Build a list of objects to render and instruct the geometry cache to update (if necessary) any geometries we might need to render.
// Traverse the scene and update any data structures (such as render lists and resource caches) needed to render the frame.
m_game_thread_render_objects.clear();
m_render_camera.view = Matrix4::Identity();
m_render_camera.projection = Matrix4::Identity();
scene_root->Traverse([&](SceneNode* node) -> bool {
if(!node->IsVisible()) return false;

Expand All @@ -41,6 +44,13 @@ namespace zephyr {
}
}

// TODO(fleroviux): think of a better way to mark the camera we actually want to use.
if(node->HasComponent<PerspectiveCameraComponent>()) {
const PerspectiveCameraComponent& camera_component = node->GetComponent<PerspectiveCameraComponent>();
m_render_camera.view = node->GetTransform().GetWorld().Inverse();
m_render_camera.projection = camera_component.GetProjectionMatrix();
}

return true;
});

Expand Down Expand Up @@ -68,9 +78,8 @@ namespace zephyr {
while(m_render_thread_running) {
ReadyRenderThreadData();

// TODO(fleroviux): do not hardcode the aspect ratio.
const Matrix4 projection = Matrix4::PerspectiveVK(45.0f, 16.0f/9.0, 0.01f, 100.0f);
m_render_backend->Render(projection, m_render_objects);
const Matrix4 view_projection = m_render_camera.projection * m_render_camera.view;
m_render_backend->Render(view_projection, m_render_objects);
m_render_backend->SwapBuffers();
}

Expand Down

0 comments on commit 234dc72

Please sign in to comment.