1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
-- Basic vertex + fragment shader pair
-- Demonstrates: structs, uniforms, entry points, @varying, auto-location
struct VertexInput
position: vec3
normal: vec3
uv: vec2
end
-- @varying marks a struct shared between vertex output and fragment input.
-- Fragment inputs automatically skip @builtin fields.
@varying
struct Interpolated
@builtin(position) position: vec4
uv: vec2
normal: vec3
end
struct Uniforms
model: mat4
view_proj: mat4
normal_mat: mat4
end
-- Binding attributes are optional: @group defaults to 0, @binding auto-increments
uniform uniforms: Uniforms
@entry(vertex)
function vs_main(input: VertexInput) -> Interpolated
let world_pos = uniforms.model * vec4(input.position, 1.0)
let clip_pos = uniforms.view_proj * world_pos
let world_normal = normalize((uniforms.normal_mat * vec4(input.normal, 0.0)).xyz)
return Interpolated {
position = clip_pos,
uv = input.uv,
normal = world_normal,
}
end
struct FragmentOutput
@location(0) color: vec4
end
-- sampler2D is automatically split into texture + sampler bindings
@group(1) @binding(0)
uniform albedo_tex: sampler2D
@entry(fragment)
function fs_main(input: Interpolated) -> FragmentOutput
let albedo = sample(albedo_tex, input.uv)
let light = max(dot(input.normal, normalize(vec3(1.0, 1.0, 0.0))), 0.0)
let color = albedo * (light * 0.8 + 0.2)
return FragmentOutput {
color = vec4(color.rgb, 1.0),
}
end