封装着色器编译代码命令

编写部分注释
This commit is contained in:
Nanako 2024-11-05 16:48:15 +08:00
parent 498a75c95f
commit f73e7e4a50
13 changed files with 241 additions and 164 deletions

View File

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

View File

@ -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()

View File

@ -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} $<TARGET_FILE_DIR:${PROJECT_NAME}>/resource/shaders
COMMENT "Copying shader files to resource directory after build")

View File

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

View File

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

View File

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

View File

@ -20,7 +20,7 @@ public:
void build_index_buffer(int triangle_count);
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();
void unlock_constant_buffer();

View File

@ -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<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 (draw_test) {
// 生成渐变色
if (is_white) {
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, 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);
}

View File

@ -1,11 +1,12 @@
#pragma once
#include <span>
#include <string>
#include <Eigen/Eigen>
#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<const aorii_vertex_type>& in_vertexes, const std::span<const aorii_triangle_type>& in_triangles) = 0;
};
class custom_pipeline : public pipeline {

View File

@ -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<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 std::filesystem::path get_shader_path(const std::string& shader_name) { return std::filesystem::current_path() / s_shader_relative_path / shader_name; }
}

View File

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

View File

@ -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<aorii_triangle_type>& 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<aorii_vertex_type> vertices;
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;
};

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