测试代码
This commit is contained in:
327
shaders/common_2d.slang
Normal file
327
shaders/common_2d.slang
Normal file
@@ -0,0 +1,327 @@
|
||||
// =============================================================================
|
||||
// SDL 2D Shader Common Definitions
|
||||
// 全局变量和通用功能定义
|
||||
// =============================================================================
|
||||
|
||||
#ifndef SDL_2D_COMMON_H
|
||||
#define SDL_2D_COMMON_H
|
||||
|
||||
// =============================================================================
|
||||
// 平台检测和资源绑定宏
|
||||
// =============================================================================
|
||||
|
||||
#ifdef METAL_TARGET
|
||||
// Metal使用统一索引空间
|
||||
#define BIND_VERTEX_TEXTURE(slot) register(t##slot)
|
||||
#define BIND_VERTEX_SAMPLER(slot) register(s##slot)
|
||||
#define BIND_VERTEX_BUFFER(slot) register(b##slot)
|
||||
#define BIND_VERTEX_STORAGE(slot) register(u##slot)
|
||||
|
||||
#define BIND_PIXEL_TEXTURE(slot) register(t##slot)
|
||||
#define BIND_PIXEL_SAMPLER(slot) register(s##slot)
|
||||
#define BIND_PIXEL_BUFFER(slot) register(b##slot)
|
||||
#define BIND_PIXEL_STORAGE(slot) register(u##slot)
|
||||
#else
|
||||
// Vulkan/DirectX 使用分离空间
|
||||
#define BIND_VERTEX_TEXTURE(slot) register(t##slot, space0)
|
||||
#define BIND_VERTEX_SAMPLER(slot) register(s##slot, space0)
|
||||
#define BIND_VERTEX_BUFFER(slot) register(b##slot, space1)
|
||||
#define BIND_VERTEX_STORAGE(slot) register(u##slot, space0)
|
||||
|
||||
#define BIND_PIXEL_TEXTURE(slot) register(t##slot, space2)
|
||||
#define BIND_PIXEL_SAMPLER(slot) register(s##slot, space2)
|
||||
#define BIND_PIXEL_BUFFER(slot) register(b##slot, space3)
|
||||
#define BIND_PIXEL_STORAGE(slot) register(u##slot, space2)
|
||||
#endif
|
||||
|
||||
// =============================================================================
|
||||
// 数学常量
|
||||
// =============================================================================
|
||||
|
||||
static const float PI = 3.14159265359;
|
||||
static const float TWO_PI = 6.28318530718;
|
||||
static const float HALF_PI = 1.57079632679;
|
||||
static const float INV_PI = 0.31830988618;
|
||||
static const float EPSILON = 1e-6;
|
||||
static const float GAMMA = 2.2;
|
||||
static const float INV_GAMMA = 0.454545;
|
||||
|
||||
// =============================================================================
|
||||
// 标准2D顶点格式
|
||||
// =============================================================================
|
||||
|
||||
struct Vertex2D {
|
||||
float2 position; // 位置
|
||||
float2 texCoord; // 纹理坐标
|
||||
float4 color; // 顶点颜色
|
||||
};
|
||||
|
||||
struct VertexShaderOutput {
|
||||
float4 clipPos : SV_Position;
|
||||
float2 texCoord : TEXCOORD0;
|
||||
float4 color : TEXCOORD1;
|
||||
float2 worldPos : TEXCOORD2; // 世界空间位置(用于特效)
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// 全局Uniform缓冲区结构
|
||||
// =============================================================================
|
||||
|
||||
// 场景级别的全局数据
|
||||
struct SceneGlobals {
|
||||
float4x4 viewProjection; // 视图投影矩阵
|
||||
float4x4 invViewProjection; // 逆视图投影矩阵
|
||||
float2 screenSize; // 屏幕尺寸
|
||||
float2 invScreenSize; // 1.0 / 屏幕尺寸
|
||||
float time; // 当前时间(秒)
|
||||
float deltaTime; // 帧时间
|
||||
float2 _padding0;
|
||||
};
|
||||
|
||||
// 每个绘制调用的数据
|
||||
struct DrawCallData {
|
||||
float4x4 modelMatrix; // 模型矩阵
|
||||
float4 tintColor; // 色调
|
||||
float4 uvTransform; // UV变换 (offset.xy, scale.xy)
|
||||
float2 pivot; // 旋转中心点
|
||||
float rotation; // 旋转角度(弧度)
|
||||
float _padding1;
|
||||
};
|
||||
|
||||
// 材质参数
|
||||
struct MaterialParams {
|
||||
float4 baseColor; // 基础颜色
|
||||
float opacity; // 不透明度
|
||||
float brightness; // 亮度
|
||||
float contrast; // 对比度
|
||||
float saturation; // 饱和度
|
||||
float hue; // 色相偏移
|
||||
float bloomIntensity; // 泛光强度
|
||||
float2 distortionAmount; // 扭曲程度
|
||||
};
|
||||
|
||||
// 特效参数
|
||||
struct EffectParams {
|
||||
float4 glowColor; // 发光颜色
|
||||
float glowSize; // 发光大小
|
||||
float shadowSoftness; // 阴影柔和度
|
||||
float shadowDistance; // 阴影距离
|
||||
float shadowAngle; // 阴影角度
|
||||
float4 gradientColors[4]; // 渐变颜色(最多4个)
|
||||
float gradientStops[4]; // 渐变停止点
|
||||
float noiseScale; // 噪声缩放
|
||||
float noiseIntensity; // 噪声强度
|
||||
float2 _padding2;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// 全局资源声明宏
|
||||
// =============================================================================
|
||||
|
||||
// 顶点着色器全局资源
|
||||
#define DECLARE_VERTEX_GLOBALS \
|
||||
ConstantBuffer<SceneGlobals> g_scene : BIND_VERTEX_BUFFER(0); \
|
||||
ConstantBuffer<DrawCallData> g_draw : BIND_VERTEX_BUFFER(1);
|
||||
|
||||
// 像素着色器全局资源
|
||||
#define DECLARE_PIXEL_GLOBALS \
|
||||
ConstantBuffer<SceneGlobals> g_scene : BIND_PIXEL_BUFFER(0); \
|
||||
ConstantBuffer<MaterialParams> g_material : BIND_PIXEL_BUFFER(1); \
|
||||
ConstantBuffer<EffectParams> g_effect : BIND_PIXEL_BUFFER(2);
|
||||
|
||||
// 标准纹理资源
|
||||
#define DECLARE_STANDARD_TEXTURES \
|
||||
Texture2D g_mainTexture : BIND_PIXEL_TEXTURE(0); \
|
||||
Texture2D g_normalTexture : BIND_PIXEL_TEXTURE(1); \
|
||||
Texture2D g_maskTexture : BIND_PIXEL_TEXTURE(2); \
|
||||
Texture2D g_noiseTexture : BIND_PIXEL_TEXTURE(3); \
|
||||
SamplerState g_linearSampler : BIND_PIXEL_SAMPLER(0); \
|
||||
SamplerState g_pointSampler : BIND_PIXEL_SAMPLER(1); \
|
||||
SamplerState g_linearClampSampler : BIND_PIXEL_SAMPLER(2); \
|
||||
SamplerState g_pointClampSampler : BIND_PIXEL_SAMPLER(3);
|
||||
|
||||
// =============================================================================
|
||||
// 实用函数库
|
||||
// =============================================================================
|
||||
|
||||
// 2D变换函数
|
||||
float2 rotate2D(float2 v, float angle) {
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
return float2(
|
||||
v.x * c - v.y * s,
|
||||
v.x * s + v.y * c
|
||||
);
|
||||
}
|
||||
|
||||
float2 scale2D(float2 v, float2 scale) {
|
||||
return v * scale;
|
||||
}
|
||||
|
||||
float2 translate2D(float2 v, float2 offset) {
|
||||
return v + offset;
|
||||
}
|
||||
|
||||
// UV坐标变换
|
||||
float2 transformUV(float2 uv, float4 uvTransform) {
|
||||
return uv * uvTransform.zw + uvTransform.xy;
|
||||
}
|
||||
|
||||
// 颜色空间转换
|
||||
float3 sRGBToLinear(float3 color) {
|
||||
return pow(color, float3(GAMMA));
|
||||
}
|
||||
|
||||
float3 linearToSRGB(float3 color) {
|
||||
return pow(color, float3(INV_GAMMA));
|
||||
}
|
||||
|
||||
float4 sRGBToLinear(float4 color) {
|
||||
return float4(sRGBToLinear(color.rgb), color.a);
|
||||
}
|
||||
|
||||
float4 linearToSRGB(float4 color) {
|
||||
return float4(linearToSRGB(color.rgb), color.a);
|
||||
}
|
||||
|
||||
// HSV颜色空间
|
||||
float3 rgbToHSV(float3 rgb) {
|
||||
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||
float4 p = lerp(float4(rgb.bg, K.wz), float4(rgb.gb, K.xy), step(rgb.b, rgb.g));
|
||||
float4 q = lerp(float4(p.xyw, rgb.r), float4(rgb.r, p.yzx), step(p.x, rgb.r));
|
||||
|
||||
float d = q.x - min(q.w, q.y);
|
||||
float e = EPSILON;
|
||||
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||
}
|
||||
|
||||
float3 hsvToRGB(float3 hsv) {
|
||||
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
float3 p = abs(frac(hsv.xxx + K.xyz) * 6.0 - K.www);
|
||||
return hsv.z * lerp(K.xxx, saturate(p - K.xxx), hsv.y);
|
||||
}
|
||||
|
||||
// 颜色调整函数
|
||||
float3 adjustBrightness(float3 color, float brightness) {
|
||||
return color * brightness;
|
||||
}
|
||||
|
||||
float3 adjustContrast(float3 color, float contrast) {
|
||||
return (color - 0.5) * contrast + 0.5;
|
||||
}
|
||||
|
||||
float3 adjustSaturation(float3 color, float saturation) {
|
||||
float gray = dot(color, float3(0.299, 0.587, 0.114));
|
||||
return lerp(float3(gray), color, saturation);
|
||||
}
|
||||
|
||||
float3 adjustHue(float3 color, float hueShift) {
|
||||
float3 hsv = rgbToHSV(color);
|
||||
hsv.x = frac(hsv.x + hueShift);
|
||||
return hsvToRGB(hsv);
|
||||
}
|
||||
|
||||
// 混合模式
|
||||
float3 blendNormal(float3 base, float3 blend, float opacity) {
|
||||
return lerp(base, blend, opacity);
|
||||
}
|
||||
|
||||
float3 blendMultiply(float3 base, float3 blend, float opacity) {
|
||||
return lerp(base, base * blend, opacity);
|
||||
}
|
||||
|
||||
float3 blendScreen(float3 base, float3 blend, float opacity) {
|
||||
return lerp(base, 1.0 - (1.0 - base) * (1.0 - blend), opacity);
|
||||
}
|
||||
|
||||
float3 blendOverlay(float3 base, float3 blend, float opacity) {
|
||||
float3 result = lerp(
|
||||
2.0 * base * blend,
|
||||
1.0 - 2.0 * (1.0 - base) * (1.0 - blend),
|
||||
step(0.5, base)
|
||||
);
|
||||
return lerp(base, result, opacity);
|
||||
}
|
||||
|
||||
// 抗锯齿函数
|
||||
float smootherstep(float edge0, float edge1, float x) {
|
||||
x = saturate((x - edge0) / (edge1 - edge0));
|
||||
return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
|
||||
}
|
||||
|
||||
// SDF相关函数
|
||||
float sdCircle(float2 p, float r) {
|
||||
return length(p) - r;
|
||||
}
|
||||
|
||||
float sdBox(float2 p, float2 b) {
|
||||
float2 d = abs(p) - b;
|
||||
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
|
||||
}
|
||||
|
||||
float sdRoundedBox(float2 p, float2 b, float r) {
|
||||
float2 q = abs(p) - b + r;
|
||||
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 标准顶点着色器模板
|
||||
// =============================================================================
|
||||
|
||||
#define STANDARD_VERTEX_SHADER(name) \
|
||||
DECLARE_VERTEX_GLOBALS \
|
||||
\
|
||||
[shader("vertex")] \
|
||||
VertexShaderOutput name(Vertex2D input) { \
|
||||
VertexShaderOutput output; \
|
||||
\
|
||||
float2 pos = input.position; \
|
||||
\
|
||||
/* 应用旋转 */ \
|
||||
if (abs(g_draw.rotation) > EPSILON) { \
|
||||
pos -= g_draw.pivot; \
|
||||
pos = rotate2D(pos, g_draw.rotation); \
|
||||
pos += g_draw.pivot; \
|
||||
} \
|
||||
\
|
||||
/* 应用模型变换 */ \
|
||||
float4 worldPos = mul(g_draw.modelMatrix, float4(pos, 0.0, 1.0)); \
|
||||
output.clipPos = mul(g_scene.viewProjection, worldPos); \
|
||||
output.worldPos = worldPos.xy; \
|
||||
\
|
||||
/* UV变换 */ \
|
||||
output.texCoord = transformUV(input.texCoord, g_draw.uvTransform); \
|
||||
\
|
||||
/* 颜色 */ \
|
||||
output.color = input.color * g_draw.tintColor; \
|
||||
\
|
||||
return output; \
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 标准像素着色器模板
|
||||
// =============================================================================
|
||||
|
||||
#define STANDARD_PIXEL_SHADER(name, code) \
|
||||
DECLARE_PIXEL_GLOBALS \
|
||||
DECLARE_STANDARD_TEXTURES \
|
||||
\
|
||||
[shader("fragment")] \
|
||||
float4 name(VertexShaderOutput input) : SV_Target { \
|
||||
float4 color = g_mainTexture.Sample(g_linearSampler, input.texCoord); \
|
||||
color *= input.color; \
|
||||
\
|
||||
/* 用户代码 */ \
|
||||
code \
|
||||
\
|
||||
/* 应用材质参数 */ \
|
||||
color.rgb = adjustBrightness(color.rgb, g_material.brightness); \
|
||||
color.rgb = adjustContrast(color.rgb, g_material.contrast); \
|
||||
color.rgb = adjustSaturation(color.rgb, g_material.saturation); \
|
||||
color.rgb = adjustHue(color.rgb, g_material.hue); \
|
||||
color.a *= g_material.opacity; \
|
||||
\
|
||||
return color; \
|
||||
}
|
||||
|
||||
#endif // SDL_2D_COMMON_H
|
||||
110
shaders/core.slang
Normal file
110
shaders/core.slang
Normal file
@@ -0,0 +1,110 @@
|
||||
// =============================================================================
|
||||
// sprite_shader.slang - 使用全局变量的精灵着色器
|
||||
// =============================================================================
|
||||
|
||||
#include "common_2d.slang"
|
||||
|
||||
// 自动生成标准顶点着色器
|
||||
STANDARD_VERTEX_SHADER(vertexMain)
|
||||
|
||||
// 简单的像素着色器
|
||||
STANDARD_PIXEL_SHADER(pixelMain, {
|
||||
// 这里可以添加自定义代码
|
||||
// color 变量已经包含了采样后的纹理颜色
|
||||
})
|
||||
|
||||
// 带发光效果的像素着色器
|
||||
DECLARE_PIXEL_GLOBALS
|
||||
DECLARE_STANDARD_TEXTURES
|
||||
|
||||
[shader("fragment")]
|
||||
float4 pixelMainGlow(VertexShaderOutput input) : SV_Target {
|
||||
float4 color = g_mainTexture.Sample(g_linearSampler, input.texCoord);
|
||||
color *= input.color;
|
||||
|
||||
// 发光效果
|
||||
if (g_effect.glowSize > 0.0) {
|
||||
float2 texelSize = g_scene.invScreenSize;
|
||||
float4 glow = float4(0.0);
|
||||
|
||||
// 简单的发光采样
|
||||
for (int y = -2; y <= 2; y++) {
|
||||
for (int x = -2; x <= 2; x++) {
|
||||
float2 offset = float2(x, y) * texelSize * g_effect.glowSize;
|
||||
float4 sample = g_mainTexture.Sample(g_linearSampler, input.texCoord + offset);
|
||||
float weight = 1.0 / (1.0 + length(float2(x, y)));
|
||||
glow += sample * weight;
|
||||
}
|
||||
}
|
||||
|
||||
glow *= g_effect.glowColor;
|
||||
color.rgb += glow.rgb * g_effect.glowColor.a;
|
||||
}
|
||||
|
||||
// 应用标准材质参数
|
||||
color.rgb = adjustBrightness(color.rgb, g_material.brightness);
|
||||
color.rgb = adjustContrast(color.rgb, g_material.contrast);
|
||||
color.rgb = adjustSaturation(color.rgb, g_material.saturation);
|
||||
color.a *= g_material.opacity;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
// 文字渲染着色器
|
||||
DECLARE_PIXEL_GLOBALS
|
||||
DECLARE_STANDARD_TEXTURES
|
||||
|
||||
[shader("fragment")]
|
||||
float4 pixelMainText(VertexShaderOutput input) : SV_Target {
|
||||
// 文字通常存储在alpha通道
|
||||
float alpha = g_mainTexture.Sample(g_linearSampler, input.texCoord).a;
|
||||
|
||||
// SDF文字渲染
|
||||
float distance = alpha;
|
||||
float smoothing = fwidth(distance) * 0.75;
|
||||
alpha = smootherstep(0.5 - smoothing, 0.5 + smoothing, distance);
|
||||
|
||||
// 应用颜色
|
||||
float4 color = float4(input.color.rgb, input.color.a * alpha);
|
||||
|
||||
// 文字阴影
|
||||
if (g_effect.shadowDistance > 0.0) {
|
||||
float2 shadowOffset = float2(
|
||||
cos(g_effect.shadowAngle),
|
||||
sin(g_effect.shadowAngle)
|
||||
) * g_effect.shadowDistance * g_scene.invScreenSize;
|
||||
|
||||
float shadowAlpha = g_mainTexture.Sample(g_linearSampler, input.texCoord - shadowOffset).a;
|
||||
shadowAlpha = smootherstep(0.5 - smoothing * g_effect.shadowSoftness, 0.5 + smoothing * g_effect.shadowSoftness, shadowAlpha);
|
||||
|
||||
// 混合阴影
|
||||
color.rgb = lerp(float3(0.0, 0.0, 0.0), color.rgb, alpha);
|
||||
color.a = max(color.a, shadowAlpha * 0.5);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
// 形状渲染着色器(使用SDF)
|
||||
DECLARE_PIXEL_GLOBALS
|
||||
|
||||
[shader("fragment")]
|
||||
float4 pixelMainShape(VertexShaderOutput input) : SV_Target {
|
||||
float2 p = input.texCoord * 2.0 - 1.0; // 转换到[-1, 1]空间
|
||||
|
||||
// 圆角矩形SDF
|
||||
float d = sdRoundedBox(p, float2(0.8, 0.6), 0.1);
|
||||
|
||||
// 抗锯齿边缘
|
||||
float alpha = 1.0 - smoothstep(-0.01, 0.01, d);
|
||||
|
||||
// 渐变填充
|
||||
float gradient = (p.y + 1.0) * 0.5;
|
||||
float3 color = lerp(
|
||||
g_effect.gradientColors[0].rgb,
|
||||
g_effect.gradientColors[1].rgb,
|
||||
gradient
|
||||
);
|
||||
|
||||
return float4(color * input.color.rgb, alpha * input.color.a * g_material.opacity);
|
||||
}
|
||||
221
shaders/test.slang
Normal file
221
shaders/test.slang
Normal file
@@ -0,0 +1,221 @@
|
||||
// ===== 平台检测 =====
|
||||
#ifdef __METAL_VERSION__
|
||||
#define METAL_PLATFORM
|
||||
#endif
|
||||
|
||||
#ifdef SPIRV
|
||||
#define SPIRV_PLATFORM
|
||||
#endif
|
||||
|
||||
// ===== 基础类型定义 =====
|
||||
#ifdef METAL_PLATFORM
|
||||
// Metal类型别名
|
||||
typealias Texture2D_float = texture2d<float>;
|
||||
typealias Texture2D_float4 = texture2d<float4>;
|
||||
typealias RWTexture2D_float4 = texture2d<float4, access::read_write>;
|
||||
typealias SamplerState = sampler;
|
||||
|
||||
// Metal属性包装器
|
||||
struct MetalAttribute<T> {
|
||||
T value;
|
||||
};
|
||||
#else
|
||||
// HLSL/SPIR-V使用原生类型
|
||||
typealias Texture2D_float = Texture2D<float>;
|
||||
typealias Texture2D_float4 = Texture2D<float4>;
|
||||
typealias RWTexture2D_float4 = RWTexture2D<float4>;
|
||||
#endif
|
||||
|
||||
// ===== 资源声明辅助函数 =====
|
||||
|
||||
// 顶点着色器资源
|
||||
#ifdef METAL_PLATFORM
|
||||
#define VERTEX_TEXTURE(Type, Name, Binding) \
|
||||
[[texture(Binding)]] Type Name
|
||||
|
||||
#define VERTEX_SAMPLER(Name, Binding) \
|
||||
[[sampler(Binding)]] sampler Name
|
||||
|
||||
#define VERTEX_STORAGE_TEXTURE(Type, Name, Binding) \
|
||||
[[texture(Binding)]] texture2d<Type, access::read_write> Name
|
||||
|
||||
#define VERTEX_UNIFORM_BUFFER(Type, Name, Binding) \
|
||||
[[buffer(Binding)]] constant Type& Name
|
||||
|
||||
#define VERTEX_STORAGE_BUFFER(Type, Name, Binding) \
|
||||
[[buffer(Binding)]] device Type* Name
|
||||
#else
|
||||
#define VERTEX_TEXTURE(Type, Name, Binding) \
|
||||
[[vk::binding(Binding, 0)]] \
|
||||
Type Name : register(t##Binding, space0)
|
||||
|
||||
#define VERTEX_SAMPLER(Name, Binding) \
|
||||
[[vk::binding(Binding, 0)]] \
|
||||
SamplerState Name : register(s##Binding, space0)
|
||||
|
||||
#define VERTEX_STORAGE_TEXTURE(Type, Name, Binding) \
|
||||
[[vk::binding(Binding, 0)]] \
|
||||
RWTexture2D<Type> Name : register(t##Binding, space0)
|
||||
|
||||
#define VERTEX_UNIFORM_BUFFER(Type, Name, Binding) \
|
||||
[[vk::binding(Binding, 1)]] \
|
||||
ConstantBuffer<Type> Name : register(b##Binding, space1)
|
||||
|
||||
#define VERTEX_STORAGE_BUFFER(Type, Name, Binding) \
|
||||
[[vk::binding(Binding, 0)]] \
|
||||
RWStructuredBuffer<Type> Name : register(t##Binding, space0)
|
||||
#endif
|
||||
|
||||
// 片元着色器资源
|
||||
#ifdef METAL_PLATFORM
|
||||
#define FRAGMENT_TEXTURE(Type, Name, Binding) \
|
||||
[[texture(Binding)]] Type Name
|
||||
|
||||
#define FRAGMENT_SAMPLER(Name, Binding) \
|
||||
[[sampler(Binding)]] sampler Name
|
||||
|
||||
#define FRAGMENT_STORAGE_TEXTURE(Type, Name, Binding) \
|
||||
[[texture(Binding)]] texture2d<Type, access::read_write> Name
|
||||
|
||||
#define FRAGMENT_UNIFORM_BUFFER(Type, Name, Binding) \
|
||||
[[buffer(Binding)]] constant Type& Name
|
||||
|
||||
#define FRAGMENT_STORAGE_BUFFER(Type, Name, Binding) \
|
||||
[[buffer(Binding)]] device Type* Name
|
||||
#else
|
||||
#define FRAGMENT_TEXTURE(Type, Name, Binding) \
|
||||
[[vk::binding(Binding, 2)]] \
|
||||
Type Name : register(t##Binding, space2)
|
||||
|
||||
#define FRAGMENT_SAMPLER(Name, Binding) \
|
||||
[[vk::binding(Binding, 2)]] \
|
||||
SamplerState Name : register(s##Binding, space2)
|
||||
|
||||
#define FRAGMENT_STORAGE_TEXTURE(Type, Name, Binding) \
|
||||
[[vk::binding(Binding, 2)]] \
|
||||
RWTexture2D<Type> Name : register(t##Binding, space2)
|
||||
|
||||
#define FRAGMENT_UNIFORM_BUFFER(Type, Name, Binding) \
|
||||
[[vk::binding(Binding, 3)]] \
|
||||
ConstantBuffer<Type> Name : register(b##Binding, space3)
|
||||
|
||||
#define FRAGMENT_STORAGE_BUFFER(Type, Name, Binding) \
|
||||
[[vk::binding(Binding, 2)]] \
|
||||
RWStructuredBuffer<Type> Name : register(t##Binding, space2)
|
||||
#endif
|
||||
|
||||
// ===== 更灵活的Slang风格接口方案 =====
|
||||
|
||||
// 定义资源接口
|
||||
interface IShaderResources {
|
||||
// 这里可以定义通用的资源访问方法
|
||||
}
|
||||
|
||||
// 顶点着色器资源包装器
|
||||
struct VertexResources : IShaderResources {
|
||||
// 根据目标平台选择不同的实现
|
||||
#ifdef METAL_PLATFORM
|
||||
struct Textures {
|
||||
[[texture(0)]] texture2d<float> tex0;
|
||||
[[texture(1)]] texture2d<float> tex1;
|
||||
};
|
||||
|
||||
struct Samplers {
|
||||
[[sampler(0)]] sampler samp0;
|
||||
[[sampler(1)]] sampler samp1;
|
||||
};
|
||||
|
||||
struct Uniforms<T> {
|
||||
[[buffer(0)]] constant T& data;
|
||||
};
|
||||
#else
|
||||
struct Textures {
|
||||
[[vk::binding(0, 0)]] Texture2D tex0 : register(t0, space0);
|
||||
[[vk::binding(1, 0)]] Texture2D tex1 : register(t1, space0);
|
||||
};
|
||||
|
||||
struct Samplers {
|
||||
[[vk::binding(0, 0)]] SamplerState samp0 : register(s0, space0);
|
||||
[[vk::binding(1, 0)]] SamplerState samp1 : register(s1, space0);
|
||||
};
|
||||
|
||||
struct Uniforms<T> {
|
||||
[[vk::binding(0, 1)]] ConstantBuffer<T> data : register(b0, space1);
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
// 片元着色器资源包装器
|
||||
struct FragmentResources : IShaderResources {
|
||||
#ifdef METAL_PLATFORM
|
||||
struct Textures {
|
||||
[[texture(0)]] texture2d<float> tex0;
|
||||
[[texture(1)]] texture2d<float> tex1;
|
||||
};
|
||||
|
||||
struct Samplers {
|
||||
[[sampler(0)]] sampler samp0;
|
||||
[[sampler(1)]] sampler samp1;
|
||||
};
|
||||
|
||||
struct Uniforms<T> {
|
||||
[[buffer(0)]] constant T& data;
|
||||
};
|
||||
#else
|
||||
struct Textures {
|
||||
[[vk::binding(0, 2)]] Texture2D tex0 : register(t0, space2);
|
||||
[[vk::binding(1, 2)]] Texture2D tex1 : register(t1, space2);
|
||||
};
|
||||
|
||||
struct Samplers {
|
||||
[[vk::binding(0, 2)]] SamplerState samp0 : register(s0, space2);
|
||||
[[vk::binding(1, 2)]] SamplerState samp1 : register(s1, space2);
|
||||
};
|
||||
|
||||
struct Uniforms<T> {
|
||||
[[vk::binding(0, 3)]] ConstantBuffer<T> data : register(b0, space3);
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
// ===== 使用示例 =====
|
||||
/*
|
||||
// 定义统一数据结构
|
||||
struct MyVertexUniforms {
|
||||
float4x4 mvpMatrix;
|
||||
float4 color;
|
||||
};
|
||||
|
||||
struct MyFragmentUniforms {
|
||||
float4 tintColor;
|
||||
float opacity;
|
||||
};
|
||||
|
||||
// 顶点着色器
|
||||
VERTEX_TEXTURE(Texture2D, vertexTexture, 0);
|
||||
VERTEX_SAMPLER(vertexSampler, 0);
|
||||
VERTEX_UNIFORM_BUFFER(MyVertexUniforms, vertexUniforms, 0);
|
||||
|
||||
// 或者使用结构化方式
|
||||
VertexResources::Textures vertTextures;
|
||||
VertexResources::Samplers vertSamplers;
|
||||
VertexResources::Uniforms<MyVertexUniforms> vertUniforms;
|
||||
|
||||
// 片元着色器
|
||||
FRAGMENT_TEXTURE(Texture2D, fragmentTexture, 0);
|
||||
FRAGMENT_SAMPLER(fragmentSampler, 0);
|
||||
FRAGMENT_UNIFORM_BUFFER(MyFragmentUniforms, fragmentUniforms, 0);
|
||||
|
||||
// 着色器函数
|
||||
[shader("vertex")]
|
||||
float4 vertexMain(float3 position : POSITION) : SV_Position {
|
||||
float4 color = vertexTexture.Sample(vertexSampler, float2(0.5, 0.5));
|
||||
return mul(vertexUniforms.mvpMatrix, float4(position, 1.0));
|
||||
}
|
||||
|
||||
[shader("fragment")]
|
||||
float4 fragmentMain(float2 uv : TEXCOORD0) : SV_Target {
|
||||
float4 color = fragmentTexture.Sample(fragmentSampler, uv);
|
||||
return color * fragmentUniforms.tintColor * fragmentUniforms.opacity;
|
||||
}
|
||||
*/
|
||||
26
src/main.cpp
26
src/main.cpp
@@ -6,6 +6,7 @@
|
||||
#include "SDL3/SDL_video.h"
|
||||
#include "SDL3/SDL_log.h"
|
||||
#include "SDL3/SDL_timer.h"
|
||||
#include "SDL3/SDL_gpu.h"
|
||||
#include "SDL3_ttf/SDL_ttf.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
@@ -15,12 +16,13 @@ int main(int argc, char* argv[]) {
|
||||
SDL_Log("Could not create window: %s", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
SDL_Renderer* renderer = SDL_CreateRenderer(window, "direct3d11");
|
||||
SDL_Renderer* renderer = SDL_CreateRenderer(window, "direct3d12,metal,vulkan");
|
||||
if (renderer == nullptr) {
|
||||
SDL_Log("Could not create renderer: %s", SDL_GetError());
|
||||
SDL_DestroyWindow(window);
|
||||
return 1;
|
||||
}
|
||||
auto gpu_device = (SDL_GPUDevice*)SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_GPU_DEVICE_POINTER, NULL);
|
||||
|
||||
TTF_Init();
|
||||
|
||||
@@ -32,7 +34,7 @@ int main(int argc, char* argv[]) {
|
||||
return 1;
|
||||
}
|
||||
// 设置字体hinting为轻量级
|
||||
TTF_SetFontHinting(font, TTF_HINTING_LIGHT);
|
||||
TTF_SetFontHinting(font, TTF_HINTING_LIGHT_SUBPIXEL);
|
||||
// 设置字体为 SDF 模式
|
||||
// TTF_SetFontSDF(font, true);
|
||||
// 设置渲染器的混合模式
|
||||
@@ -40,7 +42,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
SDL_Color color = { 255, 255, 255, 255 }; // 白色文字
|
||||
SDL_Color bg_color = { 0, 0, 0, 255 }; // 背景颜色
|
||||
auto text_surface = TTF_RenderText_LCD_Wrapped(font, "Hello World!\n你好,世界!", 0, color, bg_color, 0);
|
||||
auto text_surface = TTF_RenderText_LCD_Wrapped(font, "Hello World!\n你好,世界!🆒", 0, color, bg_color, 0);
|
||||
if (text_surface == nullptr) {
|
||||
SDL_Log("Could not render text: %s", SDL_GetError());
|
||||
TTF_CloseFont(font);
|
||||
@@ -65,6 +67,23 @@ int main(int argc, char* argv[]) {
|
||||
SDL_GetTextureSize(texture, &text_width, &text_height);
|
||||
SDL_FRect dest_rect = { 0, 0, text_width, text_height };
|
||||
|
||||
SDL_GPUShaderCreateInfo shader_info;
|
||||
shader_info.code_size = 10;
|
||||
shader_info.code = nullptr; // 这里需要填入实际的着色器代码
|
||||
shader_info.entrypoint = "main";
|
||||
shader_info.format = SDL_GPU_SHADERFORMAT_DXIL;
|
||||
shader_info.stage = SDL_GPU_SHADERSTAGE_FRAGMENT;
|
||||
shader_info.num_samplers = 0;
|
||||
shader_info.num_storage_textures = 0;
|
||||
shader_info.num_uniform_buffers = 0;
|
||||
shader_info.num_storage_buffers = 0;
|
||||
auto shader = SDL_CreateGPUShader(gpu_device, &shader_info);
|
||||
|
||||
SDL_GPURenderStateDesc desc;
|
||||
SDL_INIT_INTERFACE(&desc);
|
||||
desc.fragment_shader = shader;
|
||||
auto render_state = SDL_CreateGPURenderState(renderer, &desc);
|
||||
|
||||
SDL_Event e;
|
||||
bool running = true;
|
||||
while (running) {
|
||||
@@ -79,6 +98,7 @@ int main(int argc, char* argv[]) {
|
||||
SDL_RenderClear(renderer); // 先清屏
|
||||
SDL_RenderTexture(renderer, texture, nullptr, &dest_rect); // 然后绘制文字
|
||||
SDL_RenderPresent(renderer); // 最后呈现
|
||||
SDL_RenderLines(renderer, nullptr, 0); // 确保没有多余的线条
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(16)); // ~60 FPS
|
||||
}
|
||||
|
||||
|
||||
21
src/shader_handle.cpp
Normal file
21
src/shader_handle.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Created by 46944 on 25-6-6.
|
||||
//
|
||||
#include "shader_handle.h"
|
||||
|
||||
#include "tmpxm05mgxl.layout.h"
|
||||
|
||||
SDL_GPUGraphicsPipeline* pixel_shader_handle_t::create_graphics_pipeline(SDL_GPUDevice* in_gpu_device) {
|
||||
SDL_GPUGraphicsPipelineCreateInfo desc = {};
|
||||
desc.vertex_shader = vertex_shader_;
|
||||
desc.fragment_shader = fragment_shader_;
|
||||
desc.vertex_input_state = g_vertexInputState;
|
||||
desc.primitive_type = primitive_type_;
|
||||
desc.rasterizer_state.fill_mode = fill_mode_;
|
||||
desc.rasterizer_state.cull_mode = cull_mode_;
|
||||
desc.rasterizer_state.front_face = front_face_;
|
||||
desc.multisample_state.sample_count = sample_count_;
|
||||
desc.depth_stencil_state.enable_depth_test = false;
|
||||
|
||||
return SDL_CreateGPUGraphicsPipeline(in_gpu_device, &desc);
|
||||
}
|
||||
87
src/shader_handle.h
Normal file
87
src/shader_handle.h
Normal file
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Created by 46944 on 25-6-6.
|
||||
//
|
||||
#pragma once
|
||||
#include <expected>
|
||||
#include <SDL3/SDL_gpu.h>
|
||||
#include <string>
|
||||
|
||||
class shader_handle_t {
|
||||
public:
|
||||
virtual ~shader_handle_t() = default;
|
||||
virtual std::expected<bool, std::string> init(SDL_GPUDevice* in_gpu_device) = 0;
|
||||
virtual void clear(SDL_GPUDevice* in_gpu_device) = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
class pixel_shader_handle_t : public shader_handle_t {
|
||||
public:
|
||||
virtual std::expected<bool, std::string> init(SDL_GPUDevice* in_gpu_device) override {
|
||||
vertex_shader_ = create_vertex_shader(in_gpu_device);
|
||||
if (!vertex_shader_) {
|
||||
return std::unexpected("Failed to create vertex shader");
|
||||
}
|
||||
fragment_shader_ = create_fragment_shader(in_gpu_device);
|
||||
if (!fragment_shader_) {
|
||||
clear(in_gpu_device);
|
||||
return std::unexpected("Failed to create fragment shader");
|
||||
}
|
||||
graphics_pipeline_ = create_graphics_pipeline(in_gpu_device);
|
||||
if (!graphics_pipeline_) {
|
||||
clear(in_gpu_device);
|
||||
return std::unexpected("Failed to create graphics pipeline");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void clear(SDL_GPUDevice* in_gpu_device) override {
|
||||
if (graphics_pipeline_) {
|
||||
SDL_ReleaseGPUGraphicsPipeline(in_gpu_device, graphics_pipeline_);
|
||||
graphics_pipeline_ = nullptr;
|
||||
}
|
||||
if (fragment_shader_) {
|
||||
SDL_ReleaseGPUShader(in_gpu_device, fragment_shader_);
|
||||
fragment_shader_ = nullptr;
|
||||
}
|
||||
if (vertex_shader_) {
|
||||
SDL_ReleaseGPUShader(in_gpu_device, vertex_shader_);
|
||||
vertex_shader_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual SDL_GPUShader* create_vertex_shader(SDL_GPUDevice* in_gpu_device) { return nullptr; }
|
||||
virtual SDL_GPUShader* create_fragment_shader(SDL_GPUDevice* in_gpu_device) = 0;
|
||||
virtual SDL_GPUGraphicsPipeline* create_graphics_pipeline(SDL_GPUDevice* in_gpu_device);
|
||||
private:
|
||||
SDL_GPUShader* vertex_shader_ = nullptr;
|
||||
SDL_GPUShader* fragment_shader_ = nullptr;
|
||||
SDL_GPUGraphicsPipeline* graphics_pipeline_ = nullptr;
|
||||
SDL_GPUPrimitiveType primitive_type_ = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
|
||||
SDL_GPUFillMode fill_mode_ = SDL_GPU_FILLMODE_FILL;
|
||||
SDL_GPUCullMode cull_mode_ = SDL_GPU_CULLMODE_NONE;
|
||||
SDL_GPUFrontFace front_face_ = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE;
|
||||
SDL_GPUSampleCount sample_count_ = SDL_GPU_SAMPLECOUNT_1;
|
||||
};
|
||||
|
||||
class compute_shader_handle_t : public shader_handle_t {
|
||||
public:
|
||||
virtual std::expected<bool, std::string> init(SDL_GPUDevice* in_gpu_device) override {
|
||||
compute_shader_ = create_compute_shader(in_gpu_device);
|
||||
if (!compute_shader_) {
|
||||
return std::unexpected("Failed to create compute shader");
|
||||
}
|
||||
compute_pipeline_ = SDL_CreateGPUComputePipeline(in_gpu_device, compute_shader_);
|
||||
if (!compute_pipeline_) {
|
||||
clear(in_gpu_device);
|
||||
return std::unexpected("Failed to create compute pipeline");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
virtual SDL_GPUShader* create_compute_shader(SDL_GPUDevice* in_gpu_device) = 0;
|
||||
private:
|
||||
SDL_GPUShader* compute_shader_ = nullptr;
|
||||
SDL_GPUComputePipeline* compute_pipeline_ = nullptr;
|
||||
};
|
||||
122
src/test.shader.h
Normal file
122
src/test.shader.h
Normal file
File diff suppressed because one or more lines are too long
126
src/tmpxm05mgxl.layout.h
Normal file
126
src/tmpxm05mgxl.layout.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_gpu.h>
|
||||
|
||||
// Auto-generated from: C:\Users\46944\AppData\Local\Temp\tmpufk9_wv_.json
|
||||
|
||||
// Auto-generated vertex structure
|
||||
typedef struct Vertex {
|
||||
float position[2];
|
||||
// location: 0, semantic: POSITION
|
||||
float uv[2];
|
||||
// location: 1, semantic: TEXCOORD
|
||||
float color[4];
|
||||
// location: 2, semantic: COLOR
|
||||
float param_a[4];
|
||||
// location: 3, semantic: TEXCOORD1
|
||||
float param_b[4];
|
||||
// location: 4, semantic: TEXCOORD2
|
||||
float param_c[4];
|
||||
// location: 5, semantic: TEXCOORD3
|
||||
} Vertex;
|
||||
|
||||
// Uniform buffer structures
|
||||
typedef struct ParamBuffer {
|
||||
float transform[4][4];
|
||||
} ParamBuffer;
|
||||
// Binding: 0, Size: 64 bytes
|
||||
|
||||
// Vertex attribute descriptions
|
||||
#define VERTEX_ATTRIBUTE_COUNT 6
|
||||
|
||||
static const SDL_GPUVertexAttribute g_vertexAttributes[] = {
|
||||
{
|
||||
.location = 0,
|
||||
.buffer_slot = 0,
|
||||
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
|
||||
.offset = 0
|
||||
}, // position
|
||||
{
|
||||
.location = 1,
|
||||
.buffer_slot = 0,
|
||||
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
|
||||
.offset = 8
|
||||
}, // uv
|
||||
{
|
||||
.location = 2,
|
||||
.buffer_slot = 0,
|
||||
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4,
|
||||
.offset = 16
|
||||
}, // color
|
||||
{
|
||||
.location = 3,
|
||||
.buffer_slot = 0,
|
||||
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4,
|
||||
.offset = 32
|
||||
}, // param_a
|
||||
{
|
||||
.location = 4,
|
||||
.buffer_slot = 0,
|
||||
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4,
|
||||
.offset = 48
|
||||
}, // param_b
|
||||
{
|
||||
.location = 5,
|
||||
.buffer_slot = 0,
|
||||
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4,
|
||||
.offset = 64
|
||||
} // param_c
|
||||
};
|
||||
|
||||
// Vertex buffer description
|
||||
static const SDL_GPUVertexBufferDescription g_vertexBufferDesc = {
|
||||
.slot = 0,
|
||||
.pitch = 80, // sizeof(Vertex)
|
||||
.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX,
|
||||
.instance_step_rate = 0
|
||||
};
|
||||
|
||||
// Vertex input state
|
||||
static const SDL_GPUVertexInputState g_vertexInputState = {
|
||||
.vertex_buffer_descriptions = &g_vertexBufferDesc,
|
||||
.num_vertex_buffers = 1,
|
||||
.vertex_attributes = g_vertexAttributes,
|
||||
.num_vertex_attributes = VERTEX_ATTRIBUTE_COUNT
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
|
||||
static SDL_GPUBuffer* createVertexBuffer(SDL_GPUDevice* device,
|
||||
const Vertex* vertices,
|
||||
Uint32 vertexCount) {
|
||||
SDL_GPUBufferCreateInfo bufferInfo = {
|
||||
.usage = SDL_GPU_BUFFERUSAGE_VERTEX,
|
||||
.size = static_cast<Uint32>(sizeof(Vertex)) * vertexCount
|
||||
};
|
||||
|
||||
SDL_GPUBuffer* buffer = SDL_CreateGPUBuffer(device, &bufferInfo);
|
||||
|
||||
SDL_GPUTransferBufferCreateInfo transferInfo = {
|
||||
.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
|
||||
.size = bufferInfo.size
|
||||
};
|
||||
|
||||
// Upload vertex data
|
||||
SDL_GPUTransferBuffer* transfer = SDL_CreateGPUTransferBuffer(device, &transferInfo);
|
||||
|
||||
void* mapped = SDL_MapGPUTransferBuffer(device, transfer, false);
|
||||
SDL_memcpy(mapped, vertices, bufferInfo.size);
|
||||
SDL_UnmapGPUTransferBuffer(device, transfer);
|
||||
|
||||
// Copy to GPU
|
||||
SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device);
|
||||
SDL_GPUCopyPass* copy = SDL_BeginGPUCopyPass(cmd);
|
||||
|
||||
SDL_GPUTransferBufferLocation src = {.transfer_buffer = transfer, .offset = 0};
|
||||
SDL_GPUBufferRegion dst = {.buffer = buffer, .offset = 0, .size = bufferInfo.size};
|
||||
|
||||
SDL_UploadToGPUBuffer(copy, &src, &dst, false);
|
||||
SDL_EndGPUCopyPass(copy);
|
||||
SDL_SubmitGPUCommandBuffer(cmd);
|
||||
|
||||
SDL_ReleaseGPUTransferBuffer(device, transfer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user