着色技巧详解

颜色与渐变

在深入了解着色器中的颜色处理之前,让我们先建立对颜色在计算机图形学中的基本认知

基本颜色表示

在 Makepad 着色器中,我们使用 vec4 (RGBA向量) 来表示颜色:

  • Red (红色): 0.01.0
  • Green (绿色): 0.01.0
  • Blue (蓝色): 0.01.0
  • Alpha (透明度): 0.0(完全透明)到 1.0(完全不透明)
1// 基础纯色着色器
2fn pixel(self) -> vec4 {
3    // 格式: vec4(红, 绿, 蓝, 透明度)
4    return vec4(1.0, 0.0, 0.0, 1.0); // 纯红色
5}

线性渐变

线性渐变是在两种颜色之间创建平滑过渡的技术。以下是一个水平渐变的实现:

1fn pixel(self) -> vec4 {
2    // self.pos.x 给出从0.0到1.0的水平位置
3    let mix_factor = self.pos.x;
4
5    let color1 = vec4(1.0, 0.0, 0.0, 1.0); // 红色
6    let color2 = vec4(0.0, 0.0, 1.0, 1.0); // 蓝色
7
8    // 在两种颜色之间线性插值
9    return mix(color1, color2, mix_factor);
10}

视觉表现如下:

1红色 [================>] 蓝色
2        <- 混合因子 ->

对于对角线渐变,我们可以这样实现:

1fn pixel(self) -> vec4 {
2    // 组合x和y坐标实现对角线方向
3    let mix_factor = (self.pos.x + self.pos.y) * 0.5;
4
5    let color1 = vec4(1.0, 0.0, 0.0, 1.0); // 红色
6    let color2 = vec4(0.0, 0.0, 1.0, 1.0); // 蓝色
7
8    return mix(color1, color2, mix_factor);
9}

径向渐变

径向渐变创建从中心点向外扩散的圆形颜色过渡:

1fn pixel(self) -> vec4 {
2    // 计算到中心点的距离
3    let center = vec2(0.5, 0.5);
4    let dist = length(self.pos - center);
5
6    // 将距离转换为混合因子
7    let mix_factor = clamp(dist * 2.0, 0.0, 1.0);
8
9    let inner_color = vec4(1.0, 1.0, 1.0, 1.0); // 中心白色
10    let outer_color = vec4(0.0, 0.0, 0.0, 1.0); // 边缘黑色
11
12    return mix(inner_color, outer_color, mix_factor);
13}

纹理映射

纹理映射是将 2D 图像应用到几何图形表面的技术。

基础纹理采样

1DrawTexture = {{DrawTexture}} {
2    texture tex: texture2d // 声明纹理uniform
3
4    fn pixel(self) -> vec4 {
5        // 在当前位置采样纹理
6        return sample2d(self.tex, self.pos);
7    }
8}

UV坐标系统

UV坐标用于将纹理像素映射到几何体:

1(0,0) +-----------+ (1,0)
2      |           |
3      |   纹理     |
4      |           |
5(0,1) +-----------+ (1,1)
1fn vertex(self) -> vec4 {
2    // 转换UV坐标
3    self.uv = self.geom_pos * self.tex_scale + self.tex_offset;
4
5    // 常规顶点变换
6    let clip_pos = self.geom_pos * self.rect_size + self.rect_pos;
7    return self.camera_projection * vec4(clip_pos, 0.0, 1.0);
8}
9
10fn pixel(self) -> vec4 {
11    // 使用变换后的UV采样
12    return sample2d(self.tex, self.uv);
13}

特效处理

高斯模糊

下面是一个简单的高斯模糊实现:

1fn blur(self) -> vec4 {
2    let blur_radius = 2.0; // 模糊半径
3    let mut color = vec4(0.0);
4    let mut total_weight = 0.0;
5
6    // 在当前像素周围的5x5网格中采样
7    for i in -2..3 {
8        for j in -2..3 {
9            let offset = vec2(float(i), float(j)) * blur_radius;
10            // 计算高斯权重
11            let weight = exp(-(offset.x * offset.x + offset.y * offset.y));
12
13            color += sample2d(self.tex, self.pos + offset) * weight;
14            total_weight += weight;
15        }
16    }
17
18    return color / total_weight; // 归一化结果
19}

发光效果

1fn glow(self) -> vec4 {
2    let base_color = sample2d(self.tex, self.pos); // 原始颜色
3    let blur_color = self.blur(); // 模糊后的颜色
4
5    // 将模糊版本叠加以创建发光效果
6    return base_color + blur_color * self.glow_strength;
7}

阴影效果

1// 使用Makepad内置的GaussShadow来实现阴影效果
2fn draw_shadow(self) -> vec4 {
3    let shadow_color = vec4(0.0, 0.0, 0.0, 0.5);
4    let shadow_offset = vec2(5.0, 5.0);
5
6    // 计算阴影区域
7    let shadow = GaussShadow::box_shadow(
8        self.rect_pos + shadow_offset,
9        self.rect_size,
10        self.pos,
11        10.0 // 阴影模糊半径
12    );
13
14    return shadow_color * shadow;
15}