圆角矩形

This commit is contained in:
Nanako 2024-11-08 18:20:35 +08:00
parent 755fe590a1
commit 242cdacf2b
21 changed files with 479 additions and 115 deletions

View File

@ -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") 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}") message(STATUS "SHADER_OUTPUT_DIR not defined, using default: ${SHADER_OUTPUT_DIR}")
endif () endif ()
compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_rect.slang" "vertex" "vertex_main") function(compile_aorii_shader SHADER_FILE)
compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_rect.slang" "pixel" "pixel_main") compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/${SHADER_FILE}.slang" "vertex" "vertex_main")
compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_rounded_rect.slang" "vertex" "vertex_main") compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/${SHADER_FILE}.slang" "pixel" "pixel_main")
compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_rounded_rect.slang" "pixel" "pixel_main") endfunction()
compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_texture.slang" "vertex" "vertex_main") compile_aorii_shader(aorii_rect)
compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/aorii_texture.slang" "pixel" "pixel_main") 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}) add_compile_shaders_target("compile_aorii_shaders" ${PROJECT_NAME})
# example, shader # example, shader

View File

@ -34,6 +34,7 @@ bool dx_renderer::init() {
rect_p.init(); rect_p.init();
rounded_rect_p.init(); rounded_rect_p.init();
texture_p.init(); texture_p.init();
segment_p.init();
return true; return true;
} }
@ -59,6 +60,29 @@ renderer_texture* dx_renderer::create_texture(const Eigen::Vector2i& size, textu
return new dx_texture(size, in_format); 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<float>(size.x());
const float scale_y = -2.0f / static_cast<float>(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<char> dx_renderer::load_shader(const std::string& shader_name) { std::vector<char> dx_renderer::load_shader(const std::string& shader_name) {
auto file_pathname = aorii::get_shader_path(shader_name).generic_string() + ".dxbc"; auto file_pathname = aorii::get_shader_path(shader_name).generic_string() + ".dxbc";
std::ifstream file(file_pathname, std::ios::binary); std::ifstream file(file_pathname, std::ios::binary);

View File

@ -4,6 +4,7 @@
#include "core/renderer/renderer.h" #include "core/renderer/renderer.h"
#include "pipeline/dx_rect_pipeline.h" #include "pipeline/dx_rect_pipeline.h"
#include "pipeline/dx_rounded_rect_pipeline.h" #include "pipeline/dx_rounded_rect_pipeline.h"
#include "pipeline/dx_segment_pipeline.h"
#include "pipeline/dx_texture_pipeline.h" #include "pipeline/dx_texture_pipeline.h"
class dx_window; class dx_window;
@ -22,6 +23,10 @@ public:
rect_pipeline* get_rect_pipeline() override { return &rect_p; } rect_pipeline* get_rect_pipeline() override { return &rect_p; }
rounded_rect_pipeline* get_rounded_rect_pipeline() override { return &rounded_rect_p; } rounded_rect_pipeline* get_rounded_rect_pipeline() override { return &rounded_rect_p; }
texture_pipeline* get_texture_pipeline() override { return &texture_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; } [[nodiscard]] ID3D11BlendState* get_blend_state() const { return blend_state; }
std::vector<char> load_shader(const std::string& shader_name) override; std::vector<char> load_shader(const std::string& shader_name) override;
@ -39,6 +44,7 @@ private:
dx_rect_pipeline rect_p; dx_rect_pipeline rect_p;
dx_rounded_rect_pipeline rounded_rect_p; dx_rounded_rect_pipeline rounded_rect_p;
dx_texture_pipeline texture_p; dx_texture_pipeline texture_p;
dx_segment_pipeline segment_p;
}; };
inline DXGI_FORMAT get_dxgi_format(texture_format format) { inline DXGI_FORMAT get_dxgi_format(texture_format format) {

View File

@ -8,6 +8,7 @@
using namespace aorii; using namespace aorii;
static float thickness = 1.f;
bool dx_window::create_surface(GLFWwindow* in_window) { bool dx_window::create_surface(GLFWwindow* in_window) {
auto dx = aorii::get_renderer<dx_renderer>(); auto dx = aorii::get_renderer<dx_renderer>();
const auto d3d_device = dx->get_d3d_device(); 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); 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; return true;
} }
@ -80,16 +84,19 @@ void dx_window::begin_frame() {
d3d_context->OMSetRenderTargets(1, &render_target_view, nullptr); d3d_context->OMSetRenderTargets(1, &render_target_view, nullptr);
d3d_context->OMSetBlendState(render->get_blend_state(), nullptr, 0xffffffff); d3d_context->OMSetBlendState(render->get_blend_state(), nullptr, 0xffffffff);
d3d_context->ClearRenderTargetView(render_target_view, clear_color); 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 }); context.draw_rectangle({ 400, 0 }, { 100, 100 }, { 0, 1, 0, 1 });
auto radius = abs(sin(get_total_time().count())) * 50; 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; double mouse_x, mouse_y;
context.draw_line({ 600, 600 - height }, { 700, 600 + height }, { 0, 0, 1, 1 }, 0.5); 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(); context.flush();

View File

@ -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<dx_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);
}

View File

@ -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;
};

View File

@ -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<dx_renderer>()->get_d3d_context();
// 设置顶点缓冲区
constexpr UINT stride = sizeof(aorii_vertex);
constexpr UINT offset = 0;
auto* v_buffer = static_cast<ID3D11Buffer*>(vertex_buffer->get_native_handle());
auto* i_buffer = static_cast<ID3D11Buffer*>(index_buffer->get_native_handle());
auto* c_buffer = static_cast<ID3D11Buffer*>(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);
}

View File

@ -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;
};

View File

@ -5,9 +5,10 @@ class rounded_rect_pipeline : public pipeline {
public: public:
struct param { struct param {
Eigen::Matrix4f projection_matrix; Eigen::Matrix4f projection_matrix;
Eigen::Vector2f pos; Eigen::Vector2f p1;
Eigen::Vector2f size; Eigen::Vector2f p2;
float radius; float radius;
float thickness;
}; };
bool init() override; bool init() override;

View File

@ -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);
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <cfloat>
#include "pipeline.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include <omp.h>
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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -6,6 +6,7 @@
#include "renderer_buffer.h" #include "renderer_buffer.h"
#include "core/pipeline/pipeline.h" #include "core/pipeline/pipeline.h"
class segment_pipeline;
class texture_pipeline; class texture_pipeline;
class rounded_rect_pipeline; class rounded_rect_pipeline;
class rect_pipeline; class rect_pipeline;
@ -241,6 +242,9 @@ public:
virtual rect_pipeline* get_rect_pipeline() = 0; virtual rect_pipeline* get_rect_pipeline() = 0;
virtual rounded_rect_pipeline* get_rounded_rect_pipeline() = 0; virtual rounded_rect_pipeline* get_rounded_rect_pipeline() = 0;
virtual texture_pipeline* get_texture_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: private:
virtual renderer_window* create_window() = 0; virtual renderer_window* create_window() = 0;
virtual void destroy_window(renderer_window* window); virtual void destroy_window(renderer_window* window);

View File

@ -6,28 +6,119 @@
void renderer_context::init() { 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(); to_rect_pipeline();
make_rect(in_pos, in_size, in_color); 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) { 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_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::Vector2f& in_pos_p1, const Eigen::Vector2f& in_pos_p2, const linear_color& in_color, float in_thickness) {
}
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); make_rect(in_pos, in_size, in_color);
// 立刻绘制并重置管线, 因为下一个绘制命令的参数可能不同, 所以无法合批 // 立刻绘制并重置管线, 因为下一个绘制命令的参数可能不同, 所以无法合批
flush(); 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) { void renderer_context::set_projection_matrix(const Eigen::Matrix4f& in_matrix, const Eigen::Vector2i& in_framebuffer_size) {
to_rect_pipeline(); projection_matrix = in_matrix;
const Eigen::Vector2f direction = (in_pos_p2 - in_pos_p1).cast<float>().normalized(); framebuffer_size = in_framebuffer_size;
const Eigen::Vector2f normal = { -direction.y(), direction.x() };
const Eigen::Vector2f offset = normal * 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 auto rect_p = aorii::get_renderer<dx_renderer>()->get_rect_pipeline();
const aorii_vertex v3{ { in_pos_p2.x() + offset.x(), in_pos_p2.y() + offset.y() }, { 0, 1 }, in_color }; rect_p->set_param({ in_matrix });
const aorii_vertex v4{ { in_pos_p2.x() - offset.x(), in_pos_p2.y() - offset.y() }, { 1, 1 }, in_color }; // 更新纹理管线的投影矩阵
const auto texture_p = aorii::get_renderer<dx_renderer>()->get_texture_pipeline();
texture_p->set_param({ in_matrix });
// 圆角矩形管线的投影矩阵不需要更新, 因为它在每次绘制时都会更新
// 线段管线的投影矩阵不需要更新, 因为它在每次绘制时都会更新
}
void renderer_context::to_rect_pipeline() {
const auto rect_p = aorii::get_renderer<dx_renderer>()->get_rect_pipeline();
switch_pipeline(rect_p);
}
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<dx_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<float, 2>(center) * // 平移到旋转中心
Eigen::Rotation2D<float>(in_angle) * // 旋转
Eigen::Translation<float, 2>(-center); // 平移回原点
top_middle = transform * top_middle;
bottom_middle = transform * bottom_middle;
}
rounded_rect_pipeline::param param;
param.projection_matrix = projection_matrix;
param.p1 = top_middle;
param.p2 = bottom_middle;
param.radius = in_radius;
param.thickness = in_size.x();
rounded_rect_p->set_param(param);
}
void renderer_context::to_texture_pipeline(renderer_texture* in_texture) {
const auto texture_p = aorii::get_renderer<dx_renderer>()->get_texture_pipeline();
switch_pipeline(texture_p);
texture_p->set_texture(in_texture);
}
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<dx_renderer>()->get_segment_pipeline();
switch_pipeline(segment_p);
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<float, 2>(center) * // 平移到旋转中心
Eigen::Rotation2D<float>(in_angle) * // 旋转
Eigen::Translation<float, 2>(-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(); const uint32_t index1 = vertices.size();
vertices.push_back(v1); vertices.push_back(v1);
@ -42,53 +133,8 @@ void renderer_context::draw_line(const Eigen::Vector2i& in_pos_p1, const Eigen::
const aorii_triangle t2 = { index2, index3, index4 }; const aorii_triangle t2 = { index2, index3, index4 };
triangles.push_back(t1); triangles.push_back(t1);
triangles.push_back(t2); triangles.push_back(t2);
} }
else {
void renderer_context::draw_texture(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& 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) {
projection_matrix = in_matrix;
// 更新默认管线的投影矩阵
const auto rect_p = aorii::get_renderer<dx_renderer>()->get_rect_pipeline();
rect_p->set_param({ in_matrix });
// 更新纹理管线的投影矩阵
const auto texture_p = aorii::get_renderer<dx_renderer>()->get_texture_pipeline();
texture_p->set_param({ in_matrix });
// 圆角矩形管线的投影矩阵不需要更新, 因为它在每次绘制时都会更新
}
void renderer_context::to_rect_pipeline() {
const auto rect_p = aorii::get_renderer<dx_renderer>()->get_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) {
const auto rounded_rect_p = aorii::get_renderer<dx_renderer>()->get_rounded_rect_pipeline();
switch_pipeline(rounded_rect_p);
rounded_rect_pipeline::param param;
param.projection_matrix = projection_matrix;
param.pos = in_pos.cast<float>();
param.size = in_size.cast<float>();
param.radius = in_radius;
rounded_rect_p->set_param(param);
}
void renderer_context::to_texture_pipeline(renderer_texture* in_texture) {
const auto texture_p = aorii::get_renderer<dx_renderer>()->get_texture_pipeline();
switch_pipeline(texture_p);
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 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 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 v3{ { in_pos.x(), in_pos.y() + in_size.y() }, { 0, 1 }, in_color }; // 左下角
@ -107,4 +153,5 @@ void renderer_context::make_rect(const Eigen::Vector2i& in_pos, const Eigen::Vec
const aorii_triangle t2 = { index2, index3, index4 }; const aorii_triangle t2 = { index2, index3, index4 };
triangles.push_back(t1); triangles.push_back(t1);
triangles.push_back(t2); triangles.push_back(t2);
}
} }

View File

@ -16,16 +16,17 @@ public:
* @param in_size () * @param in_size ()
* @param in_color * @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_pos
* @param in_size () * @param in_size ()
* @param in_color * @param in_color
* @param in_angle
* @param in_radius () * @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_color 线
* @param in_thickness 线(), 0, 线 * @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_size ()
* @param in_texture * @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() { void clear() {
vertices.clear(); vertices.clear();
@ -63,7 +64,7 @@ public:
} }
clear(); 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: protected:
void switch_pipeline(pipeline* in_pipeline) { void switch_pipeline(pipeline* in_pipeline) {
@ -79,14 +80,16 @@ protected:
} }
void to_rect_pipeline(); 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_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: private:
std::vector<aorii_vertex> vertices; std::vector<aorii_vertex> vertices;
std::vector<aorii_triangle> triangles; std::vector<aorii_triangle> triangles;
pipeline* current_pipeline = nullptr; pipeline* current_pipeline = nullptr;
Eigen::Matrix4f projection_matrix; Eigen::Matrix4f projection_matrix;
Eigen::Vector2i framebuffer_size;
private: 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);
}; };

View File

@ -1,4 +1,6 @@
#include "renderer_window.h" #include "renderer_window.h"
#include "core/renderer/renderer.h"
#include "GLFW/glfw3native.h" #include "GLFW/glfw3native.h"
renderer_window::~renderer_window() { if (window) glfwDestroyWindow(window); } 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 renderer_window::get_projection_matrix() const {
// 创建一个单位矩阵 return aorii::get_renderer_raw()->make_projection_matrix(get_window_size());
Eigen::Matrix4f matrix = Eigen::Matrix4f::Identity();
const auto& window_size = get_window_size();
// 缩放因子
const float scale_x = 2.0f / static_cast<float>(window_size.x());
const float scale_y = -2.0f / static_cast<float>(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;
} }
void* renderer_window::get_window_handle() const { void* renderer_window::get_window_handle() const {

View File

@ -30,7 +30,7 @@ public:
glfwGetFramebufferSize(window, &w, &h); glfwGetFramebufferSize(window, &w, &h);
return { 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]] void* get_window_handle() const;
[[nodiscard]] GLFWwindow* get_glfw_window() const { return window; } [[nodiscard]] GLFWwindow* get_glfw_window() const { return window; }

View File

@ -1,11 +1,11 @@
struct ParamBuffer cbuffer ParamBuffer : register(b0)
{ {
matrix transform; matrix transform;
float2 pos; // 屏幕坐标 float2 p1; // 点1位置
float2 size; // 圆角矩形像素单位大小 float2 p2; // 点2位置
float radius; // 圆角像素单位 float radius; // 圆角像素单位
float thickness; // 线段的宽度
}; };
ParameterBlock<ParamBuffer> param_buffer : register(b0);
struct VSInput { struct VSInput {
float2 position : POSITION; // 窗口坐标 float2 position : POSITION; // 窗口坐标
@ -22,7 +22,8 @@ struct PSInput {
PSInput vertex_main(VSInput input) PSInput vertex_main(VSInput input)
{ {
PSInput output; 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; output.color = input.color;
return output; return output;
} }
@ -30,24 +31,30 @@ PSInput vertex_main(VSInput input)
// 圆角矩形像素着色器 // 圆角矩形像素着色器
float4 pixel_main(PSInput input) : SV_TARGET float4 pixel_main(PSInput input) : SV_TARGET
{ {
// 圆角半径 // 计算input.position到线段p1p2的最短距离
float radius = param_buffer.radius; float2 p = input.uv;
// 计算矩形的中心位置 return float4(p, 0, 1);
float2 rect_center = param_buffer.pos + param_buffer.size * 0.5;
// 计算半尺寸,减去圆角半径
float2 half_size = param_buffer.size * 0.5 - radius;
// 当前像素在视口内位置 // 计算当前片段到线段的距离
float2 pixel_pos = input.position.xy; float2 ba = p2 - p1;
// 将坐标系平移到矩形中心 float2 pa = p - p1;
float2 pos = pixel_pos - rect_center; float2 ba_norm = normalize(ba);
float h = clamp(dot(pa, ba_norm), 0.0, length(ba));
float2 pb = p1 + ba_norm * h;
// 计算距离 float dist = length(p - pb); // 点到线段的距离
float2 d = abs(pos) - half_size; 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 corner_dist = length(max_d);
float inside = length(max(d, 0.0)) - radius; // float corner_alpha = smoothstep(0, 1, corner_dist);
// inside <= 0.0 说明在圆角矩形内 float4 color = input.color;
return input.color * step(inside, 0.0); color.a *= (1 - alpha);
return color;
} }

View File

@ -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<Constants> 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<FontParams> 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;
}

View File

@ -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);
}