如何创建一个信箱效果的着色器以在wgpu中保留一个纵横比

huangapple go评论62阅读模式
英文:

How to create a letterbox shader to reserve an aspect ratio in wgpu

问题

我需要一个着色器,它能保持像许多游戏中看到的纵横比例。我有一个正交四边形,在第二个渲染通道中覆盖屏幕,同时带有帧作为纹理、屏幕宽度和高度,以及目标分辨率的宽度和高度。但是我无法弄清楚数学计算。

以下是我要处理的数据:

struct PostprocessOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) tex_coords: vec2<f32>,
    @location(1) resolution: vec2<f32>,
    @location(2) window_size: vec2<f32>,
}
英文:

I want a shader that reserves the aspect ratio like you see in many games. I have a quad that covers the screen in a second render pass along with the frame as a texture, screen width and height, and target resolution width and height. However I cant figure out the math.

Here is the data I have to work with:

struct PostprocessOutput {
    @builtin(position) clip_position: vec4&lt;f32&gt;,
    @location(0) tex_coords: vec2&lt;f32&gt;,
    @location(1) resolution: vec2&lt;f32&gt;,
    @location(2) window_size: vec2&lt;f32&gt;,
}

答案1

得分: 1

关于如何用全屏四边形填充视口的问题与您正在使用的模型视图投影矩阵有关。也许这个问题可以转化为:如何将模型坐标为[-1, 1]的标准矩形投影到完全填充整个视口。

pub fn cal_fullscreen_mvp(viewport: Size<f32>) -> glam::Mat4 {
    let fovy: f32 = 75.0 / 180.0 * std::f32::consts::PI;
    let factor = fullscreen_factor(viewport, fovy);

    let p_matrix = Mat4::perspective_rh(fovy, viewport.width / viewport.height, 0.1, 100.0);
    let vm_matrix = Mat4::from_translation(glam::vec3(0.0, 0.0, factor.0));
    let scale_matrix = Mat4::from_scale(glam::Vec3::new(factor.1, factor.2, 1.0));

    p_matrix * vm_matrix * scale_matrix
}
  

pub fn fullscreen_factor(viewport: Size<f32>, fovy: f32) -> (f32, f32, f32) {
    let mut sx = 1.0;
    let mut sy = 1.0;
    
    let ratio = if viewport.height > viewport.width {
        let ratio = viewport.height / viewport.width;
        sy = ratio;
        ratio
    } else {
        sx = viewport.width / viewport.height;
        1.0
    };

    let translate_z = -(ratio / (fovy / 2.0).tan());
    
    (translate_z, sx, sy)
}
英文:

The issue of filling the viewport with a full-screen quad is related to the model view projection matrix you are using. Perhaps this problem can be transformed into: How to project a standard rectangle with model coordinates of [-1, 1] to exactly fill the entire viewport.

pub fn cal_fullscreen_mvp(viewport: Size&lt;f32&gt;) -&gt; glam::Mat4 {
	let fovy: f32 = 75.0 / 180.0 * std::f32::consts::PI;
	let factor = fullscreen_factor(viewport, fovy);

	let p_matrix = Mat4::perspective_rh(fovy, viewport.width / viewport.height, 0.1, 100.0);
	let vm_matrix = Mat4::from_translation(glam::vec3(0.0, 0.0, factor.0));
	let scale_matrix = Mat4::from_scale(glam::Vec3::new(factor.1, factor.2, 1.0));

	p_matrix * vm_matrix * scale_matrix
}
  

pub fn fullscreen_factor(viewport: Size&lt;f32&gt;, fovy: f32) -&gt; (f32, f32, f32) {
	let mut sx = 1.0;
	let mut sy = 1.0;
	
	let ratio = if viewport.height &gt; viewport.width {
		let ratio = viewport.height / viewport.width;
		sy = ratio;
		ratio
	} else {
		sx = viewport.width / viewport.height;
		1.0
	};

	let translate_z = -(ratio / (fovy / 2.0).tan());
	
	(translate_z, sx, sy)
}

huangapple
  • 本文由 发表于 2023年2月16日 08:56:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75466832.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定