diff --git a/Resources/Shaders/initial.frag b/Resources/Shaders/base.frag similarity index 100% rename from Resources/Shaders/initial.frag rename to Resources/Shaders/base.frag diff --git a/Resources/Shaders/base.vert b/Resources/Shaders/base.vert new file mode 100644 index 00000000..594985b5 --- /dev/null +++ b/Resources/Shaders/base.vert @@ -0,0 +1,6 @@ +#version 460 + +void main() +{ + gl_Position = vec4(vec3(0), 0.0f); +} diff --git a/Resources/Shaders/composite.frag b/Resources/Shaders/composite.frag new file mode 100644 index 00000000..d9425d3f --- /dev/null +++ b/Resources/Shaders/composite.frag @@ -0,0 +1,14 @@ +#version 460 + +layout(location = 0) in vec2 outUV; + +layout(set = 0, binding = 0) uniform texture2D sharedRTAsTex; +layout(set = 1, binding = 1) uniform sampler LinearWrapSampler; + +layout(location = 0) out vec4 outColor; + +void main() +{ + vec4 color = texture(sampler2D(sharedRTAsTex, LinearWrapSampler), outUV); + outColor = color; +} diff --git a/Resources/Shaders/composite.vert b/Resources/Shaders/composite.vert new file mode 100644 index 00000000..f6f16976 --- /dev/null +++ b/Resources/Shaders/composite.vert @@ -0,0 +1,9 @@ +#version 460 + +layout(location = 0) out vec2 outUV; + +void main() +{ + outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f); +} diff --git a/Resources/Shaders/infinite_grid.frag b/Resources/Shaders/infinite_grid.frag index 14fceda8..ffa9bea4 100644 --- a/Resources/Shaders/infinite_grid.frag +++ b/Resources/Shaders/infinite_grid.frag @@ -8,21 +8,24 @@ layout(location = 1) in float scaleFactor; layout(location = 0) out vec4 outColor; float gridCellSize = 0.025; - vec4 gridColorThin = vec4(1.0, 1.0, 1.0, 1.0); vec4 gridColorThick = vec4(0.5, 0.5, 0.5, 1.0); const float gridMinPixelsBetweenCells = 2.0; void main() { - vec2 dudv = vec2(length(vec2(dFdx(uv.x), dFdy(uv.x))), length(vec2(dFdx(uv.y), dFdy(uv.y)))); + vec2 dudv = vec2(length(vec2(dFdx(uv.x), dFdy(uv.x))), length(vec2(dFdx(uv.y), dFdy(uv.y)))); + dudv = max(dudv, vec2(0.0001)); float lodLevel = max(0.0, log_10((length(dudv) * gridMinPixelsBetweenCells) / gridCellSize) + 1.0); - float lodFade = fract(lodLevel); + lodLevel = min(lodLevel, 2.0); + + // Smooth fade between LOD levels to kill flickering + float lodFade = smoothstep(0.0, 1.0, fract(lodLevel)); - float lod0 = gridCellSize * pow(10.0, floor(lodLevel + 0)); - float lod1 = gridCellSize * pow(10.0, floor(lodLevel + 1)); - float lod2 = gridCellSize * pow(10.0, floor(lodLevel + 2)); + float lod0 = gridCellSize * pow(10.0, floor(lodLevel)); + float lod1 = gridCellSize * pow(10.0, floor(lodLevel + 1.0)); + float lod2 = gridCellSize * pow(10.0, floor(lodLevel + 2.0)); dudv *= 4.0; @@ -31,8 +34,17 @@ void main() float lod2a = max2(vec2(1.0) - abs(satv(mod(uv, lod2) / dudv) * 2.0 - vec2(1.0))); vec4 c = lod2a > 0.0 ? gridColorThick : lod1a > 0.0 ? mix(gridColorThick, gridColorThin, lodFade) : gridColorThin; - float opacityFalloff = (1.0 - satf(length(uv) / scaleFactor)); - c.a *= lod2a > 0.0 ? lod2a : lod1a > 0.0 ? lod1a : (lod0a * (1.0 - lodFade)); + + // Fade based on distance from camera, using actual world-space diagonal + float maxDist = scaleFactor * 1.5; // covers the quad diagonal + float opacityFalloff = pow(1.0 - satf(length(uv) / maxDist), 0.5); + + c.a = lod2a > 0.0 ? lod2a : lod1a > 0.0 ? lod1a : (lod0a * (1.0 - lodFade)); c.a *= opacityFalloff; - outColor = c; -} \ No newline at end of file + + // Discard fully transparent fragments to avoid depth artifacts + if (c.a < 0.001) + discard; + + outColor = c; +} diff --git a/Resources/Shaders/infinite_grid.vert b/Resources/Shaders/infinite_grid.vert index 8b267caa..56e60571 100644 --- a/Resources/Shaders/infinite_grid.vert +++ b/Resources/Shaders/infinite_grid.vert @@ -13,9 +13,9 @@ Camera; void main() { - scaleFactor = 50.0; + scaleFactor = 1000.0f; + vec3 worldPos = pos + vec3(Camera.Position.x, 0.0, Camera.Position.z); - vec3 posScale = pos * scaleFactor; - uv = posScale.xz; - gl_Position = Camera.Projection * Camera.View * vec4(posScale, 1.0); -} \ No newline at end of file + uv = worldPos.xz; + gl_Position = Camera.Projection * Camera.View * vec4(worldPos, 1.0); +} diff --git a/Resources/Shaders/initial.vert b/Resources/Shaders/initial.vert deleted file mode 100644 index d7c27ac1..00000000 --- a/Resources/Shaders/initial.vert +++ /dev/null @@ -1,16 +0,0 @@ -#version 460 - -layout(location = 0) in vec3 pos; - -layout(set = 0, binding = 0) uniform UBCamera -{ - mat4 View; - mat4 Projection; - vec4 Position; -} -Camera; - -void main() -{ - gl_Position = vec4(pos, 1.0f); -} \ No newline at end of file diff --git a/Resources/Shaders/skybox.frag b/Resources/Shaders/skybox.frag index 05386bcb..949763eb 100644 --- a/Resources/Shaders/skybox.frag +++ b/Resources/Shaders/skybox.frag @@ -3,9 +3,9 @@ layout(location = 0) in vec3 dir; layout(location = 0) out vec4 outColor; layout(set = 0, binding = 1) uniform textureCube EnvMap; -layout(set = 1, binding = 1) uniform sampler LinearWrapSampler; +layout(set = 0, binding = 2) uniform sampler LinearClampToEdgeSampler; void main() { - outColor = texture(samplerCube(EnvMap, LinearWrapSampler), dir); -} \ No newline at end of file + outColor = texture(samplerCube(EnvMap, LinearClampToEdgeSampler), normalize(dir)); +} diff --git a/Resources/Shaders/skybox.vert b/Resources/Shaders/skybox.vert index 772c862c..d9851947 100644 --- a/Resources/Shaders/skybox.vert +++ b/Resources/Shaders/skybox.vert @@ -12,8 +12,10 @@ Camera; void main() { - dir = normalize(vec3(pos.x, -pos.y, pos.z)); + dir = pos; // normalize(vec3(pos.x, -pos.y, pos.z)); mat4 rotScaleView = mat4(mat3(Camera.View)); - vec4 position = Camera.Projection * rotScaleView * vec4(pos, 1.0f); + + vec4 position = Camera.Projection * rotScaleView * vec4(pos * 10.0f, 1.0f); + gl_Position = position.xyww; } diff --git a/Tetragrama/Components/HierarchyViewUIComponent.cpp b/Tetragrama/Components/HierarchyViewUIComponent.cpp index 404c3a66..4d86db3f 100644 --- a/Tetragrama/Components/HierarchyViewUIComponent.cpp +++ b/Tetragrama/Components/HierarchyViewUIComponent.cpp @@ -223,8 +223,8 @@ namespace Tetragrama::Components if (app->CameraController) { auto camera = app->CameraController->GetCamera(); - const auto camera_projection = camera->GetPerspectiveMatrix(); - const auto camera_view_matrix = camera->GetViewMatrix(); + const auto camera_projection = camera->GetProjection(); + const auto camera_view_matrix = camera->GetView(); auto& global_transform = current_scene->GlobalTransforms[selected_node]; auto initial_transform = global_transform; @@ -233,7 +233,7 @@ namespace Tetragrama::Components if (camera && IDevice::As()->IsKeyPressed(ZENGINE_KEY_F, app->CurrentWindow)) { auto active_editor_camera = reinterpret_cast(app->CameraController); - active_editor_camera->SetTarget(Vec3f(global_transform[0][3], global_transform[1][3], global_transform[2][3])); + // active_editor_camera->SetFocus(Vec3f(global_transform[0][3], global_transform[1][3], global_transform[2][3])); } // snapping diff --git a/Tetragrama/Components/SceneViewportUIComponent.cpp b/Tetragrama/Components/SceneViewportUIComponent.cpp index b56365ee..b65c02b3 100644 --- a/Tetragrama/Components/SceneViewportUIComponent.cpp +++ b/Tetragrama/Components/SceneViewportUIComponent.cpp @@ -104,7 +104,7 @@ namespace Tetragrama::Components if (m_scene_texture.Valid()) { - ImGui::Image((ImTextureID) m_scene_texture.Index, m_viewport_size, ImVec2(0, 1), ImVec2(1, 0)); + ImGui::Image((ImTextureID) m_scene_texture.Index, m_viewport_size, ImVec2(0, 0), ImVec2(1, 1)); } // ViewPort bound computation ImVec2 viewport_windows_size = ImGui::GetWindowSize(); diff --git a/Tetragrama/Controllers/EditorCameraController.cpp b/Tetragrama/Controllers/EditorCameraController.cpp index b68bfa4f..b317be75 100644 --- a/Tetragrama/Controllers/EditorCameraController.cpp +++ b/Tetragrama/Controllers/EditorCameraController.cpp @@ -7,17 +7,12 @@ using namespace ZEngine::Core::Maths; namespace Tetragrama::Controllers { - void EditorCameraController::Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, ZEngine::Windows::CoreWindow* window, double distance, float yaw_degree, float pitch_degree) + void EditorCameraController::Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, ZEngine::Windows::CoreWindow* window) { - m_position = {0.0f, 0.0f, 1.5f}; - m_process_event = true; - m_controller_type = ZEngine::Controllers::CameraControllerType::PERSPECTIVE_CONTROLLER; - m_window = window; + m_window = window; + m_controller_type = ZEngine::Controllers::CameraControllerType::PERSPECTIVE_CONTROLLER; - m_perspective_camera = ZPushStructCtor(arena, PerspectiveCamera); - m_perspective_camera->Initialize(m_camera_fov, m_aspect_ratio, m_camera_near, m_camera_far, radians(yaw_degree), radians(pitch_degree)); - m_perspective_camera->SetDistance(distance); - - m_window = window; + const auto& win_props = m_window->GetWindowProperty(); + m_camera = ZPushStructCtorArgs(arena, FlyCamera, win_props.AspectRatio); } } // namespace Tetragrama::Controllers diff --git a/Tetragrama/Controllers/EditorCameraController.h b/Tetragrama/Controllers/EditorCameraController.h index 4a742bbf..aec08614 100644 --- a/Tetragrama/Controllers/EditorCameraController.h +++ b/Tetragrama/Controllers/EditorCameraController.h @@ -1,14 +1,14 @@ #pragma once -#include +#include namespace Tetragrama::Controllers { - struct EditorCameraController : public ZEngine::Controllers::PerspectiveCameraController + struct EditorCameraController : public ZEngine::Controllers::FlyCameraController { EditorCameraController() = default; virtual ~EditorCameraController() = default; - void Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, ZEngine::Windows::CoreWindow* window, double distance, float yaw_degree, float pitch_degree); + void Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, ZEngine::Windows::CoreWindow* window); }; ZDEFINE_PTR(EditorCameraController); } // namespace Tetragrama::Controllers diff --git a/Tetragrama/Editor.cpp b/Tetragrama/Editor.cpp index 22dbf84f..e823cbeb 100644 --- a/Tetragrama/Editor.cpp +++ b/Tetragrama/Editor.cpp @@ -47,7 +47,7 @@ namespace Tetragrama UILayer = ZPushStructCtor(Arena, ImguiLayer); UILayer->Initialize(Arena, this); - editor_cam_controller->Initialize(Arena, CurrentWindow, 150.0, 0.f, 45.f); + editor_cam_controller->Initialize(Arena, CurrentWindow); editor_scene->Initialize(Arena, Configuration->ActiveSceneName.c_str()); CameraController = editor_cam_controller; diff --git a/ZEngine/ZEngine/Controllers/FlyCameraController.cpp b/ZEngine/ZEngine/Controllers/FlyCameraController.cpp new file mode 100644 index 00000000..ebc84ac1 --- /dev/null +++ b/ZEngine/ZEngine/Controllers/FlyCameraController.cpp @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +using namespace ZEngine::Helpers; +using namespace ZEngine::Windows::Inputs; +using namespace ZEngine::Windows::Events; + +namespace ZEngine::Controllers +{ + void FlyCameraController::Update(Core::TimeStep dt) + { + m_camera->OnUpdate(dt); + } + + bool FlyCameraController::OnEvent(Core::CoreEvent& e) + { + if (!m_process_event.value.load(std::memory_order_acquire)) + { + return false; + } + + Core::EventDispatcher dispatcher(e); + dispatcher.Dispatch(std::bind(&FlyCameraController::OnMouseButtonWheelMoved, this, std::placeholders::_1)); + dispatcher.Dispatch(std::bind(&FlyCameraController::OnMouseButtonReleased, this, std::placeholders::_1)); + dispatcher.Dispatch(std::bind(&FlyCameraController::OnMouseButtonPressed, this, std::placeholders::_1)); + dispatcher.Dispatch(std::bind(&FlyCameraController::OnMouseButtonMoved, this, std::placeholders::_1)); + + dispatcher.Dispatch(std::bind(&FlyCameraController::OnKeyPressed, this, std::placeholders::_1)); + dispatcher.Dispatch(std::bind(&FlyCameraController::OnKeyReleased, this, std::placeholders::_1)); + return false; + } + + Rendering::Cameras::CameraPtr FlyCameraController::GetCamera() const + { + return m_camera; + } + + Core::Maths::Vec3f FlyCameraController::GetPosition() const + { + return m_camera->GetPosition(); + } + + void FlyCameraController::SetPosition(const Core::Maths::Vec3f& position) + { + m_camera->SetPosition(position); + } + + void FlyCameraController::SetViewport(float width, float height) + { + m_camera->SetViewportSize(width, height); + } + + bool FlyCameraController::OnMouseButtonReleased(MouseButtonReleasedEvent& e) + { + m_camera->OnMouseButtonUp((int) e.GetButton()); + return false; + } + + bool FlyCameraController::OnMouseButtonPressed(MouseButtonPressedEvent& e) + { + m_camera->OnMouseButtonDown((int) e.GetButton()); + return false; + } + + bool FlyCameraController::OnMouseButtonWheelMoved(MouseButtonWheelEvent& e) + { + const auto mouse_position = IDevice::As()->GetMousePosition(m_window); + m_camera->OnMouseScroll(e.GetOffetY(), mouse_position[0], mouse_position[1]); + return false; + } + + bool FlyCameraController::OnMouseButtonMoved(MouseButtonMovedEvent& e) + { + m_camera->OnMouseMove(e.GetXOffset(), e.GetYOffset()); + return false; + } + + bool FlyCameraController::OnKeyPressed(KeyPressedEvent& e) + { + m_camera->OnKeyDown((int) e.GetKeyCode()); + return false; + } + + bool FlyCameraController::OnKeyReleased(KeyReleasedEvent& e) + { + m_camera->OnKeyUp((int) e.GetKeyCode()); + return false; + } + + void FlyCameraController::ResumeEventProcessing() + { + m_process_event.value.store(true, std::memory_order_release); + } + + void FlyCameraController::PauseEventProcessing() + { + m_process_event.value.store(false, std::memory_order_release); + } +} // namespace ZEngine::Controllers \ No newline at end of file diff --git a/ZEngine/ZEngine/Controllers/FlyCameraController.h b/ZEngine/ZEngine/Controllers/FlyCameraController.h new file mode 100644 index 00000000..3f69d47a --- /dev/null +++ b/ZEngine/ZEngine/Controllers/FlyCameraController.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include + +namespace ZEngine::Controllers +{ + struct FlyCameraController : public ICameraController, public Windows::Inputs::IMouseEventCallback, public Windows::Inputs::IKeyboardEventCallback + { + FlyCameraController() = default; + virtual ~FlyCameraController() = default; + + void Update(Core::TimeStep) override; + bool OnEvent(Core::CoreEvent&) override; + + Rendering::Cameras::CameraPtr GetCamera() const override; + virtual Core::Maths::Vec3f GetPosition() const override; + virtual void SetPosition(const Core::Maths::Vec3f& position) override; + + void SetViewport(float width, float height); + void ResumeEventProcessing(); + void PauseEventProcessing(); + + virtual bool OnMouseButtonPressed(Windows::Events::MouseButtonPressedEvent&) override; + virtual bool OnMouseButtonReleased(Windows::Events::MouseButtonReleasedEvent&) override; + virtual bool OnMouseButtonMoved(Windows::Events::MouseButtonMovedEvent&) override; + virtual bool OnMouseButtonWheelMoved(Windows::Events::MouseButtonWheelEvent&) override; + + virtual bool OnKeyPressed(Windows::Events::KeyPressedEvent&) override; + virtual bool OnKeyReleased(Windows::Events::KeyReleasedEvent&) override; + + protected: + PaddedAtomic m_process_event = {.value = false}; + Rendering::Cameras::FlyCameraPtr m_camera = nullptr; + }; +} // namespace ZEngine::Controllers \ No newline at end of file diff --git a/ZEngine/ZEngine/Controllers/ICameraController.h b/ZEngine/ZEngine/Controllers/ICameraController.h index 12698dea..7cacb825 100644 --- a/ZEngine/ZEngine/Controllers/ICameraController.h +++ b/ZEngine/ZEngine/Controllers/ICameraController.h @@ -10,79 +10,20 @@ namespace ZEngine::Controllers struct ICameraController : public IController { ICameraController() {} - virtual ~ICameraController() = default; + virtual ~ICameraController() = default; - virtual Core::Maths::Vec3f GetPosition() const = 0; - virtual void SetPosition(const Core::Maths::Vec3f& position) = 0; - virtual ZRawPtr(Rendering::Cameras::Camera) GetCamera() const = 0; - virtual void UpdateProjectionMatrix() = 0; + virtual Core::Maths::Vec3f GetPosition() const = 0; + virtual void SetPosition(const Core::Maths::Vec3f& position) = 0; + virtual Rendering::Cameras::CameraPtr GetCamera() const = 0; - float GetRotationAngle() const - { - return m_rotation_angle; - } - - float GetZoomFactor() const - { - return m_zoom_factor; - } - - float GetMoveSpeed() const - { - return m_move_speed; - } - - float GetRotationSpeed() const - { - return m_rotation_speed; - } - - float GetAspectRatio() const - { - return m_aspect_ratio; - } - - CameraControllerType GetControllerType() const + CameraControllerType GetControllerType() const { return m_controller_type; } - void SetRotationAngle(float angle) - { - m_rotation_angle = angle; - } - - void SetZoomFactor(float factor) - { - m_zoom_factor = factor; - } - - void SetMoveSpeed(float speed) - { - m_move_speed = speed; - } - - void SetRotationSpeed(float speed) - { - m_rotation_speed = speed; - } - - void SetAspectRatio(float ar) - { - m_aspect_ratio = ar; - UpdateProjectionMatrix(); - } - protected: - Core::Maths::Vec3f m_position{0.0f, 0.0f, 10.0f}; - float m_rotation_angle{0.0f}; - float m_zoom_factor{1.0f}; - float m_move_speed{0.05f}; - float m_rotation_speed{0.05f}; - float m_aspect_ratio{0.0f}; - bool m_can_rotate{false}; - CameraControllerType m_controller_type{CameraControllerType::UNDEFINED}; - ZRawPtr(Windows::CoreWindow) m_window = nullptr; + CameraControllerType m_controller_type{CameraControllerType::UNDEFINED}; + Windows::CoreWindowPtr m_window = nullptr; }; ZDEFINE_PTR(ICameraController); } // namespace ZEngine::Controllers diff --git a/ZEngine/ZEngine/Controllers/PerspectiveCameraController.cpp b/ZEngine/ZEngine/Controllers/PerspectiveCameraController.cpp index 83335293..d6192732 100644 --- a/ZEngine/ZEngine/Controllers/PerspectiveCameraController.cpp +++ b/ZEngine/ZEngine/Controllers/PerspectiveCameraController.cpp @@ -46,35 +46,6 @@ namespace ZEngine::Controllers m_perspective_camera->SetPosition(position); } - float PerspectiveCameraController::GetFieldOfView() const - { - return m_perspective_camera->Fov; - } - - void PerspectiveCameraController::SetFieldOfView(float rad_fov) - { - m_perspective_camera->Fov = rad_fov; - } - - float PerspectiveCameraController::GetNear() const - { - return m_perspective_camera->ClipNear; - } - - void PerspectiveCameraController::SetNear(float value) - { - m_perspective_camera->ClipNear = value; - } - - float PerspectiveCameraController::GetFar() const - { - return m_perspective_camera->ClipFar; - } - void PerspectiveCameraController::SetFar(float value) - { - m_perspective_camera->ClipFar = value; - } - void PerspectiveCameraController::SetViewport(float width, float height) { m_perspective_camera->SetViewport(width, height); @@ -106,8 +77,6 @@ namespace ZEngine::Controllers return m_perspective_camera; } - void PerspectiveCameraController::UpdateProjectionMatrix() {} - bool PerspectiveCameraController::OnEvent(Core::CoreEvent& e) { if (!m_process_event) diff --git a/ZEngine/ZEngine/Controllers/PerspectiveCameraController.h b/ZEngine/ZEngine/Controllers/PerspectiveCameraController.h index b7632b6a..ed0cb6eb 100644 --- a/ZEngine/ZEngine/Controllers/PerspectiveCameraController.h +++ b/ZEngine/ZEngine/Controllers/PerspectiveCameraController.h @@ -14,30 +14,19 @@ namespace ZEngine::Controllers PerspectiveCameraController(); virtual ~PerspectiveCameraController() = default; - void Update(Core::TimeStep) override; - bool OnEvent(Core::CoreEvent&) override; + void Update(Core::TimeStep) override; + bool OnEvent(Core::CoreEvent&) override; - ZRawPtr(Rendering::Cameras::Camera) GetCamera() const override; + Rendering::Cameras::CameraPtr GetCamera() const override; - void UpdateProjectionMatrix() override; + virtual Core::Maths::Vec3f GetPosition() const override; + virtual void SetPosition(const Core::Maths::Vec3f& position) override; - virtual Core::Maths::Vec3f GetPosition() const override; - virtual void SetPosition(const Core::Maths::Vec3f& position) override; + void SetViewport(float width, float height); + void SetTarget(const Core::Maths::Vec3f& target); - virtual float GetFieldOfView() const; - virtual void SetFieldOfView(float rad_fov); - - virtual float GetNear() const; - virtual void SetNear(float value); - - virtual float GetFar() const; - virtual void SetFar(float value); - - void SetViewport(float width, float height); - void SetTarget(const Core::Maths::Vec3f& target); - - virtual void ResumeEventProcessing(); - virtual void PauseEventProcessing(); + virtual void ResumeEventProcessing(); + virtual void PauseEventProcessing(); public: bool OnMouseButtonPressed(Windows::Events::MouseButtonPressedEvent&) override @@ -59,7 +48,7 @@ namespace ZEngine::Controllers protected: float m_camera_fov = 90.0f; - float m_camera_near = 1.f; + float m_camera_near = 0.1f; float m_camera_far = 1000.0f; bool m_process_event = true; Core::Maths::Vec3f m_camera_target = {0.0f, 0.0f, 0.0f}; diff --git a/ZEngine/ZEngine/Core/Maths/MathUtils.h b/ZEngine/ZEngine/Core/Maths/MathUtils.h index 2f42f858..1b12db2f 100644 --- a/ZEngine/ZEngine/Core/Maths/MathUtils.h +++ b/ZEngine/ZEngine/Core/Maths/MathUtils.h @@ -214,4 +214,27 @@ namespace ZEngine::Core::Maths return sin(x) / c; } + inline static float smoothstep(float t) + { + // Ken Perlin's improved smoothstep (C2 continuous) + return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); + } + + inline static float lerpAngle(float a, float b, float t) + { + float diff = b - a; + // Wrap to [-180, 180] + while (diff > 180.0f) + diff -= 360.0f; + while (diff < -180.0f) + diff += 360.0f; + return a + diff * t; + } + + template + constexpr T lerp(T a, T b, F t) + { + return a + (b - a) * t; + } + } // namespace ZEngine::Core::Maths \ No newline at end of file diff --git a/ZEngine/ZEngine/Core/Maths/Quaternion.h b/ZEngine/ZEngine/Core/Maths/Quaternion.h index 9b0fd1a1..f3b4bfe0 100644 --- a/ZEngine/ZEngine/Core/Maths/Quaternion.h +++ b/ZEngine/ZEngine/Core/Maths/Quaternion.h @@ -348,4 +348,22 @@ namespace ZEngine::Core::Maths return Mat4(T(1) - (yy + zz), xy - wz, xz + wy, T(0), xy + wz, T(1) - (xx + zz), yz - wx, T(0), xz - wy, yz + wx, T(1) - (xx + yy), T(0), T(0), T(0), T(0), T(1)); } + template + inline Vec3f QuaternionToForwardVec(const Quaternion& quat) + { + return Vec3f(2 * ((quat.x * quat.z) + (quat.w * quat.y)), 2 * ((quat.y * quat.z) - (quat.w * quat.x)), 1 - 2 * ((quat.x * quat.x) + (quat.y * quat.y))); + } + + template + inline Vec3f QuaternionToRightVec(const Quaternion& quat) + { + return Vec3f(1 - 2 * ((quat.y * quat.y) + (quat.z * quat.z)), 2 * ((quat.x * quat.y) + (quat.w * quat.z)), 2 * ((quat.x * quat.z) - (quat.w * quat.y))); + } + + template + inline Vec3f QuaternionToUpVec(const Quaternion& quat) + { + return Vec3f(2 * ((quat.x * quat.y) - (quat.w * quat.z)), 1 - 2 * ((quat.x * quat.x) + (quat.z * quat.z)), 2 * ((quat.y * quat.z) + (quat.w * quat.x))); + } + } // namespace ZEngine::Core::Maths \ No newline at end of file diff --git a/ZEngine/ZEngine/Core/Memory/Allocator.cpp b/ZEngine/ZEngine/Core/Memory/Allocator.cpp index 127fcbdd..d2b7ef3b 100644 --- a/ZEngine/ZEngine/Core/Memory/Allocator.cpp +++ b/ZEngine/ZEngine/Core/Memory/Allocator.cpp @@ -84,12 +84,12 @@ namespace ZEngine::Core::Memory void ArenaAllocator::CreateSubArena(size_t size, ArenaAllocator* out_arena) { out_arena->m_memory = reinterpret_cast(Allocate(size)); - out_arena->m_initial_previous_offset = m_previous_offset; - out_arena->m_initial_current_offset = m_previous_offset; + out_arena->m_initial_previous_offset = 0; + out_arena->m_initial_current_offset = 0; - out_arena->m_previous_offset = out_arena->m_initial_previous_offset; - out_arena->m_current_offset = out_arena->m_initial_current_offset; - out_arena->m_total_size = m_previous_offset + size; + out_arena->m_previous_offset = 0; + out_arena->m_current_offset = 0; + out_arena->m_total_size = size; } ArenaTemp BeginTempArena(ArenaAllocator* arena) diff --git a/ZEngine/ZEngine/Hardwares/AsyncResourceLoader.cpp b/ZEngine/ZEngine/Hardwares/AsyncResourceLoader.cpp index 1bdf4427..a3fde334 100644 --- a/ZEngine/ZEngine/Hardwares/AsyncResourceLoader.cpp +++ b/ZEngine/ZEngine/Hardwares/AsyncResourceLoader.cpp @@ -620,7 +620,6 @@ namespace ZEngine::Hardwares TextureUploadRequest upload_req = {}; int width = 0, height = 0, channel = 0; - stbi_set_flip_vertically_on_load(1); if (file_request.TextureSpec.IsCubemap) { @@ -698,6 +697,7 @@ namespace ZEngine::Hardwares } else { + stbi_set_flip_vertically_on_load(1); stbi_uc* image_data = stbi_load(file_request.Filename.data(), &width, &height, &channel, STBI_rgb_alpha); if (!image_data) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index 047107e8..8d7eb1f1 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -435,27 +435,46 @@ namespace ZEngine::Hardwares /* * Creating Global Descriptor Pool for : Textures, Samplers */ - VkSamplerCreateInfo sampler_create_info = {}; - sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - sampler_create_info.minFilter = VK_FILTER_LINEAR; - sampler_create_info.magFilter = VK_FILTER_LINEAR; - sampler_create_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_create_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_create_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_create_info.anisotropyEnable = PhysicalDeviceFeature.features.samplerAnisotropy; - sampler_create_info.maxAnisotropy = PhysicalDeviceFeature.features.samplerAnisotropy ? PhysicalDeviceProperties.properties.limits.maxSamplerAnisotropy : 1.0f; - sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - sampler_create_info.unnormalizedCoordinates = VK_FALSE; - sampler_create_info.compareEnable = VK_FALSE; - sampler_create_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - sampler_create_info.mipLodBias = 0.0f; - sampler_create_info.minLod = 0.0f; - sampler_create_info.maxLod = VK_LOD_CLAMP_NONE; - - ZENGINE_VALIDATE_ASSERT(vkCreateSampler(LogicalDevice, &sampler_create_info, nullptr, &GlobalLinearWrapSampler) == VK_SUCCESS, "Failed to create Texture Sampler") - - GlobalLinearWrapSamplerImageInfo = VkDescriptorImageInfo{.sampler = GlobalLinearWrapSampler, .imageView = VK_NULL_HANDLE, .imageLayout = VK_IMAGE_LAYOUT_UNDEFINED}; - MaxGlobalTexture = std::min(MaxGlobalTexture, PhysicalDeviceVulkan12Properties.maxPerStageDescriptorUpdateAfterBindSampledImages - 1); + VkSamplerCreateInfo linear_sampler_create_info = {}; + linear_sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + linear_sampler_create_info.minFilter = VK_FILTER_LINEAR; + linear_sampler_create_info.magFilter = VK_FILTER_LINEAR; + linear_sampler_create_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + linear_sampler_create_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + linear_sampler_create_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + linear_sampler_create_info.anisotropyEnable = PhysicalDeviceFeature.features.samplerAnisotropy; + linear_sampler_create_info.maxAnisotropy = PhysicalDeviceFeature.features.samplerAnisotropy ? PhysicalDeviceProperties.properties.limits.maxSamplerAnisotropy : 1.0f; + linear_sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + linear_sampler_create_info.unnormalizedCoordinates = VK_FALSE; + linear_sampler_create_info.compareEnable = VK_FALSE; + linear_sampler_create_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + linear_sampler_create_info.mipLodBias = 0.0f; + linear_sampler_create_info.minLod = 0.0f; + linear_sampler_create_info.maxLod = VK_LOD_CLAMP_NONE; + + VkSamplerCreateInfo linear_sampler_clamp_to_edge_create_info = {}; + linear_sampler_clamp_to_edge_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + linear_sampler_clamp_to_edge_create_info.minFilter = VK_FILTER_LINEAR; + linear_sampler_clamp_to_edge_create_info.magFilter = VK_FILTER_LINEAR; + linear_sampler_clamp_to_edge_create_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + linear_sampler_clamp_to_edge_create_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + linear_sampler_clamp_to_edge_create_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + linear_sampler_clamp_to_edge_create_info.anisotropyEnable = VK_FALSE; + linear_sampler_clamp_to_edge_create_info.maxAnisotropy = 1.0f; + linear_sampler_clamp_to_edge_create_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + linear_sampler_clamp_to_edge_create_info.unnormalizedCoordinates = VK_FALSE; + linear_sampler_clamp_to_edge_create_info.compareEnable = VK_FALSE; + linear_sampler_clamp_to_edge_create_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + linear_sampler_clamp_to_edge_create_info.mipLodBias = 0.0f; + linear_sampler_clamp_to_edge_create_info.minLod = 0.0f; + linear_sampler_clamp_to_edge_create_info.maxLod = VK_LOD_CLAMP_NONE; + + ZENGINE_VALIDATE_ASSERT(vkCreateSampler(LogicalDevice, &linear_sampler_create_info, nullptr, &GlobalLinearWrapSampler) == VK_SUCCESS, "Failed to create Texture Sampler") + ZENGINE_VALIDATE_ASSERT(vkCreateSampler(LogicalDevice, &linear_sampler_clamp_to_edge_create_info, nullptr, &GlobalLinearClampToEdgeSampler) == VK_SUCCESS, "Failed to create Texture Sampler") + + GlobalLinearWrapSamplerImageInfo = VkDescriptorImageInfo{.sampler = GlobalLinearWrapSampler, .imageView = VK_NULL_HANDLE, .imageLayout = VK_IMAGE_LAYOUT_UNDEFINED}; + GlobalLinearClampToEdgeSamplerImageInfo = VkDescriptorImageInfo{.sampler = GlobalLinearClampToEdgeSampler, .imageView = VK_NULL_HANDLE, .imageLayout = VK_IMAGE_LAYOUT_UNDEFINED}; + MaxGlobalTexture = std::min(MaxGlobalTexture, PhysicalDeviceVulkan12Properties.maxPerStageDescriptorUpdateAfterBindSampledImages - 1); GlobalTextures.Initialize(Arena, MaxGlobalTexture); Image2DBufferManager.Initialize(Arena, MaxGlobalTexture); @@ -618,12 +637,14 @@ namespace ZEngine::Hardwares __createDebugMessengerPtr = nullptr; } vkDestroySampler(LogicalDevice, GlobalLinearWrapSampler, nullptr); + vkDestroySampler(LogicalDevice, GlobalLinearClampToEdgeSampler, nullptr); vkDestroyDevice(LogicalDevice, nullptr); vkDestroyInstance(Instance, nullptr); - GlobalLinearWrapSampler = VK_NULL_HANDLE; - LogicalDevice = VK_NULL_HANDLE; - Instance = VK_NULL_HANDLE; + GlobalLinearWrapSampler = VK_NULL_HANDLE; + GlobalLinearClampToEdgeSampler = VK_NULL_HANDLE; + LogicalDevice = VK_NULL_HANDLE; + Instance = VK_NULL_HANDLE; } void VulkanDevice::QueueSubmit(CommandBuffer* const command_buffer, Rendering::Primitives::Semaphore* const signal_semaphore, uint32_t wait_flag, uint64_t signal_value, uint64_t wait_value, Rendering::Primitives::Semaphore* const wait_semaphore) @@ -1360,12 +1381,18 @@ namespace ZEngine::Hardwares if (std::filesystem::exists(vertex_file)) { - spec.VertexFilename = vertex_file.c_str(); + auto name_c_size = (vertex_file.size() + 1u); + auto name_c_str = ZPushString(Arena, name_c_size); + Helpers::secure_strcpy(name_c_str, name_c_size, vertex_file.c_str()); + spec.VertexFilename = name_c_str; } if (std::filesystem::exists(fragment_file)) { - spec.FragmentFilename = fragment_file.c_str(); + auto name_c_size = (fragment_file.size() + 1u); + auto name_c_str = ZPushString(Arena, name_c_size); + Helpers::secure_strcpy(name_c_str, name_c_size, fragment_file.c_str()); + spec.FragmentFilename = name_c_str; } shader->Initialize(this, spec); @@ -1612,10 +1639,16 @@ namespace ZEngine::Hardwares // We're safe to use index as Set for (uint32_t i = 0; i < set_layout.size(); ++i) { - frame_sets.push(descriptor_set_map.at(i)[frame_index]); + if (descriptor_set_map.contains(i)) + { + frame_sets.push(descriptor_set_map.at(i)[frame_index]); + } } - vkCmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, frame_sets.size(), frame_sets.data(), 0, nullptr); + if(!frame_sets.empty()) + { + vkCmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, frame_sets.size(), frame_sets.data(), 0, nullptr); + } ZReleaseScratch(scratch); } } @@ -1741,8 +1774,8 @@ namespace ZEngine::Hardwares VkViewport viewport = {}; viewport.x = x; viewport.y = y; - viewport.width = w; - viewport.height = h; + viewport.width = (float)w; + viewport.height = (float)h; viewport.minDepth = min_depth; viewport.maxDepth = max_depth; vkCmdSetViewport(m_command_buffer, 0, 1, &viewport); diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.h b/ZEngine/ZEngine/Hardwares/VulkanDevice.h index d88eda40..5c0e7033 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.h +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.h @@ -609,9 +609,11 @@ namespace ZEngine::Hardwares VkPhysicalDeviceFeatures2 PhysicalDeviceFeature = {}; VkPhysicalDeviceMemoryProperties PhysicalDeviceMemoryProperties = {}; VkSampler GlobalLinearWrapSampler = VK_NULL_HANDLE; + VkSampler GlobalLinearClampToEdgeSampler = VK_NULL_HANDLE; VkDescriptorPool GlobalDescriptorPoolHandle = VK_NULL_HANDLE; VmaAllocator VmaAllocatorValue = nullptr; VkDescriptorImageInfo GlobalLinearWrapSamplerImageInfo = {}; + VkDescriptorImageInfo GlobalLinearClampToEdgeSamplerImageInfo = {}; CommandBufferManagerPtr CommandBufferMgr = {}; DeviceSwapchainPtr SwapchainPtr = {}; Core::Containers::Array DefaultDepthFormats = {}; diff --git a/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp b/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp index e2dd5a51..cc22f8fc 100644 --- a/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp +++ b/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp @@ -37,8 +37,8 @@ namespace ZEngine::Importers m_is_importing.store(true, std::memory_order_release); - int width = 0, height = 0, channel = 0; - stbi_set_flip_vertically_on_load(1); + int width = 0, height = 0, channel = 0; + // stbi_set_flip_vertically_on_load(1); const float* image_data = stbi_loadf(path.c_str(), &width, &height, &channel, 4); if (!image_data) diff --git a/ZEngine/ZEngine/Rendering/Cameras/Camera.h b/ZEngine/ZEngine/Rendering/Cameras/Camera.h index cfa719f9..de1095d6 100644 --- a/ZEngine/ZEngine/Rendering/Cameras/Camera.h +++ b/ZEngine/ZEngine/Rendering/Cameras/Camera.h @@ -5,35 +5,76 @@ namespace ZEngine::Rendering::Cameras { + enum class CameraMode + { + Orbit, + Free + }; + + struct CameraSetting + { + float MinMoveSpeed = 1.0f; + float MaxMoveSpeed = 500.0f; + float PanSpeed = 1.0f; // multiplier + float MoveSpeed = 10.0f; + float FastMoveSpeed = 40.0f; + float RotationSpeed = 0.25f; // degrees per pixel + float OrbitSpeed = 0.25f; // degrees per pixel + float FastSpeedMultiplier = 4.0f; // shift multiplier + float ScrollSpeed = 3.0f; + float FocusDuration = 0.25f; // seconds + float MinOrbitDistance = 0.5f; + float MaxOrbitDistance = 10000.0f; + float FOV = 60.0f; + float NearPlane = 0.1f; + float FarPlane = 10000.0f; + float SmoothingFactor = 12.0f; // higher = snappier + }; + struct Camera { - float Fov = 0.0f; - float AspectRatio = 0.0f; - float ClipNear = 0.1f; - float ClipFar = 1000.0f; + CameraType Type = CameraType::UNDEFINED; + + float AspectRatio = 16.0f / 9.0f; + float Pitch = 0.0f; + float Yaw = 0.0f; /* * Coordinate Vectors */ - ZEngine::Core::Maths::Vec3f Position = {0.0f, 0.0f, 0.0f}; - ZEngine::Core::Maths::Vec3f Up = {0.0f, 1.0f, 0.0f}; - const ZEngine::Core::Maths::Vec3f WorldUp = {0.0f, 1.0f, 0.0f}; - ZEngine::Core::Maths::Vec3f Right = {0.0f, 0.0f, 0.0f}; - ZEngine::Core::Maths::Vec3f Forward = {0.0f, 0.0f, 0.0f}; - ZEngine::Core::Maths::Vec3f Target = {0.0f, 0.0f, -1.0f}; + ZEngine::Core::Maths::Vec3f Position = {0.0f, 5.f, 10.0f}; + ZEngine::Core::Maths::Vec3f Up = {0.0f, 1.0f, 0.0f}; + const ZEngine::Core::Maths::Vec3f WorldUp = {0.0f, 1.0f, 0.0f}; + ZEngine::Core::Maths::Vec3f Right = {0.0f, 0.0f, 0.0f}; + ZEngine::Core::Maths::Vec3f Forward = {0.0f, 0.0f, 0.0f}; + ZEngine::Core::Maths::Vec3f Target = {0.0f, 0.0f, -1.0f}; /* * Matrices */ - ZEngine::Core::Maths::Mat4f View = ZEngine::Core::Maths::Identity(); - ZEngine::Core::Maths::Mat4f Projection = ZEngine::Core::Maths::Identity(); - ZEngine::Core::Maths::Mat4f ViewProjection = ZEngine::Core::Maths::Identity(); - /* - * Extras data - */ - CameraType Type = CameraType::UNDEFINED; + ZEngine::Core::Maths::Mat4f View = ZEngine::Core::Maths::Identity(); + ZEngine::Core::Maths::Mat4f Projection = ZEngine::Core::Maths::Identity(); + ZEngine::Core::Maths::Mat4f ViewProjection = ZEngine::Core::Maths::Identity(); + + CameraSetting Settings = {}; + + virtual const ZEngine::Core::Maths::Mat4f& GetView() const + { + return View; + } + + virtual const ZEngine::Core::Maths::Mat4f& GetProjection() const + { + return Projection; + } + + virtual ZEngine::Core::Maths::Mat4f GetViewProjection() const + { + return Projection * View; + } - virtual ZEngine::Core::Maths::Mat4f GetViewMatrix() = 0; - virtual ZEngine::Core::Maths::Mat4f GetPerspectiveMatrix() const = 0; - virtual ZEngine::Core::Maths::Vec3f GetPosition() const = 0; + virtual ZEngine::Core::Maths::Vec3f GetPosition() const = 0; + virtual ZEngine::Core::Maths::Vec3f GetForward() = 0; + virtual ZEngine::Core::Maths::Vec3f GetUp() = 0; + virtual ZEngine::Core::Maths::Vec3f GetRight() = 0; }; ZDEFINE_PTR(Camera); } // namespace ZEngine::Rendering::Cameras diff --git a/ZEngine/ZEngine/Rendering/Cameras/FlyCamera.cpp b/ZEngine/ZEngine/Rendering/Cameras/FlyCamera.cpp new file mode 100644 index 00000000..7220272b --- /dev/null +++ b/ZEngine/ZEngine/Rendering/Cameras/FlyCamera.cpp @@ -0,0 +1,435 @@ +#include +#include +#include +#include + +using namespace ZEngine::Core::Maths; + +namespace ZEngine::Rendering::Cameras +{ + static constexpr float kPitchLimit = radians(89.0f); + + FlyCamera::FlyCamera(float aspectRatio, CameraSetting settings) + { + AspectRatio = aspectRatio; + Settings = settings; + Position = {0.0f, 20.0f, 10.0f}; + Pitch = radians(30.0f); + + m_targetPosition = Position; + + m_projectionDirty = true; + m_viewDirty = true; + + UpdateMatrices(); + } + + Quaternion FlyCamera::GetOrientation() const + { + return fromEulerAngles(-Pitch, -Yaw, 0.0f); + } + + Vec3f FlyCamera::GetPosition() const + { + return Position; + } + + Vec3f FlyCamera::GetForward() + { + return rotate(GetOrientation(), Vec3f(0.0f, 0.0f, -1.0f)); + } + + Vec3f FlyCamera::GetRight() + { + return rotate(GetOrientation(), Vec3f(1.0f, 0.0f, 0.0f)); + } + + Vec3f FlyCamera::GetUp() + { + return rotate(GetOrientation(), WorldUp); + } + + void FlyCamera::UpdateMatrices() + { + if (m_projectionDirty) + RecalculateProjection(); + if (m_viewDirty) + RecalculateView(); + } + + void FlyCamera::RecalculateView() + { + Vec3f f = GetForward(); + Vec3f r = GetRight(); + Vec3f u = GetUp(); + + View = Mat4f(r.x, r.y, r.z, -dot(r, Position), u.x, u.y, u.z, -dot(u, Position), -f.x, -f.y, -f.z, dot(f, Position), 0.0f, 0.0f, 0.0f, 1.0f); + m_viewDirty = false; + } + + void FlyCamera::RecalculateProjection() + { + float fovRad = radians(Settings.FOV); + float tanHalf = tanf(fovRad * 0.5f); + float n = Settings.NearPlane; + float f = Settings.FarPlane; + float a = AspectRatio; + + // Vulkan: Y flipped, Depth [0, 1] + Projection = Mat4f(1.0f / (a * tanHalf), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f / tanHalf, 0.0f, 0.0f, 0.0f, 0.0f, f / (n - f), (n * f) / (n - f), 0.0f, 0.0f, -1.0f, 0.0f); + m_projectionDirty = false; + } + + void FlyCamera::SetViewportSize(float width, float height) + { + m_viewportWidth = width; + m_viewportHeight = height; + AspectRatio = width / height; + RecalculateProjection(); + } + + void FlyCamera::SetPosition(Vec3f position) + { + Position = m_targetPosition = position; + RecalculateView(); + } + + void FlyCamera::SetOrientation(float pitchDeg, float yawDeg) + { + Pitch = m_targetPitch = clamp(radians(pitchDeg), -kPitchLimit, kPitchLimit); + Yaw = m_targetYaw = radians(yawDeg); + m_viewDirty = true; + RecalculateView(); + } + + void FlyCamera::FocusOn(Vec3f center, float radius) + { + float fovRad = radians(Settings.FOV); + float distance = (radius / tanf(fovRad * 0.5f)) * 1.5f; + distance = max(distance, Settings.MinOrbitDistance); + + // Keep the current look direction — move straight back along it + Vec3f dir = (Position - center).magnitude() > 0.001f ? (Position - center).normalize() : -GetForward(); + Vec3f endPos = center + dir * distance; + + // Compute the yaw/pitch that looks FROM endPos TOWARD center + Vec3f lookDir = -dir; + float endPitch = asinf(clamp(lookDir.y, -1.0f, 1.0f)); + float endYaw = -atan2f(lookDir.x, -lookDir.z); + + // Enter orbit around the focused point + m_orbitPivot = center; + m_orbitDistance = distance; + m_targetOrbitDist = distance; + m_mode = CameraMode::Orbit; + + // Animate smoothly + m_animStartPos = Position; + m_animEndPos = endPos; + m_animStartPitch = Pitch; + m_animStartYaw = Yaw; + m_animEndPitch = endPitch; + m_animEndYaw = endYaw; + m_animTimer = 0.0f; + m_animDuration = Settings.FocusDuration; + m_animating = true; + } + + void FlyCamera::FocusOn(Vec3f point) + { + float dist = (Position - point).magnitude(); + float radius = clamp(dist * 0.3f, 0.5f, 500.0f); + FocusOn(point, radius); + } + + void FlyCamera::OnMouseButtonDown(int button) + { + using KC = Windows::Inputs::GlfwKeyCode; + if (button == (int) KC::MOUSE_BUTTON_RIGHT) + m_rightMouseDown = true; + if (button == (int) KC::MOUSE_BUTTON_MIDDLE) + m_middleMouseDown = true; + } + + void FlyCamera::OnMouseButtonUp(int button) + { + using KC = Windows::Inputs::GlfwKeyCode; + if (button == (int) KC::MOUSE_BUTTON_RIGHT) + { + m_rightMouseDown = false; + if (!m_altDown && m_mode == CameraMode::Orbit) + ExitOrbitMode(); + } + if (button == (int) KC::MOUSE_BUTTON_MIDDLE) + m_middleMouseDown = false; + } + + void FlyCamera::OnKeyDown(int key) + { + using KC = Windows::Inputs::GlfwKeyCode; + if (key >= 0 && key < 512) + m_keys[key] = true; + if (key == (int) KC::KEY_LEFT_SHIFT) + m_shiftDown = true; + if (key == (int) KC::KEY_LEFT_ALT) + m_altDown = true; + } + + void FlyCamera::OnKeyUp(int key) + { + using KC = Windows::Inputs::GlfwKeyCode; + if (key >= 0 && key < 512) + m_keys[key] = false; + + if (key == (int) KC::KEY_LEFT_SHIFT) + m_shiftDown = false; + + if (key == (int) KC::KEY_LEFT_ALT) + { + m_altDown = false; + if (m_mode == CameraMode::Orbit && !m_rightMouseDown) + ExitOrbitMode(); + } + + // F — frame to world origin (override with selected-object bounds externally) + if (key == (int) KC::KEY_F) + FocusOn(Vec3f(0.0f, 0.0f, 0.0f), 5.0f); + } + + void FlyCamera::OnMouseMove(float deltaX, float deltaY) + { + if (m_animating) + return; + + float dx = deltaX / m_viewportWidth; + float dy = deltaY / m_viewportHeight; + + // 1. ALT + RMB = Orbit/Tumble + if (m_altDown && m_mode == CameraMode::Orbit) + { + float yawSign = GetUp().y < 0.0f ? -1.0f : 1.0f; + m_targetYaw -= yawSign * dx * PI * Settings.OrbitSpeed; + m_targetPitch = clamp(m_targetPitch - dy * PI * Settings.OrbitSpeed, -kPitchLimit, kPitchLimit); + return; + } + + // 2. MMB = Screen-Plane Pan (Refined) + if (m_middleMouseDown) + { + float focalDist = (m_mode == CameraMode::Orbit) ? m_orbitDistance : 10.0f; + float fovRad = radians(Settings.FOV); + + // Calculate plane dimensions at focal distance + float planeH = 2.0f * tanf(fovRad * 0.5f) * focalDist; + float planeW = planeH * AspectRatio; + + // Use the Screen-space basis for panning to avoid "drift" at poles + Vec3f right = GetRight(); + Vec3f screenUp = cross3d(right, GetForward()).normalize(); + + Vec3f pan = (right * (-dx * planeW * Settings.PanSpeed)) + (screenUp * (dy * planeH * Settings.PanSpeed)); + + m_targetPosition += pan; + if (m_mode == CameraMode::Orbit) + m_orbitPivot += pan; + m_viewDirty = true; + return; + } + + // 3. RMB = Free Look + if (m_rightMouseDown) + { + float yawSign = GetUp().y < 0.0f ? -1.0f : 1.0f; + m_targetYaw -= yawSign * dx * PI * Settings.RotationSpeed; + m_targetPitch = clamp(m_targetPitch - dy * PI * Settings.RotationSpeed, -kPitchLimit, kPitchLimit); + + if (m_mode == CameraMode::Orbit) + ExitOrbitMode(); + } + } + + void FlyCamera::OnMouseScroll(float delta, float mouseX, float mouseY) + { + if (m_mode == CameraMode::Orbit) + { + // Zoom toward pivot — same quadratic speed as PerspectiveCamera::Zoom + float distance = m_targetOrbitDist * 0.2f; + distance = std::max(distance, 0.001f); + float speed = std::min(distance * distance, 100.0f); + + m_targetOrbitDist -= delta * speed * Settings.ScrollSpeed; + m_targetOrbitDist = clamp(m_targetOrbitDist, Settings.MinOrbitDistance, Settings.MaxOrbitDistance); + } + else + { + float speed = ComputeAdaptiveSpeed(); + m_targetPosition += GetForward() * delta * Settings.ScrollSpeed * speed; + } + } + + void FlyCamera::OnUpdate(float dt) + { + if (dt <= 0.0f) + return; + + if (m_animating) + UpdateAnimation(dt); + else if (m_mode == CameraMode::Orbit) + UpdateOrbitCamera(dt); + else + UpdateFreeCamera(dt); + + UpdateMatrices(); + } + + void FlyCamera::UpdateFreeCamera(float dt) + { + float t = clamp(Settings.SmoothingFactor * dt, 0.0f, 1.0f); + + if (m_rightMouseDown) + { + float speed = ComputeAdaptiveSpeed() * (m_shiftDown ? Settings.FastSpeedMultiplier : 1.0f); + m_targetPosition += GetKeyboardMoveDirection() * speed * dt; + } + + // Position Smoothing + if ((m_targetPosition - Position).magnitude() > 0.00001f) + { + Position = lerp(Position, m_targetPosition, t); + m_viewDirty = true; + } + + // Rotation Smoothing + m_targetPitch = clamp(m_targetPitch, -kPitchLimit, kPitchLimit); + float newPitch = clamp(lerpAngle(Pitch, m_targetPitch, t), -kPitchLimit, kPitchLimit); + float newYaw = lerpAngle(Yaw, m_targetYaw, t); + + if (newPitch != Pitch || newYaw != Yaw) + { + Pitch = newPitch; + Yaw = newYaw; + m_viewDirty = true; + } + } + + void FlyCamera::UpdateOrbitCamera(float dt) + { + float t = clamp(Settings.SmoothingFactor * dt, 0.0f, 1.0f); + + m_targetPitch = clamp(m_targetPitch, -kPitchLimit, kPitchLimit); + Pitch = clamp(lerp(Pitch, m_targetPitch, t), -kPitchLimit, kPitchLimit); + Yaw = lerpAngle(Yaw, m_targetYaw, t); // was lerp — now shortest path + m_orbitDistance = lerp(m_orbitDistance, m_targetOrbitDist, t); + + Vec3f fwd = GetForward(); + float safeDist = CollideCameraRay(m_orbitPivot, -fwd, m_orbitDistance); + Position = m_orbitPivot - fwd * safeDist; + m_targetPosition = Position; + m_viewDirty = true; + } + + void FlyCamera::UpdateAnimation(float dt) + { + m_animTimer += dt; + + // Clamp t to [0,1] — on a slow first frame dt can exceed duration + float t = smoothstep(clamp(m_animTimer / m_animDuration, 0.0f, 1.0f)); + + Position = lerp(m_animStartPos, m_animEndPos, t); + Pitch = clamp(lerpAngle(m_animStartPitch, m_animEndPitch, t), -kPitchLimit, kPitchLimit); + Yaw = lerpAngle(m_animStartYaw, m_animEndYaw, t); + + m_viewDirty = true; + + if (m_animTimer >= m_animDuration) + { + Position = m_animEndPos; + Pitch = clamp(m_animEndPitch, -kPitchLimit, kPitchLimit); + Yaw = m_animEndYaw; + m_animating = false; + m_targetPosition = Position; + m_targetPitch = Pitch; + m_targetYaw = Yaw; + m_targetOrbitDist = m_orbitDistance; + } + } + + void FlyCamera::EnterOrbitMode(Vec3f pivot) + { + m_orbitPivot = pivot; + m_orbitDistance = clamp((Position - pivot).magnitude(), Settings.MinOrbitDistance, Settings.MaxOrbitDistance); + m_targetOrbitDist = m_orbitDistance; + m_mode = CameraMode::Orbit; + } + + void FlyCamera::ExitOrbitMode() + { + m_targetPosition = Position; + m_targetPitch = Pitch; + m_targetYaw = Yaw; + m_mode = CameraMode::Free; + } + + Vec3f FlyCamera::GetKeyboardMoveDirection() + { + using KC = Windows::Inputs::GlfwKeyCode; + + Vec3f forward = GetForward(); + Vec3f right = GetRight(); + Vec3f up = WorldUp; // world-up so Q/E always move vertically + + Vec3f dir = {}; + if (m_keys[(int) KC::KEY_W]) + dir += forward; + if (m_keys[(int) KC::KEY_S]) + dir -= forward; + if (m_keys[(int) KC::KEY_D]) + dir += right; + if (m_keys[(int) KC::KEY_A]) + dir -= right; + if (m_keys[(int) KC::KEY_E]) + dir += up; + if (m_keys[(int) KC::KEY_Q]) + dir -= up; + + float mag = dir.magnitude(); + if (mag > 0.0001f) + dir = dir / mag; + + return dir; + } + + float FlyCamera::ComputeAdaptiveSpeed() const + { + // Stub — replace with raycast against your scene + // float hitFwd = Scene::Raycast(Position, GetForward(), FLT_MAX).distance; + // float hitDown = Scene::Raycast(Position, {0,-1,0}, FLT_MAX).distance; + // return clamp(min(hitFwd, hitDown) * 0.5f, Settings.MinMoveSpeed, Settings.MaxMoveSpeed); + + // Fallback: scale by height above ground plane + float h = fabsf(Position.y); + return clamp(h * 0.5f, Settings.MinMoveSpeed, Settings.MaxMoveSpeed); + } + + Vec3f FlyCamera::Unproject(float mouseX, float mouseY, float depth) + { + float ndcX = (mouseX / m_viewportWidth) * 2.0f - 1.0f; + float ndcY = -((mouseY / m_viewportHeight) * 2.0f - 1.0f); // Y flip for Vulkan + + float fovRad = radians(Settings.FOV); + float tanHalf = tanf(fovRad * 0.5f); + float viewX = ndcX * AspectRatio * tanHalf * depth; + float viewY = ndcY * tanHalf * depth; + + return Position + GetForward() * depth + GetRight() * viewX + GetUp() * viewY; + } + + float FlyCamera::CollideCameraRay(Vec3f /*origin*/, Vec3f /*dir*/, float desiredDist) const + { + // Plug your scene raycast here: + // RayHit hit = Scene::Raycast(origin, dir, desiredDist); + // if (hit) return hit.distance * 0.9f; + return desiredDist; + } + +} // namespace ZEngine::Rendering::Cameras \ No newline at end of file diff --git a/ZEngine/ZEngine/Rendering/Cameras/FlyCamera.h b/ZEngine/ZEngine/Rendering/Cameras/FlyCamera.h new file mode 100644 index 00000000..cad9484f --- /dev/null +++ b/ZEngine/ZEngine/Rendering/Cameras/FlyCamera.h @@ -0,0 +1,103 @@ +#pragma once +#include +#include +#include +#include + +namespace ZEngine::Rendering::Cameras +{ + + class FlyCamera : public Camera + { + public: + FlyCamera() = default; + FlyCamera(float aspectRatio, CameraSetting settings = {}); + + CameraSetting Settings = {}; + + void OnUpdate(float dt); + + void OnMouseMove(float deltaX, float deltaY); + void OnMouseScroll(float delta, float mouseX, float mouseY); + void OnMouseButtonDown(int button); + void OnMouseButtonUp(int button); + void OnKeyDown(int key); + void OnKeyUp(int key); + + void FocusOn(Core::Maths::Vec3f center, float radius); + void FocusOn(Core::Maths::Vec3f point); + + void SetViewportSize(float width, float height); + + void SetPosition(Core::Maths::Vec3f position); + void SetOrientation(float pitchDeg, float yawDeg); + + virtual Core::Maths::Vec3f GetPosition() const override; + virtual ZEngine::Core::Maths::Vec3f GetForward() override; + virtual ZEngine::Core::Maths::Vec3f GetUp() override; + virtual ZEngine::Core::Maths::Vec3f GetRight() override; + CameraMode GetMode() const + { + return m_mode; + } + + void EnterOrbitMode(Core::Maths::Vec3f pivot); + void ExitOrbitMode(); + + // Recomputed fresh every frame from m_pitch / m_yaw — + // identical pattern to PerspectiveCamera::GetOrientation(). + // No quaternion accumulation => zero roll, zero drift, zero flip. + Core::Maths::Quaternion GetOrientation() const; + + void UpdateFreeCamera(float dt); + void UpdateOrbitCamera(float dt); + void UpdateAnimation(float dt); + void RecalculateView(); + void RecalculateProjection(); + void UpdateMatrices(); + + Core::Maths::Vec3f GetKeyboardMoveDirection(); + float ComputeAdaptiveSpeed() const; + Core::Maths::Vec3f Unproject(float mouseX, float mouseY, float depth); + float CollideCameraRay(Core::Maths::Vec3f origin, Core::Maths::Vec3f dir, float desiredDist) const; + + // World-space position + Core::Maths::Vec3f m_targetPosition = {0.0f, 5.0f, 10.0f}; + + // Orientation stored as plain Euler angles (radians). + // GetOrientation() rebuilds the quaternion each frame — no accumulation. + float m_targetPitch = 0.0f; + float m_targetYaw = 0.0f; + + float m_viewportWidth = 1280.0f; + float m_viewportHeight = 720.0f; + + // Orbit + CameraMode m_mode = CameraMode::Free; + Core::Maths::Vec3f m_orbitPivot = {0.0f, 0.0f, 0.0f}; + float m_orbitDistance = 10.0f; + float m_targetOrbitDist = 10.0f; + + // Smooth focus animation + bool m_animating = false; + Core::Maths::Vec3f m_animStartPos = {}; + Core::Maths::Vec3f m_animEndPos = {}; + float m_animStartPitch = 0.0f; + float m_animStartYaw = 0.0f; + float m_animEndPitch = 0.0f; + float m_animEndYaw = 0.0f; + float m_animTimer = 0.0f; + float m_animDuration = 0.20f; + + // Input state + bool m_rightMouseDown = false; + bool m_middleMouseDown = false; + bool m_altDown = false; + bool m_shiftDown = false; + bool m_keys[512] = {}; + + bool m_projectionDirty = true; + bool m_viewDirty = true; + }; + ZDEFINE_PTR(FlyCamera); +} // namespace ZEngine::Rendering::Cameras \ No newline at end of file diff --git a/ZEngine/ZEngine/Rendering/Cameras/PerspectiveCamera.cpp b/ZEngine/ZEngine/Rendering/Cameras/PerspectiveCamera.cpp index dab22236..16122b6c 100644 --- a/ZEngine/ZEngine/Rendering/Cameras/PerspectiveCamera.cpp +++ b/ZEngine/ZEngine/Rendering/Cameras/PerspectiveCamera.cpp @@ -5,10 +5,10 @@ namespace ZEngine::Rendering::Cameras { void PerspectiveCamera::Initialize(float field_of_view, float aspect_ratio, float clip_near, float clip_far, float yaw_rad, float pitch_rad) { - Fov = ZEngine::Core::Maths::radians(field_of_view); + // Fov = ZEngine::Core::Maths::radians(field_of_view); AspectRatio = aspect_ratio; - ClipNear = clip_near; - ClipFar = clip_far; + // ClipNear = clip_near; + // ClipFar = clip_far; Target = {0.f, 0.f, 0.f}; Type = CameraType::PERSPECTIVE; m_yaw_angle = yaw_rad; @@ -64,7 +64,7 @@ namespace ZEngine::Rendering::Cameras speed = std::min(speed, 100.0f); m_distance -= delta * speed; - m_distance = ZEngine::Core::Maths::clamp(static_cast(m_distance), 3.0f, ClipFar); + // m_distance = ZEngine::Core::Maths::clamp(static_cast(m_distance), 3.0f, ClipFar); } void PerspectiveCamera::SetDistance(double distance) @@ -90,38 +90,38 @@ namespace ZEngine::Rendering::Cameras m_viewport_height = height; } - ZEngine::Core::Maths::Mat4f PerspectiveCamera::GetViewMatrix() - { - Position = Target - GetForward() * static_cast(m_distance); - auto orientation = GetOrientation(); - ZEngine::Core::Maths::Mat4f view = ZEngine::Core::Maths::translate(ZEngine::Core::Maths::Identity(), Position) * ZEngine::Core::Maths::quaternionToMat4(orientation); - view = view.Inverse(); - return view; - } + // ZEngine::Core::Maths::Mat4f PerspectiveCamera::GetViewMatrix() + //{ + // Position = Target - GetForward() * static_cast(m_distance); + // auto orientation = GetOrientation(); + // ZEngine::Core::Maths::Mat4f view = ZEngine::Core::Maths::translate(ZEngine::Core::Maths::Identity(), Position) * ZEngine::Core::Maths::quaternionToMat4(orientation); + // view = view.Inverse(); + // return view; + // } - ZEngine::Core::Maths::Mat4f PerspectiveCamera::GetPerspectiveMatrix() const - { - /* - * Ref : https://johannesugb.github.io/gpu-programming/why-do-opengl-proj-matrices-fail-in-vulkan/ - * Unlike the article, for our implementation we decided to use have the y-axis Up. - * For future Gfx API we may want to revisit/adapt it. - */ - ZEngine::Core::Maths::Mat4f I = ZEngine::Core::Maths::Identity(); - I[2][2] = -1; - - float inv_a = m_viewport_height / m_viewport_width; - float tan_half_fov = ZEngine::Core::Maths::tan(Fov / 2); - float far_minus_near = ClipFar - ClipNear; - - ZEngine::Core::Maths::Mat4f P(ZEngine::Core::Maths::Identity()); - P[0][0] = (inv_a / tan_half_fov); - P[1][1] = (1.0f / tan_half_fov); - P[2][2] = (ClipFar / far_minus_near); - P[2][3] = 1; - P[3][2] = (-(ClipFar * ClipNear) / far_minus_near); - - return P * I; - } + // ZEngine::Core::Maths::Mat4f PerspectiveCamera::GetPerspectiveMatrix() const + //{ + // /* + // * For future Gfx API we may want to revisit/adapt it. + // */ + // //float a = m_viewport_width / m_viewport_height; + // // float tan_half_fov = ZEngine::Core::Maths::tan(Fov / 2.0f); + // // float far_minus_near = ClipFar - ClipNear; + + // ZEngine::Core::Maths::Mat4f P{}; + // // P[0][0] = 1.0f / (a * tan_half_fov); + + // // Y scale (Vulkan Y is Down, so we use a negative here to keep Y-Up in world space) + // // P[1][1] = (-1.0f / tan_half_fov); + + // // P[2][2] = (ClipFar / far_minus_near); + + // P[2][3] = 1.0f; + + // // P[3][2] = (-(ClipFar * ClipNear) / far_minus_near); + + // return P; + //} ZEngine::Core::Maths::Vec3f PerspectiveCamera::GetPosition() const { diff --git a/ZEngine/ZEngine/Rendering/Cameras/PerspectiveCamera.h b/ZEngine/ZEngine/Rendering/Cameras/PerspectiveCamera.h index 2f0ba856..a3a7f7f3 100644 --- a/ZEngine/ZEngine/Rendering/Cameras/PerspectiveCamera.h +++ b/ZEngine/ZEngine/Rendering/Cameras/PerspectiveCamera.h @@ -4,7 +4,7 @@ namespace ZEngine::Rendering::Cameras { - + // Todo (@jeanphilippekernel): Need to revisit this class - for now we use FlyCamera class PerspectiveCamera : public Camera { public: @@ -24,8 +24,6 @@ namespace ZEngine::Rendering::Cameras virtual std::pair PanSpeed() const; virtual void SetViewport(float width, float height); - virtual ZEngine::Core::Maths::Mat4f GetViewMatrix() override; - virtual ZEngine::Core::Maths::Mat4f GetPerspectiveMatrix() const override; virtual ZEngine::Core::Maths::Vec3f GetPosition() const override; ZEngine::Core::Maths::Quaternion GetOrientation(); diff --git a/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp b/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp index 395a252b..33e51657 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp @@ -57,14 +57,16 @@ namespace ZEngine::Rendering::Renderers /* * Renderer Passes */ + auto base_pass = ZPushStructCtor(Device->Arena, BasePass); auto upload_pass = ZPushStructCtor(Device->Arena, UploadPass); - auto initial_pass = ZPushStructCtor(Device->Arena, InitialPass); auto scene_depth_prepass = ZPushStructCtor(Device->Arena, DepthPrePass); auto skybox_pass = ZPushStructCtor(Device->Arena, SkyboxPass); auto grid_pass = ZPushStructCtor(Device->Arena, GridPass); auto gbuffer_pass = ZPushStructCtor(Device->Arena, GbufferPass); auto lighting_pass = ZPushStructCtor(Device->Arena, LightingPass); + auto composite_pass = ZPushStructCtor(Device->Arena, CompositePass); + // FrameSharedRenderTarget = Device->CreateTexture({.PerformTransition = false, .Width = 1280, .Height = 780, .Format = ImageFormat::R8G8B8A8_UNORM}); FrameColorRenderTarget = Device->CreateTexture({.PerformTransition = false, .Width = 1280, .Height = 780, .Format = ImageFormat::R8G8B8A8_UNORM}); FrameDepthRenderTarget = Device->CreateTexture({.PerformTransition = false, .Width = 1280, .Height = 780, .Format = ImageFormat::DEPTH_STENCIL_FROM_DEVICE}); @@ -74,6 +76,7 @@ namespace ZEngine::Rendering::Renderers */ RenderGraph->Initialize(Device, RenderSceneData); + // RenderGraph->ResourceBuilder->AttachRenderTarget(RendererResourceName::FrameSharedRenderTargetName, FrameSharedRenderTarget); RenderGraph->ResourceBuilder->AttachRenderTarget(RendererResourceName::FrameDepthRenderTargetName, FrameDepthRenderTarget); RenderGraph->ResourceBuilder->AttachRenderTarget(RendererResourceName::FrameColorRenderTargetName, FrameColorRenderTarget); @@ -82,12 +85,13 @@ namespace ZEngine::Rendering::Renderers RenderGraph->ResourceBuilder->CreateBufferSet("g_scene_spot_light_buffer"); RenderGraph->AddCallbackPass("Upload Pass", upload_pass); - // RenderGraph->AddCallbackPass("Initial Pass", initial_pass); + RenderGraph->AddCallbackPass("Base Pass", base_pass); RenderGraph->AddCallbackPass("Depth Pre-Pass", scene_depth_prepass); RenderGraph->AddCallbackPass("Skybox Pass", skybox_pass); RenderGraph->AddCallbackPass("Grid Pass", grid_pass); // RenderGraph->AddCallbackPass("G-Buffer Pass", gbuffer_pass); // RenderGraph->AddCallbackPass("Lighting Pass", lighting_pass); + // RenderGraph->AddCallbackPass("Composite Pass", composite_pass); RenderGraph->Setup(); RenderGraph->Compile(); @@ -103,7 +107,7 @@ namespace ZEngine::Rendering::Renderers void GraphicRenderer::DrawScene(uint8_t frame_index, uint8_t thread_index, Hardwares::CommandBufferPtr const cb, Cameras::CameraPtr const camera) { auto asset_manager = Managers::AssetManager::Instance(); - auto ubo_camera_data = UBOCameraLayout{.View = camera->GetViewMatrix(), .Projection = camera->GetPerspectiveMatrix(), .Position = Vec4f(camera->GetPosition(), 1.0f)}; + auto ubo_camera_data = UBOCameraLayout{.View = camera->GetView(), .Projection = camera->GetProjection(), .Position = Vec4f(camera->GetPosition(), 1.0f)}; auto material_buffer_set = Device->StorageBufferSetManager.Access(RenderSceneData->MaterialBufferHandle); auto camera_buffer_set = Device->UniformBufferSetManager.Access(RenderSceneData->SceneCameraBufferHandle); diff --git a/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.h b/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.h index 9361b9a1..97655b73 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.h +++ b/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.h @@ -10,14 +10,15 @@ namespace ZEngine::Rendering::Renderers GraphicRenderer(); ~GraphicRenderer(); - cstring VertexBufferName = "VertexStorageBuffer"; - cstring IndexBufferName = "IndexStorageBuffer"; - cstring TransformBufferName = "TransformStorageBuffer"; - cstring RenderDataBufferName = "RenderDataStorageBuffer"; - cstring MaterialBufferName = "MaterialStorageBuffer"; + cstring VertexBufferName = "VertexStorageBuffer"; + cstring IndexBufferName = "IndexStorageBuffer"; + cstring TransformBufferName = "TransformStorageBuffer"; + cstring RenderDataBufferName = "RenderDataStorageBuffer"; + cstring MaterialBufferName = "MaterialStorageBuffer"; - Textures::TextureHandle FrameColorRenderTarget = {}; - Textures::TextureHandle FrameDepthRenderTarget = {}; + Textures::TextureHandle FrameSharedRenderTarget = {}; + Textures::TextureHandle FrameColorRenderTarget = {}; + Textures::TextureHandle FrameDepthRenderTarget = {}; void Initialize(Hardwares::VulkanDevicePtr device) override; void Deinitialize() override; diff --git a/ZEngine/ZEngine/Rendering/Renderers/IRenderer.h b/ZEngine/ZEngine/Rendering/Renderers/IRenderer.h index 9cdd365b..e2bf000a 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/IRenderer.h +++ b/ZEngine/ZEngine/Rendering/Renderers/IRenderer.h @@ -48,10 +48,11 @@ namespace ZEngine::Rendering::Renderers struct RendererResourceName { - inline static cstring FrameDepthRenderTargetName = "g_frame_depth_render_target"; - inline static cstring FrameColorRenderTargetName = "g_frame_color_render_target"; + inline static cstring FrameDepthRenderTargetName = "g_frame_depth_render_target"; + inline static cstring FrameSharedRenderTargetName = "g_frame_shared_render_target"; + inline static cstring FrameColorRenderTargetName = "g_frame_color_render_target"; - inline static cstring SceneCameraBufferName = "SceneCamera"; + inline static cstring SceneCameraBufferName = "SceneCamera"; }; struct IRenderer diff --git a/ZEngine/ZEngine/Rendering/Renderers/Pipelines/RendererPipeline.cpp b/ZEngine/ZEngine/Rendering/Renderers/Pipelines/RendererPipeline.cpp index f4ecae51..a275dd79 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/Pipelines/RendererPipeline.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/Pipelines/RendererPipeline.cpp @@ -84,7 +84,7 @@ namespace ZEngine::Rendering::Renderers::Pipelines rasterization_create_info.rasterizerDiscardEnable = VK_FALSE; rasterization_create_info.polygonMode = VK_POLYGON_MODE_FILL; rasterization_create_info.lineWidth = 1.0f; - rasterization_create_info.cullMode = VK_CULL_MODE_NONE; + rasterization_create_info.cullMode = (VkCullModeFlagBits) Specification.CullMode; rasterization_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rasterization_create_info.depthBiasEnable = VK_FALSE; rasterization_create_info.depthBiasConstantFactor = 0.0f; // Optional @@ -123,14 +123,34 @@ namespace ZEngine::Rendering::Renderers::Pipelines color_blend_attachment_states.init(scratch.Arena, attachment_count, attachment_count); for (uint32_t i = 0; i < attachment_count; ++i) { - color_blend_attachment_states[i].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - color_blend_attachment_states[i].blendEnable = Specification.EnableBlending ? VK_TRUE : VK_FALSE; - color_blend_attachment_states[i].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - color_blend_attachment_states[i].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_blend_attachment_states[i].colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment_states[i].srcAlphaBlendFactor = Specification.EnableBlending ? VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA : VK_BLEND_FACTOR_ONE; - color_blend_attachment_states[i].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment_states[i].alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_states[i].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + if (Specification.EnableBlending) + { + color_blend_attachment_states[i].blendEnable = VK_TRUE; + + // todo (jpkernel): those config should be expose at the pass builder level + // Color: Standard Alpha Blending + color_blend_attachment_states[i].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_states[i].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_states[i].colorBlendOp = VK_BLEND_OP_ADD; + + // Alpha: Accumulate opaqueness + color_blend_attachment_states[i].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment_states[i].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_states[i].alphaBlendOp = VK_BLEND_OP_ADD; + } + else + { + color_blend_attachment_states[i].blendEnable = VK_FALSE; + // Standard "Opaque" settings + color_blend_attachment_states[i].srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment_states[i].dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment_states[i].colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_states[i].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment_states[i].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment_states[i].alphaBlendOp = VK_BLEND_OP_ADD; + } } VkPipelineColorBlendStateCreateInfo color_blend_state_create_info = {}; diff --git a/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp b/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp index 3573c8d5..4b17b7cb 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp @@ -33,7 +33,7 @@ namespace ZEngine::Rendering::Renderers { for (auto [name, _] : NodeMap) // Todo UnorderedHashMap needs to support for (auto& [key, val]) {....} { - NodeMap[name].EdgeNodes.init(Device->Arena, 5); + NodeMap[name].EdgeNodes.init(Device->Arena); NodeMap[name].CallbackPass->Setup(Device, name, ResourceBuilder, ResourceInspector); } } @@ -50,7 +50,7 @@ namespace ZEngine::Rendering::Renderers if (NodeMap.contains(resource.ProducerNodeName)) { RenderGraphNode& producer_node = NodeMap[resource.ProducerNodeName]; - producer_node.EdgeNodes.push(pass.first); + producer_node.EdgeNodes.insert(pass.first); } } } @@ -61,48 +61,54 @@ namespace ZEngine::Rendering::Renderers /* * Topological Sorting */ - auto scratch = ZGetScratch(Device->Arena); + auto scratch = ZGetScratch(Device->Arena); - Array sorted_nodes = {}; - UnorderedHashMap visited_nodes = {}; - Array stack = {}; + Array sorted_nodes = {}; + UnorderedHashSet processed_nodes = {}; + UnorderedHashSet visited_nodes = {}; + std::stack stack = {}; - sorted_nodes.init(scratch.Arena, 6); - stack.init(scratch.Arena, 6); + sorted_nodes.init(scratch.Arena, NodeMap.size()); visited_nodes.init(scratch.Arena); + processed_nodes.init(scratch.Arena); - for (auto node : NodeMap) + for (const auto& [name, _] : NodeMap) { - stack.push(node.first); + if (processed_nodes.contains(name)) + { + continue; + } + + stack.push(name); + while (!stack.empty()) { - auto& node_name = stack.back(); - if (visited_nodes[node_name] == 2) - { - stack.pop(); - continue; - } + const auto& top = stack.top(); - if (visited_nodes[node_name] == 1) + if (!visited_nodes.contains(top)) { - visited_nodes[node_name] = 2; - sorted_nodes.push(node_name); - stack.pop(); - continue; - } + visited_nodes.insert(top); - visited_nodes[node_name] = 1; - auto& graph_node = NodeMap[node_name]; - if (graph_node.EdgeNodes.empty()) - { - continue; + auto& graph_node = NodeMap[top]; + if (!graph_node.EdgeNodes.empty()) + { + for (auto edge : graph_node.EdgeNodes) + { + if (!visited_nodes.contains(edge)) + { + stack.push(edge); + } + } + } } - - for (auto edge : graph_node.EdgeNodes) + else { - if (!visited_nodes.contains(edge)) + stack.pop(); + + if (!processed_nodes.contains(top)) { - stack.push(edge); + sorted_nodes.push(top); + processed_nodes.insert(top); } } } @@ -144,6 +150,11 @@ namespace ZEngine::Rendering::Renderers RenderPassBuilder->UseRenderTarget(resource.ResourceInfo.TextureHandle); } + + else if (output.Type == RenderGraphResourceType::REFERENCE) + { + RenderPassBuilder->UseRenderTarget(resource.ResourceInfo.TextureHandle); + } } for (auto& input : node.Creation.Inputs) @@ -165,9 +176,19 @@ namespace ZEngine::Rendering::Renderers for (cstring name : SortedNodesMap) { - auto& node = NodeMap[name]; - Specifications::FrameBufferSpecificationVNext framebuffer_spec = {.Width = node.Handle->RenderAreaWidth, .Height = node.Handle->RenderAreaHeight, .RenderTargets = node.Handle->RenderTargets, .Attachment = node.Handle->Attachment}; - node.Framebuffer = ZPushStructCtorArgs(Device->Arena, Buffers::FramebufferVNext, Device, framebuffer_spec); + auto& node = NodeMap[name]; + if (node.Handle && (node.Handle->Specification.Type != Specifications::RenderPassType::GRAPHIC)) + { + continue; + } + + Specifications::FrameBufferSpecificationVNext framebuffer_spec = { + .Width = node.Handle->RenderAreaWidth, + .Height = node.Handle->RenderAreaHeight, + .RenderTargets = node.Handle->RenderTargets, + .Attachment = node.Handle->Attachment, + }; + node.Framebuffer = ZPushStructCtorArgs(Device->Arena, Buffers::FramebufferVNext, Device, framebuffer_spec); } } @@ -175,7 +196,7 @@ namespace ZEngine::Rendering::Renderers { ZENGINE_VALIDATE_ASSERT(command_buffer, "Command Buffer can't be null") - command_buffer->ClearColor(0.1f, 0.1f, 0.1f, 1.0f); + command_buffer->ClearColor(0.5f, 0.5f, 0.5f, 1.0f); command_buffer->ClearDepth(1.0f, 0); for (auto& node_name : SortedNodesMap) @@ -227,47 +248,49 @@ namespace ZEngine::Rendering::Renderers } auto& resource = ResourceMap[output.Name]; - ZENGINE_VALIDATE_ASSERT(resource.Type == RenderGraphResourceType::ATTACHMENT, "RenderPass Output should be an Attachment") - auto texture = Device->GlobalTextures.Access(resource.ResourceInfo.TextureHandle); - auto img_buf = Device->Image2DBufferManager.Access(texture->BufferHandle); - auto& buffer = img_buf->GetBuffer(); - - Specifications::ImageMemoryBarrierSpecification barrier_spec = {}; - if (texture->IsDepthTexture) - { - barrier_spec.ImageHandle = buffer.Handle; - barrier_spec.OldLayout = img_buf->Layout; - barrier_spec.NewLayout = Specifications::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - barrier_spec.ImageAspectMask = VkImageAspectFlagBits(VK_IMAGE_ASPECT_DEPTH_BIT /*| VK_IMAGE_ASPECT_STENCIL_BIT*/); // Todo : To consider Stencil - // buffer, we want to extend - // Texture spec to introduce - // HasStencil bit - barrier_spec.SourceAccessMask = 0; - barrier_spec.DestinationAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; - barrier_spec.SourceStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - barrier_spec.DestinationStageMask = VkPipelineStageFlagBits(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); - barrier_spec.LayerCount = 1; - - Primitives::ImageMemoryBarrier barrier{barrier_spec}; - command_buffer->TransitionImageLayout(barrier); - img_buf->Layout = barrier_spec.NewLayout; - } - else + if (resource.Type == RenderGraphResourceType::ATTACHMENT) { - barrier_spec.ImageHandle = buffer.Handle; - barrier_spec.OldLayout = img_buf->Layout; - barrier_spec.NewLayout = Specifications::ImageLayout::COLOR_ATTACHMENT_OPTIMAL; - barrier_spec.ImageAspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier_spec.SourceAccessMask = 0; - barrier_spec.DestinationAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier_spec.SourceStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - barrier_spec.DestinationStageMask = VkPipelineStageFlagBits(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - barrier_spec.LayerCount = 1; + auto texture = Device->GlobalTextures.Access(resource.ResourceInfo.TextureHandle); + auto img_buf = Device->Image2DBufferManager.Access(texture->BufferHandle); + auto& buffer = img_buf->GetBuffer(); - Primitives::ImageMemoryBarrier barrier{barrier_spec}; - command_buffer->TransitionImageLayout(barrier); - img_buf->Layout = barrier_spec.NewLayout; + Specifications::ImageMemoryBarrierSpecification barrier_spec = {}; + if (texture->IsDepthTexture) + { + barrier_spec.ImageHandle = buffer.Handle; + barrier_spec.OldLayout = img_buf->Layout; + barrier_spec.NewLayout = Specifications::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + barrier_spec.ImageAspectMask = VkImageAspectFlagBits(VK_IMAGE_ASPECT_DEPTH_BIT /*| VK_IMAGE_ASPECT_STENCIL_BIT*/); // Todo : To consider Stencil + // buffer, we want to extend + // Texture spec to introduce + // HasStencil bit + barrier_spec.SourceAccessMask = 0; + barrier_spec.DestinationAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + barrier_spec.SourceStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + barrier_spec.DestinationStageMask = VkPipelineStageFlagBits(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); + barrier_spec.LayerCount = 1; + + Primitives::ImageMemoryBarrier barrier{barrier_spec}; + command_buffer->TransitionImageLayout(barrier); + img_buf->Layout = barrier_spec.NewLayout; + } + else + { + barrier_spec.ImageHandle = buffer.Handle; + barrier_spec.OldLayout = img_buf->Layout; + barrier_spec.NewLayout = Specifications::ImageLayout::COLOR_ATTACHMENT_OPTIMAL; + barrier_spec.ImageAspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier_spec.SourceAccessMask = 0; + barrier_spec.DestinationAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + barrier_spec.SourceStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + barrier_spec.DestinationStageMask = VkPipelineStageFlagBits(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + barrier_spec.LayerCount = 1; + + Primitives::ImageMemoryBarrier barrier{barrier_spec}; + command_buffer->TransitionImageLayout(barrier); + img_buf->Layout = barrier_spec.NewLayout; + } } } @@ -283,6 +306,11 @@ namespace ZEngine::Rendering::Renderers auto& pass_spec = node.Handle->Specification; + if ((pass_spec.Type != Specifications::RenderPassType::GRAPHIC) && (pass_spec.Type != Specifications::RenderPassType::COMPUTE)) + { + continue; + } + pass_spec.ExternalOutputs.clear(); pass_spec.Inputs.clear(); pass_spec.InputTextures.clear(); @@ -293,6 +321,7 @@ namespace ZEngine::Rendering::Renderers if (output.Type == RenderGraphResourceType::REFERENCE) { + pass_spec.ExternalOutputs.push(resource.ResourceInfo.TextureHandle); continue; } @@ -351,10 +380,13 @@ namespace ZEngine::Rendering::Renderers { auto& node = NodeMap[node_name]; node.Handle->Dispose(); - node.Framebuffer->Dispose(); + if (node.Handle->Specification.Type == Specifications::RenderPassType::GRAPHIC) + { + node.Framebuffer->Dispose(); + } } - for (auto resource : ResourceMap) + for (const auto& resource : ResourceMap) { auto& value = ResourceMap[resource.first]; if (value.ResourceInfo.External) @@ -450,9 +482,9 @@ namespace ZEngine::Rendering::Renderers void RenderGraphResourceBuilder::CreateRenderPassNode(const RenderGraphRenderPassCreation& creation) { Graph->NodeMap[creation.Name].Creation = creation; - for (const auto& output : Graph->NodeMap.at(creation.Name).Creation.Outputs) + for (const auto& output : creation.Outputs) { - if (output.Type == RenderGraphResourceType::ATTACHMENT) + if ((output.Type == RenderGraphResourceType::ATTACHMENT) || (output.Type == RenderGraphResourceType::BUFFER_SET)) { RenderGraphResource& resource = Graph->ResourceMap[output.Name]; resource.ProducerNodeName = creation.Name; diff --git a/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.h b/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.h index 1e784b78..4467bbba 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.h +++ b/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -88,12 +89,12 @@ namespace ZEngine::Rendering::Renderers struct RenderGraphNode { - bool Enabled = true; - RenderGraphRenderPassCreation Creation = {}; - Core::Containers::Array EdgeNodes = {}; - ZRawPtr(RenderPasses::RenderPass) Handle = nullptr; - ZRawPtr(Buffers::FramebufferVNext) Framebuffer = nullptr; - IRenderGraphCallbackPassPtr CallbackPass = nullptr; + bool Enabled = true; + RenderGraphRenderPassCreation Creation = {}; + Core::Containers::UnorderedHashSet EdgeNodes = {}; + RenderPasses::RenderPassPtr Handle = nullptr; + ZRawPtr(Buffers::FramebufferVNext) Framebuffer = nullptr; + IRenderGraphCallbackPassPtr CallbackPass = nullptr; }; struct RenderGraph diff --git a/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp b/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp index 724ca679..b8815a90 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp @@ -18,6 +18,12 @@ namespace ZEngine::Rendering::Renderers::RenderPasses { m_device = device; Specification = specification; + + if ((specification.Type != Specifications::RenderPassType::GRAPHIC) && (specification.Type != Specifications::RenderPassType::COMPUTE)) + { + return; + } + RenderTargets.init(device->Arena, 4); if (Specification.SwapchainAsRenderTarget) @@ -95,7 +101,10 @@ namespace ZEngine::Rendering::Renderers::RenderPasses m_device->GlobalTextures.Remove(handle); } - Pipeline->Dispose(); + if (Pipeline) + { + Pipeline->Dispose(); + } if (!(Specification.SwapchainAsRenderTarget) && Attachment) { @@ -105,6 +114,10 @@ namespace ZEngine::Rendering::Renderers::RenderPasses void RenderPass::Bake() { + if ((Specification.Type != Specifications::RenderPassType::GRAPHIC) && (Specification.Type != Specifications::RenderPassType::COMPUTE)) + { + return; + } Pipeline->Bake(); } @@ -128,7 +141,7 @@ namespace ZEngine::Rendering::Renderers::RenderPasses auto end = missing_names.end(); std::string unset_inputs = std::accumulate(std::next(start), end, *start, [](std::string_view a, std::string_view b) { return fmt::format("{}, {}", a.data(), b.data()); }); - ZENGINE_CORE_WARN("Shader '{}': {} unset input(s): {}", Specification.PipelineSpecification.DebugName, missing_names.size(), unset_inputs.c_str()); + ZENGINE_CORE_WARN("Pipeline '{}': {} unset input(s): {}", Specification.PipelineSpecification.DebugName, missing_names.size(), unset_inputs.c_str()); verify = false; } @@ -430,6 +443,12 @@ namespace ZEngine::Rendering::Renderers::RenderPasses return *this; } + RenderPassBuilder& RenderPassBuilder::SetCullMode(uint32_t mode) + { + m_spec.PipelineSpecification.CullMode = mode; + return *this; + } + RenderPassBuilder& RenderPassBuilder::SetInputBindingCount(uint32_t count) { m_spec.PipelineSpecification.VertexInputBindingSpecifications.init(Arena, count, count); diff --git a/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.h b/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.h index 643d152c..8b5949db 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.h +++ b/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.h @@ -28,6 +28,7 @@ namespace ZEngine::Rendering::Renderers::RenderPasses uint32_t RenderAreaWidth = 0; uint32_t RenderAreaHeight = 0; + Specifications::RenderPassSpecification Specification = {}; std::set Inputs = {}; Core::Containers::Array RenderTargets = {}; @@ -57,6 +58,7 @@ namespace ZEngine::Rendering::Renderers::RenderPasses bool m_perform_update{false}; Hardwares::VulkanDevice* m_device; }; + ZDEFINE_PTR(RenderPass); struct RenderPassBuilder { @@ -72,6 +74,7 @@ namespace ZEngine::Rendering::Renderers::RenderPasses RenderPassBuilder& PipelineDepthCompareOp(uint32_t value); RenderPassBuilder& SetShaderOverloadMaxSet(uint32_t count); RenderPassBuilder& SetOverloadPoolSize(uint32_t count); + RenderPassBuilder& SetCullMode(uint32_t); RenderPassBuilder& SetInputBindingCount(uint32_t count); RenderPassBuilder& SetStride(uint32_t input_binding_index, uint32_t value); diff --git a/ZEngine/ZEngine/Rendering/Renderers/RendererPasses.cpp b/ZEngine/ZEngine/Rendering/Renderers/RendererPasses.cpp index 4086e5d3..a961ee4c 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/RendererPasses.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/RendererPasses.cpp @@ -13,7 +13,7 @@ namespace ZEngine::Rendering::Renderers SkyboxVertexData.init(device->Arena, 24, make_initializer_list(device->Arena, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f)); SkyboxIndexData.init(device->Arena, 36, make_initializer_list(device->Arena, 0, 1, 2, 2, 3, 0, 1, 5, 6, 6, 2, 1, 5, 4, 7, 7, 6, 5, 4, 0, 3, 3, 7, 4, 3, 2, 6, 6, 7, 3, 4, 5, 1, 1, 0, 4)); - GridVertexData.init(device->Arena, 12, make_initializer_list(device->Arena, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f)); + GridVertexData.init(device->Arena, 12, make_initializer_list(device->Arena, -1000.0f, 0.01f, -1000.0f, 1000.0f, 0.01f, -1000.0f, 1000.0f, 0.01f, 1000.0f, -1000.0f, 0.01f, 1000.0f)); GridIndexData.init(device->Arena, 6, make_initializer_list(device->Arena, 0, 1, 2, 2, 3, 0)); const auto& skybox_res_vb_info = res_builder->CreateBufferSet("SkyboxVbSet", BufferSetCreationType::VERTEX); @@ -49,36 +49,25 @@ namespace ZEngine::Rendering::Renderers RenderGraphRenderPassCreation pass_node = {.Name = name}; pass_node.Inputs.init(device->Arena, 1); - pass_node.Outputs.init(device->Arena, 2); - pass_node.Outputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameDepthRenderTargetName}); - pass_node.Outputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameColorRenderTargetName}); + pass_node.Outputs.init(device->Arena, 4); + + pass_node.Outputs.push(RenderGraphRenderPassInputOutputInfo{.Name = skybox_res_vb_info.Name, .Type = RenderGraphResourceType::BUFFER_SET}); + pass_node.Outputs.push(RenderGraphRenderPassInputOutputInfo{.Name = skybox_res_ib_info.Name, .Type = RenderGraphResourceType::BUFFER_SET}); + pass_node.Outputs.push(RenderGraphRenderPassInputOutputInfo{.Name = grid_res_vb_info.Name, .Type = RenderGraphResourceType::BUFFER_SET}); + pass_node.Outputs.push(RenderGraphRenderPassInputOutputInfo{.Name = grid_res_ib_info.Name, .Type = RenderGraphResourceType::BUFFER_SET}); res_builder->CreateRenderPassNode(pass_node); } void UploadPass::Compile(Hardwares::VulkanDevicePtr const device, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPassBuilder* pass_builder, RenderGraphResourceInspectorPtr res_inspector, RenderPasses::RenderPass** const output_pass) { - // this compile action is purely fake, as this pass is only used to upload data to the buffers, - // and doesn't actually need a render pass. However, we need to create a dummy render pass to be able to execute this pass in the render graph. + CHECK_AND_ESCAPE_NULL(output_pass) + if (output_pass && !(*output_pass)) { - auto pass_spec = pass_builder->SetPipelineName("Initial-Pipeline") - .SetInputBindingCount(1) - .SetStride(0, sizeof(float) * 3) - .SetRate(0, VK_VERTEX_INPUT_RATE_VERTEX) - .SetInputAttributeCount(1) - .SetLocation(0, 0) - - .SetBinding(0, 0) - .SetFormat(0, Specifications::ImageFormat::R32G32B32_SFLOAT) - .SetOffset(0, 0) - - .EnablePipelineDepthTest(true) - .UseShader("initial") - .Detach(); - // clang-format off - *output_pass = device->CreateRenderPass(pass_spec); - // clang-format on + auto pass_spec = pass_builder->Detach(); + pass_spec.Type = Specifications::RenderPassType::TRANSFER; + *output_pass = device->CreateRenderPass(pass_spec); (*output_pass)->Bake(); } } @@ -104,63 +93,41 @@ namespace ZEngine::Rendering::Renderers WriteOnceControl[device->SwapchainPtr->CurrentFrame->Index] = 1; } - void InitialPass::Setup(Hardwares::VulkanDevicePtr const device, cstring name, RenderGraphResourceBuilderPtr const res_builder, RenderGraphResourceInspectorPtr res_inspector) + void BasePass::Setup(Hardwares::VulkanDevicePtr const device, cstring name, RenderGraphResourceBuilderPtr const res_builder, RenderGraphResourceInspectorPtr res_inspector) { - // VertexData.init(device->Arena, 3, make_initializer_list(device->Arena, 0.0f, 0.0f, 0.0f)); - - // auto& vb_res = res_builder->CreateBufferSet("initial_vertex_buffer", BufferSetCreationType::VERTEX); - // VBHandle = vb_res.ResourceInfo.VertexBufferSetHandle; - - // auto vb_view = ArrayView{VertexData}; - - // auto buffer_set = device->VertexBufferSetManager.Access(VBHandle); - // for (unsigned i = 0; i < device->SwapchainPtr->BufferredFrameCount; ++i) - //{ - // auto buffer = buffer_set->At(i); - // buffer->Allocate(vb_view.size_bytes(), "initial_vertex_buffer"); - // buffer->Write(i, 0, vb_view); - // } - RenderGraphRenderPassCreation pass_node = {.Name = name}; - pass_node.Inputs.init(device->Arena, 2); + pass_node.Inputs.init(device->Arena, 1); pass_node.Outputs.init(device->Arena, 1); + pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameDepthRenderTargetName}); - pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameColorRenderTargetName}); + pass_node.Outputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameColorRenderTargetName}); res_builder->CreateRenderPassNode(pass_node); } - void InitialPass::Compile(Hardwares::VulkanDevicePtr const device, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPassBuilder* pass_builder, RenderGraphResourceInspectorPtr res_inspector, RenderPasses::RenderPass** const output_pass) + void BasePass::Compile(Hardwares::VulkanDevicePtr const device, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPassBuilder* pass_builder, RenderGraphResourceInspectorPtr res_inspector, RenderPasses::RenderPass** const output_pass) { + CHECK_AND_ESCAPE_NULL(output_pass) + if (output_pass && !(*output_pass)) { - auto pass_spec = pass_builder->SetPipelineName("Initial-Pipeline") - .SetInputBindingCount(1) - .SetStride(0, sizeof(float) * 3) - .SetRate(0, VK_VERTEX_INPUT_RATE_VERTEX) - .SetInputAttributeCount(1) - .SetLocation(0, 0) - - .SetBinding(0, 0) - .SetFormat(0, Specifications::ImageFormat::R32G32B32_SFLOAT) - .SetOffset(0, 0) - + auto pass_spec = pass_builder->SetPipelineName("Base-Pipeline") + .SetInputBindingCount(0) .EnablePipelineDepthTest(true) - .UseShader("initial") + + .UseShader("base") .Detach(); // clang-format off *output_pass = device->CreateRenderPass(pass_spec); // clang-format on (*output_pass)->Bake(); } + (*output_pass)->Verify(); } - void InitialPass::Execute(Hardwares::VulkanDevicePtr const device, RenderGraphResourceInspectorPtr res_inspector, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPass* const pass, Buffers::FramebufferVNext* const framebuffer, Hardwares::CommandBufferPtr const command_buffer) + void BasePass::Execute(Hardwares::VulkanDevicePtr const device, RenderGraphResourceInspectorPtr res_inspector, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPass* const pass, Buffers::FramebufferVNext* const framebuffer, Hardwares::CommandBufferPtr const command_buffer) { - auto buffer_set = device->VertexBufferSetManager.Access(VBHandle); - auto vertex_buffer = buffer_set->At(device->SwapchainPtr->CurrentFrame->Index); - command_buffer->BeginRenderPass(pass, framebuffer->Handle, false); { uint32_t w = pass->GetRenderAreaWidth(); @@ -169,9 +136,8 @@ namespace ZEngine::Rendering::Renderers command_buffer->SetScissor(w, h); } command_buffer->BindPipeline(Specifications::PipelineBindPoint::GRAPHIC, pass->Pipeline); - command_buffer->BindVertexBuffer(*vertex_buffer); command_buffer->BindDescriptorSets(device->SwapchainPtr->CurrentFrame->Index); - command_buffer->Draw(1, 1, 0, 0); + command_buffer->Draw(3, 1, 0, 0); command_buffer->EndRenderPass(); } @@ -180,7 +146,8 @@ namespace ZEngine::Rendering::Renderers RenderGraphRenderPassCreation pass_node = {.Name = name}; pass_node.Inputs.init(device->Arena, 1); - pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameDepthRenderTargetName}); + pass_node.Outputs.init(device->Arena, 1); + pass_node.Outputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameDepthRenderTargetName}); res_builder->CreateRenderPassNode(pass_node); } @@ -240,37 +207,19 @@ namespace ZEngine::Rendering::Renderers auto env_map_res = res_builder->CreateTexture("skybox_env_map", "Settings/EnvironmentMaps/bergen_4k.zenvmap"); m_env_map = env_map_res.ResourceInfo.TextureHandle; - // m_vb_handle = device->CreateVertexBufferSet(); - // m_ib_handle = device->CreateIndexBufferSet(); - - // auto count = device->SwapchainPtr->BufferredFrameCount; - // auto vtx_buffer_set = device->VertexBufferSetManager.Access(m_vb_handle); - // auto idx_buffer_set = device->IndexBufferSetManager.Access(m_ib_handle); - // auto vtx_buf_view = ArrayView{m_vertex_data}; - // auto idx_buf_view = ArrayView{m_index_data}; - - // for (int i = 0; i < count; ++i) - //{ - // auto vertex_buffer = vtx_buffer_set->At(i); - // auto index_buffer = idx_buffer_set->At(i); - - // vertex_buffer->Allocate(vtx_buf_view.size_bytes(), "SkyboxPassVtx"); - // index_buffer->Allocate(idx_buf_view.size_bytes(), "SkyboxPassIdx"); - - // vertex_buffer->Write(i, 0, vtx_buf_view); - // index_buffer->Write(i, 0, idx_buf_view); - //} + const auto& skybox_vb_set = res_inspector->GetResource("SkyboxVbSet"); + const auto& skybox_ib_set = res_inspector->GetResource("SkyboxIbSet"); - auto& output_skybox = res_builder->CreateRenderTarget("skybox_render_target", {.Width = 1280, .Height = 780, .Format = ImageFormat::R8G8B8A8_UNORM}); RenderGraphRenderPassCreation pass_node = {.Name = name}; - pass_node.Inputs.init(device->Arena, 2); + pass_node.Inputs.init(device->Arena, 4); pass_node.Outputs.init(device->Arena, 1); + pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = skybox_vb_set.Name, .Type = skybox_vb_set.Type}); + pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = skybox_ib_set.Name, .Type = skybox_ib_set.Type}); pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameDepthRenderTargetName}); pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameColorRenderTargetName}); - pass_node.Outputs.push(RenderGraphRenderPassInputOutputInfo{.Name = output_skybox.Name}); res_builder->CreateRenderPassNode(pass_node); } @@ -293,7 +242,11 @@ namespace ZEngine::Rendering::Renderers .SetOffset(0, 0) .EnablePipelineDepthTest(true) .EnablePipelineDepthWrite(false) + .PipelineDepthCompareOp(2) + + .EnablePipelineBlending(false) + .SetCullMode(0) .UseShader("skybox") .Detach(); // clang-format off @@ -306,7 +259,7 @@ namespace ZEngine::Rendering::Renderers { (*output_pass)->SetInput("UBCamera", scene->SceneCameraBufferHandle); (*output_pass)->SetInput("EnvMap", m_env_map); - (*output_pass)->SetInput("LinearWrapSampler", device->GlobalLinearWrapSamplerImageInfo); + (*output_pass)->SetInput("LinearClampToEdgeSampler", device->GlobalLinearClampToEdgeSamplerImageInfo); } (*output_pass)->Verify(); @@ -339,40 +292,18 @@ namespace ZEngine::Rendering::Renderers { auto arena = device->Arena; - // m_index_data.init(arena, 6, make_initializer_list(arena, 0, 1, 2, 2, 3, 0)); - // m_vertex_data.init(arena, 12, make_initializer_list(arena, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f)); - - // m_vb_handle = device->CreateVertexBufferSet(); - // m_ib_handle = device->CreateIndexBufferSet(); - - // auto count = device->SwapchainPtr->BufferredFrameCount; - // auto vtx_buffer_set = device->VertexBufferSetManager.Access(m_vb_handle); - // auto idx_buffer_set = device->IndexBufferSetManager.Access(m_ib_handle); - - // auto vtx_buf_view = ArrayView{m_vertex_data}; - // auto idx_buf_view = ArrayView{m_index_data}; - - // for (int i = 0; i < count; ++i) - //{ - // auto vertex_buffer = vtx_buffer_set->At(i); - // auto index_buffer = idx_buffer_set->At(i); - - // vertex_buffer->Allocate(vtx_buf_view.size_bytes(), "GridPassVtx"); - // index_buffer->Allocate(idx_buf_view.size_bytes(), "GridPassIdx"); + const auto& grid_vb_set = res_inspector->GetResource("GridVbSet"); + const auto& grid_ib_set = res_inspector->GetResource("GridIbSet"); - // vertex_buffer->Write(i, 0, vtx_buf_view); - // index_buffer->Write(i, 0, idx_buf_view); - //} - - auto& output_grid = res_builder->CreateRenderTarget("grid_render_target", {.Width = 1280, .Height = 780, .Format = ImageFormat::R8G8B8A8_UNORM}); RenderGraphRenderPassCreation pass_node = {.Name = name}; - pass_node.Inputs.init(arena, 2); + pass_node.Inputs.init(arena, 4); pass_node.Outputs.init(arena, 1); + pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = grid_vb_set.Name, .Type = grid_vb_set.Type}); + pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = grid_ib_set.Name, .Type = grid_ib_set.Type}); pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameDepthRenderTargetName}); pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameColorRenderTargetName}); - pass_node.Outputs.push(RenderGraphRenderPassInputOutputInfo{.Name = output_grid.Name}); res_builder->CreateRenderPassNode(pass_node); } @@ -395,6 +326,12 @@ namespace ZEngine::Rendering::Renderers .SetOffset(0, 0) .EnablePipelineDepthTest(true) + .EnablePipelineDepthWrite(false) + .PipelineDepthCompareOp(3) + + .EnablePipelineBlending(true) + + .SetCullMode(0) .UseShader("infinite_grid") .Detach(); // clang-format off @@ -406,8 +343,8 @@ namespace ZEngine::Rendering::Renderers if (scene) { (*output_pass)->SetInput("UBCamera", scene->SceneCameraBufferHandle); - (*output_pass)->Verify(); } + (*output_pass)->Verify(); } void GridPass::Execute(Hardwares::VulkanDevicePtr const device, RenderGraphResourceInspectorPtr res_inspector, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPass* const pass, Buffers::FramebufferVNext* const framebuffer, Hardwares::CommandBufferPtr const command_buffer) @@ -455,7 +392,6 @@ namespace ZEngine::Rendering::Renderers pass_node.Outputs.init(device->Arena, 4); pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameDepthRenderTargetName}); - pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameColorRenderTargetName}); pass_node.Outputs.push({.Name = gbuffer_albedo.Name}); pass_node.Outputs.push({.Name = gbuffer_specular.Name}); @@ -600,4 +536,63 @@ namespace ZEngine::Rendering::Renderers // command_buffer->DrawIndirect(*indirect_buffer->At(scene->FrameIndex)); // command_buffer->EndRenderPass(); } + + void CompositePass::Setup(Hardwares::VulkanDevicePtr const device, cstring name, RenderGraphResourceBuilderPtr const res_builder, RenderGraphResourceInspectorPtr res_inspector) + { + auto arena = device->Arena; + + // auto& gbuffer_albedo = res_inspector->GetResource("gbuffer_albedo_render_target"); + // auto& gbuffer_specular = res_inspector->GetResource("gbuffer_specular_render_target"); + // auto& gbuffer_normals = res_inspector->GetResource("gbuffer_normals_render_target"); + // auto& gbuffer_position = res_inspector->GetResource("gbuffer_position_render_target"); + + RenderGraphRenderPassCreation pass_node = {.Name = name}; + + const auto& shared_rt = res_inspector->GetResource(RendererResourceName::FrameSharedRenderTargetName); + + pass_node.Inputs.init(arena, 3); + pass_node.Outputs.init(arena, 1); + + pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameDepthRenderTargetName}); + pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = shared_rt.Name, .BindingInputKeyName = "sharedRTAsTex", .Type = RenderGraphResourceType::TEXTURE}); + + // pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = gbuffer_albedo.Name}); + // pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = gbuffer_specular.Name}); + // pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = gbuffer_normals.Name}); + // pass_node.Inputs.push(RenderGraphRenderPassInputOutputInfo{.Name = gbuffer_position.Name}); + + pass_node.Outputs.push(RenderGraphRenderPassInputOutputInfo{.Name = RendererResourceName::FrameColorRenderTargetName}); + + res_builder->CreateRenderPassNode(pass_node); + } + + void CompositePass::Compile(Hardwares::VulkanDevicePtr const device, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPassBuilder* pass_builder, RenderGraphResourceInspectorPtr res_inspector, RenderPasses::RenderPass** const output_pass) + { + CHECK_AND_ESCAPE_NULL(output_pass) + + if (output_pass && !(*output_pass)) + { + auto pass_spec = pass_builder->SetPipelineName("Composite-Pipeline").SetInputBindingCount(0).EnablePipelineDepthTest(true).UseShader("composite").Detach(); + *output_pass = device->CreateRenderPass(pass_spec); + (*output_pass)->Bake(); + } + + (*output_pass)->SetInput("LinearWrapSampler", device->GlobalLinearWrapSamplerImageInfo); + (*output_pass)->Verify(); + } + + void CompositePass::Execute(Hardwares::VulkanDevicePtr const device, RenderGraphResourceInspectorPtr res_inspector, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPass* const pass, Buffers::FramebufferVNext* const framebuffer, Hardwares::CommandBufferPtr const command_buffer) + { + command_buffer->BeginRenderPass(pass, framebuffer->Handle, false); + { + uint32_t w = pass->GetRenderAreaWidth(); + uint32_t h = pass->GetRenderAreaHeight(); + command_buffer->SetViewport(w, h); + command_buffer->SetScissor(w, h); + } + command_buffer->BindPipeline(Specifications::PipelineBindPoint::GRAPHIC, pass->Pipeline); + command_buffer->BindDescriptorSets(device->SwapchainPtr->CurrentFrame->Index); + command_buffer->Draw(3, 1, 0, 0); + command_buffer->EndRenderPass(); + } } // namespace ZEngine::Rendering::Renderers diff --git a/ZEngine/ZEngine/Rendering/Renderers/RendererPasses.h b/ZEngine/ZEngine/Rendering/Renderers/RendererPasses.h index 3438674c..c65809bb 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/RendererPasses.h +++ b/ZEngine/ZEngine/Rendering/Renderers/RendererPasses.h @@ -33,14 +33,11 @@ namespace ZEngine::Rendering::Renderers virtual void Execute(Hardwares::VulkanDevicePtr const device, RenderGraphResourceInspectorPtr res_inspector, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPass* const pass, Buffers::FramebufferVNext* const framebuffer, Hardwares::CommandBufferPtr const command_buffer) override; }; - struct InitialPass : public IRenderGraphCallbackPass + struct BasePass : public IRenderGraphCallbackPass { - Core::Containers::Array VertexData = {}; - Hardwares::VertexBufferSetHandle VBHandle = {}; - - virtual void Setup(Hardwares::VulkanDevicePtr const device, cstring name, RenderGraphResourceBuilderPtr const res_builder, RenderGraphResourceInspectorPtr res_inspector) override; - virtual void Compile(Hardwares::VulkanDevicePtr const device, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPassBuilder* pass_builder, RenderGraphResourceInspectorPtr res_inspector, RenderPasses::RenderPass** const output_pass) override; - virtual void Execute(Hardwares::VulkanDevicePtr const device, RenderGraphResourceInspectorPtr res_inspector, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPass* const pass, Buffers::FramebufferVNext* const framebuffer, Hardwares::CommandBufferPtr const command_buffer) override; + virtual void Setup(Hardwares::VulkanDevicePtr const device, cstring name, RenderGraphResourceBuilderPtr const res_builder, RenderGraphResourceInspectorPtr res_inspector) override; + virtual void Compile(Hardwares::VulkanDevicePtr const device, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPassBuilder* pass_builder, RenderGraphResourceInspectorPtr res_inspector, RenderPasses::RenderPass** const output_pass) override; + virtual void Execute(Hardwares::VulkanDevicePtr const device, RenderGraphResourceInspectorPtr res_inspector, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPass* const pass, Buffers::FramebufferVNext* const framebuffer, Hardwares::CommandBufferPtr const command_buffer) override; }; struct DepthPrePass : public IRenderGraphCallbackPass @@ -81,4 +78,11 @@ namespace ZEngine::Rendering::Renderers virtual void Execute(Hardwares::VulkanDevicePtr const device, RenderGraphResourceInspectorPtr res_inspector, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPass* const pass, Buffers::FramebufferVNext* const framebuffer, Hardwares::CommandBufferPtr const command_buffer) override; }; + struct CompositePass : public IRenderGraphCallbackPass + { + virtual void Setup(Hardwares::VulkanDevicePtr const device, cstring name, RenderGraphResourceBuilderPtr const res_builder, RenderGraphResourceInspectorPtr res_inspector) override; + virtual void Compile(Hardwares::VulkanDevicePtr const device, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPassBuilder* pass_builder, RenderGraphResourceInspectorPtr res_inspector, RenderPasses::RenderPass** const output_pass) override; + virtual void Execute(Hardwares::VulkanDevicePtr const device, RenderGraphResourceInspectorPtr res_inspector, Rendering::Scenes::SceneDataPtr const scene, RenderPasses::RenderPass* const pass, Buffers::FramebufferVNext* const framebuffer, Hardwares::CommandBufferPtr const command_buffer) override; + }; + } // namespace ZEngine::Rendering::Renderers \ No newline at end of file diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp index eeb9de38..8f722359 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp @@ -518,7 +518,7 @@ namespace ZEngine::Rendering::Shaders */ if (pool_size_collection.empty()) { - ZENGINE_CORE_WARN("Shader: - The pool size is empty!") + ZENGINE_CORE_WARN("Shader '{0}': - The pool size is empty!", m_specification.Name) ZReleaseScratch(scratch); return; } diff --git a/ZEngine/ZEngine/Rendering/Specifications/GraphicRendererPipelineSpecification.h b/ZEngine/ZEngine/Rendering/Specifications/GraphicRendererPipelineSpecification.h index 6a81d431..639d8d39 100644 --- a/ZEngine/ZEngine/Rendering/Specifications/GraphicRendererPipelineSpecification.h +++ b/ZEngine/ZEngine/Rendering/Specifications/GraphicRendererPipelineSpecification.h @@ -26,9 +26,10 @@ namespace ZEngine::Rendering::Specifications bool EnableBlending = false; bool EnableDepthTest = false; bool EnableDepthWrite = true; - uint32_t DepthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; bool EnableStencilTest = false; const char* DebugName = {}; + uint32_t DepthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + uint32_t CullMode = 0; ShaderSpecification ShaderSpecificationValue = {}; Rendering::Buffers::FramebufferVNext* TargetFrameBuffer = {}; Renderers::RenderPasses::Attachment* Attachment = {}; diff --git a/ZEngine/ZEngine/Rendering/Specifications/RenderPassSpecification.h b/ZEngine/ZEngine/Rendering/Specifications/RenderPassSpecification.h index cdf823ba..13327935 100644 --- a/ZEngine/ZEngine/Rendering/Specifications/RenderPassSpecification.h +++ b/ZEngine/ZEngine/Rendering/Specifications/RenderPassSpecification.h @@ -7,10 +7,18 @@ namespace ZEngine::Rendering::Specifications { + enum class RenderPassType + { + GRAPHIC, + COMPUTE, + TRANSFER + }; + struct RenderPassSpecification { const char* DebugName = {}; bool SwapchainAsRenderTarget = false; + RenderPassType Type = {RenderPassType::GRAPHIC}; Specifications::GraphicRendererPipelineSpecification PipelineSpecification = {}; Core::Containers::Array Inputs = {}; Core::Containers::UnorderedHashMap InputTextures = {}; diff --git a/ZEngine/ZEngine/Windows/Events/MouseEvent.h b/ZEngine/ZEngine/Windows/Events/MouseEvent.h index ab58ce3c..e2f05b89 100644 --- a/ZEngine/ZEngine/Windows/Events/MouseEvent.h +++ b/ZEngine/ZEngine/Windows/Events/MouseEvent.h @@ -73,7 +73,7 @@ namespace ZEngine::Windows::Events class MouseButtonMovedEvent : public MouseEvent { public: - MouseButtonMovedEvent(double xpos, double ypos) : m_xpos(xpos), m_ypos(ypos) {} + MouseButtonMovedEvent(double xpos, double ypos, double xoffset, double yoffset) : m_xpos(xpos), m_ypos(ypos), m_xoffset(xoffset), m_yoffset(yoffset) {} double GetPosX() const { @@ -85,6 +85,16 @@ namespace ZEngine::Windows::Events return m_ypos; } + double GetXOffset() const + { + return m_xoffset; + } + + double GetYOffset() const + { + return m_yoffset; + } + EVENT_TYPE(MouseMoved) virtual Core::EventType GetType() const override @@ -105,6 +115,8 @@ namespace ZEngine::Windows::Events private: double m_xpos{0}; double m_ypos{0}; + double m_xoffset{0}; + double m_yoffset{0}; }; class MouseButtonWheelEvent : public MouseEvent diff --git a/ZEngine/ZEngine/Windows/GameWindow.cpp b/ZEngine/ZEngine/Windows/GameWindow.cpp index de53341f..fed7e14b 100644 --- a/ZEngine/ZEngine/Windows/GameWindow.cpp +++ b/ZEngine/ZEngine/Windows/GameWindow.cpp @@ -280,12 +280,17 @@ namespace ZEngine::Windows } } - void GameWindow::__OnGlfwCursorMoved(GLFWwindow* window, double xoffset, double yoffset) + void GameWindow::__OnGlfwCursorMoved(GLFWwindow* window, double xpos, double ypos) { + static double lastX = 0, lastY = 0; // Initial center WindowProperty* property = reinterpret_cast(glfwGetWindowUserPointer(window)); if (property) { - MouseButtonMovedEvent e{xoffset, yoffset}; + double xoffset = (xpos - lastX); + double yoffset = (ypos - lastY); + lastX = xpos; + lastY = ypos; + MouseButtonMovedEvent e{xpos, ypos, xoffset, yoffset}; property->CallbackFn(e); } } diff --git a/ZEngine/tests/CMakeLists.txt b/ZEngine/tests/CMakeLists.txt index 6e1b3a12..b1899149 100644 --- a/ZEngine/tests/CMakeLists.txt +++ b/ZEngine/tests/CMakeLists.txt @@ -18,6 +18,13 @@ set_target_properties(ZEngineTests PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREF install(TARGETS ZEngineTests RUNTIME DESTINATION tests) +if(APPLE) + add_custom_command(TARGET ZEngineTests POST_BUILD + COMMAND codesign --force --sign - $ + COMMENT "Ad-hoc signing ZEngineTests" + ) +endif() + if(BUILD_TESTING) include(GoogleTest) gtest_discover_tests(ZEngineTests)