// pbr.wjsl - Simple PBR fragment shader (WJSL RFC syntax)
// Compiles with: wj build examples/pbr.wjsl --target wgsl -o shaders/
struct Material {
base_color: vec4,
metallic: f32,
roughness: f32,
ao: f32,
emissive: vec3,
}
struct Light {
position: vec3,
color: vec3,
intensity: f32,
}
struct CameraUniforms {
view_matrix: mat4x4,
proj_matrix: mat4x4,
position: vec3,
screen_size: vec2,
near_plane: f32,
far_plane: f32,
}
@group(0) @binding(0) uniform material: Material;
@group(0) @binding(1) uniform camera: CameraUniforms;
@group(0) @binding(2) uniform light: Light;
fn pbr_lighting(albedo: vec3, metallic: f32, roughness: f32, ao: f32,
n: vec3, v: vec3, l: vec3, radiance: vec3) -> vec3 {
let h = normalize(v + l);
var f0 = vec3(0.04);
f0 = mix(f0, albedo, metallic);
let n_dot_l = max(dot(n, l), 0.0);
let n_dot_v = max(dot(n, v), 0.0);
let diffuse = (vec3(1.0) - f0) * (1.0 - metallic) * albedo / 3.14159265;
return diffuse * radiance * n_dot_l * ao;
}
@fragment
fn main(
@location(0) world_pos: vec3,
@location(1) normal: vec3,
@location(2) uv: vec2
) -> @location(0) vec4 {
let n = normalize(normal);
let v = normalize(camera.position - world_pos);
let l = normalize(light.position - world_pos);
let dist = length(light.position - world_pos);
let attenuation = 1.0 / (dist * dist);
let radiance = light.color * light.intensity * attenuation;
let albedo = material.base_color.rgb;
let lit = pbr_lighting(albedo, material.metallic, material.roughness,
material.ao, n, v, l, radiance);
let ambient = vec3(0.03) * albedo * material.ao;
return vec4(lit + ambient + material.emissive, material.base_color.a);
}