From f73e7e4a50d83c9499cfb29fd9e371607c1f5bfa Mon Sep 17 00:00:00 2001 From: Nanako <469449812@qq.com> Date: Tue, 5 Nov 2024 16:48:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=81=E8=A3=85=E7=9D=80=E8=89=B2=E5=99=A8?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E4=BB=A3=E7=A0=81=E5=91=BD=E4=BB=A4=20?= =?UTF-8?q?=E7=BC=96=E5=86=99=E9=83=A8=E5=88=86=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 7 - cmake/compile_shaders.cmake | 155 +++++++++--------- example/CMakeLists.txt | 6 + example/src/main.cpp | 2 +- resource/shader/default_shader.slang | 29 ---- src/renderer/CMakeLists.txt | 8 + src/renderer/backend/dx/dx_pipeline.h | 2 +- src/renderer/backend/dx/dx_window.cpp | 31 ++-- src/renderer/core/pipeline/pipeline.h | 7 +- src/renderer/core/renderer/renderer.h | 6 +- .../core/renderer/renderer_context.cpp | 42 +++-- src/renderer/core/renderer/renderer_context.h | 47 +++++- src/renderer/shader/default_shader.slang | 63 +++++++ 13 files changed, 241 insertions(+), 164 deletions(-) delete mode 100644 resource/shader/default_shader.slang create mode 100644 src/renderer/shader/default_shader.slang diff --git a/CMakeLists.txt b/CMakeLists.txt index 060e449..1ea79d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,6 @@ cmake_minimum_required(VERSION 3.10) project(aorii) set(CMAKE_CXX_STANDARD 23) -set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/shader) - include(cmake/retrieve_files.cmake) include(cmake/detect_os.cmake) include(cmake/configure_glfw_native.cmake) @@ -29,8 +27,3 @@ if (BUILD_EXAMPLE) add_subdirectory(example) endif () -set(SHADER_STAGES - "vertex" - "pixel" -) -compile_slang_shaders(${CMAKE_CURRENT_SOURCE_DIR}/resource/shader/default_shader.slang SHADER_STAGES) diff --git a/cmake/compile_shaders.cmake b/cmake/compile_shaders.cmake index b5485aa..54bb379 100644 --- a/cmake/compile_shaders.cmake +++ b/cmake/compile_shaders.cmake @@ -1,87 +1,84 @@ -function(compile_slang_shaders input_shaders shader_stages) - # Ensure the output directory exists + +function(compile_slang_shaders input_file stage entry_point) + # 保证输出目录存在 + if (NOT DEFINED SHADER_OUTPUT_DIR) + message(FATAL_ERROR "SHADER_OUTPUT_DIR not defined") + endif () set(output_dir ${SHADER_OUTPUT_DIR}) - file(MAKE_DIRECTORY ${output_dir}) - foreach(input_file IN LISTS input_shaders) - # Get the base name for the output file - get_filename_component(filename ${input_file} NAME_WE) + # 获取输出文件的基本名称 + get_filename_component(filename ${input_file} NAME_WE) - # Initialize a list to hold all the output files for this shader - set(output_files) + # 定义根据阶段确定的配置 + if(stage STREQUAL "vertex") + set(profile "vs_5_0") + elseif(stage STREQUAL "pixel") + set(profile "ps_5_0") + elseif (stage STREQUAL "comp") + set(profile "cs_5_0") + else() + message(FATAL_ERROR "Unsupported shader stage: ${stage}") + endif() - # Use a set to track processed stages to avoid duplication - set(processed_stages) + # 初始化一个列表来存储输出文件 + set(output_files) - foreach(stage IN LISTS ${shader_stages}) - # Check if the stage has already been processed - if(NOT stage IN_LIST processed_stages) - list(APPEND processed_stages ${stage}) - - # Define the entry point based on the stage - if(stage STREQUAL "vertex") - set(entry_point "vertex_main") - set(profile "vs_5_0") - elseif(stage STREQUAL "pixel") - set(entry_point "pixel_main") - set(profile "ps_5_0") - elseif (stage STREQUAL "comp") - set(entry_point "compute_main") - set(profile "cs_5_0") - else() - message(FATAL_ERROR "Unsupported shader stage: ${stage}") - endif() - - # Check and compile for each backend - if(GL_BACKEND) - list(APPEND output_files ${output_dir}/${filename}_${stage}.glsl) - add_custom_command( - OUTPUT ${output_dir}/${filename}_${stage}.glsl - COMMAND slangc -target glsl -entry ${entry_point} -stage ${stage} -o ${output_dir}/${filename}_${stage}.glsl ${input_file} - DEPENDS ${input_file} - COMMENT "Compiling ${input_file} to GLSL (${stage})" - ) - endif() - - if(DX_BACKEND) - list(APPEND output_files ${output_dir}/${filename}_${stage}.dxbc) - add_custom_command( - OUTPUT ${output_dir}/${filename}_${stage}.dxbc - COMMAND slangc -target dxbc -profile ${profile} -entry ${entry_point} -stage ${stage} -o ${output_dir}/${filename}_${stage}.dxbc ${input_file} - DEPENDS ${input_file} - COMMENT "Compiling ${input_file} to DXBC (${stage})" - ) - endif() - - if(VK_BACKEND) - list(APPEND output_files ${output_dir}/${filename}_${stage}.spirv) - add_custom_command( - OUTPUT ${output_dir}/${filename}_${stage}.spirv - COMMAND slangc -target spirv -entry ${entry_point} -stage ${stage} -o ${output_dir}/${filename}_${stage}.spirv ${input_file} - DEPENDS ${input_file} - COMMENT "Compiling ${input_file} to SPIR-V (${stage})" - ) - endif() - - if(METAL_BACKEND) - list(APPEND output_files ${output_dir}/${filename}_${stage}.metal) - add_custom_command( - OUTPUT ${output_dir}/${filename}_${stage}.metal - COMMAND slangc -target msl -entry ${entry_point} -stage ${stage} -o ${output_dir}/${filename}_${stage}.metal ${input_file} - DEPENDS ${input_file} - COMMENT "Compiling ${input_file} to Metal Shading Language (${stage})" - ) - endif() - else() - message(WARNING "The stage '${stage}' has already been processed for entry point '${entry_point}'. Skipping duplicate.") - endif() - endforeach() - - # Add the custom command outputs to the compile_shader target - add_custom_target( - compile_shader - DEPENDS ${output_files} + # 为每个后台创建自定义命令 + if(GL_BACKEND) + set(output_file ${output_dir}/${filename}_${entry_point}.glsl) + add_custom_command( + OUTPUT ${output_file} + COMMAND slangc -target glsl -entry ${entry_point} -stage ${stage} -o ${output_file} ${input_file} + DEPENDS ${input_file} + COMMENT "Compiling ${input_file} to GLSL (${stage}, ${entry_point})" ) - endforeach() + list(APPEND output_files ${output_file}) + endif() + + if(DX_BACKEND) + set(output_file ${output_dir}/${filename}_${entry_point}.dxbc) + add_custom_command( + OUTPUT ${output_file} + COMMAND slangc -target dxbc -profile ${profile} -entry ${entry_point} -stage ${stage} -o ${output_file} ${input_file} + DEPENDS ${input_file} + COMMENT "Compiling ${input_file} to DXBC (${stage}, ${entry_point}) with profile ${profile}" + ) + list(APPEND output_files ${output_file}) + endif() + + if(VK_BACKEND) + set(output_file ${output_dir}/${filename}_${entry_point}.spirv) + add_custom_command( + OUTPUT ${output_file} + COMMAND slangc -target spirv -entry ${entry_point} -stage ${stage} -o ${output_file} ${input_file} + DEPENDS ${input_file} + COMMENT "Compiling ${input_file} to SPIR-V (${stage}, ${entry_point})" + ) + list(APPEND output_files ${output_file}) + endif() + + if(METAL_BACKEND) + set(output_file ${output_dir}/${filename}_${entry_point}.metal) + add_custom_command( + OUTPUT ${output_file} + COMMAND slangc -target msl -entry ${entry_point} -stage ${stage} -o ${output_file} ${input_file} + DEPENDS ${input_file} + COMMENT "Compiling ${input_file} to Metal Shading Language (${stage}, ${entry_point})" + ) + list(APPEND output_files ${output_file}) + endif() + + # 将输出文件添加到全局列表中 + set_property(GLOBAL APPEND PROPERTY ALL_SHADER_OUTPUTS ${output_files}) endfunction() +function(add_compile_shaders_target target_name before_target) + file(MAKE_DIRECTORY ${SHADER_OUTPUT_DIR}) + + get_property(ALL_SHADER_OUTPUTS GLOBAL PROPERTY ALL_SHADER_OUTPUTS) + add_custom_target(${target_name} ALL DEPENDS ${ALL_SHADER_OUTPUTS}) + # 将编译着色器的目标添加到指定目标之前 + add_dependencies(${before_target} ${target_name}) + # 将ALL_SHADER_OUTPUTS清空 + set_property(GLOBAL PROPERTY ALL_SHADER_OUTPUTS "") +endfunction() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 6ba6266..9976ced 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -5,3 +5,9 @@ set(SRC_FILES "") retrieve_files(src SRC_FILES) add_executable(${PROJECT_NAME} ${SRC_FILES}) target_link_libraries(${PROJECT_NAME} PRIVATE aorii_renderer) + +# 复制${SHADER_OUTPUT_DIR}文件到${CMAKE_CURRENT_BINARY_DIR}/resource +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${SHADER_OUTPUT_DIR} $/resource/shaders + COMMENT "Copying shader files to resource directory after build") diff --git a/example/src/main.cpp b/example/src/main.cpp index bc2e12b..b5869de 100644 --- a/example/src/main.cpp +++ b/example/src/main.cpp @@ -8,7 +8,7 @@ int main(int argc, char* argv[]) { aorii::create_renderer(renderer_api::dx11); aorii::create_window_manager(); - auto window = aorii::create_window({128, 128}, "hello world"); + auto window = aorii::create_window({1280, 1280}, "hello world"); auto glfw_window = window->get_glfw_window(); while (!glfwWindowShouldClose(glfw_window)) { glfwPollEvents(); diff --git a/resource/shader/default_shader.slang b/resource/shader/default_shader.slang deleted file mode 100644 index bd2517b..0000000 --- a/resource/shader/default_shader.slang +++ /dev/null @@ -1,29 +0,0 @@ -struct MatrixBuffer -{ - matrix transform; -}; -ParameterBlock matrix_buffer : register(b0); -SamplerState texture_sampler : register(s0); - -struct VSInput { - float2 position : POSITION; - float4 color : COLOR; -}; - -struct PSInput { - float4 position : SV_POSITION; - float4 color : COLOR; -}; - -PSInput vertex_main(VSInput input) -{ - PSInput output; - output.position = mul(float4(input.position, 0.0, 1.0), matrix_buffer.transform); - output.color = input.color; - return output; -} - -float4 pixel_main(PSInput input) : SV_TARGET -{ - return input.color; -} diff --git a/src/renderer/CMakeLists.txt b/src/renderer/CMakeLists.txt index d395981..562fd14 100644 --- a/src/renderer/CMakeLists.txt +++ b/src/renderer/CMakeLists.txt @@ -54,3 +54,11 @@ foreach(BACKEND ${ALL_BACKENDS}) target_compile_definitions(${PROJECT_NAME} PUBLIC ${BACKEND}=0) endforeach() +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/default_shader.slang vertex vertex_main) +compile_slang_shaders(${CMAKE_CURRENT_SOURCE_DIR}/shader/default_shader.slang pixel pixel_main) +compile_slang_shaders(${CMAKE_CURRENT_SOURCE_DIR}/shader/default_shader.slang pixel rounded_rect_pixel_main) +add_compile_shaders_target("compile_aorii_shaders" ${PROJECT_NAME}) diff --git a/src/renderer/backend/dx/dx_pipeline.h b/src/renderer/backend/dx/dx_pipeline.h index 0feb641..206cf3b 100644 --- a/src/renderer/backend/dx/dx_pipeline.h +++ b/src/renderer/backend/dx/dx_pipeline.h @@ -20,7 +20,7 @@ public: void build_index_buffer(int triangle_count); void build_constant_buffer(); - void set_triangle(const std::span& in_vertexes, const std::span& in_triangles); + void set_triangle(const std::span& in_vertexes, const std::span& in_triangles) override; aorii_constant_buffer_type* lock_constant_buffer(); void unlock_constant_buffer(); diff --git a/src/renderer/backend/dx/dx_window.cpp b/src/renderer/backend/dx/dx_window.cpp index c506f82..27ccaaf 100644 --- a/src/renderer/backend/dx/dx_window.cpp +++ b/src/renderer/backend/dx/dx_window.cpp @@ -80,6 +80,7 @@ bool dx_window::create_surface(GLFWwindow* in_window) { pipeline.load_pixel_shader(); pipeline.load_vertex_shader(); + context.set_default_pipeline(&pipeline); return true; } @@ -103,15 +104,7 @@ void dx_window::begin_frame() { static float pos_y = 0; static bool draw_test = true; - auto delta_time = get_delta_time(); - - timer += delta_time; - if (draw_test && timer.count() >= 0.01) { - // float random_r = static_cast(rand()) / RAND_MAX; - // float random_g = static_cast(rand()) / RAND_MAX; - // float random_b = static_cast(rand()) / RAND_MAX; - // random_color = { random_r, random_g, random_b, 1.0f }; - + if (draw_test) { // 生成渐变色 if (is_white) { if (random_color.r > 0) { @@ -139,20 +132,16 @@ void dx_window::begin_frame() { } } - timer -= std::chrono::duration(0.01); - context.draw_rectangle({pos_x, pos_y}, {1, 1000}, random_color); + context.draw_rectangle({ pos_x, pos_y }, { 1, 100 }, random_color); + pos_x += 1; + if (pos_x >= 1000) { + pos_x = 0; + draw_test = false; + } } - - pos_x += delta_time.count() * 100; - if (pos_x >= 1000) { - pos_x = 0; - pos_y += 1; - draw_test = false; - } - - pipeline.set_triangle(context.get_vertices(), context.get_triangles()); } - pipeline.draw(); + + context.flush(); swap_chain->Present(1, 0); } diff --git a/src/renderer/core/pipeline/pipeline.h b/src/renderer/core/pipeline/pipeline.h index 2345342..6f27dd6 100644 --- a/src/renderer/core/pipeline/pipeline.h +++ b/src/renderer/core/pipeline/pipeline.h @@ -1,11 +1,12 @@ #pragma once +#include #include #include #include "misc/color.h" -#define AORII_DEFAULT_PIXEL_SHADER_NAME "default_shader_pixel" -#define AORII_DEFAULT_VERTEX_SHADER_NAME "default_shader_vertex" +#define AORII_DEFAULT_PIXEL_SHADER_NAME "default_shader_pixel_main" +#define AORII_DEFAULT_VERTEX_SHADER_NAME "default_shader_vertex_main" struct aorii_vertex { Eigen::Vector2f position; @@ -28,6 +29,8 @@ public: virtual void use() = 0; virtual void draw() = 0; + + virtual void set_triangle(const std::span& in_vertexes, const std::span& in_triangles) = 0; }; class custom_pipeline : public pipeline { diff --git a/src/renderer/core/renderer/renderer.h b/src/renderer/core/renderer/renderer.h index f324fae..21fe9f0 100644 --- a/src/renderer/core/renderer/renderer.h +++ b/src/renderer/core/renderer/renderer.h @@ -13,10 +13,6 @@ enum class renderer_api { metal, }; -struct vertex_data { - Eigen::Vector3f position; -}; - class renderer { friend class window_manager; public: @@ -49,7 +45,7 @@ namespace aorii { const std::chrono::duration& get_delta_time(); - inline std::filesystem::path s_shader_relative_path = "resource/shader"; + inline std::filesystem::path s_shader_relative_path = "resource/shaders"; inline void set_shader_relative_path(const std::filesystem::path& path) { s_shader_relative_path = path; } inline std::filesystem::path get_shader_path(const std::string& shader_name) { return std::filesystem::current_path() / s_shader_relative_path / shader_name; } } diff --git a/src/renderer/core/renderer/renderer_context.cpp b/src/renderer/core/renderer/renderer_context.cpp index 223d93b..e397245 100644 --- a/src/renderer/core/renderer/renderer_context.cpp +++ b/src/renderer/core/renderer/renderer_context.cpp @@ -1,12 +1,11 @@ #include "renderer_context.h" -void renderer_context::draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, - const linear_color& in_color) { - - const aorii_vertex_type v1 {{in_pos.x(), in_pos.y()}, in_color }; // 左上角 - const aorii_vertex_type v2 {{in_pos.x() + in_size.x(), in_pos.y()}, in_color }; // 右上角 - const aorii_vertex_type v3 {{in_pos.x(), in_pos.y() + in_size.y()}, in_color }; // 左下角 - const aorii_vertex_type v4 {{in_pos.x() + in_size.x(), in_pos.y() + in_size.y()}, in_color }; // 右下角 +void renderer_context::draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color) { + switch_pipeline(default_pipeline); + const aorii_vertex_type v1{ { in_pos.x(), in_pos.y() }, in_color }; // 左上角 + const aorii_vertex_type v2{ { in_pos.x() + in_size.x(), in_pos.y() }, in_color }; // 右上角 + const aorii_vertex_type v3{ { in_pos.x(), in_pos.y() + in_size.y() }, in_color }; // 左下角 + const aorii_vertex_type v4{ { in_pos.x() + in_size.x(), in_pos.y() + in_size.y() }, in_color }; // 右下角 const uint32_t index1 = vertices.size(); vertices.push_back(v1); @@ -17,22 +16,29 @@ void renderer_context::draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen const uint32_t index4 = vertices.size(); vertices.push_back(v4); - const aorii_triangle_type t1 = {index1, index2, index3}; - const aorii_triangle_type t2 = {index2, index3, index4}; + const aorii_triangle_type t1 = { index1, index2, index3 }; + const aorii_triangle_type t2 = { index2, index3, index4 }; triangles.push_back(t1); triangles.push_back(t2); } -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) { +void renderer_context::draw_rounded_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color, float in_radius) { + switch_pipeline(rounded_rectangular_pipeline); + + // 立刻绘制并重置管线, 因为下一个绘制命令的参数可能不同, 所以无法合批 + 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) { + switch_pipeline(default_pipeline); const Eigen::Vector2f direction = (in_pos_p2 - in_pos_p1).cast().normalized(); - const Eigen::Vector2f normal = {-direction.y(), direction.x()}; + const Eigen::Vector2f normal = { -direction.y(), direction.x() }; const Eigen::Vector2f offset = normal * in_thickness; - const aorii_vertex_type v1 {{in_pos_p1.x() + offset.x(), in_pos_p1.y() + offset.y()}, in_color }; - const aorii_vertex_type v2 {{in_pos_p1.x() - offset.x(), in_pos_p1.y() - offset.y()}, in_color }; - const aorii_vertex_type v3 {{in_pos_p2.x() + offset.x(), in_pos_p2.y() + offset.y()}, in_color }; - const aorii_vertex_type v4 {{in_pos_p2.x() - offset.x(), in_pos_p2.y() - offset.y()}, in_color }; + const aorii_vertex_type v1{ { in_pos_p1.x() + offset.x(), in_pos_p1.y() + offset.y() }, in_color }; + const aorii_vertex_type v2{ { in_pos_p1.x() - offset.x(), in_pos_p1.y() - offset.y() }, in_color }; + const aorii_vertex_type v3{ { in_pos_p2.x() + offset.x(), in_pos_p2.y() + offset.y() }, in_color }; + const aorii_vertex_type v4{ { in_pos_p2.x() - offset.x(), in_pos_p2.y() - offset.y() }, in_color }; const uint32_t index1 = vertices.size(); vertices.push_back(v1); @@ -43,8 +49,8 @@ void renderer_context::draw_line(const Eigen::Vector2i& in_pos_p1, const Eigen:: const uint32_t index4 = vertices.size(); vertices.push_back(v4); - const aorii_triangle_type t1 = {index1, index2, index3}; - const aorii_triangle_type t2 = {index2, index3, index4}; + const aorii_triangle_type t1 = { index1, index2, index3 }; + const aorii_triangle_type 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 93772ae..e4a70f2 100644 --- a/src/renderer/core/renderer/renderer_context.h +++ b/src/renderer/core/renderer/renderer_context.h @@ -5,9 +5,36 @@ class renderer_context { public: + /** + * 绘制一个实心矩形 + * @param in_pos 当前控件坐标系的位置 + * @param in_size 绘制的大小(受控件缩放影响) + * @param in_color 绘制的颜色 + */ void draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color); + + /** + * 绘制一个实心圆角矩形 + * @param in_pos 当前控件坐标系的位置 + * @param in_size 绘制的大小(受控件缩放影响) + * @param in_color 绘制的颜色 + * @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); + + /** + * 绘制一条线 + * @param in_pos_p1 点1 + * @param in_pos_p2 点2 + * @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 set_default_pipeline(pipeline* in_pipeline) { + default_pipeline = in_pipeline; + } + void clear() { vertices.clear(); triangles.clear(); @@ -19,8 +46,26 @@ public: [[nodiscard]] const std::vector& get_triangles() const { return triangles; } + void flush() { + if (default_pipeline) { + default_pipeline->set_triangle(vertices, triangles); + default_pipeline->draw(); + } + clear(); + } +protected: + void switch_pipeline(pipeline* in_pipeline) { + if (current_pipeline != in_pipeline) { + flush(); + current_pipeline = in_pipeline; + } + } private: std::vector vertices; std::vector triangles; - void add_triangle(const Eigen::Vector2i& in_pos_p1, const Eigen::Vector2i& in_pos_p2, const Eigen::Vector2i& in_pos_p3); + + pipeline* default_pipeline = nullptr; + pipeline* rounded_rectangular_pipeline = nullptr; + + pipeline* current_pipeline = nullptr; }; diff --git a/src/renderer/shader/default_shader.slang b/src/renderer/shader/default_shader.slang new file mode 100644 index 0000000..5256210 --- /dev/null +++ b/src/renderer/shader/default_shader.slang @@ -0,0 +1,63 @@ +struct MatrixBuffer +{ + matrix transform; +}; +struct RoundedRectBuffer +{ + float2 size; // 像素单位 + float radius; // 像素单位 +}; +ParameterBlock matrix_buffer : register(b0); +ParameterBlock rounded_rect_buffer : register(b1); +SamplerState texture_sampler : register(s0); + +struct VSInput { + float2 position : POSITION; + float4 color : COLOR; +}; + +struct PSInput { + float4 position : SV_POSITION; + float4 color : COLOR; + float2 uv : TEXCOORD0; +}; + +PSInput vertex_main(VSInput input) +{ + PSInput output; + output.position = mul(float4(input.position, 0.0, 1.0), matrix_buffer.transform); + output.color = input.color; + output.uv = input.position + 0.5; + return output; +} + +float4 pixel_main(PSInput input) : SV_TARGET +{ + return input.color; +} + +// 计算点到矩形边的最小距离 +float rounded_box_SDF(float2 center_position, float2 size, float radius) +{ + float2 q = abs(center_position) - size + radius; + return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius; +} + +// 圆角矩形像素着色器 +float4 rounded_rect_pixel_main(PSInput input) : SV_TARGET +{ + float2 size = rounded_rect_buffer.size; + float radius = rounded_rect_buffer.radius; + + // 将UV坐标转换为中心坐标系统 + float2 center_position = (input.uv - 0.5) * size; + + // 计算到圆角矩形边缘的距离 + float distance = rounded_box_SDF(center_position, size * 0.5, radius); + + // 使用平滑步进函数创建抗锯齿边缘 + float alpha = 1.0 - smoothstep(-1.0, 1.0, distance); + + // 返回最终颜色 + return float4(input.color.xyz, input.color.a * alpha); +}