Search code examples
wgpu-rswgsl

WGSL get different results even using the same data


I am new to WGSL. I am following the tuorial of wgpu to write my first traingle.

The correct shader is like this

// Vertex shader

struct VertexOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) position: vec2<f32>,
};

@vertex
fn vs_main(
    @builtin(vertex_index) in_vertex_index: u32,
) -> VertexOutput {
    var out: VertexOutput;
    let x = f32(1 - i32(in_vertex_index)) * 0.5;
    let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
    out.position = vec2<f32>(x, y);
    out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
    return out;
}

// Fragment shader

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    return vec4<f32>(in.position, 0.5, 1.0);
}

The rendered result: enter image description here

Since out.position is the same as first two elements of out.clip_position, I think I can change the fragment shader like this

- return vec4<f32>(in.position, 0.5, 1.0);
+ return vec4<f32>(in.clip_position.xy, 0.5, 1.0);

But this will give me a wrong result enter image description here

Skeleton code can be found here


Solution

  • The reason for this is that clip_position uses @builtin(position).

    Which means

    An output value (x,y,z,w) will map to (x/w, y/w, z/w) in WebGPU normalized device coordinates.

    You can easily verify the desired behaviour using the shader below:

    // Vertex shader
    
    struct VertexOutput {
        @builtin(position) clip_position: vec4<f32>,
        @location(0) position: vec2<f32>,
        @location(1) clip_position_raw: vec4<f32>,
    };
    
    @vertex
    fn vs_main(
        @builtin(vertex_index) in_vertex_index: u32,
    ) -> VertexOutput {
        var out: VertexOutput;
        let x = f32(1 - i32(in_vertex_index)) * 0.5;
        let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
        out.position = vec2<f32>(x, y);
        out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
        out.clip_position_raw = vec4<f32>(x, y, 0.0, 1.0);
        return out;
    }
    
    // Fragment shader
    
    @fragment
    fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
        return vec4<f32>(in.clip_position_raw.xy, 0.5, 1.0);
    }