From 242cdacf2b0beb6a93a3a77796e0689960aaf1ad Mon Sep 17 00:00:00 2001 From: Nanako <469449812@qq.com> Date: Fri, 8 Nov 2024 18:20:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=86=E8=A7=92=E7=9F=A9=E5=BD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/CMakeLists.txt | 14 +- src/renderer/backend/dx/dx_renderer.cpp | 24 +++ src/renderer/backend/dx/dx_renderer.h | 6 + src/renderer/backend/dx/dx_window.cpp | 17 +- .../dx/pipeline/dx_sdf_text_pipeline.cpp | 27 ++++ .../dx/pipeline/dx_sdf_text_pipeline.h | 16 ++ .../dx/pipeline/dx_segment_pipeline.cpp | 34 ++++ .../backend/dx/pipeline/dx_segment_pipeline.h | 12 ++ .../core/pipeline/rounded_rect_pipeline.h | 5 +- .../core/pipeline/sdf_text_pipeline.cpp | 22 +++ .../core/pipeline/sdf_text_pipeline.h | 28 ++++ .../core/pipeline/segment_pipeline.cpp | 17 ++ src/renderer/core/pipeline/segment_pipeline.h | 19 +++ src/renderer/core/renderer/renderer.h | 4 + .../core/renderer/renderer_context.cpp | 151 ++++++++++++------ src/renderer/core/renderer/renderer_context.h | 17 +- src/renderer/core/window/renderer_window.cpp | 24 +-- src/renderer/core/window/renderer_window.h | 2 +- src/renderer/shader/aorii_rounded_rect.slang | 49 +++--- src/renderer/shader/aorii_sdf_text.slang | 56 +++++++ src/renderer/shader/aorii_segment.slang | 50 ++++++ 21 files changed, 479 insertions(+), 115 deletions(-) create mode 100644 src/renderer/backend/dx/pipeline/dx_sdf_text_pipeline.cpp create mode 100644 src/renderer/backend/dx/pipeline/dx_sdf_text_pipeline.h create mode 100644 src/renderer/backend/dx/pipeline/dx_segment_pipeline.cpp create mode 100644 src/renderer/backend/dx/pipeline/dx_segment_pipeline.h create mode 100644 src/renderer/core/pipeline/sdf_text_pipeline.cpp create mode 100644 src/renderer/core/pipeline/sdf_text_pipeline.h create mode 100644 src/renderer/core/pipeline/segment_pipeline.cpp create mode 100644 src/renderer/core/pipeline/segment_pipeline.h create mode 100644 src/renderer/shader/aorii_sdf_text.slang create mode 100644 src/renderer/shader/aorii_segment.slang diff --git a/src/renderer/CMakeLists.txt b/src/renderer/CMakeLists.txt index d20b11b..8542647 100644 --- a/src/renderer/CMakeLists.txt +++ b/src/renderer/CMakeLists.txt @@ -59,12 +59,14 @@ if (NOT DEFINED SHADER_OUTPUT_DIR) set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/shaders CACHE PATH "Output directory for compiled shaders") message(STATUS "SHADER_OUTPUT_DIR not defined, using default: ${SHADER_OUTPUT_DIR}") endif () -compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_rect.slang" "vertex" "vertex_main") -compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_rect.slang" "pixel" "pixel_main") -compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_rounded_rect.slang" "vertex" "vertex_main") -compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_rounded_rect.slang" "pixel" "pixel_main") -compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_texture.slang" "vertex" "vertex_main") -compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_texture.slang" "pixel" "pixel_main") +function(compile_aorii_shader SHADER_FILE) + compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/${SHADER_FILE}.slang" "vertex" "vertex_main") + compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/${SHADER_FILE}.slang" "pixel" "pixel_main") +endfunction() +compile_aorii_shader(aorii_rect) +compile_aorii_shader(aorii_rounded_rect) +compile_aorii_shader(aorii_texture) +compile_aorii_shader(aorii_segment) add_compile_shaders_target("compile_aorii_shaders" ${PROJECT_NAME}) # 如果需要编译example, 添加自定义命令用于拷贝shader文件 diff --git a/src/renderer/backend/dx/dx_renderer.cpp b/src/renderer/backend/dx/dx_renderer.cpp index 5359ea9..9e64088 100644 --- a/src/renderer/backend/dx/dx_renderer.cpp +++ b/src/renderer/backend/dx/dx_renderer.cpp @@ -34,6 +34,7 @@ bool dx_renderer::init() { rect_p.init(); rounded_rect_p.init(); texture_p.init(); + segment_p.init(); return true; } @@ -59,6 +60,29 @@ renderer_texture* dx_renderer::create_texture(const Eigen::Vector2i& size, textu return new dx_texture(size, in_format); } +Eigen::Matrix4f dx_renderer::make_projection_matrix(const Eigen::Vector2i& size) { + // 创建一个单位矩阵 + Eigen::Matrix4f matrix = Eigen::Matrix4f::Identity(); + + // 缩放因子 + const float scale_x = 2.0f / static_cast(size.x()); + const float scale_y = -2.0f / static_cast(size.y()); // Y轴翻转,因为窗口坐标系Y轴向下 + + // 平移因子 + constexpr float translate_x = -1.0f; + constexpr float translate_y = 1.0f; + + // 设置缩放 + matrix(0, 0) = scale_x; + matrix(1, 1) = scale_y; + + // 设置平移 + matrix(0, 3) = translate_x; + matrix(1, 3) = translate_y; + + return matrix; +} + std::vector dx_renderer::load_shader(const std::string& shader_name) { auto file_pathname = aorii::get_shader_path(shader_name).generic_string() + ".dxbc"; std::ifstream file(file_pathname, std::ios::binary); diff --git a/src/renderer/backend/dx/dx_renderer.h b/src/renderer/backend/dx/dx_renderer.h index 10f090f..4e84ea0 100644 --- a/src/renderer/backend/dx/dx_renderer.h +++ b/src/renderer/backend/dx/dx_renderer.h @@ -4,6 +4,7 @@ #include "core/renderer/renderer.h" #include "pipeline/dx_rect_pipeline.h" #include "pipeline/dx_rounded_rect_pipeline.h" +#include "pipeline/dx_segment_pipeline.h" #include "pipeline/dx_texture_pipeline.h" class dx_window; @@ -22,6 +23,10 @@ public: rect_pipeline* get_rect_pipeline() override { return &rect_p; } rounded_rect_pipeline* get_rounded_rect_pipeline() override { return &rounded_rect_p; } texture_pipeline* get_texture_pipeline() override { return &texture_p; } + segment_pipeline* get_segment_pipeline() override { return &segment_p; } + + Eigen::Matrix4f make_projection_matrix(const Eigen::Vector2i& size) override; + [[nodiscard]] ID3D11BlendState* get_blend_state() const { return blend_state; } std::vector load_shader(const std::string& shader_name) override; @@ -39,6 +44,7 @@ private: dx_rect_pipeline rect_p; dx_rounded_rect_pipeline rounded_rect_p; dx_texture_pipeline texture_p; + dx_segment_pipeline segment_p; }; inline DXGI_FORMAT get_dxgi_format(texture_format format) { diff --git a/src/renderer/backend/dx/dx_window.cpp b/src/renderer/backend/dx/dx_window.cpp index 6b4fb47..fa2c7d3 100644 --- a/src/renderer/backend/dx/dx_window.cpp +++ b/src/renderer/backend/dx/dx_window.cpp @@ -8,6 +8,7 @@ using namespace aorii; +static float thickness = 1.f; bool dx_window::create_surface(GLFWwindow* in_window) { auto dx = aorii::get_renderer(); const auto d3d_device = dx->get_d3d_device(); @@ -69,6 +70,9 @@ bool dx_window::create_surface(GLFWwindow* in_window) { } test_texture = dx->load_image(R"(D:\69054578_p0.jpg)", texture_format::RGBA8_UNORM); + glfwSetScrollCallback(get_glfw_window(), [](GLFWwindow* window, double xoffset, double yoffset) { + thickness += yoffset; + }); return true; } @@ -80,16 +84,19 @@ void dx_window::begin_frame() { d3d_context->OMSetRenderTargets(1, &render_target_view, nullptr); d3d_context->OMSetBlendState(render->get_blend_state(), nullptr, 0xffffffff); d3d_context->ClearRenderTargetView(render_target_view, clear_color); - context.set_projection_matrix(projection_matrix); + context.set_projection_matrix(projection_matrix, get_framebuffer_size()); context.draw_rectangle({ 400, 0 }, { 100, 100 }, { 0, 1, 0, 1 }); auto radius = abs(sin(get_total_time().count())) * 50; - context.draw_rounded_rectangle({ 100, 100 }, { 200, 200 }, { 1, 0, 0, 1 }, radius); + auto angle = sin(get_total_time().count() * 0.001) * 45; + context.draw_rounded_rectangle({ 100, 100 }, { 200, 400 }, { 1, 0, 0, 1 }, angle, 10); - auto height = sin(get_total_time().count()) * 100; - context.draw_line({ 600, 600 - height }, { 700, 600 + height }, { 0, 0, 1, 1 }, 0.5); + double mouse_x, mouse_y; + glfwGetCursorPos(get_glfw_window(), &mouse_x, &mouse_y); + // auto height = sin(get_total_time().count()) * 100; + context.draw_line( { 600, 600 }, { mouse_x, mouse_y }, { 1, 0, 1, 1 }, thickness); - if (test_texture) context.draw_texture({ 0, 0 }, test_texture->size(), test_texture); + // if (test_texture) context.draw_texture({ 0, 0 }, test_texture->size(), test_texture); context.flush(); diff --git a/src/renderer/backend/dx/pipeline/dx_sdf_text_pipeline.cpp b/src/renderer/backend/dx/pipeline/dx_sdf_text_pipeline.cpp new file mode 100644 index 0000000..0b34aef --- /dev/null +++ b/src/renderer/backend/dx/pipeline/dx_sdf_text_pipeline.cpp @@ -0,0 +1,27 @@ +#include "dx_sdf_text_pipeline.h" + +#include "backend/dx/dx_renderer.h" + +bool dx_sdf_text_pipeline::init() { + sdf_text_pipeline::init(); + loader.load("aorii_sdf_text_vertex_main", "aorii_sdf_text_pixel_main"); + return true; +} + +void dx_sdf_text_pipeline::use() { + loader.use(); +} + +void dx_sdf_text_pipeline::draw() { + const auto d3d_context = aorii::get_renderer()->get_d3d_context(); + + // 绘制 + d3d_context->DrawIndexed(index_buffer->get_size(), 0, 0); + d3d_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); +} + +void dx_sdf_text_pipeline::set_param(const param& in_param) { sdf_text_pipeline::set_param(in_param); } + +void dx_sdf_text_pipeline::set_sdf_font_param(const sdf_font_param& in_param) { + sdf_text_pipeline::set_sdf_font_param(in_param); +} diff --git a/src/renderer/backend/dx/pipeline/dx_sdf_text_pipeline.h b/src/renderer/backend/dx/pipeline/dx_sdf_text_pipeline.h new file mode 100644 index 0000000..e94795c --- /dev/null +++ b/src/renderer/backend/dx/pipeline/dx_sdf_text_pipeline.h @@ -0,0 +1,16 @@ +#pragma once +#include "dx_pipeline_loader.h" +#include "core/pipeline/sdf_text_pipeline.h" + +class dx_sdf_text_pipeline : public sdf_text_pipeline { +public: + bool init() override; + + void use() override; + void draw() override; + + void set_param(const param& in_param) override; + void set_sdf_font_param(const sdf_font_param& in_param) override; +private: + dx_pipeline_loader loader; +}; diff --git a/src/renderer/backend/dx/pipeline/dx_segment_pipeline.cpp b/src/renderer/backend/dx/pipeline/dx_segment_pipeline.cpp new file mode 100644 index 0000000..4716757 --- /dev/null +++ b/src/renderer/backend/dx/pipeline/dx_segment_pipeline.cpp @@ -0,0 +1,34 @@ +#include "dx_segment_pipeline.h" + +#include "backend/dx/dx_renderer.h" + +bool dx_segment_pipeline::init() { + segment_pipeline::init(); + loader.load("aorii_segment_vertex_main", "aorii_segment_pixel_main"); + return true; +} + +void dx_segment_pipeline::use() { + loader.use(); +} + +void dx_segment_pipeline::draw() { + const auto d3d_context = aorii::get_renderer()->get_d3d_context(); + + // 设置顶点缓冲区 + constexpr UINT stride = sizeof(aorii_vertex); + constexpr UINT offset = 0; + auto* v_buffer = static_cast(vertex_buffer->get_native_handle()); + auto* i_buffer = static_cast(index_buffer->get_native_handle()); + auto* c_buffer = static_cast(param_buffer->get_native_handle()); + d3d_context->IASetVertexBuffers(0, 1, &v_buffer, &stride, &offset); + d3d_context->IASetIndexBuffer(i_buffer, DXGI_FORMAT_R32_UINT, 0); + d3d_context->VSSetConstantBuffers(0, 1, &c_buffer); + d3d_context->PSSetConstantBuffers(0, 1, &c_buffer); + + // 设置图元拓扑 + d3d_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + // 绘制矩形 + d3d_context->Draw(vertex_buffer->get_size(), 0); +} diff --git a/src/renderer/backend/dx/pipeline/dx_segment_pipeline.h b/src/renderer/backend/dx/pipeline/dx_segment_pipeline.h new file mode 100644 index 0000000..ae2f659 --- /dev/null +++ b/src/renderer/backend/dx/pipeline/dx_segment_pipeline.h @@ -0,0 +1,12 @@ +#pragma once +#include "dx_pipeline_loader.h" +#include "core/pipeline/segment_pipeline.h" + +class dx_segment_pipeline : public segment_pipeline { +public: + bool init() override; + void use() override; + void draw() override; +private: + dx_pipeline_loader loader; +}; diff --git a/src/renderer/core/pipeline/rounded_rect_pipeline.h b/src/renderer/core/pipeline/rounded_rect_pipeline.h index 083260c..b4f481d 100644 --- a/src/renderer/core/pipeline/rounded_rect_pipeline.h +++ b/src/renderer/core/pipeline/rounded_rect_pipeline.h @@ -5,9 +5,10 @@ class rounded_rect_pipeline : public pipeline { public: struct param { Eigen::Matrix4f projection_matrix; - Eigen::Vector2f pos; - Eigen::Vector2f size; + Eigen::Vector2f p1; + Eigen::Vector2f p2; float radius; + float thickness; }; bool init() override; diff --git a/src/renderer/core/pipeline/sdf_text_pipeline.cpp b/src/renderer/core/pipeline/sdf_text_pipeline.cpp new file mode 100644 index 0000000..c869059 --- /dev/null +++ b/src/renderer/core/pipeline/sdf_text_pipeline.cpp @@ -0,0 +1,22 @@ +#include "sdf_text_pipeline.h" + +#include "core/renderer/renderer.h" + +bool sdf_text_pipeline::init() { + param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::constant, sizeof(param), 1); + sdf_font_param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::constant, sizeof(sdf_font_param), 1); + return pipeline::init(); +} +void sdf_text_pipeline::destroy() { + pipeline::destroy(); + aorii::get_renderer_raw()->destroy_buffer(param_buffer); + aorii::get_renderer_raw()->destroy_buffer(sdf_font_param_buffer); +} + +void sdf_text_pipeline::set_param(const param& in_param) { + param_buffer->set_data(in_param); +} + +void sdf_text_pipeline::set_sdf_font_param(const sdf_font_param& in_param) { + sdf_font_param_buffer->set_data(in_param); +} diff --git a/src/renderer/core/pipeline/sdf_text_pipeline.h b/src/renderer/core/pipeline/sdf_text_pipeline.h new file mode 100644 index 0000000..00efd54 --- /dev/null +++ b/src/renderer/core/pipeline/sdf_text_pipeline.h @@ -0,0 +1,28 @@ +#pragma once +#include + +#include "pipeline.h" +#include +#include FT_FREETYPE_H +#include + +class sdf_text_pipeline : public pipeline { +public: + struct param { + Eigen::Matrix4f projection_matrix; + }; // b0 + struct sdf_font_param { + float smoothing; + float thickness; + float outline_width; + linear_color outline_color; + }; // b1 + bool init() override; + void destroy() override; + + virtual void set_param(const param& in_param); + virtual void set_sdf_font_param(const sdf_font_param& in_param); +private: + renderer_buffer* param_buffer = nullptr; + renderer_buffer* sdf_font_param_buffer = nullptr; +}; diff --git a/src/renderer/core/pipeline/segment_pipeline.cpp b/src/renderer/core/pipeline/segment_pipeline.cpp new file mode 100644 index 0000000..398f8ed --- /dev/null +++ b/src/renderer/core/pipeline/segment_pipeline.cpp @@ -0,0 +1,17 @@ +#include "segment_pipeline.h" + +#include "core/renderer/renderer.h" + +bool segment_pipeline::init() { + pipeline::init(); + param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::constant, sizeof(param), 1); + return true; +} +void segment_pipeline::destroy() { + aorii::get_renderer_raw()->destroy_buffer(param_buffer); + pipeline::destroy(); +} + +void segment_pipeline::set_param(const param& in_param) { + param_buffer->set_data(in_param); +} diff --git a/src/renderer/core/pipeline/segment_pipeline.h b/src/renderer/core/pipeline/segment_pipeline.h new file mode 100644 index 0000000..ddd0596 --- /dev/null +++ b/src/renderer/core/pipeline/segment_pipeline.h @@ -0,0 +1,19 @@ +#pragma once +#include "pipeline.h" + +class segment_pipeline : public pipeline { +public: + struct param { + Eigen::Matrix4f projection_matrix; + Eigen::Vector2f point_a; + Eigen::Vector2f point_b; + float thickness; + }; + + bool init() override; + void destroy() override; + + void set_param(const param& in_param); +protected: + renderer_buffer* param_buffer = nullptr; +}; diff --git a/src/renderer/core/renderer/renderer.h b/src/renderer/core/renderer/renderer.h index d67e6da..3d8a346 100644 --- a/src/renderer/core/renderer/renderer.h +++ b/src/renderer/core/renderer/renderer.h @@ -6,6 +6,7 @@ #include "renderer_buffer.h" #include "core/pipeline/pipeline.h" +class segment_pipeline; class texture_pipeline; class rounded_rect_pipeline; class rect_pipeline; @@ -241,6 +242,9 @@ public: virtual rect_pipeline* get_rect_pipeline() = 0; virtual rounded_rect_pipeline* get_rounded_rect_pipeline() = 0; virtual texture_pipeline* get_texture_pipeline() = 0; + virtual segment_pipeline* get_segment_pipeline() = 0; + + virtual Eigen::Matrix4f make_projection_matrix(const Eigen::Vector2i& size) = 0; private: virtual renderer_window* create_window() = 0; virtual void destroy_window(renderer_window* window); diff --git a/src/renderer/core/renderer/renderer_context.cpp b/src/renderer/core/renderer/renderer_context.cpp index 0b9b002..2022918 100644 --- a/src/renderer/core/renderer/renderer_context.cpp +++ b/src/renderer/core/renderer/renderer_context.cpp @@ -6,54 +6,34 @@ void renderer_context::init() { } -void renderer_context::draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color) { +void renderer_context::draw_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color) { to_rect_pipeline(); make_rect(in_pos, in_size, in_color); } -void renderer_context::draw_rounded_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color, float in_radius) { - to_rounded_rect_pipeline(in_pos, in_size, in_radius); - make_rect(in_pos, in_size, in_color); +void renderer_context::draw_rounded_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color, float in_angle, float in_radius) { + to_rounded_rect_pipeline(in_pos, in_size, in_angle, in_radius); + + make_rect(in_pos, in_size, in_color, in_angle); // 立刻绘制并重置管线, 因为下一个绘制命令的参数可能不同, 所以无法合批 flush(); } -void renderer_context::draw_line(const Eigen::Vector2i& in_pos_p1, const Eigen::Vector2i& in_pos_p2, const linear_color& in_color, float in_thickness) { - to_rect_pipeline(); - const Eigen::Vector2f direction = (in_pos_p2 - in_pos_p1).cast().normalized(); - const Eigen::Vector2f normal = { -direction.y(), direction.x() }; - const Eigen::Vector2f offset = normal * in_thickness; +void renderer_context::draw_line(const Eigen::Vector2f& in_pos_p1, const Eigen::Vector2f& in_pos_p2, const linear_color& in_color, float in_thickness) { - const aorii_vertex v1{ { in_pos_p1.x() + offset.x(), in_pos_p1.y() + offset.y() }, { 0, 0 }, in_color }; - const aorii_vertex v2{ { in_pos_p1.x() - offset.x(), in_pos_p1.y() - offset.y() }, { 1, 0 }, in_color }; - const aorii_vertex v3{ { in_pos_p2.x() + offset.x(), in_pos_p2.y() + offset.y() }, { 0, 1 }, in_color }; - const aorii_vertex v4{ { in_pos_p2.x() - offset.x(), in_pos_p2.y() - offset.y() }, { 1, 1 }, in_color }; - - const uint32_t index1 = vertices.size(); - vertices.push_back(v1); - const uint32_t index2 = vertices.size(); - vertices.push_back(v2); - const uint32_t index3 = vertices.size(); - vertices.push_back(v3); - const uint32_t index4 = vertices.size(); - vertices.push_back(v4); - - const aorii_triangle t1 = { index1, index2, index3 }; - const aorii_triangle t2 = { index2, index3, index4 }; - triangles.push_back(t1); - triangles.push_back(t2); } -void renderer_context::draw_texture(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, - renderer_texture* in_texture, const linear_color& in_color) { +void renderer_context::draw_texture(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, + renderer_texture* in_texture, const linear_color& in_color) { to_texture_pipeline(in_texture); make_rect(in_pos, in_size, in_color); // 立刻绘制并重置管线, 因为下一个绘制命令的参数可能不同, 所以无法合批 flush(); } -void renderer_context::set_projection_matrix(const Eigen::Matrix4f& in_matrix) { +void renderer_context::set_projection_matrix(const Eigen::Matrix4f& in_matrix, const Eigen::Vector2i& in_framebuffer_size) { projection_matrix = in_matrix; + framebuffer_size = in_framebuffer_size; // 更新默认管线的投影矩阵 const auto rect_p = aorii::get_renderer()->get_rect_pipeline(); @@ -63,6 +43,7 @@ void renderer_context::set_projection_matrix(const Eigen::Matrix4f& in_matrix) { texture_p->set_param({ in_matrix }); // 圆角矩形管线的投影矩阵不需要更新, 因为它在每次绘制时都会更新 + // 线段管线的投影矩阵不需要更新, 因为它在每次绘制时都会更新 } void renderer_context::to_rect_pipeline() { @@ -70,14 +51,32 @@ void renderer_context::to_rect_pipeline() { switch_pipeline(rect_p); } -void renderer_context::to_rounded_rect_pipeline(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, float in_radius) { +void renderer_context::to_rounded_rect_pipeline(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, float in_angle, float in_radius) { const auto rounded_rect_p = aorii::get_renderer()->get_rounded_rect_pipeline(); switch_pipeline(rounded_rect_p); + + Eigen::Vector2f top_middle = in_pos + Eigen::Vector2f(in_size.x() / 2, 0); + Eigen::Vector2f bottom_middle = in_pos + Eigen::Vector2f(in_size.x() / 2, in_size.y()); + + // 如果角度不为0, 则需要计算旋转后的坐标 + if (in_angle != 0) { + // 将top_middle和bottom_middle绕盒子中心旋转 + const Eigen::Vector2f& center = in_pos + in_size / 2; + Eigen::Affine2f transform = + Eigen::Translation(center) * // 平移到旋转中心 + Eigen::Rotation2D(in_angle) * // 旋转 + Eigen::Translation(-center); // 平移回原点 + + top_middle = transform * top_middle; + bottom_middle = transform * bottom_middle; + } + rounded_rect_pipeline::param param; param.projection_matrix = projection_matrix; - param.pos = in_pos.cast(); - param.size = in_size.cast(); + param.p1 = top_middle; + param.p2 = bottom_middle; param.radius = in_radius; + param.thickness = in_size.x(); rounded_rect_p->set_param(param); } @@ -87,24 +86,72 @@ void renderer_context::to_texture_pipeline(renderer_texture* in_texture) { texture_p->set_texture(in_texture); } -void renderer_context::make_rect(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, - const linear_color& in_color) { - const aorii_vertex v1{ { in_pos.x(), in_pos.y() }, { 0, 0 }, in_color }; // 左上角 - const aorii_vertex v2{ { in_pos.x() + in_size.x(), in_pos.y() }, { 1, 0 }, in_color }; // 右上角 - const aorii_vertex v3{ { in_pos.x(), in_pos.y() + in_size.y() }, { 0, 1 }, in_color }; // 左下角 - const aorii_vertex v4{ { in_pos.x() + in_size.x(), in_pos.y() + in_size.y() }, { 1, 1 }, in_color }; // 右下角 +void renderer_context::to_segment_pipeline(const Eigen::Vector2f& in_pos_p1, const Eigen::Vector2f& in_pos_p2, float in_thickness) { + const auto segment_p = aorii::get_renderer()->get_segment_pipeline(); + switch_pipeline(segment_p); - const uint32_t index1 = vertices.size(); - vertices.push_back(v1); - const uint32_t index2 = vertices.size(); - vertices.push_back(v2); - const uint32_t index3 = vertices.size(); - vertices.push_back(v3); - const uint32_t index4 = vertices.size(); - vertices.push_back(v4); - - const aorii_triangle t1 = { index1, index2, index3 }; - const aorii_triangle t2 = { index2, index3, index4 }; - triangles.push_back(t1); - triangles.push_back(t2); + segment_pipeline::param param; + param.projection_matrix = projection_matrix; + param.point_a = in_pos_p1; + param.point_b = in_pos_p2; + param.thickness = in_thickness; + segment_p->set_param(param); +} + +void renderer_context::make_rect(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, + const linear_color& in_color, float in_angle) { + // 如果角度不为0, 则需要计算旋转后的坐标 + if (in_angle != 0) { + // 绕盒子中心旋转 + // 创建仿射变换矩阵(先平移,后旋转,再平移回去) + const Eigen::Vector2f& center = in_pos + in_size / 2; + Eigen::Affine2f transform = + Eigen::Translation(center) * // 平移到旋转中心 + Eigen::Rotation2D(in_angle) * // 旋转 + Eigen::Translation(-center); // 平移回原点 + + const Eigen::Vector2f top_left = transform * in_pos; + const Eigen::Vector2f top_right = transform * Eigen::Vector2f(in_pos.x() + in_size.x(), in_pos.y()); + const Eigen::Vector2f bottom_left = transform * Eigen::Vector2f(in_pos.x(), in_pos.y() + in_size.y()); + const Eigen::Vector2f bottom_right = transform * (in_pos + in_size); + + const aorii_vertex v1{ { top_left.x(), top_left.y() }, { 0, 0 }, in_color }; // 左上角 + const aorii_vertex v2{ { top_right.x(), top_right.y() }, { 1, 0 }, in_color }; // 右上角 + const aorii_vertex v3{ { bottom_left.x(), bottom_left.y() }, { 0, 1 }, in_color }; // 左下角 + const aorii_vertex v4{ { bottom_right.x(), bottom_right.y() }, { 1, 1 }, in_color }; // 右下角 + + const uint32_t index1 = vertices.size(); + vertices.push_back(v1); + const uint32_t index2 = vertices.size(); + vertices.push_back(v2); + const uint32_t index3 = vertices.size(); + vertices.push_back(v3); + const uint32_t index4 = vertices.size(); + vertices.push_back(v4); + + const aorii_triangle t1 = { index1, index2, index3 }; + const aorii_triangle t2 = { index2, index3, index4 }; + triangles.push_back(t1); + triangles.push_back(t2); + } + else { + const aorii_vertex v1{ { in_pos.x(), in_pos.y() }, { 0, 0 }, in_color }; // 左上角 + const aorii_vertex v2{ { in_pos.x() + in_size.x(), in_pos.y() }, { 1, 0 }, in_color }; // 右上角 + const aorii_vertex v3{ { in_pos.x(), in_pos.y() + in_size.y() }, { 0, 1 }, in_color }; // 左下角 + const aorii_vertex v4{ { in_pos.x() + in_size.x(), in_pos.y() + in_size.y() }, { 1, 1 }, in_color }; // 右下角 + + const uint32_t index1 = vertices.size(); + vertices.push_back(v1); + const uint32_t index2 = vertices.size(); + vertices.push_back(v2); + const uint32_t index3 = vertices.size(); + vertices.push_back(v3); + const uint32_t index4 = vertices.size(); + vertices.push_back(v4); + + const aorii_triangle t1 = { index1, index2, index3 }; + const aorii_triangle t2 = { index2, index3, index4 }; + triangles.push_back(t1); + triangles.push_back(t2); + } } diff --git a/src/renderer/core/renderer/renderer_context.h b/src/renderer/core/renderer/renderer_context.h index af88cb3..90d327d 100644 --- a/src/renderer/core/renderer/renderer_context.h +++ b/src/renderer/core/renderer/renderer_context.h @@ -16,16 +16,17 @@ public: * @param in_size 绘制的大小(受控件缩放影响) * @param in_color 绘制的颜色 */ - void draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color); + void draw_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color); /** * 绘制一个实心圆角矩形 * @param in_pos 当前控件坐标系的位置 * @param in_size 绘制的大小(受控件缩放影响) * @param in_color 绘制的颜色 + * @param in_angle * @param in_radius 圆角半径(像素) */ - void draw_rounded_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color, float in_radius); + void draw_rounded_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color, float in_angle, float in_radius); /** * 绘制一条线 @@ -34,7 +35,7 @@ public: * @param in_color 线颜色 * @param in_thickness 线宽度(像素), 当宽度为0时, 按照最小线宽度绘制 */ - void draw_line(const Eigen::Vector2i& in_pos_p1, const Eigen::Vector2i& in_pos_p2, const linear_color& in_color, float in_thickness); + void draw_line(const Eigen::Vector2f& in_pos_p1, const Eigen::Vector2f& in_pos_p2, const linear_color& in_color, float in_thickness); /** * 绘制一个纹理 @@ -42,7 +43,7 @@ public: * @param in_size 绘制的大小(受控件缩放影响) * @param in_texture 纹理 */ - void draw_texture(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, renderer_texture* in_texture, const linear_color& in_color = linear_color::white); + void draw_texture(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, renderer_texture* in_texture, const linear_color& in_color = linear_color::white); void clear() { vertices.clear(); @@ -63,7 +64,7 @@ public: } clear(); } - void set_projection_matrix(const Eigen::Matrix4f& in_matrix); + void set_projection_matrix(const Eigen::Matrix4f& in_matrix, const Eigen::Vector2i& in_framebuffer_size); protected: void switch_pipeline(pipeline* in_pipeline) { @@ -79,14 +80,16 @@ protected: } void to_rect_pipeline(); - void to_rounded_rect_pipeline(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, float in_radius); + void to_rounded_rect_pipeline(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, float in_angle, float in_radius); void to_texture_pipeline(renderer_texture* in_texture); + void to_segment_pipeline(const Eigen::Vector2f& in_pos_p1, const Eigen::Vector2f& in_pos_p2, float in_thickness); private: std::vector vertices; std::vector triangles; pipeline* current_pipeline = nullptr; Eigen::Matrix4f projection_matrix; + Eigen::Vector2i framebuffer_size; private: - void make_rect(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color); + void make_rect(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color, float in_angle = 0); }; diff --git a/src/renderer/core/window/renderer_window.cpp b/src/renderer/core/window/renderer_window.cpp index 8218afe..865eff4 100644 --- a/src/renderer/core/window/renderer_window.cpp +++ b/src/renderer/core/window/renderer_window.cpp @@ -1,4 +1,6 @@ #include "renderer_window.h" + +#include "core/renderer/renderer.h" #include "GLFW/glfw3native.h" renderer_window::~renderer_window() { if (window) glfwDestroyWindow(window); } @@ -10,27 +12,7 @@ bool renderer_window::init(const Eigen::Vector2i& in_size, const std::string& in } Eigen::Matrix4f renderer_window::get_projection_matrix() const { - // 创建一个单位矩阵 - Eigen::Matrix4f matrix = Eigen::Matrix4f::Identity(); - const auto& window_size = get_window_size(); - - // 缩放因子 - const float scale_x = 2.0f / static_cast(window_size.x()); - const float scale_y = -2.0f / static_cast(window_size.y()); // Y轴翻转,因为窗口坐标系Y轴向下 - - // 平移因子 - constexpr float translate_x = -1.0f; - constexpr float translate_y = 1.0f; - - // 设置缩放 - matrix(0, 0) = scale_x; - matrix(1, 1) = scale_y; - - // 设置平移 - matrix(0, 3) = translate_x; - matrix(1, 3) = translate_y; - - return matrix; + return aorii::get_renderer_raw()->make_projection_matrix(get_window_size()); } void* renderer_window::get_window_handle() const { diff --git a/src/renderer/core/window/renderer_window.h b/src/renderer/core/window/renderer_window.h index f6b809d..061ae40 100644 --- a/src/renderer/core/window/renderer_window.h +++ b/src/renderer/core/window/renderer_window.h @@ -30,7 +30,7 @@ public: glfwGetFramebufferSize(window, &w, &h); return { w, h }; } - [[nodiscard]] virtual Eigen::Matrix4f get_projection_matrix() const; + [[nodiscard]] Eigen::Matrix4f get_projection_matrix() const; [[nodiscard]] void* get_window_handle() const; [[nodiscard]] GLFWwindow* get_glfw_window() const { return window; } diff --git a/src/renderer/shader/aorii_rounded_rect.slang b/src/renderer/shader/aorii_rounded_rect.slang index ad6f605..67940ba 100644 --- a/src/renderer/shader/aorii_rounded_rect.slang +++ b/src/renderer/shader/aorii_rounded_rect.slang @@ -1,11 +1,11 @@ -struct ParamBuffer +cbuffer ParamBuffer : register(b0) { matrix transform; - float2 pos; // 屏幕坐标 - float2 size; // 圆角矩形像素单位大小 + float2 p1; // 点1位置 + float2 p2; // 点2位置 float radius; // 圆角像素单位 + float thickness; // 线段的宽度 }; -ParameterBlock param_buffer : register(b0); struct VSInput { float2 position : POSITION; // 窗口坐标 @@ -22,7 +22,8 @@ struct PSInput { PSInput vertex_main(VSInput input) { PSInput output; - output.position = mul(float4(input.position, 0.0, 1.0), param_buffer.transform); + output.position = mul(float4(input.position, 0.0, 1.0), transform); + output.uv = input.uv; output.color = input.color; return output; } @@ -30,24 +31,30 @@ PSInput vertex_main(VSInput input) // 圆角矩形像素着色器 float4 pixel_main(PSInput input) : SV_TARGET { - // 圆角半径 - float radius = param_buffer.radius; - // 计算矩形的中心位置 - float2 rect_center = param_buffer.pos + param_buffer.size * 0.5; - // 计算半尺寸,减去圆角半径 - float2 half_size = param_buffer.size * 0.5 - radius; + // 计算input.position到线段p1p2的最短距离 + float2 p = input.uv; + return float4(p, 0, 1); - // 当前像素在视口内位置 - float2 pixel_pos = input.position.xy; - // 将坐标系平移到矩形中心 - float2 pos = pixel_pos - rect_center; + // 计算当前片段到线段的距离 + float2 ba = p2 - p1; + float2 pa = p - p1; + float2 ba_norm = normalize(ba); + float h = clamp(dot(pa, ba_norm), 0.0, length(ba)); + float2 pb = p1 + ba_norm * h; - // 计算距离 - float2 d = abs(pos) - half_size; + float dist = length(p - pb); // 点到线段的距离 + float half_thickness = thickness / 2; + // 抗锯齿 + float alpha = smoothstep(half_thickness - 1, half_thickness, dist); + // 圆角 + float2 corner = float2(radius, radius); + float2 d = abs(p - pb) - corner; + float2 max_d = max(d, 0); - // 取最大值与0比较,确保不小于0 - float inside = length(max(d, 0.0)) - radius; + // float corner_dist = length(max_d); + // float corner_alpha = smoothstep(0, 1, corner_dist); - // inside <= 0.0 说明在圆角矩形内 - return input.color * step(inside, 0.0); + float4 color = input.color; + color.a *= (1 - alpha); + return color; } diff --git a/src/renderer/shader/aorii_sdf_text.slang b/src/renderer/shader/aorii_sdf_text.slang new file mode 100644 index 0000000..26a01c3 --- /dev/null +++ b/src/renderer/shader/aorii_sdf_text.slang @@ -0,0 +1,56 @@ +struct VSInput { + float2 position : POSITION; + float2 uv : TEXCOORD0; + float4 color : COLOR0; +}; + +struct PSInput { + float4 position : SV_Position; + float2 uv : TEXCOORD0; + float4 color : COLOR0; +}; + +struct Constants { + matrix transform; +}; +ParameterBlock param_buffer : register(b0); + +PSInput vertex_main(VSInput input) { + PSInput output; + output.position = mul(float4(input.position, 0.0f, 1.0f), param_buffer.transform); + output.uv = input.uv; + output.color = input.color; + return output; +} + +Texture2D sdf_texture : register(t0); +SamplerState sdf_sampler : register(s0); + +struct FontParams { + float smoothing; // 平滑度 + float thickness; // 字体粗细 + float outline_width; // 描边宽度 + float4 outline_color; // 描边颜色 +} +ParameterBlock font_param : register(b1); + +float4 pixel_main(PSInput input) : SV_Target { + // 采样SDF纹理 + float distance = sdf_texture.Sample(sdf_sampler, input.uv).r; + + // 计算主要形状 + float alpha = smoothstep(font_param.thickness - font_param.smoothing, + font_param.thickness + font_param.smoothing, + distance); + + // 计算轮廓 + float outline_alpha = smoothstep(font_param.thickness - font_param.outline_width - font_param.smoothing, + font_param.thickness - font_param.outline_width + font_param.smoothing, + distance); + + // 混合主要颜色和轮廓颜色 + float4 main_color = input.color * alpha; + float4 outline = font_param.outline_color * (outline_alpha - alpha); + + return main_color + outline; +} \ No newline at end of file diff --git a/src/renderer/shader/aorii_segment.slang b/src/renderer/shader/aorii_segment.slang new file mode 100644 index 0000000..de8cece --- /dev/null +++ b/src/renderer/shader/aorii_segment.slang @@ -0,0 +1,50 @@ +struct VSInput { + float2 position : POSITION; // 窗口坐标 + float2 uv : TEXCOORD0; // 纹理坐标 + float4 color : COLOR; // 颜色 +}; + +struct PSInput { + float4 position : SV_POSITION; // 裁剪空间坐标 + float2 uv : TEXCOORD0; // 纹理坐标 + float4 color : COLOR; // 颜色 +}; + +cbuffer segment_buffer : register(b0) { + matrix transform; + float2 pos_a; // 线段的起点 + float2 pos_b; // 线段的终点 + float thickness; // 线段的宽度 +}; + +PSInput vertex_main(VSInput input) { + PSInput output; + output.position = mul(float4(input.position, 0.0, 1.0), transform); + output.color = input.color; + return output; +} + +// 计算点到线段的最短距mulnamespace离 +float sdf_line(float2 p, float2 a, float2 b) { + float2 pa = p - a; + float2 ba = b - a; + + float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); + return length(pa - ba * h); +} + +// 片段着色器 +float4 pixel_main(PSInput input) : SV_TARGET { + // 将屏幕空间坐标转化为归一化设备坐标 (NDC) + float2 p = input.position.xy; // 归一化设备坐标 (NDC) + + // 计算当前片段到线段的距离 + float distance = sdf_line(p, pos_a, pos_b); + + // 根据线段的粗细来决定颜色输出,使用抗锯齿处理 + float alpha = smoothstep(thickness, thickness + 1, distance); + + // 最终输出颜色,带上 alpha 通道 + return float4(input.color.rgb, (1.0 - alpha) * input.color.a); +} +