-- PBR fragment shader -- Demonstrates: multiple uniforms, texture sampling, math builtins struct FragInput @location(0) uv: vec2 @location(1) normal: vec3 @location(2) world_pos: vec3 end struct FragOutput @location(0) color: vec4 end struct Material base_color: vec3 roughness: float metallic: float end struct Light position: vec3 color: vec3 intensity: float end @group(0) @binding(0) uniform material: Material @group(0) @binding(1) uniform light: Light @group(1) @binding(0) uniform albedo_map: sampler2D const PI = 3.14159265 -- Helper: Schlick Fresnel approximation function fresnel_schlick(cos_theta: float, f0: vec3) -> vec3 return f0 + (vec3(1.0, 1.0, 1.0) - f0) * pow(1.0 - cos_theta, 5.0) end @entry(fragment) function main(input: FragInput) -> FragOutput let n = normalize(input.normal) let v = normalize(-input.world_pos) let l = normalize(light.position - input.world_pos) let h = normalize(v + l) let albedo = sample(albedo_map, input.uv).rgb * material.base_color let ndotl = max(dot(n, l), 0.0) let ndoth = max(dot(n, h), 0.0) let f0 = mix(vec3(0.04, 0.04, 0.04), albedo, material.metallic) let f = fresnel_schlick(max(dot(h, v), 0.0), f0) let diffuse = albedo * (1.0 - material.metallic) let specular = f * pow(ndoth, (1.0 - material.roughness) * 256.0) let result = (diffuse + specular) * light.color * light.intensity * ndotl return FragOutput { color = vec4(result, 1.0), } end