封装着色器编译代码命令
编写部分注释
This commit is contained in:
parent
498a75c95f
commit
f73e7e4a50
@ -2,8 +2,6 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
project(aorii)
|
project(aorii)
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
|
||||||
set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/shader)
|
|
||||||
|
|
||||||
include(cmake/retrieve_files.cmake)
|
include(cmake/retrieve_files.cmake)
|
||||||
include(cmake/detect_os.cmake)
|
include(cmake/detect_os.cmake)
|
||||||
include(cmake/configure_glfw_native.cmake)
|
include(cmake/configure_glfw_native.cmake)
|
||||||
@ -29,8 +27,3 @@ if (BUILD_EXAMPLE)
|
|||||||
add_subdirectory(example)
|
add_subdirectory(example)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(SHADER_STAGES
|
|
||||||
"vertex"
|
|
||||||
"pixel"
|
|
||||||
)
|
|
||||||
compile_slang_shaders(${CMAKE_CURRENT_SOURCE_DIR}/resource/shader/default_shader.slang SHADER_STAGES)
|
|
||||||
|
@ -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})
|
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(GL_BACKEND)
|
||||||
if(NOT stage IN_LIST processed_stages)
|
set(output_file ${output_dir}/${filename}_${entry_point}.glsl)
|
||||||
list(APPEND processed_stages ${stage})
|
add_custom_command(
|
||||||
|
OUTPUT ${output_file}
|
||||||
# Define the entry point based on the stage
|
COMMAND slangc -target glsl -entry ${entry_point} -stage ${stage} -o ${output_file} ${input_file}
|
||||||
if(stage STREQUAL "vertex")
|
DEPENDS ${input_file}
|
||||||
set(entry_point "vertex_main")
|
COMMENT "Compiling ${input_file} to GLSL (${stage}, ${entry_point})"
|
||||||
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}
|
|
||||||
)
|
)
|
||||||
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()
|
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()
|
||||||
|
@ -5,3 +5,9 @@ set(SRC_FILES "")
|
|||||||
retrieve_files(src SRC_FILES)
|
retrieve_files(src SRC_FILES)
|
||||||
add_executable(${PROJECT_NAME} ${SRC_FILES})
|
add_executable(${PROJECT_NAME} ${SRC_FILES})
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE aorii_renderer)
|
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} $<TARGET_FILE_DIR:${PROJECT_NAME}>/resource/shaders
|
||||||
|
COMMENT "Copying shader files to resource directory after build")
|
||||||
|
@ -8,7 +8,7 @@ int main(int argc, char* argv[]) {
|
|||||||
aorii::create_renderer(renderer_api::dx11);
|
aorii::create_renderer(renderer_api::dx11);
|
||||||
aorii::create_window_manager();
|
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();
|
auto glfw_window = window->get_glfw_window();
|
||||||
while (!glfwWindowShouldClose(glfw_window)) {
|
while (!glfwWindowShouldClose(glfw_window)) {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
struct MatrixBuffer
|
|
||||||
{
|
|
||||||
matrix transform;
|
|
||||||
};
|
|
||||||
ParameterBlock<MatrixBuffer> 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;
|
|
||||||
}
|
|
@ -54,3 +54,11 @@ foreach(BACKEND ${ALL_BACKENDS})
|
|||||||
target_compile_definitions(${PROJECT_NAME} PUBLIC ${BACKEND}=0)
|
target_compile_definitions(${PROJECT_NAME} PUBLIC ${BACKEND}=0)
|
||||||
endforeach()
|
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})
|
||||||
|
@ -20,7 +20,7 @@ public:
|
|||||||
void build_index_buffer(int triangle_count);
|
void build_index_buffer(int triangle_count);
|
||||||
void build_constant_buffer();
|
void build_constant_buffer();
|
||||||
|
|
||||||
void set_triangle(const std::span<const aorii_vertex_type>& in_vertexes, const std::span<const aorii_triangle_type>& in_triangles);
|
void set_triangle(const std::span<const aorii_vertex_type>& in_vertexes, const std::span<const aorii_triangle_type>& in_triangles) override;
|
||||||
|
|
||||||
aorii_constant_buffer_type* lock_constant_buffer();
|
aorii_constant_buffer_type* lock_constant_buffer();
|
||||||
void unlock_constant_buffer();
|
void unlock_constant_buffer();
|
||||||
|
@ -80,6 +80,7 @@ bool dx_window::create_surface(GLFWwindow* in_window) {
|
|||||||
|
|
||||||
pipeline.load_pixel_shader();
|
pipeline.load_pixel_shader();
|
||||||
pipeline.load_vertex_shader();
|
pipeline.load_vertex_shader();
|
||||||
|
context.set_default_pipeline(&pipeline);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -103,15 +104,7 @@ void dx_window::begin_frame() {
|
|||||||
static float pos_y = 0;
|
static float pos_y = 0;
|
||||||
static bool draw_test = true;
|
static bool draw_test = true;
|
||||||
|
|
||||||
auto delta_time = get_delta_time();
|
if (draw_test) {
|
||||||
|
|
||||||
timer += delta_time;
|
|
||||||
if (draw_test && timer.count() >= 0.01) {
|
|
||||||
// float random_r = static_cast<float>(rand()) / RAND_MAX;
|
|
||||||
// float random_g = static_cast<float>(rand()) / RAND_MAX;
|
|
||||||
// float random_b = static_cast<float>(rand()) / RAND_MAX;
|
|
||||||
// random_color = { random_r, random_g, random_b, 1.0f };
|
|
||||||
|
|
||||||
// 生成渐变色
|
// 生成渐变色
|
||||||
if (is_white) {
|
if (is_white) {
|
||||||
if (random_color.r > 0) {
|
if (random_color.r > 0) {
|
||||||
@ -139,20 +132,16 @@ void dx_window::begin_frame() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timer -= std::chrono::duration<double>(0.01);
|
context.draw_rectangle({ pos_x, pos_y }, { 1, 100 }, random_color);
|
||||||
context.draw_rectangle({pos_x, pos_y}, {1, 1000}, 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);
|
swap_chain->Present(1, 0);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <Eigen/Eigen>
|
#include <Eigen/Eigen>
|
||||||
|
|
||||||
#include "misc/color.h"
|
#include "misc/color.h"
|
||||||
|
|
||||||
#define AORII_DEFAULT_PIXEL_SHADER_NAME "default_shader_pixel"
|
#define AORII_DEFAULT_PIXEL_SHADER_NAME "default_shader_pixel_main"
|
||||||
#define AORII_DEFAULT_VERTEX_SHADER_NAME "default_shader_vertex"
|
#define AORII_DEFAULT_VERTEX_SHADER_NAME "default_shader_vertex_main"
|
||||||
|
|
||||||
struct aorii_vertex {
|
struct aorii_vertex {
|
||||||
Eigen::Vector2f position;
|
Eigen::Vector2f position;
|
||||||
@ -28,6 +29,8 @@ public:
|
|||||||
|
|
||||||
virtual void use() = 0;
|
virtual void use() = 0;
|
||||||
virtual void draw() = 0;
|
virtual void draw() = 0;
|
||||||
|
|
||||||
|
virtual void set_triangle(const std::span<const aorii_vertex_type>& in_vertexes, const std::span<const aorii_triangle_type>& in_triangles) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class custom_pipeline : public pipeline {
|
class custom_pipeline : public pipeline {
|
||||||
|
@ -13,10 +13,6 @@ enum class renderer_api {
|
|||||||
metal,
|
metal,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vertex_data {
|
|
||||||
Eigen::Vector3f position;
|
|
||||||
};
|
|
||||||
|
|
||||||
class renderer {
|
class renderer {
|
||||||
friend class window_manager;
|
friend class window_manager;
|
||||||
public:
|
public:
|
||||||
@ -49,7 +45,7 @@ namespace aorii {
|
|||||||
|
|
||||||
const std::chrono::duration<double>& get_delta_time();
|
const std::chrono::duration<double>& 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 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; }
|
inline std::filesystem::path get_shader_path(const std::string& shader_name) { return std::filesystem::current_path() / s_shader_relative_path / shader_name; }
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
#include "renderer_context.h"
|
#include "renderer_context.h"
|
||||||
|
|
||||||
void renderer_context::draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size,
|
void renderer_context::draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color) {
|
||||||
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 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 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 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 aorii_vertex_type v4 {{in_pos.x() + in_size.x(), in_pos.y() + in_size.y()}, in_color }; // 右下角
|
|
||||||
|
|
||||||
const uint32_t index1 = vertices.size();
|
const uint32_t index1 = vertices.size();
|
||||||
vertices.push_back(v1);
|
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();
|
const uint32_t index4 = vertices.size();
|
||||||
vertices.push_back(v4);
|
vertices.push_back(v4);
|
||||||
|
|
||||||
const aorii_triangle_type t1 = {index1, index2, index3};
|
const aorii_triangle_type t1 = { index1, index2, index3 };
|
||||||
const aorii_triangle_type t2 = {index2, index3, index4};
|
const aorii_triangle_type t2 = { index2, index3, index4 };
|
||||||
triangles.push_back(t1);
|
triangles.push_back(t1);
|
||||||
triangles.push_back(t2);
|
triangles.push_back(t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderer_context::draw_line(const Eigen::Vector2i& in_pos_p1, const Eigen::Vector2i& in_pos_p2,
|
void renderer_context::draw_rounded_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color, float in_radius) {
|
||||||
const linear_color& in_color, float in_thickness) {
|
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<float>().normalized();
|
const Eigen::Vector2f direction = (in_pos_p2 - in_pos_p1).cast<float>().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 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 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 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 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 v4{ { in_pos_p2.x() - offset.x(), in_pos_p2.y() - offset.y() }, in_color };
|
||||||
|
|
||||||
const uint32_t index1 = vertices.size();
|
const uint32_t index1 = vertices.size();
|
||||||
vertices.push_back(v1);
|
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();
|
const uint32_t index4 = vertices.size();
|
||||||
vertices.push_back(v4);
|
vertices.push_back(v4);
|
||||||
|
|
||||||
const aorii_triangle_type t1 = {index1, index2, index3};
|
const aorii_triangle_type t1 = { index1, index2, index3 };
|
||||||
const aorii_triangle_type t2 = {index2, index3, index4};
|
const aorii_triangle_type t2 = { index2, index3, index4 };
|
||||||
triangles.push_back(t1);
|
triangles.push_back(t1);
|
||||||
triangles.push_back(t2);
|
triangles.push_back(t2);
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,36 @@
|
|||||||
|
|
||||||
class renderer_context {
|
class renderer_context {
|
||||||
public:
|
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);
|
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 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() {
|
void clear() {
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
triangles.clear();
|
triangles.clear();
|
||||||
@ -19,8 +46,26 @@ public:
|
|||||||
[[nodiscard]] const std::vector<aorii_triangle_type>& get_triangles() const {
|
[[nodiscard]] const std::vector<aorii_triangle_type>& get_triangles() const {
|
||||||
return triangles;
|
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:
|
private:
|
||||||
std::vector<aorii_vertex_type> vertices;
|
std::vector<aorii_vertex_type> vertices;
|
||||||
std::vector<aorii_triangle_type> triangles;
|
std::vector<aorii_triangle_type> 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;
|
||||||
};
|
};
|
||||||
|
63
src/renderer/shader/default_shader.slang
Normal file
63
src/renderer/shader/default_shader.slang
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
struct MatrixBuffer
|
||||||
|
{
|
||||||
|
matrix transform;
|
||||||
|
};
|
||||||
|
struct RoundedRectBuffer
|
||||||
|
{
|
||||||
|
float2 size; // 像素单位
|
||||||
|
float radius; // 像素单位
|
||||||
|
};
|
||||||
|
ParameterBlock<MatrixBuffer> matrix_buffer : register(b0);
|
||||||
|
ParameterBlock<RoundedRectBuffer> 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);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user