如何在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>, // 当前窗口的实际尺寸 }
数学计算逻辑
计算宽高比
分别算出目标分辨率和窗口的宽高比:let target_aspect = resolution.x / resolution.y; let window_aspect = window_size.x / 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 = 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
相关产品推荐
相关产品推荐

