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);
}
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
Skeleton code can be found here
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);
}