You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在wgpu中创建保留宽高比的Letterbox着色器

实现保留宽高比的Letterbox着色器

核心思路是通过对比窗口与目标分辨率的宽高比,计算合适的缩放比例与偏移,让原始画面居中显示并保留宽高比,超出有效区域的部分输出黑边。

可用数据说明

你手上的PostprocessOutput结构体包含关键参数:

struct PostprocessOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) tex_coords: vec2<f32>,
    @location(1) resolution: vec2<f32>, // 目标分辨率(比如游戏原生1920x1080)
    @location(2) window_size: vec2<f32>, // 当前窗口的实际尺寸
}

数学计算逻辑

  1. 计算宽高比
    分别算出目标分辨率和窗口的宽高比:

    let target_aspect = resolution.x / resolution.y;
    let window_aspect = window_size.x / window_size.y;
    
  2. 确定缩放因子与偏移
    对比两个宽高比,判断是上下留黑边还是左右留黑边,计算出纹理的缩放比例和居中偏移:

    var scale: vec2<f32>;
    var offset: vec2<f32>;
    
    if (window_aspect > target_aspect) {
        // 窗口比目标宽,左右留黑边
        scale.x = target_aspect / window_aspect;
        scale.y = 1.0;
        offset.x = (1.0 - scale.x) / 2.0;
        offset.y = 0.0;
    } else {
        // 窗口比目标高,上下留黑边
        scale.x = 1.0;
        scale.y = window_aspect / target_aspect;
        offset.y = (1.0 - scale.y) / 2.0;
        offset.x = 0.0;
    }
    
  3. 调整纹理坐标并采样
    用计算出的缩放和偏移调整原始纹理坐标,同时判断坐标是否在有效范围内,超出则输出黑边:

    // 计算调整后的纹理坐标
    let adjusted_tex_coords = tex_coords * scale + offset;
    
    // 检查坐标是否在有效区域内(0到1之间)
    let is_inside = adjusted_tex_coords.x >= 0.0 && adjusted_tex_coords.x <= 1.0 &&
                    adjusted_tex_coords.y >= 0.0 && adjusted_tex_coords.y <= 1.0;
    
    // 采样纹理或输出黑边
    var color = vec4<f32>(0.0, 0.0, 0.0, 1.0); // 黑边颜色
    if (is_inside) {
        color = textureSample(your_frame_texture, your_sampler, adjusted_tex_coords);
    }
    

完整片段着色器示例

把上述逻辑整合到片段着色器中:

@group(0) @binding(0) var your_frame_texture: texture_2d<f32>;
@group(0) @binding(1) var your_sampler: sampler;

@fragment
fn fs(input: PostprocessOutput) -> @location(0) vec4<f32> {
    let target_aspect = input.resolution.x / input.resolution.y;
    let window_aspect = input.window_size.x / input.window_size.y;

    var scale: vec2<f32>;
    var offset: vec2<f32>;

    if (window_aspect > target_aspect) {
        scale.x = target_aspect / window_aspect;
        scale.y = 1.0;
        offset.x = (1.0 - scale.x) / 2.0;
        offset.y = 0.0;
    } else {
        scale.x = 1.0;
        scale.y = window_aspect / target_aspect;
        offset.y = (1.0 - scale.y) / 2.0;
        offset.x = 0.0;
    }

    let adjusted_tex_coords = input.tex_coords * scale + offset;
    let is_inside = adjusted_tex_coords.x >= 0.0 && adjusted_tex_coords.x <= 1.0 &&
                   adjusted_tex_coords.y >= 0.0 && adjusted_tex_coords.y <= 1.0;

    var color = vec4<f32>(0.0, 0.0, 0.0, 1.0);
    if (is_inside) {
        color = textureSample(your_frame_texture, your_sampler, adjusted_tex_coords);
    }

    return color;
}

内容的提问来源于stack exchange,提问作者Jove

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 23:39:08