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

WGSL顶点归一化到裁剪空间后字母F不显示的问题求助

WGSL顶点归一化到裁剪空间后字母F不显示的问题求助

大家好,我最近跟着webgpufundamentals的教程,用Rust的wgpu和leptos实现2D平移相关的功能,遇到了一个奇怪的问题:当我把字母"F"的顶点归一化并转换到裁剪空间(包括Y轴翻转)后,屏幕上完全看不到这个F;但如果我去掉Y轴翻转的步骤,F会出现在屏幕右下角,只是是倒着的。我实在搞不懂哪里出问题了,想请大家帮忙看看。

下面是相关的代码片段:

生成F顶点数据的函数

#[allow(non_snake_case)]
#[rustfmt::skip]
pub fn create_F_buffer(
    device: &wgpu::Device,
    canvas_size: &PhysicalSize<u32>,
) -> Canvas2dBuffer {
    let vertex_data = [
        // left column
        0., 0.,
        30., 0.,
        0., 150.,
        30., 150.,
        // top rung
        30., 0.,
        100., 0.,
        30., 30.,
        100., 30.,
        // middle rung
        30., 60.,
        70., 60.,
        30., 90.,
        70., 90.,
    ];

    let index_data = [
        0 as u16, 1, 2, 2, 1, 3, // left column
        4, 5, 6, 6, 5, 7, // top run
        8, 9, 10, 10, 9, 11, // middle run
    ];

    let mut vertices = Vec::with_capacity(vertex_data.len() / 2);
    for i in (0..vertex_data.len()).step_by(2) {
        vertices.push(Vertex {
            position: [vertex_data[i], vertex_data[i + 1]]
        });
    }

    let indices = index_data.to_vec();

    let mut rng = rand::thread_rng();
    let triangle_uniform = TriangleUniform::new(
        [rng.gen_range(0.0..=1.0), rng.gen_range(0.0..=1.0), rng.gen_range(0.0..=1.0), 1.0],
        [canvas_size.width as f32, canvas_size.height as f32]
    );

    Canvas2dBuffer::new(device, triangle_uniform, vertices, indices)
}

WGSL着色器代码

struct Uniforms {
    color: vec4f,
    resolution: vec2f,
    _pad: vec2f,
};

struct Vertex {
    @location(0) position: vec2f,
};

struct VSOutput {
    @builtin(position) position: vec4f,
};

@group(0) @binding(0) var<uniform> uni: Uniforms;

@vertex
fn vs_main(vert: Vertex) -> VSOutput {
    var vsOut: VSOutput;
    let position = vert.position;

    // convert the position from pixels to a 0.0 to 1.0 value
    let zeroToOne = position / uni.resolution;
    // convert from 0 <-> 1 to 0 <-> 2
    let zeroToTwo = zeroToOne * 2.0;
    // covert from 0 <-> 2 to -1 <-> +1 (clip space)
    let flippedClipSpace = zeroToTwo - 1.0;
    // flip Y
    let clipSpace = flippedClipSpace * vec2f(1, -1);

    vsOut.position = vec4f(clipSpace, 0.0, 1.0);
    return vsOut;
}

@fragment
fn fs_main(vsOut: VSOutput) -> @location(0) vec4f {
    return uni.color;
}

Canvas2dBuffer结构体代码

use crate::utils::graphics::types::{triangle_uniform::TriangleUniform, vertex::Vertex};
use wgpu::util::DeviceExt;

#[allow(unused)]
pub struct Canvas2dBuffer {
    // handle uniforms
    pub triangle_buffer: wgpu::Buffer,
    triangle_uniform: TriangleUniform,
    // handle vertices
    pub vertex_buffer: wgpu::Buffer,
    vertices: Vec<Vertex>,
    // handle indices
    pub index_buffer: wgpu::Buffer,
    indices: Vec<u16>,
    pub num_indices: u32,
    // handle instancing
    // nothing for now
}

impl Canvas2dBuffer {
    pub fn new(
        device: &wgpu::Device,
        triangle_uniform: TriangleUniform,
        vertices: Vec<Vertex>,
        indices: Vec<u16>,
    ) -> Self {
        // Create triangle uniform buffer
        let triangle_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
            label: Some("Triangle Uniform Buffer"),
            contents: bytemuck::cast_slice(&[triangle_uniform]),
            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
        });

        // Create vertex buffer
        let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
            label: Some("Vertex Buffer"),
            contents: bytemuck::cast_slice(&vertices),
            usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
        });

        // Create index buffer
        let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
            label: Some("Index Buffer"),
            contents: bytemuck::cast_slice(&indices),
            usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
        });

        let num_indices = indices.len();

        Self {
            triangle_buffer,
            triangle_uniform,
            vertex_buffer,
            vertices,
            index_buffer,
            indices,
            num_indices: num_indices as u32,
        }
    }
}

我自己排查了一下,怀疑是不是裁剪空间转换的步骤哪里错了?或者顶点数据的坐标系统和我理解的不一样?比如,是不是Y轴翻转后,整个F被移出了可视区域?但按道理来说,原来的顶点Y坐标是0到150,除以画布高度后再翻转,应该还是在-1到1之间才对...

有没有大佬能帮我分析一下问题出在哪里?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 07:18:01